[
  {
    "path": ".commitlintrc.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/commitlintrc.json\",\n\t\"extends\": [\"@commitlint/config-angular\"],\n\t\"rules\": {\n\t\t\"type-enum\": [\n\t\t\t2,\n\t\t\t\"always\",\n\t\t\t[\"chore\", \"build\", \"ci\", \"docs\", \"feat\", \"fix\", \"perf\", \"refactor\", \"revert\", \"style\", \"test\", \"types\"]\n\t\t],\n\t\t\"scope-case\": [0],\n\t\t\"subject-exclamation-mark\": [0]\n\t}\n}\n"
  },
  {
    "path": ".dockerignore",
    "content": "# Packages\n**/node_modules\n\n# Log files\n**/logs\n**/*.log\n**/npm-debug.log*\n\n# Runtime data\n**/pids\n**/*.pid\n**/*.seed\n\n# Env\n**/.env\n\n# Dist\n**/dist/\n**/dist-docs/\n\n# Miscellaneous\n**/.tmp\n**/.vscode\n**/.idea\n**/.DS_Store\n**/.turbo\n**/tsconfig.tsbuildinfo\n**/coverage\n**/__tests__\n**/out\n\n# yarn\n.pnp.*\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n\n# Cache\n**/.prettiercache\n**/.eslintcache\n**/.vercel\n\n# Docker specific\n**/.cliff-jumperrc.json\n**/api-extractor.json\n**/api-extractor-docs.json\n**/.eslintignore\n**/.eslintrc.json\n**/.lintstagedrc.js\n**/.lintstagedrc.cjs\n**/.lintstagedrc.json\n**/.prettierignore\n**/.prettierrc.js\n**/.prettierrc.cjs\n**/.prettierrc.json\n**/cliff.toml\n**/CHANGELOG.md\n**/README.md\n**/LICENSE\n**/tsconfig.eslint.json\n**/tsconfig.docs.json\n**/docs/\n**/vitest.config.ts\n\n"
  },
  {
    "path": ".git-blame-ignore-revs",
    "content": "# .git-blame-ignore-revs\n# switched to eslint-config-neon for mainlib discord.js\nb03c65c34c6e8bab7f97d507d6ccd7c441a14360\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto eol=lf\npnpm-lock.yaml linguist-generated=true text=auto eol=lf\n"
  },
  {
    "path": ".github/.kodiak.toml",
    "content": "version = 1\n\n[merge]\nrequire_automerge_label = false\nblocking_labels = ['blocked', 'in review', 'semver:major']\nmethod = 'squash'\n\n[merge.message]\ntitle = 'pull_request_title'\nstrip_html_comments = true\ninclude_coauthors = true\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "# Learn how to add code owners here:\n# https://help.github.com/articles/about-code-owners\n\n* @iCrawl\n\npackage.json @discordjs/core\npnpm-lock.yaml @discordjs/core\n\n/.github/ISSUE_TEMPLATE/ @discordjs/guide @discordjs/core\n\n/apps/guide/ @discordjs/website @discordjs/guide\n/apps/guide/content/ @discordjs/guide\n/apps/proxy-container/ @discordjs/proxy\n/apps/website/ @discordjs/website\n\n/packages/actions/ @discordjs/actions\n/packages/api-extractor/ @discordjs/api-extractor-utils\n/packages/api-extractor-model/ @discordjs/api-extractor-utils\n/packages/api-extractor-utils/ @discordjs/api-extractor-utils\n/packages/brokers/ @discordjs/brokers\n/packages/builders/ @discordjs/builders\n/packages/collection/ @discordjs/collection\n/packages/core/ @discordjs/core\n/packages/create-discord-bot/ @discordjs/guide\n/packages/discord.js/ @discordjs/core\n/packages/docgen/ @iCrawl\n/packages/formatters/ @discordjs/formatters\n/packages/next/ @discordjs/core\n/packages/proxy/ @discordjs/proxy\n/packages/rest/ @discordjs/rest\n/packages/scripts/ @discordjs/scripts\n/packages/structures/ @discordjs/structures\n/packages/ui/ @discordjs/ui\n/packages/util/ @discordjs/util\n/packages/voice/ @discordjs/core\n/packages/ws/ @discordjs/ws\n"
  },
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to make participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n- Using welcoming and inclusive language\n- Being respectful of differing viewpoints and experiences\n- Gracefully accepting constructive criticism\n- Focusing on what is best for the community\n- Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n- The use of sexualized language or imagery and unwelcome sexual attention or\n  advances\n- Trolling, insulting/derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n- Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies within all project spaces, and it also applies when\nan individual is representing the project or its community in public spaces.\nExamples of representing a project or community include using an official\nproject e-mail address, posting via an official social media account, or acting\nas an appointed representative at an online or offline event. Representation of\na project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at https://discord.gg/djs. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": ".github/COMMIT_CONVENTION.md",
    "content": "## Git Commit Message Convention\n\n> This is adapted from [Angular's commit convention](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular).\n\n#### TL;DR:\n\nMessages must be matched by the following regex:\n\n```js\n/^(revert: )?(feat|fix|docs|style|refactor|perf|test|build|ci|chore|types)(\\(.+\\))?!?: .{1,72}/;\n```\n\n#### Examples\n\nAppears under \"Features\" header, `GuildMember` subheader:\n\n```\nfeat(GuildMember): add 'tag' method\n```\n\nAppears under \"Bug Fixes\" header, `Guild` subheader, with a link to issue #28:\n\n```\nfix(Guild): handle events correctly\n\nclose #28\n```\n\nAppears under \"Performance Improvements\" header, and under \"Breaking Changes\" with the breaking change explanation:\n\n```\nperf(core): improve patching by removing 'bar' option\n\nBREAKING CHANGE: The 'bar' option has been removed.\n```\n\nThe following commit and commit `667ecc1` do not appear in the changelog if they are under the same release. If not, the revert commit appears under the \"Reverts\" header.\n\n```\nrevert: feat(Managers): add Managers\n\nThis reverts commit 667ecc1654a317a13331b17617d973392f415f02.\n```\n\n### Full Message Format\n\nA commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**:\n\n```\n<type>(<scope>): <subject>\n<BLANK LINE>\n<body>\n<BLANK LINE>\n<footer>\n```\n\nThe **header** is mandatory and the **scope** of the header is optional.\nIf the commit contains **Breaking Changes**, a `!` can be added before the `:` as an indicator.\n\n### Revert\n\nIf the commit reverts a previous commit, it should begin with `revert:`, followed by the header of the reverted commit. In the body, it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.\n\n### Type\n\nIf the prefix is `feat`, `fix` or `perf`, it will appear in the changelog. However, if there is any [BREAKING CHANGE](#footer), the commit will always appear in the changelog.\n\nOther prefixes are up to your discretion. Suggested prefixes are `docs`, `chore`, `style`, `refactor`, and `test` for non-changelog related tasks.\n\n### Scope\n\nThe scope could be anything specifying the place of the commit change. For example `GuildMember`, `Guild`, `Message`, `TextChannel` etc...\n\n### Subject\n\nThe subject contains a succinct description of the change:\n\n- use the imperative, present tense: \"change\" not \"changed\" nor \"changes\"\n- don't capitalize the first letter\n- no dot (.) at the end\n\n### Body\n\nJust as in the **subject**, use the imperative, present tense: \"change\" not \"changed\" nor \"changes\".\nThe body should include the motivation for the change and contrast this with previous behavior.\n\n### Footer\n\nThe footer should contain any information about **Breaking Changes** and is also the place to\nreference GitHub issues that this commit **Closes**.\n\n**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Contributing\n\n**The issue tracker is only for bug reports and enhancement suggestions. If you have a question, please ask it in the [Discord server](https://discord.gg/djs) instead of opening an issue – you will get redirected there anyway.**\n\nIf you wish to contribute to the discord.js codebase or documentation, feel free to fork the repository and submit a\npull request. We use ESLint to enforce a consistent coding style, so having that set up in your editor of choice\nis a great boon to your development process.\n\n## Setup\n\nTo get ready to work on the codebase, please do the following:\n\n1. Fork & clone the repository, and make sure you're on the **main** branch\n2. Run `pnpm install --frozen-lockfile` ([install](https://pnpm.io/installation))\n3. Run `pnpm run build` to build local packages\n4. Code your heart out!\n5. Run `pnpm run test` to run ESLint and ensure any JSDoc changes are valid\n6. [Submit a pull request](https://github.com/discordjs/discord.js/compare) (Make sure you follow the [conventional commit format](https://github.com/discordjs/discord.js/blob/main/.github/COMMIT_CONVENTION.md))\n\n## Testing changes locally\n\nIf you want to test changes you've made locally, you can do so by using `pnpm link <package-you-want-to-link-to-your-current-package>`. This will create a symlink to your local copy of the discord.js libraries.\n\n1. Create a new directory `mkdir discordjs-test` and move into it `cd discordjs-test`\n2. Initialize a new pnpm project `pnpm init`\n3. Now link the discord.js package from the directory you cloned earlier `pnpm link {PATH_TO_DISCORDJS_REPO}/packages/<package>`. (e.g. `pnpm link ~/discord.js/packages/rest`)\n4. Import the package in your source code and test them out!\n\n### Working with TypeScript packages\n\nWhen testing local changes, you may notice you need to manually recompile TypeScript projects on every change in order to get the latest code changes to test locally.\n\nTo avoid this you can use the `--watch` parameter in the package build script to automatically recompile the project when changes are detected.\n\nFor example, to automatically recompile the `@discordjs/rest` project when changes are detected, run `pnpm turbo run build --filter='@discordjs/rest' -- --watch` in the root folder of where you cloned the discord.js repo.\n\n## Adding new packages\n\nIf you'd like to create another package under the `@discordjs` organization run the following command:\n\n```sh\npnpm run create-package <package-name> [package-description]\n```\n\nThis will create new package directory under `packages/` with the required configuration files. You may begin\nto make changes within the `src/` directory. You may also need to:\n\n- Update workflows that utilize packages\n- Update the CODEOWNERS file\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: [iCrawl, amishshah, vladfrangu, kyranet]\nopen_collective: discordjs\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/01-package_bug_report.yml",
    "content": "name: Bug report\ndescription: Report an issue with discord.js or another package.\nlabels: [bug, need repro]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thank you for filing an issue! If you are here to ask a question, use Discord instead: https://discord.gg/djs\n\n        This issue form is for discord.js, including other packages.\n  - type: dropdown\n    id: package\n    attributes:\n      label: Which package is this bug report for?\n      options:\n        - discord.js\n        - brokers\n        - builders\n        - collection\n        - core\n        - create-discord-bot\n        - formatters\n        - next\n        - proxy\n        - rest\n        - structures\n        - ui\n        - util\n        - voice\n        - ws\n    validations:\n      required: true\n  - type: textarea\n    id: description\n    attributes:\n      label: Issue description\n      description: Describe the issue in as much detail as possible.\n      placeholder: |\n        Steps to reproduce with below code sample:\n        1. Do thing\n        2. Do thing in Discord client\n        3. Observe behavior\n        4. See error logs below\n    validations:\n      required: true\n  - type: textarea\n    id: code_sample\n    attributes:\n      label: Code sample\n      description: |\n        Your code sample should be:\n        1. Minimal - Use as little code as possible that still produces the same problem (and is understandable)\n        2. Complete - Provide all parts someone else needs to reproduce your problem\n        3. Reproducible - Test the code you're about to provide to make sure it reproduces the problem\n\n        This will be automatically formatted into code, so no need for backticks.\n      render: typescript\n  - type: textarea\n    id: versions\n    attributes:\n      label: Versions\n      description: List necessary versions here. This includes your package version, runtime version, operating system etc.\n      placeholder: |\n        - discord.js 14.24.2 (`npm ls discord.js` or another package)\n        - Node.js 24.11.0 (`node --version`)\n        - TypeScript 5.9.3 (`npm ls typescript` if you use it)\n        - macOS Ventura 13.3.1\n    validations:\n      required: true\n  - type: dropdown\n    id: priority\n    attributes:\n      label: Issue priority\n      description: Please be realistic. If you need to elaborate on your reasoning, please use the issue description field above.\n      options:\n        - Low (slightly annoying)\n        - Medium (should be fixed soon)\n        - High (immediate attention needed)\n    validations:\n      required: true\n  - type: dropdown\n    id: partials\n    attributes:\n      label: Which partials do you have configured?\n      description: Check your `Client` constructor for the `partials` key.\n      options:\n        - Not applicable\n        - No Partials\n        - User\n        - Channel\n        - GuildMember\n        - Message\n        - Reaction\n        - GuildScheduledEvent\n        - ThreadMember\n        - Poll\n        - PollAnswer\n        - SoundboardSound\n      multiple: true\n    validations:\n      required: true\n  - type: dropdown\n    id: intents\n    attributes:\n      label: Which gateway intents are you subscribing to?\n      description: Check your `Client` constructor for the `intents` key.\n      options:\n        - Not applicable\n        - No Intents\n        - Guilds\n        - GuildMembers\n        - GuildModeration\n        - GuildExpressions\n        - GuildIntegrations\n        - GuildWebhooks\n        - GuildInvites\n        - GuildVoiceStates\n        - GuildPresences\n        - GuildMessages\n        - GuildMessageReactions\n        - GuildMessageTyping\n        - DirectMessages\n        - DirectMessageReactions\n        - DirectMessageTyping\n        - MessageContent\n        - GuildScheduledEvents\n        - AutoModerationConfiguration\n        - AutoModerationExecution\n        - GuildMessagePolls\n        - DirectMessagePolls\n      multiple: true\n    validations:\n      required: true\n  - type: input\n    id: dev_release\n    attributes:\n      label: I have tested this issue on a development release\n      placeholder: d23280c (commit hash)\n      description: |\n        The issue might already be fixed in a development release or main. This is not required, but helps us greatly.\n        [discord.js only] To install the latest development release run `npm i discord.js@dev` in your project directory.\n        Run `npm list discord.js` and use the last part of the printed information (`d23280c` for `discord.js@xx.x.x-dev.1530234593.d23280c`)\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/02-application_bug_report.yml",
    "content": "name: Websites bug report\ndescription: Report an issue with the documentation or guide websites.\nlabels: [bug, need repro]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thank you for filing an issue! If you are here to ask a question, use Discord instead: https://discord.gg/djs\n\n        This issue form is for our documentation and guide websites.\n  - type: dropdown\n    id: application\n    attributes:\n      label: Which application is this bug report for?\n      options:\n        - Documentation\n        - Guide\n    validations:\n      required: true\n  - type: textarea\n    id: description\n    attributes:\n      label: Issue description\n      description: Describe the issue in as much detail as possible.\n    validations:\n      required: true\n  - type: textarea\n    id: steps_to_reproduce\n    attributes:\n      label: Steps to Reproduce\n      description: What steps must be taken to reproduce this issue?\n      placeholder: |\n        1. Visit a page\n        2. Click a link\n        3. ...\n    validations:\n      required: true\n  - type: textarea\n    id: versions\n    attributes:\n      label: Versions\n      description: List necessary versions here. This includes your browser, operating system etc.\n      placeholder: |\n        - Safari 16.4 (18615.1.26.11.23)\n        - macOS Ventura 13.3.1\n    validations:\n      required: true\n  - type: dropdown\n    id: priority\n    attributes:\n      label: Issue priority\n      description: Please be realistic. If you need to elaborate on your reasoning, please use the issue description field above.\n      options:\n        - Low (slightly annoying)\n        - Medium (should be fixed soon)\n        - High (immediate attention needed)\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/03-proxy_container_bug_report.yml",
    "content": "name: Proxy Container bug report\ndescription: Report an issue with the proxy container.\nlabels: [bug, need repro, apps:proxy-container]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thank you for filing an issue! If you are here to ask a question, use Discord instead: https://discord.gg/djs\n\n        This issue form is for the proxy container.\n  - type: textarea\n    id: description\n    attributes:\n      label: Issue description\n      description: Describe the issue in as much detail as possible.\n    validations:\n      required: true\n  - type: textarea\n    id: steps_to_reproduce\n    attributes:\n      label: Steps to Reproduce\n      description: What steps must be taken to reproduce this issue?\n      placeholder: |\n        1. Pull the container image\n        2. Run the container with specific configuration\n        3. Send a request\n        4. Observe behavior\n    validations:\n      required: true\n  - type: textarea\n    id: versions\n    attributes:\n      label: Versions\n      description: List necessary versions here. This includes the container image tag, Docker version, operating system etc.\n      placeholder: |\n        - discordjs/proxy 1.0.0\n        - Docker 27.5.1\n        - Linux 6.1.0\n    validations:\n      required: true\n  - type: dropdown\n    id: priority\n    attributes:\n      label: Issue priority\n      description: Please be realistic. If you need to elaborate on your reasoning, please use the issue description field above.\n      options:\n        - Low (slightly annoying)\n        - Medium (should be fixed soon)\n        - High (immediate attention needed)\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/04-feature_request.yml",
    "content": "name: Feature request\ndescription: Request a new feature (discord.js accepts documented features of the official Discord developer API only!)\nlabels: [feature request]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        We can only implement features that Discord publishes, documents, and merges into the Discord API documentation.\n        We do not implement unreleased features.\n        Use Discord for questions: https://discord.gg/djs\n  - type: dropdown\n    id: application_or_package\n    attributes:\n      label: Which application or package is this feature request for?\n      options:\n        - discord.js\n        - Documentation\n        - Guide\n        - Proxy Container\n        - brokers\n        - builders\n        - collection\n        - core\n        - create-discord-bot\n        - formatters\n        - next\n        - proxy\n        - rest\n        - structures\n        - ui\n        - util\n        - voice\n        - ws\n    validations:\n      required: true\n  - type: textarea\n    id: description\n    attributes:\n      label: Feature\n      description: A clear and concise description of what the problem is, or what feature you want to be implemented.\n      placeholder: I'm always frustrated when..., Discord has recently released..., A good addition would be...\n    validations:\n      required: true\n  - type: textarea\n    id: solution\n    attributes:\n      label: Ideal solution or implementation\n      description: A clear and concise description of what you want to happen.\n    validations:\n      required: true\n  - type: textarea\n    id: alternatives\n    attributes:\n      label: Alternative solutions or implementations\n      description: A clear and concise description of any alternative solutions or features you have considered.\n  - type: textarea\n    id: additional_context\n    attributes:\n      label: Other context\n      description: Any other context, screenshots, or file uploads that help us understand your feature request.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/05-guide.yml",
    "content": "name: Guide content\ndescription: Request to add to the guide or change existing content\nlabels: [apps:guide]\ntype: Task\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for filing a suggestion! If you are here to ask a question, use Discord instead: https://discord.gg/djs\n  - type: dropdown\n    id: issuetype\n    attributes:\n      label: What is your suggestion about?\n      options:\n        - Requesting new content\n        - Changing existing content\n        - Correcting wrong information\n    validations:\n      required: true\n  - type: input\n    id: section\n    attributes:\n      label: Guide section the suggestion is about.\n  - type: textarea\n    id: body\n    attributes:\n      label: Describe your suggestion in detail.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Discord server\n    url: https://discord.gg/djs\n    about: Please visit our Discord server for questions and support requests.\n"
  },
  {
    "path": ".github/SUPPORT.md",
    "content": "# Seeking support?\n\nWe only use this issue tracker for bug reports and feature request. We are not able to provide general support or answer questions in the form of GitHub issues.\n\nFor general questions about discord.js installation and use please use the dedicated support channels in our Discord server: https://discord.gg/djs\n\nAny issues that don't directly involve a bug or a feature request will likely be closed and redirected.\n"
  },
  {
    "path": ".github/issue-labeler.yml",
    "content": "apps:guide:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\nGuide\\\\n\"\napps:proxy-container:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\nProxy Container\\\\n\"\napps:website:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\nDocumentation\\\\n\"\npackages:brokers:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\nbrokers\\\\n\"\npackages:builders:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\nbuilders\\\\n\"\npackages:collection:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\ncollection\\\\n\"\npackages:core:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\ncore\\\\n\"\npackages:create-discord-bot:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\ncreate-discord-bot\\\\n\"\npackages:discord.js:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\ndiscord.js\\\\n\"\npackages:formatters:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\nformatters\\\\n\"\npackages:next:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\nnext\\\\n\"\npackages:proxy:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\nproxy\\\\n\"\npackages:rest:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\nrest\\\\n\"\npackages:structures:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\nstructures\\\\n\"\npackages:ui:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\ui\\\\n\"\npackages:util:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\util\\\\n\"\npackages:voice:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\nvoice\\\\n\"\npackages:ws:\n  - \"### Which (application|package|application or package) is this (bug\n    report|feature request) for\\\\?\\\\n\\\\nws\\\\n\"\n"
  },
  {
    "path": ".github/labeler.yml",
    "content": "apps:guide:\n  - changed-files:\n      - any-glob-to-any-file:\n          - apps/guide/*\n          - apps/guide/**/*\napps:proxy-container:\n  - changed-files:\n      - any-glob-to-any-file:\n          - apps/proxy-container/*\n          - apps/proxy-container/**/*\napps:website:\n  - changed-files:\n      - any-glob-to-any-file:\n          - apps/website/*\n          - apps/website/**/*\npackages:api-extractor:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/api-extractor/*\n          - packages/api-extractor/**/*\npackages:api-extractor-model:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/api-extractor-model/*\n          - packages/api-extractor-model/**/*\npackages:brokers:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/brokers/*\n          - packages/brokers/**/*\npackages:builders:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/builders/*\n          - packages/builders/**/*\npackages:collection:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/collection/*\n          - packages/collection/**/*\npackages:core:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/core/*\n          - packages/core/**/*\npackages:create-discord-bot:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/create-discord-bot/*\n          - packages/create-discord-bot/**/*\npackages:discord.js:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/discord.js/*\n          - packages/discord.js/**/*\npackages:docgen:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/docgen/*\n          - packages/docgen/**/*\npackages:formatters:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/formatters/*\n          - packages/formatters/**/*\npackages:next:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/next/*\n          - packages/next/**/*\npackages:proxy:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/proxy/*\n          - packages/proxy/**/*\npackages:rest:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/rest/*\n          - packages/rest/**/*\npackages:structures:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/structures/*\n          - packages/structures/**/*\npackages:ui:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/ui/*\n          - packages/ui/**/*\npackages:util:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/util/*\n          - packages/util/**/*\npackages:voice:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/voice/*\n          - packages/voice/**/*\npackages:ws:\n  - changed-files:\n      - any-glob-to-any-file:\n          - packages/ws/*\n          - packages/ws/**/*\n"
  },
  {
    "path": ".github/labels.yml",
    "content": "- name: api changes\n  color: '5663e9'\n- name: api support\n  color: '5663e9'\n- name: apps:guide\n  color: fbca04\n- name: apps:proxy-container\n  color: fbca04\n- name: apps:website\n  color: fbca04\n- name: backlog\n  color: 7ef7ef\n- name: backport\n  color: 88aabb\n- name: backport-candidate\n  color: 0075ca\n- name: blocked\n  color: fc1423\n- name: bug\n  color: d73a4a\n- name: caching\n  color: 80c042\n- name: chore\n  color: ffffff\n- name: ci\n  color: 0075ca\n- name: dependencies\n  color: 276bd1\n- name: discord\n  color: '5663e9'\n- name: discussion\n  color: b6b1f9\n- name: documentation\n  color: 0075ca\n- name: duplicate\n  color: cfd3d7\n- name: error handling\n  color: 80c042\n- name: feature request\n  color: fcf95a\n- name: gateway\n  color: 80c042\n- name: good first issue\n  color: 7057ff\n- name: help wanted\n  color: '008672'\n- name: in progress\n  color: ffccd7\n- name: in review\n  color: aed5fc\n- name: interactions\n  color: 80c042\n- name: invalid\n  color: e4e669\n- name: need repro\n  color: c66037\n- name: packages:api-extractor\n  color: fbca04\n- name: packages:api-extractor-model\n  color: fbca04\n- name: packages:brokers\n  color: fbca04\n- name: packages:builders\n  color: fbca04\n- name: packages:collection\n  color: fbca04\n- name: packages:core\n  color: fbca04\n- name: packages:create-discord-bot\n  color: fbca04\n- name: packages:discord.js\n  color: fbca04\n- name: packages:docgen\n  color: fbca04\n- name: packages:formatters\n  color: fbca04\n- name: packages:next\n  color: fbca04\n- name: packages:proxy\n  color: fbca04\n- name: packages:rest\n  color: fbca04\n- name: packages:structures\n  color: fbca04\n- name: packages:ui\n  color: fbca04\n- name: packages:util\n  color: fbca04\n- name: packages:voice\n  color: fbca04\n- name: packages:ws\n  color: fbca04\n- name: performance\n  color: 80c042\n- name: permissions\n  color: 80c042\n- name: priority:high\n  color: fc1423\n- name: question (please use Discord instead)\n  color: d876e3\n- name: ratelimits\n  color: 80c042\n- name: refactor\n  color: 1d637f\n- name: regression\n  color: ea8785\n- name: REST\n  color: 80c042\n- name: semver:major\n  color: c10f47\n- name: semver:minor\n  color: e4f486\n- name: semver:patch\n  color: e8be8b\n- name: sharding\n  color: 80c042\n- name: tests\n  color: f06dff\n- name: threads\n  color: 80c042\n- name: typings\n  color: 80c042\n- name: utility\n  color: 80c042\n- name: wontfix\n  color: ffffff\n"
  },
  {
    "path": ".github/tsc.json",
    "content": "{\n\t\"problemMatcher\": [\n\t\t{\n\t\t\t\"owner\": \"tsc\",\n\t\t\t\"pattern\": [\n\t\t\t\t{\n\t\t\t\t\t\"regexp\": \"^(?:\\\\s+\\\\d+\\\\>)?([^\\\\s].*)\\\\((\\\\d+),(\\\\d+)\\\\)\\\\s*:\\\\s+(error|warning|info)\\\\s+(\\\\w{1,2}\\\\d+)\\\\s*:\\\\s*(.*)$\",\n\t\t\t\t\t\"file\": 1,\n\t\t\t\t\t\"line\": 2,\n\t\t\t\t\t\"column\": 3,\n\t\t\t\t\t\"severity\": 4,\n\t\t\t\t\t\"code\": 5,\n\t\t\t\t\t\"message\": 6\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t]\n}\n"
  },
  {
    "path": ".github/workflows/cleanup-cache.yml",
    "content": "# https://docs.github.com/actions/using-workflows/caching-dependencies-to-speed-up-workflows#force-deleting-cache-entries\nname: Cleanup caches\non:\n  pull_request:\n    types:\n      - closed\n  workflow_dispatch:\njobs:\n  cleanup:\n    name: Cleanup caches\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Cleanup caches\n        run: |\n          gh extension install actions/gh-actions-cache\n\n          REPO=${{ github.repository }}\n          BRANCH=\"refs/pull/${{ github.event.pull_request.number }}/merge\"\n\n          echo \"Fetching list of cache key\"\n          cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 )\n\n          ## Setting this to not fail the workflow while deleting cache keys.\n          set +e\n          echo \"Deleting caches...\"\n          for cacheKey in $cacheKeysForPR\n          do\n              gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm\n          done\n          echo \"Done\"\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/deploy-website.yml",
    "content": "name: Deploy website\non:\n  workflow_dispatch:\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}\n  cancel-in-progress: true\njobs:\n  deploy-website:\n    name: Deploy website\n    runs-on: ubuntu-latest\n    env:\n      VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}\n      VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}\n    if: github.repository_owner == 'discordjs'\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Install Node.js v24\n        uses: actions/setup-node@v6\n        with:\n          node-version: 24\n          package-manager-cache: false\n\n      - name: Install dependencies\n        uses: ./packages/actions/src/pnpmCache\n\n      - name: Pull vercel production environment\n        run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}\n\n      - name: Build website artifacts\n        run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}\n\n      - name: Deploy website artifacts to vercel\n        run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/deprecate-version.yml",
    "content": "name: Deprecate version\non:\n  workflow_dispatch:\n    inputs:\n      package:\n        description: Package\n        required: true\n        type: choice\n        options:\n          - '@discordjs/brokers'\n          - '@discordjs/builders'\n          - '@discordjs/collection'\n          - '@discordjs/core'\n          - 'create-discord-app'\n          - 'create-discord-bot'\n          - '@discordjs/formatters'\n          - 'discord.js'\n          - '@discordjs/next'\n          - '@discordjs/proxy'\n          - '@discordjs/rest'\n          - '@discordjs/structures'\n          - '@discordjs/util'\n          - '@discordjs/voice'\n          - '@discordjs/ws'\n      version:\n        description: Version(s)\n        required: true\n        type: string\n      message:\n        description: Deprecation message\n        required: false\n        type: string\njobs:\n  deprecate:\n    runs-on: ubuntu-latest\n    if: github.repository_owner == 'discordjs'\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Install Node.js v24\n        uses: actions/setup-node@v6\n        with:\n          node-version: 24\n          package-manager-cache: false\n\n      - name: Install dependencies\n        uses: ./packages/actions/src/pnpmCache\n\n      - name: Deprecate\n        uses: ./packages/actions/src/deprecateVersion\n        with:\n          package: ${{ inputs.package }}\n          version: ${{ inputs.version }}\n          message: ${{ inputs.message }}\n          node-auth-token: ${{ secrets.NPM_PUBLISH_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/documentation.yml",
    "content": "name: Documentation\non:\n  push:\n    branches:\n      - 'main'\n    paths:\n      - 'packages/*/src/**'\n      - '!packages/create-discord-bot/**'\n      - '!packages/ui/**'\n    tags:\n      - '**'\n      - '!create-discord-app@*'\n      - '!create-discord-bot@*'\n  workflow_dispatch:\n    inputs:\n      ref:\n        description: 'The branch, tag or SHA to checkout'\n        required: true\n      ref_type:\n        type: choice\n        description: 'Branch or tag'\n        options:\n          - branch\n          - tag\n        required: true\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}\n  cancel-in-progress: true\njobs:\n  build-docs:\n    name: Build & upload documentation\n    runs-on: ubuntu-latest\n    env:\n      TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}\n      TURBO_TEAM: ${{ vars.TURBO_TEAM }}\n      REF_TYPE: ${{ inputs.ref_type || github.ref_type }}\n    if: github.repository_owner == 'discordjs'\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n        with:\n          ref: ${{ inputs.ref || '' }}\n\n      - name: Install Node.js v24\n        uses: actions/setup-node@v6\n        with:\n          node-version: 24\n          package-manager-cache: false\n\n      - name: Install dependencies\n        uses: ./packages/actions/src/pnpmCache\n\n      - name: Build dependencies\n        run: pnpm run build\n\n      - name: Checkout main repository\n        if: ${{ inputs.ref && inputs.ref != 'main' }}\n        uses: actions/checkout@v6\n        with:\n          path: 'main'\n\n      - name: Build main\n        if: ${{ inputs.ref && inputs.ref != 'main' }}\n        shell: bash\n        env:\n          COREPACK_ENABLE_STRICT: 0\n        run: |\n          cd main\n          pnpm self-update 10\n          pnpm install --frozen-lockfile --prefer-offline --loglevel error\n          pnpm run build\n          cd ..\n\n      - name: Extract package and semver from tag\n        if: ${{ env.REF_TYPE == 'tag' }}\n        id: extract-tag\n        uses: ./packages/actions/src/formatTag\n        with:\n          tag: ${{ inputs.ref || github.ref_name }}\n\n      - name: Apply tag to api-extractor config\n        if: ${{ env.REF_TYPE == 'tag' && !inputs.ref }}\n        run: sed -i 's!https://github.com/discordjs/discord.js/tree/main!https://github.com/discordjs/discord.js/tree/${{ github.ref_name }}!' \"packages/${{ steps.extract-tag.outputs.package}}/api-extractor.json\"\n\n      - name: Build docs\n        run: pnpm run docs\n\n      - name: Build docs with main api-extractor\n        if: ${{ inputs.ref && inputs.ref != 'main' }}\n        run: |\n          declare -a PACKAGES=(\"brokers\" \"builders\" \"collection\" \"core\" \"discord.js\" \"formatters\" \"next\" \"proxy\" \"rest\" \"structures\" \"util\" \"voice\" \"ws\")\n          for PACKAGE in \"${PACKAGES[@]}\"; do\n            if [ ! -d \"packages/${PACKAGE}\" ]; then\n              echo \"::notice::${PACKAGE} does not exist on this ref. Skipping...\"\n              continue\n            fi\n\n            cd \"packages/${PACKAGE}\"\n            sed -i 's!https://github.com/discordjs/discord.js/tree/main!https://github.com/discordjs/discord.js/tree/${{ inputs.ref }}!' api-extractor.json\n            ../../main/packages/api-extractor/bin/api-extractor run --local --minify\n            ../../main/packages/scripts/bin/generateSplitDocumentation.js\n            cd ../..\n          done\n\n      - name: Upload documentation to database\n        if: ${{ env.REF_TYPE == 'tag' && (!inputs.ref || inputs.ref == 'main') }}\n        env:\n          CF_D1_DOCS_API_KEY: ${{ secrets.CF_D1_DOCS_API_KEY }}\n          CF_D1_DOCS_ID: ${{ secrets.CF_D1_DOCS_ID }}\n          CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}\n          CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}\n          CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}\n          CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}\n          CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}\n          CF_R2_DOCS_BUCKET_URL: ${{ secrets.CF_R2_DOCS_BUCKET_URL }}\n        uses: ./packages/actions/src/uploadDocumentation\n        with:\n          package: ${{ steps.extract-tag.outputs.package }}\n          version: ${{ steps.extract-tag.outputs.semver }}\n\n      - name: Upload documentation to database\n        if: ${{ env.REF_TYPE == 'tag' && inputs.ref && inputs.ref != 'main' }}\n        env:\n          CF_D1_DOCS_API_KEY: ${{ secrets.CF_D1_DOCS_API_KEY }}\n          CF_D1_DOCS_ID: ${{ secrets.CF_D1_DOCS_ID }}\n          CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}\n          CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}\n          CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}\n          CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}\n          CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}\n          CF_R2_DOCS_BUCKET_URL: ${{ secrets.CF_R2_DOCS_BUCKET_URL }}\n        uses: ./main/packages/actions/src/uploadDocumentation\n        with:\n          package: ${{ steps.extract-tag.outputs.package }}\n          version: ${{ steps.extract-tag.outputs.semver }}\n\n      - name: Upload split documentation to blob storage\n        if: ${{ env.REF_TYPE == 'tag' && (!inputs.ref || inputs.ref == 'main') }}\n        env:\n          CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}\n          CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}\n          CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}\n          CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}\n        uses: ./packages/actions/src/uploadSplitDocumentation\n        with:\n          package: ${{ steps.extract-tag.outputs.package }}\n          version: ${{ steps.extract-tag.outputs.semver }}\n\n      - name: Upload split documentation to blob storage\n        if: ${{ env.REF_TYPE == 'tag' && inputs.ref && inputs.ref != 'main' }}\n        env:\n          CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}\n          CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}\n          CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}\n          CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}\n        uses: ./main/packages/actions/src/uploadSplitDocumentation\n        with:\n          package: ${{ steps.extract-tag.outputs.package }}\n          version: ${{ steps.extract-tag.outputs.semver }}\n\n      - name: Upload documentation to database\n        if: ${{ env.REF_TYPE == 'branch' && (!inputs.ref || inputs.ref == 'main') }}\n        env:\n          CF_D1_DOCS_API_KEY: ${{ secrets.CF_D1_DOCS_API_KEY }}\n          CF_D1_DOCS_ID: ${{ secrets.CF_D1_DOCS_ID }}\n          CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}\n          CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}\n          CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}\n          CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}\n          CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}\n          CF_R2_DOCS_BUCKET_URL: ${{ secrets.CF_R2_DOCS_BUCKET_URL }}\n        uses: ./packages/actions/src/uploadDocumentation\n\n      - name: Upload documentation to database\n        if: ${{ env.REF_TYPE == 'branch' && inputs.ref && inputs.ref != 'main' }}\n        env:\n          CF_D1_DOCS_API_KEY: ${{ secrets.CF_D1_DOCS_API_KEY }}\n          CF_D1_DOCS_ID: ${{ secrets.CF_D1_DOCS_ID }}\n          CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}\n          CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}\n          CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}\n          CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}\n          CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}\n          CF_R2_DOCS_BUCKET_URL: ${{ secrets.CF_R2_DOCS_BUCKET_URL }}\n        uses: ./main/packages/actions/src/uploadDocumentation\n\n      - name: Upload split documentation to blob storage\n        if: ${{ env.REF_TYPE == 'branch' && (!inputs.ref || inputs.ref == 'main') }}\n        env:\n          CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}\n          CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}\n          CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}\n          CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}\n        uses: ./packages/actions/src/uploadSplitDocumentation\n\n      - name: Upload split documentation to blob storage\n        if: ${{ env.REF_TYPE == 'branch' && inputs.ref && inputs.ref != 'main' }}\n        env:\n          CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}\n          CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}\n          CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}\n          CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}\n        uses: ./main/packages/actions/src/uploadSplitDocumentation\n\n  build-indices:\n    needs: build-docs\n    name: Build & upload search indices\n    runs-on: ubuntu-latest\n    env:\n      TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}\n      TURBO_TEAM: ${{ vars.TURBO_TEAM }}\n    if: github.repository_owner == 'discordjs'\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Install Node.js v24\n        uses: actions/setup-node@v6\n        with:\n          node-version: 24\n          package-manager-cache: false\n\n      - name: Install dependencies\n        uses: ./packages/actions/src/pnpmCache\n\n      - name: Build dependencies\n        run: pnpm run build\n\n      - name: Upload search indices to meilisearch\n        env:\n          CF_D1_DOCS_API_KEY: ${{ secrets.CF_D1_DOCS_API_KEY }}\n          CF_D1_DOCS_ID: ${{ secrets.CF_D1_DOCS_ID }}\n          CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}\n          SEARCH_API_URL: ${{ secrets.SEARCH_API_URL }}\n          SEARCH_API_KEY: ${{ secrets.SEARCH_API_KEY }}\n        uses: ./packages/actions/src/uploadSearchIndices\n"
  },
  {
    "path": ".github/workflows/issue-triage.yml",
    "content": "name: 'Issue Labeler'\non:\n  issues:\n    types: [opened]\njobs:\n  issue-triage:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: github/issue-labeler@v3.4\n        with:\n          repo-token: '${{ secrets.GITHUB_TOKEN }}'\n          configuration-path: .github/issue-labeler.yml\n          not-before: 2023-01-13T10:25:03.847Z\n          enable-versioned-regex: 0\n"
  },
  {
    "path": ".github/workflows/label-sync.yml",
    "content": "name: Label sync\non:\n  schedule:\n    - cron: '0 0 * * *'\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n    paths:\n      - '.github/labels.yml'\njobs:\n  label-sync:\n    name: Label sync\n    runs-on: ubuntu-latest\n    if: github.repository_owner == 'discordjs'\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Label sync\n        uses: crazy-max/ghaction-github-labeler@v5\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/lock.yml",
    "content": "name: Lock Ancient Issues\non:\n  schedule:\n    - cron: '0 16 * * *'\n  workflow_dispatch:\nconcurrency:\n  group: lock\njobs:\n  action:\n    runs-on: ubuntu-latest\n    permissions:\n      issues: write\n    steps:\n      - uses: dessant/lock-threads@v5\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          issue-inactive-days: 365\n          issue-lock-reason: resolved\n          process-only: issues\n"
  },
  {
    "path": ".github/workflows/pr-triage.yml",
    "content": "name: 'PR Triage'\non:\n  pull_request_target:\n    types:\n      - opened\n      - edited\n      - reopened\n      - synchronize\njobs:\n  label:\n    name: Label\n    if: github.event.action != 'edited'\n    runs-on: ubuntu-latest\n    steps:\n      - name: Label pull request\n        uses: actions/labeler@v5\n        with:\n          repo-token: '${{ secrets.GITHUB_TOKEN }}'\n          sync-labels: true\n  validate-title:\n    name: Validate title\n    runs-on: ubuntu-latest\n    steps:\n      - name: Validate pull request title\n        env:\n          TITLE: ${{ github.event.pull_request.title }}\n        run: |\n          REGEX=\"^(revert: )?(feat|fix|docs|style|refactor|perf|test|build|ci|chore|types)(\\\\(.+\\\\))?!?: .{1,72}$\"\n\n          echo \"Title: \\\"$TITLE\\\"\"\n\n          if [[ ! \"$TITLE\" =~ $REGEX ]]; then\n            exit 1\n          fi\n"
  },
  {
    "path": ".github/workflows/publish-dev-docker.yml",
    "content": "name: Publish dev docker images\non:\n  schedule:\n    - cron: '0 */12 * * *'\n  workflow_dispatch:\nenv:\n  IMAGE_NAME: discordjs/proxy\njobs:\n  build:\n    name: Build ${{ matrix.platform }}\n    runs-on: ${{ matrix.runner }}\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - platform: linux/amd64\n            runner: ubuntu-latest\n          - platform: linux/arm64\n            runner: ubuntu-24.04-arm\n    steps:\n      - name: Prepare\n        run: |\n          platform=${{ matrix.platform }}\n          echo \"PLATFORM_PAIR=${platform//\\//-}\" >> $GITHUB_ENV\n\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v3\n\n      - name: Login to DockerHub\n        uses: docker/login-action@v3\n        with:\n          username: ${{ secrets.DOCKER_USERNAME }}\n          password: ${{ secrets.DOCKER_ACCESS_TOKEN }}\n\n      - name: Build and push by digest\n        id: build\n        uses: docker/build-push-action@v6\n        with:\n          context: .\n          file: apps/proxy-container/Dockerfile\n          platforms: ${{ matrix.platform }}\n          outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true\n\n      - name: Export digest\n        run: |\n          mkdir -p /tmp/digests\n          digest=\"${{ steps.build.outputs.digest }}\"\n          touch \"/tmp/digests/${digest#sha256:}\"\n\n      - name: Upload digest\n        uses: actions/upload-artifact@v5\n        with:\n          name: digests-${{ env.PLATFORM_PAIR }}\n          path: /tmp/digests/*\n          if-no-files-found: error\n          retention-days: 1\n\n  merge:\n    name: Create and push manifest list\n    runs-on: ubuntu-latest\n    needs: build\n    steps:\n      - name: Download digests\n        uses: actions/download-artifact@v6\n        with:\n          path: /tmp/digests\n          pattern: digests-*\n          merge-multiple: true\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v3\n\n      - name: Login to DockerHub\n        uses: docker/login-action@v3\n        with:\n          username: ${{ secrets.DOCKER_USERNAME }}\n          password: ${{ secrets.DOCKER_ACCESS_TOKEN }}\n\n      - name: Create manifest list and push\n        working-directory: /tmp/digests\n        run: |\n          docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:latest \\\n            $(printf '${{ env.IMAGE_NAME }}@sha256:%s ' *)\n\n      - name: Inspect image\n        run: |\n          docker buildx imagetools inspect ${{ env.IMAGE_NAME }}:latest\n"
  },
  {
    "path": ".github/workflows/publish-dev.yml",
    "content": "name: Publish dev\non:\n  schedule:\n    - cron: '0 */12 * * *'\n  workflow_dispatch:\n    inputs:\n      ref:\n        description: 'The ref to check out. e.g. main, feat/new-feature, refs/pull/1234/head'\n        required: false\n        default: 'main'\n      tag:\n        description: 'The tag to use, generally a feature name'\n        required: false\n        type: string\n      dry_run:\n        description: 'Perform a dry run that skips publishing and outputs logs indicating what would have happened'\n        type: boolean\n        default: false\njobs:\n  npm-publish:\n    name: npm publish\n    runs-on: ubuntu-latest\n    permissions:\n      id-token: write\n    env:\n      TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}\n      TURBO_TEAM: ${{ vars.TURBO_TEAM }}\n    if: github.repository_owner == 'discordjs'\n    steps:\n      - uses: actions/create-github-app-token@v2\n        id: app-token\n        with:\n          app-id: ${{ vars.DISCORDJS_APP_ID }}\n          private-key: ${{ secrets.DISCORDJS_APP_KEY_RELEASE }}\n\n      - name: Checkout repository\n        uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n          token: ${{ steps.app-token.outputs.token }}\n          ref: ${{ inputs.ref }}\n\n      - name: Install Node.js v24\n        uses: actions/setup-node@v6\n        with:\n          node-version: 24\n          package-manager-cache: false\n          registry-url: https://registry.npmjs.org/\n\n      - name: Install dependencies\n        uses: ./packages/actions/src/pnpmCache\n\n      - name: Build dependencies\n        run: pnpm run build\n\n      - name: Checkout main repository (non-main ref)\n        if: ${{ inputs.ref != 'main' }}\n        uses: actions/checkout@v6\n        with:\n          path: 'main'\n\n      - name: Install action deps (non-main ref)\n        if: ${{ inputs.ref != 'main' }}\n        shell: bash\n        working-directory: ./main\n        env:\n          COREPACK_ENABLE_STRICT: 0\n        run: |\n          pnpm self-update 10\n          pnpm install --filter @discordjs/actions --frozen-lockfile --prefer-offline --loglevel error\n\n      - name: Publish packages (non-main ref)\n        if: ${{ inputs.ref != 'main' }}\n        uses: ./main/packages/actions/src/releasePackages\n        with:\n          exclude: '@discordjs/docgen'\n          dry: ${{ inputs.dry_run }}\n          dev: true\n          tag: ${{ inputs.tag || 'dev' }}\n        env:\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Publish packages (main ref)\n        if: ${{ inputs.ref == 'main' }}\n        uses: ./packages/actions/src/releasePackages\n        with:\n          exclude: '@discordjs/docgen'\n          dry: ${{ inputs.dry_run }}\n          dev: true\n          tag: ${{ inputs.tag || 'dev' }}\n        env:\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/publish-docker.yml",
    "content": "name: Publish docker images\non:\n  workflow_dispatch:\nenv:\n  IMAGE_NAME: discordjs/proxy\njobs:\n  build:\n    name: Build ${{ matrix.platform }}\n    runs-on: ${{ matrix.runner }}\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - platform: linux/amd64\n            runner: ubuntu-latest\n          - platform: linux/arm64\n            runner: ubuntu-24.04-arm\n    steps:\n      - name: Prepare\n        run: |\n          platform=${{ matrix.platform }}\n          echo \"PLATFORM_PAIR=${platform//\\//-}\" >> $GITHUB_ENV\n\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v3\n\n      - name: Login to DockerHub\n        uses: docker/login-action@v3\n        with:\n          username: ${{ secrets.DOCKER_USERNAME }}\n          password: ${{ secrets.DOCKER_ACCESS_TOKEN }}\n\n      - name: Build and push by digest\n        id: build\n        uses: docker/build-push-action@v6\n        with:\n          context: .\n          file: apps/proxy-container/Dockerfile\n          platforms: ${{ matrix.platform }}\n          outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true\n\n      - name: Export digest\n        run: |\n          mkdir -p /tmp/digests\n          digest=\"${{ steps.build.outputs.digest }}\"\n          touch \"/tmp/digests/${digest#sha256:}\"\n\n      - name: Upload digest\n        uses: actions/upload-artifact@v5\n        with:\n          name: digests-${{ env.PLATFORM_PAIR }}\n          path: /tmp/digests/*\n          if-no-files-found: error\n          retention-days: 1\n\n  merge:\n    name: Create and push manifest list\n    runs-on: ubuntu-latest\n    needs: build\n    steps:\n      - name: Download digests\n        uses: actions/download-artifact@v6\n        with:\n          path: /tmp/digests\n          pattern: digests-*\n          merge-multiple: true\n\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Get Major Version\n        id: version\n        run: |\n          FULL_VER=$(jq --raw-output '.version' apps/proxy-container/package.json)\n          MAJOR=$(echo $FULL_VER | cut -d '.' -f1)\n          echo \"major=$MAJOR\" >> $GITHUB_OUTPUT\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v3\n\n      - name: Login to DockerHub\n        uses: docker/login-action@v3\n        with:\n          username: ${{ secrets.DOCKER_USERNAME }}\n          password: ${{ secrets.DOCKER_ACCESS_TOKEN }}\n\n      - name: Create manifest list and push\n        working-directory: /tmp/digests\n        run: |\n          docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${{ steps.version.outputs.major }} \\\n            $(printf '${{ env.IMAGE_NAME }}@sha256:%s ' *)\n\n      - name: Inspect image\n        run: |\n          docker buildx imagetools inspect ${{ env.IMAGE_NAME }}:${{ steps.version.outputs.major }}\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\non:\n  workflow_dispatch:\n    inputs:\n      ref:\n        description: 'The branch, tag or SHA to checkout'\n        required: true\n        default: 'main'\n      package:\n        description: 'The published name of a single package to release'\n        type: choice\n        required: false\n        options:\n          - all\n          - discord.js\n          - '@discordjs/brokers'\n          - '@discordjs/builders'\n          - '@discordjs/collection'\n          - '@discordjs/core'\n          - 'create-discord-bot'\n          # - '@discordjs/docgen'\n          - '@discordjs/formatters'\n          - '@discordjs/next'\n          - '@discordjs/proxy'\n          - '@discordjs/rest'\n          - '@discordjs/structures'\n          - '@discordjs/util'\n          - '@discordjs/voice'\n          - '@discordjs/ws'\n      exclude:\n        description: 'Comma separated list of packages to exclude from release (if not depended upon)'\n        required: false\n        type: string\n        default: '@discordjs/docgen,@discordjs/next'\n      dry_run:\n        description: Perform a dry run?\n        type: boolean\n        default: false\njobs:\n  npm-publish:\n    name: npm publish\n    runs-on: ubuntu-latest\n    permissions:\n      id-token: write\n    env:\n      TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}\n      TURBO_TEAM: ${{ vars.TURBO_TEAM }}\n    if: github.repository_owner == 'discordjs'\n    steps:\n      - uses: actions/create-github-app-token@v2\n        id: app-token\n        with:\n          app-id: ${{ vars.DISCORDJS_APP_ID }}\n          private-key: ${{ secrets.DISCORDJS_APP_KEY_RELEASE }}\n          permission-contents: write\n\n      - name: Checkout repository\n        uses: actions/checkout@v6\n        with:\n          token: ${{ steps.app-token.outputs.token }}\n          ref: ${{ inputs.ref || '' }}\n\n      - name: Install Node.js v24\n        uses: actions/setup-node@v6\n        with:\n          node-version: 24\n          package-manager-cache: false\n          registry-url: https://registry.npmjs.org/\n\n      - name: Install dependencies\n        uses: ./packages/actions/src/pnpmCache\n\n      - name: Build dependencies\n        run: pnpm run build\n\n      - name: Checkout main repository\n        if: ${{ inputs.ref && inputs.ref != 'main' }}\n        uses: actions/checkout@v6\n        with:\n          path: 'main'\n\n      - name: Install action deps (non-main ref only)\n        if: ${{ inputs.ref && inputs.ref != 'main' }}\n        shell: bash\n        working-directory: ./main\n        env:\n          COREPACK_ENABLE_STRICT: 0\n        run: |\n          pnpm self-update 10\n          pnpm install --filter @discordjs/actions --frozen-lockfile --prefer-offline --loglevel error\n\n      - name: Release packages (non-main ref)\n        if: ${{ inputs.ref && inputs.ref != 'main' }}\n        uses: ./main/packages/actions/src/releasePackages\n        with:\n          package: ${{ inputs.package }}\n          exclude: ${{ inputs.exclude }}\n          dry: ${{ inputs.dry_run }}\n        env:\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}\n          GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}\n\n      - name: Release packages (main ref)\n        if: ${{ !inputs.ref || inputs.ref == 'main' }}\n        uses: ./packages/actions/src/releasePackages\n        with:\n          package: ${{ inputs.package }}\n          exclude: ${{ inputs.exclude }}\n          dry: ${{ inputs.dry_run }}\n        env:\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}\n          GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}\n"
  },
  {
    "path": ".github/workflows/remove-tag.yml",
    "content": "name: Remove tag\non:\n  workflow_dispatch:\n    inputs:\n      tag:\n        description: The tag to remove\n        required: true\n        type: string\n      message:\n        description: Deprecation message\n        required: false\n        type: string\njobs:\n  removal:\n    runs-on: ubuntu-latest\n    if: github.repository_owner == 'discordjs'\n    strategy:\n      matrix:\n        package:\n          - '@discordjs/brokers'\n          - '@discordjs/builders'\n          - '@discordjs/collection'\n          - '@discordjs/core'\n          - 'create-discord-app'\n          - 'create-discord-bot'\n          - '@discordjs/formatters'\n          - 'discord.js'\n          - '@discordjs/next'\n          - '@discordjs/proxy'\n          - '@discordjs/rest'\n          - '@discordjs/structures'\n          - '@discordjs/util'\n          - '@discordjs/voice'\n          - '@discordjs/ws'\n      fail-fast: false\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Install Node.js\n        uses: actions/setup-node@v6\n        with:\n          node-version: 24\n          registry-url: 'https://registry.npmjs.org'\n\n      - name: Install dependencies\n        uses: ./packages/actions/src/pnpmCache\n\n      - name: Remove tag\n        run: pnpm dist-tag rm \"${{ matrix.package }}\" \"${{ inputs.tag }}\"\n        env:\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}\n\n      - name: Deprecate version\n        uses: ./packages/actions/src/deprecateVersion\n        with:\n          package: ${{ matrix.package }}\n          version: '*-${{ inputs.tag }}.*'\n          message: ${{ inputs.message }}\n          node-auth-token: ${{ secrets.NPM_PUBLISH_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "name: Tests\non:\n  push:\n  pull_request:\nconcurrency:\n  # Group based on workflow name and PR if it exists, if no PR, let it run so carryforward flags work\n  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\njobs:\n  tests:\n    name: Tests\n    runs-on: ubuntu-latest\n    env:\n      TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}\n      TURBO_TEAM: ${{ vars.TURBO_TEAM }}\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n\n      - name: Install Node.js v24\n        uses: actions/setup-node@v6\n        with:\n          node-version: 24\n          package-manager-cache: false\n\n      - name: Install dependencies\n        uses: ./packages/actions/src/pnpmCache\n\n      - name: Build dependencies (PR)\n        if: ${{ github.event_name != 'push' }}\n        run: pnpm exec turbo run build --filter=\"...[origin/${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref || 'main' }}]\" --concurrency=4\n\n      - name: Build dependencies (Push)\n        if: ${{ github.event_name == 'push' }}\n        run: pnpm exec turbo run build --filter=\"...[HEAD^1]\" --concurrency=4\n\n      - name: Tests (PR)\n        if: ${{ github.event_name != 'push' }}\n        run: pnpm exec turbo run test --filter=\"...[origin/${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref || 'main' }}]\" --concurrency=4\n\n      - name: Tests (Push)\n        if: ${{ github.event_name == 'push' }}\n        run: pnpm exec turbo run test --filter=\"...[HEAD^1]\" --concurrency=4\n\n      - name: ESLint (PR)\n        if: ${{ github.event_name != 'push' }}\n        run: pnpm exec turbo run lint --filter=\"...[origin/${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref || 'main' }}]\" --concurrency=4 -- --format=compact\n\n      - name: ESLint (Push)\n        if: ${{ github.event_name == 'push' }}\n        run: pnpm exec turbo run lint --filter=\"...[HEAD^1]\" --concurrency=4 -- --format=compact\n\n      - name: Docs (PR)\n        if: ${{ github.event_name != 'push' }}\n        run: pnpm exec turbo run docs --filter=\"...[origin/${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref || 'main' }}]\" --concurrency=4\n\n      - name: Docs (Push)\n        if: ${{ github.event_name == 'push' }}\n        run: pnpm exec turbo run docs --filter=\"...[HEAD^1]\" --concurrency=4\n\n      - name: Upload Coverage\n        if: github.repository_owner == 'discordjs'\n        uses: ./packages/actions/src/uploadCoverage\n        with:\n          codecov_token: ${{ secrets.CODECOV_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/upload-readmes.yml",
    "content": "name: Upload README.md files\non:\n  push:\n    branches:\n      - 'main'\n    paths:\n      - 'packages/*/README.md'\n  workflow_dispatch:\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}\n  cancel-in-progress: true\njobs:\n  upload-readmes:\n    name: Upload README.md files\n    runs-on: ubuntu-latest\n    env:\n      TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}\n      TURBO_TEAM: ${{ vars.TURBO_TEAM }}\n    if: github.repository_owner == 'discordjs'\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Install Node.js\n        uses: actions/setup-node@v6\n        with:\n          node-version: 24\n          package-manager-cache: false\n\n      - name: Install dependencies\n        uses: ./packages/actions/src/pnpmCache\n\n      - name: Build dependencies\n        run: pnpm --filter @discordjs/actions... run build\n\n      - name: Upload README.md files\n        env:\n          CF_R2_READMES_ACCESS_KEY_ID: ${{ secrets.CF_R2_READMES_ACCESS_KEY_ID }}\n          CF_R2_READMES_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_READMES_SECRET_ACCESS_KEY }}\n          CF_R2_READMES_BUCKET: ${{ secrets.CF_R2_READMES_BUCKET }}\n          CF_R2_READMES_URL: ${{ secrets.CF_R2_READMES_URL }}\n        uses: ./packages/actions/src/uploadReadmeFiles\n"
  },
  {
    "path": ".gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\ndist-docs\npackages/discord-api-types\n\n# Miscellaneous\n.tmp\n.vscode/*\n!.vscode/extensions.json\n!.vscode/settings.json\n.idea\n.DS_Store\n.turbo\ntsconfig.tsbuildinfo\ncoverage\nout\npackage.tgz\ntsup.config.bundled*\nvitest.config.ts.timestamp*\n\n# Deno\ndeno.lock\n\n# Bun\nbun.lockb\n\n# yarn\n.pnp.*\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n\n# Cache\n.prettiercache\n.eslintcache\n.vercel\n"
  },
  {
    "path": ".husky/commit-msg",
    "content": "pnpm exec commitlint --edit $1\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "pnpm run build:affected && pnpm exec lint-staged\n"
  },
  {
    "path": ".lintstagedrc.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/lintstagedrc.schema.json\",\n\t\"*\": \"prettier --ignore-unknown --write\",\n\t\"{src/**,__tests__/**}.{mjs,js,cjs,ts,tsx}\": \"eslint --fix\",\n\t\"src/**.ts\": \"vitest related --run --config ../../vitest.config.ts\"\n}\n"
  },
  {
    "path": ".prettierignore",
    "content": "CODEOWNERS\nCHANGELOG.md\ntsup.config.bundled*\nvitest.config.ts.timestamp*\npnpm-lock.yaml\n"
  },
  {
    "path": ".prettierrc.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/prettierrc.json\",\n\t\"printWidth\": 120,\n\t\"useTabs\": true,\n\t\"singleQuote\": true,\n\t\"quoteProps\": \"as-needed\",\n\t\"trailingComma\": \"all\",\n\t\"endOfLine\": \"lf\"\n}\n"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n\t\"recommendations\": [\n\t\t\"esbenp.prettier-vscode\",\n\t\t\"dbaeumer.vscode-eslint\",\n\t\t\"tamasfe.even-better-toml\",\n\t\t\"github.vscode-pull-request-github\",\n\t\t\"codezombiech.gitignore\",\n\t\t\"eamodio.gitlens\",\n\t\t\"christian-kohler.npm-intellisense\",\n\t\t\"christian-kohler.path-intellisense\",\n\t\t\"unifiedjs.vscode-mdx\"\n\t]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n\t\"eslint.validate\": [\"javascript\", \"javascriptreact\", \"typescript\", \"typescriptreact\"],\n\t\"eslint.useESLintClass\": true,\n\t\"eslint.useFlatConfig\": true,\n\t\"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n\t\"editor.formatOnSave\": true,\n\t\"editor.codeActionsOnSave\": {\n\t\t\"source.organizeImports\": \"never\",\n\t\t\"source.fixAll.eslint\": \"always\",\n\t\t\"source.fixAll\": \"always\"\n\t},\n\t\"editor.trimAutoWhitespace\": false,\n\t\"files.associations\": {\n\t\t\"tsconfig.json\": \"jsonc\",\n\t\t\"tsconfig.eslint.json\": \"jsonc\"\n\t},\n\t\"files.insertFinalNewline\": true,\n\t\"files.eol\": \"\\n\",\n\t\"search.exclude\": {\n\t\t\"**/.yarn\": true,\n\t\t\"**/.next\": true,\n\t\t\"**/dist\": true,\n\t\t\"**/coverage\": true,\n\t\t\"**/test-results\": true\n\t},\n\t\"search.followSymlinks\": false,\n\t\"search.useParentIgnoreFiles\": true,\n\t\"files.watcherExclude\": {\n\t\t\"**/.next/*/**\": true,\n\t\t\"**/.yarn/*/**\": true,\n\t\t\"**/coverage/*/**\": true,\n\t\t\"**/dist/*/**\": true,\n\t\t\"**/test-results/*/**\": true\n\t},\n\t\"unocss.disable\": true,\n\t\"npm.packageManager\": \"pnpm\",\n\t\"typescript.tsdk\": \"node_modules/typescript/lib\",\n\t\"typescript.enablePromptUseWorkspaceTsdk\": true,\n\t\"tailwindCSS.experimental.classRegex\": [\n\t\t[\"cva\\\\(((?:[^()]|\\\\([^()]*\\\\))*)\\\\)\", \"[\\\"'`]?([^\\\"'`]+)[\\\"'`]?\"],\n\t\t[\"cx\\\\(((?:[^()]|\\\\([^()]*\\\\))*)\\\\)\", \"(?:'|\\\"|`)([^']*)(?:'|\\\"|`)\"],\n\t\t[\"class:\\\\s*?[\\\"'`]([^\\\"'`]*).*?,\"]\n\t],\n\t\"workbench.editor.customLabels.patterns\": {\n\t\t\"**/app/**/page.tsx\": \"${dirname} (${filename}.${extname}) - Page\",\n\t\t\"**/app/**/layout.tsx\": \"${dirname} (${filename}.${extname}) - Layout\",\n\t\t\"**/app/**/template.tsx\": \"${dirname} (${filename}.${extname}) - Template\",\n\t\t\"**/app/**/error.tsx\": \"${dirname} (${filename}.${extname}) - Error\",\n\t\t\"**/app/**/not-found.tsx\": \"${dirname} (${filename}.${extname}) - Not Found\",\n\t\t\"**/components/**/page.tsx\": \"${dirname} (${filename}.${extname}) - Component\"\n\t},\n\t\"deno.enable\": false,\n\t\"deno.enablePaths\": [\"./packages/create-discord-bot/template/Deno\"],\n\t\"deno.lint\": false,\n\t\"deno.unstable\": [],\n\t\"deno.config\": \"./packages/create-discord-bot/template/Deno/deno.jsonc\"\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2021 Noel Buechler\n   Copyright 2015 Amish Shah\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/discord.js\"><img src=\"https://img.shields.io/npm/v/discord.js.svg?maxAge=3600\" alt=\"npm version\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/discord.js\"><img src=\"https://img.shields.io/npm/dt/discord.js.svg?maxAge=3600\" alt=\"npm downloads\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Tests status\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/commits/main\"><img src=\"https://img.shields.io/github/last-commit/discordjs/discord.js.svg?logo=github&logoColor=ffffff\" alt=\"Last commit.\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/graphs/contributors\"><img src=\"https://img.shields.io/github/contributors/discordjs/discord.js.svg?maxAge=3600&logo=github&logoColor=fff&color=00c7be\" alt=\"contributors\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t\t<a href=\"https://codecov.io/gh/discordjs/discord.js\"><img src=\"https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2\" alt=\"Code coverage\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## About\n\nThis repository contains multiple packages with separate [releases][github-releases]. You can find the assembled Discord API wrapper at [`discord.js`][source]. It is a powerful [Node.js](https://nodejs.org/en) module that allows you to easily interact with the [Discord API](https://discord.com/developers/docs/intro).\n\n## Packages\n\n- `discord.js` ([source][source]) - A powerful Node.js module for interacting with the Discord API\n- `create-discord-bot` ([source][create-discord-bot-source]) - A CLI tool to quickly scaffold a Discord bot project\n- `@discordjs/brokers` ([source][brokers-source]) - A collection of brokers for use with discord.js\n- `@discordjs/builders` ([source][builders-source]) - A utility package for easily building Discord API payloads\n- `@discordjs/collection` ([source][collection-source]) - A powerful utility data structure\n- `@discordjs/core` ([source][core-source]) - A thinly abstracted wrapper around the core components of the Discord API\n- `@discordjs/formatters` ([source][formatters-source]) - A collection of functions for formatting strings\n- `@discordjs/proxy` ([source][proxy-source]) - A wrapper around `@discordjs/rest` for running an HTTP proxy\n- `@discordjs/rest` ([source][rest-source]) - A module for interacting with the Discord REST API\n- `@discordjs/structures` ([source][structures-source]) - A wrapper around Discord's structures\n- `@discordjs/util` ([source][util-source]) - A collection of utility functions\n- `@discordjs/voice` ([source][voice-source]) - A module for interacting with the Discord Voice API\n- `@discordjs/ws` ([source][ws-source]) - A wrapper around Discord's gateway\n\n## Containers\n\n- `discordjs/proxy` ([source][proxy-container-source]) - A lightweight HTTP proxy for Discord's API\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Documentation][documentation]\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [npm][npm]\n- [Related libraries][related-libs]\n\n### Extensions\n\n- [RPC][rpc] ([source][rpc-source])\n\n## Contributing\n\nPlease read through our [contribution guidelines][contributing] before starting a pull request. We welcome contributions of all kinds, not just code! If you're stuck for ideas, look for the [good first issue][good-first-issue] label on issues in the repository. If you have any questions about the project, feel free to ask them on [Discord][discord]. Before creating your own issue or pull request, always check to see if one already exists! Don't rush contributions, take your time and ensure you're doing it correctly.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please join our [Discord server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/discord.js\n[npm]: https://www.npmjs.com/package/discord.js\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[rpc]: https://www.npmjs.com/package/discord-rpc\n[rpc-source]: https://github.com/discordjs/RPC\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n[github-releases]: https://github.com/discordjs/discord.js/releases\n[create-discord-bot-source]: https://github.com/discordjs/discord.js/tree/main/packages/create-discord-bot\n[brokers-source]: https://github.com/discordjs/discord.js/tree/main/packages/brokers\n[builders-source]: https://github.com/discordjs/discord.js/tree/main/packages/builders\n[collection-source]: https://github.com/discordjs/discord.js/tree/main/packages/collection\n[core-source]: https://github.com/discordjs/discord.js/tree/main/packages/core\n[formatters-source]: https://github.com/discordjs/discord.js/tree/main/packages/formatters\n[proxy-source]: https://github.com/discordjs/discord.js/tree/main/packages/proxy\n[rest-source]: https://github.com/discordjs/discord.js/tree/main/packages/rest\n[structures-source]: https://github.com/discordjs/discord.js/tree/main/packages/structures\n[util-source]: https://github.com/discordjs/discord.js/tree/main/packages/util\n[voice-source]: https://github.com/discordjs/discord.js/tree/main/packages/voice\n[ws-source]: https://github.com/discordjs/discord.js/tree/main/packages/ws\n[proxy-container-source]: https://github.com/discordjs/discord.js/tree/main/apps/proxy-container\n[good-first-issue]: https://github.com/discordjs/discord.js/contribute\n"
  },
  {
    "path": "api-extractor.json",
    "content": "/**\n * Config file for API Extractor.  For more info, please visit: https://api-extractor.com\n */\n{\n\t\"$schema\": \"https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json\",\n\n\t/**\n\t * Optionally specifies another JSON config file that this file extends from.  This provides a way for\n\t * standard settings to be shared across multiple projects.\n\t *\n\t * If the path starts with \"./\" or \"../\", the path is resolved relative to the folder of the file that contains\n\t * the \"extends\" field.  Otherwise, the first path segment is interpreted as an NPM package name, and will be\n\t * resolved using NodeJS require().\n\t *\n\t * SUPPORTED TOKENS: none\n\t * DEFAULT VALUE: \"\"\n\t */\n\t// \"extends\": \"./shared/api-extractor-base.json\"\n\t// \"extends\": \"my-package/include/api-extractor-base.json\"\n\n\t/**\n\t * Determines the \"<projectFolder>\" token that can be used with other config file settings.  The project folder\n\t * typically contains the tsconfig.json and package.json config files, but the path is user-defined.\n\t *\n\t * The path is resolved relative to the folder of the config file that contains the setting.\n\t *\n\t * The default value for \"projectFolder\" is the token \"<lookup>\", which means the folder is determined by traversing\n\t * parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder\n\t * that contains a tsconfig.json file.  If a tsconfig.json file cannot be found in this way, then an error\n\t * will be reported.\n\t *\n\t * SUPPORTED TOKENS: <lookup>\n\t * DEFAULT VALUE: \"<lookup>\"\n\t */\n\t// \"projectFolder\": \"..\",\n\n\t/**\n\t * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis.  API Extractor\n\t * analyzes the symbols exported by this module.\n\t *\n\t * The file extension must be \".d.ts\" and not \".ts\".\n\t *\n\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t * prepend a folder token such as \"<projectFolder>\".\n\t *\n\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t */\n\t\"mainEntryPointFilePath\": \"<projectFolder>/dist-docs/index.d.ts\",\n\n\t/**\n\t * A list of NPM package names whose exports should be treated as part of this package.\n\t *\n\t * For example, suppose that Webpack is used to generate a distributed bundle for the project \"library1\",\n\t * and another NPM package \"library2\" is embedded in this bundle.  Some types from library2 may become part\n\t * of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly\n\t * imports library2.  To avoid this, we can specify:\n\t *\n\t *   \"bundledPackages\": [ \"library2\" ],\n\t *\n\t * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been\n\t * local files for library1.\n\t */\n\t\"bundledPackages\": [],\n\n\t/**\n\t * Determines how the TypeScript compiler engine will be invoked by API Extractor.\n\t */\n\t\"compiler\": {\n\t\t/**\n\t\t * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project.\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * Note: This setting will be ignored if \"overrideTsconfig\" is used.\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"<projectFolder>/tsconfig.json\"\n\t\t */\n\t\t// \"tsconfigFilePath\": \"<projectFolder>/tsconfig.json\",\n\t\t/**\n\t\t * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk.\n\t\t * The object must conform to the TypeScript tsconfig schema:\n\t\t *\n\t\t * http://json.schemastore.org/tsconfig\n\t\t *\n\t\t * If omitted, then the tsconfig.json file will be read from the \"projectFolder\".\n\t\t *\n\t\t * DEFAULT VALUE: no overrideTsconfig section\n\t\t */\n\t\t\"overrideTsconfig\": {\n\t\t\t\"compilerOptions\": {\n\t\t\t\t// Type Checking\n\t\t\t\t\"allowUnreachableCode\": false,\n\t\t\t\t\"allowUnusedLabels\": false,\n\t\t\t\t\"exactOptionalPropertyTypes\": true,\n\t\t\t\t\"noFallthroughCasesInSwitch\": true,\n\t\t\t\t\"noImplicitOverride\": true,\n\t\t\t\t\"noImplicitReturns\": true,\n\t\t\t\t\"noPropertyAccessFromIndexSignature\": false,\n\t\t\t\t\"noUncheckedIndexedAccess\": true,\n\t\t\t\t\"noUnusedLocals\": true,\n\t\t\t\t\"noUnusedParameters\": true,\n\t\t\t\t\"strict\": true,\n\n\t\t\t\t// Modules\n\t\t\t\t\"allowArbitraryExtensions\": false,\n\t\t\t\t\"allowImportingTsExtensions\": false,\n\t\t\t\t\"module\": \"ESNext\",\n\t\t\t\t\"moduleResolution\": \"Bundler\",\n\t\t\t\t\"resolveJsonModule\": true,\n\t\t\t\t\"resolvePackageJsonExports\": false,\n\t\t\t\t\"resolvePackageJsonImports\": false,\n\n\t\t\t\t// Emit\n\t\t\t\t\"declaration\": true,\n\t\t\t\t\"declarationMap\": true,\n\t\t\t\t\"importHelpers\": false,\n\t\t\t\t\"newLine\": \"lf\",\n\t\t\t\t\"noEmitHelpers\": true,\n\t\t\t\t\"outDir\": \"dist\",\n\t\t\t\t\"removeComments\": false,\n\t\t\t\t\"sourceMap\": true,\n\n\t\t\t\t// Interop Constraints\n\t\t\t\t\"esModuleInterop\": false,\n\t\t\t\t\"forceConsistentCasingInFileNames\": true,\n\t\t\t\t\"isolatedModules\": true,\n\n\t\t\t\t// Language and Environment\n\t\t\t\t\"experimentalDecorators\": true,\n\t\t\t\t\"lib\": [\"ESNext\"],\n\t\t\t\t\"target\": \"ES2022\",\n\t\t\t\t\"useDefineForClassFields\": true\n\t\t\t}\n\t\t}\n\t\t/**\n\t\t * This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended\n\t\t * and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when\n\t\t * dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses\n\t\t * for its analysis.  Where possible, the underlying issue should be fixed rather than relying on skipLibCheck.\n\t\t *\n\t\t * DEFAULT VALUE: false\n\t\t */\n\t\t// \"skipLibCheck\": true,\n\t},\n\n\t/**\n\t * Configures how the API report file (*.api.md) will be generated.\n\t */\n\t\"apiReport\": {\n\t\t/**\n\t\t * (REQUIRED) Whether to generate an API report.\n\t\t */\n\t\t\"enabled\": false\n\n\t\t/**\n\t\t * The filename for the API report files.  It will be combined with \"reportFolder\" or \"reportTempFolder\" to produce\n\t\t * a full file path.\n\t\t *\n\t\t * The file extension should be \".api.md\", and the string should not contain a path separator such as \"\\\" or \"/\".\n\t\t *\n\t\t * SUPPORTED TOKENS: <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"<unscopedPackageName>.api.md\"\n\t\t */\n\t\t// \"reportFileName\": \"<unscopedPackageName>.api.md\",\n\n\t\t/**\n\t\t * Specifies the folder where the API report file is written.  The file name portion is determined by\n\t\t * the \"reportFileName\" setting.\n\t\t *\n\t\t * The API report file is normally tracked by Git.  Changes to it can be used to trigger a branch policy,\n\t\t * e.g. for an API review.\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"<projectFolder>/temp/\"\n\t\t */\n\t\t// \"reportFolder\": \"<projectFolder>/temp/\",\n\n\t\t/**\n\t\t * Specifies the folder where the temporary report file is written.  The file name portion is determined by\n\t\t * the \"reportFileName\" setting.\n\t\t *\n\t\t * After the temporary file is written to disk, it is compared with the file in the \"reportFolder\".\n\t\t * If they are different, a production build will fail.\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"<projectFolder>/temp/\"\n\t\t */\n\t\t// \"reportTempFolder\": \"<projectFolder>/temp/\"\n\t},\n\n\t/**\n\t * Configures how the doc model file (*.api.json) will be generated.\n\t */\n\t\"docModel\": {\n\t\t/**\n\t\t * (REQUIRED) Whether to generate a doc model file.\n\t\t */\n\t\t\"enabled\": true,\n\n\t\t/**\n\t\t * The output path for the doc model file.  The file extension should be \".api.json\".\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"<projectFolder>/temp/<unscopedPackageName>.api.json\"\n\t\t */\n\t\t\"apiJsonFilePath\": \"<projectFolder>/docs/docs.api.json\"\n\t},\n\n\t/**\n\t * Configures how the .d.ts rollup file will be generated.\n\t */\n\t\"dtsRollup\": {\n\t\t/**\n\t\t * (REQUIRED) Whether to generate the .d.ts rollup file.\n\t\t */\n\t\t\"enabled\": false,\n\n\t\t/**\n\t\t * Specifies the output path for a .d.ts rollup file to be generated without any trimming.\n\t\t * This file will include all declarations that are exported by the main entry point.\n\t\t *\n\t\t * If the path is an empty string, then this file will not be written.\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"<projectFolder>/dist/<unscopedPackageName>.d.ts\"\n\t\t */\n\t\t\"untrimmedFilePath\": \"<projectFolder>/dist-docs/index.d.ts\"\n\n\t\t/**\n\t\t * Specifies the output path for a .d.ts rollup file to be generated with trimming for an \"alpha\" release.\n\t\t * This file will include only declarations that are marked as \"@public\", \"@beta\", or \"@alpha\".\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"\"\n\t\t */\n\t\t// \"alphaTrimmedFilePath\": \"<projectFolder>/dist/<unscopedPackageName>-alpha.d.ts\",\n\n\t\t/**\n\t\t * Specifies the output path for a .d.ts rollup file to be generated with trimming for a \"beta\" release.\n\t\t * This file will include only declarations that are marked as \"@public\" or \"@beta\".\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"\"\n\t\t */\n\t\t// \"betaTrimmedFilePath\": \"<projectFolder>/dist/<unscopedPackageName>-beta.d.ts\",\n\n\t\t/**\n\t\t * Specifies the output path for a .d.ts rollup file to be generated with trimming for a \"public\" release.\n\t\t * This file will include only declarations that are marked as \"@public\".\n\t\t *\n\t\t * If the path is an empty string, then this file will not be written.\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"\"\n\t\t */\n\t\t// \"publicTrimmedFilePath\": \"<projectFolder>/dist/<unscopedPackageName>-public.d.ts\",\n\n\t\t/**\n\t\t * When a declaration is trimmed, by default it will be replaced by a code comment such as\n\t\t * \"Excluded from this release type: exampleMember\".  Set \"omitTrimmingComments\" to true to remove the\n\t\t * declaration completely.\n\t\t *\n\t\t * DEFAULT VALUE: false\n\t\t */\n\t\t// \"omitTrimmingComments\": true\n\t},\n\n\t/**\n\t * Configures how the tsdoc-metadata.json file will be generated.\n\t */\n\t\"tsdocMetadata\": {\n\t\t/**\n\t\t * Whether to generate the tsdoc-metadata.json file.\n\t\t *\n\t\t * DEFAULT VALUE: true\n\t\t */\n\t\t// \"enabled\": true,\n\t\t/**\n\t\t * Specifies where the TSDoc metadata file should be written.\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * The default value is \"<lookup>\", which causes the path to be automatically inferred from the \"tsdocMetadata\",\n\t\t * \"typings\" or \"main\" fields of the project's package.json.  If none of these fields are set, the lookup\n\t\t * falls back to \"tsdoc-metadata.json\" in the package folder.\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"<lookup>\"\n\t\t */\n\t\t// \"tsdocMetadataFilePath\": \"<projectFolder>/dist/tsdoc-metadata.json\"\n\t},\n\n\t/**\n\t * Specifies what type of newlines API Extractor should use when writing output files.  By default, the output files\n\t * will be written with Windows-style newlines.  To use POSIX-style newlines, specify \"lf\" instead.\n\t * To use the OS's default newline kind, specify \"os\".\n\t *\n\t * DEFAULT VALUE: \"crlf\"\n\t */\n\t\"newlineKind\": \"lf\",\n\n\t/**\n\t * Configures how API Extractor reports error and warning messages produced during analysis.\n\t *\n\t * There are three sources of messages:  compiler messages, API Extractor messages, and TSDoc messages.\n\t */\n\t\"messages\": {\n\t\t/**\n\t\t * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing\n\t\t * the input .d.ts files.\n\t\t *\n\t\t * TypeScript message identifiers start with \"TS\" followed by an integer.  For example: \"TS2551\"\n\t\t *\n\t\t * DEFAULT VALUE:  A single \"default\" entry with logLevel=warning.\n\t\t */\n\t\t\"compilerMessageReporting\": {\n\t\t\t/**\n\t\t\t * Configures the default routing for messages that don't match an explicit rule in this table.\n\t\t\t */\n\t\t\t\"default\": {\n\t\t\t\t/**\n\t\t\t\t * Specifies whether the message should be written to the the tool's output log.  Note that\n\t\t\t\t * the \"addToApiReportFile\" property may supersede this option.\n\t\t\t\t *\n\t\t\t\t * Possible values: \"error\", \"warning\", \"none\"\n\t\t\t\t *\n\t\t\t\t * Errors cause the build to fail and return a nonzero exit code.  Warnings cause a production build fail\n\t\t\t\t * and return a nonzero exit code.  For a non-production build (e.g. when \"api-extractor run\" includes\n\t\t\t\t * the \"--local\" option), the warning is displayed but the build will not fail.\n\t\t\t\t *\n\t\t\t\t * DEFAULT VALUE: \"warning\"\n\t\t\t\t */\n\t\t\t\t\"logLevel\": \"warning\"\n\n\t\t\t\t/**\n\t\t\t\t * When addToApiReportFile is true:  If API Extractor is configured to write an API report file (.api.md),\n\t\t\t\t * then the message will be written inside that file; otherwise, the message is instead logged according to\n\t\t\t\t * the \"logLevel\" option.\n\t\t\t\t *\n\t\t\t\t * DEFAULT VALUE: false\n\t\t\t\t */\n\t\t\t\t// \"addToApiReportFile\": false\n\t\t\t}\n\n\t\t\t// \"TS2551\": {\n\t\t\t//   \"logLevel\": \"warning\",\n\t\t\t//   \"addToApiReportFile\": true\n\t\t\t// },\n\t\t\t//\n\t\t\t// . . .\n\t\t},\n\n\t\t/**\n\t\t * Configures handling of messages reported by API Extractor during its analysis.\n\t\t *\n\t\t * API Extractor message identifiers start with \"ae-\".  For example: \"ae-extra-release-tag\"\n\t\t *\n\t\t * DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings\n\t\t */\n\t\t\"extractorMessageReporting\": {\n\t\t\t\"default\": {\n\t\t\t\t\"logLevel\": \"warning\"\n\t\t\t\t// \"addToApiReportFile\": false\n\t\t\t},\n\n\t\t\t// Disable the following warning:\n\t\t\t// (ae-missing-release-tag) \"x\" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal)\n\t\t\t\"ae-missing-release-tag\": {\n\t\t\t\t\"logLevel\": \"none\"\n\t\t\t}\n\n\t\t\t// \"ae-extra-release-tag\": {\n\t\t\t//   \"logLevel\": \"warning\",\n\t\t\t//   \"addToApiReportFile\": true\n\t\t\t// },\n\t\t\t//\n\t\t\t// . . .\n\t\t},\n\n\t\t/**\n\t\t * Configures handling of messages reported by the TSDoc parser when analyzing code comments.\n\t\t *\n\t\t * TSDoc message identifiers start with \"tsdoc-\".  For example: \"tsdoc-link-tag-unescaped-text\"\n\t\t *\n\t\t * DEFAULT VALUE:  A single \"default\" entry with logLevel=warning.\n\t\t */\n\t\t\"tsdocMessageReporting\": {\n\t\t\t\"default\": {\n\t\t\t\t\"logLevel\": \"warning\"\n\t\t\t\t// \"addToApiReportFile\": false\n\t\t\t}\n\n\t\t\t// \"tsdoc-link-tag-unescaped-text\": {\n\t\t\t//   \"logLevel\": \"warning\",\n\t\t\t//   \"addToApiReportFile\": true\n\t\t\t// },\n\t\t\t//\n\t\t\t// . . .\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "apps/guide/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n.env*.local\n\n# Dist\n.open-next\n.next\n.wrangler\n.source\n\n# Miscellaneous\n.tmp\n.vscode\n.vercel\nnext-env.d.ts\n"
  },
  {
    "path": "apps/guide/.lintstagedrc.cjs",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "apps/guide/.prettierignore",
    "content": ".next\n.turbo\n.vscode\ncoverage\nsrc/assets/readme\nsrc/styles/unocss.css\nnext-env.d.ts\n.source\n"
  },
  {
    "path": "apps/guide/.prettierrc.cjs",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = {\n\t...require('../../.prettierrc.json'),\n\tplugins: ['prettier-plugin-tailwindcss'],\n\ttailwindFunctions: ['cva', 'cx'],\n};\n"
  },
  {
    "path": "apps/guide/CONTRIBUTING.md",
    "content": "# Contributing\n\n## Local development\n\nClone the code base into a local folder, `cd` into it, and install the dependencies:\n\n```bash\ngit clone https://github.com/discordjs/discord.js.git\ncd discord.js/apps/guide\npnpm --filter guide install\n```\n\nYou can and should use `pnpm dev` to check your changes out locally before pushing them for review.\n\n## Adding pages\n\nTo add a new page to the guide, create a `filename.mdx` file in the folder of your choice located under `/content`. Fumadocs will pick it up and route appropriately. To list the section in the sidebar, make sure it is listed in the `meta.json` file of the directory you placed it in under the `pages` key. The order in the `pages` array determines the order pages have in the sidebar.\n\n## Framework and components\n\nThe guide uses the fumadocs documentation framework for Next.js. You can find examples as well as documentation for the components you can use at <https://fumadocs.dev/docs/ui>.\n\n## General guidelines\n\nPlease try your best to follow the guidelines below. They help to make the guide appear as a coherent piece of work rather than a collection of disconnected pieces with different writing styles.\n\n### Spelling, grammar, and wording\n\nImproper grammar, strange wording, and incorrect spelling are all things that may lead to confusion when a user reads a guide page. It's important to attempt to keep the content clear and consistent. Re-read what you've written and place yourself in the shoes of someone else for a moment to see if you can fully understand everything without any confusion.\n\nDon't worry if you aren't super confident with your grammar/spelling/wording skills; all pull requests get thoroughly reviewed, and comments are left in areas that need to be fixed or could be done better/differently.\n\n#### \"You\"/\"your\" instead of \"we\"/\"our\"\n\nWhen explaining parts of the guide, we recommend to use \"you\" instead of \"we\" when referring to the read or things they can do:\n\n```diff\n- To check our Node version, we can run `node -v`.\n+ To check your Node version, you can run `node -v`.\n\n- To delete a message, we can do: `message.delete();`\n+ To delete a message, you can do: `message.delete();`\n\n- Our final code should look like this: ...\n+ Your final code should look like this: ...\n\n- Before we can actually do this, we need to update our configuration file.\n+ Before you can actually do this, you need to update your configuration file.\n```\n\n#### \"We\" instead of \"I\"\n\nWhen referring to yourself, use \"we\" (as in \"the writers of this guide\") instead of \"I\". For example:\n\n```diff\n- If you don't already have this package installed, I would highly recommend doing so.\n+ If you don't already have this package installed, we would highly recommend doing so.\n# Valid alternative:\n+ If you don't already have this package installed, it's highly recommended that you do so.\n\n- In this section, I'll be covering how to do that really cool thing everyone's asking about.\n+ In this section, we'll be covering how to do that really cool thing everyone's asking about.\n```\n\n#### Inclusive language\n\nTry to avoid using gendered and otherwise non-inclusive language. The following are just examples to give you an idea of what we expect. Don't understand this as a complete list of \"banned terms\":\n\n- Use they/them/their instead of gendered pronouns (he/him/his, she/her/hers).\n- Avoid using \"master\" and \"slave\", you can use \"primary\" and \"replica\" or \"secondary\" instead.\n- Avoid gendered terms like \"guys\", \"folks\" and \"people\" work just as well.\n- Avoid ableist terms \"sanity check\", use \"confidence check\" or \"coherence check\" instead.\n- Avoid talking about \"dummy\" values, call them \"placeholder\" or \"sample value\" instead.\n\n### Paragraph structure\n\nTry to keep guide articles formatted nicely and easy to read. If paragraphs get too long, you can usually split them up where they introduce a new concept or facet. Adding a bit of spacing can make the guide easier to digest and follow! Try to avoid run-on sentences with many embedded clauses.\n\n## Semantic components\n\nYou can find the full documentation for the guide framework at <https://fumadocs.dev/docs/ui/>. If you are unsure what to use when, consider looking through the existing guide pages and how they approach things.\n\n### Callouts\n\nYou can use [Callouts](https://fumadocs.dev/docs/ui/markdown#callouts) to describe additional context that doesn't fully fit into the flow of the paragraph or requires special attention. Prefer to MDX syntax `<Callout />` over Remark `:::` admonitions.\n\n### Code\n\nFumadocs integrates [Shiki transformers](https://fumadocs.dev/docs/ui/markdown#shiki-transformers) for visual highlighting through the use of [Rhype Code](https://fumadocs.dev/docs/headless/mdx/rehype-code).\n\nWhen describing changes or additions to code, prefer using the appropriate language (`js` in most cases for this guide) with diff transformers over `diff` highlights:\n\n```js\nconsole.log('Hello'); // [!code --]\nconsole.log('Hello World'); // [!code ++]\n```\n\nYou can put the transformer syntax above the respective line and declare ranges instead of repeating formatting intsructions. You can also combine different transformers on the same line. Note that word highlights highlight the word across the code block by default, but do respect ranges.\n\n```js\nconsole.log('Hello'); // [!code --:2]\nconsole.log('World');\n// [!code ++]\nconsole.log('Hello World');\n```\n\n```js\n// ...\n// [!code focus:2] [!code word:log:1]\nconsole.log('Hello World!'); // this instance of \"log\" is highlighted\nconsole.log('Foobar'); // this one is not\n// ...\n```\n\nWhen introducing new functions in a paragraph, consider highlighting them in the following code snippet to draw additional attention to their use. For example, if you just described the `log` function:\n\n```js\nconsole.log('Hello World'); // [!code word:log]\n```\n\nMake sure to denote the file names or paths if you describe progress in a specific code sample. When descrbing multiple files, use [tab groups](https://fumadocs.dev/docs/ui/markdown#tab-groups).\n\n````md\n```json title=\"package.json\" tab=\"Configuration\"\n{ ... }\n```\n\n```js tab=\"Usage\"\n// code showing how to use what is being configured\n```\n````\n\n### Directory Structure\n\nYou can use the [Files](https://fumadocs.dev/docs/ui/components/files) component to visualize the expected directory structure, if it is relevant to the approach you describe.\n"
  },
  {
    "path": "apps/guide/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2022 Noel Buechler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "apps/guide/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Documentation][documentation]\n- [Guide][guide] ([source][guide-source])\n- [discord.js Discord server][discord]\n- [GitHub][source]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the existing guide. See [the contributing guide][contributing] if you'd like to submit a pull request.\n\n## Local Development\n\nTo install and run just the guide portion of the repository for development, you can install dependencies with `pnpm --filter guide install` and serve a development version of the guide on localhost with `pnpm dev`.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/additional-features/cooldowns.mdx",
    "content": "---\ntitle: Cooldowns\n---\n\nSpam is something you generally want to avoid, especially if one of your commands require calls to other APIs or takes a bit of time to build/send.\n\n<Callout>\n\tThis section assumes you followed the [Command Handling](../app-creation/handling-commands) part of the guide.\n</Callout>\n\nFirst, add a cooldown property to your command. This will determine how long the user would have to wait (in seconds) before using the command again.\n\n```js title=\"commands/utility/ping.js\"\nconst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tcooldown: 5, // [!code ++]\n\tdata: new SlashCommandBuilder().setName('ping').setDescription('Replies with Pong!'),\n\tasync execute(interaction) {\n\t\t// ...\n\t},\n};\n```\n\nIn your main file, initialize a [Collection](../additional-info/collections) to store cooldowns of commands:\n\n```js\nclient.cooldowns = new Collection();\n```\n\nThe key will be the command names, and the values will be Collections associating the user's id (key) to the last time (value) this user used this command. Overall the logical path to get a user's last usage of a command will be `cooldowns > command > user > timestamp`.\n\nIn your `InteractionCreate` event handler, add the following code:\n\n```js title=\"index.js / interactionCreate.js (if you followed the event handler section)\"\n// ...\n// [!code ++:14]\nconst { cooldowns } = interaction.client;\n\nif (!cooldowns.has(command.data.name)) {\n\tcooldowns.set(command.data.name, new Collection());\n}\n\nconst now = Date.now();\nconst timestamps = cooldowns.get(command.data.name);\nconst defaultCooldownDuration = 3;\nconst cooldownAmount = (command.cooldown ?? defaultCooldownDuration) * 1_000;\n\nif (timestamps.has(interaction.user.id)) {\n\t// ...\n}\n```\n\nYou check if the `cooldowns` Collection already has an entry for the command being used. If this is not the case, you can add a new entry, where the value is initialized as an empty Collection. Next, create the following variables:\n\n1. `now`: The current timestamp.\n2. `timestamps`: A reference to the Collection of user ids and timestamp key/value pairs for the triggered command.\n3. `cooldownAmount`: The specified cooldown for the command, converted to milliseconds for straightforward calculation. If none is specified, this defaults to three seconds.\n\nIf the user has already used this command in this session, get the timestamp, calculate the expiration time, and inform the user of the amount of time they need to wait before using this command again. Note the use of the `return` statement here, causing the code below this snippet to execute only if the user has not used this command in this session or the wait has already expired.\n\nContinuing with your current setup, this is the complete `if` statement:\n\n```js title=\"index.js / interactionCreate.js (if you followed the event handler section)\"\nconst defaultCooldownDuration = 3;\nconst cooldownAmount = (command.cooldown ?? defaultCooldownDuration) * 1_000;\n\n// [!code focus:13]\nif (timestamps.has(interaction.user.id)) {\n\t// ... // [!code --]\n\t// [!code ++:9]\n\tconst expirationTime = timestamps.get(interaction.user.id) + cooldownAmount;\n\n\tif (now < expirationTime) {\n\t\tconst expiredTimestamp = Math.round(expirationTime / 1_000);\n\t\treturn interaction.reply({\n\t\t\tcontent: `Please wait, you are on a cooldown for \\`${command.data.name}\\`. You can use it again <t:${expiredTimestamp}:R>.`,\n\t\t\tflags: MessageFlags.Ephemeral,\n\t\t});\n\t}\n}\n```\n\nSince the `timestamps` Collection has the user's id as the key, you can use the `get()` method on it to get the value and sum it up with the `cooldownAmount` variable to get the correct expiration timestamp and further check to see if it's expired or not.\n\nThe previous user check serves as a precaution in case the user leaves the guild. You can now use the `setTimeout` method, which will allow you to execute a function after a specified amount of time and remove the timeout.\n\n```js\n// [!code focus]\nif (timestamps.has(interaction.user.id)) {\n\tconst expiredTimestamp = Math.round(expirationTime / 1_000);\n\treturn interaction.reply({\n\t\tcontent: `Please wait, you are on a cooldown for \\`${command.data.name}\\`. You can use it again <t:${expiredTimestamp}:R>.`,\n\t\tflags: MessageFlags.Ephemeral,\n\t});\n} // [!code focus]\n\n// [!code ++:2] [!code focus:2]\ntimestamps.set(interaction.user.id, now);\nsetTimeout(() => timestamps.delete(interaction.user.id), cooldownAmount);\n```\n\nThis line causes the entry for the user under the specified command to be deleted after the command's cooldown time has expired for them.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/additional-features/meta.json",
    "content": "{\n\t\"title\": \"Additional Features\"\n}\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/additional-features/reloading-commands.mdx",
    "content": "---\ntitle: Reloading Commands\n---\n\nWhen writing your commands, you may find it tedious to restart your bot every time for testing the smallest changes. With a command handler, you can eliminate this issue and reload your commands while your bot is running.\n\n<Callout>\n\tESM does not support require and clearing import cache. You can use [hot-esm](https://www.npmjs.com/package/hot-esm)\n\tto import files without cache. Windows support is experimental per [this\n\tissue](https://github.com/vinsonchuong/hot-esm/issues/33).\n</Callout>\n\n<Callout>\n\tThis section assumes you followed the [Command Handling](../app-creation/handling-commands) part of the guide.\n</Callout>\n\n```js title=\"commands/utility/reload.js\"\nconst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('reload')\n\t\t.setDescription('Reloads a command.')\n\t\t.addStringOption((option) => option.setName('command').setDescription('The command to reload.').setRequired(true)),\n\tasync execute(interaction) {\n\t\t// ...\n\t},\n};\n```\n\nFirst off, you need to check if the command you want to reload exists. You can do this check similarly to getting a command.\n\n```js\nmodule.exports = {\n\t// ...\n\t// [!code focus:10]\n\tasync execute(interaction) {\n\t\t// ... // [!code --]\n\t\t// [!code ++:6]\n\t\tconst commandName = interaction.options.getString('command', true).toLowerCase();\n\t\tconst command = interaction.client.commands.get(commandName);\n\n\t\tif (!command) {\n\t\t\treturn interaction.reply(`There is no command with name \\`${commandName}\\`!`);\n\t\t}\n\t},\n};\n```\n\n<Callout type=\"warn\">\n\tThe reload command ideally should not be used by every user. You should deploy it as a guild command in a private\n\tguild.\n</Callout>\n\nTo build the correct file path, you will need the file name. You can use `command.data.name` for doing that.\n\nIn theory, all there is to do is delete the previous command from `client.commands` and require the file again. In practice, you cannot do this easily as `require()` caches the file. If you were to require it again, you would load the previously cached file without any changes. You first need to delete the file from `require.cache`, and only then should you require and set the command file to `client.commands`:\n\n```js\ndelete require.cache[require.resolve(`./${command.data.name}.js`)];\n\ntry {\n\tconst newCommand = require(`./${command.data.name}.js`);\n\tinteraction.client.commands.set(newCommand.data.name, newCommand);\n\tawait interaction.reply(`Command \\`${newCommand.data.name}\\` was reloaded!`);\n} catch (error) {\n\tconsole.error(error);\n\tawait interaction.reply(\n\t\t`There was an error while reloading a command \\`${command.data.name}\\`:\\n\\`${error.message}\\``,\n\t);\n}\n```\n\nThe snippet above uses a `try...catch` block to load the command file and add it to `client.commands`. In case of an error, it will log the full error to the console and notify the user about it with the error's message component `error.message`. Note that you never actually delete the command from the commands Collection and instead overwrite it. This behavior prevents you from deleting a command and ending up with no command at all after a failed `require()` call, as each use of the reload command checks that Collection again.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/additional-info/async-await.mdx",
    "content": "---\ntitle: Understanding async/await\n---\n\nIf you aren't very familiar with ECMAScript 2017, you may not know about async/await. It's a useful way to handle Promises in a hoisted manner. It's also slightly faster and increases overall readability.\n\n## How do Promises work?\n\nBefore we can get into async/await, you should know what Promises are and how they work because async/await is just a way to handle Promises. If you know what Promises are and how to deal with them, you can skip this part.\n\nPromises are a way to handle asynchronous tasks in JavaScript; they are the newer alternative to callbacks. A Promise has many similarities to a progress bar; they represent an unfinished and ongoing process. An excellent example of this is a request to a server (e.g., discord.js sends requests to Discord's API).\n\nA Promise can have three states; pending, resolved, and rejected.\n\n- The **pending** state means that the Promise still is ongoing and neither resolved nor rejected.\n- The **resolved** state means that the Promise is done and executed without any errors.\n- The **rejected** state means that the Promise encountered an error and could not execute correctly.\n\nOne important thing to know is that a Promise can only have one state simultaneously; it can never be pending and resolved, rejected and resolved, or pending and rejected. You may be asking, \"How would that look in code?\". Here is a small example:\n\n<Callout>\n\tThis example uses ES6 code. If you do not know what that is, you should read up on that [here](./es6-syntax).\n</Callout>\n\n```js\nfunction deleteMessages(amount) {\n\t// [!code word:Promise]\n\treturn new Promise((resolve, reject) => {\n\t\tif (amount > 10) return reject(new Error(\"You can't delete more than 10 Messages at a time.\"));\n\t\tsetTimeout(() => resolve('Deleted 10 messages.'), 2_000);\n\t});\n}\n\ndeleteMessages(5)\n\t// [!code word:then]\n\t.then((value) => {\n\t\t// `deleteMessages` is complete and has not encountered any errors\n\t\t// the resolved value will be the string \"Deleted 10 messages\"\n\t})\n\t// [!code word:catch]\n\t.catch((error) => {\n\t\t// `deleteMessages` encountered an error\n\t\t// the error will be an Error Object\n\t});\n```\n\nIn this scenario, the `deleteMessages` function returns a Promise. The `.then()` method will trigger if the Promise resolves, and the `.catch()` method if the Promise rejects. In the `deleteMessages` function, the Promise is resolved after 2 seconds with the string \"Deleted 10 messages.\", so the `.catch()` method will never be executed. You can also pass the `.catch()` function as the second parameter of `.then()`.\n\n## How to implement async/await\n\n### Theory\n\nThe following information is essential to know before working with async/await. You can only use the `await` keyword inside a function declared as `async` (you put the `async` keyword before the `function` keyword or before the parameters when using a callback function).\n\nA simple example would be:\n\n```js\n// [!code word:async]\nasync function declaredAsAsync() {\n\t// ...\n}\n```\n\nor\n\n```js\n// [!code word:async]\nconst declaredAsAsync = async () => {\n\t// ...\n};\n```\n\nYou can use that as well if you use the arrow function as an event listener.\n\n```js\nclient.on('event', async (first, last) => {\n\t// ...\n});\n```\n\nAn important thing to know is that a function declared as `async` will always return a Promise. In addition to this, if you return something, the Promise will resolve with that value, and if you throw an error, it will reject the Promise with that error.\n\n### Execution with discord.js code\n\nNow that you know how Promises work and what they are used for, let's look at an example that handles multiple Promises. Let's say you want to react with letters (regional indicators) in a specific order. For this example, here's a basic template for a discord.js bot with some ES6 adjustments.\n\n```js title=\"promise-example.js\" lineNumbers\nconst { Client, Events, GatewayIntentBits } = require('discord.js');\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\nclient.once(Events.ClientReady, () => {\n\tconsole.log('I am ready!');\n});\n\nclient.on(Events.InteractionCreate, (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tif (interaction.commandName === 'react') {\n\t\t// ...\n\t}\n});\n\nclient.login('your-token-goes-here');\n```\n\nIf you don't know how Node.js asynchronous execution works, you would probably try something like this:\n\n```js title=\"promise-example.js\" lineNumbers=9\nclient.on(Events.InteractionCreate, (interaction) => {\n\t// ...\n\t// [!code focus:7]\n\tif (commandName === 'react') {\n\t\tconst response = interaction.reply({ content: 'Reacting!', withResponse: true }); // [!code ++:5]\n\t\tconst { message } = response.resource;\n\t\tmessage.react('🇦');\n\t\tmessage.react('🇧');\n\t\tmessage.react('🇨');\n\t}\n});\n```\n\nBut since all of these methods are started at the same time, it would just be a race to which server request finished first, so there would be no guarantee that it would react at all (if the message isn't fetched) or in the order you wanted it to. In order to make sure it reacts after the message is sent and in order (a, b, c), you'd need to use the `.then()` callback from the Promises that these methods return. The code would look like this:\n\n```js title=\"promise-example.js\" lineNumbers=9\nclient.on(Events.InteractionCreate, (interaction) => {\n\t// ...\n\tif (commandName === 'react') {\n\t\tinteraction.reply({ content: 'Reacting!', withResponse: true }).then((response) => {\n\t\t\tconst { message } = response.resource;\n\t\t\tmessage.react('🇦'); // [!code --:3]\n\t\t\tmessage.react('🇧');\n\t\t\tmessage.react('🇨');\n\t\t\tmessage // [!code ++:7]\n\t\t\t\t.react('🇦')\n\t\t\t\t.then(() => message.react('🇧'))\n\t\t\t\t.then(() => message.react('🇨'))\n\t\t\t\t.catch((error) => {\n\t\t\t\t\t// handle failure of any Promise rejection inside here\n\t\t\t\t});\n\t\t});\n\t}\n});\n```\n\nIn this piece of code, the Promises are [chain resolved](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise/then#Chaining) with each other, and if one of the Promises gets rejected, the function passed to `.catch()` gets called. Here's the same code but with async/await:\n\n```js title=\"promise-example.js\" lineNumbers=9\nclient.on(Events.InteractionCreate, async (interaction) => {\n\t// ...\n\tif (commandName === 'react') {\n\t\tconst response = await interaction.reply({ content: 'Reacting!', withResponse: true });\n\t\tconst { message } = response.resource;\n\t\tmessage.react('🇦'); // [!code --:3]\n\t\tmessage.react('🇧');\n\t\tmessage.react('🇨');\n\t\tawait message.react('🇦'); // [!code ++:3]\n\t\tawait message.react('🇧');\n\t\tawait message.react('🇨');\n\t}\n});\n```\n\nIt's mostly the same code, but how would you catch Promise rejections now since `.catch()` isn't there anymore? That is also a useful feature with async/await; the error will be thrown if you await it so that you can wrap the awaited Promises inside a try/catch, and you're good to go.\n\n```js title=\"promise-example.js\" lineNumbers=9\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (commandName === 'react') {\n\t\t// [!code ++]\n\t\ttry {\n\t\t\tconst response = await interaction.reply({ content: 'Reacting!', withResponse: true });\n\t\t\tconst { message } = response.resource;\n\t\t\tawait message.react('🇦');\n\t\t\tawait message.react('🇧');\n\t\t\tawait message.react('🇨');\n\t\t\t// [!code ++:3]\n\t\t} catch (error) {\n\t\t\t// handle failure of any Promise rejection inside here\n\t\t}\n\t}\n});\n```\n\nThis code looks clean and is also easy to read.\n\nSo you may be asking, \"How would I get the value the Promise resolved with?\".\n\nLet's look at an example where you want to delete a sent reply.\n\n```js title=\"promise-example.js\"\nclient.on(Events.InteractionCreate, (interaction) => {\n\t// ...\n\tif (commandName === 'delete') {\n\t\tinteraction\n\t\t\t.reply({ content: 'This message will be deleted.', withResponse: true })\n\t\t\t.then((response) => setTimeout(() => response.resource.message.delete(), 10_000)) // [!code word:response]\n\t\t\t.catch((error) => {\n\t\t\t\t// handle error\n\t\t\t});\n\t}\n});\n```\n\nThe return value of a `.reply()` with the `withResponse` option set to `true` is a promise which resolves with `InteractionCallbackResponse`, but how would the same code with async/await look?\n\n```js title=\"promise-example.js\"\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (commandName === 'delete') {\n\t\ttry {\n\t\t\tconst response = await interaction.reply({ content: 'This message will be deleted.', withResponse: true }); // [!code word:response]\n\t\t\tsetTimeout(() => response.resource.message.delete(), 10_000);\n\t\t} catch (error) {\n\t\t\t// handle error\n\t\t}\n\t}\n});\n```\n\nWith async/await, you can assign the awaited function to a variable representing the returned value. Now you know how you use async/await.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/additional-info/changes-in-v14.mdx",
    "content": "---\ntitle: Updating to v14\n---\n\n## Before you start\n\nMake sure you're using the latest LTS version of Node. To check your Node version, use `node -v` in your terminal or command prompt, and if it's not high enough, update it! There are many resources online to help you with this step based on your host system.\n\n### Various packages are now included in v14\n\nIf you previously had `@discordjs/builders`, `@discordjs/formatters`, `@discordjs/rest`, or `discord-api-types` manually installed, it's _highly_ recommended that you uninstall the packages to avoid package version conflicts.\n\n```sh tab=\"npm\"\nnpm uninstall @discordjs/builders @discordjs/formatters @discordjs/rest discord-api-types\n```\n\n```sh tab=\"yarn\"\nyarn remove @discordjs/builders @discordjs/formatters @discordjs/rest discord-api-types\n```\n\n```sh tab=\"pnpm\"\npnpm remove @discordjs/builders @discordjs/formatters @discordjs/rest discord-api-types\n```\n\n## Breaking Changes\n\n### API version\n\ndiscord.js v14 makes the switch to Discord API v10!\n\n### Common Breakages\n\n### Enum Values\n\nAny areas that used to accept a `string` or `number` type for an enum parameter will now only accept exclusively `number`s.\n\nIn addition, the old enums exported by discord.js v13 and lower are replaced with new enums from [discord-api-types](https://discord-api-types.dev/api/discord-api-types-v10).\n\n#### New enum differences\n\nMost of the difference between enums from discord.js and discord-api-types can be summarized as so:\n\n1. Enums are singular, i.e., `ApplicationCommandOptionTypes` -> `ApplicationCommandOptionType`\n2. Enums that are prefixed with `Message` no longer have the `Message` prefix, i.e., `MessageButtonStyles` -> `ButtonStyle`\n3. Enum values are `PascalCase` rather than `SCREAMING_SNAKE_CASE`, i.e., `.CHAT_INPUT` -> `.ChatInput`\n\n<Callout>\n\tYou might be inclined to use raw `number`s (most commonly referred to as [magic numbers](<https://en.wikipedia.org/wiki/Magic_number_(programming)>)) instead of enum values. This is highly discouraged. Enums provide more readability and are more resistant to changes in the API. Magic numbers can obscure the meaning of your code in many ways, check out this [blog post](https://blog.webdevsimplified.com/2020-02/magic-numbers/) if you want more context on as to why they shouldn't be used.\n</Callout>\n\n#### Common enum breakages\n\nAreas like `Client` initialization, JSON slash commands and JSON message components will likely need to be modified to accommodate these changes:\n\n##### Common Client Initialization Changes\n\n```js\nconst { Client, Intents } = require('discord.js'); // [!code --]\nconst { Client, GatewayIntentBits, Partials } = require('discord.js'); // [!code ++]\n\nconst client = new Client({ intents: [Intents.FLAGS.GUILDS], partials: ['CHANNEL'] }); // [!code --]\nconst client = new Client({ intents: [GatewayIntentBits.Guilds], partials: [Partials.Channel] }); // [!code ++]\n```\n\n##### Common Application Command Data changes\n\n```js\nconst { ApplicationCommandType, ApplicationCommandOptionType } = require('discord.js'); // [!code ++]\n\nconst command = {\n\tname: 'ping',\n\ttype: 'CHAT_INPUT', // [!code --]\n\ttype: ApplicationCommandType.ChatInput, // [!code ++]\n\toptions: [\n\t\t{\n\t\t\tname: 'option',\n\t\t\tdescription: 'A sample option',\n\t\t\ttype: 'STRING', // [!code --]\n\t\t\ttype: ApplicationCommandOptionType.String, // [!code ++]\n\t\t},\n\t],\n};\n```\n\n##### Common Button Data changes\n\n```js\nconst { ButtonStyle } = require('discord.js'); // [!code ++]\n\nconst button = {\n\tlabel: 'test',\n\tstyle: 'PRIMARY', // [!code --]\n\tstyle: ButtonStyle.Primary, // [!code ++]\n\tcustomId: '1234',\n};\n```\n\n### Removal of method-based type guards\n\n#### Channels\n\nSome channel type guard methods that narrowed to one channel type have been removed. Instead compare the `type` property against a [ChannelType](https://discord-api-types.dev/api/discord-api-types-v10/enum/ChannelType) enum member to narrow channels.\n\n```js\nconst { ChannelType } = require('discord.js'); // [!code ++]\n\nchannel.isText(); // [!code --]\nchannel.type === ChannelType.GuildText; // [!code ++]\n\nchannel.isVoice(); // [!code --]\nchannel.type === ChannelType.GuildVoice; // [!code ++]\n\nchannel.isDM(); // [!code --]\nchannel.type === ChannelType.DM; // [!code ++]\n```\n\n### Builders\n\nBuilders are no longer returned by the API like they were previously. For example you send the API an `EmbedBuilder` but you receive an `Embed` of the same data from the API. This may affect how your code handles received structures such as components. Refer to [message component changes section](#messagecomponent) for more details.\n\nAdded `disableValidators()` and `enableValidators()` as top-level exports which disable or enable validation (enabled by default).\n\n### Consolidation of `create()` & `edit()` parameters\n\nVarious `create()` and `edit()` methods on managers and objects have had their parameters consolidated. The changes are below:\n\n- `Guild#edit()` now takes `reason` in the `data` parameter\n- `GuildChannel#edit()` now takes `reason` in the `data` parameter\n- `GuildEmoji#edit()` now takes `reason` in the `data` parameter\n- `Role#edit()` now takes `reason` in the `data` parameter\n- `Sticker#edit()` now takes `reason` in the `data` parameter\n- `ThreadChannel#edit()` now takes `reason` in the `data` parameter\n- `GuildChannelManager#create()` now takes `name` in the `options` parameter\n- `GuildChannelManager#createWebhook()` (and other text-based channels) now takes `channel` and `name` in the `options` parameter\n- `GuildChannelManager#edit()` now takes `reason` as a part of `data`\n- `GuildEmojiManager#edit()` now takes `reason` as a part of `data`\n- `GuildManager#create()` now takes `name` as a part of `options`\n- `GuildMemberManager#edit()` now takes `reason` as a part of `data`\n- `GuildMember#edit()` now takes `reason` as a part of `data`\n- `GuildStickerManager#edit()` now takes `reason` as a part of `data`\n- `RoleManager#edit()` now takes `reason` as a part of `options`\n- `Webhook#edit()` now takes `reason` as a part of `options`\n- `GuildEmojiManager#create()` now takes `attachment` and `name` as a part of `options`\n- `GuildStickerManager#create()` now takes `file`, `name`, and `tags` as a part of `options`\n\n### Activity\n\nThe following properties have been removed as they are not documented by Discord:\n\n- `Activity#id`\n- `Activity#platform`\n- `Activity#sessionId`\n- `Activity#syncId`\n\n### Application\n\n`Application#fetchAssets()` has been removed as it is no longer supported by the API.\n\n### BitField\n\n- BitField constituents now have a `BitField` suffix to avoid naming conflicts with the enum names:\n\n```js\nnew Permissions(); // [!code --]\nnew PermissionsBitField(); // [!code ++]\n\nnew MessageFlags(); // [!code --]\nnew MessageFlagsBitField(); // [!code ++]\n\nnew ThreadMemberFlags(); // [!code --]\nnew ThreadMemberFlagsBitField(); // [!code ++]\n\nnew UserFlags(); // [!code --]\nnew UserFlagsBitField(); // [!code ++]\n\nnew SystemChannelFlags(); // [!code --]\nnew SystemChannelFlagsBitField(); // [!code ++]\n\nnew ApplicationFlags(); // [!code --]\nnew ApplicationFlagsBitField(); // [!code ++]\n\nnew Intents(); // [!code --]\nnew IntentsBitField(); // [!code ++]\n\nnew ActivityFlags(); // [!code --]\nnew ActivityFlagsBitField(); // [!code ++]\n```\n\n- `#FLAGS` has been renamed to `#Flags`\n\n### CDN\n\nThe methods that return CDN URLs have changed. Here is an example on a User:\n\n```js\nconst url = user.displayAvatarURL({ dynamic: true, format: 'png', size: 1_024 }); // [!code --]\nconst url = user.displayAvatarURL({ extension: 'png', size: 1_024 }); // [!code ++]\n```\n\nDynamic URLs use `ImageURLOptions` and static URLs use `BaseImageURLOptions`. Since dynamic URLs are returned by default, this option has been renamed to `forceStatic` which forces the return of a static URL. Additionally, `format` has been renamed to `extension`.\n\n### CategoryChannel\n\n`CategoryChannel#children` is no longer a `Collection` of channels the category contains. It is now a manager (`CategoryChannelChildManager`). This also means `CategoryChannel#createChannel()` has been moved to the `CategoryChannelChildManager`.\n\n### Channel\n\nThe following type guards have been removed:\n\n- `Channel#isText()`\n- `Channel#isVoice()`\n- `Channel#isDirectory()`\n- `Channel#isDM()`\n- `Channel#isGroupDM()`\n- `Channel#isCategory()`\n- `Channel#isNews()`\n\nRefer to [this section](#channels) for more context.\n\nThe base channel class is now `BaseChannel`.\n\n### Client\n\nThe `restWsBridgeTimeout` client option has been removed.\n\n### CommandInteractionOptionResolver\n\n`CommandInteractionOptionResolver#getMember()` no longer has a parameter for `required`. See [this pull request](https://github.com/discordjs/discord.js/pull/7188) for more information.\n\n### Constants\n\n- Many constant objects and key arrays are now top-level exports for example:\n\n```js\nconst { Constants } = require('discord.js'); // [!code --]\nconst { Colors } = Constants; // [!code --]\nconst { Colors } = require('discord.js'); // [!code ++]\n```\n\n- The refactored constants structures have `PascalCase` member names as opposed to `SCREAMING_SNAKE_CASE` member names.\n\n- Many of the exported constants structures have been replaced and renamed:\n\n```js\nOpcodes; // [!code --]\nGatewayOpcodes; // [!code ++]\n\nWSEvents; // [!code --]\nGatewayDispatchEvents; // [!code ++]\n\nWSCodes; // [!code --]\nGatewayCloseCodes; // [!code ++]\n\nInviteScopes; // [!code --]\nOAuth2Scopes; // [!code ++]\n```\n\n### Events\n\nThe `message` and `interaction` events are now removed. Use `messageCreate` and `interactionCreate` instead.\n\n`applicationCommandCreate`, `applicationCommandDelete` and `applicationCommandUpdate` have all been removed. See [this pull request](https://github.com/discordjs/discord.js/pull/6492) for more information.\n\nThe `threadMembersUpdate` event now emits the users who were added, the users who were removed, and the thread respectively.\n\n### GuildBanManager\n\nDevelopers should utilise `deleteMessageSeconds` instead of `days` and `deleteMessageDays`:\n\n```js\n<GuildBanManager>.create('123456789', {\n days: 3 // [!code --]\n deleteMessageDays: 3 // [!code --]\n deleteMessageSeconds: 3 * 24 * 60 * 60 // [!code ++]\n});\n```\n\n`deleteMessageDays` (introduced with version 14) and `days` are both deprecated and will be removed in the future.\n\n### Guild\n\n`Guild#setRolePositions()` and `Guild#setChannelPositions()` have been removed. Use `RoleManager#setPositions()` and `GuildChannelManager#setPositions()` instead respectively.\n\n`Guild#maximumPresences` no longer has a default value of 25,000.\n\n`Guild#me` has been moved to `GuildMemberManager#me`. See [this pull request](https://github.com/discordjs/discord.js/pull/7669) for more information.\n\n### GuildAuditLogs & GuildAuditLogsEntry\n\n`GuildAuditLogs.build()` has been removed as it has been deemed defunct. There is no alternative.\n\nThe following properties & methods have been moved to the `GuildAuditLogsEntry` class:\n\n- `GuildAuditLogs.Targets`\n- `GuildAuditLogs.actionType()`\n- `GuildAuditLogs.targetType()`\n\n### GuildMember\n\n`GuildMember#pending` is now nullable to account for partial guild members. See [this issue](https://github.com/discordjs/discord.js/issues/6546) for more information.\n\n### IntegrationApplication\n\n`IntegrationApplication#summary` has been removed as it is no longer supported by the API.\n\n### Interaction\n\nWhenever an interaction is replied to and one fetches the reply, it could possibly give an `APIMessage` if the guild was not cached. However, interaction replies now always return an `InteractionCallbackResponse` with `withResponse` set to `true`.\n\nThe base interaction class is now `BaseInteraction`.\n\n### Invite\n\n`Invite#inviter` is now a getter and resolves structures from the cache.\n\n### MessageAttachment\n\n`MessageAttachment` has now been renamed to `AttachmentBuilder`. // [!code --]\n\n```js\nnew MessageAttachment(buffer, 'image.png'); // [!code --]\nnew AttachmentBuilder(buffer, { name: 'image.png' }); // [!code ++]\n```\n\n### MessageComponent\n\n- MessageComponents have been renamed as well. They no longer have the `Message` prefix, and now have a `Builder` suffix:\n\n```js\nconst button = new MessageButton(); // [!code --]\nconst button = new ButtonBuilder(); // [!code ++]\n\nconst selectMenu = new MessageSelectMenu(); // [!code --]\nconst selectMenu = new StringSelectMenuBuilder(); // [!code ++]\n\nconst actionRow = new MessageActionRow(); // [!code --]\nconst actionRow = new ActionRowBuilder(); // [!code ++]\n\nconst textInput = new TextInputComponent(); // [!code --]\nconst textInput = new TextInputBuilder(); // [!code ++]\n```\n\n- Components received from the API are no longer directly mutable. If you wish to mutate a component from the API, use `ComponentBuilder#from`. For example, if you want to make a button mutable:\n\n```js\nconst editedButton = receivedButton // [!code --]\n\t.setDisabled(true); // [!code --]\nconst { ButtonBuilder } = require('discord.js'); // [!code ++]\nconst editedButton = ButtonBuilder.from(receivedButton) // [!code ++]\n\t.setDisabled(true); // [!code ++]\n```\n\n### MessageManager\n\n`MessageManager#fetch()`'s second parameter has been removed. The `BaseFetchOptions` the second parameter once was is now merged into the first parameter.\n\n```js\nmessageManager.fetch('1234567890', { cache: false, force: true }); // [!code --]\nmessageManager.fetch({ message: '1234567890', cache: false, force: true }); // [!code ++]\n```\n\n### MessageSelectMenu\n\n- `MessageSelectMenu` has been renamed to `StringSelectMenuBuilder`\n- `StringSelectMenuBuilder#addOption()` has been removed. Use `StringSelectMenuBuilder#addOptions()` instead.\n\n### MessageEmbed\n\n- `MessageEmbed` has now been renamed to `EmbedBuilder`.\n- `EmbedBuilder#setAuthor()` now accepts a sole `EmbedAuthorOptions` object.\n- `EmbedBuilder#setFooter()` now accepts a sole `EmbedFooterOptions` object.\n- `EmbedBuilder#addField()` has been removed. Use `EmbedBuilder#addFields()` instead.\n\n```js\nnew MessageEmbed().addField('Inline field title', 'Some value here', true); // [!code --]\nnew EmbedBuilder().addFields([ // [!code ++]\n { name: 'one', value: 'one', inline: true }, // [!code ++]\n { name: 'two', value: 'two', inline: true }, // [!code ++]\n+]);\n```\n\n### Modal\n\n- `Modal` has been renamed as well and now has a `Builder` suffix:\n\n```js\nconst modal = new Modal(); // [!code --]\nconst modal = new ModalBuilder(); // [!code ++]\n```\n\n### PartialTypes\n\nThe `PartialTypes` string array has been removed. Use the `Partials` enum instead.\n\nIn addition to this, there is now a new partial: `Partials.ThreadMember`.\n\n### Permissions\n\nThread permissions `USE_PUBLIC_THREADS` and `USE_PRIVATE_THREADS` have been removed as they are deprecated in the API. Use `CREATE_PUBLIC_THREADS` and `CREATE_PRIVATE_THREADS` respectively.\n\n`ManageEmojisAndStickers` has been deprecated due to API changes. Its replacement is `ManageGuildExpressions`. See [this pull request](https://github.com/discord/discord-api-docs/pull/6017) for more information.\n\n### PermissionOverwritesManager\n\nOverwrites are now keyed by the `PascalCase` permission key rather than the `SCREAMING_SNAKE_CASE` permission key.\n\n### REST Events\n\n#### apiRequest\n\nThis REST event has been removed as discord.js now uses [Undici](https://github.com/nodejs/undici) as the underlying request handler. You must now use a [Diagnostics Channel](https://undici.nodejs.org/#/docs/api/DiagnosticsChannel). Here is a simple example:\n\n```js\nimport diagnosticsChannel from 'node:diagnostics_channel';\n\ndiagnosticsChannel.channel('undici:request:create').subscribe((data) => {\n\t// If you use TypeScript, `data` may be casted as\n\t// `DiagnosticsChannel.RequestCreateMessage`\n\t// from Undici to receive type definitions.\n\tconst { request } = data;\n\tconsole.log(request.method); // Log the method\n\tconsole.log(request.path); // Log the path\n\tconsole.log(request.headers); // Log the headers\n\tconsole.log(request); // Or just log everything!\n});\n```\n\nYou can find further examples at the [Undici Diagnostics Channel documentation](https://undici.nodejs.org/#/docs/api/DiagnosticsChannel).\n\n#### apiResponse\n\nThis REST event has been renamed to `response` and moved to `Client#rest`:\n\n```js\nclient.on('apiResponse', ...); // [!code --]\nclient.rest.on('response', ...); // [!code ++]\n```\n\n#### invalidRequestWarning\n\nThis REST event has been moved to `Client#rest`:\n\n```js\nclient.on('invalidRequestWarning', ...); // [!code --]\nclient.rest.on('invalidRequestWarning', ...); // [!code ++]\n```\n\n#### rateLimit\n\nThis REST event has been renamed to `rateLimited` and moved to `Client#rest`:\n\n```js\nclient.on('rateLimit', ...); // [!code --]\nclient.rest.on('rateLimited', ...); // [!code ++]\n```\n\n### RoleManager\n\n`Role.comparePositions()` has been removed. Use `RoleManager#comparePositions()` instead.\n\n### Sticker\n\n`Sticker#tags` is now a nullable string (`string | null`). Previously, it was a nullable array of strings (`string[] | null`). See [this pull request](https://github.com/discordjs/discord.js/pull/8010) for more information.\n\n### ThreadChannel\n\nThe `MAX` helper used in `ThreadAutoArchiveDuration` has been removed. Discord has since allowed any guild to use any auto archive time which makes this helper redundant.\n\n### ThreadMemberManager\n\n`ThreadMemberManager#fetch()`'s second parameter has been removed. The `BaseFetchOptions` the second parameter once was is now merged into the first parameter. In addition, the boolean helper to specify `cache` has been removed.\n\nUsage is now as follows:\n\n```js\n// The second parameter is merged into the first parameter.\nthreadMemberManager.fetch('1234567890', { cache: false, force: true }); // [!code --]\nthreadMemberManager.fetch({ member: '1234567890', cache: false, force: true }); // [!code ++]\n\n// The lone boolean has been removed. One must be explicit here.\nthreadMemberManager.fetch(false); // [!code --]\nthreadMemberManager.fetch({ cache: false }); // [!code ++]\n```\n\n### Util\n\n`Util.removeMentions()` has been removed. To control mentions, you should use `allowedMentions` on `BaseMessageOptions` instead.\n\n`Util.splitMessage()` has been removed. This utility method is something the developer themselves should do.\n\n`Util.resolveAutoArchiveMaxLimit()` has been removed. Discord has since allowed any guild to use any auto archive time which makes this method redundant.\n\nOther functions in `Util` have been moved to top-level exports so you can directly import them from `discord.js`.\n\n```js\nimport { Util } from 'discord.js'; // [!code --]\nUtil.escapeMarkdown(message); // [!code --]\nimport { escapeMarkdown } from 'discord.js'; // [!code ++]\nescapeMarkdown(message); // [!code ++]\n```\n\n### `.deleted` Field(s) have been removed\n\nYou can no longer use the `deleted` property to check if a structure was deleted. See [this issue](https://github.com/discordjs/discord.js/issues/7091) for more information.\n\n### VoiceChannel\n\n`VoiceChannel#editable` has been removed. You should use `GuildChannel#manageable` instead.\n\n### VoiceRegion\n\n`VoiceRegion#vip` has been removed as it is no longer part of the API.\n\n### Webhook\n\n`Webhook#fetchMessage()`'s second parameter no longer allows a boolean to be passed. The `cache` option in `WebhookFetchMessageOptions` should be used instead.\n\n## Features\n\n### ApplicationCommand\n\nNSFW commands are supported.\n\n### Attachment\n\nAdded support for voice message metadata fields.\n\n### AutocompleteInteraction\n\n`AutocompleteInteraction#commandGuildId` has been added which is the id of the guild the invoked application command is registered to.\n\n### BaseChannel\n\nAdded support for `BaseChannel#flags`.\n\nStore channels have been removed as they are no longer part of the API.\n\n`BaseChannel#url` has been added which is a link to a channel, just like in the client.\n\nAdditionally, new typeguards have been added:\n\n- `BaseChannel#isDMBased()`\n- `BaseChannel#isTextBased()`\n- `BaseChannel#isVoiceBased()`\n\n### BaseInteraction\n\nAdded `BaseInteraction#isRepliable()` to check whether a given interaction can be replied to.\n\n### ClientApplication\n\nAdded support for role connection metadata.\n\n### Collection\n\n- Added `Collection#merge()` and `Collection#combineEntries()`.\n- New type: `ReadonlyCollection` which indicates an immutable `Collection`.\n\n### Collector\n\nA new `ignore` event has been added which is emitted whenever an element is not collected by the collector.\n\nComponent collector options now use the `ComponentType` enum values:\n\n```js\nconst { ComponentType } = require('discord.js'); // [!code ++]\n\nconst collector = interaction.channel.createMessageComponentCollector({\n\tfilter: collectorFilter,\n\tcomponentType: 'BUTTON', // [!code --]\n\tcomponentType: ComponentType.Button, // [!code ++]\n\ttime: 20_000,\n});\n```\n\n### CommandInteraction\n\n`CommandInteraction#commandGuildId` has been added which is the id of the guild the invoked application command is registered to.\n\n### CommandInteractionOptionResolver\n\n`CommandInteractionOptionResolver#getChannel()` now has a third parameter which narrows the channel type.\n\n### Events\n\nAdded support for `guildAuditLogEntryCreate` event.\n\n### ForumChannel\n\nAdded support for forum channels.\n\nAdded support for `ForumChannel#defaultForumLayout`.\n\n### Guild\n\nAdded `Guild#setMFALevel()` which sets the guild's MFA level.\n\nAdded `Guild#maxVideoChannelUsers` which indicates the maximum number of video channel users.\n\nAdded `Guild#maxStageVideoChannelUsers` which indicates the maximum number of video channel users for stage channels.\n\nAdded `Guild#disableInvites()` which disables the guild's invites.\n\nAdded support for the `after` parameter in `Guild#fetchAuditLogs()`.\n\n### GuildChannelManager\n\n`videoQualityMode` may be used whilst creating a channel to initially set the camera video quality mode.\n\n### GuildEmojiManager\n\nAdded `GuildEmojiManager#delete()` and `GuildEmojiManager#edit()` for managing existing guild emojis.\n\n### GuildForumThreadManager\n\nAdded `GuildForumThreadManager` as manager for threads in forum channels.\n\n### GuildMember\n\nAdded support for `GuildMember#flags`.\n\n### GuildMembersChunk\n\nThis object now supports the `GuildMembersChunk#notFound` property.\n\n### GuildMemberManager\n\nAdded `GuildMemberManager#fetchMe()` to fetch the client user in the guild.\n\nAdded `GuildMemberManager#addRole()` and `GuildMemberManager#removeRole()`. These methods allow a single addition or removal of a role respectively to a guild member, even if uncached.\n\n### GuildTextThreadManager\n\nAdded `GuildTextThreadManager` as manager for threads in text channels and announcement channels.\n\n### Message\n\n`Message#position` has been added as an approximate position in a thread.\n\nAdded support for role subscription data.\n\n### MessageReaction\n\nAdded `MessageReaction#react()` to make the client user react with the reaction the class belongs to.\n\n### Role\n\nAdded support for role subscriptions.\n\nAdded support for `Role#tags#guildConnections`.\n\n### StageChannel\n\nStage channels now allow messages to be sent in them, much like voice channels.\n\n### Sticker\n\nAdded support for GIF stickers.\n\n### ThreadMemberManager\n\nThe new `withMember` options returns the associated guild member with the thread member.\n\nWhen fetching multiple thread members alongside `withMember`, paginated results will be returned. The `after` and `limit` option are supported in this scenario.\n\n### Webhook\n\nAdded `Webhook#applicationId`.\n\nAdded the `threadName` property in `Webhook#send()` options which allows a webhook to create a post in a forum channel.\n\n### WebSocketManager\n\ndiscord.js uses `@discordjs/ws` internally\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/additional-info/collections.mdx",
    "content": "---\ntitle: Collections\n---\n\ndiscord.js comes with a utility class known as `Collection`.\nIt extends JavaScript's native `Map` class, so it has all the `Map` features and more!\n\n<Callout type=\"warn\">\n\tIf you're not familiar with `Map`, read [MDN's page on\n\tit](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Map) before continuing. You should be\n\tfamiliar with `Array` [methods](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array) as\n\twell. We will also use some ES6 features, so read up [here](./es6-syntax) if you do not know what they are.\n</Callout>\n\nA `Map` allows for an association between unique keys and their values.\nFor example, how can you transform every value or filter the entries in a `Map` easily?\nThis is the point of the `Collection` class!\n\n## Array-like Methods\n\nMany of the methods on `Collection` correspond to their namesake in `Array`. One of them is `find`:\n\n```js\n// Assume we have an array of users and a collection of the same users.\narray.find((u) => u.discriminator === '1000'); // [!code word:find]\ncollection.find((u) => u.discriminator === '1000');\n```\n\nThe interface of the callback function is very similar between the two.\nFor arrays, callbacks usually pass the parameters `(value, index, array)`, where `value` is the value iterated to,\n`index` is the current index, and `array` is the array. For collections, you would have `(value, key, collection)`.\nHere, `value` is the same, but `key` is the key of the value, and `collection` is the collection itself instead.\n\nMethods that follow this philosophy of staying close to the `Array` interface are as follows:\n\n- `find`\n- `filter` - Note that this returns a `Collection` rather than an `Array`.\n- `map` - Yet this returns an `Array` of values instead of a `Collection`!\n- `every`\n- `some`\n- `reduce`\n- `concat`\n- `sort`\n\n## Converting to Array\n\nSince `Collection` extends `Map`, it is an [iterable](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Iteration_protocols), and can be converted to an `Array` through either `Array.from()` or spread syntax (`...collection`).\n\n```js\n// For values.\nArray.from(collection.values());\n[...collection.values()];\n\n// For keys.\nArray.from(collection.keys());\n[...collection.keys()];\n\n// For [key, value] pairs.\nArray.from(collection);\n[...collection];\n```\n\n<Callout>\n\tMany people convert Collections to Arrays way too much!\n\n    This can lead to unnecessary and confusing code. Before you use `Array.from()` or similar, ask yourself if whatever you are trying to do can't be done with the given `Map` or `Collection` methods or with a for-of loop. Not being familiar with a new data structure should not mean you default to transforming it into the other.\n\n    There is usually a reason, why a `Map` or `Collection` is used. Most structures in Discord can be identified with an `id`, which lends itself well to `key -> value` associations like in `Map`s.\n\n</Callout>\n\n## Extra Utilities\n\nSome methods are not from `Array` and are instead entirely new to standard JavaScript.\n\n```js\n// A random value.\ncollection.random();\n\n// The first value.\ncollection.first();\n\n// The first 5 values.\ncollection.first(5);\n\n// Similar to `first`, but from the end.\ncollection.last();\ncollection.last(2);\n\n// Removes anything that meets the condition from the collection.\n// Sort of like `filter`, but in-place.\ncollection.sweep((user) => user.username === 'Bob');\n```\n\nA more complicated method is `partition`, which splits a single Collection into two new Collections based on the provided function.\nYou can think of it as two `filter`s, but done at the same time (and because of that much more performant):\n\n```js\n// `bots` is a Collection of users where their `bot` property was true.\n// `humans` is a Collection where the property was false instead!\nconst [bots, humans] = collection.partition((u) => u.bot); // [!code word:partition]\n\n// Both return true.\nbots.every((b) => b.bot);\nhumans.every((h) => !h.bot); // note the \"not\" ! operator\n```\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/additional-info/es6-syntax.mdx",
    "content": "---\ntitle: ES6 Syntax\n---\n\nIf you've used JavaScript for only a (relatively) small amount of time or don't have much experience with it, you might not be aware of what ES6 is and what beneficial features it includes. Since this is a guide primarily for Discord bots, we'll be using some discord.js code as an example of what you might have versus what you could do to benefit from ES6.\n\nHere's the startup code we'll be using:\n\n```js title=\"index.js\" lineNumbers\nconst { Client, Events, GatewayIntentBits } = require('discord.js'); // [!code word:const]\nconst config = require('./config.json');\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\n// [!code word:=>]\nclient.once(Events.ClientReady, () => {\n\tconsole.log('Ready!');\n});\n\nclient.on(Events.InteractionCreate, (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tconst { commandName } = interaction;\n\n\tif (commandName === 'ping') {\n\t\tinteraction.reply('Pong.');\n\t} else if (commandName === 'beep') {\n\t\tinteraction.reply('Boop.');\n\t} else if (commandName === 'server') {\n\t\tinteraction.reply('Guild name: ' + interaction.guild.name + '\\nTotal members: ' + interaction.guild.memberCount);\n\t} else if (commandName === 'user-info') {\n\t\tinteraction.reply('Your username: ' + interaction.user.username + '\\nYour ID: ' + interaction.user.id);\n\t}\n});\n\nclient.login(config.token);\n```\n\nIf you haven't noticed, this piece of code is already using a bit of ES6 here! The `const` keyword and arrow function declaration (`() => ...`) is ES6 syntax, and we recommend using it whenever possible.\n\nAs for the code above, there are a few places where things can be done better. Let's look at them.\n\n## Template literals\n\nIf you check the code above, it's currently doing things like `'Guild name: ' + interaction.guild.name` and `'Your username: ' + interaction.user.username`, which is perfectly valid. It is a bit hard to read, though, and it's not too fun to constantly type out. Fortunately, there's a better alternative.\n\n```js title=\"index.js\" lineNumbers=19\n} else if (commandName === 'server') {\n\tinteraction.reply('Guild name: ' + interaction.guild.name + '\\nTotal members: ' + interaction.guild.memberCount); // [!code --]\n\tinteraction.reply(`Guild name: ${interaction.guild.name}\\nTotal members: ${interaction.guild.memberCount}`); // [!code ++]\n}\nelse if (commandName === 'user-info') {\n\tinteraction.reply('Your username: ' + interaction.user.username + '\\nYour ID: ' + interaction.user.id); // [!code --]\n\tinteraction.reply(`Your username: ${interaction.user.username}\\nYour ID: ${interaction.user.id}`); // [!code ++]\n}\n```\n\nEasier to read and write! The best of both worlds.\n\n### Template literals vs string concatenation\n\nIf you've used other programming languages, you might be familiar with the term \"string interpolation\". Template literals would be JavaScript's implementation of string interpolation. If you're familiar with the heredoc syntax, it's very much like that; it allows for string interpolation, as well as multiline strings.\n\nThe example below won't go too much into detail about it, but if you're interested in reading more, you can [read about them on MDN](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Template_literals).\n\n```js\nconst username = 'Sanctuary';\nconst password = 'pleasedonthackme';\n\nfunction letsPretendThisDoesSomething() {\n\treturn 'Yay for sample data.';\n}\n\nconsole.log('Your username is: **' + username + '**.'); // [!code --:2]\nconsole.log('Your password is: **' + password + '**.');\nconsole.log(`Your username is: **${username}**.`); // [!code ++:2]\nconsole.log(`Your password is: **${password}**.`);\n\nconsole.log('1 + 1 = ' + (1 + 1)); // [!code --]\nconsole.log(`1 + 1 = ${1 + 1}`); // [!code ++]\n\nconsole.log(\"And here's a function call: \" + letsPretendThisDoesSomething()); // [!code --]\nconsole.log(`And here's a function call: ${letsPretendThisDoesSomething()}`); // [!code ++]\n\nconsole.log('Putting strings on new lines\\n' + 'can be a bit painful\\n' + 'with string concatenation.'); // [!code --]\n// [!code ++:5]\nconsole.log(`\n\tPutting strings on new lines\n\tis a breeze\n\twith template literals!\n`);\n```\n\n<Callout>\n\tAs you will notice, template literals will also render the white space inside them, including the indentation! There\n\tare ways around this, which we will discuss in another section.\n</Callout>\n\nYou can see how it makes things easier and more readable. In some cases, it can even make your code shorter! This one is something you'll want to take advantage of as much as possible.\n\n## Arrow functions\n\nArrow functions are shorthand for regular functions, with the addition that they use a lexical `this` context inside of their own. If you don't know what the `this` keyword is referring to, don't worry about it; you'll learn more about it as you advance.\n\nHere are some examples of ways you can benefit from arrow functions over regular functions:\n\n```js\n// [!code --:3]\nclient.once(Events.ClientReady, function () {\n\tconsole.log('Ready!');\n});\nclient.once(Events.ClientReady, () => console.log('Ready!')); // [!code ++]\n\n// [!code --:3]\nclient.on(Events.TypingStart, function (typing) {\n\tconsole.log(typing.user.tag + ' started typing in #' + typing.channel.name);\n});\nclient.on(Events.TypingStart, (typing) => console.log(`${typing.user.tag} started typing in #${typing.channel.name}`)); // [!code ++]\n\n// [!code --:3]\nclient.on(Events.MessageCreate, function (message) {\n\tconsole.log(message.author.tag + ' sent: ' + message.content);\n});\nclient.on(Events.MessageCreate, (message) => console.log(`${message.author.tag} sent: ${message.content}`)); // [!code ++]\n\n// [!code --:3]\nvar doubleAge = function (age) {\n\treturn 'Your age doubled is: ' + age * 2;\n};\nconst doubleAge = (age) => `Your age doubled is: ${age * 2}`; // [!code ++]\n\n// [!code --:4]\nvar collectorFilter = function (m) {\n\treturn m.content === 'I agree' && !m.author.bot;\n};\nvar collector = message.createMessageCollector({ filter: collectorFilter, time: 15_000 });\nconst collectorFilter = (m) => m.content === 'I agree' && !m.author.bot; // [!code ++:2]\nconst collector = message.createMessageCollector({ filter: collectorFilter, time: 15_000 });\n```\n\nThere are a few important things you should note here:\n\n- The parentheses around function parameters are optional when you have only one parameter but are required otherwise. If you feel like this will confuse you, it may be a good idea to use parentheses.\n- You can cleanly put what you need on a single line without curly braces.\n- Omitting curly braces will make arrow functions use **implicit return**, but only if you have a single-line expression. The `doubleAge` and `filter` variables are a good example of this.\n- Unlike the `function someFunc() { ... }` declaration, arrow functions cannot be used to create functions with such syntax. You can create a variable and give it an anonymous arrow function as the value, though (as seen with the `doubleAge` and `filter` variables).\n\nWe won't be covering the lexical `this` scope with arrow functions in here, but you can Google around if you're still curious. Again, if you aren't sure what `this` is or when you need it, reading about lexical `this` first may only confuse you.\n\n## Destructuring\n\nDestructuring is an easy way to extract items from an object or array. If you've never seen the syntax for it before, it can be a bit confusing, but it's straightforward to understand once explained!\n\n### Object destructuring\n\nHere's a common example where object destructuring would come in handy:\n\n```js\nconst config = require('./config.json');\nconst prefix = config.prefix;\nconst token = config.token;\n```\n\nThis code is a bit verbose and not the most fun to write out each time. Object destructuring simplifies this, making it easier to both read and write. Take a look:\n\n```js\nconst config = require('./config.json'); // [!code --:3]\nconst prefix = config.prefix;\nconst token = config.token;\nconst { prefix, token } = require('./config.json'); // [!code ++]\n```\n\nObject destructuring takes those properties from the object and stores them in variables. If the property doesn't exist, it'll still create a variable but with the value of `undefined`. So instead of using `config.token` in your `client.login()` method, you'd simply use `token`. And since destructuring creates a variable for each item, you don't even need that `const prefix = config.prefix` line. Pretty cool!\n\nAdditionally, you could do this for your commands:\n\n```js\nclient.on(Events.InteractionCreate, (interaction) => {\n\tconst { commandName } = interaction;\n\n\tif (commandName === 'ping') {\n\t\t// ping command here...\n\t} else if (commandName === 'beep') {\n\t\t// beep command here...\n\t}\n\t// other commands here...\n});\n```\n\nThe code is shorter and looks cleaner, but it shouldn't be necessary if you follow along with the [command handler](../app-creation/handling-commands) part of the guide.\n\nYou can also rename variables when destructuring, if necessary. A good example is when you're extracting a property with a name already being used or conflicts with a reserved keyword. The syntax is as follows:\n\n```js\n// `default` is a reserved keyword\nconst { default: defaultValue } = someObject;\n\nconsole.log(defaultValue);\n// 'Some default value here'\n```\n\n### Array destructuring\n\nArray destructuring syntax is very similar to object destructuring, except that you use brackets instead of curly braces. In addition, since you're using it on an array, you destructure the items in the same order the array is. Without array destructuring, this is how you'd extract items from an array:\n\n```js\n// assuming we're in a `profile` command and have an `args` variable\nconst name = args[0];\nconst age = args[1];\nconst location = args[2];\n```\n\nLike the first example with object destructuring, this is a bit verbose and not fun to write out. Array destructuring eases this pain.\n\n```js\nconst name = args[0]; // [!code --:3]\nconst age = args[1];\nconst location = args[2];\nconst [name, age, location] = args; // [!code ++]\n```\n\nA single line of code that makes things much cleaner! In some cases, you may not even need all the array's items (e.g., when using `string.match(regex)`). Array destructuring still allows you to operate in the same sense.\n\n```js\nconst [, username, id] = message.content.match(someRegex);\n```\n\nIn this snippet, we use a comma without providing a name for the item in the array we don't need. You can also give it a placeholder name (`_match` or similar) if you prefer, of course; it's entirely preference at that point.\n\n<Callout>\n\tThe underscore `_` prefix is a convention for unused variables. Some lint rules will error or warn if you define\n\tidentifiers without using them in your code but ignore identifiers starting with `_`.\n</Callout>\n\n## var, let, and const\n\nSince there are many, many articles out there that can explain this part more in-depth, we'll only be giving you a TL;DR and an article link if you choose to read more about it.\n\n1. The `var` keyword is what was (and can still be) used in JavaScript before `let` and `const` came to surface. There are many issues with `var`, though, such as it being function-scoped, hoisting related issues, and allowing redeclaration.\n2. The `let` keyword is essentially the new `var`; it addresses many of the issues `var` has, but its most significant factor would be that it's block-scoped and disallows redeclaration (_not_ reassignment).\n3. The `const` keyword is for giving variables a constant value that is unable to be reassigned. `const`, like `let`, is also block-scoped.\n\nThe general rule of thumb recommended by this guide is to use `const` wherever possible, `let` otherwise, and avoid using `var`. Here's a [helpful article](https://madhatted.com/2016/1/25/let-it-be) if you want to read more about this subject.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/additional-info/meta.json",
    "content": "{\n\t\"title\": \"Additional Info\",\n\t\"pages\": [\"async-await\", \"collections\", \"es6-syntax\", \"notation\", \"rest-api\", \"proxy\"]\n}\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/additional-info/notation.mdx",
    "content": "---\ntitle: Understanding Notation\n---\n\nThroughout the discord.js docs and when asking for help on the official server, you will run into many different kinds of notations. To help you understand the texts that you read, we will be going over some standard notations.\n\n<Callout>\n\tAlways keep in mind that notation is not always rigorous. There will be typos, misunderstandings, or contexts that\n\twill cause notation to differ from the usual meanings.\n</Callout>\n\n## Classes\n\nSome common notations refer to a class or the properties, methods, or events of a class. There are many variations on these notations, and they are very flexible depending on the person, so use your best judgment when reading them.\n\nThe notation `<Class>` means an instance of the `Class` class. For example, a snippet like `<BaseInteraction>.reply('Hello')` is asking you to replace `<BaseInteraction>` with some value that is an instance of `BaseInteraction`, e.g. `interaction.reply('Hello')`. It could also just be a placeholder, e.g., `<id>` would mean a placeholder for some ID.\n\nThe notation `Class#foo` can refer to the `foo` property, method, or event of the `Class` class. Which one the writer meant needs to be determined from context. For example:\n\n- `BaseInteraction#user` means that you should refer to the `user` property on a `BaseInteraction`.\n- `TextChannel#send` means that you should refer to the `send` method on a `TextChannel`.\n- `Client#interactionCreate` means that you should refer to the `interactionCreate` event on a `Client`.\n\n<Callout>\n\tRemember that this notation is not valid JavaScript; it is a shorthand to refer to a specific piece of code.\n</Callout>\n\nSometimes, the notation is extended, which can help you determine which one the writer meant. For example, `TextChannel#send(options)` is definitely a method of `TextChannel`, since it uses function notation. `Client#event:messageCreate` is an event since it says it is an event.\n\nThe vital thing to take away from this notation is that the `#` symbol signifies that the property, method, or event can only be accessed through an instance of the class. Unfortunately, many abuse this notation, e.g., `<Message>#send` or `Util#resolveColor`. `<Message>` is already an instance, so this makes no sense, and `resolveColor` is a static method–you should write it as `Util.resolveColor`. Always refer back to the docs if you are confused.\n\nAs an example, the documentation's search feature uses this notation.\n\n![Docs search](./images/search.png)\n\nNotice the use of the `.` operator for the static method, `Role.comparePositions` and the `#` notation for the method, `Role#comparePositionsTo`.\n\n## Types\n\nIn the discord.js docs, there are type signatures everywhere, such as in properties, parameters, or return values. If you do not come from a statically typed language, you may not know what specific notations mean.\n\nThe symbol `*` means any type. For example, methods that return `*` mean that they can return anything, and a parameter of type `*` can be anything.\n\nThe symbol `?` means that the type is nullable. You can see it before or after the type (e.g. `?T` or `T?`). This symbol means that the value can be of the type `T` or `null`. An example is `GuildMember#nickname`; its type is `?string` since a member may or may not have a nickname.\n\nThe expression `T[]` means an array of `T`. You can sometimes see multiple brackets `[]`, indicating that the array is multi-dimensional, e.g., `string[][]`.\n\nThe expression `...T` signifies a rest parameter of type `T`. This means that the function can take any amount of arguments, and all those arguments must be of the type `T`.\n\nThe operator `|`, which can read as \"or\", creates a union type, e.g. `A|B|C`. Simply, it means the value can be of any one of the types given.\n\nThe angle brackets `<>` are used for generic types or parameterized types, signifying a type that uses another type(s). The notation looks like `A<B>` where `A` is the type and `B` is a type parameter. If this is hard to follow, it is enough to keep in mind that whenever you see `A<B>`, you can think of an `A` containing `B`. Examples:\n\n- `Array<String>` means an array of strings.\n- `Promise<User>` means a `Promise` that contains a `User`.\n- `Array<Promise<User|GuildMember>>` would be an array of `Promise`s, each containing a `User` or a `GuildMember`.\n- `Collection<Snowflake, User>` would be a `Collection`, containing key-value pairs where the keys are `Snowflake`s, and the values are `User`s.\n\n![TextChannel#send on the docs](./images/send.png)\n\nIn this piece of the docs, you can see two type signatures, `string`, `MessagePayload`, or `MessageOptions`, and `Promise<(Message|Array<Message>)>`. The meaning of the word \"or\" here is the same as `|`.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/additional-info/proxy.mdx",
    "content": "---\ntitle: Using a Proxy\n---\n\nThis guide will show you how to set up a proxy with discord.js. This may be necessary if you are deploying your bot to a server with a firewall only allowing outside traffic through the proxy.\n\nProxying discord.js requires two components: a REST proxy and a WebSocket proxy.\n\n## Prerequisites\n\nTo achieve these two components you can utilize the `undici` and `global-agent` packages:\n\n```sh tab=\"npm\"\nnpm install undici global-agent\n```\n\n```sh tab=\"yarn\"\nyarn add undici global-agent\n```\n\n```sh tab=\"pnpm\"\npnpm add undici global-agent\n```\n\n```sh tab=\"bun\"\nbun add undici global-agent\n```\n\n## Setting up the proxy for REST calls\n\nThe `@discordjs/rest` package handling HTTP requests in discord.js uses the `undici` package. Accordingly, you can provide a custom `ProxyAgent` configuration to the client constructor:\n\n```js title=\"index.js\" lineNumbers\nconst { ProxyAgent } = require('undici'); // [!code word:ProxyAgent]\nconst { Client } = require('discord.js');\n\nconst client = new Client({\n\t// ...other client options\n\trest: {\n\t\tagent: new ProxyAgent('http://my-proxy-server:port'),\n\t},\n});\n\nclient.login('your-token-goes-here');\n```\n\n<Callout>\n\tFor further information on the `undici` `ProxyAgent`, please refer to the [undici\n\tdocumentation](https://undici.nodejs.org/#/docs/api/ProxyAgent.md).\n</Callout>\n\n## Setting up the proxy for the WebSocket connection\n\nTo set up a proxy for WebSocket, you can use the `global-agent` package. You will need to import and call the `bootstrap()` function and set the required `GLOBAL_AGENT` globals as shown below:\n\n```js title=\"index.js\" lineNumbers\nconst { ProxyAgent } = require('undici');\nconst { Client } = require('discord.js');\nconst { bootstrap } = require('global-agent'); // [!code ++:5]\n\nbootstrap(); // [!code word:bootstrap]\nglobal.GLOBAL_AGENT.HTTP_PROXY = 'http://my-proxy-server:port';\nglobal.GLOBAL_AGENT.HTTPS_PROXY = 'https://my-proxy-server:port';\n\nconst client = new Client({\n\t// ...other client options\n\trest: {\n\t\tagent: new ProxyAgent('http://my-proxy-server:port'),\n\t},\n});\n\nclient.login('your-token-goes-here');\n```\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/additional-info/rest-api.mdx",
    "content": "---\ntitle: REST APIs\n---\n\nREST APIs are extremely popular on the web and allow you to freely grab a site's data if it has an available API over an HTTP connection.\n\n## Making HTTP requests with Node\n\nIn these examples, we will be using [undici](https://www.npmjs.com/package/undici), an excellent library for making HTTP requests.\n\nTo install undici, run the following command:\n\n```sh tab=\"npm\"\nnpm i install undici\n```\n\n```sh tab=\"yarn\"\nyarn add undici\n```\n\n```sh tab=\"pnpm\"\npnpm add undici\n```\n\n## Skeleton code\n\nTo start off, you will be using the following skeleton code. Since both the commands you will be adding in this section require an interaction with external APIs, you will defer the reply, so your application responds with a \"thinking...\" state. You can then edit the reply once you got the data you need:\n\n```js title=\"rest-examples.js\" lineNumbers\nconst { Client, EmbedBuilder, Events, GatewayIntentBits } = require('discord.js');\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\nclient.once(Events.ClientReady, (readyClient) => {\n\tconsole.log(`Ready! Logged in as ${readyClient.user.tag}`);\n});\n\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tconst { commandName } = interaction;\n\tawait interaction.deferReply();\n\t// ...\n});\n\nclient.login('your-token-goes-here');\n```\n\n<Callout>\n\tWe're taking advantage of [destructuring](./es6-syntax#destructuring) in this tutorial to maintain readability.\n</Callout>\n\n## Using undici\n\nUndici is a Promise-based HTTP/1.1 client, written from scratch for Node.js. If you aren't already familiar with Promises, you should read up on them [here](./async-await).\n\nIn this tutorial, you will be making a bot with two API-based commands using the [random.cat](https://aws.random.cat) and [Urban Dictionary](https://www.urbandictionary.com) APIs.\n\nOn top of your file, import the library function you will be using:\n\n```js\nconst { request } = require('undici');\n```\n\n### Random Cat\n\n<Callout title=\"No more cats :(\" type=\"error\">\n\tUnfortunately, the `aws.random.cat` API doesn't work anymore. We will keep the example as-is until we find a better\n\tshowcase!\n</Callout>\n\nRandom cat's API is available at [https://aws.random.cat/meow](https://aws.random.cat/meow) and returns a [JSON](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON) response. To actually fetch data from the API, you're going to do the following:\n\n```js\nconst catResult = await request('https://aws.random.cat/meow');\nconst { file } = await catResult.body.json();\n```\n\nIf you just add this code, it will seem like nothing happens. What you do not see, is that you are launching a request to the random.cat server, which responds some JSON data. The helper function parses the response data to a JavaScript object you can work with. The object will have a `file` property with the value of a link to a random cat image.\n\nNext, you will implement this approach into an application command:\n\n```js\nclient.on(Events.InteractionCreate, async (interaction) => {\n\t// ...\n\tif (commandName === 'cat') {\n\t\tconst catResult = await request('https://aws.random.cat/meow');\n\t\tconst { file } = await catResult.body.json();\n\t\tinteraction.editReply({ files: [file] });\n\t}\n});\n```\n\nSo, here's what's happening in this code:\n\n1. Your application sends a `GET` request to random.cat.\n2. random.cat sees the request and gets a random file url from their database.\n3. random.cat then sends that file's URL as a JSON object in a stringified form that contains a link to the image.\n4. undici receives the response and you parse the body to a JSON object.\n5. Your application then attaches the image and sends it in Discord.\n\n### Urban Dictionary\n\nUrban Dictionary's API is available at [https://api.urbandictionary.com/v0/define](https://api.urbandictionary.com/v0/define), accepts a `term` parameter, and returns a JSON response.\n\nThe following code will fetch data from this api:\n\n```js\n// ...\nclient.on(Events.InteractionCreate, async (interaction) => {\n\t// ...\n\tif (commandName === 'urban') {\n\t\tconst term = interaction.options.getString('term');\n\t\tconst query = new URLSearchParams({ term }); // [!code word:URLSearchParams]\n\n\t\tconst dictResult = await request(`https://api.urbandictionary.com/v0/define?${query}`);\n\t\tconst { list } = await dictResult.body.json();\n\t}\n});\n```\n\nHere, you are using JavaScript's native [URLSearchParams class](https://developer.mozilla.org/docs/Web/API/URLSearchParams) to create a [query string](https://en.wikipedia.org/wiki/Query_string) for the URL so that the Urban Dictionary server can parse it and know what you want to look up.\n\nIf you were to do `/urban hello world`, then the URL would become https://api.urbandictionary.com/v0/define?term=hello%20world since the string `\"hello world\"` is encoded.\n\nYou can get the respective properties from the returned JSON. If you were to view it in your browser, it usually looks like a bunch of mumbo jumbo. If it doesn't, great! If it does, then you should get a JSON formatter/viewer. If you're using Chrome, [JSON Formatter](https://chrome.google.com/webstore/detail/json-formatter/bcjindcccaagfpapjjmafapmmgkkhgoa) is one of the more popular extensions. If you're not using Chrome, search for \"JSON formatter/viewer &lt;your browser&gt;\" and get one.\n\nNow, if you look at the JSON, you can see that it has a `list` property, which is an array of objects containing various definitions for the term (maximum 10). Something you always want to do when making API-based commands is to handle the case when no results are available. So, if you throw a random term in there (e.g. `njaksdcas`) and then look at the response the `list` array should be empty. Now you are ready to start writing!\n\nAs explained above, you'll want to check if the API returned any answers for your query, and send back the definition if that's the case:\n\n```js\nif (commandName === 'urban') {\n\t// ...\n\tif (!list.length) {\n\t\treturn interaction.editReply(`No results found for **${term}**.`);\n\t}\n\n\tinteraction.editReply(`**${term}**: ${list[0].definition}`);\n}\n```\n\nHere, you are only getting the first object from the array of objects called `list` and grabbing its `definition` property.\n\nIf you've followed the tutorial, you should have something like this:\n\nNow, you can make it an [embed](../popular-topics/embeds) for easier formatting.\n\nYou can define the following helper function at the top of your file. In the code below, you can use this function to truncate the returned data and make sure the embed doesn't error, because field values exceed 1024 characters.\n\n```js\nconst trim = (str, max) => (str.length > max ? `${str.slice(0, max - 3)}...` : str);\n```\n\nAnd here is how you can build the embed from the API data:\n\n```js\nconst [answer] = list;\n\nconst embed = new EmbedBuilder()\n\t.setColor(0xefff00)\n\t.setTitle(answer.word)\n\t.setURL(answer.permalink)\n\t.addFields(\n\t\t{ name: 'Definition', value: trim(answer.definition, 1_024) },\n\t\t{ name: 'Example', value: trim(answer.example, 1_024) },\n\t\t{ name: 'Rating', value: `${answer.thumbs_up} thumbs up. ${answer.thumbs_down} thumbs down.` },\n\t);\n\ninteraction.editReply({ embeds: [embed] });\n```\n\n<Callout>\n\tCheck out display components for a newer approach to message formatting! You can read the [display\n\tcomponents](../popular-topics/display-components) section of this guide to learn more about using them!\n</Callout>\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/app-creation/creating-commands.mdx",
    "content": "---\ntitle: Creating Slash Commands\n---\n\nimport { Step, Steps } from 'fumadocs-ui/components/steps';\nimport { File, Folder, Files } from 'fumadocs-ui/components/files';\n\nDiscord allows developers to register [slash commands](https://discord.com/developers/docs/interactions/application-commands), which provide users a first-class way of interacting directly with your application.\n\nSlash commands provide a huge number of benefits over manual message parsing, including:\n\n- Integration with the Discord client interface.\n- Automatic command detection and parsing of the associated options/arguments.\n- Typed argument inputs for command options, e.g. \"String\", \"User\", or \"Role\".\n- Validated or dynamic choices for command options.\n- In-channel private responses (ephemeral messages).\n- Pop-up form-style inputs for capturing additional information.\n\n...and many more!\n\n## Before you continue\n\nAssuming you've followed the guide so far, your project directory should look something like this:\n\n<Files>\n\t<Folder name=\"discord-bot\" defaultOpen>\n\t\t<Folder name=\"node_modules\" defaultOpen />\n\t\t<File name=\"config.json\" />\n\t\t<File name=\"index.js\" />\n\t\t<File name=\"package-lock.json\" />\n\t\t<File name=\"package.json\" />\n\t</Folder>\n</Files>\n\n<Steps>\n<Step>\n\n### Command Files\n\nThe individual command files, containing slash command definitions and functionality.\n\n</Step>\n<Step>\n\n### Command Handler\n\nThe [command handler](./handling-commands), dynamically reads the command files and executes commands.\n\n</Step>\n<Step>\n\n### Command Deployment\n\nThe command [deployment script](./deploying-commands) to register your slash commands with Discord.\n\n</Step>\n</Steps>\n\nThese steps can be followed in any order, but are all required to make your bot work. This page details step **1**. Make sure you also check out the other linked pages.\n\n## Individual command files\n\nCreate a new folder named `commands` and a subfolder named `utility` inside it, which is where you'll store all of your utility command files. You'll be using the class to construct the command definitions.\n\nAt a minimum, the definition of a slash command must have a name and a description. Slash command names must be between 1-32 characters and contain no capital letters, spaces, or symbols other than `-` and `_`. Using the builder, a simple `ping` command definition would look like this:\n\n```js\nnew SlashCommandBuilder().setName('ping').setDescription('Replies with Pong!');\n```\n\nA slash command also requires a function to run when the command is used, to respond to the interaction. Using an interaction response method confirms to Discord that your bot successfully received the interaction, and has responded to the user. Discord enforces this to ensure that all slash commands provide a good user experience (UX). Failing to respond will cause Discord to show that the command failed, even if your bot is performing other actions as a result.\n\nThe simplest way to acknowledge and respond to an interaction is the `interaction.reply()` method. Other methods of replying are covered on the [Response methods](../slash-commands/response-methods) page later in this section.\n\n```js\nasync execute(interaction) {\n\tawait interaction.reply('Pong!')\n}\n```\n\nPut these two together by creating a `ping.js` file in the `commands/utility` folder for your first command. Inside this file, you're going to define and export two items.\n\n- The `data` property, which will provide the command definition shown above for registering to Discord.\n- The `execute` method, which will contain the functionality to run from our event handler when the command is used.\n\nThese are placed inside `module.exports` so they can be read by other files; namely the command loader and command deployment scripts mentioned earlier.\n\n```js title=\"commands/utility/ping.js\"\nconst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder().setName('ping').setDescription('Replies with Pong!'),\n\tasync execute(interaction) {\n\t\tawait interaction.reply('Pong!');\n\t},\n};\n```\n\n<Callout>\n\t[`module.exports`](https://nodejs.org/api/modules.html#modules_module_exports) is how you export data in Node.js so that you can [`require()`](https://nodejs.org/api/modules.html#modules_require_id) it in other files.\n\n    If you need to access your client instance from inside a command file, you can access it via `interaction.client`. If you need to access external files, packages, etc., you should `require()` them at the top of the file.\n\n</Callout>\n\nThat's it for your basic ping command. Below are examples of two more commands we're going to build upon throughout the guide, so create two more files for these before you continue reading.\n\n```js tab=\"User\" title=\"commands/utility/user.js\"\nconst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder().setName('user').setDescription('Provides information about the user.'),\n\tasync execute(interaction) {\n\t\t// interaction.user is the object representing the User who ran the command\n\t\t// interaction.member is the GuildMember object, which represents the user in the specific guild\n\t\tawait interaction.reply(\n\t\t\t`This command was run by ${interaction.user.username}, who joined on ${interaction.member.joinedAt}.`,\n\t\t);\n\t},\n};\n```\n\n```js tab=\"Server\" title=\"commands/utility/server.js\"\nconst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder().setName('server').setDescription('Provides information about the server.'),\n\tasync execute(interaction) {\n\t\t// interaction.guild is the object representing the Guild in which the command was run\n\t\tawait interaction.reply(\n\t\t\t`This server is ${interaction.guild.name} and has ${interaction.guild.memberCount} members.`,\n\t\t);\n\t},\n};\n```\n\n#### Next steps\n\nYou can implement additional commands by creating new files within a dedicated subfolder in the `commands` folder, but these three are the ones we're going to use for the examples as we go on. For now let's move on to the code you'll need for command handling, to load the files and respond to incoming interactions.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/app-creation/deploying-commands.mdx",
    "content": "---\ntitle: Registering Commands\n---\n\nimport { Step, Steps } from 'fumadocs-ui/components/steps';\n\nFor fully functional slash commands, you need three important pieces of code:\n\n<Steps>\n<Step>\n\n### Command Files\n\nThe individual command files, containing [slash command](./creating-commands) definitions and functionality.\n\n</Step>\n<Step>\n\n### Command Handler\n\nThe [command handler](./handling-commands), dynamically reads the command files and executes commands.\n\n</Step>\n<Step>\n\n### Command Deployment\n\nThe command deployment script to register your slash commands with Discord.\n\n</Step>\n</Steps>\n\nThese steps can be followed in any order, but are all required to make your bot work. This page details step **3**. Make sure you also check out the other linked pages.\n\n## Command registration\n\nSlash commands can be registered in two ways; in one specific guild, or for every guild the bot is in. We're going to look at single-guild registration first, as this is a good way to develop and test your commands before a global deployment.\n\nYour application will need the `applications.commands` scope authorized in a guild for any of its slash commands to appear, and to be able to register them in a specific guild without error.\n\nSlash commands only need to be registered once, and updated when the definition (description, options etc) is changed. As there is a daily limit on command creations, it's not necessary nor desirable to connect a whole client to the gateway or do this on every `ready` event. As such, a standalone script using the lighter REST manager is preferred.\n\nThis script is intended to be run separately, only when you need to make changes to your slash command **definitions** - you're free to modify parts such as the execute function as much as you like without redeployment.\n\n### Guild commands\n\nCreate a `deploy-commands.js` file in your project directory. This file will be used to register and update the slash commands for your bot application.\n\nAdd two more properties to your `config.json` file, which we'll need in the deployment script:\n\n- `clientId`: Your application's client id ([Discord Developer Portal](https://discord.com/developers/applications) > \"General Information\" > application id)\n- `guildId`: Your development server's id ([Enable developer mode](https://support.discord.com/hc/articles/206346498) > Right-click the server title > \"Copy ID\")\n\n```json title=\"config.json\"\n{\n\t\"token\": \"your-token-goes-here\",\n\t// [!code ++:2]\n\t\"clientId\": \"your-application-id-goes-here\",\n\t\"guildId\": \"your-server-id-goes-here\"\n}\n```\n\nWith these defined, you can use the deployment script below:\n\n```js title=\"deploy-commands.js\" lineNumbers\nconst { REST, Routes } = require('discord.js');\nconst { clientId, guildId, token } = require('./config.json');\nconst fs = require('node:fs');\nconst path = require('node:path');\n\nconst commands = [];\n// Grab all the command folders from the commands directory you created earlier\nconst foldersPath = path.join(__dirname, 'commands');\nconst commandFolders = fs.readdirSync(foldersPath);\n\nfor (const folder of commandFolders) {\n\t// Grab all the command files from the commands directory you created earlier\n\tconst commandsPath = path.join(foldersPath, folder);\n\tconst commandFiles = fs.readdirSync(commandsPath).filter((file) => file.endsWith('.js'));\n\t// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment\n\tfor (const file of commandFiles) {\n\t\tconst filePath = path.join(commandsPath, file);\n\t\tconst command = require(filePath);\n\t\tif ('data' in command && 'execute' in command) {\n\t\t\tcommands.push(command.data.toJSON());\n\t\t} else {\n\t\t\tconsole.log(`[WARNING] The command at ${filePath} is missing a required \"data\" or \"execute\" property.`);\n\t\t}\n\t}\n}\n\n// Construct and prepare an instance of the REST module\nconst rest = new REST().setToken(token);\n\n// and deploy your commands!\n(async () => {\n\ttry {\n\t\tconsole.log(`Started refreshing ${commands.length} application (/) commands.`);\n\n\t\t// [!code word:Guild]\n\t\t// The put method is used to fully refresh all commands in the guild with the current set\n\t\tconst data = await rest.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands });\n\n\t\tconsole.log(`Successfully reloaded ${data.length} application (/) commands.`);\n\t} catch (error) {\n\t\t// And of course, make sure you catch and log any errors!\n\t\tconsole.error(error);\n\t}\n})();\n```\n\nOnce you fill in these values, run `node deploy-commands.js` in your project directory to register your commands to the guild specified. If you see the success message, check for the commands in the server by typing `/`! If all goes well, you should be able to run them and see your bot's response in Discord!\n\n### Global commands\n\nGlobal application commands will be available in all the guilds your application has the `applications.commands` scope authorized in, and in direct messages by default.\n\nTo deploy global commands, you can use the same script from the guild commands section above and simply adjust the route in the script to `.applicationCommands(clientId)`\n\n```js\nawait rest.put(Routes.applicationCommands(clientId), { body: commands });\n```\n\n### Where to deploy\n\n<Callout>\n    Guild-based deployment of commands is best suited for development and testing in your own personal server. Once you're satisfied that it's ready, deploy the command globally to publish it to all guilds that your bot is in.\n\n    You may wish to have a separate application and token in the Discord Dev Portal for your dev application, to avoid duplication between your guild-based commands and the global deployment.\n\n</Callout>\n\n#### Further reading\n\nYou've successfully sent a response to a slash command! However, this is only the most basic of command event and response functionality. Much more is available to enhance the user experience including:\n\n<Cards>\n\t<Card title=\"Event Handling\" href=\"./handling-events\">\n\t\tApply a similar dynamic, modular handling approach to client events.\n\t</Card>\n\t<Card title=\"Response Methods\" href=\"../slash-commands/response-methods\">\n\t\tUtilize different response methods for slash commands.\n\t</Card>\n\t<Card title=\"Advanced Command Creation\" href=\"../slash-commands/advanced-creation\">\n\t\tExpand on the command examples with additional, validated, option types.\n\t</Card>\n\t<Card title=\"Display Components\" href=\"../popular-topics/display-components\">\n\t\tLevel up command responses with formatted content and display components.\n\t</Card>\n\t<Card title=\"Interactive Components\" href=\"../interactive-components/action-rows\">\n\t\tEnhance your commands with more input methods using Buttons, Select Menus, and Modals!\n\t</Card>\n</Cards>\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/app-creation/handling-commands.mdx",
    "content": "---\ntitle: Command Handling\n---\n\nimport { Step, Steps } from 'fumadocs-ui/components/steps';\n\nUnless your bot project is small, it's not a very good idea to have a single file with a giant `if`/`else if` chain for commands. If you want to implement features into your bot and make your development process a lot less painful, you'll want to implement a command handler. Let's get started on that!\n\nFor fully functional slash commands, you need three important pieces of code:\n\n<Steps>\n<Step>\n\n### Command Files\n\nThe individual command files, containing [slash command](./creating-commands) definitions and functionality.\n\n</Step>\n<Step>\n\n### Command Handler\n\nThe command handler, dynamically reads the command files and executes commands.\n\n</Step>\n<Step>\n\n### Command Deployment\n\nThe command [deployment script](./deploying-commands) to register your slash commands with Discord.\n\n</Step>\n</Steps>\n\nThese steps can be followed in any order, but are all required to make your bot work. This page details step **2**. Make sure you also check out the other linked pages.\n\n## Loading command files\n\nNow that your command files have been created, your bot needs to load these files on startup.\n\nIn your `index.js` file, make these additions to the base template:\n\n```js title=\"index.js\" lineNumbers\n// [!code ++:4]\nconst fs = require('node:fs');\nconst path = require('node:path');\nconst { Client, Collection, Events, GatewayIntentBits, MessageFlags } = require('discord.js');\nconst { token } = require('./config.json');\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\nclient.once(Events.ClientReady, (readyClient) => {\n\tconsole.log(`Ready! Logged in as ${readyClient.user.tag}`);\n});\n\nclient.commands = new Collection(); // [!code ++]\n```\n\nWe recommend attaching a `.commands` property to your client instance so that you can access your commands in other files. The rest of the examples in this guide will follow this convention. For TypeScript users, we recommend extending the base Client class to add this property, [casting](https://www.typescripttutorial.net/typescript-tutorial/type-casting/), or [augmenting the module type](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation).\n\n<Callout>\n\t- The [`fs`](https://nodejs.org/api/fs.html) module is Node's native file system module. `fs` is used to read the\n\t`commands` directory and identify our command files. - The [`path`](https://nodejs.org/api/path.html) module is Node's\n\tnative path utility module. `path` helps construct paths to access files and directories. One of the advantages of the\n\t`path` module is that it automatically detects the operating system and uses the appropriate joiners. - The\n\t`Collection` class extends JavaScript's native\n\t[`Map`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Map) class, and includes more\n\textensive, useful functionality. `Collection` is used to store and efficiently retrieve commands for execution.\n</Callout>\n\nNext, using the modules imported above, dynamically retrieve your command files with a few more additions to the `index.js` file:\n\n```js title=\"index.js\" lineNumbers=12\nclient.commands = new Collection();\n\nconst foldersPath = path.join(__dirname, 'commands');\nconst commandFolders = fs.readdirSync(foldersPath);\n\nfor (const folder of commandFolders) {\n\tconst commandsPath = path.join(foldersPath, folder);\n\tconst commandFiles = fs.readdirSync(commandsPath).filter((file) => file.endsWith('.js'));\n\tfor (const file of commandFiles) {\n\t\tconst filePath = path.join(commandsPath, file);\n\t\tconst command = require(filePath);\n\t\t// Set a new item in the Collection with the key as the command name and the value as the exported module\n\t\tif ('data' in command && 'execute' in command) {\n\t\t\tclient.commands.set(command.data.name, command);\n\t\t} else {\n\t\t\tconsole.log(`[WARNING] The command at ${filePath} is missing a required \"data\" or \"execute\" property.`);\n\t\t}\n\t}\n}\n```\n\nFirst, [`path.join()`](https://nodejs.org/api/path.html#pathjoinpaths) helps to construct a path to the `commands` directory. The first [`fs.readdirSync()`](https://nodejs.org/api/fs.html#fs_fs_readdirsync_path_options) method then reads the path to the directory and returns an array of all the folder names it contains, currently `['utility']`. The second `fs.readdirSync()` method reads the path to this directory and returns an array of all the file names they contain, currently `['ping.js', 'server.js', 'user.js']`. To ensure only command files get processed, `Array.filter()` removes any non-JavaScript files from the array.\n\nWith the correct files identified, the last step is dynamically set each command into the `client.commands` Collection. For each file being loaded, check that it has at least the `data` and `execute` properties. This helps to prevent errors resulting from loading empty, unfinished, or otherwise incorrect command files while you're still developing.\n\n## Receiving command interactions\n\nYou will receive an interaction for every slash command executed. To respond to a command, you need to create a listener for the `interactionCreate` event that will execute code when your application receives an interaction. Place the code below in the `index.js` file you created earlier.\n\n```js title=\"index.js\" lineNumbers=32\n// [!code ++:3]\nclient.on(Events.InteractionCreate, (interaction) => {\n\tconsole.log(interaction);\n});\n```\n\nNot every interaction is a slash command (e.g. `MessageComponent` interactions). Make sure to only handle slash commands in this function by making use of the `BaseInteraction#isChatInputCommand` method to exit the handler if another type is encountered. This method also provides typeguarding for TypeScript users, narrowing the type from `BaseInteraction` to a `ChatInputCommandInteraction`.\n\n```js title=\"index.js\" lineNumbers=32\nclient.on(Events.InteractionCreate, (interaction) => {\n\tif (!interaction.isChatInputCommand()) return; // [!code ++]\n\tconsole.log(interaction);\n});\n```\n\n## Executing commands\n\nWhen your bot receives a `interactionCreate` event, the interaction object contains all the information you need to dynamically retrieve and execute your commands!\n\nLet's take a look at the `ping` command again. Note the `execute()` function that will reply to the interaction with \"Pong!\".\n\n```js title=\"commands/utility/ping.js\"\n// [!code word:execute]\nmodule.exports = {\n\tdata: new SlashCommandBuilder().setName('ping').setDescription('Replies with Pong!'),\n\tasync execute(interaction) {\n\t\tawait interaction.reply('Pong!');\n\t},\n};\n```\n\nFirst, you need to get the matching command from the `client.commands` Collection based on the `interaction.commandName`. Your `Client` instance is always available via `interaction.client`. If no matching command is found, log an error to the console and ignore the event.\n\nWith the right command identified, all that's left to do is call the command's `.execute()` method and pass in the `interaction` variable as its argument. In case something goes wrong, catch and log any error to the console.\n\n```js title=\"index.js\" lineNumbers=32\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\t// [!code ++:23]\n\tconst command = interaction.client.commands.get(interaction.commandName);\n\n\tif (!command) {\n\t\tconsole.error(`No command matching ${interaction.commandName} was found.`);\n\t\treturn;\n\t}\n\n\ttry {\n\t\tawait command.execute(interaction);\n\t} catch (error) {\n\t\tconsole.error(error);\n\t\tif (interaction.replied || interaction.deferred) {\n\t\t\tawait interaction.followUp({\n\t\t\t\tcontent: 'There was an error while executing this command!',\n\t\t\t\tflags: MessageFlags.Ephemeral,\n\t\t\t});\n\t\t} else {\n\t\t\tawait interaction.reply({\n\t\t\t\tcontent: 'There was an error while executing this command!',\n\t\t\t\tflags: MessageFlags.Ephemeral,\n\t\t\t});\n\t\t}\n\t}\n});\n```\n\n#### Next steps\n\nYour command files are now loaded into your bot, and the event listener is prepared and ready to respond. In the next section, we cover the final step: a command deployment script you'll need to register your commands so they appear in the Discord client.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/app-creation/handling-events.mdx",
    "content": "---\ntitle: Event Handling\n---\n\nimport { File, Folder, Files } from 'fumadocs-ui/components/files';\n\nNode.js uses an event-driven architecture, making it possible to execute code when a specific event occurs. The discord.js library takes full advantage of this. You can visit the `Client` documentation to see the full list of events.\n\n<Callout>\n\tThis page assumes you've followed the guide up to this point, and created your `index.js` and individual slash\n\tcommands according to those pages.\n</Callout>\n\nAt this point, your `index.js` file has listeners for two events: `ClientReady` and `InteractionCreate`.\n\n```js title=\"index.js\"\n// [!code word:ClientReady]\nclient.once(Events.ClientReady, (readyClient) => {\n\tconsole.log(`Ready! Logged in as ${readyClient.user.tag}`);\n\n// [!code word:InteractionCreate]\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tconst command = interaction.client.commands.get(interaction.commandName);\n\n\tif (!command) {\n\t\tconsole.error(`No command matching ${interaction.commandName} was found.`);\n\t\treturn;\n\t}\n\n\ttry {\n\t\tawait command.execute(interaction);\n\t} catch (error) {\n\t\tconsole.error(error);\n\t\tif (interaction.replied || interaction.deferred) {\n\t\t\tawait interaction.followUp({\n\t\t\t\tcontent: 'There was an error while executing this command!',\n\t\t\t\tflags: MessageFlags.Ephemeral,\n\t\t\t});\n\t\t} else {\n\t\t\tawait interaction.reply({\n\t\t\t\tcontent: 'There was an error while executing this command!',\n\t\t\t\tflags: MessageFlags.Ephemeral,\n\t\t\t});\n\t\t}\n\t}\n});\n```\n\nCurrently, the event listeners are in the `index.js` file. `Client#ready`emits once when the `Client` becomes ready for use, and `Client#interactionCreate` emits whenever an interaction is received. Moving the event listener code into individual files is simple, and we'll be taking a similar approach to the command handler.\n\n<Callout type=\"warn\">\n\tYou're only going to move these two events from `index.js`. The code for [loading command\n\tfiles](./handling-commands#loading-command-files) will stay here!\n</Callout>\n\n## Individual event files\n\nYour project directory should look something like this:\n\n<Files>\n\t<Folder name=\"discord-bot\" defaultOpen>\n\t\t<Folder name=\"commands\" defaultOpen />\n\t\t<Folder name=\"node_modules\" defaultOpen />\n\t\t<File name=\"config.json\" />\n\t\t<File name=\"deploy-commands.js\" />\n\t\t<File name=\"index.js\" />\n\t\t<File name=\"package-lock.json\" />\n\t\t<File name=\"package.json\" />\n\t</Folder>\n</Files>\n\nCreate an `events` folder in the same directory. You can then move the code from your event listeners in `index.js` to separate files: `events/ready.js` and `events/interactionCreate.js`.\n\n```js tab=\"Ready Handler\" title=\"events/ready.js\"\nconst { Events } = require('discord.js');\n\nmodule.exports = {\n\tname: Events.ClientReady,\n\tonce: true,\n\texecute(client) {\n\t\tconsole.log(`Ready! Logged in as ${client.user.tag}`);\n\t},\n};\n```\n\n```js tab=\"Interaction Handler\" title=\"events/interactionCreate.js\"\nconst { Events, MessageFlags } = require('discord.js');\n\nmodule.exports = {\n\tname: Events.InteractionCreate,\n\tasync execute(interaction) {\n\t\tif (!interaction.isChatInputCommand()) return;\n\n\t\tconst command = interaction.client.commands.get(interaction.commandName);\n\n\t\tif (!command) {\n\t\t\tconsole.error(`No command matching ${interaction.commandName} was found.`);\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tawait command.execute(interaction);\n\t\t} catch (error) {\n\t\t\tconsole.error(error);\n\t\t\tif (interaction.replied || interaction.deferred) {\n\t\t\t\tawait interaction.followUp({\n\t\t\t\t\tcontent: 'There was an error while executing this command!',\n\t\t\t\t\tflags: MessageFlags.Ephemeral,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tawait interaction.reply({\n\t\t\t\t\tcontent: 'There was an error while executing this command!',\n\t\t\t\t\tflags: MessageFlags.Ephemeral,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t},\n};\n```\n\n```js title=\"index.js\" tab=\"Main File (after removing events)\"\nconst fs = require('node:fs');\nconst path = require('node:path');\nconst { Client, Collection, GatewayIntentBits } = require('discord.js');\nconst { token } = require('./config.json');\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\nclient.commands = new Collection();\nconst foldersPath = path.join(__dirname, 'commands');\nconst commandFolders = fs.readdirSync(foldersPath);\n\nfor (const folder of commandFolders) {\n\tconst commandsPath = path.join(foldersPath, folder);\n\tconst commandFiles = fs.readdirSync(commandsPath).filter((file) => file.endsWith('.js'));\n\tfor (const file of commandFiles) {\n\t\tconst filePath = path.join(commandsPath, file);\n\t\tconst command = require(filePath);\n\t\tif ('data' in command && 'execute' in command) {\n\t\t\tclient.commands.set(command.data.name, command);\n\t\t} else {\n\t\t\tconsole.log(`[WARNING] The command at ${filePath} is missing a required \"data\" or \"execute\" property.`);\n\t\t}\n\t}\n}\n\nclient.login(token);\n```\n\nThe `name` property states which event this file is for, and the `once` property holds a boolean value that specifies if the event should run only once. You don't need to specify this in `interactionCreate.js` as the default behavior will be to run on every event instance. The `execute` function holds your event logic, which will be called by the event handler whenever the event emits.\n\n## Reading event files\n\nNext, let's write the code for dynamically retrieving all the event files in the `events` folder. We'll be taking a similar approach to our [command handler](./handling-commands). Place the new code highlighted below in your `index.js`.\n\n`fs.readdirSync().filter()` returns an array of all the file names in the given directory and filters for only `.js` files, i.e. `['ready.js', 'interactionCreate.js']`.\n\n```js title=\"index.js\"\nconst fs = require('node:fs');\nconst path = require('node:path');\nconst { Client, Collection, GatewayIntentBits } = require('discord.js');\nconst { token } = require('./config.json');\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\nclient.commands = new Collection();\nconst foldersPath = path.join(__dirname, 'commands');\nconst commandFolders = fs.readdirSync(foldersPath);\n\nfor (const folder of commandFolders) {\n\tconst commandsPath = path.join(foldersPath, folder);\n\tconst commandFiles = fs.readdirSync(commandsPath).filter((file) => file.endsWith('.js'));\n\tfor (const file of commandFiles) {\n\t\tconst filePath = path.join(commandsPath, file);\n\t\tconst command = require(filePath);\n\t\tif ('data' in command && 'execute' in command) {\n\t\t\tclient.commands.set(command.data.name, command);\n\t\t} else {\n\t\t\tconsole.log(`[WARNING] The command at ${filePath} is missing a required \"data\" or \"execute\" property.`);\n\t\t}\n\t}\n}\n\n// [!code ++:12]\nconst eventsPath = path.join(__dirname, 'events');\nconst eventFiles = fs.readdirSync(eventsPath).filter((file) => file.endsWith('.js'));\n\nfor (const file of eventFiles) {\n\tconst filePath = path.join(eventsPath, file);\n\tconst event = require(filePath);\n\tif (event.once) {\n\t\tclient.once(event.name, (...args) => event.execute(...args));\n\t} else {\n\t\tclient.on(event.name, (...args) => event.execute(...args));\n\t}\n}\n\nclient.login(token);\n```\n\nYou'll notice the code looks very similar to the command loading above it - read the files in the events folder and load each one individually.\n\nThe `Client` class in discord.js extends the [`EventEmitter`](https://nodejs.org/api/events.html#events_class_eventemitter) class. Therefore, the `client` object exposes the [`.on()`](https://nodejs.org/api/events.html#events_emitter_on_eventname_listener) and [`.once()`](https://nodejs.org/api/events.html#events_emitter_once_eventname_listener) methods that you can use to register event listeners. These methods take two arguments: the event name and a callback function. These are defined in your separate event files as `name` and `execute`.\n\nThe callback function passed takes argument(s) returned by its respective event, collects them in an `args` array using the `...` [rest parameter syntax](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Functions/rest_parameters), then calls `event.execute()` while passing in the `args` array using the `...` [spread syntax](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Spread_syntax). They are used here because different events in discord.js have different numbers of arguments. The rest parameter collects these variable number of arguments into a single array, and the spread syntax then takes these elements and passes them to the `execute` function.\n\nAfter this, listening for other events is as easy as creating a new file in the `events` folder. The event handler will automatically retrieve and register it whenever you restart your bot.\n\n<Callout>\n\tIn most cases, you can access your `client` instance in other files by obtaining it from one of the other discord.js\n\tstructures, e.g. `interaction.client` in the `interactionCreate` event. You do not need to manually pass it to your\n\tevents.\n</Callout>\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/app-creation/main-file.mdx",
    "content": "---\ntitle: The Main File\n---\n\n<Callout>\n\tThis page assumes you've already prepared the [configuration files](../app-creation/project-setup#configuration-files)\n\tfrom the previous page. We're using the `config.json` approach, however feel free to substitute your own!\n</Callout>\n\n## Creating the main file\n\nOpen your code editor and create a new file. We suggest that you save the file as `index.js`, but you may name it whatever you wish.\n\nHere's the base code to get you started:\n\n```js title=\"index.js\"\n// Require the necessary discord.js classes\nconst { Client, Events, GatewayIntentBits } = require('discord.js');\nconst { token } = require('./config.json');\n\n// Create a new client instance\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\n// When the client is ready, run this code (only once).\n// The distinction between `client: Client<boolean>` and `readyClient: Client<true>` is important for TypeScript developers.\n// It makes some properties non-nullable.\nclient.once(Events.ClientReady, (readyClient) => {\n\tconsole.log(`Ready! Logged in as ${readyClient.user.tag}`);\n});\n\n// Log in to Discord with your client's token\nclient.login(token);\n```\n\nThis is how you create a client instance for your Discord bot and log in to Discord. The `GatewayIntentBits.Guilds` intents option is necessary for the discord.js client to work as you expect it to, as it ensures that the caches for guilds, channels, and roles are populated and available for internal use.\n\n<Callout>The term \"guild\" is used by the Discord API and in discord.js to refer to a Discord server.</Callout>\n\nIntents also define which events Discord should send to your bot, and you may wish to enable more than just the minimum. You can read more about the other intents in the [Intents topic](../popular-topics/intents).\n\n## Running your application\n\nOpen your terminal and run `node index.js` to start the process. If you see \"Ready!\" after a few seconds, you're good to go! The next step is to start adding slash commands to develop your app's functionality.\n\n<Callout>\n    You can open your `package.json` file and edit the `\"main\": \"index.js\"` field to point to your main file. You can then run `node .` in your terminal to start the process!\n\n    After closing the process with <kbd>Ctrl</kbd> <kbd>C</kbd>, you can press the up arrow on your keyboard to bring up the latest commands you've run. Pressing up and then enter after closing the process is a quick way to start it up again.\n\n</Callout>\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/app-creation/meta.json",
    "content": "{\n\t\"title\": \"Creating Your App\",\n\t\"pages\": [\n\t\t\"project-setup\",\n\t\t\"main-file\",\n\t\t\"creating-commands\",\n\t\t\"handling-commands\",\n\t\t\"deploying-commands\",\n\t\t\"handling-events\"\n\t]\n}\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/app-creation/project-setup.mdx",
    "content": "---\ntitle: Project Setup\n---\n\n## Configuration files\n\nOnce you [add your bot to a server](../preparations/adding-your-app), the next step is to start coding and get it online! Let's start by creating a config file for your client token and a main file for your bot application.\n\nAs explained in the [\"What is a token, anyway?\"](../preparations/app-setup#what-is-a-token-anyway) section, your token is essentially your bot's password, and you should protect it as best as possible. This can be done through a `config.json` file or by using environment variables.\n\nOpen your application in the [Discord Developer Portal](https://discord.com/developers/applications) and go to the \"Bot\" page to copy your token.\n\n## Using `config.json`\n\nStoring data in a `config.json` file is a common way of keeping your sensitive values safe. Create a `config.json` file in your project directory and paste in your token. You can access your token inside other files by using `require()`.\n\n```json tab=\"Config\" title=\"config.json\"\n{\n\t\"token\": \"your-token-goes-here\"\n}\n```\n\n```js tab=\"Usage\"\nconst { token } = require('./config.json');\n\nconsole.log(token);\n```\n\n<Callout title=\"Danger\" type=\"error\">\n\tIf you're using Git, you should not commit files containing secrets. Read on to find out how to [exclude them from\n\tversioning by using `.gitignore`](#git-and-gitignore).\n</Callout>\n\n## Using environment variables\n\nEnvironment variables are, as the name suggests, values you can pass to your environment (e.g. terminal session, Docker container, node process). This has the benefit that you can keep your code the same for different execution contexts.\n\n```txt title=\".env\"\nA=Hello World\nB=123\nDISCORD_TOKEN=MTI3NDMxMjA3PDQ3ODIxNzIzNg.G6uEbl.IpA3-9YeScYr9pu9K1utMlpP4p-KJwNxcIAbi8\n```\n\n<Callout title=\"Danger\" type=\"error\">\n\tIf you're using Git, you should not commit `.env` or other environment files containing secrets. Read on to find out\n\thow to [exclude them from versioning by using `.gitignore`](#git-and-gitignore).\n</Callout>\n\nTo use environment variables in Node.js, we recommend you use the command line interface flag `--env-file` to point to the `.env` file you want to use. Note that the file name `.env` is just a convention. You could for example have a `.env.development` and `.env.production` file with different values depending on the Discord application you want to run your code.\n\nYou can also read multiple environment files by using the `--env-file` flag multiple times.\n\n```sh\nnode --env-file=.env index.js\n```\n\n<Callout>You don't need to pass any special flags when using Bun! Bun reads `.env` files automatically.</Callout>\n\nThe values you specify in `.env` files this way are exposed through the `process.env` global variable in any file. Note that values passed this way will always be strings. If you want to do calculations on environment numbers, you will have to parse them:\n\n```js title=\"index.js\"\n// [!code word:env]\nconsole.log(process.env.A);\nconsole.log(process.env.B + 9); // 1239 (this concatenates the number to the string!)\nconsole.log(Number(process.env.C) + 9); // 132\nconsole.log(process.env.DISCORD_TOKEN);\n```\n\n## Online editors\n\nWhile we generally do not recommend using online editors as hosting solutions, but rather invest in a proper virtual private server, these services do offer ways to keep your credentials safe as well! Please see the respective service's documentation and help articles for more information on how to keep sensitive values safe:\n\n<Cards>\n\t<Card title=\"Glitch\" href=\"https://help.glitch.com/s/article/Adding-Private-Data\">\n\t\tLearn more about storing secrets in `.env` files using Glitch\n\t</Card>\n\t<Card title=\"Heroku\" href=\"https://devcenter.heroku.com/articles/config-vars\">\n\t\tLearn more about configuration variables in Heroku\n\t</Card>\n\t<Card title=\"Replit\" href=\"https://docs.replit.com/replit-workspace/workspace-features/secrets#secrets\">\n\t\tLearn more about secrets and environment variables in Replit\n\t</Card>\n</Cards>\n\n## Git and `.gitignore`\n\nGit is a fantastic tool to keep track of your code changes and allows you to upload progress to services like [GitHub](https://github.com/), [GitLab](https://about.gitlab.com/), or [Bitbucket](https://bitbucket.org/product). While this is super useful to share code with other developers, it also bears the risk of uploading your configuration files with sensitive values!\n\nYou can specify files that Git should ignore in its versioning systems with a `.gitignore` file. Create a `.gitignore` file in your project directory and add the names of the files and folders you want to ignore. The following example ignores the `config.json` and `.env` files as well as the `node_modules` directory:\n\n```txt title=\".gitignore\"\nnode_modules\n.env\nconfig.json\n```\n\n<Callout>\n\t`.gitignore` files can specify intricate patterns and help with your general development flow. Apart from keeping your\n\tcredentials safe, you should exclude `node_modules` from version control as well, its contents can be restored from\n\tthe entries in your `package.json` and `package-lock.json` files.\n</Callout>\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/improving-dev-environment/meta.json",
    "content": "{\n\t\"title\": \"Improving Your Dev Environment\"\n}\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/improving-dev-environment/package-json-scripts.mdx",
    "content": "---\ntitle: Package Scripts\n---\n\n## Setting up package.json scripts\n\nAn easy way to run scripts like a script to start your bot, a script to lint your bot's files, or whatever scripts you use is by storing them in your `package.json` file. After you store these scripts in your `package.json` file, you can run the `start` script to start your bot or the `lint` script to lint your code for errors.\n\n```sh tab=\"npm\"\nnpm run start\nnpm run lint\n```\n\n```sh tab=\"yarn\"\nyarn run start\nyarn run lint\n```\n\n```sh tab=\"pnpm\"\npnpm run start\npnpm run lint\n```\n\n```sh tab=\"bun\"\nbun run start\nbun run lint\n```\n\n## Getting started\n\n<Callout>\nBefore getting started, you'll need to have a `package.json` file. If you don't have a `package.json` file yet, you can run the following command in the console to generate one.\n\n```sh tab=\"npm\"\nnpm init -y\n```\n\n```sh tab=\"yarn\"\nyarn init -y\n```\n\n```sh tab=\"pnpm\"\npnpm init\n```\n\n```sh tab=\"bun\"\nbun init -y\n```\n\n</Callout>\n\nIf you haven't touched your `package.json` file yet (excluding installing dependencies), your `package.json` file should look similar to the following:\n\n```json title=\"package.json\"\n{\n\t\"name\": \"my-bot\",\n\t\"version\": \"1.0.0\",\n\t\"description\": \"A Discord bot!\",\n\t\"main\": \"index.js\",\n\t\"scripts\": {\n\t\t\"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n\t},\n\t\"keywords\": [],\n\t\"author\": \"\",\n\t\"license\": \"ISC\"\n}\n```\n\nLet's zoom in more. Below `main`, you'll see `scripts`. You can specify your scripts there. In this guide, we'll show how to start and lint your bot using a `package.json` script.\n\n## Adding your first script\n\n<Callout>\n\tWe'll assume you have finished the [creating your app](../app-creation/project-setup) section of the guide. If you\n\thaven't, ensure to follow it first!\n</Callout>\n\nOver at your `package.json` file, add the following line to the `scripts`:\n\n```json title=\"package.json\"\n{\n\t\"name\": \"my-bot\",\n\t\"version\": \"1.0.0\",\n\t\"description\": \"A Discord bot!\",\n\t\"main\": \"index.js\",\n\t\"scripts\": { // [!code focus:5]\n\t\t\"test\": \"echo \\\"Error: no test specified\\\" && exit 1\" // needs a comma // [!code --]\n\t\t\"test\": \"echo \\\"Error: no test specified\\\" && exit 1\", // [!code ++]\n\t\t\"start\": \"node .\" // [!code ++]\n\t},\n\t\"keywords\": [],\n\t\"author\": \"\",\n\t\"license\": \"ISC\"\n}\n```\n\n<Callout>\n\tThe `node .` script will run the file you have specified at the `main` entry in your `package.json` file. If you don't\n\thave it set yet, make sure to select your bot's main file as `main`!\n</Callout>\n\nNow, whenever you run the `start` script in your bot's directory, it will run the `node .` command.\n\n```sh tab=\"npm\"\nnpm run start\n```\n\n```sh tab=\"yarn\"\nyarn run start\n```\n\n```sh tab=\"pnpm\"\npnpm run start\n```\n\n```sh tab=\"bun\"\nbun run start\n```\n\nLet's create another script to lint your code via the command line. Add the following line to your scripts:\n\n```json title=\"package.json\"\n{\n\t\"name\": \"my-bot\",\n\t\"version\": \"1.0.0\",\n\t\"description\": \"A Discord bot!\",\n\t\"main\": \"index.js\",\n\t\"scripts\": { // [!code focus:6]\n\t\t\"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n\t\t\"start\": \"node .\" // needs a comma // [!code --]\n\t\t\"start\": \"node .\", // [!code ++]\n\t\t\"lint\": \"eslint .\" // [!code ++]\n\t},\n\t\"keywords\": [],\n\t\"author\": \"\",\n\t\"license\": \"ISC\"\n}\n```\n\nNow, whenever you run the `lint` script, ESLint will lint your `index.js` file.\n\n```sh tab=\"npm\"\nnpm run lint\n```\n\n```sh tab=\"yarn\"\nyarn run lint\n```\n\n```sh tab=\"pnpm\"\npnpm run lint\n```\n\n```sh tab=\"bun\"\nbun run lint\n```\n\nYour `package.json` file should now look similar to the following:\n\n```json\n{\n\t\"name\": \"my-bot\",\n\t\"version\": \"1.0.0\",\n\t\"description\": \"A Discord bot!\",\n\t\"main\": \"index.js\",\n\t\"scripts\": {\n\t\t\"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n\t\t\"start\": \"node .\",\n\t\t\"lint\": \"eslint .\"\n\t},\n\t\"keywords\": [],\n\t\"author\": \"\",\n\t\"license\": \"ISC\"\n}\n```\n\nAnd that's it! You can always add more scripts now, running them with:\n\n```sh tab=\"npm\"\nnpm run <script-name>\n```\n\n```sh tab=\"yarn\"\nyarn run <script-name>\n```\n\n```sh tab=\"pnpm\"\npnpm run <script-name>\n```\n\n```sh tab=\"bun\"\nbun run <script-name>\n```\n\n<Cards>\n\t<Card title=\"Package Scripts\" href=\"https://docs.npmjs.com/cli/v7/using-npm/scripts\">\n\t\tPackage scripts allow some more configuration (like pre-, post- and lifecycle scripts) than we can cover in this\n\t\tguide. Check out the official documentation on for more information.\n\t</Card>\n</Cards>\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/improving-dev-environment/pm2.mdx",
    "content": "---\ntitle: PM2\n---\n\nPM2 is a process manager. It manages your applications' states, so you can start, stop, restart, and delete processes. It offers features such as monitoring running processes and setting up a \"start with operating system\" (be that Windows, Linux, or Mac) so your processes start when you boot your system.\n\n## Installation\n\nYou can install PM2 via the following command:\n\n```sh tab=\"npm\"\nnpm install --global pm2\n```\n\n```sh tab=\"yarn\"\nyarn global add pm2\n```\n\n```sh tab=\"pnpm\"\npnpm add --global pm2\n```\n\n```sh tab=\"bun\"\nbun add --global pm2\n```\n\n## Starting your app\n\nAfter you install PM2, the easiest way you can start your app is by going to the directory your bot is in and then run the following:\n\n```sh\npm2 start your-app-name.js\n```\n\n### Additional notes\n\nThe `pm2 start` script allows for more optional command-line arguments.\n\n- `--name`: This allows you to set the name of your process when listing it up with `pm2 list` or `pm2 monit`:\n\n```sh\npm2 start your-app-name.js --name \"Some cool name\"\n```\n\n- `--watch`: This option will automatically restart your process as soon as a file change is detected, which can be useful for development environments:\n\n```bash\npm2 start your-app-name.js --watch\n```\n\n<Callout>\n\tThe `pm2 start` command can take more optional parameters, but only these two are relevant. If you want to see all the\n\tparameters available, you can check the documentation of pm2\n\t[here](https://pm2.keymetrics.io/docs/usage/pm2-doc-single-page/).\n</Callout>\n\nOnce the process launches with pm2, you can run `pm2 monit` to monitor all console outputs from the processes started by pm2. This accounts for any `console.log()` in your code or outputted errors.\n\nIn a similar fashion to how you start the process, running `pm2 stop` will stop the current process without removing it from PM2's interface:\n\n```sh\npm2 stop your-app-name.js\n```\n\n## Setting up booting with your system\n\nPerhaps one of the more useful features of PM2 is being able to boot up with your Operating System. This feature will ensure that your bot processes will always be started after an (unexpected) reboot (e.g., after a power outage).\n\nThe initial steps differ per OS. In this guide, we'll cover those for Windows and Linux/macOS.\n\n### Initial steps for Windows\n\nIt is recommended to use `pm2-installer`. Follow the steps over at their [`GitHub`](https://github.com/jessety/pm2-installer).\n\n### Initial steps for Linux/macOS\n\nYou'll need a start script, which you can get by running the following command:\n\n```sh\n# Detects the available init system, generates the config, and enables startup system\npm2 startup\n```\n\nOr, if you want to specify your machine manually, select one of the options with the command:\n\n```sh\npm2 startup [ubuntu | ubuntu14 | ubuntu12 | centos | centos6 | arch | oracle | amazon | macos | darwin | freesd | systemd | systemv | upstart | launchd | rcd | openrc]\n```\n\nThe output of running one of the commands listed above will output a command for you to run with all environment variables and options configured.\n\n**Example output for an Ubuntu user:**\n\n```\n[PM2] You have to run this command as root. Execute the following command:\n      sudo su -c \"env PATH=$PATH:/home/user/.nvm/versions/node/v8.9/bin pm2 startup ubuntu -u user --hp /home/user\n```\n\nAfter running that command, you can continue to the next step.\n\n### Saving the current process list\n\nTo save the current process list so it will automatically get started after a restart, run the following command:\n\n```sh\npm2 save\n```\n\nTo disable this, you can run the following command:\n\n```sh\npm2 unstartup\n```\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/index.mdx",
    "content": "---\ntitle: Introduction\n---\n\nimport { GithubInfo } from '@/components/GitHubInfo';\n\n<GithubInfo owner=\"discordjs\" repo=\"discord.js\" />\n\nIf you're reading this, it probably means you want to learn how to make a bot with discord.js. Awesome! You've come to the right place.\nThis guide will teach you things such as:\n\n- How to get a bot [up and running](./legacy/preparations/app-setup) from scratch;\n- How to properly [create](./legacy/app-creation/project-setup), [organize](./legacy/app-creation/handling-commands), and expand on your commands;\n- In-depth explanations and examples regarding popular topics (e.g. [components](./legacy/popular-topics/display-components), [reactions](./legacy/popular-topics/reactions), [embeds](./legacy/popular-topics/embeds), [canvas](./legacy/popular-topics/canvas));\n- Working with databases (e.g. [sequelize](./legacy/sequelize/) and [keyv](./legacy/keyv/keyv));\n- Getting started with [sharding](./legacy/sharding/);\n- And much more.\n\nThis guide will also cover subjects like common errors and how to solve them, keeping your code clean, setting up a proper development environment, etc.\nSounds good? Great! Let's get started, then.\n\n## Before you begin...\n\nAlright, making a bot is cool and all, but there are some prerequisites to it. To create a bot with discord.js, you should have a fairly decent grasp of JavaScript itself.\nWhile you _can_ make a bot with very little JavaScript and programming knowledge, trying to do so without understanding the language first will only hinder you. You may get stuck on many uncomplicated issues, struggle with solutions to incredibly easy problems, and all-in-all end up frustrated. Sounds pretty annoying.\n\nIf you don't know JavaScript but would like to learn about it, here are a few links to help get you started:\n\n- [Eloquent JavaScript, a free online book](http://eloquentjavascript.net/)\n- [JavaScript.info, a modern javascript tutorial](https://javascript.info/)\n- [Codecademy's interactive JavaScript course](https://www.codecademy.com/learn/introduction-to-javascript)\n- [Nodeschool, for both JavaScript and Node.js lessons](https://nodeschool.io/)\n- [MDN's JavaScript guide and full documentation](https://developer.mozilla.org/docs/Web/JavaScript)\n- [Google, your best friend](https://google.com)\n\nTake your pick, learn some JavaScript, and once you feel like you're confident enough to make a bot, come back and get started!\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/interactions/context-menus.mdx",
    "content": "---\ntitle: Context Menus\n---\n\nContext Menus are application commands which appear when right clicking or tapping a user or a message, in the Apps submenu.\n\n<Callout>\n\tThis page is a follow-up to the [slash commands](../slash-commands/advanced-creation) section. Please carefully read\n\tthose pages first so that you can understand the methods used in this section.\n</Callout>\n\n## Registering context menu commands\n\nTo create a context menu command, use the `ContextMenuCommandBuilder` class. You can then set the type of the context menu (user or message) using the `setType()` method.\n\n```js\nconst { ContextMenuCommandBuilder, ApplicationCommandType } = require('discord.js');\n\nconst data = new ContextMenuCommandBuilder().setName('User Information').setType(ApplicationCommandType.User);\n```\n\n## Receiving context menu command interactions\n\nContext menus commands, just like slash commands, are received via an interaction. You can check if a given interaction is a context menu by invoking the `isContextMenuCommand()` method, or the `isMessageContextMenuCommand()` and `isUserContextMenuCommand()` methods to check for the specific type of context menu interaction:\n\n```js\nclient.on(Events.InteractionCreate, (interaction) => {\n\tif (!interaction.isUserContextMenuCommand()) return;\n\tconsole.log(interaction);\n});\n```\n\n## Extracting data from context menus\n\nFor user context menus, you can get the targeted user by accessing the `targetUser` or `targetMember` property from the `UserContextMenuCommandInteraction`.\n\nFor message context menus, you can get the targeted message by accessing the `targetMessage` property from the `MessageContextMenuCommandInteraction`.\n\n```js\nclient.on(Events.InteractionCreate, (interaction) => {\n\tif (!interaction.isUserContextMenuCommand()) return;\n\t// Get the User's username from context menu\n\tconst { username } = interaction.targetUser;\n\tconsole.log(username);\n});\n```\n\n## Notes\n\n- Context menu commands cannot have subcommands or any options.\n- Responding to context menu commands functions the same as slash commands. Refer to our [slash command responses](../slash-commands/response-methods) guide for more information.\n- Context menu command permissions also function the same as slash commands. Refer to our [slash command permissions](../slash-commands/permissions) guide for more information.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/interactions/meta.json",
    "content": "{\n\t\"title\": \"Other Interactions\"\n}\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/interactions/modals.mdx",
    "content": "---\ntitle: Modals\n---\n\nModals are pop-up forms that allow you to prompt users for additional input. This form-like interaction response blocks the user from interacting with Discord until the modal is submitted or dismissed. In this section, we will cover how to create, show, and receive modals using discord.js!\n\n<Callout>\n\tThis page is a follow-up to the [interactions (slash commands) page](../slash-commands/advanced-creation). Reading\n\tthat page first will help you understand the concepts introduced in this page.\n</Callout>\n\n## Building and responding with modals\n\nWith the `ModalBuilder` class, discord.js offers a convenient way to build modals step by step using setters and callbacks.\n\n<Callout>\n\tYou can have a maximum of five top-level components per modal, each of which can be a label or a text display\n\tcomponent.\n</Callout>\n\n```js\nconst { Events, ModalBuilder } = require('discord.js');\n\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\tif (interaction.commandName === 'ping') {\n\t\tconst modal = new ModalBuilder().setCustomId('myModal').setTitle('My Modal');\n\n\t\t// TODO: Add components to modal...\n\t}\n});\n```\n\n<Callout>\n\tThe `customId` is a developer-defined string of up to 100 characters and uniquely identifies this modal instance. You\n\tcan use it to differentiate incoming interactions.\n</Callout>\n\nThe next step is adding components to the modal, which may either request input or present information.\n\n### Label\n\nLabel components wrap around other modal components (text input, select menus, etc.) to add a label and description to it.\nSince labels are not stand-alone components, we will use this example label to wrap a text input component in the next section:\n\n```js\nconst { LabelBuilder, ModalBuilder } = require('discord.js');\n\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\tif (interaction.commandName === 'ping') {\n\t\t// [!code focus:11]\n\t\t// Create the modal\n\t\tconst modal = new ModalBuilder().setCustomId('myModal').setTitle('My Modal');\n\n\t\t// [!code ++:5]\n\t\tconst hobbiesLabel = new LabelBuilder()\n\t\t\t// The label is a large header text that identifies the interactive component for the user.\n\t\t\t.setLabel('What are some of your favorite hobbies?')\n\t\t\t// The description is an additional optional subtext that aids the label.\n\t\t\t.setDescription('Activities you like to participate in');\n\n\t\t// [!code ++:2]\n\t\t// Add label to the modal\n\t\tmodal.addLabelComponents(hobbiesLabel);\n\t}\n});\n```\n\n<Callout>\n\tThe `label` field has a max length of 45 characters. The `description` field has a max length of 100 characters.\n</Callout>\n\n### Text input\n\nText input components prompt users for single or multi line free-form text.\n\n```js\nconst { LabelBuilder, ModalBuilder, TextInputBuilder, TextInputStyle } = require('discord.js');\n\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\tif (interaction.commandName === 'ping') {\n\t\t// [!code focus:10]\n\t\t// Create the modal\n\t\tconst modal = new ModalBuilder().setCustomId('myModal').setTitle('My Modal');\n\n\t\t// [!code ++:6]\n\t\tconst hobbiesInput = new TextInputBuilder()\n\t\t\t.setCustomId('hobbiesInput')\n\t\t\t// Short means a single line of text.\n\t\t\t.setStyle(TextInputStyle.Short)\n\t\t\t// Placeholder text displayed inside the text input box\n\t\t\t.setPlaceholder('card games, films, books, etc.');\n\n\t\t// [!code focus:10]\n\t\tconst hobbiesLabel = new LabelBuilder()\n\t\t\t// The label is a large header that identifies the interactive component for the user.\n\t\t\t.setLabel(\"What's some of your favorite hobbies?\")\n\t\t\t// The description is an additional optional subtext that aids the label.\n\t\t\t.setDescription('Activities you like to participate in')\n\t\t\t// [!code ++:2]\n\t\t\t// Set text input as the component of the label\n\t\t\t.setTextInputComponent(hobbiesInput);\n\n\t\t// Add the label to the modal\n\t\tmodal.addLabelComponents(hobbiesLabel);\n\t}\n});\n```\n\n#### Input styles\n\nDiscord offers two different input styles:\n\n- `Short`, a single-line text entry\n- `Paragraph`, a multi-line text entry\n\n#### Input properties\n\nA text input field can be customized in a number of ways to apply validation or set default values via the following `TextInputBuilder` methods:\n\n```js\nconst input = new TextInputBuilder()\n\t// Set the component id (this is not the custom id)\n\t.setId(1)\n\t// Set the maximum number of characters allowed\n\t.setMaxLength(1_000)\n\t// Set the minimum number of characters required for submission\n\t.setMinLength(10)\n\t// Set a default value to prefill the text input\n\t.setValue('Default')\n\t// Require a value in this text input field (defaults to true)\n\t.setRequired(true);\n```\n\n<Callout>\n\tThe `id` field is used to differentiate components within interactions (which text input, selection, etc.). In\n\tcontrast, the `customId` covered earlier identifies the interaction (which modal, command, etc.).\n</Callout>\n\n### Select menu\n\nSelect menus allow you to limit user input to a preselected list of values. Discord also offers select menus linked directly to native Discord entities like users, roles, and channels.\nSince they behave very similarly to how they do in messages, please refer to the [corresponding guide page](../interactive-components/select-menus) for more information on configuring select menus.\n\nHere again, you wrap the select menu with a label component to add context to the selection and add the label to the modal:\n\n```js\n// ...\n\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\tif (interaction.commandName === 'ping') {\n\t\t// Create the modal\n\t\tconst modal = new ModalBuilder().setCustomId('myModal').setTitle('My Modal');\n\n\t\t// ...\n\n\t\t// [!code focus:24]\n\t\t// [!code ++:23]\n\t\tconst favoriteStarterSelect = new StringSelectMenuBuilder()\n\t\t\t.setCustomId('starter')\n\t\t\t.setPlaceholder('Make a selection!')\n\t\t\t// Modal only property on select menus to prevent submission, defaults to true\n\t\t\t.setRequired(true)\n\t\t\t.addOptions(\n\t\t\t\t// String select menu options\n\t\t\t\tnew StringSelectMenuOptionBuilder()\n\t\t\t\t\t// Label displayed to user\n\t\t\t\t\t.setLabel('Bulbasaur')\n\t\t\t\t\t// Description of option\n\t\t\t\t\t.setDescription('The dual-type Grass/Poison Seed Pokémon.')\n\t\t\t\t\t// Value returned to you in modal submission\n\t\t\t\t\t.setValue('bulbasaur'),\n\t\t\t\tnew StringSelectMenuOptionBuilder()\n\t\t\t\t\t.setLabel('Charmander')\n\t\t\t\t\t.setDescription('The Fire-type Lizard Pokémon.')\n\t\t\t\t\t.setValue('charmander'),\n\t\t\t\tnew StringSelectMenuOptionBuilder()\n\t\t\t\t\t.setLabel('Squirtle')\n\t\t\t\t\t.setDescription('The Water-type Tiny Turtle Pokémon.')\n\t\t\t\t\t.setValue('squirtle'),\n\t\t\t);\n\n\t\t// ...\n\n\t\t// [!code focus:4]\n\t\t// [!code ++:4]\n\t\tconst favoriteStarterLabel = new LabelBuilder()\n\t\t\t.setLabel(\"What's your favorite Gen 1 Pokémon starter?\")\n\t\t\t// Set string select menu as component of the label\n\t\t\t.setStringSelectMenuComponent(favoriteStarterSelect);\n\n\t\t// [!code focus:3]\n\t\t// Add labels to modal\n\t\tmodal.addLabelComponents(hobbiesLabel); // [!code --]\n\t\tmodal.addLabelComponents(hobbiesLabel, favoriteStarterLabel); // [!code ++]\n\t}\n});\n```\n\n### Text display\n\nText display components offer you a way to give additional context to the user that doesn't fit into labels or isn't directly connected to any specific input field.\n\n```js\n// ...\n\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\tif (interaction.commandName === 'ping') {\n\t\t// Create the modal\n\t\tconst modal = new ModalBuilder().setCustomId('myModal').setTitle('My Modal');\n\n\t\t// ...\n\n\t\t// [!code focus:3]\n\t\t// [!code ++:3]\n\t\tconst text = new TextDisplayBuilder().setContent(\n\t\t\t'Text that could not fit in to a label or description\\n-# Markdown can also be used',\n\t\t);\n\n\t\t// [!code focus:5]\n\t\t// Add components to modal\n\t\tmodal\n\t\t\t// [!code --]\n\t\t\t.addLabelComponents(hobbiesLabel, favoriteStarterLabel);\n\t\t\t// [!code ++:2]\n\t\t\t.addLabelComponents(hobbiesLabel, favoriteStarterLabel)\n\t\t\t.addTextDisplayComponents(text);\n\t}\n});\n```\n\n### File upload\n\nFile upload components allow you to prompt the user to upload a file from their system.\n\n<Callout type=\"warn\">\n\tDiscord **does not send the file data** itself in the resulting interaction. You will have to download it from\n\tDiscords CDN to process and validate it. Do not execute arbitrary code people upload via your app!\n</Callout>\n\n```js\n// ...\n\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\tif (interaction.commandName === 'ping') {\n\t\t// Create the modal\n\t\tconst modal = new ModalBuilder().setCustomId('myModal').setTitle('My Modal');\n\n\t\t// ...\n\n\t\t// [!code focus:2]\n\t\t// [!code ++]\n\t\tconst pictureOfTheWeekUpload = new FileUploadBuilder().setCustomId('picture');\n\n\t\t// ...\n\n\t\t// [!code focus:12]\n\t\t// [!code ++:5]\n\t\tconst pictureOfTheWeekLabel = new LabelBuilder()\n\t\t\t.setLabel('Picture of the Week')\n\t\t\t.setDescription('The best pictures you have taken this week')\n\t\t\t// Set file upload as component of the label\n\t\t\t.setFileUploadComponent(pictureOfTheWeekUpload);\n\n\t\t// Add components to modal\n\t\tmodal\n\t\t\t.addLabelComponents(hobbiesLabel, favoriteStarterLabel)\n\t\t\t// [!code --]\n\t\t\t.addTextDisplayComponents(text);\n\t\t\t// [!code ++:2]\n\t\t\t.addTextDisplayComponents(text)\n\t\t\t.addLabelComponents(pictureOfTheWeekLabel);\n\t}\n});\n```\n\n#### File upload properties\n\nA file upload component can be customized to apply validation via the following `FileUploadBuilder` methods:\n\n```js\nconst pictureOfTheWeekUpload = new FileUploadBuilder()\n\t// Set the optional identifier for component\n\t.setId(1)\n\t// Minimum number of items that must be uploaded (defaults to 1); min 0, max 10\n\t.setMinValues(1)\n\t// Maximum number of items that can be uploaded (defaults to 1); max 10\n\t.setMaxValues(1)\n\t// Require a value in this file upload component (defaults to true)\n\t.setRequired(true);\n```\n\n<Callout>\n The `id` field is used to differentiate components within interactions (which text input, selection, etc.).   \n In contrast, the `customId` covered earlier identifies the interaction (which modal, command, etc.).\n\nYou **cannot** limit and validate the **file size** or the **file extension**.\n\n</Callout>\n\n### Responding with a modal\n\nWith the modal built, call `ChatInputCommandInteraction#showModal()` to send the interaction response to Discord and display the modal to the user.\n\n<Callout type=\"warn\">\n\tShowing a modal must be the first response to an interaction. You **cannot** defer modals.\n</Callout>\n\n```js\n// ...\n// [!code focus:5]\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\tif (interaction.commandName === 'ping') {\n\t\t// Create the modal\n\t\tconst modal = new ModalBuilder().setCustomId('myModal').setTitle('My Modal');\n\n\t\t// ...\n\n\t\t// [!code focus:9]\n\t\t// Add components to modal\n\t\tmodal\n\t\t\t.addLabelComponents(hobbiesLabel, favoriteStarterLabel)\n\t\t\t.addTextDisplayComponents(text)\n\t\t\t.addLabelComponents(pictureOfTheWeekLabel);\n\n\t\t// [!code ++:2]\n\t\t// Show modal to the user\n\t\tawait interaction.showModal(modal);\n\t}\n});\n```\n\nRestart your bot and invoke the `/ping` command again. You should see the modal as shown below:\n\n![Modal Example](./images/modal-example.png)\n\n## Receiving modal submissions\n\n### Interaction collectors\n\nModal submissions can be collected within the scope of the interaction that sent the modal by utilizing an `InteractionCollector`, or the `ChatInputCommandInteraction#awaitModalSubmit` promisified version. These both provide instances of the `ModalSubmitInteraction` class as collected items.\n\nFor a detailed guide on handling interactions with collectors, please refer to the [collectors guide](../popular-topics/collectors#interaction-collectors).\n\n### The interactionCreate event\n\nTo receive a `ModalSubmitInteraction` event, attach an `Client#interactionCreate` event listener to your client and use the `BaseInteraction#isModalSubmit` type guard to make sure you only receive modals:\n\n```js\nclient.on(Events.InteractionCreate, (interaction) => {\n\t// ...\n\t// [!code word:isModalSubmit] [!code highlight:2]\n\tif (!interaction.isModalSubmit()) return;\n\tconsole.log(interaction);\n});\n```\n\n## Responding to modal submissions\n\nThe `ModalSubmitInteraction` class provides the same methods as the `ChatInputCommandInteraction` class. These methods behave equally:\n\n- `reply()`\n- `editReply()`\n- `deferReply()`\n- `fetchReply()`\n- `deleteReply()`\n- `followUp()`\n\nIf the modal was prompted through a button or select menu interaction, these methods may be used to update the underlying message:\n\n- `update()`\n- `deferUpdate()`\n\n```js\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isModalSubmit()) return;\n\tconsole.log(interaction);\n\tif (interaction.customId === 'myModal') {\n\t\t// [!code highlight] [!code word:reply]\n\t\tawait interaction.reply({ content: 'Your submission was received successfully!' });\n\t}\n});\n```\n\n<Callout>\n\tIf you're using TypeScript, you can use the `ModalSubmitInteraction#isFromMessage()` type guard to make sure the\n\treceived interaction originated from a `MessageComponentInteraction`.\n</Callout>\n\n## Extracting data from modal submissions\n\nYou can process the submitted input fields through the use of convenience getters on `ModalSubmitInteraction#fields`. The library provides getters for all modal components with user submitted data:\n\n```js\nclient.on(Events.InteractionCreate, (interaction) => {\n\tif (!interaction.isModalSubmit()) return;\n\tif (interaction.customId === 'myModal') {\n\t\tawait interaction.reply({ content: 'Your submission was received successfully!' });\n\n\t\t// [!code focus:6]\n\t\t// Get the data entered by the user\n\t\tconst hobbies = interaction.fields.getTextInputValue('hobbiesInput');\n\t\tconst starter = interaction.fields.getStringSelectValues('starter');\n\t\tconst picture = interaction.fields.getUploadedFiles('picture');\n\n\t\tconsole.log({ hobbies, starter, picture });\n\t}\n});\n```\n\n<Callout>\n\tEmpty text input submissions return an empty string `\"\"`. Select menus without a selection return an empty array `[]`.\n</Callout>\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/interactive-components/action-rows.mdx",
    "content": "---\ntitle: Action Rows\n---\n\nAction rows are a layout component with five \"slots\" that can be filled with other components. At the time of writing this guide, buttons take up one slot and select menus take up five \"slots\". Accordingly, each `ActionRow` can hold up to 5 buttons or a single select menu. A message can have up to five rows without providing the `IsComponentsV2` message flag. If you want to place buttons or action rows into the message body, they have to be wrapped inside rows.\n\n<Callout>\n\tRead our guide section on [display components](../popular-topics/display-components) if you want to learn more about\n\tthose.\n</Callout>\n\n## Building action rows\n\nTo create an action row, use the `ActionRowBuilder` class and the `ActionRowBuilder#addComponents` method to add buttons or a select menu.\n\n```js\nconst row = new ActionRowBuilder().addComponents(component);\n```\n\n<Callout>\nIf you're using TypeScript, you'll need to specify the type of components your action row holds. This can be done by specifying the component builder you will add to it using a generic parameter in `ActionRowBuilder`.\n\n```js\nnew ActionRowBuilder() // [!code --]\nnew ActionRowBuilder<ButtonBuilder>() // [!code ++]\n```\n\n</Callout>\n\n## Sending action rows\n\nOnce one or many components are inside your row(s), send them in the `components` property of your `InteractionReplyOptions` (extends `BaseMessageOptions`).\n\n```js\nconst row = new ActionRowBuilder().addComponents(component);\n\nawait interaction.reply({ components: [row] });\n```\n\nTo learn how to create the buttons and select menus that will go inside your row, including more detailed examples on how you might use them, continue on to the other pages in this section.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/interactive-components/buttons.mdx",
    "content": "---\ntitle: Buttons\n---\n\nThe first type of interactive component we'll cover creating is a Button. Buttons are available in a variety of styles and can be used to provide permanent interfaces, temporary confirmation workflows, and other forms of additional interaction with your bot.\n\n<Callout>\n\tThis page is a follow-up to the [slash commands](../slash-commands/advanced-creation) section and [action\n\trows](./action-rows) page. Please carefully read those pages first so that you can understand the methods used here.\n</Callout>\n\n## Building buttons\n\nButtons are one of the `MessageComponent` classes, which can be sent via messages or interaction responses.\n\nFor this example, you're going to expand on the `ban` command that was previously covered on the [parsing options](../slash-commands/parsing-options) page with a confirmation workflow.\n\nTo create your buttons, use the `ButtonBuilder` class, defining at least the `customId`, `style` and `label`.\n\n```js\nconst { ButtonBuilder, ButtonStyle, SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\t// data: new SlashCommandBuilder()...\n\tasync execute(interaction) {\n\t\tconst target = interaction.options.getUser('target');\n\t\tconst reason = interaction.options.getString('reason') ?? 'No reason provided';\n\n\t\tconst confirm = new ButtonBuilder().setCustomId('confirm').setLabel('Confirm Ban').setStyle(ButtonStyle.Danger);\n\n\t\tconst cancel = new ButtonBuilder().setCustomId('cancel').setLabel('Cancel').setStyle(ButtonStyle.Secondary);\n\t},\n};\n```\n\n<Callout>\n\tThe custom id is a developer-defined string of up to 100 characters. Use this field to ensure you can uniquely define\n\tall incoming interactions.\n</Callout>\n\n## Sending buttons\n\nTo send your buttons, create an action row and add the buttons as components. Then, send the row in the `components` property of `InteractionReplyOptions` (extends `BaseMessageOptions`).\n\n```js\nconst { ActionRowBuilder, ButtonBuilder, ButtonStyle, SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\t// data: new SlashCommandBuilder()...\n\tasync execute(interaction) {\n\t\tconst target = interaction.options.getUser('target');\n\t\tconst reason = interaction.options.getString('reason') ?? 'No reason provided';\n\n\t\tconst confirm = new ButtonBuilder().setCustomId('confirm').setLabel('Confirm Ban').setStyle(ButtonStyle.Danger);\n\n\t\tconst cancel = new ButtonBuilder().setCustomId('cancel').setLabel('Cancel').setStyle(ButtonStyle.Secondary);\n\n\t\tconst row = new ActionRowBuilder().addComponents(cancel, confirm);\n\n\t\tawait interaction.reply({\n\t\t\tcontent: `Are you sure you want to ban ${target} for reason: ${reason}?`,\n\t\t\tcomponents: [row],\n\t\t});\n\t},\n};\n```\n\nRestart your bot and then send the command to a channel your bot has access to. If all goes well, you should see something like this:\n\n## Button styles\n\nYou'll notice in the above example that two different styles of buttons have been used, the grey Secondary style and the red Danger style. These were chosen specifically to support good UI/UX principles. In total, there are five button styles that can be used as appropriate to the action of the button:\n\n- `Primary` style buttons are blue. These are suitable for most general purpose actions, where it's the primary or most significant action expected.\n- `Secondary` style buttons are grey. Use these for less important actions like the \"Cancel\" button in the example above.\n- `Success` style buttons are green. Similar to the Primary button, these are a good choice for \"positive\" confirmation actions.\n- `Danger` style buttons are red. Where the action being confirmed is \"destructive\", such a ban or delete, using a red button helps alert the user to the risk of the action.\n- `Link` style buttons are also grey, but are tagged with the \"external link\" symbol. These buttons will open the provided link in the browser without sending an interaction to the bot.\n\n## Link buttons\n\nLink buttons are a little different to the other styles. `Link` buttons **must** have a `url`, **cannot** have a `customId` and **do not** send an interaction event when clicked.\n\n```js\nconst button = new ButtonBuilder()\n\t.setLabel('discord.js docs')\n\t.setURL('https://discord.js.org') // [!code word:setURL]\n\t.setStyle(ButtonStyle.Link); // [!code word:Link]\n```\n\n## Disabled buttons\n\nIf you want to prevent a button from being used, but not remove it from the message, you can disable it with the `ButtonBuilder#setDisabled` method:\n\n```js\nconst button = new ButtonBuilder()\n\t.setCustomId('disabled')\n\t.setLabel('Click me?')\n\t.setStyle(ButtonStyle.Primary)\n\t.setDisabled(true); // [!code word:setDisabled]\n```\n\n## Emoji buttons\n\nIf you want to use a guild emoji within a `ButtonBuilder`, you can use the `ButtonBuilder#setEmoji` method:\n\n```js\nconst button = new ButtonBuilder()\n\t.setCustomId('primary')\n\t.setLabel('Primary')\n\t.setStyle(ButtonStyle.Primary)\n\t.setEmoji('123456789012345678'); // [!code word:setEmoji]\n```\n\n#### Next steps\n\n<Callout>\n\tButtons can also be set as an accessory in section components. Check the guide section on [display\n\tcomponents](../popular-topics/display-components) if you want to find out more about this.\n</Callout>\n\nThat's everything you need to know about building and sending buttons! From here you can learn about the other type of message component, [select menus](./select-menus), or have your bot start listening to [component interactions](./interactions) from your buttons.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/interactive-components/interactions.mdx",
    "content": "---\ntitle: Interactions\n---\n\n## Component interactions\n\nEvery button click or select menu selection on a component sent by your bot fires an `interaction`, triggering the `Client#interactionCreate` event. How you decide to handle this will likely depend on the purpose of the components. Options include:\n\n- Waiting for a single interaction via `awaitMessageComponent()` on a channel or a message.\n- Listening for multiple interactions over a period of time using an `InteractionCollector`.\n- Creating a permanent component handler in the `Client#interactionCreate` event.\n\n<Callout>\n\tThis page is a follow-up to the [slash commands](../slash-commands/advanced-creation) section, and assumes you have\n\tcreated either [buttons](./buttons) or [select menus](./select-menus) as detailed in this guide. Please carefully read\n\tthose pages first so that you can understand the methods used here.\n</Callout>\n\n## Responding to component interactions\n\nAs with all other interactions message components interactions require a response within 3 seconds, else Discord will treat them as failed.\n\nLike slash commands, all types of message component interactions support the `reply()`, `deferReply()`, `editReply()` and `followUp()` methods, with the option for these responses to be ephemeral. These function identically to how they do for slash commands, so refer to the page on [slash command response methods](../slash-commands/response-methods) for information on those.\n\nComponent interactions also support two additional methods of response, detailed below and demonstrated in examples later on the page.\n\n### Updates\n\nResponding to a component interaction via the `update()` method acknowledges the interaction by editing the message on which the component was attached. This method should be preferred to calling `editReply()` on the original interaction which sent the components. Like `editReply()`, `update()` cannot be used to change the ephemeral state of a message.\n\nOnce `update()` has been called, future messages can be sent by calling `followUp()` or edits can be made by calling `editReply()` on the component interaction.\n\n### Deferred updates\n\nResponding to a component interaction via the `deferUpdate()` method acknowledges the interaction and resets the message state. This method can be used to suppress the need for further responses, however it's encouraged to provide meaningful feedback to users via an `update()` or ephemeral `reply()` at least.\n\nOnce `deferUpdate()` has been called, future messages can be sent by calling `followUp()` or edits can be made by calling `editReply()` on the component interaction.\n\n## Awaiting components\n\nIf you followed our [buttons](./buttons) guide, the confirmation workflow for the `ban` command is a good example of a situation where your bot is expecting to receive a single response, from either the Confirm or Cancel button.\n\nBegin by adding `withResponse` to the options, and then calling `Message#awaitMessageComponent` on the message. This method returns a [Promise](../additional-info/async-await) that resolves when any interaction passes its filter (if one is provided), or throws if none are received before the timeout. If this happens, remove the components and notify the user.\n\n```js title=\"commands/moderation/ban.js\"\nconst response = await interaction.reply({\n\tcontent: `Are you sure you want to ban ${target.username} for reason: ${reason}?`,\n\tcomponents: [row],\n\t// [!code ++]\n\twithResponse: true,\n});\n\n// [!code ++:7]\nconst collectorFilter = (i) => i.user.id === interaction.user.id;\n\ntry {\n\tconst confirmation = await response.resource.message.awaitMessageComponent({ filter: collectorFilter, time: 60_000 });\n} catch {\n\tawait interaction.editReply({ content: 'Confirmation not received within 1 minute, cancelling', components: [] });\n}\n```\n\n<Callout>\n\tThe filter applied here ensures that only the user who triggered the original interaction can use the buttons.\n</Callout>\n\nWith the confirmation collected, check which button was clicked and perform the appropriate action.\n\n```js\nconst response = await interaction.reply({\n\tcontent: `Are you sure you want to ban ${target.username} for reason: ${reason}?`,\n\tcomponents: [row],\n\twithResponse: true,\n});\n\nconst collectorFilter = (i) => i.user.id === interaction.user.id;\ntry {\n\t// [!code focus:8] [!code word:customId]\n\tconst confirmation = await response.resource.message.awaitMessageComponent({ filter: collectorFilter, time: 60_000 });\n\n\tif (confirmation.customId === 'confirm') {\n\t\tawait interaction.guild.members.ban(target);\n\t\tawait confirmation.update({ content: `${target.username} has been banned for reason: ${reason}`, components: [] });\n\t} else if (confirmation.customId === 'cancel') {\n\t\tawait confirmation.update({ content: 'Action cancelled', components: [] });\n\t}\n} catch {\n\tawait interaction.editReply({ content: 'Confirmation not received within 1 minute, cancelling', components: [] });\n}\n```\n\n## Component collectors\n\nFor situations where you want to collect multiple interactions, the Collector approach is better suited than awaiting singular interactions. Following on from the [select menus](./select-menus) guide, you're going to extend that example to use an `InteractionCollector` to listen for multiple `StringSelectMenuInteraction`.\n\nBegin by adding `withResponse` to the options, and then calling `Message#createMessageComponentCollector` on this instance. This method returns an InteractionCollector that will fire its `InteractionCollector#collect` event whenever an interaction passes its filter (if one is provided).\n\nIn the `collect` event, each interaction is a `StringSelectMenuInteraction` thanks to the `componentType: ComponentType.StringSelect` option provided to the collector (and because that was the only type of component in the message). The selected value(s) are available via the `StringSelectMenuInteraction#values` property.\n\n```js\nconst response = await interaction.reply({\n\tcontent: 'Choose your starter!',\n\tcomponents: [row],\n\twithResponse: true, // [!code ++]\n});\n\n// [!code ++:9]\nconst collector = response.resource.message.createMessageComponentCollector({\n\tcomponentType: ComponentType.StringSelect,\n\ttime: 3_600_000, // 1 hour\n});\n\ncollector.on('collect', async (i) => {\n\tconst selection = i.values[0];\n\tawait i.reply(`${i.user} has selected ${selection}!`);\n});\n```\n\n## The Client#interactionCreate event\n\nThird and finally, you may wish to have a listener setup to respond to permanent button or select menu features of your guild. For this, returning to the `Client#interactionCreate` event is the best approach.\n\nIf your event handling has been setup in multiple files as per our [event handling](../app-creation/handling-events) guide, you should already have an `events/interactionCreate.js` file that looks something like this.\n\n```js title=\"events/interactionCreate.js\"\nconst { Events } = require('discord.js');\n\nmodule.exports = {\n\tname: Events.InteractionCreate,\n\tasync execute(interaction) {\n\t\tif (!interaction.isChatInputCommand()) return;\n\n\t\tconst command = interaction.client.commands.get(interaction.commandName);\n\n\t\tif (!command) {\n\t\t\tconsole.error(`No command matching ${interaction.commandName} was found.`);\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tawait command.execute(interaction);\n\t\t} catch (error) {\n\t\t\tconsole.error(`Error executing ${interaction.commandName}`);\n\t\t\tconsole.error(error);\n\t\t}\n\t},\n};\n```\n\nThe way this was previously set up returns from the `execute` function whenever it encounters an interaction that is not a `ChatInputCommandInteraction`, as shown on the highlighted line above. The first change that needs to be made is to invert this logic, without actually changing the functionality.\n\n```js title=\"events/interactionCreate.js\"\nconst { Events } = require('discord.js');\n\n// [!code focus:22]\nmodule.exports = {\n\tname: Events.InteractionCreate,\n\tasync execute(interaction) {\n\t\tif (!interaction.isChatInputCommand()) return; // [!code --]\n\t\t// [!code ++:15]\n\t\tif (interaction.isChatInputCommand()) {\n\t\t\tconst command = interaction.client.commands.get(interaction.commandName);\n\n\t\t\tif (!command) {\n\t\t\t\tconsole.error(`No command matching ${interaction.commandName} was found.`);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tawait command.execute(interaction);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(`Error executing ${interaction.commandName}`);\n\t\t\t\tconsole.error(error);\n\t\t\t}\n\t\t}\n\t},\n};\n```\n\nNow that the logic is setup to run code when something _is_ a `ChatInputCommandInteraction`, rather than to stop and exit when it isn't, you can add handling for additional interaction types via simple `if...else` logic.\n\n```js\nconst { Events } = require('discord.js');\n\nmodule.exports = {\n\tname: Events.InteractionCreate,\n\t// [!code focus]\n\tasync execute(interaction) {\n\t\t// [!code focus]\n\t\tif (interaction.isChatInputCommand()) {\n\t\t\tconst command = interaction.client.commands.get(interaction.commandName);\n\n\t\t\tif (!command) {\n\t\t\t\tconsole.error(`No command matching ${interaction.commandName} was found.`);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tawait command.execute(interaction);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(`Error executing ${interaction.commandName}`);\n\t\t\t\tconsole.error(error);\n\t\t\t}\n\t\t\t// [!code focus:5] [!code ++:5]\n\t\t} else if (interaction.isButton()) {\n\t\t\t// respond to the button\n\t\t} else if (interaction.isStringSelectMenu()) {\n\t\t\t// respond to the select menu\n\t\t}\n\t\t// [!code focus]\n\t},\n};\n```\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/interactive-components/meta.json",
    "content": "{\n\t\"title\": \"Interactive Components\",\n\t\"pages\": [\"action-rows\", \"buttons\", \"select-menus\", \"interactions\"]\n}\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/interactive-components/select-menus.mdx",
    "content": "---\ntitle: Select Menus\n---\n\nSelect menus are interactive components which can be sent via messages, interaction responses, or in modals.\n\n<Callout>\n\tThis page is a follow-up to the [slash commands](../slash-commands/advanced-creation) section and [action\n\trows](../interactive-components/action-rows) page. Please carefully read those pages first so that you can understand\n\tthe methods used here.\n</Callout>\n<Callout>\n\tThis page is for using select menus in messages. For using [select menus in\n\tmodals](../interactions/modals#select-menu) visit the modal page\n</Callout>\n\n## Building string select menus\n\nThe \"standard\" and most customizable type of select menu is the string select menu. To create a string select menu, use the `StringSelectMenuBuilder` and `StringSelectMenuOptionBuilder` classes.\n\nIf you're a Pokémon fan, you've probably made a selection pretty similar to this example at some point in your life!\n\n```js\nconst { StringSelectMenuBuilder, StringSelectMenuOptionBuilder, SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\t// data: new SlashCommandBuilder()...\n\tasync execute(interaction) {\n\t\tconst favoriteStarterSelect = new StringSelectMenuBuilder()\n\t\t\t.setCustomId('starter')\n\t\t\t.setPlaceholder('Make a selection!')\n\t\t\t.addOptions(\n\t\t\t\t// String select menu options\n\t\t\t\tnew StringSelectMenuOptionBuilder()\n\t\t\t\t\t// Label displayed to user\n\t\t\t\t\t.setLabel('Bulbasaur')\n\t\t\t\t\t// Description of option\n\t\t\t\t\t.setDescription('The dual-type Grass/Poison Seed Pokémon.')\n\t\t\t\t\t// Value returned in select menu interaction\n\t\t\t\t\t.setValue('bulbasaur'),\n\t\t\t\tnew StringSelectMenuOptionBuilder()\n\t\t\t\t\t.setLabel('Charmander')\n\t\t\t\t\t.setDescription('The Fire-type Lizard Pokémon.')\n\t\t\t\t\t.setValue('charmander'),\n\t\t\t\tnew StringSelectMenuOptionBuilder()\n\t\t\t\t\t.setLabel('Squirtle')\n\t\t\t\t\t.setDescription('The Water-type Tiny Turtle Pokémon.')\n\t\t\t\t\t.setValue('squirtle'),\n\t\t\t);\n\t},\n};\n```\n\n<Callout>\n\tThe custom id is a developer-defined string of up to 100 characters. Use this field to ensure you can uniquely define\n\tall incoming interactions from your select menus!\n</Callout>\n\n## Sending select menus\n\nTo send your select menu, create an action row and add the buttons as components. Then, send the row in the `components` property of `InteractionReplyOptions` (extends `BaseMessageOptions`).\n\n```js\nconst {\n\tActionRowBuilder,\n\tStringSelectMenuBuilder,\n\tStringSelectMenuOptionBuilder,\n\tSlashCommandBuilder,\n} = require('discord.js');\n// [!code focus:33]\nmodule.exports = {\n\t// data: new SlashCommandBuilder()...\n\tasync execute(interaction) {\n\t\tconst favoriteStarterSelect = new StringSelectMenuBuilder()\n\t\t\t.setCustomId('starter')\n\t\t\t.setPlaceholder('Make a selection!')\n\t\t\t.addOptions(\n\t\t\t\t// String select menu options\n\t\t\t\tnew StringSelectMenuOptionBuilder()\n\t\t\t\t\t// Label displayed to user\n\t\t\t\t\t.setLabel('Bulbasaur')\n\t\t\t\t\t// Description of option\n\t\t\t\t\t.setDescription('The dual-type Grass/Poison Seed Pokémon.')\n\t\t\t\t\t// Value returned in select menu interaction\n\t\t\t\t\t.setValue('bulbasaur'),\n\t\t\t\tnew StringSelectMenuOptionBuilder()\n\t\t\t\t\t.setLabel('Charmander')\n\t\t\t\t\t.setDescription('The Fire-type Lizard Pokémon.')\n\t\t\t\t\t.setValue('charmander'),\n\t\t\t\tnew StringSelectMenuOptionBuilder()\n\t\t\t\t\t.setLabel('Squirtle')\n\t\t\t\t\t.setDescription('The Water-type Tiny Turtle Pokémon.')\n\t\t\t\t\t.setValue('squirtle'),\n\t\t\t);\n\n\t\t// [!code ++:8]\n\t\t// Adding a string select menu to an action row\n\t\tconst row = new ActionRowBuilder().addComponents(favoriteStarterSelect);\n\n\t\t// Reply with the action row\n\t\tawait interaction.reply({\n\t\t\tcontent: 'Choose your starter!',\n\t\t\tcomponents: [row],\n\t\t});\n\t},\n};\n```\n\n<Callout>Remember that if you have more than one select menu, each one will need its own action row.</Callout>\n\n<Callout>\n\tYou can also send action rows inside containers or between other components, when using the [display\n\tcomponents](../popular-topics/display-components) system.\n</Callout>\n\n## String select menu options\n\nString select menu options are custom-defined by the user, as shown in the example above. At a minimum, each option must have it's `label` and `value` defined. The label is shown to the user, while the value is included in the interaction sent to the bot.\n\nIn addition to these, each option can be enhanced with a `description` or `emoji`, or can be set to be selected by default.\n\n```js\nconst select = new StringSelectMenuBuilder().setCustomId('select').addOptions(\n\t// [!code focus:6]\n\tnew StringSelectMenuOptionBuilder()\n\t\t.setLabel('Option')\n\t\t.setValue('option')\n\t\t.setDescription('A selectable option') // [!code word:setDescription]\n\t\t.setEmoji('123456789012345678') // [!code word:setEmoji]\n\t\t.setDefault(true), // [!code word:setDefault]\n);\n```\n\n## Auto-populating select menus\n\nAlthough the String select menu with its user-defined options is the most customizable, there are four other types of select menu that auto-populate with their corresponding Discord entities, much like slash command options. These are:\n\n- `UserSelectMenuBuilder`\n- `RoleSelectMenuBuilder`\n- `MentionableSelectMenuBuilder`\n- `ChannelSelectMenuBuilder`\n\nThe `ChannelSelectMenuBuilder` can be configured to only show specific channel types using `ChannelSelectMenuBuilder#setChannelTypes`.\n\n## Multi-selects\n\nWhere slash command options fall behind is in their single-select limitation on User, Role and Channel option types. Select menus can support this use case via `BaseSelectMenuBuilder#setMinValues` and `BaseSelectMenuBuilder#setMaxValues`. When these values are set, users can select multiple items, and the interaction will be sent with all selected values only when the user clicks outside the select menu.\n\n```js\nmodule.exports = {\n\t// data: new SlashCommandBuilder()...\n\tasync execute(interaction) {\n\t\t// [!code focus:5]\n\t\tconst userSelect = new UserSelectMenuBuilder()\n\t\t\t.setCustomId('users')\n\t\t\t.setPlaceholder('Select multiple users.')\n\t\t\t.setMinValues(1) // [!code word:setMinValues]\n\t\t\t.setMaxValues(10); // [!code word:setMaxValues]\n\n\t\tconst row1 = new ActionRowBuilder().addComponents(userSelect);\n\n\t\tawait interaction.reply({\n\t\t\tcontent: 'Select users:',\n\t\t\tcomponents: [row1],\n\t\t});\n\t},\n};\n```\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/keyv/keyv.mdx",
    "content": "---\ntitle: Keyv\n---\n\n[Keyv](https://www.npmjs.com/package/keyv) is a simple key-value store that works with multiple backends. It's fully scalable for [sharding](../sharding/) and supports JSON storage.\n\n## Installation\n\n```sh tab=\"npm\"\nnpm install keyv\n```\n\n```sh tab=\"yarn\"\nyarn add keyv\n```\n\n```sh tab=\"pnpm\"\npnpm add keyv\n```\n\n```sh tab=\"bun\"\nbun add keyv\n```\n\nKeyv requires an additional package depending on which persistent backend you would prefer to use. If you want to keep everything in memory, you can skip this part. Otherwise, install one of the below.\n\n```sh tab=\"npm\"\nnpm install @keyv/redis\nnpm install @keyv/mongo\nnpm install @keyv/sqlite\nnpm install @keyv/postgres\nnpm install @keyv/mysql\n```\n\n```sh tab=\"yarn\"\nyarn add @keyv/redis\nyarn add @keyv/mongo\nyarn add @keyv/sqlite\nyarn add @keyv/postgres\nyarn add @keyv/mysql\n```\n\n```sh tab=\"pnpm\"\npnpm add @keyv/redis\npnpm add @keyv/mongo\npnpm add @keyv/sqlite\npnpm add @keyv/postgres\npnpm add @keyv/mysql\n```\n\n```sh tab=\"bun\"\nbun add @keyv/redis\nbun add @keyv/mongo\nbun add @keyv/sqlite\nbun add @keyv/postgres\nbun add @keyv/mysql\n```\n\nCreate an instance of Keyv once you've installed Keyv and any necessary drivers.\n\n```js\nconst { Keyv } = require('keyv');\n\n// One of the following\nconst keyv = new Keyv(); // for in-memory storage\nconst keyv = new Keyv('redis://user:pass@localhost:6379');\nconst keyv = new Keyv('mongodb://user:pass@localhost:27017/dbname');\nconst keyv = new Keyv('sqlite://path/to/database.sqlite');\nconst keyv = new Keyv('postgresql://user:pass@localhost:5432/dbname');\nconst keyv = new Keyv('mysql://user:pass@localhost:3306/dbname');\n```\n\nMake sure to handle connection errors.\n\n```js\nkeyv.on('error', (err) => console.error('Keyv connection error:', err));\n```\n\nFor a more detailed setup, check out the [Keyv readme](https://github.com/jaredwray/keyv/tree/main/packages/keyv).\n\n## Usage\n\nKeyv exposes a familiar [Map](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Map)-like API. However, it only has `set`, `get`, `delete`, and `clear` methods. Additionally, instead of immediately returning data, these methods return [Promises](../additional-info/async-await) that resolve with the data.\n\n```js\n(async () => {\n\t// true\n\tawait keyv.set('foo', 'bar');\n\n\t// bar\n\tawait keyv.get('foo');\n\n\t// undefined\n\tawait keyv.clear();\n\n\t// undefined\n\tawait keyv.get('foo');\n})();\n```\n\n## Application\n\nAlthough Keyv can assist in any scenario where you need key-value data, we will focus on setting up a per-guild prefix configuration using [Sqlite](https://www.sqlite.org/).\n\n<Callout>\n\tThis section will still work with any provider supported by Keyv. We recommend PostgreSQL for larger applications.\n\n    Do note that \"large\" here should be interpreted as absolutely massive. Sqlite is used at scale by many companies and products you use every single day. The slight overhead should not be noticeable for the application of a Discord bot at all unless you are dealing with super complicated queries or are using specific features that do not exist in sqlite.\n\n    You can find out if sqlite might be a good choice for your project (it very likely is) by reading [their own article](https://www.sqlite.org/whentouse.html) on the topic.\n\n</Callout>\n\n### Setup\n\n```js\nconst { Keyv } = require('keyv');\nconst { Client, Events, GatewayIntentBits } = require('discord.js');\nconst { globalPrefix, token } = require('./config.json');\n\nconst client = new Client({\n\tintents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent],\n});\nconst prefixes = new Keyv('sqlite://path/to.sqlite');\n```\n\n### Command handler\n\n<Callout type=\"warn\">\n\tThis guide example is from a time where parsing the message content of Discord messages was the only option for\n\tcommands. We have since moved on from this and recommend you do the same with [slash\n\tcommands](../app-creation/handling-commands). It can still serve as an example for using databases in a more\n\tintegrated example. We hope it can help you understand the core idea and apply it to your own use cases!\n</Callout>\n\n```js\nclient.on(Events.MessageCreate, async (message) => {\n\tif (message.author.bot) return;\n\n\tlet args;\n\t// handle messages in a guild\n\tif (message.guild) {\n\t\tlet prefix;\n\n\t\tif (message.content.startsWith(globalPrefix)) {\n\t\t\tprefix = globalPrefix;\n\t\t} else {\n\t\t\t// check the guild-level prefix\n\t\t\tconst guildPrefix = await prefixes.get(message.guild.id);\n\t\t\tif (message.content.startsWith(guildPrefix)) prefix = guildPrefix;\n\t\t}\n\n\t\t// if we found a prefix, setup args; otherwise, this isn't a command\n\t\tif (!prefix) return;\n\t\targs = message.content.slice(prefix.length).trim().split(/\\s+/);\n\t} else {\n\t\t// handle DMs\n\t\tconst slice = message.content.startsWith(globalPrefix) ? globalPrefix.length : 0;\n\t\targs = message.content.slice(slice).split(/\\s+/);\n\t}\n\n\t// get the first space-delimited argument after the prefix as the command\n\tconst command = args.shift().toLowerCase();\n});\n```\n\n### Prefix command\n\nNow that you have a command handler, you can make a command to allow people to use your prefix system.\n\n```js\nclient.on(Events.MessageCreate, async (message) => {\n\t// ...\n\tif (command === 'prefix') {\n\t\t// if there's at least one argument, set the prefix\n\t\tif (args.length) {\n\t\t\tawait prefixes.set(message.guild.id, args[0]);\n\t\t\treturn message.channel.send(`Successfully set prefix to \\`${args[0]}\\``);\n\t\t}\n\n\t\treturn message.channel.send(`Prefix is \\`${(await prefixes.get(message.guild.id)) || globalPrefix}\\``);\n\t}\n});\n```\n\n<Callout>\n\tYou will probably want to set up additional validation, such as required permissions and maximum prefix length.\n</Callout>\n\n## Next steps\n\nVarious other applications can use Keyv, such as guild settings; create another instance with a different [namespace](https://github.com/jaredwray/keyv/tree/main/packages/keyv#namespaces) for each setting. Additionally, it can be [extended](https://github.com/jaredwray/keyv/tree/main/packages/keyv#third-party-storage-adapters) to work with whatever storage backend you prefer.\n\nCheck out the [Keyv repository](https://github.com/jaredwray/keyv/tree/main/packages/keyv) for more information.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/meta.json",
    "content": "{\n\t\"pages\": [\n\t\t\"[MessageCircleQuestion][FAQ](/legacy/popular-topics/faq)\",\n\t\t\"[ArrowDownToLine][Updating to v14](/legacy/additional-info/changes-in-v14)\",\n\t\t\"external:[LibraryBig][Documentation](https://discord.js.org/docs)\",\n\t\t\"[Info][Introduction](/legacy)\",\n\t\t\"---Setup---\",\n\t\t\"preparations\",\n\t\t\"---Your App---\",\n\t\t\"app-creation\",\n\t\t\"additional-features\",\n\t\t\"slash-commands\",\n\t\t\"interactions\",\n\t\t\"interactive-components\",\n\t\t\"popular-topics/display-components\",\n\t\t\"---More To Know---\",\n\t\t\"popular-topics\",\n\t\t\"improving-dev-environment\",\n\t\t\"additional-info\",\n\t\t\"miscellaneous\",\n\t\t\"---Persisting Data---\",\n\t\t\"...keyv\",\n\t\t\"sequelize\",\n\t\t\"---Advanced Concepts---\",\n\t\t\"...oauth2\",\n\t\t\"sharding\"\n\t],\n\t\"title\": \"discord.js\",\n\t\"description\": \"The discord.js guide\",\n\t\"icon\": \"Book\",\n\t\"root\": true\n}\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/miscellaneous/cache-customization.mdx",
    "content": "---\ntitle: Cache Customization\n---\n\nSometimes, you would like to be able to customize discord.js's caching behavior in order to reduce memory usage.\nTo this end, discord.js provides you with two ways to do so:\n\n1. Limiting the size of caches.\n2. Periodically removing old items from caches.\n\n<Callout type=\"error\">\n\tCustomization of caching behavior is an advanced topic. It is very easy to introduce errors if your custom cache is\n\tnot working as expected.\n</Callout>\n\n## Limiting caches\n\nWhen creating a new `Client`, you can limit the size of caches, which are specific to certain managers, using the `makeCache` option. Generally speaking, almost all your customizations can be done via the helper functions from the `Options` class.\n\nBelow is the default settings, which will limit message caches.\n\n```js\nconst { Client, Options } = require('discord.js');\n\nconst client = new Client({\n\tmakeCache: Options.cacheWithLimits(Options.DefaultMakeCacheSettings),\n});\n```\n\nTo change the cache behaviors for a type of manager, add it on top of the default settings. For example, you can make caches for reactions limited to 0 items i.e. the client won't cache reactions at all:\n\n```js\nconst client = new Client({\n\tmakeCache: Options.cacheWithLimits({\n\t\t...Options.DefaultMakeCacheSettings,\n\t\tReactionManager: 0,\n\t}),\n});\n```\n\n<Callout type=\"error\" title=\"Unsupported customization\">\n\tAs noted in the documentation, customizing `GuildManager`, `ChannelManager`, `GuildChannelManager`, `RoleManager`, or\n\t`PermissionOverwriteManager` is unsupported! Functionality will break with any kind of customization.\n</Callout>\n\nWe can further customize this by passing options to `LimitedCollection`, a special kind of collection that limits the number of items. In the example below, the client is configured so that:\n\n1. Only 200 guild members maximum may be cached per `GuildMemberManager` (essentially, per guild).\n2. We never remove a member if it is the client. This is especially important, so that the client can function correctly in guilds.\n\n```js\nconst client = new Client({\n\tmakeCache: Options.cacheWithLimits({\n\t\t...Options.DefaultMakeCacheSettings,\n\t\tReactionManager: 0,\n\t\tGuildMemberManager: {\n\t\t\tmaxSize: 200,\n\t\t\tkeepOverLimit: (member) => member.id === member.client.user.id,\n\t\t},\n\t}),\n});\n```\n\n## Sweeping caches\n\nIn addition to limiting caches, you can also periodically sweep and remove old items from caches. When creating a new `Client`, you can customize the `sweepers` option.\n\nBelow is the default settings, which will occasionally sweep threads.\n\n```js\nconst { Client, Options } = require('discord.js');\n\nconst client = new Client({\n\tsweepers: Options.DefaultSweeperSettings,\n});\n```\n\nTo change the sweep behavior, you specify the type of cache to sweep (`SweeperKey`) and the options for sweeping (`SweepOptions`). If the type of cache has a lifetime associated with it, such as invites, messages, or threads, then you can set the `lifetime` option to sweep items older than specified. Otherwise, you can set the `filter` option for any type of cache, which will select the items to sweep.\n\n```js\nconst client = new Client({\n\tsweepers: {\n\t\t...Options.DefaultSweeperSettings,\n\t\tmessages: {\n\t\t\tinterval: 3_600, // Every hour.\n\t\t\tlifetime: 1_800, // Remove messages older than 30 minutes.\n\t\t},\n\t\tusers: {\n\t\t\tinterval: 3_600, // Every hour.\n\t\t\tfilter: () => (user) => user.bot && user.id !== user.client.user.id, // Remove all bots.\n\t\t},\n\t},\n});\n```\n\n<Callout title=\"Take some time to consider what you are changing and do some research about what that implies\">\n\tTake a look at the documentation for which types of cache you can sweep. Also consider what exactly lifetime implies\n\tfor invites, messages, and threads!\n</Callout>\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/miscellaneous/useful-packages.mdx",
    "content": "---\ntitle: Useful Packages\n---\n\nSome of the examples in this section are far from complete. We encourage you to look at the official documentation for all packages you are intending to use in your code. We just want to point out some we found useful in our endeavours of developing Discord apps for years and whet your appetite to try and test some of them in your own code base!\n\n## Day.js\n\n<Callout>Official documentation: [https://day.js.org/](https://day.js.org/en)</Callout>\n\nDay.js is a powerful package that parses, validates, manipulates, and displays dates and times in JavaScript.\nIt allows you to quickly and easily format dates in any way you want or parse strings back into JavaScript Date objects.\nThere are many plugins for it that allow you to work with durations and more.\n\nFor example if you wanted to ask your users to give you a date,  \nyou can use Day.js to turn it into a Date object you can use in your code:\n\n```js\nconst input = await interaction.channel.awaitMessages({\n\tfilter: (m) => m.author.id === interaction.user.id,\n\tmax: 1,\n\ttime: 10e3,\n\terrors: ['time'],\n});\nconst date = dayjs(input.first().content).toDate();\n```\n\nUsing the [duration plugin](https://day.js.org/docs/en/durations/durations), you could tell the user if the date is in the future or the past:\n\n```js\nif (date.isValid()) {\n\tconst now = dayjs();\n\tconst duration = date - now;\n\tconst formatted = dayjs.duration(duration, 'ms').format();\n\n\tif (duration > 0) {\n\t\tinteraction.reply(`The date you gave me is ${formatted} into the future.`);\n\t} else {\n\t\tinteraction.reply(`The date you gave me is ${formatted} into the past.`);\n\t}\n} else {\n\tinteraction.reply(\"You didn't give me a valid date.\");\n}\n```\n\n## ms\n\n<Callout>Official documentation: [https://github.com/vercel/ms](https://github.com/vercel/ms)</Callout>\n\nMs is another tool for working with times in JavaScript. However, ms specializes on durations.\nIt allows you to convert times in milliseconds into human-readable formats and vice versa.\n\nExample:\n\n```js\nawait interaction.reply(\"Send two messages and I'll tell you how far apart you sent them.\");\nconst messages = await interaction.channel.awaitMessages({\n\tfilter: (m) => m.author.id === interaction.user.id,\n\tmax: 2,\n\ttime: 30e3,\n\terrors: ['time'],\n});\n\nconst difference = messages.last().createdTimestamp - messages.first().createdTimestamp;\nconst formatted = ms(difference);\n\nawait interaction.followUp(`You sent the two messages ${formatted} apart.`);\n```\n\n## common-tags\n\n<Callout>\n\tOfficial documentation: [https://github.com/zspecza/common-tags](https://github.com/zspecza/common-tags)\n</Callout>\n\nCommon-tags is a library all about working with template literals.  \nSo far, you have probably only used them for interpolating variables into your strings, but they can do a whole lot more.\nIf you've got time, you should check out [the MDN's documentation about _tagged literals_.](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates).\n\nEver got annoyed your multi-line strings had nasty bits of indentation in them,\nbut you did not want to remove the indentation in your source code?  \ncommon-tags got you covered:\n\n```js\nconst packageName = 'common-tags';\n\nif (someCondition) {\n\tconst poem = stripIndents`\n\t\tI like ${packageName}.\n\t\tIt makes my strings so pretty,\n\t\tyou should use it too.\n\t`;\n\n\tconsole.log(poem);\n}\n```\n\nThis will print your little poem like expected, but it will not have any tabs or other whitespace on the left.\n\nBut this is just the start! Another set of useful functions are the list-related functions:\n`inlineLists`, `commaLists`, etc.  \nWith those, you can easily interpolate arrays into your strings without them looking ugly:\n\n```js\nconst options = ['add', 'delete', 'edit'];\n\n// -> Do you want me to add, delete or edit the channel?\ninteraction.reply(oneLineCommaListsOr`\n\tDo you want me to ${options} the channel?\n`);\n```\n\nCheck the the documentation to find more useful functions.\n\n## chalk\n\n<Callout>Official documentation: [https://www.npmjs.com/package/chalk](https://www.npmjs.com/package/chalk)</Callout>\n\nChalk is not exactly useful for Discord bots themselves, but it will make your terminal output a lot prettier and organized.\nThis package lets you color and style your `console.log`s in many different ways; No more simple white on black.\n\nLet's say you want your error messages to be easily visible; Let us give them a nice red color:\n\n```js\nconsole.error(chalk.redBright('FATAL ERROR'), 'Something really bad happened!');\n```\n\n![image of code above](./images/chalk-red.png)\n\nYou can also chain multiple different multipliers.  \nIf you wanted to have green text, a grey background, and have it all underlined, that is possible:\n\n```js\nconsole.log(chalk.green.bgBrightBlack.underline('This is so pretty.'));\n```\n\n![image of code above](./images/chalk-ugly.png)\n\n## pino\n\n<Callout>Official documentation: [getpino.io](https://getpino.io)</Callout>\n\nPino is a Node.js logger with a very low overhead. But why does that even matter, if `console.log()` exists? Well, `console.log()` is quite slow and not very versatile. Whenever you make a call to `console.log()` your program halts and cannot do anything until the logging is finished.\n\nTo get started, install the package:\n\n```sh tab=\"sh\"\nnpm install pino\nnpm install -g pino-pretty\n```\n\n```sh tab=\"yarn\"\nyarn add pino\nyarn global add pino-pretty\n```\n\n```sh tab=\"pnpm\"\npnpm add pino\npnpm add --global pino-pretty\n```\n\n```sh tab=\"bun\"\nbun add pino\nbun add --global pino-pretty\n```\n\nPino is highly configurable, so we heavily recommend you take a look at their documentation yourself.\n\nTo use the same logger across the project you can put the following code into it's own file, for example `logger.js` and import it when needed:\n\n```js\nconst pino = require('pino');\nconst logger = pino();\nmodule.exports = logger;\n```\n\n```js\nconst { Client, Events, GatewayIntentBits } = require('discord.js');\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\nconst logger = require('./logger');\n\nclient.once(Events.ClientReady, () => logger.info('The bot is online'));\nclient.on(Events.Debug, (info) => logger.debug(info));\nclient.on(Events.Warn, (info) => logger.warn(info));\nclient.on(Events.Error, (error) => logger.error(error));\n\nclient.login('your-token-goes-here');\n```\n\nPino logs in a json format, so other programs and services like log aggregators can easily parse and work with the output. This is very useful for production systems, but quite tedious to read during development. This is why you installed `pino-pretty` earlier. Instead of formatting the log output itself the developers recommended that you [pipe](<https://en.wikipedia.org/wiki/Pipeline_(Unix)>) the log output to other services instead. `pino-pretty` is a formatter you can use for easy-to-read logs during development.\n\nWe recommend you set `pino-pretty` up in a package script in your `package.json` file, rather than typing the pipeline out every time. Please read our [guide section on package scripts](../improving-dev-environment/package-json-scripts), if you are not sure what we're talking about here.\n\n```json\n{\n\t\"name\": \"my-bot\",\n\t\"version\": \"1.0.0\",\n\t\"description\": \"A Discord bot!\",\n\t\"main\": \"index.js\",\n\t\"scripts\": {\n\t\t\"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n\t\t\"start\": \"node .\",\n\t\t\"lint\": \"eslint .\",\n\t\t\"dev\": \"node . | pino-pretty -i pid,hostname -t 'yyyy-mm-dd HH:MM:ss'\" // [!code ++]\n\t},\n\t\"keywords\": [],\n\t\"author\": \"\",\n\t\"license\": \"ISC\"\n}\n```\n\n<Callout type=\"warn\">\n\tIf you are using PowerShell, you have to use a package script for `pino-pretty`. PowerShell handles pipelines in a way\n\tthat prevents logging. The command line interface is not affected.\n</Callout>\n\nIn the example above, further arguments are passed to `pino-pretty` to modify the generated output. `-i pid,hostname` hides these two elements from logged lines and `-t yyyy-mm-dd HH:MM:ss` formats the timestamp into an easy to use format. Try out what works for you! The official [pino-pretty documentation](https://github.com/pinojs/pino-pretty) explains all possible arguments.\n\nTo start your bot with prettified input you run the `dev` script via your package manager of choice:\n\n```sh tab=\"npm\"\nnpm run dev\n```\n\n```sh tab=\"yarn\"\nyarn run dev\n```\n\n```sh tab=\"pnpm\"\npnpm run dev\n```\n\n```sh tab=\"bun\"\nbun run dev\n```\n\nPino is very flexible, supports custom log levels, worker threads and many more features. Please check out the [official documentation](https://getpino.io) if you want to up your pino game! Below we show an alternative for a production setup. Using this code, you will be logging the raw json objects into a file, instead of printing to your console:\n\n```js\nconst pino = require('pino');\nconst transport = pino.transport({\n\ttarget: 'pino/file',\n\toptions: { destination: './log.json' },\n});\nconst logger = pino(transport);\nmodule.exports = logger;\n```\n\n## i18next\n\n<Callout>Official documentation: [https://www.i18next.com](https://www.i18next.com)</Callout>\n\ni18next is an internationalization-framework for JavaScript. It is beneficial to translate your bot's user-facing messages into various languages based on the server it is used in.\n\nCovering an entire use case example for internationalization would be out of this guide's scope and requires some more explanation as to how the system operates. Please refer to the official documentation linked above for an in-depth usage guide.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/oauth2/oauth2.mdx",
    "content": "---\ntitle: OAuth2\n---\n\nOAuth2 enables application developers to build applications that utilize authentication and data from the Discord API. Developers can use this to create things such as web dashboards to display user info, fetch linked third-party accounts like Twitch or Steam, access users' guild information without actually being in the guild, and much more. OAuth2 can significantly extend the functionality of your bot if used correctly.\n\n## A quick example\n\n### Setting up a basic web server\n\nMost of the time, websites use OAuth2 to get information about their users from an external service. In this example, we will use [`express`](https://expressjs.com/) to create a web server to use a user's Discord information to greet them. Start by creating three files: `config.json`, `index.js`, and `index.html`.\n\n`config.json` will be used to store the client ID, client secret, and server port.\n\n```json title=\"config.json\" lineNumbers\n{\n\t\"clientId\": \"\",\n\t\"clientSecret\": \"\",\n\t\"port\": 53134\n}\n```\n\n`index.js` will be used to start the server and handle requests. When someone visits the index page (`/`), an HTML file will be sent in response.\n\n```js title=\"index.js\" lineNumbers\nconst express = require('express');\nconst { port } = require('./config.json');\n\nconst app = express();\n\napp.get('/', (request, response) => {\n\treturn response.sendFile('index.html', { root: '.' });\n});\n\napp.listen(port, () => console.log(`App listening at http://localhost:${port}`));\n```\n\n`index.html` will be used to display the user interface and OAuth data once logged in.\n\n```html title=\"index.html\" lineNumbers\n<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<title>My Discord OAuth2 App</title>\n\t</head>\n\t<body>\n\t\t<div id=\"info\">Hoi!</div>\n\t</body>\n</html>\n```\n\nAfter running `npm i express`, you can start your server with `node index.js`. Once started, connect to `http://localhost:53134`, and you should see \"Hoi!\".\n\n<Callout>\n\tAlthough we're using express, there are many other alternatives to handle a web server, such as:\n\t[fastify](https://www.fastify.io/), [koa](https://koajs.com/), and the [native Node.js http\n\tmodule](https://nodejs.org/api/http.html).\n</Callout>\n\n### Getting an OAuth2 URL\n\nNow that you have a web server up and running, it's time to get some information from Discord. Open [your Discord applications](https://discord.com/developers/applications/), create or select an application, and head over to the \"OAuth2\" page.\n\n![OAuth2 application page](./images/oauth2-app-page.png)\n\nTake note of the `client id` and `client secret` fields. Copy these values into your `config.json` file; you'll need them later. For now, add a redirect URL to `http://localhost:53134` like so:\n\n![Adding Redirects](./images/add-redirects.png)\n\nOnce you've added your redirect URL, you will want to generate an OAuth2 URL. Lower down on the page, you can conveniently find an OAuth2 URL Generator provided by Discord. Use this to create a URL for yourself with the `identify` scope.\n\n![Generate an OAuth2 URL](./images/generate-url.png)\n\nThe `identify` scope will allow your application to get basic user information from Discord. You can find a list of all scopes [here](https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes).\n\n### Implicit grant flow\n\n<Callout type=\"error\">\n\tImplicit grant flow, as previously covered in this section, is vulnerable to token leakage and replay attacks. Please\n\tuse the **authorization grant** flow instead. You can find out more about the best implementation practices in the\n\t[Oauth2 RFC](https://datatracker.ietf.org/doc/html/rfc9700).\n</Callout>\n\n## More details\n\n### The state parameter\n\nOAuth2's protocols provide a `state` parameter, which Discord supports. This parameter helps prevent [CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) attacks and represents your application's state. The state should be generated per user and appended to the OAuth2 URL. For a basic example, you can use a randomly generated string encoded in Base64 as the state parameter.\n\n```js\nfunction generateRandomString() {\n\tlet randomString = '';\n\tconst randomNumber = Math.floor(Math.random() * 10);\n\n\tfor (let i = 0; i < 20 + randomNumber; i++) {\n\t\trandomString += String.fromCharCode(33 + Math.floor(Math.random() * 94));\n\t}\n\n\treturn randomString;\n}\n\nwindow.onload = () => {\n\t// ...\n\tif (!accessToken) {\n\t\tconst randomString = generateRandomString();\n\t\tlocalStorage.setItem('oauth-state', randomString);\n\n\t\tdocument.getElementById('login').href += `&state=${btoa(randomString)}`;\n\t\treturn (document.getElementById('login').style.display = 'block');\n\t}\n};\n```\n\nWhen you visit a URL with a `state` parameter appended to it and then click `Authorize`, you'll notice that after being redirected, the URL will also have the `state` parameter appended, which you should then check against what was stored. You can modify the script in your `index.html` file to handle this.\n\n```html title=\"index.html\"\n<script>\n\t// ... // [!code focus:15]\n\tconst fragment = new URLSearchParams(window.location.hash.slice(1));\n\tconst [accessToken, tokenType, state] = [\n\t\tfragment.get('access_token'),\n\t\tfragment.get('token_type'),\n\t\tfragment.get('state'),\n\t];\n\n\tif (!accessToken) {\n\t\t// ...\n\t}\n\n\tif (localStorage.getItem('oauth-state') !== atob(decodeURIComponent(state))) {\n\t\treturn console.log('You may have been clickjacked!');\n\t}\n</script>\n```\n\n<Callout type=\"error\" title=\"Don't forgo security for a tiny bit of convenience!\" />\n\n### Authorization code grant flow\n\nWhat you did in the quick example was go through the `implicit grant` flow, which passed the access token straight to the user's browser. This flow is great and simple, but you don't get to refresh the token without the user, and it is less secure than going through the `authorization code grant` flow. This flow involves receiving an access code, which your server then exchanges for an access token. Notice that this way, the access token never actually reaches the user throughout the process.\n\nUnlike the [implicit grant flow](#implicit-grant-flow), you need an OAuth2 URL where the `response_type` is `code`. After you change the `response_type`, try visiting the link and authorizing your application. You should notice that instead of a hash, the redirect URL now has a single query parameter appended to it, i.e. `?code=ACCESS_CODE`. Modify your `index.js` file to access the parameter from the URL if it exists. In express, you can use the `request` parameter's `query` property.\n\n```js\napp.get('/', (request, response) => {\n\tconsole.log(`The access code is: ${request.query.code}`);\n\treturn response.sendFile('index.html', { root: '.' });\n});\n```\n\nNow you have to exchange this code with Discord for an access token. To do this, you need your `client_id` and `client_secret`. If you've forgotten these, head over to [your applications](https://discord.com/developers/applications) and get them. You can use [`undici`](https://www.npmjs.com/package/undici) to make requests to Discord.\n\nTo install undici, run the following command:\n\n```sh tab=\"npm\"\nnpm install undici\n```\n\n```sh tab=\"yarn\"\nyarn add undici\n```\n\n```sh tab=\"pnpm\"\npnpm add undici\n```\n\n```sh tab=\"bun\"\nbun add undici\n```\n\nRequire `undici` and make your request.\n\n<Callout>\n\tIf you are used to the Fetch API and want to use that instead of how `undici` does it, instead of using\n\t`undici#request`, use `undici#fetch` with the same parameters as node-fetch.\n</Callout>\n\n```js title=\"index.js\"\nconst { request } = require('undici'); // [!code ++]\nconst express = require('express');\nconst { port } = require('./config.json'); // [!code --]\nconst { clientId, clientSecret, port } = require('./config.json'); // [!code ++]\n\nconst app = express();\n\napp.get('/', async ({ query }, response) => {\n\t// [!code ++:28]\n\tconst { code } = query;\n\n\tif (code) {\n\t\ttry {\n\t\t\tconst tokenResponseData = await request('https://discord.com/api/oauth2/token', {\n\t\t\t\tmethod: 'POST',\n\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\tclient_id: clientId,\n\t\t\t\t\tclient_secret: clientSecret,\n\t\t\t\t\tcode,\n\t\t\t\t\tgrant_type: 'authorization_code',\n\t\t\t\t\tredirect_uri: `http://localhost:${port}`,\n\t\t\t\t\tscope: 'identify',\n\t\t\t\t}).toString(),\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tconst oauthData = await tokenResponseData.body.json();\n\t\t\tconsole.log(oauthData);\n\t\t} catch (error) {\n\t\t\t// NOTE: An unauthorized token will not throw an error\n\t\t\t// tokenResponseData.statusCode will be 401\n\t\t\tconsole.error(error);\n\t\t}\n\t}\n\n\treturn response.sendFile('index.html', { root: '.' });\n});\n```\n\n<Callout>\n\tThe content-type for the token URL must be `application/x-www-form-urlencoded`, which is why `URLSearchParams` is\n\tused.\n</Callout>\n\nNow try visiting your OAuth2 URL and authorizing your application. Once you're redirected, you should see an [access token response](https://discord.com/developers/docs/topics/oauth2#authorization-code-grant-access-token-response) in your console.\n\n```json\n{\n\t\"access_token\": \"an access token\",\n\t\"token_type\": \"Bearer\",\n\t\"expires_in\": 604800,\n\t\"refresh_token\": \"a refresh token\",\n\t\"scope\": \"identify\"\n}\n```\n\nWith an access token and a refresh token, you can once again use the [`/api/users/@me` endpoint](https://discord.com/developers/docs/resources/user#get-current-user) to fetch the [user object](https://discord.com/developers/docs/resources/user#user-object).\n\n```js\nconst userResult = await request('https://discord.com/api/users/@me', {\n\theaders: {\n\t\tauthorization: `${oauthData.token_type} ${oauthData.access_token}`,\n\t},\n});\n\nconsole.log(await userResult.body.json());\n```\n\n<Callout\n\ttype=\"error\"\n\ttitle=\"To maintain security, store the access token server-side but associate it with a session ID that you generate for the user.\"\n/>\n\n## Additional reading\n\n[RFC 6759](https://tools.ietf.org/html/rfc6749)  \n[Discord Docs for OAuth2](https://discord.com/developers/docs/topics/oauth2)\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/audit-logs.mdx",
    "content": "---\ntitle: Audit Logs\n---\n\n## Working with Audit Logs\n\n### A Quick Background\n\nAudit logs are an excellent moderation tool offered by Discord to know what happened in a server and usually by whom. Making use of audit logs requires the `ViewAuditLog` permission. Audit logs may be fetched on a server, or they may be received via the gateway event `guildAuditLogEntryCreate` which requires the `GuildModeration` intent.\n\nThere are quite a few cases where you may use audit logs. This guide will limit itself to the most common use cases. Feel free to consult the [relevant Discord API page](https://discord.com/developers/docs/resources/audit-log) for more information.\n\nKeep in mind that these examples explore a straightforward case and are by no means exhaustive. Their purpose is to teach you how audit logs work, and expansion of these examples is likely needed to suit your specific use case.\n\n## Fetching Audit Logs\n\nLet's start by glancing at the `Guild#fetchAuditLogs` method and how to work with it. Like many discord.js methods, it returns a [`Promise`](../additional-info/async-await) containing the `GuildAuditLogs` object. This object has one property, `entries`, which holds a [`Collection`](../additional-info/collections) of `GuildAuditLogsEntry` objects, and consequently, the information you want to retrieve.\n\nHere is the most basic fetch to look at some entries.\n\n```js\nconst fetchedLogs = await guild.fetchAuditLogs();\nconst firstEntry = fetchedLogs.entries.first();\n```\n\nSimple, right? Now, let's look at utilizing its options:\n\n```js\nconst { AuditLogEvent } = require('discord.js');\n\nconst fetchedLogs = await guild.fetchAuditLogs({\n\ttype: AuditLogEvent.InviteCreate,\n\tlimit: 1,\n});\n\nconst firstEntry = fetchedLogs.entries.first();\n```\n\nThis will return the first entry where an invite was created. You used `limit: 1` here to specify only one entry.\n\n## Receiving Audit Logs\n\nAudit logs may be received via the gateway event `guildAuditLogEntryCreate`. This is the best way to receive audit logs if you want to monitor them. As soon as a message is deleted, or an invite or emoji is created, your application will receive an instance of this event. A common use case is to find out _who_ did the action that caused the audit log event to happen.\n\n### Who deleted a message?\n\nOne of the most common use cases for audit logs is understanding who deleted a message in a Discord server. If a user deleted another user's message, you can find out who did that as soon as you receive the corresponding audit log event.\n\n```js\nconst { AuditLogEvent, Events } = require('discord.js');\n\nclient.on(Events.GuildAuditLogEntryCreate, async (auditLog) => {\n\t// Define your variables.\n\t// The extra information here will be the channel.\n\tconst { action, extra: channel, executorId, targetId } = auditLog;\n\n\t// Check only for deleted messages.\n\tif (action !== AuditLogEvent.MessageDelete) return;\n\n\t// Ensure the executor is cached.\n\tconst executor = await client.users.fetch(executorId);\n\n\t// Ensure the author whose message was deleted is cached.\n\tconst target = await client.users.fetch(targetId);\n\n\t// Log the output.\n\tconsole.log(`A message by ${target.tag} was deleted by ${executor.tag} in ${channel}.`);\n});\n```\n\nWith this, you now have a very simple logger telling you who deleted a message authored by another person.\n\n### Who kicked a user?\n\nThis is very similar to the example above.\n\n```js\nconst { AuditLogEvent, Events } = require('discord.js');\n\nclient.on(Events.GuildAuditLogEntryCreate, async (auditLog) => {\n\t// Define your variables.\n\tconst { action, executorId, targetId } = auditLog;\n\n\t// Check only for kicked users.\n\tif (action !== AuditLogEvent.MemberKick) return;\n\n\t// Ensure the executor is cached.\n\tconst executor = await client.users.fetch(executorId);\n\n\t// Ensure the kicked guild member is cached.\n\tconst kickedUser = await client.users.fetch(targetId);\n\n\t// Now you can log the output!\n\tconsole.log(`${kickedUser.tag} was kicked by ${executor.tag}.`);\n});\n```\n\nIf you want to check who banned a user, it's the same example as above except the `action` should be `AuditLogEvent.MemberBanAdd`. You can check the rest of the types over at the [discord-api-types documentation](https://discord-api-types.dev/api/discord-api-types-v10/enum/AuditLogEvent).\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/canvas.mdx",
    "content": "---\ntitle: Canvas\n---\n\n## Setting up @napi-rs/canvas\n\n`@napi-rs/canvas` is an image manipulation tool that allows you to modify images with code. We'll explore how to use this module in a slash command to make a profile command.\n\n<Callout>\n\tThis guide is last tested with `@napi-rs/canvas^0.1.25`, so make sure you have this or a similar version after\n\tinstallation.\n</Callout>\n\n<Callout type=\"warn\">\n\tBe sure that you're familiar with things like [async/await](../additional-info/async-await) and [object\n\tdestructuring](../additional-info/es6-syntax#object-destructuring) before continuing, as we'll be making use of those\n\tfeatures in the coming sections.\n</Callout>\n\n## Package installation\n\nRun the following command in your terminal:\n\n```sh tab=\"npm\"\nnpm install @napi-rs/canvas\n```\n\n```sh tab=\"yarn\"\nyarn add @napi-rs/canvas\n```\n\n```sh tab=\"pnpm\"\npnpm add @napi-rs/canvas\n```\n\n```sh tab=\"bun\"\nbun add @napi-rs/canvas\n```\n\n## Getting started\n\nHere is the base code you'll be using to get started:\n\n```js lineNumbers title=\"index.js\"\nconst { AttachmentBuilder, Client, Events, GatewayIntentBits } = require('discord.js');\nconst Canvas = require('@napi-rs/canvas');\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\nclient.once(Events.ClientReady, (readyClient) => {\n\tconsole.log(`Ready! Logged in as ${readyClient.user.tag}`);\n});\n\nclient.on(Events.InteractionCreate, (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tif (interaction.commandName === 'profile') {\n\t\t// ...\n\t}\n});\n\nclient.login('your-token-goes-here');\n```\n\n<Callout>\n\tIf you followed the [event handler section](../app-creation/handling-events) of this guide, consider putting this into\n\tyour interaction handler instead!\n</Callout>\n\n<Callout type=\"warn\">\n\tRemember to register the slash commands before continuing on with this section of the guide. You can view how to do\n\tthat [here](../interactions/slash-commands.md#registering-slash-commands).\n</Callout>\n\n### Basic image loading\n\nThe end goal will be to display the user's avatar and nickname.\n\nAfter importing the `@napi-rs/canvas` module and initializing it, you should load the images. With `@napi-rs/canvas`, you have to specify where the image comes from first, naturally, and then specify how it gets loaded into the actual Canvas using `context`, which you will use to interact with Canvas.\n\n<Callout>\n\t`@napi-rs/canvas` works almost identical to HTML5 Canvas. You can read the HTML5 Canvas tutorials on\n\t[w3Schools](https://www.w3schools.com/html/html5_canvas.asp) and\n\t[MDN](https://developer.mozilla.org/docs/Web/API/Canvas_API) for more information later!\n</Callout>\n\n```js lineNumbers=10 title=\"index.js\"\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tif (interaction.commandName === 'profile') {\n\t\t// [!code ++:4]\n\t\t// Create a 700x250 pixel canvas and get its context\n\t\t// The context will be used to modify the canvas\n\t\tconst canvas = Canvas.createCanvas(700, 250);\n\t\tconst context = canvas.getContext('2d');\n\t\t// ...\n\t}\n});\n```\n\nNow, you need to load the image you want to use into Canvas.\n\nWe'll be using [this image](https://github.com/discordjs/discord.js/blob/main/apps/guide/content/docs/legacy/popular-topics/images/canvas.jpg) as the background in the welcome image, but you can use whatever you want. Be sure to download the file, name it `wallpaper.jpg`, and save it inside the same directory as your main bot file.\n\n```js lineNumbers=10 title=\"index.js\"\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tconst canvas = Canvas.createCanvas(700, 250);\n\t// [!code focus:10]\n\tconst context = canvas.getContext('2d');\n\t// [!code ++:9]\n\tconst background = await Canvas.loadImage('./wallpaper.jpg');\n\n\t// This uses the canvas dimensions to stretch the image onto the entire canvas\n\tcontext.drawImage(background, 0, 0, canvas.width, canvas.height);\n\n\t// Use the helpful Attachment class structure to process the file for you\n\tconst attachment = new AttachmentBuilder(await canvas.encode('png'), { name: 'profile-image.png' });\n\n\tinteraction.reply({ files: [attachment] });\n});\n```\n\n![Basic canvas preview](./images/canvas-preview.png)\n\n<Callout>\n\tIf you get an error such as `Error: ENOENT: no such file or directory`, then the file's provided path was incorrect.\n</Callout>\n\n### Manipulating images\n\nNext, let's place a border around the image for the sake of demonstration purposes.\n\n```js\nclient.on(Events.InteractionCreate, async (interaction) => {\n\t// ... // [!code focus:9]\n\tcontext.drawImage(background, 0, 0, canvas.width, canvas.height);\n\n\t// [!code ++:5]\n\t// Set the color of the stroke\n\tcontext.strokeStyle = '#0099ff';\n\n\t// Draw a rectangle with the dimensions of the entire canvas\n\tcontext.strokeRect(0, 0, canvas.width, canvas.height);\n\t// ...\n});\n```\n\n![Image](./images/canvas-plain.png)\n\nA bit plain, right? Fear not, for you have a bit more to do until you reach completion. Since this guide page's goal is focused more on actual code than design, let's place a basic square-shaped avatar for now on the left side of the image. In the interest of coverage, you will also make it a circle afterward.\n\n```js\nconst { request } = require('undici'); // [!code focus] [!code ++]\n\nclient.on(Events.InteractionCreate, async (interaction) => {\n\t// ... // [!code focus:13]\n\tcontext.strokeRect(0, 0, canvas.width, canvas.height);\n\n\t// [!code ++:9]\n\t// Using undici to make HTTP requests for better performance\n\tconst { body } = await request(interaction.user.displayAvatarURL({ extension: 'jpg' }));\n\tconst avatar = await Canvas.loadImage(await body.arrayBuffer());\n\n\t// If you don't care about the performance of HTTP requests, you can instead load the avatar using\n\t// const avatar = await Canvas.loadImage(interaction.user.displayAvatarURL({ extension: 'jpg' }));\n\n\t// Draw a shape onto the main canvas\n\tcontext.drawImage(avatar, 25, 0, 200, canvas.height);\n\tcontext.drawImage(background, 0, 0, canvas.width, canvas.height); // [!code --]\n\t// ...\n});\n```\n\n![Image](./images/canvas-stretched-avatar.png)\n\nIt works well, but the avatar image itself seems a bit stretched out. Let's remedy that.\n\n```js\nclient.on(Events.InteractionCreate, async (interaction) => {\n\t// ... // [!code focus:8]\n\tconst { body } = await request(interaction.user.displayAvatarURL({ extension: 'jpg' }));\n\tconst avatar = await Canvas.loadImage(await body.arrayBuffer());\n\n\tcontext.drawImage(avatar, 25, 0, 200, canvas.height); // [!code --]\n\t// [!code ++:2]\n\t// Move the image downwards vertically and constrain its height to 200, so that it's square\n\tcontext.drawImage(avatar, 25, 25, 200, 200);\n\t// ...\n});\n```\n\n![Image](./images/canvas-square-avatar.png)\n\nThe purpose of this small section is to demonstrate that working with Canvas is essentially a hit-and-miss workflow where you fiddle with properties until they work just right.\n\nSince we covered how to load external images and fix dimensions, let's turn the avatar into a circle to improve the image's overall style.\n\n```js\nclient.on(Events.InteractionCreate, async (interaction) => {\n\t// [!code focus:15]\n\t// ...\n\tcontext.strokeRect(0, 0, canvas.width, canvas.height);\n\n\t// [!code ++:11]\n\t// Pick up the pen\n\tcontext.beginPath();\n\n\t// Start the arc to form a circle\n\tcontext.arc(125, 125, 100, 0, Math.PI * 2, true);\n\n\t// Put the pen down\n\tcontext.closePath();\n\n\t// Clip off the region you drew on\n\tcontext.clip();\n\t// ...\n});\n```\n\n![Image](./images/canvas-circle-avatar.png)\n\n<Callout>\n\tYou can read more about `context.arc()` on [w3schools](https://www.w3schools.com/tags/canvas_arc.asp) or\n\t[MDN](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/arc).\n</Callout>\n\n### Adding in text\n\nNow, let's quickly go over adding text to your image. This will help make the purpose of this image apparent since currently, it's just an avatar floating on a starry background that comes out of nowhere.\n\n```js\nclient.on(Events.InteractionCreate, async (interaction) => {\n\t// ... // [!code focus:12]\n\tcontext.strokeRect(0, 0, canvas.width, canvas.height);\n\n\t// [!code ++:8]\n\t// Select the font size and type from one of the natively available fonts\n\tcontext.font = '60px sans-serif';\n\n\t// Select the style that will be used to fill the text in\n\tcontext.fillStyle = '#ffffff';\n\n\t// Actually fill the text with a solid color\n\tcontext.fillText(interaction.member.displayName, canvas.width / 2.5, canvas.height / 1.8);\n\t// ...\n});\n```\n\n![Image](./images/canvas-add-name.png)\n\n<Callout type=\"error\">\n\tIf you get an error like `Fontconfig error: Cannot load default config file`, it means you do not have any fonts\n\tinstalled on your system. On Linux, you can run the following command to fix this: `sudo apt-get install fontconfig`.\n\tThis might also need to be installed if you see boxes where the text should be. As for Windows, you will need to find\n\ta way to install fonts.\n</Callout>\n\nYou may have noticed or considered that if a member's username is too long, then the output won't be quite nice. This is because the text overflows out of the canvas, and you don't have any measures in place for that. Let's take care of this issue!\n\n```js\n// [!code focus:16] [!code ++:16]\n// Pass the entire Canvas object because you'll need access to its width and context\nconst applyText = (canvas, text) => {\n\tconst context = canvas.getContext('2d');\n\n\t// Declare a base size of the font\n\tlet fontSize = 70;\n\n\tdo {\n\t\t// Assign the font to the context and decrement it so it can be measured again\n\t\tcontext.font = `${(fontSize -= 10)}px sans-serif`;\n\t\t// Compare pixel width of the text to the canvas minus the approximate avatar size\n\t} while (context.measureText(text).width > canvas.width - 300);\n\n\t// Return the result to use in the actual canvas\n\treturn context.font;\n};\n\nclient.on(Events.InteractionCreate, async (interaction) => {\n\t// ... // [!code focus:8]\n\tcontext.strokeRect(0, 0, canvas.width, canvas.height);\n\n\tcontext.font = '60px sans-serif'; // [!code --]\n\tcontext.font = applyText(canvas, interaction.member.displayName); // [!code ++]\n\tcontext.fillStyle = '#ffffff';\n\tcontext.fillText(interaction.member.displayName, canvas.width / 2.5, canvas.height / 1.8);\n\t// ...\n});\n```\n\nBefore adjustment:\n\n![Before adjustment](./images/canvas-before-text-wrap.png)\n\nAfter adjustment:\n\n![After adjustment](./images/canvas-after-text-wrap.png)\n\nLet's move the welcome text inside the image itself instead of adding it outside as a nice finishing touch.\n\n```js\nclient.on(Events.InteractionCreate, async (interaction) => {\n\t// ... // [!code focus:15]\n\tcontext.strokeRect(0, 0, canvas.width, canvas.height);\n\n\t// Slightly smaller text placed above the member's display name // [!code ++:4]\n\tcontext.font = '28px sans-serif';\n\tcontext.fillStyle = '#ffffff';\n\tcontext.fillText('Profile', canvas.width / 2.5, canvas.height / 3.5);\n\n\t// Add an exclamation point here and below // [!code ++:2]\n\tcontext.font = applyText(canvas, `${interaction.member.displayName}!`);\n\tcontext.font = applyText(canvas, interaction.member.displayName); // [!code --]\n\tcontext.fillStyle = '#ffffff';\n\tcontext.fillText(`${interaction.member.displayName}!`, canvas.width / 2.5, canvas.height / 1.8); // [!code ++]\n\tcontext.fillText(interaction.member.displayName, canvas.width / 2.5, canvas.height / 1.8); // [!code --]\n\t// ...\n});\n```\n\n![Final result](./images/canvas-final-result.png)\n\nAnd that's it! We have covered the basics of image manipulation, text generation, and loading from a remote source.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/collectors.mdx",
    "content": "---\ntitle: Collectors\n---\n\n## Message collectors\n\n`Collector` are useful to enable your bot to obtain _additional_ input after the first command was sent. An example would be initiating a quiz, where the bot will \"await\" a correct response from somebody.\n\n### Basic message collector\n\nFor now, let's take the example that they have provided us:\n\n```js\n// `m` is a message object that will be passed through the filter function\nconst collectorFilter = (m) => m.content.includes('discord');\nconst collector = interaction.channel.createMessageCollector({ filter: collectorFilter, time: 15_000 });\n\ncollector.on('collect', (m) => {\n\tconsole.log(`Collected ${m.content}`);\n});\n\ncollector.on('end', (collected) => {\n\tconsole.log(`Collected ${collected.size} items`);\n});\n```\n\nYou can provide a `filter` key to the object parameter of `createMessageCollector()`. The value to this key should be a function that returns a boolean value to indicate if this message should be collected or not. To check for multiple conditions in your filter you can connect them using [logical operators](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Expressions_and_Operators#logical_operators). If you don't provide a filter all messages in the channel the collector was started on will be collected.\n\nNote that the above example uses [implicit return](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Functions/Arrow_functions#function_body) for the filter function and passes it to the options object using the [object property shorthand](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Object_initializer#property_definitions) notation.\n\nIf a message passes through the filter, it will trigger the `collect` event for the `collector` you've created. This message is then passed into the event listener as `collected` and the provided function is executed. In the above example, you simply log the message. Once the collector finishes collecting based on the provided end conditions the `end` event emits.\n\nYou can control when a collector ends by supplying additional option keys when creating a collector:\n\n- `time`: Amount of time in milliseconds the collector should run for\n- `max`: Number of messages to successfully pass the filter\n- `maxProcessed`: Number of messages encountered (no matter the filter result)\n\nThe benefit of using an event-based collector over `.awaitMessages()` (its promise-based counterpart) is that you can do something directly after each message is collected, rather than just after the collector ended. You can also stop the collector manually by calling `collector.stop()`.\n\n### Await messages\n\nUsing `TextChannel#awaitMessages` can be easier if you understand Promises, and it allows you to have cleaner code overall. It is essentially identical to `TextChannel#createMessageCollector`, except promisified. However, the drawback of using this method is that you cannot do things before the Promise is resolved or rejected, either by an error or completion. However, it should do for most purposes, such as awaiting the correct response in a quiz. Instead of taking their example, let's set up a basic quiz command using the `.awaitMessages()` feature.\n\nFirst, you'll need some questions and answers to choose from, so here's a basic set:\n\n```json\n[\n\t{\n\t\t\"question\": \"What color is the sky?\",\n\t\t\"answers\": [\"blue\"]\n\t},\n\t{\n\t\t\"question\": \"How many letters are there in the alphabet?\",\n\t\t\"answers\": [\"26\", \"twenty-six\", \"twenty six\", \"twentysix\"]\n\t}\n]\n```\n\nThe provided set allows for responder error with an array of answers permitted. Ideally, it would be best to place this in a JSON file, which you can call `quiz.json` for simplicity.\n\n```js\nconst quiz = require('./quiz.json');\n// ...\nconst item = quiz[Math.floor(Math.random() * quiz.length)];\nconst collectorFilter = (response) => {\n\treturn item.answers.some((answer) => answer.toLowerCase() === response.content.toLowerCase());\n};\n\ninteraction.reply({ content: item.question, withResponse: true }).then((response) => {\n\tresponse.resource.message.channel\n\t\t.awaitMessages({ filter: collectorFilter, max: 1, time: 30_000, errors: ['time'] })\n\t\t.then((collected) => {\n\t\t\tinteraction.followUp(`${collected.first().author} got the correct answer!`);\n\t\t})\n\t\t.catch((collected) => {\n\t\t\tinteraction.followUp('Looks like nobody got the answer this time.');\n\t\t});\n});\n```\n\n<Callout>\n\tIf you don't understand how `.some()` works, you can read about it in more detail\n\t[here](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/some).\n</Callout>\n\nIn this filter, you iterate through the answers to find what you want. You would like to ignore the case because simple typos can happen, so you convert each answer to its lowercase form and check if it's equal to the response in lowercase form as well. In the options section, you only want to allow one answer to pass through, hence the `max: 1` setting.\n\nThe filter looks for messages that match one of the answers in the array of possible answers to pass through the collector. The options (the second parameter) specifies that only a maximum of one message can go through the filter successfully before the Promise successfully resolves. The errors section specifies that time will cause it to error out, which will cause the Promise to reject if one correct answer is not received within the time limit of one minute. As you can see, there is no `collect` event, so you are limited in that regard.\n\n## Reaction collectors\n\n### Basic reaction collector\n\nThese work quite similarly to message collectors, except that you apply them on a message rather than a channel. This example uses the `Message#createReactionCollector` method. The filter will check for the 👍 emoji–in the default skin tone specifically, so be wary of that. It will also check that the person who reacted shares the same id as the author of the original message that the collector was assigned to.\n\n```js\nconst collectorFilter = (reaction, user) => {\n\treturn reaction.emoji.name === '👍' && user.id === message.author.id;\n};\n\nconst collector = message.createReactionCollector({ filter: collectorFilter, time: 15_000 });\n\ncollector.on('collect', (reaction, user) => {\n\tconsole.log(`Collected ${reaction.emoji.name} from ${user.tag}`);\n});\n\ncollector.on('end', (collected) => {\n\tconsole.log(`Collected ${collected.size} items`);\n});\n```\n\n### Await reactions\n\n`Message#awaitReactions` works almost the same as a reaction collector, except it is Promise-based. The same differences apply as with channel collectors.\n\n```js\nconst collectorFilter = (reaction, user) => {\n\treturn reaction.emoji.name === '👍' && user.id === message.author.id;\n};\n\nmessage\n\t.awaitReactions({ filter: collectorFilter, max: 4, time: 60_000, errors: ['time'] })\n\t.then((collected) => console.log(collected.size))\n\t.catch((collected) => {\n\t\tconsole.log(`After a minute, only ${collected.size} out of 4 reacted.`);\n\t});\n```\n\n## Interaction collectors\n\nThe third type of collector allows you to collect interactions; such as when users activate a slash command or click on a button in a message.\n\n### Basic message component collector\n\nCollecting interactions from message components works similarly to reaction collectors. In the following example, you will check that the interaction came from a button, and that the user clicking the button is the same user that initiated the command.\n\nOne important difference to note with interaction collectors is that Discord expects a response to _all_ interactions within 3 seconds - even ones that you don't want to collect. For this reason, you may wish to `.deferUpdate()` all interactions in your filter, or not use a filter at all and handle this behavior in the `collect` event.\n\n```js\nconst { ComponentType } = require('discord.js');\n\nconst collector = message.createMessageComponentCollector({ componentType: ComponentType.Button, time: 15_000 });\n\ncollector.on('collect', (i) => {\n\tif (i.user.id === interaction.user.id) {\n\t\ti.reply(`${i.user.id} clicked on the ${i.customId} button.`);\n\t} else {\n\t\ti.reply({ content: `These buttons aren't for you!`, flags: MessageFlags.Ephemeral });\n\t}\n});\n\ncollector.on('end', (collected) => {\n\tconsole.log(`Collected ${collected.size} interactions.`);\n});\n```\n\n### Await message component\n\nAs before, this works similarly to the message component collector, except it is Promise-based.\n\nUnlike other Promise-based collectors, this method will only ever collect one interaction that passes the filter. If no interactions are collected before the time runs out, the Promise will reject. This behavior aligns with Discord's requirement that actions should immediately receive a response. In this example, you will use `.deferUpdate()` on all interactions in the filter.\n\n```js\nconst { ComponentType } = require('discord.js');\n\nconst collectorFilter = (i) => {\n\ti.deferUpdate();\n\treturn i.user.id === interaction.user.id;\n};\n\nmessage\n\t.awaitMessageComponent({ filter: collectorFilter, componentType: ComponentType.StringSelect, time: 60_000 })\n\t.then((interaction) => interaction.editReply(`You selected ${interaction.values.join(', ')}!`))\n\t.catch((err) => console.log('No interactions were collected.'));\n```\n\n### Await modal submit\n\nIf you want to wait for the submission of a modal within the context of another command or button execution, you may find the promisified collector `CommandInteraction#awaitModalSubmit` useful.\n\nAs Discord does not inform you if the user dismisses the modal, supplying a maximum `time` to wait for is crucial:\n\n```js\ninitialInteraction\n\t.awaitModalSubmit({ time: 60_000, filter })\n\t.then((interaction) => interaction.editReply('Thank you for your submission!'))\n\t.catch((err) => console.log('No modal submit interaction was collected'));\n```\n\nFor more information on working with modals, see the [modals section of this guide](../interactions/modals).\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/display-components.mdx",
    "content": "---\ntitle: Display Components\n---\n\nWhile you might be familiar with [embeds](./embeds) in Discord, there are more ways to style and format your apps messages using **display components**, a comprehensive set of layout and content elements.\n\nTo use the display components, you need to pass the `IsComponentsV2` message flag (in docs: `MessageFlags`) when sending a message. You only need to use this flag when sending a message using the display components system, not when deferring interaction responses.\n\n<Callout type=\"warn\">\n    Opting into using this system by passing the `IsComponentsV2` flag comes with a set of caveats:\n\n    - You **cannot** send `content`, `poll`, `embeds`, or `stickers`.\n    - You **cannot** opt out of using display components when editing a message\n    - You **can** opt into using display components when editing a message while explicitly setting `content`, `poll`, `embeds`, and `stickers` to null.\n    - Messages can have up to **40** total components (nested components count!)\n    - The amount of text across all text display components **cannot** exceed 4000 characters.\n    - All attached files have to explicitly be referenced in a component (refer to the [Thumbnail](#thumbnail), [Media Gallery](#media-gallery), and [File](#file) sections).\n\n</Callout>\n\n## The component `id`\n\nAll components can be passed an optional, unique, `id` field holding a 32-bit integer identifier to later identify them in interaction responses. Do not confuse this with the `custom_id` field for interactive components! You can find more information about this [in the discord api documentation](https://discord.com/developers/docs/components/reference#anatomy-of-a-component). Discord will automatically populate the `id` of components that don't have the `id` specified in the payload sequentially starting from `1`. The `id` value `0` is treated as empty. The order components are automatically filled in is an implementation detail and not officially document. If you want to work with the `id` (for example to find and replace the content of a specific component later on), you should explicitly specify it.\n\nIn the following sections, we will explain all available display component types in detail and show you some examples on how you can use them.\n\n## Text Display\n\nText Display components let you add markdown-formatted text to your message and directly replace the `content` field when opting to use display components. You can use the `TextDisplayBuilder` class to easily create a Text Display component.\n\n<Callout type=\"error\">\n\tSending user and role mentions in text display components **will notify users and roles**! You can and should control\n\tmentions with the `allowedMentions` message option.\n</Callout>\n<Callout>\n\tText display components can be used in modals. See the [modal guide](../interactions/modals#text-display) for usage.\n</Callout>\n\nThe example below shows how you can send a Text Display component in a channel.\n\n```js\nconst { TextDisplayBuilder, MessageFlags } = require('discord.js');\n\nconst exampleTextDisplay = new TextDisplayBuilder().setContent(\n\t'This text is inside a Text Display component! You can use **any __markdown__** available inside this component too.',\n);\n\nawait channel.send({\n\tcomponents: [exampleTextDisplay],\n\tflags: MessageFlags.IsComponentsV2,\n});\n```\n\n![Text display component preview](./images/textdisplay-preview.png)\n\n## Section\n\nSections represent text (one to three Text Display components) with an accessory. The accessory can either be an image (thumbnail) or button. If you do not want to send an accessory, use a [Text Display](#text-display) component instead. You can use the `SectionBuilder` class to easily create a Section component:\n\n```js\nconst { SectionBuilder, ButtonStyle, MessageFlags } = require('discord.js');\n\nconst exampleSection = new SectionBuilder()\n\t.addTextDisplayComponents(\n\t\t(textDisplay) =>\n\t\t\ttextDisplay.setContent(\n\t\t\t\t'This text is inside a Text Display component! You can use **any __markdown__** available inside this component too.',\n\t\t\t),\n\t\t(textDisplay) => textDisplay.setContent('Using a section, you may only use up to three Text Display components.'),\n\t\t(textDisplay) => textDisplay.setContent('And you can place one button or one thumbnail component next to it!'),\n\t)\n\t.setButtonAccessory((button) =>\n\t\tbutton.setCustomId('exampleButton').setLabel('Button inside a Section').setStyle(ButtonStyle.Primary),\n\t);\n\nawait channel.send({\n\tcomponents: [exampleSection],\n\tflags: MessageFlags.IsComponentsV2,\n});\n```\n\n![Section component preview](./images/section-preview.png)\n\n## Thumbnail\n\nA Thumbnail is a display component that is visually similar to the `thumbnail` field inside an embed. Thumbnails are added as accessory inside a [Section](#section) component, support alt text for accessibility, and can be marked as a spoiler. You can use the `ThumbnailBuilder` class to easily create a Thumbnail component:\n\n```js\nconst { AttachmentBuilder, SectionBuilder, MessageFlags } = require('discord.js');\n\nconst file = new AttachmentBuilder('../assets/image.png');\n\nconst exampleSection = new SectionBuilder()\n\t.addTextDisplayComponents((textDisplay) =>\n\t\ttextDisplay.setContent(\n\t\t\t'This text is inside a Text Display component! You can use **any __markdown__** available inside this component too.',\n\t\t),\n\t)\n\t.setThumbnailAccessory(\n\t\t(thumbnail) => thumbnail.setDescription('alt text displaying on the image').setURL('attachment://image.png'), // Supports arbitrary URLs such as 'https://i.imgur.com/AfFp7pu.png' as well.\n\t);\n\nawait channel.send({\n\tcomponents: [exampleSection],\n\tfiles: [file],\n\tflags: MessageFlags.IsComponentsV2,\n});\n```\n\n![Thumbnail component preview](./images/thumbnail-preview.png)\n\nFor more information about using attachments in components refer to the guide on [attaching images in embeds](./embeds#attaching-images).\n\n## Media Gallery\n\nA Media Gallery is a display component that can display a grid of up to 10 media attachments. Each media item can have an optional alt text (description) and can be marked as spoiler. You can use the `MediaGalleryBuilder` and `MediaGalleryItemBuilder` classes to easily create a Media Gallery component and its items:\n\n```js\nconst { AttachmentBuilder, MediaGalleryBuilder, MessageFlags } = require('discord.js');\n\nconst file = new AttachmentBuilder('../assets/image.png');\n\nconst exampleGallery = new MediaGalleryBuilder().addItems(\n\t(mediaGalleryItem) =>\n\t\tmediaGalleryItem\n\t\t\t.setDescription('alt text displaying on an image from the AttachmentBuilder')\n\t\t\t.setURL('attachment://image.png'),\n\t(mediaGalleryItem) =>\n\t\tmediaGalleryItem\n\t\t\t.setDescription('alt text displaying on an image from an external URL')\n\t\t\t.setURL('https://i.imgur.com/AfFp7pu.png')\n\t\t\t.setSpoiler(true), // Will display as a blurred image\n);\n\nawait channel.send({\n\tcomponents: [exampleGallery],\n\tfiles: [file],\n\tflags: MessageFlags.IsComponentsV2,\n});\n```\n\n![Media gallery component preview](./images/mediagallery-preview.png)\n\n## File\n\nA File is a display component that can display a single uploaded file within the body of the message. By using multiple File components, you can upload and display multiple files in a single message. File components cannot have alt texts (description), unlike a Thumbnail or Media Gallery component, but can be marked as a spoiler. You can use the `FileBuilder` class to easily create a File component:\n\n```js\nconst { AttachmentBuilder, FileBuilder, MessageFlags } = require('discord.js');\n\nconst file = new AttachmentBuilder('../assets/guide.pdf');\n\nconst exampleFile = new FileBuilder().setURL('attachment://guide.pdf');\n\nawait channel.send({\n\tcomponents: [exampleFile],\n\tfiles: [file],\n\tflags: MessageFlags.IsComponentsV2,\n});\n```\n\n![File component preview](./images/file-preview.png)\n\n## Separator\n\nA Separator is a layout component that adds vertical padding and optional visual division between components. You can select the amount of padding used for the Separator component (small or large) as well as whether a visual divider should be displayed (defaults to `true`). You can use the `SeparatorBuilder` class to easily create a Separator component.\n\n<Callout type=\"warn\">\n\tWhen a Separator component is used without any non-Separator components in the message payload, the message will not\n\thave any visible content.\n</Callout>\n\nThe example below shows how you can send a Separator component in a channel, separating two Text Display components.\n\n```js\nconst { TextDisplayBuilder, SeparatorBuilder, SeparatorSpacingSize, MessageFlags } = require('discord.js');\n\nconst exampleTextDisplay = new TextDisplayBuilder().setContent(\n\t'This text is inside a Text Display component! You can use **any __markdown__** available inside this component too.',\n);\n\nconst exampleSeparator = new SeparatorBuilder()\n\t.setDivider(false) // No line displayed\n\t.setSpacing(SeparatorSpacingSize.Large);\n\nawait channel.send({\n\tcomponents: [exampleTextDisplay, exampleSeparator, exampleTextDisplay],\n\tflags: MessageFlags.IsComponentsV2,\n});\n```\n\n![Separator component preview](./images/separator-preview.png)\n\n## Container\n\nA Container is a layout component which groups its child components inside a visually distinct rounded box with an optional accent color on the left, similar to the message embed look. Unlike embeds, not specifying a color will make the left side of the Container component match the background color. You can mark Container components as spoiler, which blurs all content inside the container. You can use the `ContainerBuilder` class to easily create a Container component.\n\nThe example below shows how to send a Container component in a channel. It contains:\n\n- a Text Display component;\n- an Action Row component with a User Select component;\n- a Separator component;\n- a Section component with two Text Display components and a Button component accessory.\n\n```js\nconst { ContainerBuilder, UserSelectMenuBuilder, ButtonStyle, MessageFlags } = require('discord.js');\n\nconst exampleContainer = new ContainerBuilder()\n\t.setAccentColor(0x0099ff)\n\t.addTextDisplayComponents((textDisplay) =>\n\t\ttextDisplay.setContent(\n\t\t\t'This text is inside a Text Display component! You can use **any __markdown__** available inside this component too.',\n\t\t),\n\t)\n\t.addActionRowComponents((actionRow) =>\n\t\tactionRow.setComponents(new UserSelectMenuBuilder().setCustomId('exampleSelect').setPlaceholder('Select users')),\n\t)\n\t.addSeparatorComponents((separator) => separator)\n\t.addSectionComponents((section) =>\n\t\tsection\n\t\t\t.addTextDisplayComponents(\n\t\t\t\t(textDisplay) =>\n\t\t\t\t\ttextDisplay.setContent(\n\t\t\t\t\t\t'This text is inside a Text Display component! You can use **any __markdown__** available inside this component too.',\n\t\t\t\t\t),\n\t\t\t\t(textDisplay) => textDisplay.setContent('And you can place one button or one thumbnail component next to it!'),\n\t\t\t)\n\t\t\t.setButtonAccessory((button) =>\n\t\t\t\tbutton.setCustomId('exampleButton').setLabel('Button inside a Section').setStyle(ButtonStyle.Primary),\n\t\t\t),\n\t);\n\nawait channel.send({\n\tcomponents: [exampleContainer],\n\tflags: MessageFlags.IsComponentsV2,\n});\n```\n\n![Container component preview](./images/container-preview.png)\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/embeds.mdx",
    "content": "---\ntitle: Message Embeds\n---\n\nIf you have been around on Discord for a bit, chances are you have seen these special messages, often sent by bots.\nThey can have a colored border, embedded images, text fields, and other fancy properties.\n\nIn the following section, we will explain how to compose an embed, send it, and what you need to be aware of while doing so.\n\n## Embed preview\n\nHere is an example of how an embed may look. We will go over embed construction in the next part of this guide.\n\n## Using the embed constructor\n\ndiscord.js features the `EmbedBuilder` utility class for easy construction and manipulation of embeds.\n\n```js\n// at the top of your file\nconst { EmbedBuilder } = require('discord.js');\n\n// inside a command, event listener, etc.\nconst exampleEmbed = new EmbedBuilder()\n\t.setColor(0x0099ff)\n\t.setTitle('Some title')\n\t.setURL('https://discord.js.org/')\n\t.setAuthor({ name: 'Some name', iconURL: 'https://i.imgur.com/AfFp7pu.png', url: 'https://discord.js.org' })\n\t.setDescription('Some description here')\n\t.setThumbnail('https://i.imgur.com/AfFp7pu.png')\n\t.addFields(\n\t\t{ name: 'Regular field title', value: 'Some value here' },\n\t\t{ name: '\\u200B', value: '\\u200B' },\n\t\t{ name: 'Inline field title', value: 'Some value here', inline: true },\n\t\t{ name: 'Inline field title', value: 'Some value here', inline: true },\n\t)\n\t.addFields({ name: 'Inline field title', value: 'Some value here', inline: true })\n\t.setImage('https://i.imgur.com/AfFp7pu.png')\n\t.setTimestamp()\n\t.setFooter({ text: 'Some footer text here', iconURL: 'https://i.imgur.com/AfFp7pu.png' });\n\nchannel.send({ embeds: [exampleEmbed] });\n```\n\n<Callout>\n\tYou don't need to include all the elements showcased above. If you want a simpler embed, leave some out.\n</Callout>\n\nThe `.setColor()` method accepts a `ColorResolvable`, e.g. an integer, HEX color string, an array of RGB values or specific color strings.\n\nTo add a blank field to the embed, you can use `.addFields({ name: '\\u200b', value: '\\u200b' })`.\n\nThe above example chains the manipulating methods to the newly created EmbedBuilder object.\nIf you want to modify the embed based on conditions, you will need to reference it as the constant `exampleEmbed` (for our example).\n\n```js\nconst exampleEmbed = new EmbedBuilder().setTitle('Some title');\n\nif (message.author.bot) {\n\texampleEmbed.setColor(0x7289da);\n}\n```\n\n## Using an embed object\n\n```js\nconst exampleEmbed = {\n\tcolor: 0x0099ff,\n\ttitle: 'Some title',\n\turl: 'https://discord.js.org',\n\tauthor: {\n\t\tname: 'Some name',\n\t\ticon_url: 'https://i.imgur.com/AfFp7pu.png',\n\t\turl: 'https://discord.js.org',\n\t},\n\tdescription: 'Some description here',\n\tthumbnail: {\n\t\turl: 'https://i.imgur.com/AfFp7pu.png',\n\t},\n\tfields: [\n\t\t{\n\t\t\tname: 'Regular field title',\n\t\t\tvalue: 'Some value here',\n\t\t},\n\t\t{\n\t\t\tname: '\\u200b',\n\t\t\tvalue: '\\u200b',\n\t\t\tinline: false,\n\t\t},\n\t\t{\n\t\t\tname: 'Inline field title',\n\t\t\tvalue: 'Some value here',\n\t\t\tinline: true,\n\t\t},\n\t\t{\n\t\t\tname: 'Inline field title',\n\t\t\tvalue: 'Some value here',\n\t\t\tinline: true,\n\t\t},\n\t\t{\n\t\t\tname: 'Inline field title',\n\t\t\tvalue: 'Some value here',\n\t\t\tinline: true,\n\t\t},\n\t],\n\timage: {\n\t\turl: 'https://i.imgur.com/AfFp7pu.png',\n\t},\n\ttimestamp: new Date().toISOString(),\n\tfooter: {\n\t\ttext: 'Some footer text here',\n\t\ticon_url: 'https://i.imgur.com/AfFp7pu.png',\n\t},\n};\n\nchannel.send({ embeds: [exampleEmbed] });\n```\n\n<Callout>\n\tYou don't need to include all the elements showcased above. If you want a simpler embed, leave some out.\n</Callout>\n\nIf you want to modify the embed object based on conditions, you will need to reference it directly (as `exampleEmbed` for our example). You can then (re)assign the property values as you would with any other object.\n\n```js\nconst exampleEmbed = { title: 'Some title' };\n\nif (message.author.bot) {\n\texampleEmbed.color = 0x7289da;\n}\n```\n\n## Attaching images\n\nYou can upload images with your embedded message and use them as source for embed fields that support image URLs by constructing a `AttachmentBuilder` from them to send as message option alongside the embed. The attachment parameter takes a BufferResolvable or Stream including the URL to an external image.\n\nYou can then reference and use the images inside the embed itself with `attachment://fileName.extension`.\n\n<Callout>\n\tIf you plan to attach the same image repeatedly, **consider hosting it online and providing the URL** in the\n\trespective embed field instead. This also makes your bot respond faster since it doesn't need to upload the image with\n\tevery response depending on it.\n</Callout>\n\n### Using the EmbedBuilder\n\n```js\nconst { AttachmentBuilder, EmbedBuilder } = require('discord.js');\n// ...\nconst file = new AttachmentBuilder('../assets/discordjs.png');\nconst exampleEmbed = new EmbedBuilder().setTitle('Some title').setImage('attachment://discordjs.png');\n\nchannel.send({ embeds: [exampleEmbed], files: [file] });\n```\n\n### Using an embed object\n\n```js\nconst { AttachmentBuilder } = require('discord.js');\n// ...\nconst file = new AttachmentBuilder('../assets/discordjs.png');\n\nconst exampleEmbed = {\n\ttitle: 'Some title',\n\timage: {\n\t\turl: 'attachment://discordjs.png',\n\t},\n};\n\nchannel.send({ embeds: [exampleEmbed], files: [file] });\n```\n\n<Callout type=\"warn\">\n\tIf the images don't display inside the embed but outside of it, double-check your syntax to make sure it's as shown\n\tabove.\n</Callout>\n\n## Resending and editing\n\nWe will now explain how to edit embedded message content and resend a received embed.\n\n### Resending a received embed\n\nTo forward a received embed you retrieve it from the messages embed array (`message.embeds`) and pass it to the EmbedBuilder, then it can be edited before sending it again.\n\n<Callout>\n\tWe create a new Embed from `EmbedBuilder` here since embeds are immutable (their values cannot be changed directly).\n</Callout>\n\n```js\nconst receivedEmbed = message.embeds[0];\nconst exampleEmbed = EmbedBuilder.from(receivedEmbed).setTitle('New title');\n\nchannel.send({ embeds: [exampleEmbed] });\n```\n\n### Editing the embedded message content\n\nTo edit the content of an embed you need to pass a new EmbedBuilder structure or embed object to the messages `.edit()` method.\n\n```js\nconst exampleEmbed = new EmbedBuilder().setTitle('Some title').setDescription('Description after the edit');\n\nmessage.edit({ embeds: [exampleEmbed] });\n```\n\nIf you want to build the new embed data on a previously sent embed template, make sure to read the caveats in the previous section.\n\n## Notes\n\n- To display fields side-by-side, you need at least two consecutive fields set to `inline`\n- The timestamp will automatically adjust the timezone depending on the user's device\n- Mentions of any kind in embeds will only render correctly within embed descriptions and field values\n- Mentions in embeds will not trigger a notification\n- Embeds allow masked links (e.g. `[Guide](https://discordjs.guide/ 'optional hovertext')`), but only in description and field values\n- Discord may strip characters from message content. See [the documentation](https://discord.com/developers/docs/resources/message#create-message) for more information\n\n## Embed limits\n\nThere are a few limits to be aware of while planning your embeds due to the API's limitations. Here is a quick reference you can come back to:\n\n- Embed titles are limited to **256** characters\n- Embed descriptions are limited to **4096** characters\n- There can be up to **25** fields\n- A field's name is limited to **256** characters and its value to 1024 characters\n- The footer text is limited to **2048** characters\n- The author name is limited to **256** characters\n- The sum of all characters from all embed structures in a message must not exceed **6000** characters\n- **10** embeds can be sent per message\n\nSource: [Discord API documentation](https://discord.com/developers/docs/resources/message#embed-object-embed-limits)\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/errors.mdx",
    "content": "---\ntitle: Common Errors\n---\n\nThere is no doubt that you have encountered errors while making bots. While errors are instrumental at warning you of what is going wrong, many people are stumped by them and how to track them down and fix them, but don't worry, we have you covered. This section will be all about diagnosing errors, identifying where they are coming from, and fixing them.\n\n## Types of Errors\n\n### API Errors\n\nAPI Errors or DiscordAPIErrors are thrown by the Discord API when an invalid request carries out. API Errors can be mostly diagnosed using the message that is given. You can further examine errors by inspecting the HTTP method and path used. We will explore tracking these errors down in the next section.\n\nExample: `DiscordAPIError: Cannot send an empty message`\n\n### discord.js errors\n\ndiscord.js errors are thrown by the library itself. They can usually be easily tracked down using the stack trace and error message.\n\nExample: `The messages must be an Array, Collection, or number.`\n\n### JavaScript errors\n\nJavaScript errors are thrown by node itself or by discord.js. These errors can easily be fixed by looking at the type of error and the stack trace. You can find a full list of types [here](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error) and a list of common JavaScript errors [here](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors).\n\nExamples:\n\n- `ReferenceError: \"x\" is not defined`\n- `Cannot read properties of null (reading 'something')`\n\n### WebSocket and Network errors\n\nWebSocket and Network errors are common system errors thrown by Node in response to something wrong with the WebSocket connection. Unfortunately, these errors do not have a concrete solution and can be (usually) fixed by getting a better, more stable, and more robust connection. discord.js will automatically try to reconnect to the WebSocket if an error occurs.\n\nIn version 12, WebSocket errors are handled internally, meaning your process should never crash from them. If you want to log these errors, should they happen, you can listen to the `shardError` event as shown below.\n\n```js\nclient.on(Events.ShardError, (error) => {\n\tconsole.error('A websocket connection encountered an error:', error);\n});\n```\n\nThe commonly thrown codes for these errors are:\n\n- `ECONNRESET` - The connection was forcibly closed by a peer, thrown by the loss of connection to a WebSocket due to timeout or reboot.\n- `ETIMEDOUT` - A connect or send request failed because the receiving party did not respond after some time.\n- `EPIPE` - The remote side of the stream being written to has been closed.\n- `ENOTFOUND` - The domain being accessed is unavailable, usually caused by a lack of internet, can be thrown by the WebSocket and HTTP API.\n- `ECONNREFUSED` - The target machine refused the connection; check your ports and firewall.\n\n## How to diagnose API errors\n\nAPI Errors can be tracked down by adding an event listener for unhandled rejections and looking at the extra info.\nThis can be done by adding this to your main file.\n\n```js\nprocess.on('unhandledRejection', (error) => {\n\tconsole.error('Unhandled promise rejection:', error);\n});\n```\n\nThe next time you get the error it will show info along the bottom of the error which will look something like this for example:\n\n```json\n  name: 'DiscordAPIError',\n  message: 'Invalid Form Body\\nmessage_id: Value \"[object Object]\" is not snowflake.',\n  path: '/api/v10/channels/638200642359525387/messages/[object%20Object]',\n  code: 50035,\n  method: 'GET'\n```\n\nAll of this information can help you track down what caused the error and how to fix it. In this section, we will run through what each property means.\n\n### Message\n\nThe most important part of the error is the message. It tells you what went wrong, which can help you track down where it originates.\nYou can find a full list of messages [here](https://discord.com/developers/docs/topics/opcodes-and-status-codes#json) in the Discord API documentation.\n\n### Path\n\nAnother helpful piece of information is the path, which tells you what API endpoint the error occurred on. We cannot possibly cover all endpoints, but they are usually very descriptive.\n\nIn the above example, the path tells you that the action was executed in the `/channels/` scope. The number you see next is the channel's id. Next, you can spot the `message/` scope. The number is again the object's id. Combined with the method `GET` you can conclude, that the bot tried to fetch the message with the id `[object Object]` from the channel with the id `638200642359525387`.\n\nAs the error message tells you `[object Object]` is not a valid id, so you now know where to look for an error! Find out where you pass an object as an id when trying to fetch a message and fix your code in that location.\n\n### Code\n\nThe code is another partial representation of the message, in this case, `Invalid Form Body`. You can find a full list of codes [here](https://discord.com/developers/docs/topics/opcodes-and-status-codes#json-json-error-codes)\n\nThe code is also handy if you want only to handle a specific error. Say you're trying to delete a message which may or may not be there, and wanted to ignore unknown message errors. This can be done by checking the code, either manually or using discord.js constants.\n\n```js\nmessage.delete().catch((error) => {\n\t// Only log the error if it is not an Unknown Message error\n\tif (error.code !== 10_008) {\n\t\tconsole.error('Failed to delete the message:', error);\n\t}\n});\n```\n\nOr using Constants:\n\n```js\nconst { RESTJSONErrorCodes } = require('discord.js');\n\nmessage.delete().catch((error) => {\n\tif (error.code !== RESTJSONErrorCodes.UnknownMessage) {\n\t\tconsole.error('Failed to delete the message:', error);\n\t}\n});\n```\n\nYou can find a list of constants [here](https://discord-api-types.dev/api/discord-api-types-v10/enum/RESTJSONErrorCodes).\n\n### Method\n\nThe final piece of information can tell you a lot about what you tried to do to the path. There are a set of predefined keywords that describe our actions on the path.\n\n```\nGET    - Used to retrieve a piece of data\nPOST   - Used to send a piece of data\nPATCH  - Used to modify a piece of data\nPUT    - Used to replace a piece of data completely\nDELETE - Used to delete a piece of data completely\n```\n\nIn this particular example, you can see you are trying to access a piece of data, specifically, a message.\n\n## Common discord.js and API errors\n\n### An invalid token was provided.\n\nThis is a prevalent error; it originates from a wrong token being passed into `client.login()`. The most common causes of this error are:\n\n- Not importing the config or env file correctly\n- Copying the client secret instead of the bot token (the token is alphanumerical and three parts delimited by a period while the client secret is significantly smaller and one part only)\n- Not updating the token after resetting it\n\n<Callout>\n\t**Before** the release of **version 12**, there used to be an issue where the token was not prefixed correctly, which\n\tresulted in valid tokens being marked as invalid. If you have verified that all of the above is not the case, make\n\tsure you have updated discord.js to the current stable version.\n</Callout>\n\n### Request to use token, but token was unavailable to the client.\n\nThis error originates from the client attempting to execute an action that requires the token but the token not being available. This is most commonly caused by destroying the client and then trying to perform an action.\n\nThis error is also caused by attempting to use a client that has not logged in. Both of the examples below will throw errors.\n\n```js\nconst { Client, GatewayIntentBits } = require('discord.js');\n\n// Should not be here!\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\nmodule.exports = (interaction) => {\n\tconst id = interaction.options.getString('id');\n\t// Should be `interaction.client` instead!\n\tclient.users.fetch(id).then((user) => {\n\t\tinteraction.reply(`Your requested user: ${user.tag}`);\n\t});\n};\n```\n\n```js\nconst { Client, Events, GatewayIntentBits } = require('discord.js');\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\nclient.on(Events.InteractionCreate, someHandlerFunction);\n\nclient.login('your-token-goes-here');\n// client will not be logged in yet!\nclient.users.fetch('myId').then(someInitFunction);\n```\n\n### EmbedBuilder field values may not be empty.\n\nThis error originates from calling `EmbedBuilder#addFields()` with a field object's `name` property as an empty string. If you would like the title to be empty for a reason, you should use a zero width space, which can be input as `\\u200b`.\n\nIn conjunction with the previous error, this error results from calling `EmbedBuilder#addFields()` with a field object's `value` property as an empty string. You can use a zero-width space if you would like this blank.\n\n### The messages must be an Array, Collection, or number.\n\nThis error originates from an invalid call to `bulkDelete()`. Make sure you are inputting a valid Array or Collection of messages or a valid number.\n\n### Members didn't arrive in time.\n\nThis error happens when fetching multiple members via `GuildMemberManager#fetch()` and:\n\n- The `GuildMembers` intent is not specified or enabled in the [developer portal](https://discord.com/developers/applications).\n- The internet connection is somewhat bad.\n\nYou can specify the time to wait for with the `time` option in the `.fetch()` call. Another solution could be to move your bot to a faster infrastructure, if available.\n\n### Request with opcode 8 was rate limited.\n\nYou are requesting all guild members too frequently on the same guild.\n\n- Look for instances of `GuildMemberManager#fetch()` that do not specify users.\n- Make sure to handle the returned promise gracefully. Discord may change the exact values of this rate limit in the future. You can find all relevant details in the caught error.\n\n### MaxListenersExceededWarning: Possible EventEmitter memory leak detected...\n\nThis error is caused by spawning a large number of event listeners, usually for the client. The most common cause of this is nesting your event listeners instead of separating them. The way to fix this error is to make sure you do not nest your listeners; it is **not** to use `emitter.setMaxListeners()` as the error suggests.\n\nYou can debug these messages in different ways:\n\n- Through the [CLI](https://nodejs.org/api/cli.html#cli_trace_warnings): `node --trace-warnings index.js`\n- Through the [`process#warning` event](https://nodejs.org/api/process.html#process_event_warning): `process.on('warning', console.warn);`\n\n### Cannot send messages to this user.\n\nThis error throws when the bot attempts to send a DM message to a user but cannot do so. A variety of reasons causes this:\n\n- The bot and the user do not share a guild (often, people attempt to DM the user after kicking or banning them).\n- The bot tries to DM another bot.\n- The user has blocked the bot.\n- The user has disabled DMs in the privacy settings.\n\nIn the case of the last two reasons, the error is not preventable, as the Discord API does not provide a way to check if you can send a user a DM until you attempt to send one. The best way to handle this error is to add a `.catch()` where you try to DM the user and either ignore the rejected Promise or do what you want because of it.\n\n## Common miscellaneous errors\n\n### code ENOENT... syscall spawn git.\n\nThis error is commonly thrown by your system due to it not finding `git`. You need to install `git` or update your path if `git` is already installed. Here are the download links for it:\n\n- Ubuntu/Debian: `sudo apt-get install git`\n- Windows: [git-scm](https://git-scm.com/download/win)\n\n### code ELIFECYCLE\n\nThis error is commonly thrown by your system in response to the process unexpectedly closing. Cleaning the npm cache and deleting node_modules can usually fix it. The instructions for doing that are as such:\n\n- Clean npm cache with `npm cache clean --force`\n- delete `node_modules`\n- delete `package-lock.json` (make sure you have a `package.json`!)\n- run `npm install` to reinstall packages from `package.json`\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/faq.mdx",
    "content": "---\ntitle: FAQ\n---\n\n# Frequently asked Questions\n\n## Legend\n\n- `client` is a placeholder for the `Client` object, such as `const client = new Client({ intents: [GatewayIntentBits.Guilds] });`.\n- `interaction` is a placeholder for the `BaseInteraction` object, such as `client.on(Events.InteractionCreate, interaction => { ... });`.\n- `guild` is a placeholder for the `Guild` object, such as `interaction.guild` or `client.guilds.cache.get('id')`.\n- `voiceChannel` is a placeholder for the `VoiceChannel` object, such as `interaction.member.voice.channel`\n\nFor a more detailed explanation of the notations commonly used in this guide, the docs, and the support server, see [here](../additional-info/notation).\n\n## Administrative\n\n### How do I ban a user?\n\n```js\nconst user = interaction.options.getUser('target');\nguild.members.ban(user);\n```\n\n### How do I unban a user?\n\n```js\nconst user = interaction.options.getUser('target');\nguild.members.unban(user);\n```\n\n<Callout>\n\tDiscord **validates** and **resolves** user ids for users not on the server in user slash command options. To retrieve\n\tand use the full structure from the resulting interaction, you can use the `CommandInteractionOptionResolver#getUser`\n\tmethod.\n</Callout>\n\n### How do I kick a guild member?\n\n```js\nconst member = interaction.options.getMember('target');\nmember.kick();\n```\n\n### How do I timeout a guild member?\n\n```js\nconst member = interaction.options.getMember('target');\nmember.timeout(60_000); // Timeout for one minute\n```\n\n<Callout>\n\tTimeout durations are measured by the **millisecond**. The maximum timeout duration you can set is 28 days. To remove\n\ta timeout set on a member, pass `null` instead of a timeout duration.\n</Callout>\n\n### How do I add a role to a guild member?\n\n```js\nconst role = interaction.options.getRole('role');\nconst member = interaction.options.getMember('target');\nmember.roles.add(role);\n```\n\n### How do I check if a guild member has a specific role?\n\n```js\nconst member = interaction.options.getMember('target');\nif (member.roles.cache.some((role) => role.name === 'role name')) {\n\t// ...\n}\n```\n\n### How do I limit a command to a single user?\n\n```js\nif (interaction.user.id === 'id') {\n\t// ...\n}\n```\n\n## Bot Configuration and Utility\n\n### How do I set my bot's username?\n\n```js\nclient.user.setUsername('username');\n```\n\n### How do I set my bot's avatar?\n\n```js\nclient.user.setAvatar('URL or path');\n```\n\n### How do I set my playing status?\n\n```js\nclient.user.setActivity('activity');\n```\n\n### How do I set my status to \"Watching/Listening to/Competing in ...\"?\n\n```js\nconst { ActivityType } = require('discord.js');\n\nclient.user.setActivity('activity', { type: ActivityType.Watching });\nclient.user.setActivity('activity', { type: ActivityType.Listening });\nclient.user.setActivity('activity', { type: ActivityType.Competing });\n```\n\n<Callout>\n\tIf you would like to set your activity upon startup, you can use the `ClientOptions` object to set the appropriate\n\t`Presence` data.\n</Callout>\n\n### How do I make my bot display online/idle/dnd/invisible?\n\n```js\nconst { PresenceUpdateStatus } = require('discord.js');\n\nclient.user.setStatus(PresenceUpdateStatus.Online);\nclient.user.setStatus(PresenceUpdateStatus.Idle);\nclient.user.setStatus(PresenceUpdateStatus.DoNotDisturb);\nclient.user.setStatus(PresenceUpdateStatus.Invisible);\n```\n\n### How do I set both status and activity in one go?\n\n```js\nconst { PresenceUpdateStatus } = require('discord.js');\n\nclient.user.setPresence({ activities: [{ name: 'activity' }], status: PresenceUpdateStatus.Idle });\n```\n\n## Miscellaneous\n\n### How do I send a message to a specific channel?\n\n```js\nconst channel = client.channels.cache.get('id');\nchannel.send('content');\n```\n\n### How do I create a post in a forum channel?\n\n<Callout>Currently, the only way to get tag ids is programmatically through `ForumChannel#availableTags`.</Callout>\n\n```js\nconst channel = client.channels.cache.get('id');\nchannel.threads.create({\n\tname: 'Post name',\n\tmessage: { content: 'Message content' },\n\tappliedTags: ['tagID', 'anotherTagID'],\n});\n```\n\n### How do I DM a specific user?\n\n```js\nclient.users.send('id', 'content');\n```\n\n<Callout>If you want to DM the user who sent the interaction, you can use `interaction.user.send()`.</Callout>\n\n### How do I mention a specific user in a message?\n\n```js\nconst user = interaction.options.getUser('target');\nawait interaction.reply(`Hi, ${user}.`);\nawait interaction.followUp(`Hi, <@${user.id}>.`);\n```\n\n<Callout>\n\tMentions in embeds may resolve correctly in embed titles, descriptions and field values but will never notify the\n\tuser. Other areas do not support mentions at all.\n</Callout>\n\n### How do I control which users and/or roles are mentioned in a message?\n\nControlling which mentions will send a ping is done via the `allowedMentions` option, which replaces `disableMentions`.\n\nThis can be set as a default in `ClientOptions`, and controlled per-message sent by your bot.\n\n```js\nnew Client({ allowedMentions: { parse: ['users', 'roles'] } });\n```\n\nEven more control can be achieved by listing specific `users` or `roles` to be mentioned by ID, e.g.:\n\n```js\nchannel.send({\n\tcontent: '<@123456789012345678> <@987654321098765432> <@&102938475665748392>',\n\tallowedMentions: { users: ['123456789012345678'], roles: ['102938475665748392'] },\n});\n```\n\n### How do I prompt the user for additional input?\n\n```js\ninteraction.reply('Please enter more input.').then(() => {\n\tconst collectorFilter = (m) => interaction.user.id === m.author.id;\n\n\tinteraction.channel\n\t\t.awaitMessages({ filter: collectorFilter, time: 60_000, max: 1, errors: ['time'] })\n\t\t.then((messages) => {\n\t\t\tinteraction.followUp(`You've entered: ${messages.first().content}`);\n\t\t})\n\t\t.catch(() => {\n\t\t\tinteraction.followUp('You did not enter any input!');\n\t\t});\n});\n```\n\n<Callout>\n\tIf you want to learn more about this syntax or other types of collectors, check out [this dedicated guide page for\n\tcollectors](./collectors)!\n</Callout>\n\n### How do I block a user from using my bot?\n\n```js\nconst blockedUsers = ['id1', 'id2'];\nclient.on(Events.InteractionCreate, (interaction) => {\n\tif (blockedUsers.includes(interaction.user.id)) return;\n});\n```\n\n<Callout>\nYou do not need to have a constant local variable like `blockedUsers` above. If you have a database system that you use to store IDs of blocked users, you can query the database instead:\n\n```js\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tconst blockedUsers = await database.query('SELECT user_id FROM blocked_users;');\n\tif (blockedUsers.includes(interaction.user.id)) return;\n});\n```\n\nNote that this is just a showcase of how you could do such a check.\n\n</Callout>\n\n### How do I react to the message my bot sent?\n\n```js\ninteraction.channel.send('My message to react to.').then((sentMessage) => {\n\t// Unicode emoji\n\tsentMessage.react('👍');\n\n\t// Custom emoji\n\tsentMessage.react('123456789012345678');\n\tsentMessage.react('<emoji:123456789012345678>');\n\tsentMessage.react('<a:emoji:123456789012345678>');\n\tsentMessage.react('emoji:123456789012345678');\n\tsentMessage.react('a:emoji:123456789012345678');\n});\n```\n\n<Callout>\n\tIf you want to learn more about reactions, check out [this dedicated guide on reactions](./reactions)!\n</Callout>\n\n### How do I restart my bot with a command?\n\n```js\nprocess.exit();\n```\n\n<Callout type=\"error\">\n\t`process.exit()` will only kill your Node process, but when using [PM2](http://pm2.keymetrics.io/), it will restart\n\tthe process whenever it gets killed. You can read our guide on PM2 [here](../improving-dev-environment/pm2).\n</Callout>\n\n### What is the difference between a User and a GuildMember?\n\nA User represents a global Discord user, and a GuildMember represents a Discord user on a specific server. That means only GuildMembers can have permissions, roles, and nicknames, for example, because all of these things are server-bound information that could be different on each server that the user is in.\n\n### How do I find all online members of a guild?\n\n```js\n// First use guild.members.fetch to make sure all members are cached\nguild.members.fetch({ withPresences: true }).then((fetchedMembers) => {\n\tconst totalOnline = fetchedMembers.filter((member) => member.presence?.status === PresenceUpdateStatus.Online);\n\t// Now you have a collection with all online member objects in the totalOnline variable\n\tconsole.log(`There are currently ${totalOnline.size} members online in this guild!`);\n});\n```\n\n<Callout type=\"warn\">\n\tThis only works correctly if you have the `GuildPresences` intent enabled for your application and client. If you want\n\tto learn more about intents, check out [this dedicated guide on intents](./intents)!\n</Callout>\n\n### How do I check which role was added/removed and for which member?\n\n```js\n// Start by declaring a guildMemberUpdate listener\n// This code should be placed outside of any other listener callbacks to prevent listener nesting\nclient.on(Events.GuildMemberUpdate, (oldMember, newMember) => {\n\t// If the role(s) are present on the old member object but no longer on the new one (i.e role(s) were removed)\n\tconst removedRoles = oldMember.roles.cache.filter((role) => !newMember.roles.cache.has(role.id));\n\tif (removedRoles.size > 0) {\n\t\tconsole.log(`The roles ${removedRoles.map((r) => r.name)} were removed from ${oldMember.displayName}.`);\n\t}\n\n\t// If the role(s) are present on the new member object but are not on the old one (i.e role(s) were added)\n\tconst addedRoles = newMember.roles.cache.filter((role) => !oldMember.roles.cache.has(role.id));\n\tif (addedRoles.size > 0) {\n\t\tconsole.log(`The roles ${addedRoles.map((r) => r.name)} were added to ${oldMember.displayName}.`);\n\t}\n});\n```\n\n### How do I check the bot's ping?\n\nThere are two common measurements for bot pings. The first, **websocket heartbeat**, is the average interval of a regularly sent signal indicating the healthy operation of the websocket connection the library receives events over:\n\n```js\ninteraction.reply(`Websocket heartbeat: ${client.ws.ping}ms.`);\n```\n\n<Callout>\n\tIf you're using [sharding](../sharding/), a specific shard's heartbeat can be found on the WebSocketShard instance,\n\taccessible at `client.ws.shards.get(id).ping`.\n</Callout>\n\nThe second, **Roundtrip Latency**, describes the amount of time a full API roundtrip (from the creation of the command message to the creation of the response message) takes. You then edit the response to the respective value to avoid needing to send yet another message:\n\n```js\nconst sent = await interaction.reply({ content: 'Pinging...', withResponse: true });\ninteraction.editReply(`Roundtrip latency: ${sent.resource.message.createdTimestamp - interaction.createdTimestamp}ms`);\n```\n\n### Why do some emojis behave weirdly?\n\nIf you've tried using [the usual method of retrieving unicode emojis](./reactions#unicode-emojis), you may have noticed that some characters don't provide the expected results. Here's a short snippet that'll help with that issue. You can toss this into a file of its own and use it anywhere you need! Alternatively feel free to simply copy-paste the characters from below:\n\n```js\n// emojiCharacters.js\nmodule.exports = {\n\ta: '🇦',\n\tb: '🇧',\n\tc: '🇨',\n\td: '🇩',\n\te: '🇪',\n\tf: '🇫',\n\tg: '🇬',\n\th: '🇭',\n\ti: '🇮',\n\tj: '🇯',\n\tk: '🇰',\n\tl: '🇱',\n\tm: '🇲',\n\tn: '🇳',\n\to: '🇴',\n\tp: '🇵',\n\tq: '🇶',\n\tr: '🇷',\n\ts: '🇸',\n\tt: '🇹',\n\tu: '🇺',\n\tv: '🇻',\n\tw: '🇼',\n\tx: '🇽',\n\ty: '🇾',\n\tz: '🇿',\n\t0: '0️⃣',\n\t1: '1️⃣',\n\t2: '2️⃣',\n\t3: '3️⃣',\n\t4: '4️⃣',\n\t5: '5️⃣',\n\t6: '6️⃣',\n\t7: '7️⃣',\n\t8: '8️⃣',\n\t9: '9️⃣',\n\t10: '🔟',\n\t'#': '#️⃣',\n\t'*': '*️⃣',\n\t'!': '❗',\n\t'?': '❓',\n};\n```\n\n```js\n// index.js\nconst emojiCharacters = require('./emojiCharacters.js');\n\nconsole.log(emojiCharacters.a); // 🇦\nconsole.log(emojiCharacters[10]); // 🔟\nconsole.log(emojiCharacters['!']); // ❗\n```\n\n<Callout>\n\tOn Windows, you may be able to use the <kbd>Win</kbd> <kbd>.</kbd> keyboard shortcut to open up an emoji picker that can be used for quick, easy access to all the Unicode emojis available to you. Some of the emojis listed above may not be represented there, though (e.g., the 0-9 emojis).\n\n    You can also use the <kbd>⌃</kbd> <kbd>⌘</kbd> <kbd>Space</kbd> keyboard shortcut to perform the same behavior on macOS.\n\n</Callout>\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/formatters.mdx",
    "content": "---\ntitle: Formatters\n---\n\ndiscord.js provides the `formatters` package which contains a variety of utilities you can use when writing your Discord bot.\n\n## Basic Markdown\n\nThese functions format strings into all the different Markdown styles supported by Discord.\n\n```js\nconst { blockQuote, bold, italic, quote, spoiler, strikethrough, underline, subtext } = require('discord.js');\nconst string = 'Hello!';\n\nconst boldString = bold(string);\nconst italicString = italic(string);\nconst strikethroughString = strikethrough(string);\nconst underlineString = underline(string);\nconst spoilerString = spoiler(string);\nconst quoteString = quote(string);\nconst blockquoteString = blockQuote(string);\nconst subtextString = subtext(string);\n```\n\n## Links\n\nThere are also two functions to format hyperlinks. `hyperlink()` will format the URL into a masked markdown link, and `hideLinkEmbed()` will wrap the URL in `<>`, preventing it from embedding.\n\n```js\nconst { hyperlink, hideLinkEmbed } = require('discord.js');\nconst url = 'https://discord.js.org/';\n\nconst link = hyperlink('discord.js', url);\nconst hiddenEmbed = hideLinkEmbed(url);\n```\n\n## Code blocks\n\nYou can use `inlineCode()` and `codeBlock()` to turn a string into an inline code block or a regular code block with or without syntax highlighting.\n\n```js\nconst { inlineCode, codeBlock } = require('discord.js');\nconst jsString = 'const value = true;';\n\nconst inline = inlineCode(jsString);\nconst codeblock = codeBlock(jsString);\nconst highlighted = codeBlock('js', jsString);\n```\n\n## Timestamps\n\nWith `time()`, you can format Unix timestamps and dates into a Discord time string.\n\n```js\nconst { time, TimestampStyles } = require('discord.js');\nconst date = new Date();\n\nconst timeString = time(date);\nconst relative = time(date, TimestampStyles.RelativeTime);\n```\n\n## Mentions\n\n`userMention()`, `channelMention()`, and `roleMention()` all exist to format Snowflakes into mentions.\n\n```js\nconst { channelMention, roleMention, userMention } = require('discord.js');\nconst id = '123456789012345678';\n\nconst channel = channelMention(id);\nconst role = roleMention(id);\nconst user = userMention(id);\n```\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/intents.mdx",
    "content": "---\ntitle: Gateway Intents\n---\n\nGateway Intents were introduced by Discord so bot developers can choose which events their bot receives based on which data it needs to function. Intents are named groups of pre-defined WebSocket events, which the discord.js client will receive. If you omit `DirectMessageTyping`, for example, you will no longer receive typing events from direct messages. If you do not specify intents, discord.js will throw an error.\n\nRather than blindly enabling all intents, consider what information you actually need. Reducing the number of unnecessary events your bot receives improves performance and reduces bandwidth and memory usage.\n\n## Privileged Intents\n\nDiscord defines some intents as \"privileged\" due to the data's sensitive nature. At the time of writing this article, privileged intents are `GuildPresences`, `MessageContent` and `GuildMembers`. If your bot is not verified and in less than 100 guilds, you can enable privileged gateway intents in the [Discord Developer Portal](https://discord.com/developers/applications) under \"Privileged Gateway Intents\" in the \"Bot\" section. If your bot is already verified or is about to [require verification](https://support-dev.discord.com/hc/articles/23926564536471), you need to request privileged intents. You can do this in your verification application or by reaching out to Discord's [support team](https://dis.gd/contact), including why you require access to each privileged intent.\n\nBefore storming off and doing so, you should stop and carefully think about if you need these events. Discord made them opt-in so users across the platform can enjoy a higher level of [privacy](https://en.wikipedia.org/wiki/Privacy_by_design). Presences can expose quite a bit of personal information, including the games being played and overall online time. You might find that it isn't necessary for your bot to have this level of information about all guild members at all times, considering you still get the command author as GuildMember from the command execution message and can fetch other targets separately.\n\n### Error: Disallowed Intents\n\nShould you receive an error prefixed with `[DisallowedIntents]`, please review your developer dashboard settings for all privileged intents you use. Check on the [Discord API documentation](https://discord.com/developers/docs/topics/gateway#privileged-intents) for up to date information.\n\n## Enabling Intents\n\nTo specify which events you want your bot to receive, first think about which events your bot needs to operate. Then select the required intents and add them to your client constructor, as shown below.\n\nYou can find the list of all current gateway intents and the events belonging to each on the [Discord API documentation](https://discord.com/developers/docs/topics/gateway#list-of-intents) and the enum values used in discord.js on the [Discord API types documentation](https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayIntentBits).\n\n- If you need your bot to receive messages (`MESSAGE_CREATE` - `\"messageCreate\"` in discord.js), you need the `Guilds` and `GuildMessages` intent, plus the `MessageContent` privileged intent to receive the `content`, `attachments`, `embeds` and `components` fields of the message.\n- If you want your bot to post welcome messages for new members (`GUILD_MEMBER_ADD` - `\"guildMemberAdd\"` in discord.js), you need the `GuildMembers` privileged intent, and so on.\n\n```js\nconst { Client, GatewayIntentBits } = require('discord.js');\n\nconst client = new Client({\n\tintents: [\n\t\tGatewayIntentBits.Guilds,\n\t\tGatewayIntentBits.GuildMessages,\n\t\tGatewayIntentBits.MessageContent,\n\t\tGatewayIntentBits.GuildMembers,\n\t],\n});\n```\n\n<Callout>\n\tNote that discord.js relies heavily on caching to provide its functionality - this means an internal reliance on\n\tcertain events to ensure the caches are populated and up to date.\n</Callout>\n\nSome methods that seem unrelated might stop working if certain events do not arrive. For example:\n\n- The `Guilds` intent populates and maintains the `guilds`, `channels` and `guild.roles` caches, plus thread-related events. \\\n  If this intent is not enabled, data for interactions and messages will include only the guild and channel id, and will not resolve to the full class.\n- The `GuildMembers` intent keeps cached guild members up to date, including changes to their roles and permissions, nickname etc. \\\n  Note that you still receive full member data with interactions and messages without this intent enabled.\n\nPlease make sure to provide the list of gateway intents and partials you use in your Client constructor when asking for support on our [Discord server](https://discord.gg/djs) or [GitHub repository](https://github.com/discordjs/discord.js).\n\n## The Intents Bitfield\n\ndiscord.js provides the utility structure `IntentsBitField` to simplify the modification of intents bitfields.\n\nYou can use the `.add()` and `.remove()` methods to add or remove flags (Intents string literals representing a certain bit) and modify the bitfield. You can provide single flags as well as an array or bitfield. To use a set of intents as a template you can pass it to the constructor. Note that the empty constructor `new IntentsBitField()` creates an empty Intents instance, representing no intents or the bitfield `0`:\n\n```js\nconst { Client, IntentsBitField } = require('discord.js');\n\nconst myIntents = new IntentsBitField();\nmyIntents.add(IntentsBitField.Flags.GuildPresences, IntentsBitField.Flags.GuildMembers);\n\nconst client = new Client({ intents: myIntents });\n\n// other examples:\nconst otherIntents = new IntentsBitField([IntentsBitField.Flags.Guilds, IntentsBitField.Flags.DirectMessages]);\notherIntents.remove([IntentsBitField.Flags.DirectMessages]);\n```\n\nIf you want to view the built flags you can utilize the `.toArray()`, `.serialize()` methods. The first returns an array of flags represented in this bitfield, the second an object mapping all possible flag values to a boolean, based on their representation in this bitfield.\n\n## More on Bitfields\n\nDiscord Intents and Permissions are stored in a 53-bit integer and calculated using bitwise operations. If you want to dive deeper into what's happening behind the curtains, check the [Wikipedia](https://en.wikipedia.org/wiki/Bit_field) and [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators#binary_bitwise_operators) articles on the topic.\n\nIn discord.js, Permissions and Intents bitfields are represented as either the decimal value of said bit field or its referenced flags. Every position in a permissions bitfield represents one of these flags and its state (either referenced `1` or not referenced `0`).\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/meta.json",
    "content": "{\n\t\"title\": \"Popular Topics\",\n\t\"defaultOpen\": true,\n\t\"pages\": [\n\t\t\"!faq\",\n\t\t\"!display-components\",\n\t\t\"audit-logs\",\n\t\t\"canvas\",\n\t\t\"collectors\",\n\t\t\"errors\",\n\t\t\"formatters\",\n\t\t\"intents\",\n\t\t\"embeds\",\n\t\t\"partials\",\n\t\t\"permissions\",\n\t\t\"permissions-extended\",\n\t\t\"reactions\",\n\t\t\"threads\",\n\t\t\"webhooks\"\n\t]\n}\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/partials.mdx",
    "content": "---\ntitle: Partials\n---\n\nPartial Structures were introduced to the library in version 12 and are optionally received whenever there is insufficient data to emit the client event with a fully intact discord.js structure. They are (as the name suggests) incomplete, and you cannot expect them to have any information besides their ID. All other properties and methods on this object should be considered invalid and defunct. Before this feature, discord.js client events would not emit if one of the necessary structures could not be built with sufficient data to guarantee a fully functional structure. If you do not opt into partials, this is still the case.\n\nOne example leveraging partials is the handling of reactions on uncached messages, which is explained on [this page](./reactions#listening-for-reactions-on-old-messages).\n\nPrior you had to either handle the undocumented `raw` event or fetch the respective messages on startup. The first approach was prone to errors and unexpected internal behavior. The second was not fully fail-proof either, as the messages could still be uncached if cache size was exceeded in busy channels.\n\n## Enabling Partials\n\nAs we said earlier, partials do not have all the information necessary to make them fully functional discord.js structures, so it would not be a good idea to enable the functionality by default. Users should know how to handle them before opting into this feature.\n\nYou choose which structures you want to emit as partials as client options when instantiating your bot client. Available structures are: `User`, `Channel` (only DM channels can be uncached, server channels will always be available), `GuildMember`, `Message`, `Reaction`, `GuildScheduledEvent` and `ThreadMember`.\n\n```js\nconst { Client, Partials } = require('discord.js');\n\nconst client = new Client({ partials: [Partials.Message, Partials.Channel, Partials.Reaction] });\n```\n\n<Callout type=\"warn\">\n\tMake sure you enable all partials you need for your use case! If you miss one, the event does not get emitted.\n</Callout>\n\n<Callout type=\"warn\">\n\tPartial structures are enabled **globally**. You cannot make them work for only a specific event or cache. You very\n\t**likely need to adapt** other parts of your code that are accessing data from the relevant caches. All caches holding\n\tthe respective structure type might return partials as well!\n</Callout>\n\n## Handling Partial data\n\nAll structures you can choose to use partials for have a new property, fittingly called `.partial`, indicating if it is a fully functional or partial instance of its class. The value is `true` if partial, `false` if fully functional.\n\n<Callout type=\"error\">\n\tPartial data is only ever guaranteed to contain an ID! **Do not assume any property or method to work when dealing\n\twith a partial structure**!\n</Callout>\n\n```js\nif (message.partial) {\n\tconsole.log('The message is partial.');\n} else {\n\tconsole.log('The message is not partial.');\n}\n```\n\n## Obtaining the full structure\n\nAlong with `.partial` to check if the structure you call it on is partial or not, the library also introduced a `.fetch()` method to retrieve the missing data from the API and complete the structure. The method returns a [Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) you need to handle. After the Promise resolves (and with it, the missing data arrived), you can use the structure as you would before.\n\n```js\n// [!code word:partial]\nif (message.partial) {\n\tmessage\n\t\t.fetch()\n\t\t.then((fullMessage) => {\n\t\t\tconsole.log(fullMessage.content);\n\t\t})\n\t\t.catch((error) => {\n\t\t\tconsole.log('Something went wrong when fetching the message: ', error);\n\t\t});\n} else {\n\tconsole.log(message.content);\n}\n```\n\n<Callout type=\"warn\">\n\tYou **cannot fetch deleted data** from the API. For message deletions, `messageDelete` will only emit with the ID,\n\twhich you cannot use to fetch the complete message containing content, author, or other information, as it is already\n\tinaccessible by the time you receive the event.\n</Callout>\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/permissions-extended.mdx",
    "content": "---\ntitle: Permissions (extended)\n---\n\n## Discord's permission system\n\nDiscord permissions are stored in a 53-bit integer and calculated using bitwise operations. If you want to dive deeper into what's happening behind the curtains, check the [Wikipedia](https://en.wikipedia.org/wiki/Bit_field) and [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators#binary_bitwise_operators) articles on the topic.\n\nIn discord.js, permission bit fields are represented as either the decimal value of said bit field or its referenced flags.\nEvery position in a permissions bit field represents one of these flags and its state (either referenced `1` or not referenced `0`).\n\nBefore we get into actually assigning permissions, let's quickly go over the method Discord uses to determine a guild member's final permissions:\n\n1. Take all permissions for all roles the guild member has and add them up.\n2. Apply all denies for the default role (`@everyone`).\n3. Apply all allows for the default role (`@everyone`).\n4. Apply all denies for all additional roles the guild member has at once.\n5. Apply all allows for all additional roles the guild member has at once.\n6. Apply all denies for the specific guild member if they exist.\n7. Apply all allows for the specific guild member if they exist.\n\nDue to this system, you cannot deny base permissions. If you grant `SendMessages` to `@everyone` and don't grant it for a muted members role, muted members will still be able to send messages unless you specify channel-based overwrites.\n\nAll additional roles allow overwrites are applied after all additional roles denies! If any of a member's roles have an overwrite to allow a permission explicitly, the member can execute the associated actions in this channel regardless of the role hierarchy.\n\nPlacing an overwrite to allow `SendMessages` on a role will result in members with this role not being mutable via role assignment in this channel.\n\n## Elevated permissions\n\nIf the guild owner enables the server's two-factor authentication option, everyone executing a specific subset of actions will need to have 2FA enabled on their account. As bots do not have 2FA themselves, you, as the application owner, will need to enable it on your account for your bot to work on those servers.\nCheck out [Discord's help article](https://support.discord.com/hc/articles/219576828) if you need assistance with this.\n\nThe permissions assigned to these actions are called \"elevated permissions\" and are:\n`KickMembers`, `BanMembers`, `Administrator`, `ManageChannels`, `ManageGuild`, `ManageMessages`, `ManageRoles`, `ManageWebhooks`, `ManageThreads`, and `ManageGuildExpressions`.\n\n## Implicit permissions\n\nSome Discord permissions apply implicitly based on logical use, which can cause unwanted behavior if you are not aware of this fact.\n\nThe prime example for implicit permissions is `ViewChannel`. If this flag is missing in the final permissions, you can't do anything on that channel. It makes sense, right? If you can't view the channel, you can't read or send messages in it, set the topic, or change its name.\nThe library does not handle implicit permissions for you, so understanding how the system works is vital for you as a bot developer.\n\nLet's say you want to send a message to a channel. To prevent unnecessary API calls, you want to make sure your bot's permissions in this channel include `SendMessages` (more on how to achieve this [here](./permissions#checking-for-permissions)). The check passes, but you still can't send the message and are greeted with `DiscordAPIError: Missing Access`.\n\nThis error means your bot is missing `ViewChannel`, and as such, can't send messages either.\n\nOne possible scenario causing this: the channel has permission overwrites for the default role `@everyone` to grant `SendMessages` so everyone who can see the channel can also write in it, but at the same time has an overwrite to deny `ViewChannel` to make it only accessible to a subset of members.\n\nAs you only check for `SendMessages`, the bot will try to execute the send, but since `ViewChannel` is missing, the API denies the request.\n\n{/* prettier-ignore */}\n<Callout title='Causes for \"Missing Access\"'>\n\t- Text Channels require `ViewChannel` as detailed above.\n\t- Voice Channels require `Connect` in the same way.\n\t- Reacting to a message requires `ReadMessageHistory` in the channel the message was sent.\n\t- When deploying slash commands: Enable the `applications.commands` scope (for more information see the [adding your bot](../preparations/adding-your-app) section).\n\t- Timing out a member requires `ModerateMembers`.\n\t- Editing threads (tags, locking, closing, renaming etc.) requires `SendMessagesInThreads`.\n\t- Adding a member to a thread requires `ViewChannel` in the parent channel for the member being added.\n</Callout>\n\n## Limitations and oddities\n\n- Your bot needs `ManageRoles` in its base permissions to change base permissions.\n- It needs `ManageRoles` in its final permissions to change permission overwrites.\n- It cannot edit permissions for roles that are higher than or equal to its highest role.\n- It cannot grant permissions it doesn't have.\n- It can manage overwrites for roles or users with higher roles than its own highest role.\n- It can manage overwrites for permissions it doesn't have.\n- Members with the `Administrator` permission are not affected by overwrites at all.\n\n## Missing permissions\n\nDuring your development, you will likely run into `DiscordAPIError: Missing Permissions` at some point. One of the following can cause this error:\n\n- Your bot is missing the needed permission to execute this action in its calculated base or final permissions (requirement changes based on the type of action you are trying to perform).\n- You provided an invalid permission number while trying to create overwrites. (The calculator on the apps page returns decimal values while the developer documentation lists the flags in hex. Make sure you are not mixing the two and don't use the hex prefix `0x` where not applicable).\n- Your bot is currently timed out.\n- It is trying to execute an action on a guild member with a role higher than or equal to your bot's highest role.\n- It is trying to modify or assign a role higher than or equal to its highest role.\n- It is trying to add a managed role to a member.\n- It is trying to remove a managed role from a member.\n- It is trying to timeout a member with the `Administrator` permission.\n- It is trying to execute a forbidden action on the server owner.\n- It is trying to execute an action based on another unfulfilled factor (for example, reserved for partnered guilds).\n- It is trying to execute an action on a voice channel without the `ViewChannel` permission.\n- It is trying to create a channel or channel overwrite including the `ManageRoles` flag but does not have the `Administrator` permission or an explicit `ManageRoles` overwrite on this channel (note that the global permission does not count).\n\n<Callout type=\"warn\">Granting the `Administrator` permission does not skip any **hierarchical** check!</Callout>\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/permissions.mdx",
    "content": "---\ntitle: Permissions\n---\n\nPermissions are Discord's primary feature, enabling users to customize their server's workings to their liking.\nEssentially, Permissions and permission overwrites tell Discord who is allowed to do what and where.\nPermissions can be very confusing at first, but this guide is here to explain and clarify them, so let's dive in!\n\n## Roles as bot permissions\n\nIf you want to keep your bot's permission checks simple, you might find it sufficient to check if the member executing the command has a specific role.\n\nIf you have the role ID, you can check if the `.roles` Collection on a GuildMember object includes it, using `.has()`. Should you not know the ID and want to check for something like a \"Mod\" role, you can use `.some()`.\n\n```js\nmember.roles.cache.has('role-id-here');\n// returns true if the member has the role\n\nmember.roles.cache.some((role) => role.name === 'Mod');\n// returns true if any of the member's roles is exactly named \"Mod\"\n```\n\nIf you want to enhance this system slightly, you can include the guild owner by comparing the executing member's ID with `interaction.guild.ownerId`.\n\nTo include permission checks like `Administrator` or `ManageGuild`, keep reading as we will cover Discord Permissions and all their intricacies in the following sections.\n\n## Terminology\n\n- Permission: The ability to execute a certain action in Discord\n- Overwrite: Rule on a channel to modify the permissions for a member or role\n- BitField: Binary representation of Discord permissions\n- Base Permissions: Permissions for roles the member has, set on the guild level\n- Final Permissions: Permissions for a member or role, after all overwrites are applied\n- Flag: Human readable string in PascalCase (e.g., `KickMembers`) that refers to a position in the permission BitField. You can find a list of all valid flags on the `PermissionsBitField#Flags` page\n\n<Callout>\n\tYou can provide permission decimals wherever we use flag literals in this guide. If you are interested in a handy\n\tpermission calculator, you can look at the \"Bot\" section in the [Discord developer\n\tportal](https://discord.com/developers/applications).\n</Callout>\n\n## Base permissions\n\n### Setting role permissions\n\nBase permissions are set on roles, not the guild member itself. To change them, you access a Role object (for example via `member.roles.cache.first()` or `guild.roles.cache.random()`) and use the `.setPermissions()` method. This is how you'd change the base permissions for the `@everyone` role, for example:\n\n```js\nconst { PermissionsBitField } = require('discord.js');\n\nguild.roles.everyone.setPermissions([PermissionsBitField.Flags.SendMessages, PermissionsBitField.Flags.ViewChannel]);\n```\n\nAny permission not referenced in the flag array or bit field is not granted to the role.\n\n<Callout>\n\tNote that flag names are literal. Although `ViewChannel` grants access to view multiple channels, the permission flag\n\tis still called `ViewChannel` in singular form.\n</Callout>\n\n### Creating a role with permissions\n\nAlternatively you can provide permissions as a property of `RoleCreateOptions` during role creation as an array of flag strings or a permission number:\n\n```js\nconst { PermissionsBitField } = require('discord.js');\n\nguild.roles.create({\n\tname: 'Mod',\n\tpermissions: [PermissionsBitField.Flags.SendMessages, PermissionsBitField.Flags.KickMembers],\n});\n```\n\n### Checking member permissions\n\nTo know if one of a member's roles has a permission enabled, you can use the `.has()` method on `GuildMember#permissions` and provide a permission flag, array, or number to check for. You can also specify if you want to allow the `Administrator` permission or the guild owner status to override this check with the following parameters.\n\n```js\nconst { PermissionsBitField } = require('discord.js');\n\nif (member.permissions.has(PermissionsBitField.Flags.KickMembers)) {\n\tconsole.log('This member can kick');\n}\n\nif (member.permissions.has([PermissionsBitField.Flags.KickMembers, PermissionsBitField.Flags.BanMembers])) {\n\tconsole.log('This member can kick and ban');\n}\n\nif (member.permissions.has(PermissionsBitField.Flags.KickMembers, false)) {\n\tconsole.log('This member can kick without allowing admin to override');\n}\n```\n\nIf you provide multiple permissions to the method, it will only return `true` if all permissions you specified are granted.\n\n<Callout>You can learn more about the `.has()` method [here](#checking-for-permissions).</Callout>\n\n## Channel overwrites\n\nPermission overwrites control members' abilities for this specific channel or a set of channels if applied to a category with synchronized child channels.\n\nAs you have likely already seen in your desktop client, channel overwrites have three states:\n\n- Explicit allow (`true`, green ✓)\n- Explicit deny (`false`, red X)\n- Default (`null`, gray /)\n\n### Adding overwrites\n\nTo add a permission overwrite for a role or guild member, you access the channel's `TextChannel#permissionOverwrites` and use the `.create()` method. The first parameter is the target of the overwrite, either a Role or User object (or its respective resolvable), and the second is a `PermissionOverwriteOptions` object.\n\nLet's add an overwrite to lock everyone out of the channel. The guild ID doubles as the role id for the default role `@everyone` as demonstrated below:\n\n```js\nchannel.permissionOverwrites.create(channel.guild.roles.everyone, { ViewChannel: false });\n```\n\nAny permission flags not specified get neither an explicit allow nor deny overwrite and will use the base permission unless another role has an explicit overwrite set.\n\nYou can also provide an array of overwrites during channel creation, as shown below:\n\n```js\nconst { ChannelType, PermissionsBitField } = require('discord.js');\n\nguild.channels.create({\n\tname: 'new-channel',\n\ttype: ChannelType.GuildText,\n\tpermissionOverwrites: [\n\t\t{\n\t\t\tid: interaction.guild.id,\n\t\t\tdeny: [PermissionsBitField.Flags.ViewChannel],\n\t\t},\n\t\t{\n\t\t\tid: interaction.user.id,\n\t\t\tallow: [PermissionsBitField.Flags.ViewChannel],\n\t\t},\n\t],\n});\n```\n\n### Editing overwrites\n\nTo edit permission overwrites on the channel with a provided set of new overwrites, you can use the `.edit()` method.\n\n```js\n// edits overwrites to disallow everyone to view the channel\nchannel.permissionOverwrites.edit(guild.id, { ViewChannel: false });\n\n// edits overwrites to allow a user to view the channel\nchannel.permissionOverwrites.edit(user.id, { ViewChannel: true });\n```\n\n### Replacing overwrites\n\nTo replace all permission overwrites on the channel with a provided set of new overwrites, you can use the `.set()` method. This is extremely handy if you want to copy a channel's full set of overwrites to another one, as this method also allows passing an array or Collection of `PermissionOverwrites`.\n\n```js\nconst { PermissionsBitField } = require('discord.js');\n// copying overwrites from another channel\nchannel.permissionOverwrites.set(otherChannel.permissionOverwrites.cache);\n\n// replacing overwrites with PermissionOverwriteOptions\nchannel.permissionOverwrites.set([\n\t{\n\t\tid: guild.id,\n\t\tdeny: [PermissionsBitField.Flags.ViewChannel],\n\t},\n\t{\n\t\tid: user.id,\n\t\tallow: [PermissionsBitField.Flags.ViewChannel],\n\t},\n]);\n```\n\n### Removing overwrites\n\nTo remove the overwrite for a specific member or role, you can use the `.delete()` method.\n\n```js\n// deleting the channel's overwrite for the user who interacted\nchannel.permissionOverwrites.delete(interaction.user.id);\n```\n\n### Syncing with a category\n\nIf the permission overwrites on a channel under a category match with the parent (category), it is considered synchronized. This means that any changes in the categories overwrites will now also change the channels overwrites. Changing the child channels overwrites will not affect the parent.\n\n<Callout>\n\tThis is indeed all that a \"sync\" in Discord categories means! Users and developers alike commonly misunderstand this\n\tand expect a proper \"sync\" state that applies in both directions.\n</Callout>\n\nTo easily synchronize permissions with the parent channel, you can call the `.lockPermissions()` method on the respective child channel.\n\n```js\nif (!channel.parent) {\n\treturn console.log('This channel is not listed under a category');\n}\n\nchannel\n\t.lockPermissions()\n\t.then(() => console.log('Successfully synchronized permissions with parent channel'))\n\t.catch(console.error);\n```\n\n### Permissions after overwrites\n\nThere are two utility methods to easily determine the final permissions for a guild member or role in a specific channel: `GuildChannel#permissionsFor` and `GuildMember#permissionsIn` - `Role#permissionsIn`. All return a `PermissionsBitField` object.\n\nTo check your bot's permissions in the channel the command was used in, you could use something like this:\n\n```js\n// final permissions for a guild member using permissionsFor\nconst botPermissionsFor = channel.permissionsFor(guild.members.me);\n\n// final permissions for a guild member using permissionsIn\nconst botPermissionsIn = guild.members.me.permissionsIn(channel);\n\n// final permissions for a role\nconst rolePermissions = channel.permissionsFor(role);\n```\n\n<Callout type=\"warn\">\n\tThe `.permissionsFor()` and `.permissionsIn()` methods return a Permissions object with all permissions set if the\n\tmember or role has the global `Administrator` permission and does not take overwrites into consideration in this case.\n\tUsing the second parameter of the `.has()` method as described further down in the guide will not allow you to check\n\twithout taking `Administrator` into account here!\n</Callout>\n\nIf you want to know how to work with the returned Permissions objects, keep reading as this will be our next topic.\n\n## The Permissions object\n\nThe `PermissionsBitField` object is a discord.js class containing a permissions bit field and a bunch of utility methods to manipulate it easily.\nRemember that using these methods will not manipulate permissions, but rather create a new instance representing the changed bit field.\n\n### Displaying permission flags\n\ndiscord.js provides a `toArray()` method, which can be used to convert a `Permissions` object into an array containing permission flags. This is useful if you want to display/list them and it enables you to use other array manipulation methods. For example:\n\n```js\nconst memberPermissions = member.permissions.toArray();\nconst rolePermissions = role.permissions.toArray();\n// output: ['SendMessages', 'AddReactions', 'ChangeNickname', ...]\n```\n\n<Callout>\n\tThe return value of `toArray()` always represents the permission flags present in the Permissions instance that the\n\tmethod was called on. This means that if you call the method on, for example: `PermissionOverwrites#deny`, you will\n\treceive an array of all denied permissions in that overwrite.\n</Callout>\n\nAdditionally, you can serialize the Permissions object's underlying bit field by calling `.serialize()`. This returns an object that maps permission names to a boolean value, indicating whether the relevant \"bit\" is available in the Permissions instance.\n\n```js\nconst memberPermissions = member.permissions.serialize();\nconst rolePermissions = role.permissions.serialize();\n// output: {\n//\tSendMessages: true,\n//\tAddReactions: true,\n//\tBanMembers: false,\n//\t...\n// }\n```\n\n### Converting permission numbers\n\nSome methods and properties in discord.js return permission decimals rather than a Permissions object, making it hard to manipulate or read them if you don't want to use bitwise operations.\nHowever, you can pass these decimals to the Permissions constructor to convert them, as shown below.\n\n```js\nconst { PermissionsBitField } = require('discord.js');\n\nconst permissions = new PermissionsBitField(268_550_160n);\n```\n\nYou can also use this approach for other `PermissionResolvable` like flag arrays or flags.\n\n```js\nconst { PermissionsBitField } = require('discord.js');\n\nconst flags = [\n\tPermissionsBitField.Flags.ViewChannel,\n\tPermissionsBitField.Flags.EmbedLinks,\n\tPermissionsBitField.Flags.AttachFiles,\n\tPermissionsBitField.Flags.ReadMessageHistory,\n\tPermissionsBitField.Flags.ManageRoles,\n];\n\nconst permissions = new PermissionsBitField(flags);\n```\n\n### Checking for permissions\n\nThe Permissions object features the `.has()` method, allowing an easy way to check flags in a Permissions bit field.\nThe `.has()` method takes two parameters: the first being either a permission number, single flag, or an array of permission numbers and flags, the second being a boolean, indicating if you want to allow the `Administrator` permission to override (defaults to `true`).\n\nLet's say you want to know if the decimal bit field representation `268_550_160` has `ManageChannels` referenced:\n\n```js\nconst { PermissionsBitField } = require('discord.js');\n\nconst bitPermissions = new PermissionsBitField(268_550_160n);\n\nconsole.log(bitPermissions.has(PermissionsBitField.Flags.ManageChannels));\n// output: true\n\nconsole.log(bitPermissions.has([PermissionsBitField.Flags.ManageChannels, PermissionsBitField.Flags.EmbedLinks]));\n// output: true\n\nconsole.log(bitPermissions.has([PermissionsBitField.Flags.ManageChannels, PermissionsBitField.Flags.KickMembers]));\n// output: false\n\nconst flagsPermissions = new PermissionsBitField([\n\tPermissionsBitField.Flags.ManageChannels,\n\tPermissionsBitField.Flags.EmbedLinks,\n\tPermissionsBitField.Flags.AttachFiles,\n\tPermissionsBitField.Flags.ReadMessageHistory,\n\tPermissionsBitField.Flags.ManageRoles,\n]);\n\nconsole.log(flagsPermissions.has(PermissionsBitField.Flags.ManageChannels));\n// output: true\n\nconsole.log(flagsPermissions.has([PermissionsBitField.Flags.ManageChannels, PermissionsBitField.Flags.EmbedLinks]));\n// output: true\n\nconsole.log(flagsPermissions.has([PermissionsBitField.Flags.ManageChannels, PermissionsBitField.Flags.KickMembers]));\n// output: false\n\nconst adminPermissions = new PermissionsBitField(PermissionsBitField.Flags.Administrator);\n\nconsole.log(adminPermissions.has(PermissionsBitField.Flags.ManageChannels));\n// output: true\n\nconsole.log(adminPermissions.has(PermissionsBitField.Flags.ManageChannels, true));\n// output: true\n\nconsole.log(adminPermissions.has(PermissionsBitField.Flags.ManageChannels, false));\n// output: false\n```\n\n### Manipulating permissions\n\nThe Permissions object enables you to easily add or remove individual permissions from an existing bit field without worrying about bitwise operations. Both `.add()` and `.remove()` can take a single permission flag or number, an array of permission flags or numbers, or multiple permission flags or numbers as multiple parameters.\n\n```js\nconst { PermissionsBitField } = require('discord.js');\n\nconst permissions = new PermissionsBitField([\n\tPermissionsBitField.Flags.ViewChannel,\n\tPermissionsBitField.Flags.EmbedLinks,\n\tPermissionsBitField.Flags.AttachFiles,\n\tPermissionsBitField.Flags.ReadMessageHistory,\n\tPermissionsBitField.Flags.ManageRoles,\n]);\n\nconsole.log(permissions.has(PermissionsBitField.Flags.KickMembers));\n// output: false\n\npermissions.add(PermissionsBitField.Flags.KickMembers);\nconsole.log(permissions.has(PermissionsBitField.Flags.KickMembers));\n// output: true\n\npermissions.remove(PermissionsBitField.Flags.KickMembers);\nconsole.log(permissions.has(PermissionsBitField.Flags.KickMembers));\n// output: false\n```\n\nYou can utilize these methods to adapt permissions or overwrites without touching the other flags. To achieve this, you can get the existing permissions for a role, manipulating the bit field as described above and passing the changed bit field to `role.setPermissions()`.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/reactions.mdx",
    "content": "---\ntitle: Reactions\n---\n\n## Reacting to messages\n\nOne of the first things many people want to know is how to react with emojis, both custom and \"regular\" (Unicode). There are different routes you need to take for each of those, so let's look at both.\n\nHere's the base code we'll be using:\n\n```js title=\"reactionsample.js\" lineNumbers\nconst { Client, Events, GatewayIntentBits } = require('discord.js');\n\nconst client = new Client({\n\tintents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessageReactions],\n});\n\nclient.once(Events.ClientReady, (readyClient) => {\n\tconsole.log(`Ready! Logged in as ${readyClient.user.tag}`);\n});\n\nclient.on(Events.InteractionCreate, (interaction) => {\n\t// ...\n});\n\nclient.login('your-token-goes-here');\n```\n\n### Unicode emojis\n\nTo react with a Unicode emoji, you will need the actual Unicode character of the emoji. There are many ways to get a Unicode character of an emoji, but the easiest way would be through Discord itself. If you send a message with a Unicode emoji (such as `:smile:`, for example) and put a `\\` before it, it will \"escape\" the emoji and display the Unicode character instead of the standard emoji image.\n\nTo react with an emoji, you need to use the `message.react()` method. Once you have the emoji character, all you need to do is copy & paste it as a string inside the `.react()` method!\n\n```js title=\"reactionsample.js\" lineNumbers=11\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tconst { commandName } = interaction;\n\n\tif (commandName === 'react') {\n\t\tconst response = await interaction.reply({ content: 'You can react with Unicode emojis!', withResponse: true });\n\t\tresponse.resource.message.react('😄'); // [!code word:react]\n\t}\n});\n```\n\n### Custom emojis\n\nFor custom emojis, there are multiple ways of reacting. Like Unicode emojis, you can also escape custom emojis. However, when you escape a custom emoji, the result will be different.\n\nThis format is essentially the name of the emoji, followed by its ID. Copy & paste the ID into the `.react()` method as a string.\n\n```js title=\"reactionsample.js\" lineNumbers=11\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tconst { commandName } = interaction;\n\n\tif (commandName === 'react-custom') {\n\t\tconst response = await interaction.reply({ content: 'You can react with custom emojis!', withResponse: true });\n\t\tresponse.resource.message.react('😄'); // [!code --]\n\t\tresponse.resource.message.react('123456789012345678'); // [!code word:123456789012345678] [!code ++]\n\t}\n});\n```\n\n<Callout>\n    You can also pass different formats of the emoji to the `.react()` method.   \n    In the emoji mention format, animated emoji are prefixed with an `a`:\n\n    ```js\n    message.react('<:blobreach:123456789012345678>');\n    message.react('blobreach:123456789012345678');\n    message.react('<a:animated_blobreach:123456789012345678>'); // [!code word:a\\:]\n    message.react('a:animated_blobreach:123456789012345678');\n    ```\n\n</Callout>\n\nGreat! This route may not always be available to you, though. Sometimes you'll need to react with an emoji programmatically. To do so, you'll need to retrieve the emoji object.\n\nTwo of the easiest ways you can retrieve an emoji would be:\n\n- Use `.find()` on a Collection of Emojis.\n- Use `.get()` on the `client.emojis.cache` Collection.\n\n<Callout>\n\tTwo or more emojis can have the same name, and using `.find()` will only return the **first** entry it finds. As such,\n\tthis can cause unexpected results.\n</Callout>\n\nUsing `.find()`, your code would look something like this:\n\n```js title=\"reactionsample.js\" lineNumbers=16\nif (commandName === 'react-custom') {\n\tconst response = await interaction.reply({ content: 'You can react with custom emojis!', withResponse: true });\n\tconst message = response.resource.message;\n\tconst reactionEmoji = message.guild.emojis.cache.find((emoji) => emoji.name === 'blobreach'); // [!code word:find]\n\tmessage.react(reactionEmoji);\n}\n```\n\nUsing `.get()`, your code would look something like this:\n\n```js title=\"reactionsample.js\" lineNumbers=16\nif (commandName === 'react-custom') {\n\tconst response = await interaction.reply({ content: 'You can react with custom emojis!', withResponse: true });\n\tconst reactionEmoji = client.emojis.cache.get('123456789012345678'); // [!code word:get]\n\tresponse.resource.message.react(reactionEmoji);\n}\n```\n\nOf course, if you already have the emoji ID, you should put that directly inside the `.react()` method. But if you want to do other things with the emoji data later on (e.g., display the name or image URL), it's best to retrieve the full emoji object.\n\n### Reacting in order\n\nIf you just put one `message.react()` under another, it won't always react in order as-is. This is because `.react()` an asynchronous operation. Meaning `react('🍊')` will not wait for `react('🍎')` to complete before making the API call and cause a race condition. If you run this code multiple times you should be able to observe this inconsistent order:\n\n```js title=\"reactionsample.js\" lineNumbers=11\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tconst { commandName } = interaction;\n\n\tif (commandName === 'fruits') {\n\t\tconst response = await interaction.reply({ content: 'Reacting with fruits!', withResponse: true });\n\t\tconst { message } = response.resource;\n\t\tmessage.react('🍎');\n\t\tmessage.react('🍊');\n\t\tmessage.react('🍇');\n\t}\n});\n```\n\nAs you can see, if you leave it like that, it won't display as you want. It was able to react correctly on the first try but reacts differently each time after that.\n\nLuckily, there are two easy solutions to this. The first would be to chain `.then()`s in the order you want it to display.\n\n```js title=\"reactionsample.js\" lineNumbers=11\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tconst { commandName } = interaction;\n\n\tif (commandName === 'fruits') {\n\t\tconst response = await interaction.reply({ content: 'Reacting with fruits!', withResponse: true });\n\n\t\tresponse.resource.message\n\t\t\t.react('🍎')\n\t\t\t.then(() => message.react('🍊'))\n\t\t\t.then(() => message.react('🍇'))\n\t\t\t.catch((error) => console.error('One of the emojis failed to react:', error));\n\t}\n});\n```\n\nThe other would be to use the `async`/`await` keywords.\n\n```js title=\"reactionsample.js\" lineNumbers=11\n// [!code word:async]\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tconst { commandName } = interaction;\n\n\tif (commandName === 'fruits') {\n\t\tconst response = await interaction.reply({ content: 'Reacting with fruits!', withResponse: true });\n\t\tconst { message } = response.resource;\n\n\t\ttry {\n\t\t\tawait message.react('🍎'); // [!code word:await]\n\t\t\tawait message.react('🍊');\n\t\t\tawait message.react('🍇');\n\t\t} catch (error) {\n\t\t\tconsole.error('One of the emojis failed to react:', error);\n\t\t}\n\t}\n});\n```\n\nIf you try again with either of the code blocks above, you'll get the result you originally wanted!\n\n<Callout>\n\tIf you aren't familiar with Promises or `async`/`await`, you can read more about them on\n\t[MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) or [our guide page on\n\tasync/await](../additional-info/async-await.md)!\n</Callout>\n\n### Handling multiple reactions if the order doesn't matter\n\nHowever, if you don't mind the order the emojis react in, you can take advantage of `Promise.all()`, like so:\n\n```js title=\"reactionsample.js\" lineNumbers=16\nif (commandName === 'fruits') {\n\tconst message = await interaction.reply({ content: 'Reacting with fruits!' });\n\tPromise.all([message.react('🍎'), message.react('🍊'), message.react('🍇')]).catch((error) =>\n\t\tconsole.error('One of the emojis failed to react:', error),\n\t);\n}\n```\n\nThis small optimization allows you to use `.then()` to handle when all of the Promises have resolved, or `.catch()` when one fails. You can also `await` it to do things **after** all the reactions resolved since it returns a Promise.\n\n## Removing reactions\n\nNow that you know how to add reactions, you might be asking, how do you remove them? In this section, you will learn how to remove all reactions, remove reactions by user, and remove reactions by emoji.\n\n<Callout type=\"warn\">\n\tAll of these methods require `ManageMessages` permissions. Ensure your bot has permissions before attempting to\n\tutilize any of these methods, as it will error if it doesn't.\n</Callout>\n\n### Removing all reactions\n\nRemoving all reactions from a message is the easiest, the API allows you to do this through a single call. It can be done through the `message.reactions.removeAll()` method.\n\n```js\nmessage.reactions.removeAll().catch((error) => console.error('Failed to clear reactions:', error)); // [!code word:removeAll]\n```\n\n### Removing reactions by emoji\n\nRemoving reactions by emoji is easily done by using `MessageReaction#remove`.\n\n```js\nmessage.reactions.cache\n\t.get('123456789012345678')\n\t.remove() // [!code word:remove]\n\t.catch((error) => console.error('Failed to remove reactions:', error));\n```\n\n### Removing reactions by user\n\n<Callout>\n\tIf you are not familiar with `Collection#filter` and\n\t[`Map.has()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Map/has) take the time to\n\tunderstand what they do and then come back.\n</Callout>\n\nRemoving reactions by a user is not as straightforward as removing by emoji or removing all reactions. The API does not provide a method for selectively removing the reactions of a user. This means you will have to iterate through reactions that include the user and remove them.\n\n```js\nconst userReactions = message.reactions.cache.filter((reaction) => reaction.users.cache.has(userId));\n\ntry {\n\tfor (const reaction of userReactions.values()) {\n\t\tawait reaction.users.remove(userId);\n\t}\n} catch (error) {\n\tconsole.error('Failed to remove reactions.');\n}\n```\n\n## Awaiting reactions\n\nA common use case for reactions in commands is having a user confirm or deny an action or creating a poll system. Luckily, we actually [already have a guide page covering this](./collectors)! Check out that page if you want a more in-depth explanation. Otherwise, here's a basic example for reference:\n\n```js\nmessage.react('👍').then(() => message.react('👎'));\n\nconst collectorFilter = (reaction, user) => {\n\treturn ['👍', '👎'].includes(reaction.emoji.name) && user.id === interaction.user.id;\n};\n\nmessage\n\t.awaitReactions({ filter: collectorFilter, max: 1, time: 60_000, errors: ['time'] })\n\t.then((collected) => {\n\t\tconst reaction = collected.first();\n\n\t\tif (reaction.emoji.name === '👍') {\n\t\t\tmessage.reply('You reacted with a thumbs up.');\n\t\t} else {\n\t\t\tmessage.reply('You reacted with a thumbs down.');\n\t\t}\n\t})\n\t.catch((collected) => {\n\t\tmessage.reply('You reacted with neither a thumbs up, nor a thumbs down.');\n\t});\n```\n\n## Listening for reactions on old messages\n\nMessages sent before your bot started are uncached unless you fetch them first. By default, the library does not emit client events if the data received and cached is not sufficient to build fully functional objects.\nSince version 12, you can change this behavior by activating partials. For a full explanation of partials see [this page](./partials).\n\nMake sure you enable partial structures for `Message`, `Channel`, and `Reaction` when instantiating your client if you want reaction events on uncached messages for both server and direct message channels. If you do not want to support direct message channels, you can exclude `Channel`.\n\n<Callout>\n\tIf you use [gateway intents](./intents) but can't or don't want to use the privileged `GuildPresences` intent, you\n\tadditionally need the `User` partial.\n</Callout>\n\n```js title=\"old-reactions.js\"\nconst { Client, Events, GatewayIntentBits, Partials } = require('discord.js');\n\nconst client = new Client({\n\tintents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessageReactions],\n\t// [!code word:Partials]\n\tpartials: [Partials.Message, Partials.Channel, Partials.Reaction],\n});\n\nclient.on(Events.MessageReactionAdd, async (reaction, user) => {\n\t// When a reaction is received, check if the structure is partial\n\tif (reaction.partial) {\n\t\t// If the message this reaction belongs to was removed, the fetching might result in an API error which should be handled\n\t\ttry {\n\t\t\tawait reaction.fetch();\n\t\t} catch (error) {\n\t\t\tconsole.error('Something went wrong when fetching the message:', error);\n\t\t\t// Return as `reaction.message.author` may be undefined/null\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// Now the message has been cached and is fully available\n\tconsole.log(`${reaction.message.author}'s message \"${reaction.message.content}\" gained a reaction!`);\n\t// The reaction is now also fully available and the properties will be reflected accurately:\n\tconsole.log(`${reaction.count} user(s) have given the same reaction to this message!`);\n});\n```\n\n<Callout>\n\tPartial structures are enabled **globally**. You cannot only make them work for a specific event or cache, and you\n\tvery likely **need to adapt other parts of your code** that are accessing data from the relevant caches. All caches\n\tholding the respective structure type might return partials as well! For more info, check out [this page](./partials).\n</Callout>\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/threads.mdx",
    "content": "---\ntitle: Threads\n---\n\nThreads can be thought of as temporary sub-channels inside an existing channel, to help better organize conversation in a busy channel.\n\n## Thread related gateway events\n\n<Callout>You can use the `ThreadChannel#isThread` type guard to make sure a channel is a `ThreadChannel`!</Callout>\n\nThreads introduce a number of new gateway events, which are listed below:\n\n- `Client#threadCreate`: Emitted whenever a thread is created or when the client user is added to a thread.\n- `Client#threadDelete`: Emitted whenever a thread is deleted.\n- `Client#threadUpdate`: Emitted whenever a thread is updated (e.g. name change, archive state change, locked state change).\n- `Client#threadListSync`: Emitted whenever the client user gains access to a text or news channel that contains threads.\n- `Client#threadMembersUpdate`: Emitted whenever members are added or removed from a thread. Requires `GuildMembers` privileged intent.\n- `Client#threadMemberUpdate`: Emitted whenever the client user's thread member is updated.\n\n## Creating and deleting threads\n\nThreads are created and deleted using the `GuildTextThreadManager` of a text or news channel.\nTo create a thread you call the `GuildTextThreadManager#create` method:\n\n```js\n// [!code word:create]\nconst thread = await channel.threads.create({\n\tname: 'food-talk',\n\tautoArchiveDuration: ThreadAutoArchiveDuration.OneHour,\n\treason: 'Needed a separate thread for food',\n});\n\nconsole.log(`Created thread: ${thread.name}`);\n```\n\nTo delete a thread, use the `ThreadChannel#delete` method:\n\n```js\nconst thread = channel.threads.cache.find((x) => x.name === 'food-talk');\nawait thread.delete(); // [!code word:delete]\n```\n\n## Joining and leaving threads\n\nTo join your client to a ThreadChannel, use the `ThreadChannel#join` method:\n\n```js\nconst thread = channel.threads.cache.find((x) => x.name === 'food-talk');\nif (thread.joinable) await thread.join(); // [!code word:join()]\n```\n\nAnd to leave one, use `ThreadChannel#leave`;\n\n```js\nconst thread = channel.threads.cache.find((x) => x.name === 'food-talk');\nawait thread.leave(); // [!code word:leave]\n```\n\n## Archiving, unarchiving, and locking threads\n\nA thread can be either active or archived. Changing a thread from archived to active is referred to as unarchiving the thread. Threads that have `locked` set to true can only be unarchived by a member with the `ManageThreads` permission.\n\nThreads are automatically archived after inactivity. \"Activity\" is defined as sending a message, unarchiving a thread, or changing the auto-archive time.\n\nTo archive or unarchive a thread, use the `ThreadChannel#setArchived` method and pass in a boolean parameter:\n\n```js\nconst thread = channel.threads.cache.find((x) => x.name === 'food-talk');\nawait thread.setArchived(true); // archived // [!code word:setArchived]\nawait thread.setArchived(false); // unarchived\n```\n\nThis same principle applies to locking and unlocking a thread via the `ThreadChannel#setLocked` method:\n\n```js\nconst thread = channel.threads.cache.find((x) => x.name === 'food-talk');\nawait thread.setLocked(true); // locked [!code word:setLocked]\nawait thread.setLocked(false); // unlocked\n```\n\n## Public and private threads\n\nPublic threads are viewable by everyone who can view the parent channel of the thread. Public threads can be created with the `GuildTextThreadManager#create` method.\n\n```js\n// [!code word:create]\nconst thread = await channel.threads.create({\n\tname: 'food-talk',\n\tautoArchiveDuration: ThreadAutoArchiveDuration.OneHour,\n\treason: 'Needed a separate thread for food',\n});\n\nconsole.log(`Created thread: ${thread.name}`);\n```\n\nThey can also be created from an existing message with the `Message#startThread` method, but will be \"orphaned\" if that message is deleted. The thread is not deleted along with the message and will still be available through the channels thread list!\n\n```js\n// [!code word:startThread]\nconst thread = await message.startThread({\n\tname: 'food-talk',\n\tautoArchiveDuration: ThreadAutoArchiveDuration.OneHour,\n\treason: 'Needed a separate thread for food',\n});\n\nconsole.log(`Created thread: ${thread.name}`);\n```\n\n<Callout>The created thread and the message it originated from will share the same ID.</Callout>\n\nPrivate threads can only be created on text channels. Private threads can initially only be viewed by the user creating them as well as moderators with the `ManageThreads` permission. Users that are mentioned in threads are added to the thread! This is also true for roles with few role members. The notifications for `@here` and `@everyone` will only affect members in the thread and not add anyone.\n\nTo create a private thread, use `GuildTextThreadManager#create` and pass in `ChannelType.PrivateThread` as the `type`. Public channels are the default, hence passing `ChannelType.PublicThread` is not required in the example above:\n\n```js\nconst { ChannelType, ThreadAutoArchiveDuration } = require('discord.js');\n\nconst thread = await channel.threads.create({\n\tname: 'mod-talk',\n\tautoArchiveDuration: ThreadAutoArchiveDuration.OneHour,\n\ttype: ChannelType.PrivateThread, // [!code word:PrivateThread] [!code ++]\n\treason: 'Needed a separate thread for moderation',\n});\n\nconsole.log(`Created thread: ${thread.name}`);\n```\n\n<Callout>You cannot create private threads on an existing message.</Callout>\n\n## Adding and removing members\n\nYou can add and remove members to and from a thread channel.\n\nTo add a member to a thread, use the `ThreadMemberManager#add` method:\n\n```js\nconst thread = channel.threads.cache.find((x) => x.name === 'food-talk');\nawait thread.members.add('140214425276776449'); // [!code word:add]\n```\n\nAnd to remove a member from a thread, use `ThreadMemberManager#remove`:\n\n```js\nconst thread = channel.threads.cache.find((x) => x.name === 'food-talk');\nawait thread.members.remove('140214425276776449'); // [!code word:remove]\n```\n\n## Sending messages to threads with webhooks\n\nIt is possible for a webhook built on the parent channel to send messages to the channel's threads. For the purpose of this example, it is assumed a single webhook already exists for that channel (More specifically, that there are no followed channels or managed webhooks. These webhook types cannot be accessed by your app). If you wish to learn more about webhooks, see our [webhook guide](./webhooks).\n\n```js\nconst webhooks = await channel.fetchWebhooks();\nconst webhook = webhooks.first();\n\nawait webhook.send({\n\tcontent: \"Look ma! I'm in a thread!\",\n\tthreadId: '123456789012345678', // [!code word:threadId]\n});\n```\n\nAnd that's it! Now you know all there is to know on working with threads using discord.js!\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/popular-topics/webhooks.mdx",
    "content": "---\ntitle: Webhooks\n---\n\nWebhooks can send messages to a text channel without having to log in as a bot. They can also fetch, edit, and delete their own messages. There are a variety of methods in discord.js to interact with webhooks. In this section, you will learn how to create, fetch, edit, and use webhooks.\n\n## What is a webhook\n\nWebhooks are a utility used to send messages to text channels without needing a Discord application. Webhooks are useful for allowing something to send messages without requiring a Discord application. You can also directly edit or delete messages you sent through the webhook. There are two structures to make use of this functionality: `Webhook` and `WebhookClient`. `WebhookClient` is an extended version of a `Webhook`, which allows you to send messages through it without needing a bot client.\n\n<Callout>\n\tIf you would like to read about using webhooks through the API without discord.js, you can read about them\n\t[here](https://discord.com/developers/docs/resources/webhook).\n</Callout>\n\n## Detecting webhook messages\n\nBots receive webhook messages in a text channel as usual. You can detect if a webhook sent the message by checking if the `Message.webhookId` is not `null`. In this example, we return if a webhook sent the message.\n\n```js\nif (message.webhookId) return;\n```\n\nIf you would like to get the webhook object that sent the message, you can use `Message#fetchWebhook`.\n\n## Fetching webhooks\n\n<Callout>\n\tWebhook fetching will always make use of collections and Promises. If you do not understand either concept, revise\n\tthem, and then come back to this section. You can read about collections [here](../additional-info/collections), and\n\tPromises [here](../additional-info/async-await) and\n\t[here](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Using_promises).\n</Callout>\n\n### Fetching all webhooks of a guild\n\nIf you would like to get all webhooks of a guild you can use `Guild#fetchWebhooks`. This will return a Promise which will resolve into a Collection of `Webhook`s.\n\n### Fetching webhooks of a channel\n\nWebhooks belonging to a channel can be fetched using `TextChannel#fetchWebhooks`. This will return a Promise which will resolve into a Collection of `Webhook`s. A collection will be returned even if the channel contains a single webhook. If you are certain the channel contains a single webhook, you can use `Collection#first` on the Collection to get the webhook.\n\n### Fetching a single webhook\n\n#### Using client\n\nYou can fetch a specific webhook using its `id` with `Client#fetchWebhook`. You can obtain the webhook id by looking at its link, the number after `https://discord.com/api/webhooks/` is the `id`, and the part after that is the `token`.\n\n#### Using the WebhookClient constructor\n\nIf you are not using a bot client, you can get a webhook by creating a new instance of `WebhookClient` and passing the `id` and `token` into the constructor. These credentials do not require you to have a bot application, but it also offers limited information instead of fetching it using an authorized client.\n\n```js\n//  [!code word:token\\:]\nconst webhookClient = new WebhookClient({ id: 'id', token: 'token' }); // [!code word:id\\:]\n```\n\nYou can also pass in just a `url`:\n\n```js\nconst webhookClient = new WebhookClient({ url: 'https://discord.com/api/webhooks/id/token' }); // [!code word:url\\:]\n```\n\n## Creating webhooks\n\n### Creating webhooks through server settings\n\nYou can create webhooks directly through the Discord client. Go to Server Settings, and you will see an `Integrations` tab.\n\n![Integrations tab](./images/creating-webhooks-1.png)\n\nIf you already have created a webhook, the webhooks tab will look like this; you will need to click the `View Webhooks` button.\n\n![Integrations tab](./images/creating-webhooks-2.png)\n\nOnce you are there, click on the `Create Webhook` / `New Webhook` button; this will create a webhook. From here, you can edit the channel, the name, and the avatar. Copy the link, the first part is the id, and the second is the token.\n\n![Creating a Webhook](./images/creating-webhooks-3.png)\n\n### Creating webhooks with discord.js\n\nWebhooks can be created with the `TextChannel#createWebhook` method.\n\n```js\nchannel\n\t// [!code word:createWebhook]\n\t.createWebhook({\n\t\tname: 'Some-username',\n\t\tavatar: 'https://i.imgur.com/AfFp7pu.png',\n\t})\n\t.then((webhook) => console.log(`Created webhook ${webhook}`))\n\t.catch(console.error);\n```\n\n## Editing webhooks\n\nYou can edit Webhooks and WebhookClients to change their name, avatar, and channel using `Webhook#edit`.\n\n```js\nwebhook\n\t// [!code word:edit]\n\t.edit({\n\t\tname: 'Some-username',\n\t\tavatar: 'https://i.imgur.com/AfFp7pu.png',\n\t\tchannel: '222197033908436994',\n\t})\n\t.then((webhook) => console.log(`Edited webhook ${webhook}`))\n\t.catch(console.error);\n```\n\n## Using webhooks\n\nWebhooks can send messages to text channels, as well as fetch, edit, and delete their own. These methods are the same for both `Webhook` and `WebhookClient`.\n\n### Sending messages\n\nWebhooks, like bots, can send up to 10 embeds per message. They can also send attachments and normal content. The `Webhook#send` method is very similar to the method used for sending a message to a text channel. Webhooks can also choose how the username and avatar will appear when they send the message.\n\nExample using a WebhookClient:\n\n```js\nconst { EmbedBuilder, WebhookClient } = require('discord.js'); // [!code word:WebhookClient]\nconst { webhookId, webhookToken } = require('./config.json');\n\nconst webhookClient = new WebhookClient({ id: webhookId, token: webhookToken });\n\nconst embed = new EmbedBuilder().setTitle('Some Title').setColor(0x00ffff);\n\n// [!code word:send]\nwebhookClient.send({\n\tcontent: 'Webhook test',\n\tusername: 'some-username',\n\tavatarURL: 'https://i.imgur.com/AfFp7pu.png',\n\tembeds: [embed],\n});\n```\n\nTry to find a webhook your bot knows the token for. This makes sure your bot can execute the webhook later on.\n\n```js\nconst { Client, EmbedBuilder, Events, GatewayIntentBits } = require('discord.js');\nconst { token } = require('./config.json');\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\nconst embed = new EmbedBuilder().setTitle('Some Title').setColor(0x00ffff);\n\nclient.once(Events.ClientReady, async () => {\n\tconst channel = client.channels.cache.get('123456789012345678');\n\ttry {\n\t\tconst webhooks = await channel.fetchWebhooks();\n\t\tconst webhook = webhooks.find((wh) => wh.token); // [!code word:wh.token]\n\n\t\tif (!webhook) {\n\t\t\treturn console.log('No webhook was found that I can use!');\n\t\t}\n\n\t\tawait webhook.send({\n\t\t\tcontent: 'Webhook test',\n\t\t\tusername: 'some-username',\n\t\t\tavatarURL: 'https://i.imgur.com/AfFp7pu.png',\n\t\t\tembeds: [embed],\n\t\t});\n\t} catch (error) {\n\t\tconsole.error('Error trying to send a message: ', error);\n\t}\n});\n\nclient.login(token);\n```\n\n### Fetching messages\n\nYou can use `Webhook#fetchMessage` to fetch messages previously sent by the Webhook.\n\n```js\nconst message = await webhookClient.fetchMessage('123456789012345678'); // [!code word:fetchMessage]\n```\n\n### Editing messages\n\nYou can use `Webhook#editMessage` to edit messages previously sent by the Webhook.\n\n```js\n//[!code word:editMessage]\nconst message = await webhook.editMessage('123456789012345678', {\n\tcontent: 'Edited!',\n\tembeds: [embed],\n});\n```\n\n### Deleting messages\n\nYou can use `Webhook#deleteMessage` to delete messages previously sent by the Webhook.\n\n```js\nawait webhookClient.deleteMessage('123456789012345678'); // [!code word:deleteMessage]\n```\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/preparations/adding-your-app.mdx",
    "content": "---\ntitle: Adding Your App\n---\n\nAfter you set up a bot application, you'll notice that it's not in any servers yet. So how does that work?\n\nBefore you're able to see your bot in your own (or other) servers, you'll need to add it by creating and using a unique invite link using your bot application's client id.\n\n## Bot invite links\n\nThe basic version of one such link looks like this:\n\n```\nhttps://discord.com/api/oauth2/authorize?client_id=123456789012345678&permissions=0&scope=bot%20applications.commands\n```\n\nThe structure of the URL is quite simple:\n\n- `https://discord.com/api/oauth2/authorize` is Discord's standard structure for authorizing an OAuth2 application (such as your bot application) for entry to a Discord server.\n- `client_id=...` is to specify _which_ application you want to authorize. You'll need to replace this part with your client's id to create a valid invite link.\n- `permissions=...` describes what permissions your bot will have on the server you are adding it to.\n- `scope=bot%20applications.commands` specifies that you want to add this application as a Discord bot, with the ability to create slash commands.\n\n<Callout type=\"error\">\n\tIf you get an error message saying \"Bot requires a code grant\", head over to your application's settings and disable\n\tthe \"Require OAuth2 Code Grant\" option. You shouldn't enable this option unless you know why you need to.\n</Callout>\n\n## Creating and using your invite link\n\nTo create an invite link, head back to the [developer portal](https://discord.com/developers/applications/me) page under the \"Applications\" section, click on your bot application, and open the OAuth2 page.\n\nIn the sidebar, you'll find the OAuth2 URL generator. Select the `bot` and `applications.commands` options. Once you select the `bot` option, a list of permissions will appear, allowing you to configure the permissions your bot needs.\n\nGrab the link via the \"Copy\" button and enter it in your browser. You should see something like this (with your bot's username and avatar):\n\n![Bot Authorization page](./images/bot-auth-page.png)\n\nChoose the server you want to add it to and click \"Authorize\". Do note that you'll need the \"Manage Server\" permission on a server to add your bot there. This should then present you a nice confirmation message:\n\n![Bot authorized](./images/bot-authorized.png)\n\nCongratulations! You've successfully added your bot to your Discord server. It should show up in your server's member list somewhat like this:\n\n![Bot in server's member list](./images/bot-in-memberlist.png)\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/preparations/app-setup.mdx",
    "content": "---\ntitle: Application Setup\n---\n\n## Creating your bot\n\nNow that you've installed Node, discord.js, and hopefully a linter, you're almost ready to start coding! The next step you need to take is setting up an actual Discord bot application via Discord's website.\n\nIt's effortless to create one. The steps you need to take are as follows:\n\n1. Open the [Discord developer portal](https://discord.com/developers/applications) and log into your account.\n2. Click on the \"New Application\" button.\n3. Enter a name and confirm the pop-up window by clicking the \"Create\" button.\n\nYou should see a page like this:\n\n![Successfully created application](./images/create-app.png)\n\nYou can edit your application's name, description, and avatar here. Once you've done that, then congratulations—you're now the proud owner of a shiny new Discord bot! You're not entirely done, though.\n\n## Your bot's token\n\n<Callout type=\"error\" title=\"Important\">\n\t**This section is critical**, so pay close attention. It explains what your bot token is, as well as the security\n\taspects of it.\n</Callout>\n\nAfter creating a bot user, you'll see a section like this:\n\n![Bot application](./images/created-bot.png)\n\nIn this panel, you can give your bot a snazzy avatar, set its username, and make it public or private. Your bot's token will be revealed when you press the \"Reset Token\" button and confirm. When we ask you to paste your bot's token somewhere, this is the value that you need to put in. If you happen to lose your bot's token at some point, you need to come back to this page and reset your bot's token again which will reveal the new token, invalidating all old ones.\n\n### What is a token, anyway?\n\nA token is essentially your bot's password; it's what your bot uses to login to Discord. With that said, **it is vital that you do not ever share this token with anybody, purposely or accidentally**. If someone does manage to get a hold of your bot's token, they can use your bot as if it were theirs—this means they can perform malicious acts with it.\n\nTokens look like this: `NzkyNzE1NDU0MTk2MDg4ODQy.X-hvzA.Ovy4MCQywSkoMRRclStW4xAYK7I` (don't worry, we immediately reset this token before even posting it here!). If it's any shorter and looks more like this: `kxbsDRU5UfAaiO7ar9GFMHSlmTwYaIYn`, you copied your client secret instead. Make sure to copy the token if you want your bot to work!\n\n### Token leak scenario\n\nLet's imagine that you have a bot on over 1,000 servers, and it took you many, many months of coding and patience to get it on that amount. Your bot's token gets leaked somewhere, and now someone else has it. That person can:\n\n- Spam every server your bot is on;\n- DM spam as many users as possible;\n- Delete as many channels as possible;\n- Kick or ban as many server members as possible;\n- Make your bot leave all of the servers it has joined;\n\nAll that and much, much more. Sounds pretty terrible, right? So make sure to keep your bot's token as safe as possible!\n\n<Callout type=\"error\" title=\"Resetting Your Application Token\">\n\tIf your bot token has been compromised by committing it to a public repository, posting it in discord.js support etc.\n\tor otherwise see your bot's token in danger, return to this page and press \"Reset Token\". This will invalidate all old\n\ttokens belonging to your bot. Keep in mind that you will need to update your bot's token where you used it before.\n</Callout>\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/preparations/installation.mdx",
    "content": "---\ntitle: Installing Node.js and discord.js\n---\n\nimport { Grid2x2, Apple, Cpu, Zap, Package } from 'lucide-react';\n\n## Installing Node.js\n\nTo use discord.js, you'll need to install the latest LTS version of [Node.js](https://nodejs.org/).\n\n<Callout>\n\tTo check if you already have Node installed on your machine \\(e.g., if you're using a VPS\\), run `node -v` in your\n\tterminal. It is recommended to use the latest LTS version of Node.\n</Callout>\n\n<Cards>\n\t<Card icon={<Zap />} title=\"Volta\" href=\"https://volta.sh/\">\n\t\tUse volta to manage your node version cross-platform.\n\t</Card>\n\t<Card icon={<Package />} title=\"Fast Node Manager\" href=\"https://github.com/Schniz/fnm\">\n\t\tUse `Fast node Manager` to manage your node version cross-platform.\n\t</Card>\n\t<Card icon={<Grid2x2 />} title=\"Windows\" href=\"https://nodejs.org/en/download\">\n\t\tDownload the latest version from the Node.js website, open the downloaded file, and follow the steps from the\n\t\tinstaller.\n\t</Card>\n\t<Card icon={<Apple />} title=\"macOS\" href=\"https://nodejs.org/en/download\">\n\t\tDownload the latest version from the Node.js website, open the package installer, and follow the instructions.\n\t\tAlternatively you can use a package manager like Homebrew with the command `brew install node`\n\t</Card>\n\t<Card icon={<Cpu />} title=\"Linux\" href=\"https://nodejs.org/en/download\">\n\t\tDetermine how you should install Node with out package manager of choice.\n\t</Card>\n</Cards>\n\n## Preparing the essentials\n\nTo use discord.js, you'll need to install it via npm \\(Node's package manager\\). npm comes with every Node installation, so you don't have to worry about installing that. However, before you install anything, you should set up a new project folder.\n\nNavigate to a suitable place on your machine and create a new folder named `discord-bot` (or whatever you want). Next you'll need to open your terminal.\n\n## Opening the terminal\n\n<Callout>\n\tIf you use [Visual Studio Code](https://code.visualstudio.com/), you can press <kbd>Ctrl</kbd>\n\t<kbd>`</kbd> (backtick) to open its integrated terminal.\n</Callout>\n\nOn Windows, either:\n\n- Hold <kbd>Shift</kbd> and right-click inside your project directory and choose the \"Open command window here\" option\n- Press <kbd>Win</kbd> <kbd>R</kbd> and run `cmd.exe`, and then `cd` into your project directory\n\nOn macOS, either:\n\n- Open Launchpad or Spotlight and search for \"Terminal\"\n- In your \"Applications\" folder, under \"Utilities\", open the Terminal app\n\nOn Linux, you can quickly open the terminal with <kbd>Ctrl</kbd> <kbd>Alt</kbd> <kbd>T</kbd>.\n\nWith the terminal open, run the `node -v` command to make sure you've successfully installed Node.js.\n\n## Initiating a project folder\n\n```sh tab=\"npm\"\nnpm init\n```\n\n```sh tab=\"yarn\"\nyarn init\n```\n\n```sh tab=\"pnpm\"\npnpm init\n```\n\n```sh tab=\"bun\"\nbun init\n```\n\nThis is the next command you'll be running. This command creates a `package.json` file for you, which will keep track of the dependencies your project uses, as well as other info.\n\nThis command will ask you a sequence of questions–you should fill them out as you see fit. If you're not sure of something or want to skip it as a whole, leave it blank and press enter.\n\nTo get started quickly, you can run the following command to have it fill out everything for you.\n\n```sh tab=\"npm\"\nnpm init -y\n```\n\n```sh tab=\"yarn\"\nyarn init -y\n```\n\n```sh tab=\"pnpm\"\npnpm init\n```\n\n```sh tab=\"bun\"\nbun init -y\n```\n\nOnce you're done with that, you're ready to install discord.js!\n\n## Installing discord.js\n\nNow that you've installed Node.js and know how to open your console and run commands, you can finally install discord.js! Run the following command in your terminal:\n\n```sh tab=\"npm\"\nnpm install discord.js\n```\n\n```sh tab=\"yarn\"\nyarn add discord.js\n```\n\n```sh tab=\"pnpm\"\npnpm add discord.js\n```\n\n```sh tab=\"bun\"\nbun add discord.js\n```\n\nAnd that's it! With all the necessities installed, you're almost ready to start coding your bot.\n\n## Installing a linter\n\nWhile you are coding, it's possible to run into numerous syntax errors or code in an inconsistent style. You should [install a linter](./linter) to ease these troubles. While code editors generally can point out syntax errors, linters coerce your code into a specific style as defined by the configuration. While this is not required, it is advised.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/preparations/linter.mdx",
    "content": "---\ntitle: Linters\n---\n\nAs a developer, it's a good idea to make your development process as streamlined as possible. Linters check syntax and help you produce consistent code that follows specific style rules that you can define yourself or inherit from existing configurations. Although it's not required, installing a linter will help you immensely.\n\n## Installing a code editor\n\nFirst, you will need a proper code editor. Using programs such as Notepad and Notepad++ is discouraged, as they're inefficient for projects like these. If you aren't using one of the editors listed below, it's advised to switch.\n\n- [Visual Studio Code](https://code.visualstudio.com/) is a prevalent choice; it is known for being fast and powerful. It supports various languages, has a terminal, built-in IntelliSense support, and autocomplete for both JavaScript and TypeScript. This is the recommended choice.\n- [Sublime Text](https://www.sublimetext.com/) is another popular editor that's easy to use and write code with.\n\n## Installing a linter\n\nInstall the [ESLint package](https://www.npmjs.com/package/eslint) inside your project directory.\n\n```sh tab=\"npm\"\nnpm install --save-dev eslint @eslint/js\n```\n\n```sh tab=\"yarn\"\nyarn add eslint @eslint/js --dev\n```\n\n```sh tab=\"pnpm\"\npnpm add --save-dev eslint @eslint/js\n```\n\n```sh tab=\"bun\"\nbun add --dev eslint\n```\n\nOne of the advantages proper code editors have is their ability to integrate linters via editor plugins. Install the appropriate plugin(s) for your editor of choice.\n\n- [ESLint for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)\n- [ESLint for Sublime Text](https://packagecontrol.io/packages/ESLint)\n\n<Callout>\n\tYou can view plugins directly inside your editor.\n\n    - Visual Studio Code: Press <kbd>Ctrl</kbd> <kbd>Shift</kbd> <kbd>X</kbd>\n    - Sublime Text: Press <kbd>Ctrl</kbd> <kbd>Shift</kbd> <kbd>P</kbd> and search for \"Install Package\" (available via [Package Control](https://packagecontrol.io/installation))\n\n    After that, search for the appropriate plugin and install it.\n\n</Callout>\n\n## Setting up ESLint rules\n\nESLint may display many warnings and errors about your code when you start using it but don't let this startle you. To get started, create a file in your project directory named `eslint.config.js` and copy the code below into the file:\n\n```javascript title=\"eslint.config.js\"\nconst js = require('@eslint/js');\n\nmodule.exports = [\n\tjs.configs.recommended,\n\t{\n\t\tlanguageOptions: {\n\t\t\tecmaVersion: 'latest',\n\t\t},\n\t\trules: {},\n\t},\n];\n```\n\nThis is the basis of how an ESLint file will look. The `rules` object is where you'll define what rules you want to apply to ESLint. For example, if you want to make sure you never miss a semicolon, the `\"semi\": [\"error\", \"always\"]` rule is what you'll want to add inside that object.\n\nYou can find a list of all of ESLint's rules on [their website](https://eslint.org/docs/rules). There are indeed many rules, and it may be overwhelming at first, so if you don't want to go through everything on your own yet, you can use these rules:\n\n```javascript title=\"eslint.config.js\"\nconst js = require('@eslint/js');\n\nmodule.exports = [\n\tjs.configs.recommended,\n\t{\n\t\tlanguageOptions: {\n\t\t\tecmaVersion: 'latest',\n\t\t},\n\t\trules: {\n\t\t\t'arrow-spacing': ['warn', { before: true, after: true }],\n\t\t\t'brace-style': ['error', 'stroustrup', { allowSingleLine: true }],\n\t\t\t'comma-dangle': ['error', 'always-multiline'],\n\t\t\t'comma-spacing': 'error',\n\t\t\t'comma-style': 'error',\n\t\t\tcurly: ['error', 'multi-line', 'consistent'],\n\t\t\t'dot-location': ['error', 'property'],\n\t\t\t'handle-callback-err': 'off',\n\t\t\tindent: ['error', 'tab'],\n\t\t\t'keyword-spacing': 'error',\n\t\t\t'max-nested-callbacks': ['error', { max: 4 }],\n\t\t\t'max-statements-per-line': ['error', { max: 2 }],\n\t\t\t'no-console': 'off',\n\t\t\t'no-empty-function': 'error',\n\t\t\t'no-floating-decimal': 'error',\n\t\t\t'no-inline-comments': 'error',\n\t\t\t'no-lonely-if': 'error',\n\t\t\t'no-multi-spaces': 'error',\n\t\t\t'no-multiple-empty-lines': ['error', { max: 2, maxEOF: 1, maxBOF: 0 }],\n\t\t\t'no-shadow': ['error', { allow: ['err', 'resolve', 'reject'] }],\n\t\t\t'no-trailing-spaces': ['error'],\n\t\t\t'no-var': 'error',\n\t\t\t'no-undef': 'off',\n\t\t\t'object-curly-spacing': ['error', 'always'],\n\t\t\t'prefer-const': 'error',\n\t\t\tquotes: ['error', 'single'],\n\t\t\tsemi: ['error', 'always'],\n\t\t\t'space-before-blocks': 'error',\n\t\t\t'space-before-function-paren': [\n\t\t\t\t'error',\n\t\t\t\t{\n\t\t\t\t\tanonymous: 'never',\n\t\t\t\t\tnamed: 'never',\n\t\t\t\t\tasyncArrow: 'always',\n\t\t\t\t},\n\t\t\t],\n\t\t\t'space-in-parens': 'error',\n\t\t\t'space-infix-ops': 'error',\n\t\t\t'space-unary-ops': 'error',\n\t\t\t'spaced-comment': 'error',\n\t\t\tyoda: 'error',\n\t\t},\n\t},\n];\n```\n\nThe major points of this setup would be:\n\n- Allowing you to debug with `console.log()`;\n- Prefer using `const` over `let` or `var`, as well as disallow `var`;\n- Disapproving of variables with the same name in callbacks;\n- Requiring single quotes over double quotes;\n- Requiring semicolons. While not required in JavaScript, it's considered one of the most common best practices to follow;\n- Requiring accessing properties to be on the same line;\n- Requiring indenting to be done with tabs;\n- Limiting nested callbacks to 4. If you hit this error, it is a good idea to consider refactoring your code.\n\nIf your current code style is a bit different, or you don't like a few of these rules, that's perfectly fine! Just head over to the [ESLint docs](https://eslint.org/docs/rules/), find the rule(s) you want to modify, and change them accordingly.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/preparations/meta.json",
    "content": "{\n\t\"title\": \"Getting Started\",\n\t\"pages\": [\"app-setup\", \"adding-your-app\", \"installation\", \"linter\"]\n}\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/sequelize/currency.mdx",
    "content": "---\ntitle: Making a Currency System\n---\n\nA common feature of Discord bots is a currency system. It's possible to do everything in one object, but we can also abstract that in terms of _relations_ between objects. This is where the power of a RDBMS (Relational Database Management System) truly shines. Sequelize calls these _associations_, so we'll be using that term from now on.\n\n## File overview\n\nThere will be multiple files: a DB init script, your models, and your bot script. In [the sequelize guide](./), we placed all of these in the same file. Having everything in one file isn't an ideal practice, so we'll correct that.\n\nThis time we'll have six files.\n\n- `app.js` is where we'll keep the main bot code.\n- `dbInit.js` is the initialization file for the database. We run this once and forget about it.\n- `dbObjects.js` is where we'll import the models and create associations here.\n- `models/Users.js` is the Users model. Users will have a currency attribute in here.\n- `models/CurrencyShop.js` is the Shop model. The shop will have a name and a price for each item.\n- `models/UserItems.js` is the junction table between the users and the shop. A junction table connects two tables. Our junction table will have an additional field for the amount of that item the user has.\n\n## Create models\n\nHere is an entity relation diagram of the models we'll be making:\n\n<Mermaid\n\tchart=\"\nerDiagram\n\tUSER ||--o{ USERITEMS : owns \n\tCURRENCYSHOP ||..o{ USERITEMS : offers\n\tUSER {\n\t\tstring user_id PK\n\t\tstring balance\n\t}\n\tUSERITEMS\n\tUSERITEMS {\n\t\tstring user_id FK\n\t\tstring item_id FK\n\t\tnumber amount\n\t}\n\tCURRENCYSHOP\n\tCURRENCYSHOP {\n\t\tstring id PK\n\t\tstring name\n\t\tnumber cost\n\t}\n\"\n/>\n\n`Users` have a `user_id`, and a `balance`. Each `user_id` can have multiple links to the `UserItems` table, and each entry in the table connects to one of the items in the `CurrencyShop`, which will have a `name` and a `cost` associated with it.\n\nTo implement this, begin by making a `models` folder and create a `Users.js` file inside which contains the following:\n\n```js title=\"models/Users.js\" lineNumbers\nmodule.exports = (sequelize, DataTypes) => {\n\treturn sequelize.define(\n\t\t'users',\n\t\t{\n\t\t\tuser_id: {\n\t\t\t\ttype: DataTypes.STRING,\n\t\t\t\tprimaryKey: true, // [!code word:primaryKey]\n\t\t\t},\n\t\t\tbalance: {\n\t\t\t\ttype: DataTypes.INTEGER,\n\t\t\t\tdefaultValue: 0,\n\t\t\t\tallowNull: false,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\ttimestamps: false, // [!code word:timestamps]\n\t\t},\n\t);\n};\n```\n\nLike you see in the diagram above, the Users model will only have two attributes: a `user_id` primary key and a `balance`. A primary key is a particular attribute that becomes the default column used when joining tables together, and it is automatically unique and not `null`.\n\nBalance also sets `allowNull` to `false`, which means that both values have to be set in conjunction with creating a primary key; otherwise, the database would throw an error. This constraint guarantees correctness in your data storage. You'll never have `null` or empty values, ensuring that if you somehow forget to validate in the application that both values are not `null`, the database would do a final validation.\n\nNotice that the options object sets `timestamps` to `false`. This option disables the `createdAt` and the `updatedAt` columns that sequelize usually creates for you. Setting `user_id` to primary also eliminates the `id` primary key that Sequelize usually generates for you since there can only be one primary key on a table.\n\nNext, still in the same `models` folder, create a `CurrencyShop.js` file that contains the following:\n\n```js title=\"models/CurrencyShop.js\" lineNumbers\nmodule.exports = (sequelize, DataTypes) => {\n\treturn sequelize.define(\n\t\t'currency_shop',\n\t\t{\n\t\t\tname: {\n\t\t\t\ttype: DataTypes.STRING,\n\t\t\t\tunique: true, // [!code word:unique]\n\t\t\t},\n\t\t\tcost: {\n\t\t\t\ttype: DataTypes.INTEGER,\n\t\t\t\tallowNull: false,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\ttimestamps: false,\n\t\t},\n\t);\n};\n```\n\nLike the Users model, timestamps aren't needed here, so you can disable it. Unlike the Users model, however, the `unique` field is set to `true` here, allowing you to change the name without affecting the primary key that joins this to the next object. This gets generated automatically by sequelize since a primary key isn't set.\n\nThe next file will be `UserItems.js`, the junction table.\n\n```js title=\"models/UserItems.js\" lineNumbers\nmodule.exports = (sequelize, DataTypes) => {\n\treturn sequelize.define(\n\t\t'user_item',\n\t\t{\n\t\t\tuser_id: DataTypes.STRING, // [!code word:user_id]\n\t\t\titem_id: DataTypes.INTEGER, // [!code word:item_id]\n\t\t\tamount: {\n\t\t\t\ttype: DataTypes.INTEGER,\n\t\t\t\tallowNull: false,\n\t\t\t\tdefault: 0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\ttimestamps: false,\n\t\t},\n\t);\n};\n```\n\nThe junction table will link `user_id` and the `id` of the currency shop together. It also contains an `amount` number, which indicates how many of that item a user has.\n\n## Initialize database\n\nNow that the models are defined, you should create them in your database to access them in the bot file. We ran the sync inside the `ready` event in the previous tutorial, which is entirely unnecessary since it only needs to run once. You can make a file to initialize the database and never touch it again unless you want to remake the entire database.\n\nCreate a file called `dbInit.js` in the base directory (_not_ in the `models` folder).\n\n<Callout type=\"error\" title=\"Attention! Security Risk!\">\n\t**Make sure you use version 5 or later of Sequelize!** As used in this guide, version 4 and earlier will pose a\n\tsecurity threat. You can read more about this issue on the [Sequelize issue\n\ttracker](https://github.com/sequelize/sequelize/issues/7310).\n</Callout>\n\n```js title=\"dbInit.js\" lineNumbers\nconst Sequelize = require('sequelize');\n\nconst sequelize = new Sequelize('database', 'username', 'password', {\n\thost: 'localhost',\n\tdialect: 'sqlite',\n\tlogging: false,\n\tstorage: 'database.sqlite',\n});\n\nconst CurrencyShop = require('./models/CurrencyShop.js')(sequelize, Sequelize.DataTypes);\nrequire('./models/Users.js')(sequelize, Sequelize.DataTypes);\nrequire('./models/UserItems.js')(sequelize, Sequelize.DataTypes);\n\nconst force = process.argv.includes('--force') || process.argv.includes('-f');\n\nsequelize\n\t.sync({ force })\n\t.then(async () => {\n\t\tconst shop = [\n\t\t\t// [!code word:upsert]\n\t\t\tCurrencyShop.upsert({ name: 'Tea', cost: 1 }),\n\t\t\tCurrencyShop.upsert({ name: 'Coffee', cost: 2 }),\n\t\t\tCurrencyShop.upsert({ name: 'Cake', cost: 5 }),\n\t\t];\n\n\t\tawait Promise.all(shop);\n\t\tconsole.log('Database synced');\n\n\t\tsequelize.close();\n\t})\n\t.catch(console.error);\n```\n\nHere you pull the two models and the junction table from the respective model declarations, sync them, and add items to the shop.\n\nA new function here is the `.upsert()` function. It's a portmanteau for **up**date or in**sert**. `upsert` is used here to avoid creating duplicates if you run this file multiple times. That shouldn't happen because `name` is defined as _unique_, but there's no harm in being safe. Upsert also has a nice side benefit: if you adjust the cost, the respective item should also have their cost updated.\n\n<Callout>\n\tExecute `node dbInit.js` to create the database tables. Unless you make a change to the models, you'll never need to\n\ttouch the file again. If you change a model, you can execute `node dbInit.js --force` or `node dbInit.js -f` to force\n\tsync your tables. It's important to note that this **will** empty and remake your model tables.\n</Callout>\n\n## Create associations\n\nNext, add the associations to the models. Create a file named `dbObjects.js` in the base directory, next to `dbInit.js`.\n\n```js title=\"dbObjects.js\" lineNumbers\nconst Sequelize = require('sequelize');\n\nconst sequelize = new Sequelize('database', 'username', 'password', {\n\thost: 'localhost',\n\tdialect: 'sqlite',\n\tlogging: false,\n\tstorage: 'database.sqlite',\n});\n\nconst Users = require('./models/Users.js')(sequelize, Sequelize.DataTypes);\nconst CurrencyShop = require('./models/CurrencyShop.js')(sequelize, Sequelize.DataTypes);\nconst UserItems = require('./models/UserItems.js')(sequelize, Sequelize.DataTypes);\n\nUserItems.belongsTo(CurrencyShop, { foreignKey: 'item_id', as: 'item' }); // [!code word:belongsTo]\n\nReflect.defineProperty(Users.prototype, 'addItem', {\n\tvalue: async (item) => {\n\t\tconst userItem = await UserItems.findOne({\n\t\t\t// [!code word:findOne]\n\t\t\twhere: { user_id: this.user_id, item_id: item.id },\n\t\t});\n\n\t\tif (userItem) {\n\t\t\tuserItem.amount += 1;\n\t\t\treturn userItem.save();\n\t\t}\n\n\t\treturn UserItems.create({ user_id: this.user_id, item_id: item.id, amount: 1 });\n\t},\n});\n\nReflect.defineProperty(Users.prototype, 'getItems', {\n\tvalue: () => {\n\t\treturn UserItems.findAll({\n\t\t\t// [!code word:findAll]\n\t\t\twhere: { user_id: this.user_id },\n\t\t\tinclude: ['item'],\n\t\t});\n\t},\n});\n\nmodule.exports = { Users, CurrencyShop, UserItems };\n```\n\nNote that the connection object could be abstracted in another file and had both `dbInit.js` and `dbObjects.js` use that connection file, but it's not necessary to overly abstract things.\n\nAnother new method here is the `.belongsTo()` method. Using this method, you add `CurrencyShop` as a property of `UserItem` so that when you do `userItem.item`, you get the respectively attached item. You use `item_id` as the foreign key so that it knows which item to reference.\n\nYou then add some methods to the `Users` object to finish up the junction: add items to users, and get their current inventory. The code inside should be somewhat familiar from the last tutorial. `.findOne()` is used to get the item if it exists in the user's inventory. If it does, increment it; otherwise, create it.\n\nGetting items is similar; use `.findAll()` with the user's id as the key. The `include` key is for associating the CurrencyShop with the item. You must explicitly tell Sequelize to honor the `.belongsTo()` association; otherwise, it will take the path of the least effort.\n\n## Application code\n\nCreate an `app.js` file in the base directory with the following skeleton code to put it together.\n\n```js title=\"app.js\" lineNumbers\nconst { Op } = require('sequelize');\nconst { Client, codeBlock, Collection, Events, GatewayIntentBits } = require('discord.js');\nconst { Users, CurrencyShop } = require('./dbObjects.js');\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages] });\nconst currency = new Collection();\n\nclient.once(Events.ClientReady, (readyClient) => {\n\tconsole.log(`Ready! Logged in as ${readyClient.user.tag}`);\n});\n\nclient.on(Events.MessageCreate, async (message) => {\n\tif (message.author.bot) return;\n\taddBalance(message.author.id, 1);\n});\n\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tconst { commandName } = interaction;\n\t// ...\n});\n\nclient.login('your-token-goes-here');\n```\n\nNothing special about this skeleton. You import the Users and CurrencyShop models from our `dbObjects.js` file and add a currency Collection. Every time someone talks, add 1 to their currency count. The rest is just standard discord.js code and a simple if/else command handler. A Collection is used for the `currency` variable to cache individual users' currency, so you don't have to hit the database for every lookup. An if/else handler is used here, but you can put it in a framework or command handler as long as you maintain a reference to the models and the currency collection.\n\n### Helper methods\n\n```js title=\"app.js\" lineNumbers=5\n// ...\nconst client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages] });\nconst currency = new Collection();\n\nasync function addBalance(id, amount) {\n\t// [!code ++:18]\n\tconst user = currency.get(id);\n\n\tif (user) {\n\t\tuser.balance += Number(amount);\n\t\treturn user.save();\n\t}\n\n\tconst newUser = await Users.create({ user_id: id, balance: amount });\n\tcurrency.set(id, newUser);\n\n\treturn newUser;\n}\n\nfunction getBalance(id) {\n\tconst user = currency.get(id);\n\treturn user ? user.balance : 0;\n}\n```\n\nThis defines the `addBalance()` helper function, since it'll be used quite frequently. A `getBalance()` function is also defined, to ensure that a number is always returned.\n\n### Ready event data sync\n\n```js title=\"app.js\"\nclient.once(Events.ClientReady, async (readyClient) => {\n\tconst storedBalances = await Users.findAll(); // [!code ++:2]\n\tstoredBalances.forEach((b) => currency.set(b.user_id, b));\n\n\tconsole.log(`Ready! Logged in as ${readyClient.user.tag}!`);\n});\n```\n\nIn the ready event, sync the currency collection with the database for easy access later.\n\n### Show user balance\n\n```js title=\"app.js\"\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tconst { commandName } = interaction;\n\n\tif (commandName === 'balance') {\n\t\t// [!code ++:5]\n\t\tconst target = interaction.options.getUser('user') ?? interaction.user;\n\n\t\treturn interaction.reply(`${target.tag} has ${getBalance(target.id)}💰`); // [!code word:getBalance]\n\t}\n});\n```\n\nNothing tricky here. The `getBalance()` function is used to show either the author's or the mentioned user's balance.\n\n### Show user inventory\n\n```js title=\"app.js\"\nif (commandName === 'balance') {\n\t// ...\n} // [!code --]\n} else if (commandName === 'inventory') { // [!code ++:9]\n\tconst target = interaction.options.getUser('user') ?? interaction.user;\n\tconst user = await Users.findOne({ where: { user_id: target.id } });\n\tconst items = await user.getItems();\n\n\tif (!items.length) return interaction.reply(`${target.tag} has nothing!`);\n\n\treturn interaction.reply(`${target.tag} currently has ${items.map((i) => `${i.amount} ${i.item.name}`).join(', ')}`);\n}\n```\n\nThis is where you begin to see the power of associations. Even though users and the shop are different tables, and the data is stored separately, you can get a user's inventory by looking at the junction table and join it with the shop; no duplicated item names that waste space!\n\n### Transfer currency to another user\n\n```js title=\"app.js\"\nif (commandName === 'balance') {\n\t// ...\n} else if (commandName === 'inventory') // [!code focus:16]\n\t// ... /\n} // [!code --]\n} else if (commandName === 'transfer') { // [!code ++:13]\n\tconst currentAmount = getBalance(interaction.user.id);\n\tconst transferAmount = interaction.options.getInteger('amount');\n\tconst transferTarget = interaction.options.getUser('user');\n\n\tif (transferAmount > currentAmount) return interaction.reply(`Sorry ${interaction.user}, you only have ${currentAmount}.`);\n\tif (transferAmount <= 0) return interaction.reply(`Please enter an amount greater than zero, ${interaction.user}.`);\n\n\taddBalance(interaction.user.id, - transferAmount); // [!code word:addBalance]\n\taddBalance(transferTarget.id, transferAmount);\n\n\treturn interaction.reply(`Successfully transferred ${transferAmount}💰 to ${transferTarget.tag}. Your current balance is ${getBalance(interaction.user.id)}💰`); // [!code word:getBalance]\n}\n```\n\nAs a bot creator, you should always be thinking about how to make the user experience better. Good UX makes users less frustrated with your commands. If your inputs are different types, don't make them memorize which parameters come before the other.\n\n`addBalance()` is used for both removing and adding currency. Since transfer amounts below zero are disallowed, it's safe to apply the transfer amount's additive inverse to their balance.\n\n### Buying an item\n\n```js title=\"app.js\"\nif (commandName === 'balance') {\n\t// ...\n} else if (commandName === 'inventory')\n\t// ... /\n} else if (commandName === 'transfer') {\n\t// ...\n} // [!code --]\n} else if (commandName === 'buy') { // [!code ++:15]\n\tconst itemName = interaction.options.getString('item');\n\tconst item = await CurrencyShop.findOne({ where: { name: { [Op.like]: itemName } } });\n\n\tif (!item) return interaction.reply(`That item doesn't exist.`);\n\tif (item.cost > getBalance(interaction.user.id)) {\n\t\treturn interaction.reply(`You currently have ${getBalance(interaction.user.id)}, but the ${item.name} costs ${item.cost}!`);\n\t}\n\n\tconst user = await Users.findOne({ where: { user_id: interaction.user.id } });\n\taddBalance(interaction.user.id, -item.cost);\n\tawait user.addItem(item);\n\n\treturn interaction.reply(`You've bought: ${item.name}.`);\n}\n```\n\nFor users to search for an item without caring about the letter casing, you can use the `$iLike` modifier when looking for the name. Keep in mind that this may be slow if you have millions of items, so please don't put a million items in your shop.\n\n### Display the shop\n\n```js title=\"app.js\"\nif (commandName === 'balance') {\n\t// ...\n} else if (commandName === 'inventory')\n\t// ... /\n} else if (commandName === 'transfer') {\n\t// ...\n} else if (commandName === 'buy') { // [!code focus:8]\n\t// ...\n} // [!code --]\n} else if (commandName === 'shop') { // [!code ++:4]\n\tconst items = await CurrencyShop.findAll(); // [!code word:findAll]\n\treturn interaction.reply(codeBlock(items.map(i => `${i.name}: ${i.cost}💰`).join('\\n')));\n}\n```\n\nThere's nothing special here; just a regular `.findAll()` to get all the items in the shop and `.map()` to transform that data into something nice looking.\n\n### Display the leaderboard\n\n```js title=\"app.js\"\nif (commandName === 'balance') {\n\t// ...\n} else if (commandName === 'inventory')\n\t// ... /\n} else if (commandName === 'transfer') {\n\t// ...\n} else if (commandName === 'buy') {\n\t// ...\n} else if (commandName === 'shop') { // [!code focus:14]\n\t// ...\n} // [!code --]\n} else if (commandName === 'leaderboard') { // [!code ++:11]\n\treturn interaction.reply(\n\t\tcodeBlock(\n\t\t\tcurrency.sort((a, b) => b.balance - a.balance)\n\t\t\t\t.filter(user => client.users.cache.has(user.user_id))\n\t\t\t\t.first(10)\n\t\t\t\t.map((user, position) => `(${position + 1}) ${(client.users.cache.get(user.user_id).tag)}: ${user.balance}💰`)\n\t\t\t\t.join('\\n'),\n\t\t),\n\t);\n}\n```\n\nNothing extraordinary here either. You could query the database for the top ten currency holders, but since you already have access to them locally inside the `currency` variable, you can sort the Collection and use `.map()` to display it in a friendly format. The filter is in case the users no longer exist in the bot's cache.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/sequelize/index.mdx",
    "content": "---\ntitle: Sequelize\n---\n\nSequelize is an object-relational-mapper, which means you can write a query using objects and have it run on almost any other database system that Sequelize supports.\n\n### Why use an ORM?\n\nThe main benefit of using an ORM like Sequelize is that it allows you to write code that virtually looks like native JavaScript. As a side benefit, an ORM will enable you to write code that can run in almost every database system. Although databases generally adhere very closely to SQL, they each have their slight nuances and differences. You can create a database-agnostic query using an ORM that works on multiple database systems.\n\n## A simple tag system\n\nFor this tutorial, we will create a simple tag system that will allow you to add a tag, output a tag, edit a tag, show tag info, list tags, and delete a tag.  \nTo begin, you should install Sequelize into your discord.js project. We will explain SQlite as the first storage engine and show how to use other databases later. Note that you will need Node 7.6 or above to utilize the `async/await` operators.\n\n### Installing and using Sequelize\n\nCreate a new project folder and run the following:\n\n```sh tab=\"npm\"\nnpm install discord.js sequelize sqlite3\n```\n\n```sh tab=\"yarn\"\nyarn add discord.js sequelize sqlite3\n```\n\n```sh tab=\"pnpm\"\npnpm install discord.js sequelize sqlite3\n```\n\n```sh tab=\"bun\"\nbun add discord.js sequelize sqlite3\n```\n\n<Callout type=\"error\" title=\"Attention! Security Risk!\">\n\t**Make sure you use version 5 or later of Sequelize!** As used in this guide, version 4 and earlier will pose a\n\tsecurity threat. You can read more about this issue on the [Sequelize issue\n\ttracker](https://github.com/sequelize/sequelize/issues/7310).\n</Callout>\n\n<Callout>\n\tThis section will still work with any provider supported by sequelize. We recommend PostgreSQL for larger applications.\n\n    Do note that \"large\" here should be interpreted as absolutely massive. Sqlite is used at scale by many companies and products you use every single day. The slight overhead should not be noticeable for the application of a Discord bot at all unless you are dealing with super complicated queries or are using specific features that do not exist in sqlite.\n\n    You can find out if sqlite might be a good choice for your project (it very likely is) by reading [their own article](https://www.sqlite.org/whentouse.html) on the topic.\n\n</Callout>\n\nAfter you have installed discord.js and Sequelize, you can start with the following skeleton code. The comment labels will tell you where to insert code later on.\n\n```js title=\"sequelize-example.js\"\n// Require Sequelize\nconst Sequelize = require('sequelize');\n// Require the necessary discord.js classes\nconst { Client, Events, GatewayIntentBits } = require('discord.js');\n\n// Create a new client instance\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\n// When the client is ready, run this code (only once)\nclient.once(Events.ClientReady, (readyClient) => {\n\tconsole.log(`Ready! Logged in as ${readyClient.user.tag}`);\n});\n\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tconst { commandName } = interaction;\n\t// ...\n});\n\n// Login to Discord with your client's token\nclient.login('your-token-goes-here');\n```\n\n### Connection information\n\nThe first step is to define the connection information. It should look something like this:\n\n```js title=\"sequelize-example.js\"\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\n// [!code ++:7]\nconst sequelize = new Sequelize('database', 'user', 'password', {\n\thost: 'localhost',\n\tdialect: 'sqlite',\n\tlogging: false,\n\t// SQLite only\n\tstorage: 'database.sqlite',\n});\n```\n\n- `host` tells Sequelize where to look for the database. For most systems, the host will be localhost, as the database usually resides with the application. If you have a remote database, however, then you can set it to that connection address. Otherwise, don't touch this unless you know what you're doing.\n- `dialect` refers to the database engine you are going to use. For this tutorial, it will be sqlite.\n- `logging` enables verbose output from Sequelize–useful for when you are trying to debug. You can disable it by setting it to `false`.\n- `storage` is a sqlite-only setting because sqlite is the only database that stores all its data to a single file.\n\n### Creating the model\n\nIn any relational database, you need to create tables to store your data. This simple tag system will use four fields. The table in the database will look something like this:\n\n| name      | description    | username | usage_count |\n| --------- | -------------- | -------- | ----------- |\n| bob       | is the best    | bob      | 0           |\n| tableflip | (╯°□°）╯︵ ┻━┻ | joe      | 8           |\n\nTo do that in Sequelize, define a model based on this structure below the connection information, as shown below, after the `sequelize` initialization.\n\n```js title=\"sequelize-example.js\"\n// ...\n\nconst sequelize = new Sequelize('database', 'user', 'password', {\n\thost: 'localhost',\n\tdialect: 'sqlite',\n\tlogging: false,\n\tstorage: 'database.sqlite',\n});\n\n// [!code ++:21] [!code focus:24]\n/*\n * equivalent to: CREATE TABLE tags(\n * name VARCHAR(255) UNIQUE,\n * description TEXT,\n * username VARCHAR(255),\n * usage_count  INT NOT NULL DEFAULT 0\n * );\n */\n// [!code word:define]\nconst Tags = sequelize.define('tags', {\n\tname: {\n\t\ttype: Sequelize.STRING,\n\t\tunique: true,\n\t},\n\tdescription: Sequelize.TEXT,\n\tusername: Sequelize.STRING,\n\tusage_count: {\n\t\ttype: Sequelize.INTEGER,\n\t\tdefaultValue: 0,\n\t\tallowNull: false,\n\t},\n});\n\n// ...\n```\n\nThe model mirrors very closely what the database defines. There will be a table with four fields called `name`, `description`, `username`, and `usage_count`.\n\n`sequelize.define()` takes two parameters. `'tags'` are passed as the name of our table, and an object that represents the table's schema in key-value pairs. Keys in the object become the model's attributes, and the values describe the attributes.\n\n- `type` refers to what kind of data this attribute should hold. The most common types are number, string, and date, but other data types are available depending on the database.\n- `unique: true` will ensure that this field will never have duplicated entries. Duplicate tag names are disallowed in this database.\n- `defaultValue` allows you to set a fallback value if there's no initial value during the insert.\n- `allowNull` is not all that important, but this will guarantee in the database that the attribute is never unset. You could potentially set it to be a blank or empty string, but it has to be _something_.\n\n<Callout>\n\t`Sequelize.STRING` vs. `Sequelize.TEXT`: In most database systems, the string's length is a fixed length for\n\tperformance reasons. Sequelize defaults this to 255. Use STRING if your input has a max length, and use TEXT if it\n\tdoes not. For sqlite, there is no unbounded string type, so it will not matter which one you pick.\n</Callout>\n\n### Syncing the model\n\nNow that your structure is defined, you need to make sure the model exists in the database. To make sure the bot is ready and all the data you might need has arrived, add this line in your code.\n\n```js title=\"sequelizeexample.ts\"\nclient.once(Events.ClientReady, (readyClient) => {\n\tTags.sync(); // [!code ++] [!code word:sync]\n\tconsole.log(`Logged in as ${readyClient.user.tag}!`);\n});\n```\n\nThe table does not get created until you `sync` it. The schema you defined before was building the model that lets Sequelize know how the data should look. For testing, you can use `Tags.sync({ force: true })` to recreate the table every time on startup. This way, you can get a blank slate each time.\n\n### Adding a tag\n\nAfter all this preparation, you can now write your first command! Let's start with the ability to add a tag.\n\n```js title=\"sequelize-example.js\"\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tconst { commandName } = interaction;\n\n\t// [!code ++:21]\n\tif (commandName === 'addtag') {\n\t\tconst tagName = interaction.options.getString('name');\n\t\tconst tagDescription = interaction.options.getString('description');\n\n\t\ttry {\n\t\t\t// equivalent to: INSERT INTO tags (name, description, username) values (?, ?, ?);\n\t\t\tconst tag = await Tags.create({\n\t\t\t\tname: tagName,\n\t\t\t\tdescription: tagDescription,\n\t\t\t\tusername: interaction.user.username,\n\t\t\t});\n\n\t\t\treturn interaction.reply(`Tag ${tag.name} added.`);\n\t\t} catch (error) {\n\t\t\tif (error.name === 'SequelizeUniqueConstraintError') {\n\t\t\t\treturn interaction.reply('That tag already exists.');\n\t\t\t}\n\n\t\t\treturn interaction.reply('Something went wrong with adding a tag.');\n\t\t}\n\t}\n});\n```\n\n`Tags.create()` uses the models that you created previously. The `.create()` method inserts some data into the model. You are going to insert a tag name, description, and the author name into the database.\n\nThe `catch (error)` section is necessary for the insert because it will offload checking for duplicates to the database to notify you if an attempt to create a tag that already exists occurs. The alternative is to query the database before adding data and checking if a result returns. If there are no errors or no identical tag is found, only then would you add the data. Of the two methods, it is clear that catching the error is less work for you.\n\nAlthough `if (error.name === 'SequelizeUniqueConstraintError')` was mostly for doing less work, it is always good to handle your errors, especially if you know what types of errors you will receive. This error comes up if your unique constraint is violated, i.e., duplicate values are inserted.\n\n<Callout type=\"warn\">\n\tDo not use catch for inserting new data. Only use it for gracefully handling things that go wrong in your code or\n\tlogging errors.\n</Callout>\n\n### Fetching a tag\n\nNext, let's fetch the inserted tag.\n\n```js title=\"sequelize-example.js\"\nif (commandName === 'addtag') {\n\t// ...\n} // [!code --]\n} else if (command === 'tag') { // [!code ++:15]\n\tconst tagName = interaction.options.getString('name');\n\n\t// equivalent to: SELECT * FROM tags WHERE name = 'tagName' LIMIT 1;\n\tconst tag = await Tags.findOne({ where: { name: tagName } }); // [!code word:findOne]\n\n\tif (tag) {\n\t\t// equivalent to: UPDATE tags SET usage_count = usage_count + 1 WHERE name = 'tagName';\n\t\ttag.increment('usage_count'); // [!code word:increment]\n\n\t\treturn interaction.reply(tag.get('description')); // [!code word:get]\n\t}\n\n\treturn interaction.reply(`Could not find tag: ${tagName}`);\n}\n```\n\nThis is your first query. You are finally doing something with your data; yay!  \n`.findOne()` is how you fetch a single row of data. The `where: { name: tagName }` makes sure you only get the row with the desired tag. Since the queries are asynchronous, you will need to use `await` to fetch it. After receiving the data, you can use `.get()` on that object to grab the data. If no data is received, then you can tell the user that the query returned no data.\n\n### Editing a tag\n\n```js title=\"sequelize-example.js\"\nif (commandName === 'addtag') {\n\t// ...\n} else if (command === 'tag') { // [!code focus:16]\n\t// ...\n} // [!code --]\n} else if (command === 'edittag') { // [!code ++:13]\n\tconst tagName = interaction.options.getString('name');\n\tconst tagDescription = interaction.options.getString('description');\n\n\t// equivalent to: UPDATE tags (description) values (?) WHERE name='?';\n\tconst affectedRows = await Tags.update({ description: tagDescription }, { where: { name: tagName } }); // [!code word:update]\n\n\tif (affectedRows > 0) {\n\t\treturn interaction.reply(`Tag ${tagName} was edited.`);\n\t}\n\n\treturn interaction.reply(`Could not find a tag with name ${tagName}.`);\n}\n```\n\nIt is possible to edit a record by using the `.update()` function. An update returns the number of rows that the `where` condition changed. Since you can only have tags with unique names, you do not have to worry about how many rows may change. Should you get that the query didn't alter any rows, you can conclude that the tag did not exist.\n\n### Display info on a specific tag\n\n```js title=\"sequelize-example.js\"\nif (commandName === 'addtag') {\n\t// ...\n} else if (command === 'tag') {\n\t// ...\n} else if (command === 'edittag') { // [!code focus:15]\n\t// ...\n} // [!code --]\n} else if (commandName == 'taginfo') { // [!code ++:12]\n\tconst tagName = interaction.options.getString('name');\n\n\t// equivalent to: SELECT * FROM tags WHERE name = 'tagName' LIMIT 1;\n\tconst tag = await Tags.findOne({ where: { name: tagName } });\n\n\tif (tag) {\n\t\treturn interaction.reply(`${tagName} was created by ${tag.username} at ${tag.createdAt} and has been used ${tag.usage_count} times.`);\n\t}\n\n\treturn interaction.reply(`Could not find tag: ${tagName}`);\n}\n```\n\nThis section is very similar to the previous command, except you will be showing the tag metadata. `tag` contains your tag object. Notice two things: firstly, it is possible to access the object's properties without the `.get()` function. This is because the object is an instance of a Tag, which you can treat as an object and not just a row of data.\n\nSecond, you can access a property that was not defined explicitly, `createdAt`. This is because Sequelize automatically adds that column to all tables. Passing another object into the model with `{ createdAt: false }` can disable this feature, but in this case, it was useful to have.\n\n### Listing all tags\n\nThe next command will enable you to fetch a list of all the created tags.\n\n```js title=\"sequelize-example.js\"\nif (commandName === 'addtag') {\n\t// ...\n} else if (command === 'tag') {\n\t// ...\n} else if (command === 'edittag') {\n\t// ...\n} else if (commandName == 'taginfo') { // [!code focus:10]\n\t// ...\n} // [!code --]\n} else if (command === 'showtags') { // [!code ++:7]\n\t// equivalent to: SELECT name FROM tags;\n\tconst tagList = await Tags.findAll({ attributes: ['name'] }); // [!code word:attributes]\n\tconst tagString = tagList.map(t => t.name).join(', ') || 'No tags set.';\n\n\treturn interaction.reply(`List of tags: ${tagString}`);\n}\n```\n\nHere, you can use the `.findAll()` method to grab all the tag names. Notice that instead of having `where`, the optional field, `attributes`, is set. Setting attributes to name will let you get _only_ the names of tags. If you tried to access other fields, like the tag author, you would get an error.\n\nIf left blank, it will fetch _all_ of the associated column data. It will not affect the results returned, but from a performance perspective, you should only grab the necessary data. If no results return, `tagString` will default to 'No tags set'.\n\n### Deleting a tag\n\n```js title=\"sequelize-example.js\"\nif (commandName === 'addtag') {\n\t// ...\n} else if (command === 'tag') {\n\t// ...\n} else if (command === 'edittag') {\n\t// ...\n} else if (commandName == 'taginfo') {\n\t// ...\n} else if (command === 'showtags') { // [!code focus:11]\n\t// ...\n}// [!code --]\n} else if (command === 'deletetag') { // [!code ++:9]\n\tconst tagName = interaction.options.getString('name');\n\t// equivalent to: DELETE from tags WHERE name = ?;\n\tconst rowCount = await Tags.destroy({ where: { name: tagName } }); // [!code word:destroy]\n\n\tif (!rowCount) return interaction.reply('That tag doesn\\'t exist.');\n\n\treturn interaction.reply('Tag deleted.');\n}\n```\n\n`.destroy()` runs the delete operation. The operation returns a count of the number of affected rows. If it returns with a value of 0, then nothing was deleted, and that tag did not exist in the database in the first place.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/sharding/additional-information.mdx",
    "content": "---\ntitle: Additional Information\n---\n\n<Callout>This page is a follow-up and bases its code on [the previous page](./).</Callout>\n\nHere we will topic some extra topics about sharding that might have raised concerns.\n\n## Legend\n\n- `manager` is an instance of `ShardingManager`, e.g. `const manager = new ShardingManager(file, options);`\n- `client.shard` refers to the current shard.\n\n## Shard messages\n\nFor shards to communicate, they have to send messages to one another, as they each have another process. You must wait for each shard to finish spawning before you can listen to their events, otherwise `ShardingManager#shards` will be an empty `Collection`. You can listen for these messages on the individual shards by adding the following lines in your `index.js` file:\n\n```js title=\"index.js\"\nmanager\n\t.spawn()\n\t.then((shards) => {\n\t\tshards.forEach((shard) => {\n\t\t\tshard.on('message', (message) => {\n\t\t\t\tconsole.log(`Shard[${shard.id}] : ${message._eval} : ${message._result}`);\n\t\t\t});\n\t\t});\n\t})\n\t.catch(console.error);\n```\n\nAs the property names imply, the `_eval` property is what the shard is attempting to evaluate, and the `_result` property is the output of said evaluation. However, these properties are only guaranteed if a _shard_ is sending a message. There will also be an `_error` property, should the evaluation have thrown an error.\n\nYou can also send messages via `process.send('hello')`, which would not contain the same information. This is why the `.message` property's type is declared as `*` in the `Shard#message` documentation.\n\n## Specific shards\n\nThere might be times where you want to target a specific shard. An example would be to kill a specific shard that isn't working as intended. You can achieve this by taking the following snippet (in a command, preferably):\n\n<Callout>\n\t`ShardClientUtil#ids` can hold multiple ids. If you use the default sharding manager, the `.ids` array will only have\n\tone entry.\n</Callout>\n\n```js\nclient.shard.broadcastEval((c) => {\n\tif (c.shard.ids.includes(0)) process.exit();\n});\n```\n\nIf you're using something like [PM2](http://pm2.keymetrics.io/) or [Forever](https://github.com/foreverjs/forever), this is an easy way to restart a specific shard. Remember, `ShardClientUtil#broadcastEval` sends a message to **all** shards, so you have to check if it's on the shard you want.\n\n## `ShardingManager#shardArgs` and `ShardingManager#execArgv`\n\nConsider the following example of creating a new `ShardingManager` instance:\n\n```js\nconst manager = new ShardingManager('./bot.js', {\n\texecArgv: ['--trace-warnings'],\n\tshardArgs: ['--ansi', '--color'],\n\ttoken: 'your-token-goes-here',\n});\n```\n\nThe `execArgv` property is what you would usually pass to Node without sharding, e.g.:\n\n```sh\nnode --trace-warnings bot.js\n```\n\nYou can find a list of command-line options for Node [here](https://nodejs.org/api/cli.html).\n\nThe `shardArgs` property is what you would usually pass to your bot without sharding, e.g.:\n\n```sh\nnode bot.js --ansi --color\n```\n\nYou can access them later as usual via `process.argv`, which contains an array of executables, your main file, and the command-line arguments used to execute the script.\n\n## Eval arguments\n\nThere may come the point where you will want to pass arguments from the outer scope into a `.broadcastEval()` call. The `context` parameter is useful for this purpose.\n\n```js\n// [!code word:context]\nfunction funcName(client, context) {\n\t// ...\n}\n\n// Evaluate on all shards\nclient.shard.broadcastEval(funcName, {\n\tcontext: { arg: 'arg' },\n});\n\n// Evaluate on a specific shard\nclient.shard.broadcastEval(funcName, {\n\tshard: 0,\n\tcontext: { arg: 'arg' },\n});\n```\n\nThe `BroadcastEvalOptions` typedef was introduced in discord.js v13 as the second parameter in `.broadcastEval()`. It accepts two properties: `shard` and `context`. The `context` property will be sent as the second argument to your function.\n\nIn this small snippet, an argument is passed to the `funcName` function through this parameter.\nThe function will receive the arguments as an object as the second parameter.\n\n<Callout>\n\tThe `context` option only accepts properties which are JSON-serializable. This means you cannot pass complex data\n\ttypes in the context directly. For example, if you sent a `User` instance, the function would receive the raw data\n\tobject.\n</Callout>\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/sharding/extended.mdx",
    "content": "---\ntitle: Advanced Sharding\n---\n\n<Callout type=\"warn\">\n\tThis page is a follow-up and bases its code on [the previous page](./additional-information), which assumes knowledge\n\tof arguments and passing functions.\n</Callout>\n\n## Sending messages across shards\n\nLet's start with the basic usage of shards. At some point in bot development, you might have wanted to send a message to another channel, which may or may not necessarily be on the same guild, which means it may or may not be on the same shard. To achieve this, you will need to go back to your friend `.broadcastEval()` and try every shard for the desired channel. Suppose you have the following code in your `interactionCreate` event:\n\n```js title=\"bot.js\"\nclient.on(Events.InteractionCreate, (interaction) => {\n\t// ...\n\t// [!code focus:9]\n\tif (commandName === 'send') {\n\t\tconst id = interaction.options.getString('destination');\n\t\tconst channel = client.channels.cache.get(id);\n\n\t\tif (!channel) return interaction.reply('I could not find such a channel.');\n\n\t\tchannel.send('Hello!');\n\t\treturn interaction.reply(`I have sent a message to channel: \\`${id}\\`!`);\n\t}\n});\n```\n\nThis will never work for a channel that lies on another shard. So, let's remedy this.\n\n<Callout>\n\t`ShardClientUtil#ids` can hold multiple ids. If you use the default sharding manager, the `.ids` array will only have\n\tone entry.\n</Callout>\n\n```js title=\"bot.js\"\nif (commandName === 'send') {\n\tconst id = interaction.options.getString('destination');\n\treturn client.shard\n\t\t.broadcastEval(\n\t\t\tasync (c, { channelId }) => {\n\t\t\t\tconst channel = c.channels.cache.get(channelId);\n\t\t\t\tif (channel) {\n\t\t\t\t\tawait channel.send(`This is a message from shard ${c.shard.ids.join(',')}!`);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\t{ context: { channelId: id } },\n\t\t)\n\t\t.then(console.log);\n}\n```\n\nIf all is well, you should notice an output like `[false, true, false, false]`. If it is not clear why `true` and `false` are hanging around, the last expression of the eval statement will be returned. You will want this if you want any feedback from the results. Now that you have observed said results, you can adjust the command to give yourself proper feedback, like so:\n\n```js title=\"bot.js\"\nreturn client.shard\n\t.broadcastEval((c) => {\n\t\t// ...\n\t})\n\t.then((sentArray) => {\n\t\t// Search for a non falsy value before providing feedback\n\t\tif (!sentArray.includes(true)) {\n\t\t\treturn message.reply('I could not find such a channel.');\n\t\t}\n\t\treturn message.reply(`I have sent a message to channel: \\`${id}\\`!`);\n\t});\n```\n\nAnd that's it for this section! You have successfully communicated across all of your shards.\n\n## Using functions continued\n\nIf you remember, there was a brief mention of passing functions through `.broadcastEval()`, but no super clear description of exactly how to go about it. Well, fret not, for this section will cover it! Suppose you have the following code in your `interactionCreate` event:\n\n```js title=\"bot.js\"\nclient.on(Events.InteractionCreate, (interaction) => {\n\t// ...\n\t// [!code focus:5]\n\tif (commandName === 'emoji') {\n\t\tconst emojiId = interaction.options.getString('emoji');\n\t\tconst emoji = client.emojis.cache.get(emojiId);\n\n\t\treturn interaction.reply(`I have found an emoji ${emoji}!`);\n\t}\n});\n```\n\nThe aforementioned code will essentially search through `client.emojis.cache` for the provided id, which will be given provided by the `emoji` option. However, with sharding, you might notice it doesn't search through all the client's emojis. As mentioned in an earlier section of this guide, the different shards partition the client and its cache. Emojis derive from guilds meaning each shard will have the emojis from all guilds for that shard. The solution is to use `.broadcastEval()` to search all the shards for the desired emoji.\n\nLet's start with a basic function, which will try to grab an emoji from the current client and return it.\n\n```js\nfunction findEmoji(c, { nameOrId }) {\n\treturn c.emojis.cache.get(nameOrId) || c.emojis.cache.find((e) => e.name.toLowerCase() === nameOrId.toLowerCase());\n}\n```\n\nNext, you need to call the function in your command properly. If you recall from [this section](./additional-information#eval-arguments), it is shown there how to pass a function and arguments correctly.\n\n```js\nclient.on(Events.InteractionCreate, (interaction) => {\n\t// ...\n\t// [!code :5]\n\tif (commandName === 'emoji') {\n\t\tconst emojiNameOrId = interaction.options.getString('emoji');\n\n\t\treturn client.shard.broadcastEval(findEmoji, { context: { nameOrId: emojiNameOrId } }).then(console.log);\n\t}\n});\n```\n\nNow, run this code, and you will surely get a result that looks like the following:\n\n```js\n[\n\t{\n\t\tguild: {\n\t\t\tmembers: {},\n\t\t\t// ...\n\t\t\tid: '222078108977594368',\n\t\t\tname: 'discord.js Official',\n\t\t\ticon: '6e4b4d1a0c7187f9fd5d4976c50ac96e',\n\t\t\t// ...\n\t\t\temojis: {},\n\t\t},\n\t\tid: '383735055509356544',\n\t\tname: 'duckSmug',\n\t\trequiresColons: true,\n\t\tmanaged: false,\n\t\tanimated: false,\n\t\t_roles: [],\n\t},\n];\n```\n\nWhile this result isn't _necessarily_ bad or incorrect, it's simply a raw object that got `JSON.parse()`'d and `JSON.stringify()`'d over, so all of the circular references are gone. More importantly, The object is no longer a true `GuildEmoji` object as provided by discord.js. _This means none of the convenience methods usually provided to you are available._ If this is a problem for you, you will want to handle the item _inside_ the `broadcastEval`. Conveniently, the `findEmoji` function will be run, so you should execute your relevant methods there, before the object leaves the context.\n\n```js\nfunction findEmoji(c, { nameOrId }) {\n\tconst emoji =\n\t\tc.emojis.cache.get(nameOrId) || c.emojis.cache.find((e) => e.name.toLowerCase() === nameOrId.toLowerCase());\n\tif (!emoji) return null;\n\t// If you wanted to delete the emoji with discord.js, this is where you would do it. Otherwise, don't include this code.\n\temoji.delete();\n\treturn emoji;\n}\n```\n\nWith all that said and done, usually you'll want to display the result, so here is how you can go about doing that:\n\n```js\nreturn client.shard.broadcastEval(findEmoji, { context: { nameOrId: emojiNameOrId } }).then((emojiArray) => {\n\t// Locate a non falsy result, which will be the emoji in question\n\tconst foundEmoji = emojiArray.find((emoji) => emoji);\n\tif (!foundEmoji) return message.reply('I could not find such an emoji.');\n\treturn message.reply(\n\t\t`I have found the ${foundEmoji.animated ? `<${foundEmoji.identifier}>` : `<:${foundEmoji.identifier}> emoji!`}!`,\n\t);\n});\n```\n\nAnd that's all! The emoji should have pretty-printed in a message, as you'd expect.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/sharding/index.mdx",
    "content": "---\ntitle: App Sharding\n---\n\n## When to shard\n\nBefore you dive into this section, please note that sharding may not be necessary for you. Sharding is only **required at 2,500 guilds** — at that point, Discord will not allow your bot to login without sharding. With that in mind, you should consider this when your bot is around 2,000 guilds, which should be enough time to get this working. Contrary to popular belief, sharding itself is very simple. It can be complicated depending on your bot's needs, however.\n\nIf your bot is in a total of 2,000 or more servers, then please continue with this guide. Otherwise, it may be a good idea to wait until then.\n\n<Callout>\n\tSharding is only relevant if you app uses gateway events. For webhook callbacks, this is completely irrelevant!\n</Callout>\n\n## How does sharding work?\n\nAs an application grows large, a developer may find it necessary to split their process to run parallel to maximize efficiency. On a much larger scale of things, the developer might notice their process slow down, amongst other problems.\n[Check out the official Discord documentation on the topic.](https://discord.com/developers/docs/topics/gateway#sharding)\n\n<Callout type=\"warn\">\n\tThis guide only explains the basics of sharding using the built-in `ShardingManager`, which can run shards as separate processes or threads on a single machine.\n\n    If you need to scale beyond that (e.g., running shards on multiple machines/containers), you can still do it with discord.js by passing appropriate options to the Client constructor. Nevertheless, you will be on your own regarding managing shards and sharing information between them.\n\n</Callout>\n\n<Callout>\n\tApart from `ShardingManager`, discord.js also supports a sharding mode known as Internal sharding. Internal sharding creates multiple websocket connections from the same process, and does not require major code changes. To enable it, simply pass `shards: 'auto'` as ClientOptions to the Client constructor.\n\n    However, **internal sharding is not ideal for bigger bots due to high memory usage** of the single main process and will not be further discussed in this guide.\n\n</Callout>\n\n## Sharding file\n\nFirst, you'll need to have a file that you'll be launching from now on, rather than your original `index.js` file. It's highly recommended renaming that to `bot.js` and naming this new file to `index.js` instead. Copy & paste the following snippet into your new `index.js` file.\n\n```js title=\"index.js\" lineNumbers\nconst { ShardingManager } = require('discord.js');\n\nconst manager = new ShardingManager('./bot.js', { token: 'your-token-goes-here' });\n\nmanager.on('shardCreate', (shard) => console.log(`Launched shard ${shard.id}`));\n\nmanager.spawn();\n```\n\nThe above code utilizes the discord.js sharding manager to spawn the recommended amount of shards for your bot. The recommended amount should be approximately 1,000 guilds per shard. Note that you have to attach the event listener to `shardCreate` before calling `.spawn()` to prevent a race condition possibly preventing shard 0 from logging the successful launch. Even though you provide the token here, you will still need to send it over to the main bot file in `client.login()`, so don't forget to do that.\n\n<Callout>\n\tYou can find the methods available for the ShardingManager class `ShardingManager`. Though, you may not be making much\n\tuse of this section, unlike the next feature we will explore, which you may learn about by clicking [this\n\tlink](./sharding/additional-information).\n</Callout>\n\n## Getting started\n\nYou will most likely have to change some code to get your newly sharded bot to work. If your bot is very basic, then you're in luck! We assume you probably have some form of a `stats` command, by which you can quickly view your bot's statistics, such as its server count. We will use it as an example that needs to adapt to running with shards.\n\nIn this code, you likely have the snippet `client.guilds.cache.size`, which counts the number of _cached_ guilds attached to that client. Since sharding will launch multiple processes, each process (each shard) will now have its subset collection of guilds it is responsible for. This means that your original code will not function as you might expect.\n\nHere is some sample code for a `stats` command, without sharding taken into consideration:\n\n```js title=\"bot.js\" lineNumbers\nconst { Client, Events, GatewayIntentBits } = require('discord.js');\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\nclient.on(Events.InteractionCreate, (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tconst { commandName } = interaction;\n\n\tif (commandName === 'stats') {\n\t\treturn interaction.reply(`Server count: ${client.guilds.cache.size}.`);\n\t}\n});\n\nclient.login('your-token-goes-here');\n```\n\nLet's say your bot is in a total of 3,600 guilds. Using the recommended shard count, you might end up at four shards, each containing approximately 900 guilds. If a guild is on a specific shard (shard #2, for example) and receives this command, the guild count will be close to 900, which is not the \"correct\" number of guilds for your bot. Let's take a look at how to fix that.\n\n## FetchClientValues\n\nOne of the most common sharding utility methods you'll be using is `ShardClientUtil#fetchClientValues`. This method retrieves a property on the Client object of all shards.\n\nTake the following snippet of code:\n\n```js\nclient.shard.fetchClientValues('guilds.cache.size').then(console.log); // [!code word:fetchClientValues]\n```\n\nIf you run it, you will notice an output like `[898, 901, 900, 901]`. You will be correct in assuming that that's the total number of guilds per shard stored in an array in the Promise. This probably isn't the ideal output for guild count, so let's use [Array.reduce()](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) to provide a better output.\n\n<Callout>\n\tIt's highly recommended for you to visit [the\n\tdocumentation](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) to understand\n\thow the `reduce()` method works, as you will probably find great use of it in sharding.\n</Callout>\n\nIn this case, this method iterates through the array and adds each current value to the total amount:\n\n```js\nclient.shard\n\t.fetchClientValues('guilds.cache.size')\n\t.then((results) => {\n\t\tconsole.log(`${results.reduce((acc, guildCount) => acc + guildCount, 0)} total guilds`); // [!code word:reduce]\n\t})\n\t.catch(console.error);\n```\n\nWhile it's a bit unattractive to have more nesting in your commands, it is necessary when not using `async`/`await`. Now, the code at the top should look something like the below:\n\n```js title=\"bot.js\" lineNumbers=5\nclient.on(Events.InteractionCreate, (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tconst { commandName } = interaction;\n\t// [!code focus:9]\n\tif (commandName === 'stats') {\n\t\treturn interaction.reply(`Server count: ${client.guilds.cache.size}.`); // [!code --]\n\t\treturn client.shard // [!code ++:6]\n\t\t\t.fetchClientValues('guilds.cache.size')\n\t\t\t.then((results) => {\n\t\t\t\treturn interaction.reply(`Server count: ${results.reduce((acc, guildCount) => acc + guildCount, 0)}`);\n\t\t\t})\n\t\t\t.catch(console.error);\n\t}\n});\n\n// ...\n```\n\n## BroadcastEval\n\nNext, check out another handy sharding method known as `ShardClientUtil#broadcastEval`. This method makes all of the shards evaluate a given method, which receives a `client` and a `context` argument. The `client` argument refers to the Client object of the shard evaluating it. You can read about the `context` argument [here](./sharding/additional-information#eval-arguments).\n\n```js\nclient.shard\n\t.broadcastEval((c) =>\n\t\tc.guilds.cache // [!code word:broadcastEval]\n\t\t\t.reduce((acc, guild) => acc + guild.memberCount, 0),\n\t)\n\t.then(console.log);\n```\n\nThis will run the code given to `broadcastEval` on each shard and return the results to the Promise as an array, once again. You should see something like `[9001, 16658, 13337, 15687]` logged. The code sent to each shard adds up the `memberCount` property of every guild that shard is handling and returns it, so each shard's total guild member count. Of course, if you want to total up the member count of _every_ shard, you can do the same thing again on the Promise results.\n\n```js\nclient.shard\n\t.broadcastEval((c) => c.guilds.cache.reduce((acc, guild) => acc + guild.memberCount, 0)) // [!code word:broadcastEval]\n\t.then((results) => {\n\t\treturn interaction.reply(`Total member count: ${results.reduce((acc, memberCount) => acc + memberCount, 0)}`);\n\t})\n\t.catch(console.error);\n```\n\n## Putting them together\n\nYou'd likely want to output both pieces of information in the stats command. You can combine these two results with [Promise.all()](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise/all):\n\n```js\nconst promises = [\n\tclient.shard.fetchClientValues('guilds.cache.size'),\n\tclient.shard.broadcastEval((c) => c.guilds.cache.reduce((acc, guild) => acc + guild.memberCount, 0)),\n];\n\nPromise.all(promises) // [!code word:all]\n\t.then((results) => {\n\t\tconst totalGuilds = results[0].reduce((acc, guildCount) => acc + guildCount, 0);\n\t\tconst totalMembers = results[1].reduce((acc, memberCount) => acc + memberCount, 0);\n\t\treturn interaction.reply(`Server count: ${totalGuilds}\\nMember count: ${totalMembers}`);\n\t})\n\t.catch(console.error);\n```\n\n`Promise.all()` runs every Promise you pass inside an array in parallel and waits for each to finish before returning their results simultaneously. The result is an array that corresponds with the array of Promises you pass–so the first result element will be from the first Promise. With that, your stats command should look something like this:\n\n```js title=\"bot.js\" lineNumbers=5\nclient.on(Events.InteractionCreate, (interaction) => {\n\t// ...\n\t// [!code focus:21]\n\tif (commandName === 'stats') {\n\t\treturn client.shard // [!code --:6]\n\t\t\t.fetchClientValues('guilds.cache.size')\n\t\t\t.then((results) => {\n\t\t\t\treturn interaction.reply(`Server count: ${results.reduce((acc, guildCount) => acc + guildCount, 0)}`);\n\t\t\t})\n\t\t\t.catch(console.error);\n\n\t\t// [!code ++:12]\n\t\tconst promises = [\n\t\t\tclient.shard.fetchClientValues('guilds.cache.size'),\n\t\t\tclient.shard.broadcastEval((c) => c.guilds.cache.reduce((acc, guild) => acc + guild.memberCount, 0)),\n\t\t];\n\n\t\treturn Promise.all(promises)\n\t\t\t.then((results) => {\n\t\t\t\tconst totalGuilds = results[0].reduce((acc, guildCount) => acc + guildCount, 0);\n\t\t\t\tconst totalMembers = results[1].reduce((acc, memberCount) => acc + memberCount, 0);\n\t\t\t\treturn interaction.reply(`Server count: ${totalGuilds}\\nMember count: ${totalMembers}`);\n\t\t\t})\n\t\t\t.catch(console.error);\n\t}\n});\n```\n\nThe next section contains additional changes you might want to consider.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/slash-commands/advanced-creation.mdx",
    "content": "---\ntitle: Advanced Command Creation\n---\n\nThe examples we've covered so far have all been fairly simple commands, such as `ping`, `server`, and `user` which all have standard static responses. However, there's much more you can do with the full suite of slash command tools!\n\n## Adding options\n\nApplication commands can have additional `options`. Think of these options as arguments to a function, and as a way for the user to provide the additional information the command requires.\n\n<Callout>\n\tIf you've already added options to your commands and need to know how to receive and parse them, refer to the [Parsing\n\toptions](./parsing-options) page in this section of the guide.\n</Callout>\n\nOptions require at minimum a name and description. The same restrictions apply to option names as slash command names - 1-32 characters containing no capital letters, spaces, or symbols other than `-` and `_`. You can specify them as shown in the `echo` command below, which prompt the user to enter a String for the `input` option.\n\n```js title=\"commands/utility/echo.js\"\nconst { SlashCommandBuilder } = require('discord.js');\n\nconst data = new SlashCommandBuilder()\n\t.setName('echo')\n\t.setDescription('Replies with your input!')\n\t.addStringOption((option) => option.setName('input').setDescription('The input to echo back'));\n```\n\n## Option types\n\nBy specifying the `type` of an `ApplicationCommandOption` using the corresponding method you are able to restrict what the user can provide as input, and for some options, leverage the automatic parsing of options into proper objects by Discord.\n\nThe example above uses `addStringOption`, the simplest form of standard text input with no additional validation. By leveraging additional option types, you could change the behavior of this command in many ways, such as using a Channel option to direct the response to a specific channel:\n\n```js title=\"commands/utility/echo.js\"\nconst { SlashCommandBuilder } = require('discord.js');\n\nconst data = new SlashCommandBuilder()\n\t.setName('echo')\n\t.setDescription('Replies with your input!')\n\t.addStringOption((option) => option.setName('input').setDescription('The input to echo back'))\n\t// [!code ++]\n\t.addChannelOption((option) => option.setName('channel').setDescription('The channel to echo into'));\n```\n\nOr a Boolean option to give the user control over making the response ephemeral so only the command author can see the response.\n\n```js title=\"commands/utility/echo.js\"\nconst { SlashCommandBuilder } = require('discord.js');\n\nconst data = new SlashCommandBuilder()\n\t.setName('echo')\n\t.setDescription('Replies with your input!')\n\t.addStringOption((option) => option.setName('input').setDescription('The input to echo back'))\n\t// [!code ++:3]\n\t.addBooleanOption((option) =>\n\t\toption.setName('ephemeral').setDescription('Whether or not the echo should be ephemeral'),\n\t);\n```\n\nListed below is a short description of the different types of options that can be added. For more information, refer to the `add_____Option` methods in the `SlashCommandBuilder` documentation.\n\n- `String`, `Integer`, `Number` and `Boolean` options all accept primitive values of their associated type.\n  - `Integer` only accepts whole numbers.\n  - `Number` accepts both whole numbers and decimals.\n- `User`, `Channel`, `Role` and `Mentionable` options will show a selection list in the Discord interface for their associated type, or will accept a Snowflake (id) as input.\n- `Attachment` options prompt the user to make an upload along with the slash command.\n- `Subcommand` and `SubcommandGroup` options allow you to have branching pathways of subsequent options for your commands - more on that later on this page.\n\n<Callout>\n\tRefer to the Discord API documentation for detailed explanations on the [`SUB_COMMAND` and `SUB_COMMAND_GROUP` option\n\ttypes](https://discord.com/developers/docs/interactions/application-commands#subcommands-and-subcommand-groups).\n</Callout>\n\n## Required options\n\nWith option types covered, you can start looking at additional forms of validation to ensure the data your bot receives is both complete and accurate. The simplest addition is making options required, to ensure the command cannot be executed without a required value. This validation can be applied to options of any type.\n\nReview the `echo` example again and use `setRequired(true)` to mark the `input` option as required.\n\n```js title=\"commands/utility/echo.js\"\nconst { SlashCommandBuilder } = require('discord.js');\n\nconst data = new SlashCommandBuilder()\n\t.setName('echo')\n\t.setDescription('Replies with your input!')\n\t// [!code --]\n\t.addStringOption((option) => option.setName('input').setDescription('The input to echo back')); // [!code --]\n\t// [!code word:setRequired] [!code ++]\n\t.addStringOption((option) => option.setName('input').setDescription('The input to echo back').setRequired(true));\n```\n\n## Choices\n\nThe `String`, `Number`, and `Integer` option types can have `choices`. If you would prefer users select from predetermined values rather than free entry, `choices` can help you enforce this. This is particularly useful when dealing with external datasets, APIs, and similar, where specific input formats are required.\n\n<Callout type=\"warn\">\n\tIf you specify `choices` for an option, they'll be the **only** valid values users can pick!\n</Callout>\n\nSpecify choices by using the `addChoices()` method from within the option builder, such as `SlashCommandBuilder#addStringOption`. Choices require a `name` which is displayed to the user for selection, and a `value` that your bot will receive when that choice is selected, as if the user had typed it into the option manually.\n\nThe `gif` command example below allows users to select from predetermined categories of gifs to send:\n\n```js title=\"commands/fun/gif.js\"\nconst { SlashCommandBuilder } = require('discord.js');\n\nconst data = new SlashCommandBuilder()\n\t.setName('gif')\n\t.setDescription('Sends a random gif!')\n\t.addStringOption((option) =>\n\t\toption\n\t\t\t.setName('category')\n\t\t\t.setDescription('The gif category')\n\t\t\t.setRequired(true)\n\t\t\t// [!code focus:5]\n\t\t\t.addChoices(\n\t\t\t\t{ name: 'Funny', value: 'gif_funny' },\n\t\t\t\t{ name: 'Meme', value: 'gif_meme' },\n\t\t\t\t{ name: 'Movie', value: 'gif_movie' },\n\t\t\t),\n\t);\n```\n\nIf you have too many choices to display (the maximum is 25), you may prefer to provide dynamic choices based on what the user has typed so far. This can be achieved using [autocomplete](./autocomplete).\n\n## Further validation\n\nEven without predetermined choices, additional restrictions can still be applied on otherwise free inputs.\n\n- For `String` options, `setMaxLength()` and `setMinLength()` can enforce length limitations.\n- For `Integer` and `Number` options, `setMaxValue()` and `setMinValue()` can enforce range limitations on the value.\n- For `Channel` options, `addChannelTypes()` can restrict selection to specific channel types, e.g. `ChannelType.GuildText`.\n\nWe'll use these to show you how to enhance your `echo` command from earlier with extra validation to ensure it won't (or at least shouldn't) break when used:\n\n```js title=\"commands/utility/echo.js\"\nconst { SlashCommandBuilder, ChannelType } = require('discord.js');\n\nconst data = new SlashCommandBuilder()\n\t.setName('echo')\n\t.setDescription('Replies with your input!')\n\t// [!code focus:13]\n\t.addStringOption((option) =>\n\t\toption\n\t\t\t.setName('input')\n\t\t\t.setDescription('The input to echo back')\n\t\t\t// Ensure the text will fit in an embed description, if the user chooses that option\n\t\t\t// [!code ++]\n\t\t\t.setMaxLength(2_000),\n\t)\n\t.addChannelOption((option) =>\n\t\toption\n\t\t\t.setName('channel')\n\t\t\t.setDescription('The channel to echo into')\n\t\t\t// Ensure the user can only select a TextChannel for output\n\t\t\t// [!code ++]\n\t\t\t.addChannelTypes(ChannelType.GuildText),\n\t)\n\t.addBooleanOption((option) => option.setName('embed').setDescription('Whether or not the echo should be embedded'));\n```\n\n## Subcommands\n\nSubcommands are available with the `.addSubcommand()` method. This allows you to branch a single command to require different options depending on the subcommand chosen.\n\nWith this approach, you can merge the `user` and `server` information commands from the previous section into a single `info` command with two subcommands. Additionally, the `user` subcommand has a `User` type option for targeting other users, while the `server` subcommand has no need for this, and would just show info for the current guild.\n\n```js title=\"commands/utility/info.js\"\nconst { SlashCommandBuilder } = require('discord.js');\n\nconst data = new SlashCommandBuilder()\n\t.setName('info')\n\t.setDescription('Get info about a user or a server!')\n\t// [!code word:addSubcommand]\n\t.addSubcommand((subcommand) =>\n\t\tsubcommand\n\t\t\t.setName('user')\n\t\t\t.setDescription('Info about a user')\n\t\t\t.addUserOption((option) => option.setName('target').setDescription('The user')),\n\t)\n\t.addSubcommand((subcommand) => subcommand.setName('server').setDescription('Info about the server'));\n```\n\n## Localizations\n\nThe names and descriptions of slash commands can be localized to the user's selected language. You can find the list of accepted locales on the [discord API documentation](https://discord.com/developers/docs/reference#locales).\n\nSetting localizations with `setNameLocalizations()` and `setDescriptionLocalizations()` takes the format of an object, mapping location codes (e.g. `pl` and `de`) to their localized strings.\n\n```js title=\"commands/fun/dog.js\"\nconst { SlashCommandBuilder } = require('discord.js');\n\nconst data = new SlashCommandBuilder()\n\t.setName('dog')\n\t// [!code focus:4]\n\t.setNameLocalizations({\n\t\tpl: 'pies',\n\t\tde: 'hund',\n\t})\n\t.setDescription('Get a cute picture of a dog!')\n\t// [!code focus:4]\n\t.setDescriptionLocalizations({\n\t\tpl: 'Słodkie zdjęcie pieska!',\n\t\tde: 'Poste ein niedliches Hundebild!',\n\t})\n\t.addStringOption((option) =>\n\t\toption\n\t\t\t.setName('breed')\n\t\t\t.setDescription('Breed of dog')\n\t\t\t// [!code focus:8]\n\t\t\t.setNameLocalizations({\n\t\t\t\tpl: 'rasa',\n\t\t\t\tde: 'rasse',\n\t\t\t})\n\t\t\t.setDescriptionLocalizations({\n\t\t\t\tpl: 'Rasa psa',\n\t\t\t\tde: 'Hunderasse',\n\t\t\t}),\n\t);\n```\n\n#### Next steps\n\nFor more information on receiving and parsing the different types of options covered on this page, refer to [parsing options](./parsing-options), or for more general information on how you can respond to slash commands, check out [response methods](./response-methods).\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/slash-commands/autocomplete.mdx",
    "content": "---\ntitle: Autocomplete\n---\n\nAutocomplete allows you to dynamically provide a selection of values to the user, based on their input, rather than relying on static choices. In this section we will cover how to add autocomplete support to your commands.\n\n<Callout>\n\tThis page is a follow-up to the [slash commands](./advanced-creation) section covering options and option choices.\n\tPlease carefully read those pages first so that you can understand the methods used in this section.\n</Callout>\n\n## Enabling autocomplete\n\nTo use autocomplete with your commands, _instead_ of listing static choices, the option must be set to use autocompletion using `SlashCommandStringOption#setAutocomplete`:\n\n```js title=\"commands/utility/guide\".js\nconst { SlashCommandBuilder } = require('discord.js');\n\nconst data = new SlashCommandBuilder()\n\t.setName('guide')\n\t.setDescription('Search discordjs.guide!')\n\t// [!code word:setAutocomplete] [!code focus]\n\t.addStringOption((option) => option.setName('query').setDescription('Phrase to search for').setAutocomplete(true));\n```\n\n## Responding to autocomplete interactions\n\nTo handle an `AutocompleteInteraction`, use the `BaseInteraction#isAutocomplete` type guard to make sure the interaction instance is an autocomplete interaction. You can do this in a separate `interactionCreate` listener:\n\n```js\nclient.on(Events.InteractionCreate, (interaction) => {\n\t// [!code word:isAutocomplete]\n\tif (!interaction.isAutocomplete()) return;\n\t// do autocomplete handling\n});\n```\n\nOr alternatively, by making a small change to your existing [command handler](../app-creation/handling-commands) and adding an additional method to your individual command files.\n\nThe example below shows how this might be applied to a conceptual version of the `guide` command to determine the closest topic to the search input:\n\n```js tab=\"Handler\" title=\"index.js / events/interactionCreate.js (if you implemented the event handler)\"\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (interaction.isChatInputCommand()) {\n\t\t// command handling...\n\t\t// [!code ++]\n\t} else if (interaction.isAutocomplete()) {\n\t\tconst command = interaction.client.commands.get(interaction.commandName);\n\n\t\tif (!command) {\n\t\t\tconsole.error(`No command matching ${interaction.commandName} was found.`);\n\t\t\treturn;\n\t\t}\n\n\t\t// [!code ++:5]\n\t\ttry {\n\t\t\tawait command.autocomplete(interaction);\n\t\t} catch (error) {\n\t\t\tconsole.error(error);\n\t\t}\n\t}\n});\n```\n\n```js tab=\"Command\" title=\"commands/utility/guide.js\"\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('guide')\n\t\t.setDescription('Search discordjs.guide!')\n\t\t.addStringOption((option) => option.setName('query').setDescription('Phrase to search for').setAutocomplete(true)),\n\tasync autocomplete(interaction) {\n\t\t// handle the autocompletion response (more on how to do that below)\n\t},\n\tasync execute(interaction) {\n\t\t// respond to the complete slash command\n\t},\n};\n```\n\nThe command handling is almost identical, but notice the change from `execute` to `autocomplete` in the new else-if branch. By adding a separate `autocomplete` function to the `module.exports` of commands that require autocompletion, you can safely separate the logic of providing dynamic choices from the code that needs to respond to the slash command once it is complete.\n\n<Callout>\n\tYou might have already moved this code to `events/interactionCreate.js` if you followed our [Event\n\thandling](../app-creation/handling-events) guide too.\n</Callout>\n\n### Sending results\n\nThe `AutocompleteInteraction` class provides the `AutocompleteInteraction#respond` method to send a response. Using this, you can submit an array of `ApplicationCommandOptionChoiceData` objects for the user to choose from. Passing an empty array will show \"No options match your search\" for the user.\n\n<Callout type=\"warn\">\n\tUnlike static choices, autocompletion **suggestions are not enforced**, and users may still enter free text.\n</Callout>\n\nThe `CommandInteractionOptionResolver#getFocused` method returns the currently focused option's value, which can be used to apply filtering to the choices presented. For example, to only display options starting with the focused value you can use the `Array#filter()` method, then using `Array#map()`, you can transform the array into an array of `ApplicationCommandOptionChoiceData` objects.\n\n```js title=\"commands/utility/guide.js\"\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('guide')\n\t\t.setDescription('Search discordjs.guide!')\n\t\t.addStringOption((option) => option.setName('query').setDescription('Phrase to search for').setAutocomplete(true)),\n\t// [!code focus:12]\n\tasync autocomplete(interaction) {\n\t\t// [!code ++:10]\n\t\tconst focusedValue = interaction.options.getFocused(); // [!code word:getFocused]\n\t\tconst choices = [\n\t\t\t'Popular Topics: Threads',\n\t\t\t'Sharding: Getting started',\n\t\t\t'Library: Voice Connections',\n\t\t\t'Interactions: Replying to slash commands',\n\t\t\t'Popular Topics: Embed preview',\n\t\t];\n\t\tconst filtered = choices.filter((choice) => choice.startsWith(focusedValue));\n\t\tawait interaction.respond(filtered.map((choice) => ({ name: choice, value: choice })));\n\t},\n};\n```\n\n### Handling multiple autocomplete options\n\nTo distinguish between multiple options, you can pass `true` into `CommandInteractionOptionResolver#getFocused`, which will now return the full focused object instead of just the value. This is used to get the name of the focused option below, allowing for multiple options to each have their own set of suggestions:\n\n```js title=\"commands/utility/guide.js\"\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('guide')\n\t\t.setDescription('Search discordjs.guide!')\n\t\t.addStringOption((option) => option.setName('query').setDescription('Phrase to search for').setAutocomplete(true))\n\t\t// [!code focus:3] [!code ++:3]\n\t\t.addStringOption((option) =>\n\t\t\toption.setName('version').setDescription('Version to search in').setAutocomplete(true),\n\t\t),\n\t// [!code focus:28]\n\tasync autocomplete(interaction) {\n\t\t// [!code --:10]\n\t\tconst focusedValue = interaction.options.getFocused(); // [!code word:getFocused]\n\t\tconst choices = [\n\t\t\t'Popular Topics: Threads',\n\t\t\t'Sharding: Getting started',\n\t\t\t'Library: Voice Connections',\n\t\t\t'Interactions: Replying to slash commands',\n\t\t\t'Popular Topics: Embed preview',\n\t\t];\n\t\tconst filtered = choices.filter((choice) => choice.startsWith(focusedValue));\n\t\t// [!code ++:18]\n\t\tconst focusedOption = interaction.options.getFocused(true);\n\t\tlet choices;\n\n\t\tif (focusedOption.name === 'query') {\n\t\t\tchoices = [\n\t\t\t\t'Popular Topics: Threads',\n\t\t\t\t'Sharding: Getting started',\n\t\t\t\t'Library: Voice Connections',\n\t\t\t\t'Interactions: Replying to slash commands',\n\t\t\t\t'Popular Topics: Embed preview',\n\t\t\t];\n\t\t}\n\n\t\tif (focusedOption.name === 'version') {\n\t\t\tchoices = ['v9', 'v11', 'v12', 'v13', 'v14'];\n\t\t}\n\n\t\tconst filtered = choices.filter((choice) => choice.startsWith(focusedOption.value));\n\t\tawait interaction.respond(filtered.map((choice) => ({ name: choice, value: choice })));\n\t},\n};\n```\n\n### Accessing other values\n\nIn addition to filtering based on the focused value, you may also wish to change the choices displayed based on the value of other arguments in the command. The following methods work the same in `AutocompleteInteraction`:\n\n```js\nconst string = interaction.options.getString('input');\nconst integer = interaction.options.getInteger('int');\nconst boolean = interaction.options.getBoolean('choice');\nconst number = interaction.options.getNumber('num');\n```\n\nHowever, the `.getUser()`, `.getMember()`, `.getRole()`, `.getChannel()`, `.getMentionable()` and `.getAttachment()` methods are not available to autocomplete interactions. Discord does not send the respective full objects for these methods until the slash command is completed. For these, you can get the Snowflake value using `interaction.options.get('option').value`:\n\n### Notes\n\n- As with other application command interactions, autocomplete interactions must receive a response within 3 seconds.\n- You cannot defer the response to an autocomplete interaction. If you're dealing with asynchronous suggestions, such as from an API, consider keeping a local cache.\n- After the user selects a value and sends the command, it will be received as a regular `ChatInputCommandInteraction` with the chosen value.\n- You can only respond with a maximum of 25 choices at a time, though any more than this likely means you should revise your filter to further narrow the selections.\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/slash-commands/deleting-commands.mdx",
    "content": "---\ntitle: Deleting Commands\n---\n\n<Callout>\n\tThis page is a follow-up to [command deployment](../app-creation/deploying-commands). To delete commands, you need to\n\tregister them in the first place.\n</Callout>\n\nYou may have decided that you don't need a command anymore and don't want your users to be confused when they encounter a removed command.\n\n## Deleting specific commands\n\nTo delete a specific command, you will need its id. Head to **Server Settings -> Integrations -> Bots and Apps** and choose your bot. Then, right click a command and click **Copy ID**.\n\n<Callout>\n\tYou need to have [Developer Mode](https://support.discord.com/hc/articles/206346498) enabled for this to show up!\n</Callout>\n\n![bots-and-apps](./images/bots-and-apps.png)\n\n![commands-copy-id](./images/commands-copy-id.png)\n\nEdit your `deploy-commands.js` as shown below, or put it into its own file to clearly discern it from the deploy workflow:\n\n```js title=\"deleteCommands.js\"\nconst { REST, Routes } = require('discord.js');\nconst { clientId, guildId, token } = require('./config.json');\n\nconst rest = new REST().setToken(token);\n\n// ...\n\n// for guild-based commands\nrest\n\t.delete(Routes.applicationGuildCommand(clientId, guildId, 'commandId'))\n\t.then(() => console.log('Successfully deleted guild command'))\n\t.catch(console.error);\n\n// for global commands\nrest\n\t.delete(Routes.applicationCommand(clientId, 'commandId'))\n\t.then(() => console.log('Successfully deleted application command'))\n\t.catch(console.error);\n```\n\nWhere `'commandId'` is the id of the command you want to delete. Run your deploy script and it will delete the command.\n\n## Deleting all commands\n\nTo delete all commands in the respective scope (one guild, all global commands) you can pass an empty array when setting commands.\n\n```js title=\"deleteAllCommands\"\nconst { REST, Routes } = require('discord.js');\nconst { clientId, guildId, token } = require('./config.json');\n\nconst rest = new REST().setToken(token);\n\n// ...\n\n// for guild-based commands\nrest\n\t.put(Routes.applicationGuildCommands(clientId, guildId), { body: [] })\n\t.then(() => console.log('Successfully deleted all guild commands.'))\n\t.catch(console.error);\n\n// for global commands\nrest\n\t.put(Routes.applicationCommands(clientId), { body: [] })\n\t.then(() => console.log('Successfully deleted all application commands.'))\n\t.catch(console.error);\n```\n\nDiscord's API doesn't currently provide an easy way to delete guild-based commands that occur on multiple guilds from all places at once. Each will need a call of the above endpoint, while specifying the respective guild and command id.\n\n<Callout type=\"warn\">\n\tNote, that the same command will have a **different id**, if deployed to a **different guild**!\n</Callout>\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/slash-commands/meta.json",
    "content": "{\n\t\"title\": \"Slash Commands\"\n}\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/slash-commands/parsing-options.mdx",
    "content": "---\ntitle: Parsing Options\n---\n\n## Command options\n\nIn this section, we'll cover how to access the values of a command's options. Consider the following `ban` command example with two options:\n\n```js title=\"commands/moderation/ban.js\"\nconst { InteractionContextType, PermissionFlagsBits, SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ban')\n\t\t.setDescription('Select a member and ban them.')\n\t\t// [!code word:setRequired]\n\t\t.addUserOption((option) => option.setName('target').setDescription('The member to ban').setRequired(true))\n\t\t.addStringOption((option) => option.setName('reason').setDescription('The reason for banning'))\n\t\t.setDefaultMemberPermissions(PermissionFlagsBits.BanMembers)\n\t\t.setContexts(InteractionContextType.Guild),\n};\n```\n\nIn the execute method, you can retrieve the value of these two options from the `CommandInteractionOptionResolver` as shown below:\n\n```js title=\"commands/moderation/ban.js\"\nmodule.exports = {\n\t// data: new SlashCommandBuilder()...\n\t// [!code ++:7]\n\tasync execute(interaction) {\n\t\tconst target = interaction.options.getUser('target');\n\t\tconst reason = interaction.options.getString('reason') ?? 'No reason provided';\n\n\t\tawait interaction.reply(`Banning ${target.username} for reason: ${reason}`);\n\t\tawait interaction.guild.members.ban(target);\n\t},\n};\n```\n\nSince `reason` isn't a required option, the example above uses the `??` [nullish coalescing operator](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator) to set a default value in case the user does not supply a value for `reason`.\n\nIf the target user is still in the guild where the command is being run, you can also use `.getMember('target')` to get their `GuildMember` object.\n\n<Callout>\n\tIf you want the id (Snowflake) of a structure instead, grab the option via `get()` and access the Snowflake via the `value` property. Note that you should use `const { value: name } = ...` here to [destructure and rename](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) the value obtained from the `CommandInteractionOption` structure to avoid identifier name conflicts.\n</Callout>\n\nIn the same way as the above examples, you can get values of any type using the corresponding `CommandInteractionOptionResolver#get_____()` method. `String`, `Integer`, `Number` and `Boolean` options all provide the respective primitive types, while `User`, `Channel`, `Role`, and `Mentionable` options will provide either the respective discord.js class instance if your application has a bot user in the guild or a raw API structure for commands-only deployments.\n\n### Choices\n\nIf you specified preset choices for your String, Integer, or Number option, getting the selected choice is exactly the same as the free-entry options above. Consider the [gif command](./advanced-creation#choices) example you looked at earlier:\n\n```js title=\"commands/fun/gif.js\"\nconst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('gif')\n\t\t.setDescription('Sends a random gif!')\n\t\t.addStringOption((option) =>\n\t\t\t// [!code focus:5] [!code word:setRequired]\n\t\t\toption\n\t\t\t\t.setName('category')\n\t\t\t\t.setDescription('The gif category')\n\t\t\t\t.setRequired(true)\n\t\t\t\t.addChoices(\n\t\t\t\t\t{ name: 'Funny', value: 'gif_funny' },\n\t\t\t\t\t{ name: 'Meme', value: 'gif_meme' },\n\t\t\t\t\t{ name: 'Movie', value: 'gif_movie' },\n\t\t\t\t),\n\t\t),\n\n\t// [!code focus:4]\n\tasync execute(interaction) {\n\t\tconst category = interaction.options.getString('category');\n\t\t// category must be one of 'gif_funny', 'gif_meme', or 'gif_movie'\n\t},\n};\n```\n\nNotice that nothing changes - you still use `getString()` to get the choice value. The only difference is that in this case, you can be sure it's one of only three possible values.\n\n### Subcommands\n\nIf you have a command that contains subcommands, the `CommandInteractionOptionResolver#getSubcommand()` will tell you which subcommand was used. You can then get any additional options of the selected subcommand using the same methods as above.\n\nThe snippet below uses the same `info` command from the [subcommand creation guide](./advanced-creation#subcommands) to demonstrate how you can control the logic flow when replying to different subcommands:\n\n```js title=\"commands/utility/info.js\"\nmodule.exports = {\n\t// data: new SlashCommandBuilder()...\n\t// [!code focus:15] [!code word:getSubcommand]\n\tasync execute(interaction) {\n\t\tif (interaction.options.getSubcommand() === 'user') {\n\t\t\tconst user = interaction.options.getUser('target');\n\n\t\t\tif (user) {\n\t\t\t\tawait interaction.reply(`Username: ${user.username}\\nID: ${user.id}`);\n\t\t\t} else {\n\t\t\t\tawait interaction.reply(`Your username: ${interaction.user.username}\\nYour ID: ${interaction.user.id}`);\n\t\t\t}\n\t\t} else if (interaction.options.getSubcommand() === 'server') {\n\t\t\tawait interaction.reply(\n\t\t\t\t`Server name: ${interaction.guild.name}\\nTotal members: ${interaction.guild.memberCount}`,\n\t\t\t);\n\t\t}\n\t},\n};\n```\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/slash-commands/permissions.mdx",
    "content": "---\ntitle: Slash Command Permissions\n---\n\nSlash commands have their own permissions system. This system allows you to set the default level of permissions required for a user to execute a command when it is first deployed or your bot is added to a new server.\n\nThe slash command permissions for guilds are defaults only and can be altered by guild administrators, allowing them to configure access however best suits their moderation and server roles. Your code should not try to enforce its own permission management, as this can result in a conflict between the server-configured permissions and your bot's code.\n\n<Callout type=\"warn\">\n\tIt is **not possible to prevent users with Administrator permissions from using any commands deployed globally or\n\tspecifically to their guild**. Think twice before creating \"dev-only\" commands such as `eval` and restrict them to\n\tyour private, personal dev server.\n</Callout>\n\n## Member permissions\n\nYou can use `SlashCommandBuilder#setDefaultMemberPermissions` to set the default permissions required for a member to run the command. Setting it to `0` will hide the command from and prohibit anyone in a guild from using the command unless a specific overwrite is configured or the user has the Administrator permission flag.\n\nFor this, you'll introduce two common and simple moderation commands: `ban` and `kick`. For a ban command, a sensible default is to ensure that users already have the Discord permission `BanMembers` in order to use it.\n\n```js title=\"commands/moderation/ban.js\"\nconst { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');\n\nconst data = new SlashCommandBuilder()\n\t.setName('ban')\n\t.setDescription('Select a member and ban them.')\n\t.addUserOption((option) => option.setName('target').setDescription('The member to ban').setRequired(true))\n\t.setDefaultMemberPermissions(PermissionFlagsBits.BanMembers); // [!code ++]\n```\n\nFor a kick command however, you can allow members with the `KickMembers` permission to execute the command, so that's why the flag is listed here here.\n\n<Callout>\n\tYou can require the user to have all of multiple permissions by merging them with the `|` bitwise OR operator (for example `PermissionFlagsBits.BanMembers | PermissionFlagsBits.KickMembers`).\n\tYou cannot require any of multiple permissions. Discord evaluates against the combined permission bitfield!\n\n    If you want to learn more about the `|` bitwise OR operator you can check the [Wikipedia](https://en.wikipedia.org/wiki/Bitwise_operation#OR) and [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Bitwise_OR) articles on the topic.\n\n</Callout>\n\n```js title=\"commands/moderation/kick.js\"\nconst { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');\n\nconst data = new SlashCommandBuilder()\n\t.setName('kick')\n\t.setDescription('Select a member and kick them.')\n\t.addUserOption((option) => option.setName('target').setDescription('The member to kick').setRequired(true))\n\t.setDefaultMemberPermissions(PermissionFlagsBits.KickMembers);\n```\n\nIn reality, you'll probably want to have an additional confirmation step before a ban actually executes. Check out the [button components section](../interactive-components/buttons) of the guide to see how to add confirmation buttons to your command responses, and listen to button clicks.\n\n## Contexts\n\nBy default, globally-deployed commands are also available for use in DMs. You can pass in [InteractionContextType](https://discord-api-types.dev/api/discord-api-types-v10/enum/InteractionContextType) to the `setContexts` method of the builder to restrict the command to only be available in guilds or DMs.\n\nIt doesn't make much sense for your `ban` command to be available in DMs, so you can add `setContexts(InteractionContextType.Guild)` to the builder so that it is only available in guilds:\n\n```js title=\"commands/moderation/ban.js\"\nconst { InteractionContextType, PermissionFlagsBits, SlashCommandBuilder } = require('discord.js');\n\nconst data = new SlashCommandBuilder()\n\t.setName('ban')\n\t.setDescription('Select a member and ban them.')\n\t.addUserOption((option) => option.setName('target').setDescription('The member to ban').setRequired(true))\n\t.setDefaultMemberPermissions(PermissionFlagsBits.BanMembers)\n\t.setContexts(InteractionContextType.Guild); // [!code ++]\n```\n\nAnd that's all you need to know on slash command permissions and contexts!\n"
  },
  {
    "path": "apps/guide/content/docs/legacy/slash-commands/response-methods.mdx",
    "content": "---\ntitle: Command Responses\n---\n\nThe most common way of sending a response is by using the `ChatInputCommandInteraction#reply()` method, as you have done in earlier examples. This method acknowledges the interaction and sends a new message in response.\n\n```js title=\"commands/utility/ping.js\"\nmodule.exports = {\n\tdata: new SlashCommandBuilder().setName('ping').setDescription('Replies with Pong!'),\n\tasync execute(interaction) {\n\t\tawait interaction.reply('Pong!'); // [!code word:reply]\n\t},\n};\n```\n\n<Callout>\n\tInitially an interaction token is only valid for three seconds, so that's the timeframe in which you are able to use\n\tthe `ChatInputCommandInteraction#reply()` method. Responses that require more time (\"Deferred Responses\") are\n\texplained later on this page.\n</Callout>\n\n## Ephemeral responses\n\nYou may not always want everyone who has access to the channel to see a slash command's response. Previously, you would have had to DM the user to achieve this, potentially encountering the high rate limits associated with DM messages, or simply being unable to do so, if the user's DMs were disabled.\n\nThankfully, Discord provides a way to hide response messages from everyone but the executor of the slash command. This is called an ephemeral message and can be set by providing `flags: MessageFlags.Ephemeral` in the `InteractionReplyOptions`, as follows:\n\n```js\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tif (interaction.commandName === 'ping') {\n\t\tawait interaction.reply('Pong!'); // [!code --]\n\t\tawait interaction.reply({ content: 'Secret Pong!', flags: MessageFlags.Ephemeral }); // [!code ++] [!code word:Ephemeral]\n\t}\n});\n```\n\nEphemeral responses are _only_ available for interaction responses; another great reason to use the new and improved slash command user interface.\n\n## Editing responses\n\nAfter you've sent an initial response, you may want to edit that response for various reasons. This can be achieved with the `ChatInputCommandInteraction#editReply()` method:\n\n<Callout type=\"warn\">\n\tAfter the initial response, an interaction token is valid for **15 minutes**, so this is the timeframe in which you\n\tcan edit the response and send follow-up messages. You also **cannot** edit the ephemeral state of a message, so make\n\tsure that your first response sets this correctly.\n</Callout>\n\n```js\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tif (interaction.commandName === 'ping') {\n\t\tawait interaction.reply('Pong!');\n\t\t// do something that requires time (database queries, api requests, ...)\n\t\tawait interaction.editReply('Pong again!'); // [!code word:editReply]\n\t}\n});\n```\n\nIn fact, editing your interaction response is necessary to [calculate the ping](../popular-topics/faq#how-do-i-check-the-bots-ping) properly for this command.\n\n## Deferred responses\n\nAs previously mentioned, Discord requires an acknowledgement from your bot within three seconds that the interaction was received. Otherwise, Discord considers the interaction to have failed and the token becomes invalid. But what if you have a command that performs a task which takes longer than three seconds before being able to reply?\n\nIn this case, you can make use of the `ChatInputCommandInteraction#deferReply()` method, which triggers the `<application> is thinking...` message. This also acts as the initial response, to confirm to Discord that the interaction was received successfully and gives you a **15-minute timeframe to complete your tasks** before responding.\n\n```js\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tif (interaction.commandName === 'ping') {\n\t\tawait interaction.deferReply(); // [!code word:deferReply]\n\t\t// you can do things that take time here (database queries, api requests, ...) that you need for the initial response\n\t\t// you can take up to 15 minutes, then the interaction token becomes invalid!\n\t\tawait interaction.editReply('Pong!'); // [!code word:editReply]\n\t}\n});\n```\n\nIf you have a command that performs longer tasks, be sure to call `deferReply()` as early as possible.\n\nNote that if you want your response to be ephemeral, utilize `flags` from `InteractionDeferReplyOptions` here:\n\n```js\nawait interaction.deferReply({ flags: MessageFlags.Ephemeral });\n```\n\nIt is not possible to edit a reply to change its ephemeral state once sent.\n\n<Callout>\n\tIf you want to make a proper ping command, one is available in our\n\t[FAQ](../popular-topics/faq#how-do-i-check-the-bot-s-ping).\n</Callout>\n\n## Follow-ups\n\nThe `reply()` and `deferReply()` methods are both _initial_ responses, which tell Discord that your bot successfully received the interaction, but cannot be used to send additional messages. This is where follow-up messages come in. After having initially responded to an interaction, you can use `ChatInputCommandInteraction#followUp()` to send additional messages:\n\n<Callout type=\"warn\">\n\tAfter the initial response, an interaction token is valid for **15 minutes**, so this is the timeframe in which you\n\tcan edit the response and send follow-up messages.\n</Callout>\n\n```js\nclient.on(Events.InteractionCreate, async (interaction) => {\n\tif (!interaction.isChatInputCommand()) return;\n\n\tif (interaction.commandName === 'ping') {\n\t\tawait interaction.reply('Pong!');\n\t\tawait interaction.followUp('Pong again!');\n\t}\n});\n```\n\nYou can also pass the ephemeral flag to the `InteractionReplyOptions`:\n\n```js\nawait interaction.followUp({ content: 'Pong again!', flags: MessageFlags.Ephemeral });\n```\n\nNote that if you use `followUp()` after a `deferReply()`, the first follow-up will edit the `<application> is thinking` message rather than sending a new one.\n\nThat's all, now you know everything there is to know on how to reply to slash commands!\n\n<Callout>Interaction responses can use masked links (e.g. `[text](http://site.com)`) in the message content.</Callout>\n\n## Fetching and deleting responses\n\nIn addition to replying to a slash command, you may also want to delete the initial reply. You can use `ChatInputCommandInteraction#deleteReply()` for this:\n\n```js\nawait interaction.reply('Pong!');\nawait interaction.deleteReply();\n```\n\nLastly, you may require the `Message` object of a reply for various reasons, such as adding reactions. Pass `withResponse: true` to obtain the `InteractionCallbackResponse`. You can then access the `Message` object like so:\n\n```js\nconst response = await interaction.reply({ content: 'Pong!', withResponse: true });\nconsole.log(response.resource.message);\n```\n\nYou can also use the `ChatInputCommandInteraction#fetchReply()` method to fetch the `Message` instance. Do note that this incurs an extra API call in comparison to `withResponse: true`:\n\n```js\nawait interaction.reply('Pong!');\nconst message = await interaction.fetchReply();\nconsole.log(message);\n```\n\n## Localized responses\n\nIn addition to the ability to provide [localized command definitions](./advanced-creation#localizations), you can also localize your responses. To do this, get the locale of the user with `ChatInputCommandInteraction#locale` and respond accordingly:\n\n```js\nclient.on(Events.InteractionCreate, (interaction) => {\n\tconst locales = {\n\t\tpl: 'Witaj Świecie!',\n\t\tde: 'Hallo Welt!',\n\t};\n\tinteraction.reply(locales[interaction.locale] ?? 'Hello World (default is english)');\n});\n```\n"
  },
  {
    "path": "apps/guide/content/docs/meta.json",
    "content": "{\n\t\"pages\": [\"legacy\", \"v15\", \"voice\"]\n}\n"
  },
  {
    "path": "apps/guide/content/docs/v15/index.mdx",
    "content": "---\ntitle: Updating to v15\nicon: ArrowDownToLine\n---\n\nimport { Github } from 'lucide-react';\n\n<Callout type=\"idea\">\n\t**Version 15 is in a pre-release** state, but should be usable!   \n\tThat being said, we do not recommend you update your production instance without careful and thorough testing!   \n\tPlease report any bugs you experience at our GitHub repository:\n\n    <Github className=\"inline text-red-400\"/> https://github.com/discordjs/discord.js/issues\n\n</Callout>\n\n## Before you start\n\nMake sure you're using the latest LTS version of Node. To check your Node version, use `node --version` in your terminal or command prompt, and if it's not high enough, update it! There are many resources online to help you with this step based on your host system.\n\n## Breaking Changes\n\n### ActionRow\n\n`ActionRow.from()` has been removed. Use `ActionRowBuilder.from()` instead.\n\n### ApplicationCommand\n\n`ApplicationCommand#dmPermission` and `ApplicationCommand#setDMPermission()` have been removed. This was legacy functionality for commands—use contexts instead.\n\n### ApplicationCommandManager\n\n`ApplicationCommandManager#fetch()` method has been updated for consistency with other managers. Previously, it accepted two parameters: `id` (a snowflake or an options object) and an `options` object. Now, it only accepts a single `options` argument, which can be a snowflake or an options object that may include an `id` property.\n\n### AnnouncementChannel\n\n`AnnouncementChannel#addFollower()` now returns `FollowedChannelData` instead of a snowflake. This helps to expose the created webhook id in the target channel.\n\n### BaseInteraction\n\n`BaseInteraction#isAnySelectMenu()` has been removed. Use `BaseInteraction#isSelectMenu()` instead, which has been repurposed to accept all select menu component types.\n\n### Client\n\n#### Emojis\n\n`Client#emojis` has been removed due to confusion with the introduction of application emojis and performance impact. Use the `resolveGuildEmoji()` utility function to get a cached guild emoji.\n\n#### Ping\n\n`Client#ping` has been added to replace the old `WebSocketManager#ping`. This will be `null` when the heartbeat from the gateway is yet to be received.\n\n#### Premium sticker packs\n\n`Client#fetchPremiumStickerPacks()` has been removed. Use `Client#fetchStickerPacks()` instead.\n\n#### Ready event\n\n`client.on(\"\")` has been removed. `\"clientReady\"` is the replacement. If you used `client.on(Events.ClientReady)`, you do not need to change anything.\n\n#### Shard disconnect event\n\n`client.on(\"shardDisconnect\")` has been removed as the WebSocket manager replaces this functionality.\n\n#### Shard error event\n\n`client.on(\"shardError\")` has been removed as the WebSocket manager replaces this functionality.\n\n#### Shard ready event\n\n`client.on(\"shardReady\")` has been removed as the WebSocket manager replaces this functionality.\n\n#### Shard reconnecting event\n\n`client.on(\"shardReconnecting\")` has been removed as the WebSocket manager replaces this functionality.\n\n#### Shard resume event\n\n`client.on(\"shardResume\")` has been removed as the WebSocket manager replaces this functionality.\n\n#### Webhook update event\n\n`client.on(\"webhookUpdate\")` has been removed. `\"webhooksUpdate\"` is the replacement. If you used `client.on(Events.WebhooksUpdate)`, you do not need to change anything.\n\n#### WebSocket\n\nThe underlying WebSocket behaviour has changed. In version 14, this was a non-breaking implementation of [ws](https://discord.js.org/docs/packages/ws/stable). Now, it is fully integrated. See these pull requests for more information:\n\n- [discordjs/discord.js#10420](https://github.com/discordjs/discord.js/pull/10420)\n- [discordjs/discord.js#10556](https://github.com/discordjs/discord.js/pull/10556)\n\n### ClientEvents\n\n`ClientEvents` type has been removed. Use `ClientEventTypes` instead. This change ensures consistency with the rest of the event types across the library.\n\n### ClientOptions\n\nRemoved `ClientOptions#shards` and `ClientOptions#shardCount` in favor of `ClientOptions#ws#shardIds` and `ClientOptions#ws#shardCount`.\n\n### ClientUser\n\n`ClientUser#setPresence()` now returns a promise which resolves when the gateway call was sent successfully.\n\n### ClientPresence\n\n`ClientPresence#set()` now returns a promise which resolves when the gateway call was sent successfully.\n\n### CommandInteractionOptionResolver\n\n`CommandInteractionOptionResolver#getFocused()`'s parameter has been removed. `AutocompleteFocusedOption` will always be returned.\n\n### Constants\n\n`DeletableMessageTypes` has been removed. Use `UndeletableMessageTypes` instead.\n\n### DiscordjsErrorCodes\n\nThe following error codes have been removed as they either have no use or are handled in another package instead:\n\n- `WSCloseRequested`\n- `WSConnectionExists`\n- `WSNotOpen`\n- `ManagerDestroyed`\n- `ShardingInvalid`\n- `ShardingRequired`\n- `InvalidIntents`\n- `DisallowedIntents`\n- `ButtonLabel`\n- `ButtonURL`\n- `ButtonCustomId`\n- `SelectMenuCustomId`\n- `SelectMenuPlaceholder`\n- `SelectOptionLabel`\n- `SelectOptionValue`\n- `SelectOptionDescription`\n- `UserBannerNotFetched`\n- `ImageFormat`\n- `ImageSize`\n- `SplitMaxLen`\n- `MissingManageEmojisAndStickersPermission`\n- `VanityURL`\n- `InteractionEphemeralReplied`\n\n### Emoji\n\n#### Image URL is now dynamic\n\n`Emoji#imageURL()` now dynamically handles the extension. Previously, you would have to do this:\n\n```js\nemoji.imageURL({ extension: emoji.animated ? 'gif' : 'webp' });\n```\n\nNow, you can simply do this:\n\n```js\nemoji.imageURL();\n```\n\n#### Emoji URL getter removal\n\n`Emoji#url` has been removed. To allow more granular control of the returned extension, Use `Emoji#imageURL()` instead.\n\n### EventEmitter\n\n`BaseClient`, `Shard`, `ShardingManager`, and `Collector` now extend `AsyncEventEmitter` instead of `EventEmitter`. This comes from [@vladfrangu/async_event_emitter](https://npmjs.com/package/@vladfrangu/async_event_emitter).\n\n### Events\n\n- `Events.ShardError` has been removed.\n- `Events.ShardReady` has been removed.\n- `Events.ShardReconnecting` has been removed.\n- `Events.ShardResume` has been removed.\n- `Events.WebhooksUpdate` now returns a string of `\"webhooksUpdate\"`. Previously, it returned `\"webhookUpdate\"`. This is to bring it in line with the name of Discord's gateway event (`WEBHOOKS_UPDATE`).\n- `Events.ClientReady` now returns a string of `\"clientReady\"`. Previously, it returned `\"ready\"`. This is to ensure there's no confusion with Discord's `READY` gateway event.\n\n### Formatters\n\nThis utility has been removed. Everything in this class is redundant as all methods of the class can be imported from discord.js directly.\n\n```js\nimport { Formatters } from 'discord.js'; // [!code --]\nimport { userMention } from 'discord.js'; // [!code ++]\n\nFormatters.userMention('123456789012345678'); // [!code --]\nuserMention('123456789012345678'); // [!code ++]\n```\n\n### Guild\n\nRemoved `Guild#shard` as WebSocket shards are now handled by @discordjs/ws.\n\n### GuildApplicationCommandManager\n\n`GuildApplicationCommandManager#fetch()` method has been updated for consistency with other managers. Previously, it accepted two parameters: `id` (a snowflake or an options object) and an `options` object. Now, it only accepts a single `options` argument, which can be a snowflake or an options object that may include an `id` property.\n\n### GuildAuditLogs\n\n`GuildAuditLogsEntry.Targets.All` has been removed. It was not being used.\n\n### GuildBanManager\n\n`GuildBanManager#create()` no longer accepts `deleteMessageDays`. This is replaced with `deleteMessageSeconds`.\n\n### GuildChannelManager\n\n`GuildChannelManager#addFollower()` now returns `FollowedChannelData` instead of a snowflake. This helps to expose the created webhook id in the target channel.\n\n### GuildMemberResolvable\n\n`GuildMemberResolvable` type has been removed. It was defined as `GuildMember | UserResolvable`, but `UserResolvable` already includes `GuildMember`. Use `UserResolvable` instead.\n\n### MessageManager\n\n`MessageManager#crosspost()` has been moved to `GuildMessageManager`. This means it will no longer be exposed in `DMMessageManager`.\n\n### IntegrationApplication\n\n`IntegrationApplication#hook` has been removed.\n\n### InteractionResponse\n\n`InteractionResponse` has been removed. This class was encountered when responding to an interaction without `fetchReply` to allow ease of creating interaction collectors. This is no longer necessary as `withResponse` exposes the message.\n\n### InteractionResponses\n\n#### Ephemeral option removal\n\nPreviously, you would respond to an interaction ephemerally like so:\n\n```js\n// Way 1:\nawait interaction.reply({ content: 'This is an ephemeral response.', ephemeral: true });\n\n// Way 2:\nawait interaction.reply({ content: 'This is an ephemeral response.', flags: MessageFlags.Ephemeral });\n```\n\nThere are two ways to achieve the same behaviour, so the \"helper\" option has been removed. In this case, that would be `ephemeral`, as all that did was assign `MessageFlags.Ephemeral` internally.\n\n#### Fetch reply option removal\n\n`fetchReply` has been removed in favor of `withResponse`. If you were using the `fetchReply` option or fetching the response of an interaction, it is recommended to use `withResponse` instead, as the message is exposed without an additional API call:\n\n```js\nconst message = await interaction.reply({ content: 'Hello!', fetchReply: true }); // [!code --]\nconst response = await interaction.reply({ content: 'Hello!', withResponse: true }); // [!code ++:2]\nconst { message } = response.resource;\n```\n\n#### Premium response type\n\nDiscord no longer supports the `PREMIUM_REQUIRED` interaction response type. In the past, you would have done this:\n\n```js\nif (!premiumLogicCheck) {\n\t// User does not have access to our premium features.\n\tawait interaction.sendPremiumRequired();\n\treturn;\n}\n\nawait interaction.reply('You have access to our premium features!');\n```\n\nHowever, you would have already noticed that this no longer works, so this method has been removed. Sending a premium button has been the replacement ever since.\n\n### Invite\n\n`Invite#stageInstance` has been removed.\n\n### InviteStageInstance\n\n`InviteStageInstance` has been removed.\n\n### Message\n\n`Message#interaction` has been removed. Use `Message#interactionMetadata` instead.\n\n### MessagePayload\n\n`MessagePayload#isInteraction` no longer serves a purpose and has been removed.\n\n### NewsChannel\n\n`NewsChannel` has been renamed to `AnnouncementChannel`.\n\n### PermissionOverwrites\n\n`PermissionOverwrites.resolve()` previously relied on cache if a snowflake was passed. This method no longer relies on cache and instead requires an explicit `type` if supplied.\n\n### RoleManager\n\n`RoleManager#fetch()` used to return `null` when fetching a role that did not exist. This logic has been removed and will throw an error instead.\n\n### SelectMenuBuilder\n\n`SelectMenuBuilder` has been removed. Use `StringSelectMenuBuilder` instead.\n\n### SelectMenuComponent\n\n`SelectMenuComponent` has been removed. Use `StringSelectMenuComponent` instead.\n\n### SelectMenuInteraction\n\n`SelectMenuInteraction` has been removed. Use `StringSelectMenuInteraction` instead.\n\n### SelectMenuOptionBuilder\n\n`SelectMenuOptionBuilder` has been removed. Use `StringSelectMenuOptionBuilder` instead.\n\n### ShardClientUtil\n\n`ShardClientUtil#ids` and `ShardClientUtil#count` have been removed in favor of `Client#ws#getShardIds()` and `Client#ws#getShardCount()`.\n\n### StageInstance\n\n`StageInstance#discoverableDisabled` has been removed.\n\n### TeamMember\n\n`TeamMember#permissions` has been removed. Use `TeamMemberManager#role` instead.\n\n### TextBasedChannel\n\n`TextBasedChannel#bulkDelete()` could return a collection containing `undefined` values. This was because in order to return these messages, the cache must be checked, especially when only snowflakes were provided. The return type of this method has thus changed to only return an array of snowflakes that were bulk deleted.\n\n### ThreadChannel\n\n`ThreadChannel#fetchOwner()` used to return `null` when the thread owner was not present in the thread. This logic has been removed and will throw an error instead.\n\n### ThreadManager\n\n`ThreadManager#fetch()` now throws an error when the provided thread id doesn't belong to the current channel.\n\n### ThreadMember\n\nThe reason parameter of `ThreadMember#add()` and `ThreadMember#remove()` have been removed. Discord did not respect this parameter, so it did not do anything.\n\n### ThreadMemberManager\n\nThe reason parameter of `ThreadMemberManager#remove()` has been removed. Discord did not respect this parameter, so it did not do anything.\n\n### User\n\n#### Avatar decoration\n\nDiscord no longer sends avatar decoration data via `User#avatarDecoration`, so this property has been removed. `User#avatarDecorationData` is the replacement.\n\n#### Flags\n\n`User#fetchFlags()` has been removed. All this did was fetch the user and return only its `flags` property. It was quite redundant.\n\n### UserManager\n\n`UserManager#fetchFlags()` has been removed. All this did was fetch the user and return only its `flags` property. It was quite redundant.\n\n### WebSocketShardEvents\n\n`WebSocketShardEvents` has been replaced with `WebSocketShardEvents` from @discordjs/ws.\n"
  },
  {
    "path": "apps/guide/content/docs/v15/meta.json",
    "content": "{\n\t\"title\": \"discord.js v15\",\n\t\"description\": \"Work in progress...\",\n\t\"pages\": [\"external:[LibraryBig][Documentation](https://discord.js.org/docs/packages/discord.js/main)\", \"index\"],\n\t\"icon\": \"FlaskConical\",\n\t\"root\": true\n}\n"
  },
  {
    "path": "apps/guide/content/docs/voice/audio-player.mdx",
    "content": "---\ntitle: Audio Player\n---\n\nAudio players can be used to play audio across voice connections. A single audio player can play the same audio over multiple voice connections.\n\n## Cheat sheet\n\n### Creation\n\nCreating an audio player is simple:\n\n```js\nconst { createAudioPlayer } = require('@discordjs/voice');\n\nconst player = createAudioPlayer();\n```\n\nYou can also customize the behaviors of an audio player. For example, the default behavior is to pause when there are no active subscribers for an audio player. This behavior can be configured to either pause, stop, or just continue playing through the stream:\n\n```js\nconst { createAudioPlayer, NoSubscriberBehavior } = require('@discordjs/voice');\n\nconst player = createAudioPlayer({\n\tbehaviors: {\n\t\tnoSubscriber: NoSubscriberBehavior.Pause,\n\t},\n});\n```\n\n### Deletion\n\nIf you no longer require an audio player, you can `stop()` it and then remove references to it so that it gets garbage collected.\n\n```js\nplayer.stop();\n```\n\n### Playing audio\n\nYou can create [audio resources](./audio-resources) and then play them on an audio player.\n\n```js\nconst resource = createAudioResource('/home/user/voice/track.mp3');\nplayer.play(resource);\n\n// Play \"track.mp3\" across two voice connections\nconnection1.subscribe(player);\nconnection2.subscribe(player);\n```\n\n<Callout>\n\t**Audio players can play one audio resource at most.** If you try to play another audio resource while one is already\n\tplaying on the same player, the existing one is destroyed and replaced with the new one.\n</Callout>\n\n### Pausing/unpausing\n\nYou can call the `pause()` and `unpause()` methods. While the audio player is paused, no audio will be played. When it is resumed, it will continue where it left off.\n\n```js\nplayer.pause();\n\n// Unpause after 5 seconds\nsetTimeout(() => player.unpause(), 5_000);\n```\n\n## Life cycle\n\nVoice connections have their own life cycle, with five distinct states. You can follow the methods discussed in the [life cycles](./life-cycles) section to subscribe to changes to voice connections.\n\n- **Idle** - the initial state of an audio player. The audio player will be in this state when there is no audio resource for it to play.\n\n- **Buffering** - the state an audio player will be in while it is waiting for an audio resource to become playable. The audio player may transition from this state to either the `Playing` state (success) or the `Idle` state (failure).\n\n- **Playing** - the state a voice connection enters when it is actively playing an audio resource. When the audio resource comes to an end, the audio player will transition to the Idle state.\n\n- **AutoPaused** - the state a voice connection will enter when the player has paused itself because there are no active voice connections to play to. This is only possible with the `noSubscriber` behavior set to `Pause`. It will automatically transition back to `Playing` once at least one connection becomes available again.\n\n- **Paused** - the state a voice connection enters when it is paused by the user.\n\n```js\nconst { AudioPlayerStatus } = require('@discordjs/voice');\n\nplayer.on(AudioPlayerStatus.Playing, () => {\n\tconsole.log('The audio player has started playing!');\n});\n```\n\n## Handling errors\n\nWhen an audio player is given an audio resource to play, it will propagate errors from the audio resource for you to handle.\n\nIn the error handler, you can choose to either play a new audio resource or stop playback. If you take no action, the audio player will stop itself and revert to the `Idle` state.\n\nAdditionally, the error object will also contain a `resource` property that helps you to figure out which audio resource created the error.\n\nTwo different examples of how you may handle errors are shown below.\n\n### Taking action within the error handler\n\nIn this example, the audio player will only move on to playing the next audio resource if an error has occurred. If playback ends gracefully, nothing will happen. This example avoids a transition into the Idle state.\n\n```js\nconst { createAudioResource } = require('@discordjs/voice');\n\nconst resource = createAudioResource('/home/user/voice/music.mp3', {\n\tmetadata: {\n\t\ttitle: 'A good song!',\n\t},\n});\n\nplayer.play(resource);\n\nplayer.on('error', (error) => {\n\tconsole.error(`Error: ${error.message} with resource ${error.resource.metadata.title}`);\n\tplayer.play(getNextResource());\n});\n```\n\n### Taking action within the `Idle` state\n\nIn this example, the error event is used only for logging purposes. The audio player will naturally transition into the `Idle` state, and then another resource is played. This has the advantage of working with streams that come to an end gracefully, and those that are interrupted by errors.\n\n```js\nconst { createAudioResource } = require('@discordjs/voice');\n\nconst resource = createAudioResource('/home/user/voice/music.mp3', {\n\tmetadata: {\n\t\ttitle: 'A good song!',\n\t},\n});\n\nplayer.play(resource);\n\nplayer.on('error', (error) => {\n\tconsole.error(error);\n});\n\nplayer.on(AudioPlayerStatus.Idle, () => {\n\tplayer.play(getNextResource());\n});\n```\n"
  },
  {
    "path": "apps/guide/content/docs/voice/audio-resources.mdx",
    "content": "---\ntitle: Audio Resources\n---\n\nAudio resources contain audio that can be played by an audio player to voice connections.\n\n## Cheat sheet\n\n### Creation\n\nThere are many ways to create an audio resource. Below are some example scenarios:\n\n```js\nconst { createReadStream } = require('node:fs');\nconst { join } = require('node:path');\nconst { createAudioResource, StreamType } = require('@discordjs/voice');\n\n// Basic, default options are:\n// Input type is unknown, so will use FFmpeg to convert to Opus under-the-hood\n// Inline volume is opt-in to improve performance\nlet resource = createAudioResource(join(__dirname, 'file.mp3'));\n\n// Will use FFmpeg with volume control enabled\nresource = createAudioResource(join(__dirname, 'file.mp3'), { inlineVolume: true });\nresource.volume.setVolume(0.5);\n\n// Will play .ogg or .webm Opus files without FFmpeg for better performance\n// Remember, inline volume is still disabled\nresource = createAudioResource(\n\tcreateReadStream(join(__dirname, 'file.ogg'), {\n\t\tinputType: StreamType.OggOpus,\n\t}),\n);\n\n// Will play with FFmpeg due to inline volume being enabled.\nresource = createAudioResource(\n\tcreateReadStream(join(__dirname, 'file.webm'), {\n\t\tinputType: StreamType.WebmOpus,\n\t\tinlineVolume: true,\n\t}),\n);\n\nplayer.play(resource);\n```\n\n### Deletion\n\nThe underlying streams of an audio resource are destroyed and flushed once an audio player is done playing their audio. Make sure to remove any references you've created to the resource to prevent memory leaks.\n\n## Handling errors\n\nFor most scenarios, you will create an audio resource for immediate use by an audio player. The audio player will propagate errors from the resource for you, so you can attach `error` handlers to the player instead of the resource.\n\n```js\nconst { createAudioResource, createAudioPlayer } = require('@discordjs/voice');\n\nconst player = createAudioPlayer();\n// An AudioPlayer will always emit an \"error\" event with a .resource property\nplayer.on('error', (error) => {\n\tconsole.error('Error:', error.message, 'with track', error.resource.metadata.title);\n});\n\nconst resource = createAudioResource('/home/user/voice/music.mp3', {\n\tmetadata: {\n\t\ttitle: 'A good song!',\n\t},\n});\nplayer.play(resource);\n```\n\nHowever, you can also attach an error handler specifically to the audio resource if you'd like to. This is **not recommended**, as you are not allowed to change the state of an audio player from the error handlers of an audio resource (on the other hand, you are allowed to do this from the error handle of an audio player, as shown above.)\n\n```js\nconst { createAudioResource, createAudioPlayer } = require('@discordjs/voice');\n\nconst player = createAudioPlayer();\n\nconst resource = createAudioResource('/home/user/voice/music.mp3', {\n\tmetadata: {\n\t\ttitle: 'A good song!',\n\t},\n});\n\n// Not recommended - listen to errors from the audio player instead for most use cases!\nresource.playStream.on('error', (error) => {\n\tconsole.error('Error:', error.message, 'with track', resource.metadata.title);\n});\n\nplayer.play(resource);\n```\n\n## Optimizations\n\nTo improve performance, you can consider the following methods. They reduce the computational demand required to play audio, and could help to reduce jitter in the audio stream.\n\n### Not using inline volume\n\nBy default, inline volume is disabled for performance reasons. Enabling it will allow you to modify the volume of your stream in realtime. This comes at a performance cost, even if you aren't actually modifying the volume of your stream.\n\nMake sure you consider whether it is worth enabling for your use case.\n\n### Playing Opus streams\n\nIf you are repeatedly playing the same resource, you may consider converting it to Ogg opus or WebM opus. Alternatively, if you are fetching an external resource and are able to specify a format that you'd like to stream the resource in, you should consider specifying Ogg opus or WebM opus.\n\nThe reason for this is that you can remove FFmpeg from the process of streaming audio. FFmpeg is used to convert unknown inputs into Opus audio which can be streamed to Discord. If your audio is already in the Opus format, this removes one of the most computationally demanding parts of the audio pipeline from the streaming process, which would surely improve performance.\n\nBoth of the examples below will skip the FFmpeg component of the pipeline to improve performance.\n\n```js\nconst { createReadStream } = require('node:fs');\nconst { createAudioResource, StreamType } = require('@discordjs/voice');\n\nlet resource = createAudioResource(createReadStream('my_file.ogg'), {\n\tinputType: StreamType.OggOpus,\n});\n\nresource = createAudioResource(createReadStream('my_file.webm'), {\n\tinputType: StreamType.WebmOpus,\n});\n```\n\n<Callout type=\"warn\">\n\tThis optimization is useful if you do not want to use inline volume. Enabling inline volume will disable the\n\toptimization.\n</Callout>\n\n### Probing to determine stream type\n\nThe voice library is also able to determine whether a readable stream is an Ogg/Opus or WebM/Opus stream. This means\nthat you can still gain the performance benefits that come with playing an Opus stream, even if you aren't sure in\nadvance what type of audio stream you'll be playing.\n\nThis is achieved by probing a small chunk of the beginning of the audio stream to see if it is suitable for demuxing:\n\n```js\nconst { createReadStream } = require('node:fs');\nconst { demuxProbe, createAudioResource } = require('@discordjs/voice');\n\nasync function probeAndCreateResource(readableStream) {\n\tconst { stream, type } = await demuxProbe(readableStream);\n\treturn createAudioResource(stream, { inputType: type });\n}\n\nasync function createResources() {\n\t// Creates an audio resource with inputType = StreamType.Arbitrary\n\tconst mp3Stream = await probeAndCreateResource(createReadStream('file.mp3'));\n\n\t// Creates an audio resource with inputType = StreamType.OggOpus\n\tconst oggStream = await probeAndCreateResource(createReadStream('file.ogg'));\n\n\t// Creates an audio resource with inputType = StreamType.WebmOpus\n\tconst webmStream = await probeAndCreateResource(createReadStream('file.webm'));\n}\n\ncreateResources();\n```\n"
  },
  {
    "path": "apps/guide/content/docs/voice/index.mdx",
    "content": "---\ntitle: Installation\n---\n\n\"Voice\" refers to Discord bots being able to send audio in voice channels. This is supported in discord.js via [@discordjs/voice](https://github.com/discordjs/discord.js/tree/main/packages/voice), a standalone library made by the developers of discord.js. While you can use it with any Node.js Discord API library, this guide will focus on using it with discord.js.\n\n## Installation\n\n### Barebones\n\nTo add voice functionality to your discord.js bot, you will need the `@discordjs/voice` package. If your system does not support aes-256-gcm you also need one of the encryption packages listed below. For example:\n\n<Callout>\n\tYou can verify aes-256-gcm support by running `require('node:crypto').getCiphers().includes('aes-256-gcm')`.\n</Callout>\n\n```sh tab=\"npm\"\nnpm install @discordjs/voice\n```\n\n```sh tab=\"yarn\"\nyarn add @discordjs/voice\n```\n\n```sh tab=\"pnpm\"\npnpm add @discordjs/voice\n```\n\n```sh tab=\"bun\"\nbun add @discordjs/voice\n```\n\nAfter this, you'll be able to play Ogg and WebM Opus files without any other dependencies. If you want to play audio from other sources, or want to improve performance, consider installing some of the extra dependencies listed below.\n\n<Callout>\n\tThis guide assumes you have installed at least FFmpeg for all the examples to work. You can find more information\n\tabout extra dependencies in the next section.\n</Callout>\n\n### Extra Dependencies\n\n#### Opus encoding\n\n- [`@discordjs/opus`](https://github.com/discordjs/opus) (best performance)\n- [`opusscript`](https://github.com/abalabahaha/opusscript/)\n\n#### FFmpeg – allows you to play a range of media (e.g. MP3s).\n\n- [`ffmpeg`](https://ffmpeg.org/) - install and add to your system environment\n- [`ffmpeg-static`](https://www.npmjs.com/package/ffmpeg-static) - to install FFmpeg via npm\n\n#### Encryption libraries\n\n<Callout>\n\tYou only need to install one of these libraries if your system does not support `aes-256-gcm`. You can verify this by\n\trunning `require('node:crypto').getCiphers().includes('aes-256-gcm')`\n</Callout>\n\n- [`sodium-native`](https://www.npmjs.com/package/sodium-native)\n- [`sodium`](https://www.npmjs.com/package/sodium) (best performance)\n- [`@stablelib/xchacha20poly1305`](https://www.npmjs.com/package/@stablelib/xchacha20poly1305)\n- [`@noble/ciphers`](https://www.npmjs.com/package/@noble/ciphers)\n- [`libsodium-wrappers`](https://www.npmjs.com/package/libsodium-wrappers)\n\n#### DAVE Protocol Support for end-to-end encryption of voice audio\n\n- [`@snazzah/davey`](https://www.npmjs.com/package/@snazzah/davey)\n\n<Callout>\n\tAt this time, `@snazzah/davey` is the only supported DAVE protocol library in this package, and comes pre-installed.\n\tIn the future, we may support other libraries once they are created.\n</Callout>\n\n<Callout>\n\tIf you are facing issues when installing these dependencies, make sure you ticked the box to install optional build\n\ttools when installing Node.js or try manually installing build tools and python: ```sh winget install \"Visual Studio\n\tCommunity 2022\" --override \"--add Microsoft.VisualStudio.Workload.NativeDesktop \" -s msstore ```\n</Callout>\n\n## Debugging Dependencies\n\nThe library includes a helper function that helps you to find out which dependencies you've successfully installed. This information is also very helpful if you ever need to submit an issue on the `@discordjs/voice` issue tracker.\n\n```js\nconst { generateDependencyReport } = require('@discordjs/voice');\n\nconsole.log(generateDependencyReport());\n\n/*\n--------------------------------------------------\nCore Dependencies\n- @discordjs/voice: 0.3.1\n- prism-media: 1.2.9\n\nOpus Libraries\n- @discordjs/opus: 0.5.3\n- opusscript: not found\n\nEncryption Libraries\n- sodium: 3.0.2\n- libsodium-wrappers: not found\n- tweetnacl: not found\n\nFFmpeg\n- version: 4.2.4-1ubuntu0.1\n- libopus: yes\n\nDAVE Protocol\n- @snazzah/davey: 0.1.6\n--------------------------------------------------\n*/\n```\n\n- **Core Dependencies**\n  - These are dependencies that should definitely be available.\n- **Opus Libraries**\n  - If you want to play audio from many different file types, or alter volume in real-time, you will need to have one of these.\n- **Encryption Libraries**\n  - You should have at least one encryption library installed to use `@discordjs/voice`.\n- **FFmpeg**\n  - If you want to play audio from many different file types, you will need to have FFmpeg installed.\n  - If `libopus` is enabled, you will be able to benefit from increased performance if real-time volume alteration is disabled.\n- **DAVE Protocol**\n  - Required for enabling end-to-end encryption in voice channels.\n"
  },
  {
    "path": "apps/guide/content/docs/voice/life-cycles.mdx",
    "content": "---\ntitle: Life Cycles\n---\n\nTwo of the main components that you'll interact with when using `@discordjs/voice` are:\n\n- **VoiceConnection** – maintains a network connection to a Discord voice server\n- **AudioPlayer** – plays audio resources across a voice connection\n\nBoth voice connections and audio players are _stateful_, and you can subscribe to changes in their state as they progress through their respective life cycles.\n\nIt's important to listen for state change events, as they will likely require you to take some action. For example, a voice connection entering the `Disconnected` state will probably require you to attempt to reconnect it.\n\nTheir individual life cycles with descriptions of their states are documented on their respective pages.\n\nListening to changes in the life cycles of voice connections and audio players can be done in two ways:\n\n## Subscribing to individual events\n\n```js\nconst { VoiceConnectionStatus, AudioPlayerStatus } = require('@discordjs/voice');\n\nconnection.on(VoiceConnectionStatus.Ready, (oldState, newState) => {\n\tconsole.log('Connection is in the Ready state!');\n});\n\nplayer.on(AudioPlayerStatus.Playing, (oldState, newState) => {\n\tconsole.log('Audio player is in the Playing state!');\n});\n```\n\n<Callout>\n\tOne advantage of listening for transitions to individual states is that it becomes a lot easier to write sequential logic. This is made easy using our [state transition helper](https://github.com/discordjs/discord.js/blob/main/packages/voice/src/util/entersState.ts). An example is shown below.\n\n    ```js\n    const { AudioPlayerStatus, entersState } = require('@discordjs/voice');\n\n    async function start() {\n    \tplayer.play(resource);\n    \ttry {\n    \t\tawait entersState(player, AudioPlayerStatus.Playing, 5_000);\n    \t\t// The player has entered the Playing state within 5 seconds\n    \t\tconsole.log('Playback has started!');\n    \t} catch (error) {\n    \t\t// The player has not entered the Playing state and either:\n    \t\t// 1) The 'error' event has been emitted and should be handled\n    \t\t// 2) 5 seconds have passed\n    \t\tconsole.error(error);\n    \t}\n    }\n\n    void start();\n    ```\n\n</Callout>\n\n## Subscribing to all state transitions\n\nIf you would prefer to keep a single event listener for all possible state transitions, then you can also listen to the `stateChange` event:\n\n```js\nconnection.on('stateChange', (oldState, newState) => {\n\tconsole.log(`Connection transitioned from ${oldState.status} to ${newState.status}`);\n});\n\nplayer.on('stateChange', (oldState, newState) => {\n\tconsole.log(`Audio player transitioned from ${oldState.status} to ${newState.status}`);\n});\n```\n"
  },
  {
    "path": "apps/guide/content/docs/voice/meta.json",
    "content": "{\n\t\"title\": \"Voice\",\n\t\"description\": \"Working with the voice library\",\n\t\"pages\": [\n\t\t\"external:[LibraryBig][Documentation](https://discord.js.org/docs/packages/voice/main)\",\n\t\t\"---Working with Voice---\",\n\t\t\"index\",\n\t\t\"life-cycles\",\n\t\t\"voice-connections\",\n\t\t\"audio-player\",\n\t\t\"audio-resources\",\n\t\t\"seeking\"\n\t],\n\t\"root\": true,\n\t\"icon\": \"Volume2\"\n}\n"
  },
  {
    "path": "apps/guide/content/docs/voice/seeking.mdx",
    "content": "---\ntitle: Seeking\n---\n\nThere is no built-in method for seeking audio resources in discord.js. However external libraries such as `prism-media` can be used to tackle this issue.\n\n## Seeking in a stream\n\nTo seek resource, you can create a new function with the following code:\n\n```js\n// Require necessary package\nconst prism = require('prism-media'); // [!code word:prism]\n\nfunction createFFmpegStream(stream, seek) {\n\tlet seekPosition = '0';\n\tif (seek) seekPosition = String(seek);\n\tconst transcoder = new prism.FFmpeg({\n\t\targs: [\n\t\t\t'-analyzeduration',\n\t\t\t'0',\n\t\t\t'-loglevel',\n\t\t\t'0',\n\t\t\t'-f',\n\t\t\t's16le',\n\t\t\t'-ar',\n\t\t\t'48000',\n\t\t\t'-ac',\n\t\t\t'2',\n\t\t\t'-ss',\n\t\t\tseekPosition,\n\t\t\t'-ab',\n\t\t\t'320',\n\t\t],\n\t});\n\tconst s16le = stream.pipe(transcoder);\n\tconst opus = s16le.pipe(new prism.opus.Encoder({ rate: 48000, channels: 2, frameSize: 960 }));\n\treturn opus;\n}\n```\n\nThis function takes two arguments: the audio stream and the desired seek position, expressed as duration within the duration of the full stream. It returns the seeked stream.\n\n<Callout>\n\tYou can find configuration options in the [prism media documentation](https://amishshah.github.io/prism-media/).\n</Callout>\n\n## Using seek with the audio player\n\n```js\nconst { createAudioResource, createAudioPlayer } = require('@discordjs/voice');\nconst fs = require('fs');\n\nconst player = createAudioPlayer();\nconst normalAudioResource = createAudioResource('Your audio file path');\n\nplayer.play(normalAudioResource);\n\n// [!code word:createFFmpegStream]\nconst seekedAudioStream = createFFmpegStream(fs.createReadStream('Your audio file path'), 10); // Seek to 10s\nconst seekedAudioResource = createAudioResource(seekedAudioStream);\n\nplayer.play(seekedAudioResource);\n```\n"
  },
  {
    "path": "apps/guide/content/docs/voice/voice-connections.mdx",
    "content": "---\ntitle: Voice Connections\n---\n\nVoice connections represent connections to voice channels in a guild. You can only connect to one voice channel in a guild at a time.\n\nVoice connections will automatically try their best to re-establish their connections when they move across voice channels, or if the voice server region changes.\n\n## Cheat sheet\n\n### Creation\n\nCreating a voice connection is simple:\n\n```js\nconst { joinVoiceChannel } = require('@discordjs/voice');\n\nconst connection = joinVoiceChannel({\n\tchannelId: channel.id,\n\tguildId: channel.guild.id,\n\tadapterCreator: channel.guild.voiceAdapterCreator,\n});\n```\n\nIf you try to call `joinVoiceChannel` on another channel in the same guild in which there is already an active voice connection, the existing voice connection switches over to the new channel.\n\n### Access\n\nYou can access created connections elsewhere in your code without having to track the connections yourself. It is best practice to not track the voice connections yourself as you may forget to clean them up once they are destroyed, leading to memory leaks.\n\n```js\nconst { getVoiceConnection } = require('@discordjs/voice');\n\nconst connection = getVoiceConnection(myVoiceChannel.guild.id);\n```\n\n### Deletion\n\nYou can destroy a voice connection when you no longer require it. This will disconnect its connection if it is still active, stop audio playing to it, and will remove it from the internal tracker for voice connections.\n\nIt's important that you destroy voice connections when they are no longer required so that your bot leaves the voice channel, and to prevent memory leaks.\n\n```js\nconnection.destroy();\n```\n\n### Playing audio\n\nYou can subscribe voice connections to audio players as soon as they're created. Audio players will try to stream audio to all their subscribed voice connections that are in the Ready state. Destroyed voice connections cannot be subscribed to audio players.\n\n```js\n// Subscribe the connection to the audio player (will play audio on the voice connection)\nconst subscription = connection.subscribe(audioPlayer);\n\n// subscription could be undefined if the connection is destroyed!\nif (subscription) {\n\t// Unsubscribe after 5 seconds (stop playing audio on the voice connection)\n\tsetTimeout(() => subscription.unsubscribe(), 5_000);\n}\n```\n\n<Callout>\n    **Voice connections can be subscribed to one audio player at most.** If you try to subscribe to another audio player while already subscribed to one, the current audio player is unsubscribed and replaced with the new one.\n\n    It is also worth noting that the **GuildVoiceStates** [gateway intent](../legacy/popular-topics/intents) is required. Without it, the connection will permanently stay in the `signalling` state, and you'll be unable to play audio.\n\n</Callout>\n\n## Life cycle\n\nVoice connections have their own life cycle, with five distinct states. You can follow the methods discussed in the [life cycles](./life-cycles) section to subscribe to changes to voice connections.\n\n- **Signalling** - the initial state of a voice connection. The connection will be in this state when it is requesting permission to join a voice channel.\n\n- **Connecting** - the state a voice connection enters once it has permission to join a voice channel and is in the process of establishing a connection to it.\n\n- **Ready** - the state a voice connection enters once it has successfully established a connection to the voice channel. It is ready to play audio in this state.\n\n- **Disconnected** - the state a voice connection enters when the connection to a voice channel has been severed. This can occur even if the connection has not yet been established. You may choose to attempt to reconnect in this state.\n\n- **Destroyed** - the state a voice connection enters when it has been manually been destroyed. This will prevent it from accidentally being reused, and it will be removed from an in-memory tracker of voice connections.\n\n```js\nconst { VoiceConnectionStatus } = require('@discordjs/voice');\n\nconnection.on(VoiceConnectionStatus.Ready, () => {\n\tconsole.log('The connection has entered the Ready state - ready to play audio!');\n});\n```\n\n## Handling disconnects\n\nDisconnects can be quite complex to handle. There are 3 cases for handling disconnects:\n\n1. **Resumable disconnects** - there is no clear reason why the disconnect occurred. In this case, voice connections will automatically try to resume the existing session. The voice connection will enter the `Connecting` state. If this fails, it may enter a `Disconnected` state again.\n\n2. **Reconnectable disconnects** - Discord has closed the connection and given a reason as to why, and that the reason is recoverable. In this case, the voice connection will automatically try to rejoin the voice channel. The voice connection will enter the `Signalling` state. If this fails, it may enter a `Disconnected` state again.\n\n3. **Potentially reconnectable disconnects** - the bot has either been moved to another voice channel, the channel has been deleted, or the bot has been kicked/lost access to the voice channel. The bot will enter the `Disconnected` state.\n\nAs shown above, the first two cases are covered automatically by the voice connection itself. The only case you need to think carefully about is the third case.\n\nThe third case can be quite problematic to treat as a disconnect, as the bot could simply be moving to another voice channel and so not \"truly\" disconnected.\n\nAn imperfect workaround to this is to see if the bot has entered a `Signalling` / `Connecting` state shortly after entering the `Disconnected` state. If it has, then it means that the bot has moved voice channels. Otherwise, we should treat it as a real disconnect and not reconnect.\n\n```js\nconst { VoiceConnectionStatus, entersState } = require('@discordjs/voice');\n\nconnection.on(VoiceConnectionStatus.Disconnected, async (oldState, newState) => {\n\ttry {\n\t\tawait Promise.race([\n\t\t\tentersState(connection, VoiceConnectionStatus.Signalling, 5_000),\n\t\t\tentersState(connection, VoiceConnectionStatus.Connecting, 5_000),\n\t\t]);\n\t\t// Seems to be reconnecting to a new channel - ignore disconnect\n\t} catch {\n\t\t// Seems to be a real disconnect which SHOULDN'T be recovered from\n\t\tconnection.destroy();\n\t}\n});\n```\n"
  },
  {
    "path": "apps/guide/next.config.ts",
    "content": "import { createMDX } from 'fumadocs-mdx/next';\nimport type { NextConfig } from 'next';\n\nconst withMDX = createMDX();\n\nexport default withMDX({\n\tserverExternalPackages: ['typescript', 'twoslash'],\n\timages: {\n\t\tdangerouslyAllowSVG: true,\n\t\tcontentDispositionType: 'attachment',\n\t\tcontentSecurityPolicy: \"default-src 'self'; frame-src 'none'; sandbox;\",\n\t\tremotePatterns: [\n\t\t\t{\n\t\t\t\tprotocol: 'http',\n\t\t\t\thostname: 'localhost',\n\t\t\t},\n\t\t],\n\t},\n\tpoweredByHeader: false,\n\tlogging: {\n\t\tfetches: {\n\t\t\tfullUrl: true,\n\t\t},\n\t},\n\treactCompiler: true,\n\ttypescript: {\n\t\tignoreBuildErrors: true,\n\t},\n\twebpack(config) {\n\t\tconfig.module.rules.push({\n\t\t\ttest: /\\.svg$/,\n\t\t\tuse: ['@svgr/webpack'],\n\t\t});\n\n\t\treturn config;\n\t},\n} satisfies NextConfig);\n"
  },
  {
    "path": "apps/guide/open-next.config.ts",
    "content": "import { defineCloudflareConfig } from '@opennextjs/cloudflare';\n\nexport default defineCloudflareConfig();\n"
  },
  {
    "path": "apps/guide/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/guide\",\n\t\"version\": \"0.1.0\",\n\t\"description\": \"Imagine a bot... the most popular way to build discord bots\",\n\t\"private\": true,\n\t\"scripts\": {\n\t\t\"cf-typegen\": \"wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts\",\n\t\t\"build:check\": \"tsc --noEmit\",\n\t\t\"build:local\": \"cross-env NEXT_PUBLIC_LOCAL_DEV=true pnpm run build:prod\",\n\t\t\"build:prod\": \"pnpm run build:next\",\n\t\t\"build:next\": \"next build\",\n\t\t\"build\": \"next build\",\n\t\t\"preview\": \"next start\",\n\t\t\"preview:cf\": \"opennextjs-cloudflare build && opennextjs-cloudflare preview\",\n\t\t\"deploy:cf\": \"opennextjs-cloudflare build && opennextjs-cloudflare deploy\",\n\t\t\"dev\": \"next dev -p 3001 --turbopack\",\n\t\t\"lint\": \"pnpm run build:check && prettier --check . && cross-env TIMING=1 eslint --format=pretty src \",\n\t\t\"format\": \"pnpm run build:check && prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src \",\n\t\t\"fmt\": \"pnpm run format\",\n\t\t\"postinstall\": \"next typegen && fumadocs-mdx\"\n\t},\n\t\"type\": \"module\",\n\t\"directories\": {\n\t\t\"lib\": \"src\"\n\t},\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"discord\",\n\t\t\"api\",\n\t\t\"bot\",\n\t\t\"client\",\n\t\t\"node\",\n\t\t\"discordapp\",\n\t\t\"discordjs\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"apps/website\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"@opennextjs/cloudflare\": \"^1.16.5\",\n\t\t\"@vercel/analytics\": \"^1.6.1\",\n\t\t\"fumadocs-core\": \"^16.6.3\",\n\t\t\"fumadocs-mdx\": \"^14.2.7\",\n\t\t\"fumadocs-twoslash\": \"^3.1.13\",\n\t\t\"fumadocs-ui\": \"^16.6.3\",\n\t\t\"geist\": \"^1.7.0\",\n\t\t\"lucide-react\": \"^0.559.0\",\n\t\t\"mermaid\": \"^11.12.3\",\n\t\t\"next\": \"^16.1.6\",\n\t\t\"next-themes\": \"^0.4.6\",\n\t\t\"p-retry\": \"^7.1.1\",\n\t\t\"react\": \"^19.2.4\",\n\t\t\"react-dom\": \"^19.2.4\",\n\t\t\"sharp\": \"^0.34.5\",\n\t\t\"tailwind-merge\": \"^3.5.0\",\n\t\t\"tw-animate-css\": \"^1.4.0\",\n\t\t\"twoslash\": \"^0.3.6\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@shikijs/rehype\": \"^3.22.0\",\n\t\t\"@tailwindcss/postcss\": \"^4.2.0\",\n\t\t\"@types/mdx\": \"^2.0.13\",\n\t\t\"@types/node\": \"^24.10.13\",\n\t\t\"@types/react\": \"^19.2.14\",\n\t\t\"@types/react-dom\": \"^19.2.3\",\n\t\t\"autoprefixer\": \"^10.4.24\",\n\t\t\"babel-plugin-react-compiler\": \"^1.0.0\",\n\t\t\"cpy-cli\": \"^6.0.0\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"git-describe\": \"^4.1.1\",\n\t\t\"postcss\": \"^8.5.6\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"prettier-plugin-tailwindcss\": \"^0.7.2\",\n\t\t\"remark-gfm\": \"^4.0.1\",\n\t\t\"remark-rehype\": \"^11.1.2\",\n\t\t\"shiki\": \"^3.22.0\",\n\t\t\"tailwindcss\": \"^4.2.0\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vercel\": \"^49.2.0\",\n\t\t\"wrangler\": \"^4.67.0\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t}\n}\n"
  },
  {
    "path": "apps/guide/postcss.config.js",
    "content": "export default {\n\tplugins: {\n\t\t'@tailwindcss/postcss': {},\n\t},\n};\n"
  },
  {
    "path": "apps/guide/public/_headers",
    "content": "/_next/static/*\n  Cache-Control: public,max-age=31536000,immutable\n"
  },
  {
    "path": "apps/guide/public/site.webmanifest",
    "content": "{\n\t\"name\": \"discord.js\",\n\t\"short_name\": \"discord.js\",\n\t\"icons\": [\n\t\t{\n\t\t\t\"src\": \"/web-app-manifest-192x192.png\",\n\t\t\t\"sizes\": \"192x192\",\n\t\t\t\"type\": \"image/png\",\n\t\t\t\"purpose\": \"maskable\"\n\t\t},\n\t\t{\n\t\t\t\"src\": \"/web-app-manifest-512x512.png\",\n\t\t\t\"sizes\": \"512x512\",\n\t\t\t\"type\": \"image/png\",\n\t\t\t\"purpose\": \"maskable\"\n\t\t}\n\t],\n\t\"theme_color\": \"#1a1b1e\",\n\t\"background_color\": \"#1a1b1e\",\n\t\"display\": \"standalone\"\n}\n"
  },
  {
    "path": "apps/guide/source.config.ts",
    "content": "import { rehypeCodeDefaultOptions } from 'fumadocs-core/mdx-plugins';\nimport { defineConfig, defineDocs } from 'fumadocs-mdx/config';\nimport { transformerTwoslash } from 'fumadocs-twoslash';\nimport { createFileSystemTypesCache } from 'fumadocs-twoslash/cache-fs';\n\nexport const docs = defineDocs({\n\tdir: 'content/docs',\n});\n\ntransformerTwoslash({\n\ttypesCache: createFileSystemTypesCache(),\n});\n\nexport default defineConfig({\n\tmdxOptions: {\n\t\trehypeCodeOptions: {\n\t\t\tthemes: {\n\t\t\t\tlight: 'github-light',\n\t\t\t\tdark: 'github-dark',\n\t\t\t},\n\t\t\ttransformers: [...(rehypeCodeDefaultOptions.transformers ?? []), transformerTwoslash()],\n\t\t},\n\t},\n});\n"
  },
  {
    "path": "apps/guide/src/app/[[...slug]]/page.tsx",
    "content": "import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/page';\nimport type { Metadata } from 'next';\nimport { notFound } from 'next/navigation';\nimport { source } from '@/lib/source';\nimport { getMDXComponents } from '@/mdx-components';\n\nexport async function generateStaticParams() {\n\treturn source.generateParams();\n}\n\nexport async function generateMetadata(props: { params: Promise<{ slug?: string[] }> }): Promise<Metadata> {\n\tconst params = await props.params;\n\tconst page = source.getPage(params.slug);\n\n\tif (!page) {\n\t\tnotFound();\n\t}\n\n\tconst image = ['/og', ...(params.slug ?? []), 'image.png'].join('/');\n\treturn {\n\t\ttitle: page.data.title,\n\t\tdescription: page.data.description,\n\t\topenGraph: {\n\t\t\timages: image,\n\t\t},\n\t\ttwitter: {\n\t\t\tcard: 'summary_large_image',\n\t\t\timages: image,\n\t\t},\n\t};\n}\n\nexport default async function Page(props: { readonly params: Promise<{ slug?: string[] }> }) {\n\tconst params = await props.params;\n\tconst page = source.getPage(params.slug);\n\n\tif (!page) {\n\t\tnotFound();\n\t}\n\n\tconst MDX = page.data.body;\n\n\treturn (\n\t\t<DocsPage full={page.data.full!} toc={page.data.toc}>\n\t\t\t<DocsTitle>{page.data.title}</DocsTitle>\n\t\t\t<DocsDescription>{page.data.description}</DocsDescription>\n\t\t\t<DocsBody>\n\t\t\t\t{/* eslint-disable-next-line @stylistic/jsx-pascal-case */}\n\t\t\t\t<MDX components={getMDXComponents()} />\n\t\t\t</DocsBody>\n\t\t</DocsPage>\n\t);\n}\n"
  },
  {
    "path": "apps/guide/src/app/api/search/route.ts",
    "content": "import { createFromSource } from 'fumadocs-core/search/server';\nimport { source } from '@/lib/source';\n\nexport const { GET } = createFromSource(source);\n"
  },
  {
    "path": "apps/guide/src/app/layout.client.tsx",
    "content": "'use client';\n\nimport { useParams } from 'next/navigation';\nimport type { ReactNode } from 'react';\n\nexport function Body({ children }: { readonly children: ReactNode }): React.ReactElement {\n\tconst mode = useMode();\n\n\t// page highlight color based on path src/styles/base.css\n\treturn <body className={`${mode ? `${mode} ` : ''}overscroll-y-none`}>{children}</body>;\n}\n\nexport function useMode(): string | undefined {\n\tconst { slug } = useParams();\n\treturn Array.isArray(slug) && slug.length > 0 ? slug[0] : undefined;\n}\n"
  },
  {
    "path": "apps/guide/src/app/layout.config.tsx",
    "content": "import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';\n\nexport const baseOptions: BaseLayoutProps = {\n\tnav: {\n\t\ttitle: 'discord.js Guide',\n\t},\n};\n"
  },
  {
    "path": "apps/guide/src/app/layout.tsx",
    "content": "import { Analytics } from '@vercel/analytics/react';\nimport { DocsLayout } from 'fumadocs-ui/layouts/docs';\nimport { RootProvider } from 'fumadocs-ui/provider/next';\nimport { GeistMono } from 'geist/font/mono';\nimport { GeistSans } from 'geist/font/sans';\nimport type { Metadata, Viewport } from 'next';\nimport type { CSSProperties, PropsWithChildren } from 'react';\nimport { Body } from '@/app/layout.client';\nimport { source } from '@/lib/source';\nimport { ENV } from '@/util/env';\nimport { baseOptions } from './layout.config';\n\nimport '@/styles/base.css';\n\nexport const viewport: Viewport = {\n\tthemeColor: [\n\t\t{ media: '(prefers-color-scheme: light)', color: '#fbfbfb' },\n\t\t{ media: '(prefers-color-scheme: dark)', color: '#1a1a1e' },\n\t],\n\tcolorScheme: 'light dark',\n};\n\nexport const metadata: Metadata = {\n\tmetadataBase: new URL(ENV.IS_LOCAL_DEV ? `http://localhost:${ENV.PORT}` : 'https://discordjs.guide'),\n\ttitle: {\n\t\ttemplate: '%s | discord.js',\n\t\tdefault: 'discord.js',\n\t},\n\ticons: {\n\t\tother: [\n\t\t\t{\n\t\t\t\turl: '/favicon-96x96.png',\n\t\t\t\tsizes: '96x96',\n\t\t\t\ttype: 'image/png',\n\t\t\t},\n\t\t],\n\t\tapple: ['/apple-touch-icon.png'],\n\t},\n\n\tmanifest: '/site.webmanifest',\n\n\topenGraph: {\n\t\tsiteName: 'discord.js',\n\t\ttype: 'website',\n\t\ttitle: 'discord.js',\n\t},\n\n\ttwitter: {\n\t\tcard: 'summary_large_image',\n\t\tcreator: '@iCrawlToGo',\n\t},\n};\n\nexport default async function RootLayout({ children }: PropsWithChildren) {\n\treturn (\n\t\t<html className={`${GeistSans.variable} ${GeistMono.variable} antialiased`} lang=\"en\" suppressHydrationWarning>\n\t\t\t<Body>\n\t\t\t\t<RootProvider>\n\t\t\t\t\t<DocsLayout\n\t\t\t\t\t\tsidebar={{\n\t\t\t\t\t\t\ttabs: {\n\t\t\t\t\t\t\t\ttransform(option, node) {\n\t\t\t\t\t\t\t\t\tconst meta = source.getNodeMeta(node);\n\t\t\t\t\t\t\t\t\tif (!meta || !node.icon) return option;\n\n\t\t\t\t\t\t\t\t\t// category selection color based on path src/styles/base.css\n\t\t\t\t\t\t\t\t\tconst color = `var(--${meta.path.split('/')[0]}-color, var(--color-fd-foreground))`;\n\n\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\t...option,\n\t\t\t\t\t\t\t\t\t\ticon: (\n\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"size-full rounded-lg text-(--tab-color) max-md:border max-md:bg-(--tab-color)/10 max-md:p-1.5 [&_svg]:size-full\"\n\t\t\t\t\t\t\t\t\t\t\t\tstyle={\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'--tab-color': color,\n\t\t\t\t\t\t\t\t\t\t\t\t\t} as CSSProperties\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{node.icon}\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}}\n\t\t\t\t\t\ttree={source.pageTree}\n\t\t\t\t\t\t{...baseOptions}\n\t\t\t\t\t>\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</DocsLayout>\n\t\t\t\t</RootProvider>\n\t\t\t\t<Analytics />\n\t\t\t</Body>\n\t\t</html>\n\t);\n}\n"
  },
  {
    "path": "apps/guide/src/app/og/[...slug]/route.tsx",
    "content": "import { generateOGImage } from 'fumadocs-ui/og';\nimport { notFound } from 'next/navigation';\nimport pRetry, { AbortError } from 'p-retry';\nimport { source } from '@/lib/source';\n\nexport function generateStaticParams() {\n\treturn source.generateParams().map((page) => ({\n\t\t...page,\n\t\tslug: [...page.slug, 'image.png'],\n\t}));\n}\n\nasync function loadGoogleFont(font: string, text: string) {\n\treturn pRetry(\n\t\tasync () => {\n\t\t\tconst url = `https://fonts.googleapis.com/css2?family=${font}&text=${encodeURIComponent(text)}`;\n\t\t\tconst css = await (await fetch(url)).text();\n\t\t\t// eslint-disable-next-line prefer-named-capture-group\n\t\t\tconst resource = /src: url\\((.+)\\) format\\('(opentype|truetype)'\\)/.exec(css);\n\n\t\t\tif (resource) {\n\t\t\t\tconst response = await fetch(resource[1]!);\n\t\t\t\tif (response.status === 200) {\n\t\t\t\t\treturn response.arrayBuffer();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow new AbortError('failed to load font data');\n\t\t},\n\t\t{\n\t\t\tretries: 3,\n\t\t},\n\t);\n}\n\nexport async function GET(_req: Request, { params }: { params: Promise<{ slug: string[] }> }) {\n\tconst { slug } = await params;\n\tconst page = source.getPage(slug.slice(0, -1));\n\n\tif (!page) {\n\t\tnotFound();\n\t}\n\n\treturn generateOGImage({\n\t\ttitle: page.data.title,\n\t\tdescription: page.data.description,\n\t\tsite: 'discord.js Guide',\n\t\tfonts: [\n\t\t\t{\n\t\t\t\tname: 'Geist',\n\t\t\t\tdata: await loadGoogleFont('Geist:wght@400', page.data.title),\n\t\t\t\tweight: 400,\n\t\t\t\tstyle: 'normal',\n\t\t\t},\n\t\t],\n\t});\n}\n"
  },
  {
    "path": "apps/guide/src/components/GitHubInfo.tsx",
    "content": "// https://github.com/fuma-nama/fumadocs/blob/dev/packages/ui/src/components/github-info.tsx\n// https://github.com/fuma-nama/fumadocs/blob/dev/LICENSE\n\nimport { Star } from 'lucide-react';\nimport { type AnchorHTMLAttributes } from 'react';\nimport { twMerge as cn } from 'tailwind-merge';\n\nasync function getRepoStars(owner: string, repo: string, token?: string): Promise<{ stars: number } | null> {\n\tconst endpoint = `https://api.github.com/repos/${owner}/${repo}`;\n\tconst headers = new Headers({\n\t\t'Content-Type': 'application/json',\n\t\t'User-Agent': 'discordjs-guide',\n\t});\n\n\tif (token) headers.set('Authorization', `Bearer ${token}`);\n\n\tconst response = await fetch(endpoint, {\n\t\theaders,\n\t\tnext: {\n\t\t\trevalidate: 24 * 60 * 60,\n\t\t},\n\t});\n\n\tif (!response.ok) {\n\t\tconst message = await response.text();\n\t\tconsole.warn(`Failed to fetch repository data (${response.status}):`, message);\n\t\treturn null;\n\t}\n\n\tconst data = await response.json();\n\treturn { stars: data.stargazers_count };\n}\n\nexport async function GithubInfo({\n\trepo,\n\towner,\n\ttoken,\n\t...props\n}: AnchorHTMLAttributes<HTMLAnchorElement> & {\n\treadonly owner: string;\n\treadonly repo: string;\n\treadonly token?: string;\n}) {\n\tconst repoData = await getRepoStars(owner, repo, token);\n\n\treturn (\n\t\t<a\n\t\t\thref={`https://github.com/${owner}/${repo}`}\n\t\t\trel=\"noreferrer noopener\"\n\t\t\ttarget=\"_blank\"\n\t\t\t{...props}\n\t\t\tclassName={cn(\n\t\t\t\t'text-fd-foreground/80 hover:text-fd-accent-foreground hover:bg-fd-accent flex flex-col gap-1.5 rounded-lg p-2 text-sm transition-colors lg:flex-row lg:items-center',\n\t\t\t\tprops.className,\n\t\t\t)}\n\t\t>\n\t\t\t<p className=\"flex items-center gap-2 truncate\">\n\t\t\t\t<svg className=\"size-3.5\" fill=\"currentColor\" viewBox=\"0 0 24 24\">\n\t\t\t\t\t<title>GitHub</title>\n\t\t\t\t\t<path d=\"M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12\" />\n\t\t\t\t</svg>\n\t\t\t\t{owner}/{repo}\n\t\t\t</p>\n\t\t\t{repoData ? (\n\t\t\t\t<p className=\"text-fd-muted-foreground flex items-center gap-1 text-xs\">\n\t\t\t\t\t<Star className=\"size-3\" />\n\t\t\t\t\t{humanizeNumber(repoData.stars)}\n\t\t\t\t</p>\n\t\t\t) : null}\n\t\t</a>\n\t);\n}\n\n/**\n * Converts a number to a human-readable string with K suffix for thousands\n *\n * @example 1500 -> \"1.5K\", 1000000 -> \"1000000\"\n */\nfunction humanizeNumber(num: number): string {\n\tif (num < 1_000) {\n\t\treturn num.toString();\n\t}\n\n\tif (num < 100_000) {\n\t\t// For numbers between 1,000 and 99,999, show with one decimal (e.g., 1.5K)\n\t\tconst value = (num / 1_000).toFixed(1);\n\t\t// Remove trailing .0 if present\n\t\tconst formattedValue = value.endsWith('.0') ? value.slice(0, -2) : value;\n\n\t\treturn `${formattedValue}K`;\n\t}\n\n\tif (num < 1_000_000) {\n\t\t// For numbers between 10,000 and 999,999, show as whole K (e.g., 10K, 999K)\n\t\treturn `${Math.floor(num / 1_000)}K`;\n\t}\n\n\t// For 1,000,000 and above, just return the number\n\treturn num.toString();\n}\n"
  },
  {
    "path": "apps/guide/src/components/mdx/mermaid.tsx",
    "content": "'use client';\n\nimport { useTheme } from 'next-themes';\nimport { useEffect, useId, useRef, useState } from 'react';\n\nexport function Mermaid({ chart }: { readonly chart: string }) {\n\tconst id = useId();\n\tconst [svg, setSvg] = useState('');\n\tconst containerRef = useRef<HTMLDivElement>(null);\n\tconst currentChartRef = useRef<string>(null);\n\tconst { resolvedTheme } = useTheme();\n\n\tuseEffect(() => {\n\t\tif (currentChartRef.current === chart || !containerRef.current) return;\n\t\tconst container = containerRef.current;\n\t\tcurrentChartRef.current = chart;\n\n\t\tasync function renderChart() {\n\t\t\tconst { default: mermaid } = await import('mermaid');\n\n\t\t\ttry {\n\t\t\t\t// configure mermaid\n\t\t\t\tmermaid.initialize({\n\t\t\t\t\tstartOnLoad: false,\n\t\t\t\t\tsecurityLevel: 'loose',\n\t\t\t\t\tfontFamily: 'inherit',\n\t\t\t\t\tthemeCSS: 'margin: 1.5rem auto 0;',\n\t\t\t\t\ttheme: resolvedTheme === 'dark' ? 'dark' : 'default',\n\t\t\t\t});\n\n\t\t\t\tconst { svg, bindFunctions } = await mermaid.render(id, chart.replaceAll('\\\\n', '\\n'));\n\n\t\t\t\tbindFunctions?.(container);\n\t\t\t\tsetSvg(svg);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('Error while rendering mermaid', error);\n\t\t\t}\n\t\t}\n\n\t\tvoid renderChart();\n\t}, [chart, id, resolvedTheme]);\n\n\t// eslint-disable-next-line react/no-danger\n\treturn <div dangerouslySetInnerHTML={{ __html: svg }} ref={containerRef} />;\n}\n"
  },
  {
    "path": "apps/guide/src/lib/source.ts",
    "content": "import { loader } from 'fumadocs-core/source';\nimport { icons } from 'lucide-react';\nimport { createElement } from 'react';\nimport { docs } from '../../.source/server';\n\nexport const source = loader({\n\ticon(icon) {\n\t\tif (!icon) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (icon in icons) {\n\t\t\treturn createElement(icons[icon as keyof typeof icons]);\n\t\t}\n\n\t\treturn undefined;\n\t},\n\tbaseUrl: '/',\n\tsource: docs.toFumadocsSource(),\n});\n"
  },
  {
    "path": "apps/guide/src/mdx-components.tsx",
    "content": "import { Popup, PopupContent, PopupTrigger } from 'fumadocs-twoslash/ui';\nimport * as TabsComponents from 'fumadocs-ui/components/tabs';\nimport defaultMdxComponents from 'fumadocs-ui/mdx';\nimport type { MDXComponents } from 'mdx/types';\nimport { Mermaid } from '@/components/mdx/mermaid';\n\nexport function getMDXComponents(components?: MDXComponents): MDXComponents {\n\treturn {\n\t\t...defaultMdxComponents,\n\t\tPopup,\n\t\tPopupContent,\n\t\tPopupTrigger,\n\t\tMermaid,\n\t\t...TabsComponents,\n\t\t...components,\n\t};\n}\n"
  },
  {
    "path": "apps/guide/src/middleware.ts",
    "content": "import { NextResponse, type NextRequest } from 'next/server';\n\nexport function middleware(request: NextRequest) {\n\t// TODO: Remove this eventually\n\tif (request.nextUrl.pathname.startsWith('/guide/')) {\n\t\tconst newUrl = request.nextUrl.clone();\n\t\tnewUrl.pathname = newUrl.pathname.replace('/guide/', '/');\n\t\treturn NextResponse.redirect(newUrl);\n\t}\n\n\t// Redirect old urls to /legacy\n\tif (\n\t\t!request.nextUrl.pathname.startsWith('/legacy') &&\n\t\t!request.nextUrl.pathname.startsWith('/voice') &&\n\t\t!request.nextUrl.pathname.startsWith('/v15')\n\t) {\n\t\tconst newUrl = request.nextUrl.clone();\n\t\tnewUrl.pathname = `/legacy${newUrl.pathname}`;\n\t\treturn NextResponse.redirect(newUrl);\n\t}\n\n\treturn NextResponse.next();\n}\n\nexport const config = {\n\tmatcher: ['/((?!_next|api|og|.*\\\\..*|_static).*)'],\n};\n"
  },
  {
    "path": "apps/guide/src/styles/base.css",
    "content": "@import 'tailwindcss';\n@import 'fumadocs-ui/css/neutral.css';\n@import 'fumadocs-ui/css/preset.css';\n@import 'fumadocs-twoslash/twoslash.css';\n\n@import 'tw-animate-css';\n\n@custom-variant dark (&:where(.dark, .dark *));\n\n@theme {\n\t--font-sans: var(--font-geist-sans);\n\t--font-mono: var(--font-geist-mono);\n}\n\n@layer base {\n\t* {\n\t\tfont-family: var(--font-roboto);\n\t\ttext-rendering: optimizeLegibility;\n\n\t\tscrollbar-width: thin;\n\t}\n}\n\n@utility scrollbar-hidden {\n\tscrollbar-width: none;\n}\n\n:root {\n\t--legacy-color: hsl(153, 48%, 41%);\n\t--voice-color: hsl(211.3, 66.1%, 65.3%);\n\t--v15-color: oklch(70.4% 0.191 22.216);\n}\n\n.legacy {\n\t--color-fd-primary: var(--legacy-color);\n}\n\n.voice {\n\t--color-fd-primary: var(--voice-color);\n}\n\n.v15 {\n\t--color-fd-primary: var(--v15-color);\n}\n"
  },
  {
    "path": "apps/guide/src/util/env.ts",
    "content": "export const ENV = {\n\tIS_LOCAL_DEV: process.env.VERCEL_ENV === 'development' || process.env.NEXT_PUBLIC_LOCAL_DEV === 'true',\n\tIS_PREVIEW: process.env.VERCEL_ENV === 'preview',\n\tPORT: process.env.PORT ?? 3_001,\n};\n"
  },
  {
    "path": "apps/guide/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.tsx\",\n\t\t\"*.js\",\n\t\t\"*.jsx\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.tsx\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.jsx\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "apps/guide/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t// Modules\n\t\t\"baseUrl\": \".\",\n\n\t\t// Emit\n\t\t\"declaration\": false,\n\t\t\"declarationMap\": false,\n\t\t\"noEmit\": true,\n\t\t\"outDir\": \"dist\",\n\n\t\t// Interop Constraints\n\t\t\"esModuleInterop\": true,\n\t\t\"allowJs\": true,\n\t\t\"incremental\": true,\n\t\t\"skipLibCheck\": true,\n\n\t\t// Language and Environment\n\t\t\"jsx\": \"preserve\",\n\t\t\"lib\": [\"ESNext\", \"DOM\", \"DOM.Iterable\"],\n\n\t\t\"plugins\": [\n\t\t\t{\n\t\t\t\t\"name\": \"next\"\n\t\t\t}\n\t\t],\n\n\t\t\"paths\": {\n\t\t\t\"@/*\": [\"./src/*\"]\n\t\t}\n\t},\n\t\"include\": [\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.tsx\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.jsx\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"next-env.d.ts\",\n\t\t\".next/types/**/*.ts\",\n\t\t\"vitest.shims.d.ts\",\n\t\t\"__tests__/**/*.ts\",\n\t\t\"__tests__/**/*.tsx\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "apps/guide/wrangler.jsonc",
    "content": "{\n\t\"$schema\": \"node_modules/wrangler/config-schema.json\",\n\t\"main\": \".open-next/worker.js\",\n\t\"name\": \"discordjs-guide\",\n\t\"keep_names\": false,\n\t\"compatibility_date\": \"2025-10-04\",\n\t\"compatibility_flags\": [\"nodejs_compat\"],\n\t\"assets\": {\n\t\t\"directory\": \".open-next/assets\",\n\t\t\"binding\": \"ASSETS\",\n\t},\n\t\"observability\": {\n\t\t\"logs\": {\n\t\t\t\"enabled\": true,\n\t\t\t\"head_sampling_rate\": 1,\n\t\t\t\"invocation_logs\": true,\n\t\t},\n\t},\n}\n"
  },
  {
    "path": "apps/proxy-container/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\n\n# Miscellaneous\n.turbo\n.tmp\n"
  },
  {
    "path": "apps/proxy-container/.lintstagedrc.cjs",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "apps/proxy-container/.prettierignore",
    "content": ".turbo\ndist\ntsup.config.bundled*\n"
  },
  {
    "path": "apps/proxy-container/.prettierrc.cjs",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "apps/proxy-container/Dockerfile",
    "content": "FROM node:24-alpine AS base\n\nENV PNPM_HOME=\"/pnpm\"\nENV PATH=\"$PNPM_HOME:$PATH\"\n\nCOPY . /usr/proxy-container\nWORKDIR /usr/proxy-container\n\nRUN npm --global install corepack@latest\nRUN corepack enable\nRUN corepack install\n\nFROM base AS builder\n\nRUN pnpm --filter='@discordjs/proxy-container...' install --frozen-lockfile --ignore-scripts\nRUN pnpm exec turbo run build --filter='@discordjs/proxy-container...' --output-logs=full\n\nFROM builder AS pruned\n\nRUN pnpm --filter='@discordjs/proxy-container' --prod deploy --legacy pruned\n\nFROM node:24-alpine AS proxy\n\nWORKDIR /usr/proxy-container\n\nRUN addgroup --system --gid 1001 nodejs\nRUN adduser --system --uid 1001 proxy-container\nUSER proxy-container\n\nCOPY --from=pruned /usr/proxy-container/pruned .\n\nCMD [\"node\", \"--enable-source-maps\", \"dist/index.js\"]\n"
  },
  {
    "path": "apps/proxy-container/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2022 Noel Buechler\n   Copyright 2022 Denis Cristea\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "apps/proxy-container/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://hub.docker.com/r/discordjs/proxy\"><img src=\"https://img.shields.io/docker/v/discordjs/proxy.svg?sort=semver&maxAge=3600\" alt=\"dockerhub version\" /></a>\n\t\t<a href=\"https://hub.docker.com/r/discordjs/proxy\"><img src=\"https://img.shields.io/docker/pulls/discordjs/proxy.svg?maxAge=3600\" alt=\"dockerhub pulls\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## About\n\n`discordjs/proxy` - Lightweight HTTP proxy for Discord's API, brought to you as a container 📦\n\n## Usage\n\nQuickly spin up an instance:\n\n`docker run -d --restart unless-stopped --name proxy -p 127.0.0.1:8080:8080 discordjs/proxy`\n\nUse it:\n\n```ts\nimport { Client } from 'discord.js';\n\nconst client = new Client({\n\t// other options,\n\trest: {\n\t\tapi: 'http://localhost:8080/api',\n\t},\n});\n```\n\nOr with just `@discordjs/rest`:\n\n```ts\nimport { REST } from '@discordjs/rest';\n\nconst rest = new REST({\n\tapi: 'http://localhost:8080/api',\n});\n```\n\n**Do note that you should not use the same proxy with multiple bots. We cannot guarantee you won't hit rate limits.\nWebhooks with tokens or other requests that don't include the Authorization header are okay, though!**\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested.  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/apps/proxy-container\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "apps/proxy-container/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/proxy-container\",\n\t\"version\": \"1.0.0\",\n\t\"description\": \"Lightweight HTTP proxy for Discord's API, brought to you as a container 📦\",\n\t\"scripts\": {\n\t\t\"build\": \"tsc --noEmit && tsup\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src\",\n\t\t\"fmt\": \"pnpm run format\",\n\t\t\"prepack\": \"pnpm run lint && pnpm run build\"\n\t},\n\t\"type\": \"module\",\n\t\"directories\": {\n\t\t\"lib\": \"src\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"Amish Shah <amishshah.2k@gmail.com>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\",\n\t\t\"DD <didinele.dev@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"discord\",\n\t\t\"api\",\n\t\t\"rest\",\n\t\t\"proxy\",\n\t\t\"discordapp\",\n\t\t\"discordjs\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"apps/proxy-container\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"@discordjs/proxy\": \"workspace:^\",\n\t\t\"@discordjs/rest\": \"workspace:^\",\n\t\t\"tslib\": \"^2.8.1\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@types/node\": \"^24.10.13\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"terser\": \"^5.46.0\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "apps/proxy-container/src/index.ts",
    "content": "import { createServer } from 'node:http';\nimport process from 'node:process';\nimport { proxyRequests } from '@discordjs/proxy';\nimport { REST } from '@discordjs/rest';\n\nprocess.on('SIGINT', () => process.exit(0));\n\n// We want to let upstream handle retrying\nconst api = new REST({ rejectOnRateLimit: () => true, retries: 0 });\nconst server = createServer(proxyRequests(api));\n\nconst port = Number.parseInt(process.env.PORT ?? '8080', 10);\nserver.listen(port, () => console.log(`Listening on port ${port}`));\n"
  },
  {
    "path": "apps/proxy-container/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "apps/proxy-container/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "apps/proxy-container/tsup.config.ts",
    "content": "import { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tdts: false,\n\tformat: 'esm',\n\tminify: 'terser',\n});\n"
  },
  {
    "path": "apps/website/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n.env*.local\n\n# Dist\n.open-next\n.next\n.wrangler\npublic/searchIndex\npublic/readme\nsrc/assets/readme\nsrc/styles/unocss.css\n\n# Miscellaneous\n.tmp\n.vscode\nlighthouse-results\nnext-env.d.ts\n\n.vercel\n\nold_src\n"
  },
  {
    "path": "apps/website/.lintstagedrc.cjs",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "apps/website/.prettierignore",
    "content": ".next\n.turbo\n.vscode\ncoverage\npublic/searchIndex\nsrc/assets/readme\nsrc/styles/unocss.css\nnext-env.d.ts\nsrc/util/shiki.bundle.ts\n"
  },
  {
    "path": "apps/website/.prettierrc.cjs",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = {\n\t...require('../../.prettierrc.json'),\n\tplugins: ['prettier-plugin-tailwindcss'],\n\ttailwindFunctions: ['cva', 'cx'],\n};\n"
  },
  {
    "path": "apps/website/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2022 Noel Buechler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "apps/website/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Documentation][documentation]\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the\n[documentation][documentation].  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "apps/website/next.config.ts",
    "content": "import type { NextConfig } from 'next';\n\nexport default {\n\timages: {\n\t\tdangerouslyAllowSVG: true,\n\t\tcontentDispositionType: 'attachment',\n\t\tcontentSecurityPolicy: \"default-src 'self'; frame-src 'none'; sandbox;\",\n\t\tremotePatterns: [\n\t\t\t{\n\t\t\t\tprotocol: 'http',\n\t\t\t\thostname: 'localhost',\n\t\t\t},\n\t\t],\n\t},\n\tpoweredByHeader: false,\n\tlogging: {\n\t\tfetches: {\n\t\t\tfullUrl: true,\n\t\t},\n\t},\n\treactCompiler: true,\n\ttypescript: {\n\t\tignoreBuildErrors: true,\n\t},\n\tasync redirects() {\n\t\treturn [\n\t\t\t{\n\t\t\t\tsource: '/static/logo.svg',\n\t\t\t\tdestination: '/logo.svg',\n\t\t\t\tpermanent: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tsource: '/guide/:path*',\n\t\t\t\tdestination: 'https://discordjs.guide/:path*',\n\t\t\t\tpermanent: false,\n\t\t\t},\n\t\t];\n\t},\n} satisfies NextConfig;\n"
  },
  {
    "path": "apps/website/open-next.config.ts",
    "content": "import { defineCloudflareConfig } from '@opennextjs/cloudflare';\n\nexport default defineCloudflareConfig();\n"
  },
  {
    "path": "apps/website/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/website\",\n\t\"version\": \"0.1.0\",\n\t\"description\": \"Imagine a bot... the most popular way to build discord bots\",\n\t\"private\": true,\n\t\"scripts\": {\n\t\t\"cf-typegen\": \"wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts\",\n\t\t\"build:copy_readme\": \"cpy \\\"../../packages/(discord.js|brokers|builders|collection|core|formatters|next|proxy|rest|structures|util|voice|ws)/README.md\\\" \\\"src/assets/readme\\\" --rename='home-{{basename}}'\",\n\t\t\"build:check\": \"tsc --noEmit\",\n\t\t\"build:local\": \"cross-env NEXT_PUBLIC_LOCAL_DEV=true pnpm run build:prod\",\n\t\t\"build:prod\": \"pnpm run build:copy_readme && pnpm run build:next\",\n\t\t\"build:next\": \"next build\",\n\t\t\"build\": \"pnpm run build:copy_readme && next build --webpack\",\n\t\t\"build:search_indices\": \"pnpm node scripts/generateAllIndices.js\",\n\t\t\"build:analyze\": \"turbo run docs --filter='@discordjs/*' --concurrency=4 && cross-env ANALYZE=true NEXT_PUBLIC_LOCAL_DEV=true pnpm run build:prod\",\n\t\t\"preview\": \"next start\",\n\t\t\"preview:cf\": \"opennextjs-cloudflare build && opennextjs-cloudflare preview\",\n\t\t\"deploy:cf\": \"opennextjs-cloudflare build && opennextjs-cloudflare deploy\",\n\t\t\"dev\": \"next dev --turbopack\",\n\t\t\"lint\": \"pnpm run build:check && prettier --check . && cross-env TIMING=1 eslint --format=pretty src \",\n\t\t\"format\": \"pnpm run build:check && prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src \",\n\t\t\"fmt\": \"pnpm run format\",\n\t\t\"postinstall\": \"next typegen\"\n\t},\n\t\"type\": \"module\",\n\t\"directories\": {\n\t\t\"lib\": \"src\"\n\t},\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"discord\",\n\t\t\"api\",\n\t\t\"bot\",\n\t\t\"client\",\n\t\t\"node\",\n\t\t\"discordapp\",\n\t\t\"discordjs\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"apps/website\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"@opennextjs/cloudflare\": \"^1.16.5\",\n\t\t\"@radix-ui/react-collapsible\": \"^1.1.12\",\n\t\t\"@react-icons/all-files\": \"^4.1.0\",\n\t\t\"@tanstack/react-query\": \"^5.90.21\",\n\t\t\"@vercel/analytics\": \"^1.6.1\",\n\t\t\"@vercel/postgres\": \"^0.10.0\",\n\t\t\"cloudflare\": \"^5.2.0\",\n\t\t\"cmdk\": \"^1.1.1\",\n\t\t\"cva\": \"1.0.0-beta.3\",\n\t\t\"geist\": \"^1.7.0\",\n\t\t\"jotai\": \"^2.18.0\",\n\t\t\"lucide-react\": \"^0.559.0\",\n\t\t\"meilisearch\": \"^0.54.0\",\n\t\t\"next\": \"^16.1.6\",\n\t\t\"next-themes\": \"^0.4.6\",\n\t\t\"nuqs\": \"^2.8.8\",\n\t\t\"overlayscrollbars\": \"^2.14.0\",\n\t\t\"overlayscrollbars-react\": \"^0.5.6\",\n\t\t\"react\": \"^19.2.4\",\n\t\t\"react-aria\": \"^3.46.0\",\n\t\t\"react-aria-components\": \"^1.15.1\",\n\t\t\"react-dom\": \"^19.2.4\",\n\t\t\"safe-mdx\": \"^1.3.9\",\n\t\t\"sharp\": \"^0.34.5\",\n\t\t\"tailwind-merge\": \"^3.5.0\",\n\t\t\"tw-animate-css\": \"^1.4.0\",\n\t\t\"usehooks-ts\": \"^3.1.1\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@shikijs/rehype\": \"^3.22.0\",\n\t\t\"@tailwindcss/postcss\": \"^4.2.0\",\n\t\t\"@tailwindcss/typography\": \"^0.5.19\",\n\t\t\"@types/node\": \"^24.10.13\",\n\t\t\"@types/react\": \"^19.2.14\",\n\t\t\"@types/react-dom\": \"^19.2.3\",\n\t\t\"autoprefixer\": \"^10.4.24\",\n\t\t\"babel-plugin-react-compiler\": \"^1.0.0\",\n\t\t\"cpy-cli\": \"^6.0.0\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"git-describe\": \"^4.1.1\",\n\t\t\"postcss\": \"^8.5.6\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"prettier-plugin-tailwindcss\": \"^0.7.2\",\n\t\t\"remark-gfm\": \"^4.0.1\",\n\t\t\"remark-rehype\": \"^11.1.2\",\n\t\t\"shiki\": \"^3.22.0\",\n\t\t\"tailwindcss\": \"^4.2.0\",\n\t\t\"tailwindcss-react-aria-components\": \"^2.0.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vercel\": \"^49.2.0\",\n\t\t\"wrangler\": \"^4.67.0\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t}\n}\n"
  },
  {
    "path": "apps/website/postcss.config.js",
    "content": "export default {\n\tplugins: {\n\t\t'@tailwindcss/postcss': {},\n\t},\n};\n"
  },
  {
    "path": "apps/website/public/_headers",
    "content": "/_next/static/*\n  Cache-Control: public,max-age=31536000,immutable\n"
  },
  {
    "path": "apps/website/public/site.webmanifest",
    "content": "{\n\t\"name\": \"discord.js\",\n\t\"short_name\": \"discord.js\",\n\t\"icons\": [\n\t\t{\n\t\t\t\"src\": \"/web-app-manifest-192x192.png\",\n\t\t\t\"sizes\": \"192x192\",\n\t\t\t\"type\": \"image/png\",\n\t\t\t\"purpose\": \"maskable\"\n\t\t},\n\t\t{\n\t\t\t\"src\": \"/web-app-manifest-512x512.png\",\n\t\t\t\"sizes\": \"512x512\",\n\t\t\t\"type\": \"image/png\",\n\t\t\t\"purpose\": \"maskable\"\n\t\t}\n\t],\n\t\"theme_color\": \"#1a1b1e\",\n\t\"background_color\": \"#1a1b1e\",\n\t\"display\": \"standalone\"\n}\n"
  },
  {
    "path": "apps/website/scripts/generateAllIndices.js",
    "content": "import { readFile } from 'node:fs/promises';\nimport { generateAllIndices } from '@discordjs/scripts';\n\nconsole.info('Generating all indices...');\n\nawait generateAllIndices({\n\tfetchPackageVersions: () => ['main'],\n\tfetchPackageVersionDocs: async (pkg, version) => {\n\t\tconsole.log(`Fetching data for ${pkg} ${version}...`);\n\t\treturn JSON.parse(await readFile(`${process.cwd()}/../../../docs/${pkg}/${version}.api.json`, 'utf8'));\n\t},\n});\n\nconsole.info('Generated all indices.');\n"
  },
  {
    "path": "apps/website/src/app/api/docs/entrypoints/route.ts",
    "content": "import { NextResponse, type NextRequest } from 'next/server';\nimport { fetchEntryPoints } from '@/util/fetchEntryPoints';\n\nexport async function GET(request: NextRequest) {\n\tconst { searchParams } = request.nextUrl;\n\tconst packageName = searchParams.get('packageName');\n\tconst version = searchParams.get('version');\n\n\tif (!packageName || !version) {\n\t\treturn NextResponse.json({ error: 'Missing required parameters' }, { status: 400 });\n\t}\n\n\tconst response = await fetchEntryPoints(packageName, version);\n\n\treturn NextResponse.json(response);\n}\n"
  },
  {
    "path": "apps/website/src/app/api/docs/sitemap/route.ts",
    "content": "import { NextResponse, type NextRequest } from 'next/server';\nimport { fetchSitemap } from '@/util/fetchSitemap';\n\nexport async function GET(request: NextRequest) {\n\tconst { searchParams } = request.nextUrl;\n\tconst packageName = searchParams.get('packageName');\n\tconst version = searchParams.get('version');\n\tconst entryPoint = searchParams.get('entryPoint');\n\n\tif (!packageName || !version) {\n\t\treturn NextResponse.json({ error: 'Missing required parameters' }, { status: 400 });\n\t}\n\n\tconst response = await fetchSitemap({\n\t\tentryPoint,\n\t\tpackageName,\n\t\tversion,\n\t});\n\n\treturn NextResponse.json(response);\n}\n"
  },
  {
    "path": "apps/website/src/app/api/docs/versions/route.ts",
    "content": "import { NextResponse, type NextRequest } from 'next/server';\nimport { fetchVersions } from '@/util/fetchVersions';\n\nexport async function GET(request: NextRequest) {\n\tconst { searchParams } = request.nextUrl;\n\tconst packageName = searchParams.get('packageName');\n\n\tif (!packageName) {\n\t\treturn NextResponse.json({ error: 'Missing required parameters' }, { status: 400 });\n\t}\n\n\tconst response = await fetchVersions(packageName);\n\n\treturn NextResponse.json(response);\n}\n"
  },
  {
    "path": "apps/website/src/app/docs/packages/[packageName]/[version]/[[...item]]/CmdK.tsx",
    "content": "import { CmdKNoSRR } from '@/components/CmdK';\nimport { fetchDependencies } from '@/util/fetchDependencies';\n\nexport async function CmdK({\n\tparams,\n}: {\n\treadonly params: Promise<{ readonly packageName: string; readonly version: string }>;\n}) {\n\tconst { packageName, version } = await params;\n\n\tconst dependencies = await fetchDependencies({ packageName, version });\n\n\treturn <CmdKNoSRR dependencies={dependencies} />;\n}\n"
  },
  {
    "path": "apps/website/src/app/docs/packages/[packageName]/[version]/[[...item]]/layout.tsx",
    "content": "import type { Metadata } from 'next';\nimport { Suspense, type PropsWithChildren } from 'react';\nimport { CmdK } from './CmdK';\n\nexport async function generateMetadata({\n\tparams,\n}: {\n\treadonly params: Promise<{\n\t\treadonly item?: string[] | undefined;\n\t\treadonly packageName: string;\n\t\treadonly version: string;\n\t}>;\n}): Promise<Metadata> {\n\tconst { packageName, version } = await params;\n\n\treturn {\n\t\ttitle: {\n\t\t\ttemplate: '%s | discord.js',\n\t\t\tdefault: `${packageName} (${version})`,\n\t\t},\n\t};\n}\n\nexport default async function Layout({\n\tparams,\n\tchildren,\n}: PropsWithChildren<{\n\treadonly params: Promise<{ readonly packageName: string; readonly version: string }>;\n}>) {\n\treturn (\n\t\t<>\n\t\t\t{children}\n\t\t\t<Suspense>\n\t\t\t\t<CmdK params={params} />\n\t\t\t</Suspense>\n\t\t</>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/app/docs/packages/[packageName]/[version]/[[...item]]/opengraph-image.tsx.bak",
    "content": "/* eslint-disable react/no-unknown-property */\n\nimport { ImageResponse } from 'next/og';\nimport { resolveKind } from '@/util/resolveNodeKind';\n\nexport const size = {\n\twidth: 1_200,\n\theight: 630,\n};\n\nexport const contentType = 'image/png';\n\nasync function loadGoogleFont(font: string, text: string) {\n\tconst url = `https://fonts.googleapis.com/css2?family=${font}&text=${encodeURIComponent(text)}`;\n\tconst css = await (await fetch(url)).text();\n\t// eslint-disable-next-line prefer-named-capture-group\n\tconst resource = /src: url\\((.+)\\) format\\('(opentype|truetype)'\\)/.exec(css);\n\n\tif (resource) {\n\t\tconst response = await fetch(resource[1]!);\n\t\tif (response.status === 200) {\n\t\t\treturn response.arrayBuffer();\n\t\t}\n\t}\n\n\tthrow new Error('failed to load font data');\n}\n\nexport default async function Image({\n\tparams,\n}: {\n\treadonly params: Promise<{ readonly item: string; readonly packageName: string; readonly version: string }>;\n}) {\n\tconst { item, packageName, version } = await params;\n\n\tconst normalizeItem = item.split(encodeURIComponent(':')).join('.').toLowerCase();\n\n\tconst isMain = version === 'main';\n\tconst fileContent = await fetch(\n\t\t`${process.env.CF_R2_DOCS_BUCKET_URL}/${packageName}/${version}.${normalizeItem}.api.json`,\n\t\t{ next: { revalidate: isMain ? 0 : 604_800 } },\n\t);\n\tconst node = await fileContent.json();\n\n\treturn new ImageResponse(\n\t\t(\n\t\t\t<div tw=\"flex bg-[#121212] h-full w-full p-14\">\n\t\t\t\t<div tw=\"flex flex-col mx-auto h-full text-white\">\n\t\t\t\t\t<div tw=\"flex text-4xl text-gray-400\">{packageName}</div>\n\t\t\t\t\t<div tw=\"flex flex-col justify-between h-full w-full pt-14\">\n\t\t\t\t\t\t<div tw=\"flex items-center max-w-full\">\n\t\t\t\t\t\t\t<span tw=\"mr-6\">{resolveKind(node.kind, 94)}</span>\n\t\t\t\t\t\t\t<h2\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\ttextOverflow: 'ellipsis',\n\t\t\t\t\t\t\t\t\twhiteSpace: 'nowrap',\n\t\t\t\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\ttw=\"text-[5.5rem] font-bold w-full\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{node.displayName}\n\t\t\t\t\t\t\t</h2>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div tw=\"flex flex-row w-full justify-between\">\n\t\t\t\t\t\t\t<div tw=\"flex flex-row\">\n\t\t\t\t\t\t\t\t{node.members?.properties?.length ? (\n\t\t\t\t\t\t\t\t\t<div tw=\"flex mr-12\">\n\t\t\t\t\t\t\t\t\t\t<span tw=\"mr-4\">{resolveKind('Property', 42)}</span>\n\t\t\t\t\t\t\t\t\t\t<div tw=\"flex flex-col text-4xl\">\n\t\t\t\t\t\t\t\t\t\t\t<span tw=\"mb-4\">{node.members.properties.length}</span>\n\t\t\t\t\t\t\t\t\t\t\t<span>Properties</span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t{node.members?.events?.length ? (\n\t\t\t\t\t\t\t\t\t<div tw=\"flex mr-12\">\n\t\t\t\t\t\t\t\t\t\t<span tw=\"mr-4\">{resolveKind('Method', 42)}</span>\n\t\t\t\t\t\t\t\t\t\t<div tw=\"flex flex-col text-4xl\">\n\t\t\t\t\t\t\t\t\t\t\t<span tw=\"mb-4\">{node.members.events.length}</span>\n\t\t\t\t\t\t\t\t\t\t\t<span>Events</span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t{node.members?.methods?.length ? (\n\t\t\t\t\t\t\t\t\t<div tw=\"flex mr-12\">\n\t\t\t\t\t\t\t\t\t\t<span tw=\"mr-4\">{resolveKind('Method', 42)}</span>\n\t\t\t\t\t\t\t\t\t\t<div tw=\"flex flex-col text-4xl\">\n\t\t\t\t\t\t\t\t\t\t\t<span tw=\"mb-4\">{node.members.methods.length}</span>\n\t\t\t\t\t\t\t\t\t\t\t<span>Methods</span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t{node.members?.length ? (\n\t\t\t\t\t\t\t\t\t<div tw=\"flex\">\n\t\t\t\t\t\t\t\t\t\t<span tw=\"mr-4\">{resolveKind('EnumMember', 42)}</span>\n\t\t\t\t\t\t\t\t\t\t<div tw=\"flex flex-col text-4xl\">\n\t\t\t\t\t\t\t\t\t\t\t<span tw=\"mb-4\">{node.members.length}</span>\n\t\t\t\t\t\t\t\t\t\t\t<span>Members</span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div tw=\"flex h-full items-end\">\n\t\t\t\t\t\t\t\t<span tw=\"bg-[#5865f2] text-4xl font-black relative rounded-lg py-4 px-8\">discord.js</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t),\n\t\t{\n\t\t\t...size,\n\t\t\tfonts: [\n\t\t\t\t{\n\t\t\t\t\tname: 'Geist',\n\t\t\t\t\tdata: await loadGoogleFont('Geist:wght@700', node.displayName),\n\t\t\t\t\tweight: 700,\n\t\t\t\t\tstyle: 'normal',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: 'Geist',\n\t\t\t\t\tdata: await loadGoogleFont('Geist:wght@900', node.displayName),\n\t\t\t\t\tweight: 900,\n\t\t\t\t\tstyle: 'normal',\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/app/docs/packages/[packageName]/[version]/[[...item]]/page.tsx",
    "content": "import type { Metadata } from 'next';\nimport { notFound } from 'next/navigation';\nimport { SafeMdxRenderer } from 'safe-mdx';\nimport { mdxParse } from 'safe-mdx/parse';\nimport { DocItem } from '@/components/DocItem';\nimport { SyntaxHighlighter } from '@/components/SyntaxHighlighter';\n// import { PACKAGES_WITH_ENTRY_POINTS } from '@/util/constants';\nimport { fetchNode } from '@/util/fetchNode';\nimport { parseDocsPathParams } from '@/util/parseDocsPathParams';\n\nexport async function generateMetadata({\n\tparams,\n}: {\n\treadonly params: Promise<{\n\t\treadonly item?: string[] | undefined;\n\t\treadonly packageName: string;\n\t\treadonly version: string;\n\t}>;\n}): Promise<Metadata> {\n\tconst { item, packageName, version } = await params;\n\n\tconst { foundItem } = parseDocsPathParams(item);\n\n\tif (!foundItem) {\n\t\treturn {\n\t\t\ttitle: `${packageName} (${version})`,\n\t\t};\n\t}\n\n\tconst decodedItemName = decodeURIComponent(foundItem);\n\tconst titlePart = decodedItemName.split(':')?.[0] ?? decodedItemName;\n\n\treturn {\n\t\ttitle: `${titlePart} (${packageName} - ${version})`,\n\t};\n}\n\nexport default async function Page({\n\tparams,\n}: {\n\treadonly params: Promise<{\n\t\treadonly item?: string[] | undefined;\n\t\treadonly packageName: string;\n\t\treadonly version: string;\n\t}>;\n}) {\n\tconst { item, packageName, version } = await params;\n\n\tconst { entryPoints: parsedEntrypoints, foundItem } = parseDocsPathParams(item);\n\n\tif (!foundItem) {\n\t\t// const hasEntryPoint = PACKAGES_WITH_ENTRY_POINTS.includes(packageName);\n\n\t\t// if (hasEntryPoint) {\n\t\t// \treturn <>Placeholder</>;\n\t\t// }\n\n\t\tlet fileContent: string;\n\n\t\ttry {\n\t\t\tfileContent = await fetch(`${process.env.CF_R2_README_BUCKET_URL}/${packageName}/home-README.md`).then(\n\t\t\t\tasync (res) => res.text(),\n\t\t\t);\n\t\t} catch {\n\t\t\tnotFound();\n\t\t}\n\n\t\tconst mdast = mdxParse(fileContent);\n\n\t\treturn (\n\t\t\t<div className=\"prose prose-neutral dark:prose-invert prose-a:[&>img]:inline-block prose-a:[&>img]:m-0 prose-a:[&>img[height='44']]:h-11 prose-p:my-2 prose-pre:py-3 prose-pre:rounded-sm prose-pre:px-0 prose-pre:border prose-pre:border-[#d4d4d4] dark:prose-pre:border-[#404040] prose-code:font-normal prose-a:text-[#5865F2] prose-a:no-underline prose-a:hover:text-[#3d48c3] dark:prose-a:hover:text-[#7782fa] mx-auto max-w-screen-xl px-6 py-6 break-words [&_code_span:last-of-type:empty]:hidden [&_div[align='center']_p_a+a]:ml-2\">\n\t\t\t\t<SafeMdxRenderer\n\t\t\t\t\tmarkdown={fileContent}\n\t\t\t\t\tmdast={mdast}\n\t\t\t\t\trenderNode={(node) => {\n\t\t\t\t\t\tif (node.type === 'code') {\n\t\t\t\t\t\t\tconst language = node.lang ?? 'text';\n\n\t\t\t\t\t\t\treturn <SyntaxHighlighter code={node.value} lang={language} />;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst entryPointString = parsedEntrypoints.join('.');\n\n\tconst node = await fetchNode({\n\t\tentryPoint: entryPointString,\n\t\titem: decodeURIComponent(foundItem),\n\t\tpackageName,\n\t\tversion,\n\t});\n\n\tif (!node) {\n\t\tnotFound();\n\t}\n\n\treturn (\n\t\t<main className=\"mx-auto flex w-full max-w-screen-xl flex-col gap-8 px-6 py-4\">\n\t\t\t<DocItem node={node} packageName={packageName} version={version} />\n\t\t</main>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/app/docs/packages/layout.tsx",
    "content": "// import Link from 'next/link';\nimport type { PropsWithChildren } from 'react';\nimport { Footer } from '@/components/Footer';\nimport { Navigation } from '@/components/Navigation';\nimport { Scrollbars } from '@/components/OverlayScrollbars';\nimport { SidebarHeader } from '@/components/Sidebar';\nimport { Sidebar, SidebarContent, SidebarInset, SidebarTrigger } from '@/components/ui/Sidebar';\nimport { ENV } from '@/util/env';\n\nexport default async function Layout({ children }: PropsWithChildren) {\n\treturn (\n\t\t<>\n\t\t\t<Sidebar closeButton={false} intent=\"inset\">\n\t\t\t\t<SidebarHeader />\n\t\t\t\t<SidebarContent className=\"bg-[#f3f3f4] p-0 pb-4 pl-4 dark:bg-[#121214]\">\n\t\t\t\t\t<Scrollbars>\n\t\t\t\t\t\t<Navigation />\n\t\t\t\t\t</Scrollbars>\n\t\t\t\t</SidebarContent>\n\t\t\t</Sidebar>\n\t\t\t<SidebarInset>\n\t\t\t\t{ENV.IS_LOCAL_DEV ? (\n\t\t\t\t\t<div className=\"sticky top-0 z-10 flex place-content-center place-items-center border border-red-400/35 bg-red-500/65 p-2 px-4 text-center text-base text-white shadow-md backdrop-blur\">\n\t\t\t\t\t\tLocal test environment\n\t\t\t\t\t</div>\n\t\t\t\t) : null}\n\t\t\t\t{ENV.IS_PREVIEW ? (\n\t\t\t\t\t<div className=\"sticky top-0 z-10 flex place-content-center place-items-center border border-red-400/35 bg-red-500/65 p-2 px-4 text-center text-base text-white shadow-md backdrop-blur\">\n\t\t\t\t\t\tPreview environment\n\t\t\t\t\t</div>\n\t\t\t\t) : null}\n\t\t\t\t<div className=\"flex-1 bg-[#fbfbfb] pb-12 dark:bg-[#1a1a1e]\">\n\t\t\t\t\t<div className=\"relative px-6 pt-6 md:hidden\">\n\t\t\t\t\t\t<div className=\"fixed top-5 left-6 z-20 md:hidden\">\n\t\t\t\t\t\t\t<SidebarTrigger aria-label=\"Navigation\" size=\"icon\" variant=\"filled\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t{/* <div className=\"flex place-content-end\">\n\t\t\t\t\t\t\t<Link className=\"text-xl font-bold\" href={`/docs/packages/${packageName}/${version}`}>\n\t\t\t\t\t\t\t\t{packageName}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</div> */}\n\t\t\t\t\t</div>\n\t\t\t\t\t{children}\n\t\t\t\t\t<Footer />\n\t\t\t\t</div>\n\t\t\t</SidebarInset>\n\t\t</>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/app/layout.tsx",
    "content": "import { Analytics } from '@vercel/analytics/react';\nimport { GeistMono } from 'geist/font/mono';\nimport { GeistSans } from 'geist/font/sans';\nimport type { Metadata, Viewport } from 'next';\nimport type { PropsWithChildren } from 'react';\nimport { DESCRIPTION } from '@/util/constants';\nimport { ENV } from '@/util/env';\nimport { Providers } from './providers';\n\nimport '@/styles/base.css';\nimport 'overlayscrollbars/overlayscrollbars.css';\n\nexport const viewport: Viewport = {\n\tthemeColor: [\n\t\t{ media: '(prefers-color-scheme: light)', color: '#fbfbfb' },\n\t\t{ media: '(prefers-color-scheme: dark)', color: '#1a1a1e' },\n\t],\n\tcolorScheme: 'light dark',\n};\n\nexport const metadata: Metadata = {\n\tmetadataBase: new URL(ENV.IS_LOCAL_DEV ? `http://localhost:${ENV.PORT}` : 'https://discord.js.org'),\n\ttitle: {\n\t\ttemplate: '%s | discord.js',\n\t\tdefault: 'discord.js',\n\t},\n\tdescription: DESCRIPTION,\n\ticons: {\n\t\tother: [\n\t\t\t{\n\t\t\t\turl: '/favicon-96x96.png',\n\t\t\t\tsizes: '96x96',\n\t\t\t\ttype: 'image/png',\n\t\t\t},\n\t\t],\n\t\tapple: ['/apple-touch-icon.png'],\n\t},\n\n\tmanifest: '/site.webmanifest',\n\n\topenGraph: {\n\t\tsiteName: 'discord.js',\n\t\ttype: 'website',\n\t\ttitle: 'discord.js',\n\t\tdescription: DESCRIPTION,\n\t},\n\n\ttwitter: {\n\t\tcard: 'summary_large_image',\n\t\tcreator: '@iCrawlToGo',\n\t},\n};\n\nexport default async function RootLayout({ children }: PropsWithChildren) {\n\treturn (\n\t\t<html className={`${GeistSans.variable} ${GeistMono.variable} antialiased`} lang=\"en\" suppressHydrationWarning>\n\t\t\t<body className=\"text-base-md text-base-neutral-900 dark:text-base-neutral-40 overscroll-y-none bg-[#fbfbfb] dark:bg-[#1a1a1e]\">\n\t\t\t\t<Providers>{children}</Providers>\n\t\t\t\t<Analytics />\n\t\t\t</body>\n\t\t</html>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/app/not-found.tsx",
    "content": "import Link from 'next/link';\n\nexport default function NotFound() {\n\treturn (\n\t\t<div className=\"mx-auto flex min-h-[calc(100vh_-_100px)] max-w-lg flex-col place-content-center place-items-center gap-8 px-8 py-16 lg:px-6 lg:py-0\">\n\t\t\t<h1 className=\"text-[9rem] leading-none font-black md:text-[12rem]\">404</h1>\n\t\t\t<h2 className=\"text-[2rem] md:text-[3rem]\">Not found.</h2>\n\t\t\t<Link\n\t\t\t\tclassName=\"bg-base-blurple-400 inline-flex rounded-md border border-transparent px-6 py-2 font-medium text-white\"\n\t\t\t\thref=\"/docs\"\n\t\t\t>\n\t\t\t\tTake me back\n\t\t\t</Link>\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/app/opengraph-image.tsx",
    "content": "/* eslint-disable react/no-unknown-property */\n\nimport { ImageResponse } from 'next/og';\n\nexport const size = {\n\twidth: 1_200,\n\theight: 630,\n};\n\nexport const contentType = 'image/png';\n\nasync function loadGoogleFont(font: string, text: string) {\n\tconst url = `https://fonts.googleapis.com/css2?family=${font}&text=${encodeURIComponent(text)}`;\n\tconst css = await (await fetch(url)).text();\n\t// eslint-disable-next-line prefer-named-capture-group\n\tconst resource = /src: url\\((.+)\\) format\\('(opentype|truetype)'\\)/.exec(css);\n\n\tif (resource) {\n\t\tconst response = await fetch(resource[1]!);\n\t\tif (response.status === 200) {\n\t\t\treturn response.arrayBuffer();\n\t\t}\n\t}\n\n\tthrow new Error('failed to load font data');\n}\n\nexport default async function Image() {\n\treturn new ImageResponse(\n\t\t<div tw=\"flex bg-[#121214] h-full w-full\">\n\t\t\t<div tw=\"mx-auto flex items-center h-full\">\n\t\t\t\t<div tw=\"flex\">\n\t\t\t\t\t<div tw=\"flex\">\n\t\t\t\t\t\t<div tw=\"flex flex-col font-black text-8xl text-white leading-tight\">\n\t\t\t\t\t\t\t<div tw=\"flex flex-row\">\n\t\t\t\t\t\t\t\tThe <span tw=\"bg-[#5865f2] rounded-md px-3 py-2 ml-4 bottom-2\">most popular</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<span>way to build Discord</span>\n\t\t\t\t\t\t\t<span>bots.</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>,\n\t\t{\n\t\t\t...size,\n\t\t\tfonts: [\n\t\t\t\t{\n\t\t\t\t\tname: 'Geist',\n\t\t\t\t\tdata: await loadGoogleFont('Geist:wght@900', 'The most popular way to build Discord bots.'),\n\t\t\t\t\tweight: 900,\n\t\t\t\t\tstyle: 'normal',\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/app/page.tsx",
    "content": "import { ExternalLink } from 'lucide-react';\nimport Image from 'next/image';\nimport Link from 'next/link';\nimport vercelLogo from '@/assets/powered-by-vercel.svg';\nimport workersLogo from '@/assets/powered-by-workers.png';\nimport { InstallButton } from '@/components/InstallButton';\nimport { buttonStyles } from '@/styles/ui/button';\nimport { DESCRIPTION } from '@/util/constants';\n\nexport default async function Page() {\n\treturn (\n\t\t<div className=\"mx-auto flex min-h-screen w-full max-w-screen-lg flex-col place-content-center place-items-center gap-24 px-8 pt-12 pb-16\">\n\t\t\t<div className=\"flex flex-col gap-10 text-center\">\n\t\t\t\t<h1 className=\"text-base-heading-xl font-black sm:text-7xl sm:leading-tight\">\n\t\t\t\t\tThe{' '}\n\t\t\t\t\t<span className=\"bg-base-blurple-400 text-base-neutral-0 relative rounded-sm px-3 py-2\">most popular</span>{' '}\n\t\t\t\t\tway to build Discord bots.\n\t\t\t\t</h1>\n\t\t\t\t<p className=\"text-base-neutral-600 dark:text-base-neutral-300 md:my-6\">{DESCRIPTION}</p>\n\n\t\t\t\t<div className=\"flex flex-wrap place-content-center gap-4 sm:flex-wrap md:flex-row\">\n\t\t\t\t\t<Link className={buttonStyles({ variant: 'filled' })} href=\"/docs\">\n\t\t\t\t\t\tDocs\n\t\t\t\t\t</Link>\n\t\t\t\t\t<a\n\t\t\t\t\t\tclassName={buttonStyles({ variant: 'discreet' })}\n\t\t\t\t\t\thref=\"https://discordjs.guide\"\n\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t>\n\t\t\t\t\t\tGuide <ExternalLink aria-hidden data-slot=\"icon\" size={18} />\n\t\t\t\t\t</a>\n\t\t\t\t\t<a\n\t\t\t\t\t\tclassName={buttonStyles({ variant: 'discreet' })}\n\t\t\t\t\t\thref=\"https://github.com/discordjs/discord.js\"\n\t\t\t\t\t\trel=\"external noopener noreferrer\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t>\n\t\t\t\t\t\tGitHub <ExternalLink aria-hidden data-slot=\"icon\" size={18} />\n\t\t\t\t\t</a>\n\t\t\t\t</div>\n\n\t\t\t\t<InstallButton className=\"place-self-center\" />\n\t\t\t</div>\n\n\t\t\t<div className=\"flex flex-col gap-4 md:flex-row\">\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"\n\t\t\t\t\trel=\"external noopener noreferrer\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\ttitle=\"Vercel\"\n\t\t\t\t>\n\t\t\t\t\t<Image\n\t\t\t\t\t\talt=\"Vercel\"\n\t\t\t\t\t\tblurDataURL=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAABLCAQAAAA1k5H2AAAAi0lEQVR42u3SMQEAAAgDoC251a3gL2SgmfBYBRAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARCAgwWEOSWBnYbKggAAAABJRU5ErkJggg==\"\n\t\t\t\t\t\theight={44}\n\t\t\t\t\t\tplaceholder=\"blur\"\n\t\t\t\t\t\tpriority\n\t\t\t\t\t\tsrc={vercelLogo}\n\t\t\t\t\t\twidth={212}\n\t\t\t\t\t/>\n\t\t\t\t</a>\n\t\t\t\t<a\n\t\t\t\t\thref=\"https://www.cloudflare.com\"\n\t\t\t\t\trel=\"external noopener noreferrer\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\ttitle=\"Cloudflare Workers\"\n\t\t\t\t>\n\t\t\t\t\t<Image\n\t\t\t\t\t\talt=\"Cloudflare\"\n\t\t\t\t\t\tblurDataURL=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAABLCAQAAAA1k5H2AAAAi0lEQVR42u3SMQEAAAgDoC251a3gL2SgmfBYBRAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARCAgwWEOSWBnYbKggAAAABJRU5ErkJggg==\"\n\t\t\t\t\t\theight={44}\n\t\t\t\t\t\tplaceholder=\"blur\"\n\t\t\t\t\t\tpriority\n\t\t\t\t\t\tsrc={workersLogo}\n\t\t\t\t\t/>\n\t\t\t\t</a>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/app/providers.tsx",
    "content": "'use client';\n\nimport { isServer, QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { Provider as JotaiProvider } from 'jotai';\nimport { useRouter } from 'next/navigation';\nimport { ThemeProvider } from 'next-themes';\nimport { NuqsAdapter } from 'nuqs/adapters/next/app';\nimport type { PropsWithChildren } from 'react';\nimport { RouterProvider } from 'react-aria-components';\nimport { SidebarProvider } from '@/components/ui/Sidebar';\nimport { useSystemThemeFallback } from '@/hooks/useSystemThemeFallback';\nimport { useUnregisterServiceWorker } from '@/hooks/useUnregisterServiceWorker';\n\nfunction makeQueryClient() {\n\treturn new QueryClient({\n\t\tdefaultOptions: {\n\t\t\tqueries: {\n\t\t\t\tstaleTime: 60 * 1_000,\n\t\t\t},\n\t\t},\n\t});\n}\n\nlet browserQueryClient: QueryClient | undefined;\n\nfunction getQueryClient() {\n\tif (isServer) {\n\t\t// Server: always make a new query client\n\t\treturn makeQueryClient();\n\t} else {\n\t\tbrowserQueryClient ??= makeQueryClient();\n\t\treturn browserQueryClient;\n\t}\n}\n\nexport function Providers({ children }: PropsWithChildren) {\n\tconst queryClient = getQueryClient();\n\tconst router = useRouter();\n\tuseUnregisterServiceWorker();\n\tuseSystemThemeFallback();\n\n\treturn (\n\t\t<NuqsAdapter>\n\t\t\t<ThemeProvider attribute=\"class\">\n\t\t\t\t<RouterProvider navigate={router.push}>\n\t\t\t\t\t<JotaiProvider>\n\t\t\t\t\t\t<QueryClientProvider client={queryClient}>\n\t\t\t\t\t\t\t<SidebarProvider defaultOpen>{children}</SidebarProvider>\n\t\t\t\t\t\t</QueryClientProvider>\n\t\t\t\t\t</JotaiProvider>\n\t\t\t\t</RouterProvider>\n\t\t\t</ThemeProvider>\n\t\t</NuqsAdapter>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/Badges.tsx",
    "content": "import { AlertTriangle } from 'lucide-react';\nimport type { PropsWithChildren } from 'react';\n\nexport function Badge({ children, className = '' }: PropsWithChildren<{ readonly className?: string }>) {\n\treturn (\n\t\t<span\n\t\t\tclassName={`inline-flex place-items-center gap-1 rounded-full px-2 py-1 font-sans text-sm leading-none font-normal whitespace-nowrap ${className}`}\n\t\t>\n\t\t\t{children}\n\t\t</span>\n\t);\n}\n\nexport async function Badges({ node }: { readonly node: any }) {\n\tconst isDeprecated = Boolean(node.summary?.deprecatedBlock?.length);\n\tconst isUnstable = Boolean(node.summary?.unstableBlock?.length);\n\tconst isProtected = node.isProtected;\n\tconst isStatic = node.isStatic;\n\tconst isAbstract = node.isAbstract;\n\tconst isReadonly = node.isReadonly;\n\tconst isOptional = node.isOptional;\n\tconst isExternal = node.isExternal;\n\n\tconst isAny =\n\t\tisDeprecated || isUnstable || isProtected || isStatic || isAbstract || isReadonly || isOptional || isExternal;\n\n\treturn isAny ? (\n\t\t<div className=\"mb-1 flex flex-wrap gap-3\">\n\t\t\t{isDeprecated ? (\n\t\t\t\t<Badge className=\"bg-red-500/20 text-red-500\">\n\t\t\t\t\t<AlertTriangle aria-hidden size={14} /> deprecated\n\t\t\t\t</Badge>\n\t\t\t) : null}\n\t\t\t{isUnstable ? (\n\t\t\t\t<Badge className=\"bg-red-500/20 text-red-500\">\n\t\t\t\t\t<AlertTriangle aria-hidden size={14} /> unstable\n\t\t\t\t</Badge>\n\t\t\t) : null}\n\t\t\t{isProtected ? <Badge className=\"bg-purple-500/20 text-purple-500\">protected</Badge> : null}\n\t\t\t{isStatic ? <Badge className=\"bg-purple-500/20 text-purple-500\">static</Badge> : null}\n\t\t\t{isAbstract ? <Badge className=\"bg-cyan-500/20 text-cyan-500\">abstract</Badge> : null}\n\t\t\t{isReadonly ? <Badge className=\"bg-purple-500/20 text-purple-500\">readonly</Badge> : null}\n\t\t\t{isOptional ? <Badge className=\"bg-cyan-500/20 text-cyan-500\">optional</Badge> : null}\n\t\t\t{isExternal ? <Badge className=\"bg-purple-500/20 text-purple-500\">external</Badge> : null}\n\t\t</div>\n\t) : null;\n}\n"
  },
  {
    "path": "apps/website/src/components/CmdK.tsx",
    "content": "'use client';\n\nimport { Command } from 'cmdk';\nimport { useAtom, useSetAtom } from 'jotai';\nimport { ArrowRight } from 'lucide-react';\nimport MeiliSearch from 'meilisearch';\nimport dynamic from 'next/dynamic';\nimport { usePathname, useRouter } from 'next/navigation';\nimport { useEffect, useState } from 'react';\nimport { useDebounceValue, useMediaQuery } from 'usehooks-ts';\nimport { Scrollbars } from '@/components/OverlayScrollbars';\nimport { isCmdKOpenAtom } from '@/stores/cmdk';\nimport { isDrawerOpenAtom } from '@/stores/drawer';\nimport { cx } from '@/styles/cva';\nimport { resolveKind } from '@/util/resolveNodeKind';\n\nconst client = new MeiliSearch({\n\thost: 'https://search.discordjs.dev',\n\tapiKey: 'f3482b8e976a8b1092394aafbfb91f391242f40b0a6f45a008a5a72b354fb07e',\n});\n\nexport function CmdK({ dependencies }: { readonly dependencies: string[] }) {\n\tconst pathname = usePathname();\n\tconst router = useRouter();\n\tconst [open, setOpen] = useAtom(isCmdKOpenAtom);\n\tconst setDrawerOpen = useSetAtom(isDrawerOpenAtom);\n\tconst [search, setSearch] = useDebounceValue('', 250);\n\tconst [searchResults, setSearchResults] = useState<any[]>([]);\n\tconst isMobile = useMediaQuery('(max-width: 600px)');\n\n\tconst packageName = pathname?.split('/').slice(3, 4)[0];\n\tconst branchName = pathname?.split('/').slice(4, 5)[0];\n\n\tconst searchResultItems =\n\t\tsearchResults?.map((item, idx) => (\n\t\t\t<Command.Item\n\t\t\t\tclassName=\"flex cursor-pointer place-items-center gap-2 rounded-md p-2 data-[selected='true']:bg-neutral-200 dark:data-[selected='true']:bg-neutral-800\"\n\t\t\t\tkey={`${item.id}-${idx}`}\n\t\t\t\tonSelect={() => {\n\t\t\t\t\trouter.push(item.path);\n\t\t\t\t\tsetOpen(false);\n\t\t\t\t}}\n\t\t\t\tvalue={item.id}\n\t\t\t>\n\t\t\t\t{resolveKind(item.kind)}\n\t\t\t\t<div className=\"flex grow flex-col\">\n\t\t\t\t\t<span className=\"font-semibold wrap-anywhere\">{item.name}</span>\n\t\t\t\t\t<span className={cx('truncate text-sm', isMobile ? 'max-w-[30ch]' : 'max-w-[40ch]')}>{item.summary}</span>\n\t\t\t\t\t<span className={cx('truncate text-xs', isMobile ? 'max-w-[30ch]' : 'max-w-[40ch]')}>{item.path}</span>\n\t\t\t\t</div>\n\t\t\t\t<ArrowRight aria-hidden className=\"shrink-0\" />\n\t\t\t</Command.Item>\n\t\t)) ?? [];\n\n\t// Toggle the menu when ⌘K is pressed\n\tuseEffect(() => {\n\t\tconst down = (event: KeyboardEvent) => {\n\t\t\tif (event.key === 'k' && (event.metaKey || event.ctrlKey)) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tsetOpen((open) => !open);\n\t\t\t}\n\t\t};\n\n\t\tdocument.addEventListener('keydown', down);\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('keydown', down);\n\t\t};\n\t}, [setOpen]);\n\n\tuseEffect(() => {\n\t\tif (open) {\n\t\t\tsetDrawerOpen(false);\n\t\t\tsetSearch('');\n\t\t}\n\n\t\treturn () => {\n\t\t\tdocument.body.style.pointerEvents = 'auto';\n\t\t};\n\t}, [open, setDrawerOpen, setSearch]);\n\n\tuseEffect(() => {\n\t\t// const searchDoc = async (searchString: string, version: string) => {\n\t\t// \tconsole.log(dependencies);\n\t\t// \tconst res = await client\n\t\t// \t\t.index(`${packageName?.replaceAll('.', '-')}-${version}`)\n\t\t// \t\t.search(searchString, { limit: 25 });\n\t\t// \tsetSearchResults(res.hits);\n\t\t// };\n\n\t\tconst searchDoc = async (searchString: string, version: string) => {\n\t\t\tconst result = await client.multiSearch({\n\t\t\t\tqueries: [`${packageName?.replaceAll('.', '-')}-${version}`, ...dependencies].map((dep) => ({\n\t\t\t\t\tindexUid: dep,\n\t\t\t\t\t// eslint-disable-next-line id-length\n\t\t\t\t\tq: searchString,\n\t\t\t\t\tlimit: 25,\n\t\t\t\t\tattributesToSearchOn: ['name'],\n\t\t\t\t\tsort: ['type:asc'],\n\t\t\t\t})),\n\t\t\t});\n\t\t\tsetSearchResults(result.results.flatMap((res) => res.hits));\n\t\t};\n\n\t\tif (search && packageName) {\n\t\t\tvoid searchDoc(search, branchName?.replaceAll('.', '-') ?? 'main');\n\t\t} else {\n\t\t\tsetSearchResults([]);\n\t\t}\n\t}, [branchName, dependencies, packageName, search]);\n\n\treturn (\n\t\t<Command.Dialog\n\t\t\tclassName=\"w-full rounded-md border border-neutral-300 bg-neutral-100 p-2 shadow-md dark:border-neutral-700 dark:bg-neutral-900\"\n\t\t\tlabel=\"Command Menu\"\n\t\t\tonOpenChange={setOpen}\n\t\t\topen={open}\n\t\t\tshouldFilter={false}\n\t\t>\n\t\t\t<Command.Input\n\t\t\t\tclassName=\"mb-4 w-full border-b border-neutral-300 bg-transparent px-2 pt-2 pb-4 outline-none dark:border-neutral-700\"\n\t\t\t\tonValueChange={setSearch}\n\t\t\t\tplaceholder=\"Quick search...\"\n\t\t\t/>\n\t\t\t<Scrollbars\n\t\t\t\tclassName=\"max-h-96 pr-3\"\n\t\t\t\tdefer\n\t\t\t\toptions={{\n\t\t\t\t\toverflow: { x: 'hidden' },\n\t\t\t\t\tscrollbars: {\n\t\t\t\t\t\tautoHide: 'scroll',\n\t\t\t\t\t\tautoHideDelay: 500,\n\t\t\t\t\t\tautoHideSuspend: true,\n\t\t\t\t\t\tclickScroll: true,\n\t\t\t\t\t},\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<Command.List>\n\t\t\t\t\t{search && searchResultItems.length ? (\n\t\t\t\t\t\tsearchResultItems\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<div className=\"flex h-12 place-content-center place-items-center text-sm\" role=\"presentation\">\n\t\t\t\t\t\t\tNo results found.\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</Command.List>\n\t\t\t</Scrollbars>\n\t\t</Command.Dialog>\n\t);\n}\n\nexport const CmdKNoSRR = dynamic(async () => CmdK, { ssr: false });\n"
  },
  {
    "path": "apps/website/src/components/ConstructorNode.tsx",
    "content": "import { VscSymbolMethod } from '@react-icons/all-files/vsc/VscSymbolMethod';\nimport { Code2, LinkIcon } from 'lucide-react';\nimport Link from 'next/link';\nimport { ENV } from '@/util/env';\nimport { Badges } from './Badges';\nimport { ExampleNode } from './ExampleNode';\nimport { ParameterNode } from './ParameterNode';\nimport { SeeNode } from './SeeNode';\nimport { SummaryNode } from './SummaryNode';\n\nexport async function ConstructorNode({ node, version }: { readonly node: any; readonly version: string }) {\n\treturn (\n\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t<h2 className=\"flex place-items-center gap-2 p-2 text-xl font-bold\">\n\t\t\t\t<VscSymbolMethod aria-hidden className=\"flex-shrink-0\" size={24} />\n\t\t\t\tConstructors\n\t\t\t</h2>\n\n\t\t\t<div className=\"flex place-content-between place-items-center gap-1\">\n\t\t\t\t<h3\n\t\t\t\t\tclassName={`${ENV.IS_LOCAL_DEV || ENV.IS_PREVIEW ? 'scroll-mt-16' : 'scroll-mt-8'} group px-2 font-mono font-semibold break-all`}\n\t\t\t\t\tid=\"constructor\"\n\t\t\t\t>\n\t\t\t\t\t<Badges node={node} />\n\t\t\t\t\t<span>\n\t\t\t\t\t\t{/* constructor({parsedContent.constructor.parametersString}) */}\n\t\t\t\t\t\t<Link className=\"float-left -ml-6 hidden pr-2 pb-2 group-hover:block\" href=\"#constructor\">\n\t\t\t\t\t\t\t<LinkIcon aria-hidden size={16} />\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t\tconstructor({node.parameters?.length ? <ParameterNode node={node.parameters} version={version} /> : null})\n\t\t\t\t\t</span>\n\t\t\t\t</h3>\n\n\t\t\t\t<a\n\t\t\t\t\taria-label=\"Open source file in new tab\"\n\t\t\t\t\tclassName=\"min-w-min\"\n\t\t\t\t\thref={node.sourceLine ? `${node.sourceURL}#L${node.sourceLine}` : node.sourceURL}\n\t\t\t\t\trel=\"external noreferrer noopener\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t>\n\t\t\t\t\t<Code2\n\t\t\t\t\t\taria-hidden\n\t\t\t\t\t\tclassName=\"text-neutral-500 hover:text-neutral-600 dark:text-neutral-400 dark:hover:text-neutral-300\"\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t/>\n\t\t\t\t</a>\n\t\t\t</div>\n\n\t\t\t{node.summary?.summarySection.length ? (\n\t\t\t\t<SummaryNode node={node.summary.summarySection} padding version={version} />\n\t\t\t) : null}\n\n\t\t\t{node.summary?.exampleBlocks.length ? <ExampleNode node={node.summary.exampleBlocks} version={version} /> : null}\n\n\t\t\t{node.summary?.seeBlocks.length ? <SeeNode node={node.summary.seeBlocks} padding version={version} /> : null}\n\n\t\t\t<div aria-hidden className=\"p-4\">\n\t\t\t\t<div className=\"h-[2px] bg-neutral-300 dark:bg-neutral-700\" role=\"separator\" />\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/DeprecatedNode.tsx",
    "content": "import { DocNode } from './DocNode';\nimport { Alert } from './ui/Alert';\n\nexport async function DeprecatedNode({\n\tdeprecatedBlock,\n\tversion,\n}: {\n\treadonly deprecatedBlock: any;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<Alert title=\"Deprecated\" type=\"danger\">\n\t\t\t<p className=\"break-words\">\n\t\t\t\t<DocNode node={deprecatedBlock} version={version} />\n\t\t\t</p>\n\t\t</Alert>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/DocItem.tsx",
    "content": "import { VscSymbolParameter } from '@react-icons/all-files/vsc/VscSymbolParameter';\nimport { ConstructorNode } from './ConstructorNode';\nimport { DeprecatedNode } from './DeprecatedNode';\nimport { EnumMemberNode } from './EnumMemberNode';\nimport { EventNode } from './EventNode';\nimport { InformationNode } from './InformationNode';\nimport { MethodNode } from './MethodNode';\nimport { Outline } from './Outline';\nimport { Scrollbars } from './OverlayScrollbars';\nimport { ParameterNode } from './ParameterNode';\nimport { PropertyNode } from './PropertyNode';\nimport { ReturnNode } from './ReturnNode';\nimport { SeeNode } from './SeeNode';\nimport { SummaryNode } from './SummaryNode';\nimport { SyntaxHighlighter } from './SyntaxHighlighter';\nimport { TypeParameterNode } from './TypeParameterNode';\nimport { UnionMember } from './UnionMember';\nimport { UnstableNode } from './UnstableNode';\nimport { Tab, TabList, TabPanel, Tabs } from './ui/Tabs';\n\nasync function OverloadNode({\n\tnode,\n\tpackageName,\n\tversion,\n}: {\n\treadonly node: any;\n\treadonly packageName: string;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<Tabs className=\"flex flex-col gap-4\">\n\t\t\t<TabList className=\"flex flex-wrap gap-2\">\n\t\t\t\t{node.overloads.map((overload: any) => (\n\t\t\t\t\t<Tab\n\t\t\t\t\t\tclassName=\"cursor-pointer rounded-full bg-neutral-800/10 px-2 py-1 font-sans text-sm leading-none font-normal whitespace-nowrap text-neutral-800 hover:bg-neutral-800/20 data-[selected]:bg-neutral-500 data-[selected]:text-neutral-100 dark:bg-neutral-200/10 dark:text-neutral-200 dark:hover:bg-neutral-200/20 dark:data-[selected]:bg-neutral-500/70\"\n\t\t\t\t\t\tid={`overload-${overload.displayName}-${overload.overloadIndex}`}\n\t\t\t\t\t\tkey={`overload-tab-${overload.displayName}-${overload.overloadIndex}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t<span>Overload {overload.overloadIndex}</span>\n\t\t\t\t\t</Tab>\n\t\t\t\t))}\n\t\t\t</TabList>\n\t\t\t{node.overloads.map((overload: any) => (\n\t\t\t\t<TabPanel\n\t\t\t\t\tclassName=\"flex flex-col gap-4\"\n\t\t\t\t\tid={`overload-${overload.displayName}-${overload.overloadIndex}`}\n\t\t\t\t\tkey={`overload-tab-panel-${overload.displayName}-${overload.overloadIndex}`}\n\t\t\t\t>\n\t\t\t\t\t<DocItem node={overload} packageName={packageName} version={version} />\n\t\t\t\t</TabPanel>\n\t\t\t))}\n\t\t</Tabs>\n\t);\n}\n\nexport async function DocItem({\n\tnode,\n\tpackageName,\n\tversion,\n}: {\n\treadonly node: any;\n\treadonly packageName: string;\n\treadonly version: string;\n}) {\n\tif (node.overloads?.length) {\n\t\treturn <OverloadNode node={node} packageName={packageName} version={version} />;\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t<InformationNode node={node} version={version} />\n\n\t\t\t<Scrollbars className=\"border-base-neutral-200 dark:border-base-neutral-600 bg-base-neutral-100 dark:bg-base-neutral-900 rounded-sm border\">\n\t\t\t\t<SyntaxHighlighter\n\t\t\t\t\tclassName=\"min-w-max bg-[#f3f3f4] py-4 text-sm dark:bg-[#121214]\"\n\t\t\t\t\tcode={node.sourceExcerpt}\n\t\t\t\t\tlang=\"typescript\"\n\t\t\t\t/>\n\t\t\t</Scrollbars>\n\n\t\t\t{node.summary?.deprecatedBlock.length ? (\n\t\t\t\t<DeprecatedNode deprecatedBlock={node.summary.deprecatedBlock} version={version} />\n\t\t\t) : null}\n\n\t\t\t{node.summary?.unstableBlock?.length ? (\n\t\t\t\t<UnstableNode unstableBlock={node.summary.unstableBlock} version={version} />\n\t\t\t) : null}\n\n\t\t\t{node.summary?.summarySection ? <SummaryNode node={node.summary.summarySection} version={version} /> : null}\n\n\t\t\t{node.summary?.returnsBlock.length ? <ReturnNode node={node.summary.returnsBlock} version={version} /> : null}\n\n\t\t\t{node.summary?.seeBlocks.length ? <SeeNode node={node.summary.seeBlocks} version={version} /> : null}\n\n\t\t\t<Outline node={node} />\n\n\t\t\t{node.construct ? <ConstructorNode node={node.construct} version={version} /> : null}\n\n\t\t\t{node.typeParameters?.length ? (\n\t\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t\t<h2 className=\"flex place-items-center gap-2 p-2 text-xl font-bold\">\n\t\t\t\t\t\t<VscSymbolParameter aria-hidden className=\"flex-shrink-0\" size={24} />\n\t\t\t\t\t\tType Parameters\n\t\t\t\t\t</h2>\n\t\t\t\t\t<TypeParameterNode description node={node.typeParameters} version={version} />\n\t\t\t\t</div>\n\t\t\t) : null}\n\n\t\t\t{node.parameters?.length ? (\n\t\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t\t<h2 className=\"flex place-items-center gap-2 p-2 text-xl font-bold\">\n\t\t\t\t\t\t<VscSymbolParameter aria-hidden className=\"flex-shrink-0\" size={24} />\n\t\t\t\t\t\tParameters\n\t\t\t\t\t</h2>\n\t\t\t\t\t<ParameterNode description node={node.parameters} version={version} />\n\t\t\t\t</div>\n\t\t\t) : null}\n\n\t\t\t{node.members?.properties?.length ? (\n\t\t\t\t<PropertyNode node={node.members.properties} packageName={packageName} version={version} />\n\t\t\t) : null}\n\n\t\t\t{node.members?.methods?.length ? (\n\t\t\t\t<div>\n\t\t\t\t\t<MethodNode node={node.members.methods} packageName={packageName} version={version} />\n\t\t\t\t</div>\n\t\t\t) : null}\n\n\t\t\t{node.members?.events?.length ? (\n\t\t\t\t<div>\n\t\t\t\t\t<EventNode node={node.members.events} packageName={packageName} version={version} />\n\t\t\t\t</div>\n\t\t\t) : null}\n\n\t\t\t{node.members?.length ? <EnumMemberNode node={node.members} packageName={packageName} version={version} /> : null}\n\n\t\t\t{node.unionMembers?.length ? <UnionMember node={node.unionMembers} version={version} /> : null}\n\t\t</>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/DocKind.tsx",
    "content": "export function resolveNodeKind(kind: string) {\n\tswitch (kind) {\n\t\tcase 'Class':\n\t\t\treturn {\n\t\t\t\ttext: 'text-green-500',\n\t\t\t\tbackground: 'bg-green-500/20',\n\t\t\t};\n\t\tcase 'Interface':\n\t\t\treturn {\n\t\t\t\ttext: 'text-amber-500',\n\t\t\t\tbackground: 'bg-amber-500/20',\n\t\t\t};\n\t\tcase 'Function':\n\t\t\treturn {\n\t\t\t\ttext: 'text-blue-500',\n\t\t\t\tbackground: 'bg-blue-500/20',\n\t\t\t};\n\t\tcase 'Enum':\n\t\t\treturn {\n\t\t\t\ttext: 'text-rose-500',\n\t\t\t\tbackground: 'bg-rose-500/20',\n\t\t\t};\n\t\tcase 'TypeAlias':\n\t\t\treturn {\n\t\t\t\ttext: 'text-pink-500',\n\t\t\t\tbackground: 'bg-pink-500/20',\n\t\t\t};\n\t\tcase 'Variable':\n\t\t\treturn {\n\t\t\t\ttext: 'text-purple-500',\n\t\t\t\tbackground: 'bg-purple-500/20',\n\t\t\t};\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\ttext: 'text-gray-500',\n\t\t\t\tbackground: 'bg-gray-500/20',\n\t\t\t};\n\t}\n}\n\nexport async function DocKind({ background = false, node }: { readonly background?: boolean; readonly node: any }) {\n\tconst kind = resolveNodeKind(node.kind);\n\treturn <span className={background ? `${kind.background} ${kind.text}` : kind.text}>{node.kind.toLowerCase()}</span>;\n}\n"
  },
  {
    "path": "apps/website/src/components/DocNode.tsx",
    "content": "import Link from 'next/link';\nimport { BuiltinDocumentationLinks } from '@/util/builtinDocumentationLinks';\nimport { Scrollbars } from './OverlayScrollbars';\nimport { SyntaxHighlighter } from './SyntaxHighlighter';\n\nexport async function DocNode({ node, version }: { readonly node?: any; readonly version: string }) {\n\tconst createNode = (node: any, idx: number) => {\n\t\tswitch (node.kind) {\n\t\t\tcase 'PlainText':\n\t\t\t\treturn <span key={`${node.text}-${idx}`}>{node.text}</span>;\n\t\t\tcase 'LinkTag': {\n\t\t\t\tif (node.resolvedPackage) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\tclassName=\"text-base-blurple-400 hover:text-base-blurple-500 dark:hover:text-base-blurple-300 font-mono\"\n\t\t\t\t\t\t\thref={`/docs/packages/${node.resolvedPackage.packageName}/${node.resolvedPackage.version ?? version}/${node.uri}`}\n\t\t\t\t\t\t\tkey={`${node.uri}-${idx}`}\n\t\t\t\t\t\t\t// @ts-expect-error - unstable_dynamicOnHover is not part of the public types\n\t\t\t\t\t\t\tunstable_dynamicOnHover\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{node.text}\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (node.uri) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\tclassName=\"text-base-blurple-400 hover:text-base-blurple-500 dark:hover:text-base-blurple-300\"\n\t\t\t\t\t\t\thref={node.uri}\n\t\t\t\t\t\t\tkey={`${node.text}-${idx}`}\n\t\t\t\t\t\t\trel=\"external noreferrer noopener\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{`${node.text}${node.members ?? ''}`}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (node.text in BuiltinDocumentationLinks) {\n\t\t\t\t\tconst href = BuiltinDocumentationLinks[node.text as keyof typeof BuiltinDocumentationLinks];\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\tclassName=\"text-base-blurple-400 hover:text-base-blurple-500 dark:hover:text-base-blurple-300\"\n\t\t\t\t\t\t\thref={href}\n\t\t\t\t\t\t\tkey={`${node.text}-${idx}`}\n\t\t\t\t\t\t\trel=\"external noreferrer noopener\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{node.text}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn <span key={`${node.text}-${idx}`}>{node.text}</span>;\n\t\t\t}\n\n\t\t\tcase 'CodeSpan':\n\t\t\t\treturn (\n\t\t\t\t\t<code className=\"font-mono text-sm\" key={`${node.text}-${idx}`}>\n\t\t\t\t\t\t{node.text}\n\t\t\t\t\t</code>\n\t\t\t\t);\n\n\t\t\tcase 'FencedCode': {\n\t\t\t\tconst { language, text } = node;\n\n\t\t\t\treturn (\n\t\t\t\t\t<Scrollbars\n\t\t\t\t\t\tclassName=\"border-base-neutral-200 dark:border-base-neutral-600 bg-base-neutral-100 dark:bg-base-neutral-900 my-4 rounded-sm border\"\n\t\t\t\t\t\tdefer\n\t\t\t\t\t\tkey={`${language}-${text}-${idx}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t<SyntaxHighlighter\n\t\t\t\t\t\t\tclassName=\"min-w-max bg-[#f3f3f4] py-4 text-sm dark:bg-[#121214]\"\n\t\t\t\t\t\t\tcode={text}\n\t\t\t\t\t\t\tlang={language}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Scrollbars>\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tcase 'SoftBreak':\n\t\t\t\treturn null;\n\t\t\tdefault:\n\t\t\t\treturn null;\n\t\t}\n\t};\n\n\treturn node?.map(createNode) ?? null;\n}\n"
  },
  {
    "path": "apps/website/src/components/EntrypointSelect.tsx",
    "content": "'use client';\n\nimport { Loader2Icon } from 'lucide-react';\nimport { useParams, useRouter } from 'next/navigation';\nimport { Select, SelectList, SelectOption, SelectTrigger } from '@/components/ui/Select';\nimport type { EntryPoint } from '@/util/fetchEntryPoints';\nimport { parseDocsPathParams } from '@/util/parseDocsPathParams';\n\nexport function EntryPointSelect({\n\tentryPoints,\n\tisLoading,\n}: {\n\treadonly entryPoints: EntryPoint[];\n\treadonly isLoading: boolean;\n}) {\n\tconst router = useRouter();\n\tconst params = useParams<{\n\t\titem?: string[] | undefined;\n\t\tpackageName: string;\n\t\tversion: string;\n\t}>();\n\n\tconst { entryPoints: parsedEntrypoints } = parseDocsPathParams(params.item);\n\n\treturn (\n\t\t<Select\n\t\t\taria-label={isLoading ? 'Loading entrypoints...' : 'Select an entrypoint'}\n\t\t\tdefaultSelectedKey={parsedEntrypoints.join('/')}\n\t\t\tkey={parsedEntrypoints.join('/')}\n\t\t\tplaceholder={isLoading ? 'Loading entrypoints...' : 'Select an entrypoint'}\n\t\t>\n\t\t\t<SelectTrigger\n\t\t\t\tclassName=\"bg-[#f3f3f4] dark:bg-[#121214]\"\n\t\t\t\tsuffix={\n\t\t\t\t\tisLoading ? (\n\t\t\t\t\t\t<Loader2Icon\n\t\t\t\t\t\t\taria-hidden\n\t\t\t\t\t\t\tclassName=\"size-6 shrink-0 animate-spin duration-200 forced-colors:text-[ButtonText] forced-colors:group-disabled:text-[GrayText]\"\n\t\t\t\t\t\t\tsize={24}\n\t\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<SelectList classNames={{ popover: 'bg-[#f3f3f4] dark:bg-[#28282d]' }} items={entryPoints}>\n\t\t\t\t{(item) => (\n\t\t\t\t\t<SelectOption\n\t\t\t\t\t\tclassName=\"dark:pressed:bg-[#313135] bg-[#f3f3f4] dark:bg-[#28282d] dark:hover:bg-[#313135]\"\n\t\t\t\t\t\thref={`/docs/packages/${params.packageName}/${params.version}/${item.entryPoint}`}\n\t\t\t\t\t\tid={item.entryPoint}\n\t\t\t\t\t\tkey={item.entryPoint}\n\t\t\t\t\t\tonHoverStart={() =>\n\t\t\t\t\t\t\trouter.prefetch(`/docs/packages/${params.packageName}/${params.version}/${item.entryPoint}`)\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttextValue={item.entryPoint}\n\t\t\t\t\t>\n\t\t\t\t\t\t{item.entryPoint}\n\t\t\t\t\t</SelectOption>\n\t\t\t\t)}\n\t\t\t</SelectList>\n\t\t</Select>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/EnumMemberNode.tsx",
    "content": "import { VscSymbolEnumMember } from '@react-icons/all-files/vsc/VscSymbolEnumMember';\nimport { Code2, LinkIcon } from 'lucide-react';\nimport Link from 'next/link';\nimport { Fragment } from 'react';\nimport { ENV } from '@/util/env';\nimport { Badges } from './Badges';\nimport { DeprecatedNode } from './DeprecatedNode';\nimport { ExampleNode } from './ExampleNode';\nimport { ExcerptNode } from './ExcerptNode';\nimport { InheritedFromNode } from './InheritedFromNode';\nimport { ParameterNode } from './ParameterNode';\nimport { ReturnNode } from './ReturnNode';\nimport { SeeNode } from './SeeNode';\nimport { SummaryNode } from './SummaryNode';\nimport { UnstableNode } from './UnstableNode';\n\nexport async function EnumMemberNode({\n\tnode,\n\tpackageName,\n\tversion,\n}: {\n\treadonly node: any;\n\treadonly packageName: string;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t<h2 className=\"flex place-items-center gap-2 p-2 text-xl font-bold\">\n\t\t\t\t<VscSymbolEnumMember aria-hidden className=\"flex-shrink-0\" size={24} />\n\t\t\t\tMembers\n\t\t\t</h2>\n\n\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t{node.map((enumMember: any, idx: number) => (\n\t\t\t\t\t<Fragment key={`${enumMember.displayName}-${idx}`}>\n\t\t\t\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t\t\t\t<div className=\"flex place-content-between place-items-center gap-1\">\n\t\t\t\t\t\t\t\t<h3\n\t\t\t\t\t\t\t\t\tclassName={`${ENV.IS_LOCAL_DEV || ENV.IS_PREVIEW ? 'scroll-mt-16' : 'scroll-mt-8'} group px-2 font-mono font-semibold break-all`}\n\t\t\t\t\t\t\t\t\tid={enumMember.displayName}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Badges node={enumMember} />\n\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"float-left -ml-6 hidden pr-2 pb-2 group-hover:block\"\n\t\t\t\t\t\t\t\t\t\t\thref={`#${enumMember.displayName}`}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<LinkIcon aria-hidden size={16} />\n\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t{enumMember.displayName}\n\t\t\t\t\t\t\t\t\t\t{enumMember.parameters?.length ? (\n\t\t\t\t\t\t\t\t\t\t\t<ParameterNode node={enumMember.parameters} version={version} />\n\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t{enumMember.initializerExcerpt ? (\n\t\t\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t\t\t{' = '}\n\t\t\t\t\t\t\t\t\t\t\t\t<ExcerptNode node={enumMember.initializerExcerpt} version={version} />\n\t\t\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</h3>\n\n\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\taria-label=\"Open source file in new tab\"\n\t\t\t\t\t\t\t\t\tclassName=\"min-w-min\"\n\t\t\t\t\t\t\t\t\thref={\n\t\t\t\t\t\t\t\t\t\tenumMember.sourceLine ? `${enumMember.sourceURL}#L${enumMember.sourceLine}` : enumMember.sourceURL\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\trel=\"external noreferrer noopener\"\n\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Code2\n\t\t\t\t\t\t\t\t\t\taria-hidden\n\t\t\t\t\t\t\t\t\t\tclassName=\"text-neutral-500 hover:text-neutral-600 dark:text-neutral-400 dark:hover:text-neutral-300\"\n\t\t\t\t\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t{enumMember.summary?.deprecatedBlock.length ? (\n\t\t\t\t\t\t\t\t<DeprecatedNode deprecatedBlock={enumMember.summary.deprecatedBlock} version={version} />\n\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t{enumMember.summary?.unstableBlock?.length ? (\n\t\t\t\t\t\t\t\t<UnstableNode unstableBlock={enumMember.summary.unstableBlock} version={version} />\n\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t{enumMember.summary?.summarySection.length ? (\n\t\t\t\t\t\t\t\t<SummaryNode node={enumMember.summary.summarySection} padding version={version} />\n\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t{enumMember.summary?.exampleBlocks.length ? (\n\t\t\t\t\t\t\t\t<ExampleNode node={enumMember.summary.exampleBlocks} version={version} />\n\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t{enumMember.summary?.returnsBlock.length ? (\n\t\t\t\t\t\t\t\t<ReturnNode node={enumMember.summary.returnsBlock} padding version={version} />\n\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t{enumMember.inheritedFrom ? (\n\t\t\t\t\t\t\t\t<InheritedFromNode node={enumMember.inheritedFrom} packageName={packageName} version={version} />\n\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t{enumMember.summary?.seeBlocks.length ? (\n\t\t\t\t\t\t\t\t<SeeNode node={enumMember.summary.seeBlocks} padding version={version} />\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div aria-hidden className=\"p-4\">\n\t\t\t\t\t\t\t<div className=\"h-[2px] bg-neutral-300 dark:bg-neutral-700\" role=\"separator\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</Fragment>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/EventNode.tsx",
    "content": "import { VscSymbolEvent } from '@react-icons/all-files/vsc/VscSymbolEvent';\nimport { ChevronDown, ChevronUp, Code2, LinkIcon } from 'lucide-react';\nimport Link from 'next/link';\nimport { ENV } from '@/util/env';\nimport { Badges } from './Badges';\nimport { DeprecatedNode } from './DeprecatedNode';\nimport { ExampleNode } from './ExampleNode';\nimport { InheritedFromNode } from './InheritedFromNode';\nimport { ParameterNode } from './ParameterNode';\nimport { ReturnNode } from './ReturnNode';\nimport { SeeNode } from './SeeNode';\nimport { SummaryNode } from './SummaryNode';\nimport { TypeParameterNode } from './TypeParameterNode';\nimport { UnstableNode } from './UnstableNode';\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from './ui/Collapsible';\nimport { Tab, TabList, TabPanel, Tabs } from './ui/Tabs';\n\nasync function EventBodyNode({\n\tevent,\n\tpackageName,\n\tversion,\n\toverload = false,\n}: {\n\treadonly event: any;\n\treadonly overload?: boolean;\n\treadonly packageName: string;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<>\n\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t<div className=\"flex place-content-between place-items-center gap-1\">\n\t\t\t\t\t<h3\n\t\t\t\t\t\tclassName={`${overload ? (ENV.IS_LOCAL_DEV || ENV.IS_PREVIEW ? 'scroll-mt-24' : 'scroll-mt-16') : ENV.IS_LOCAL_DEV || ENV.IS_PREVIEW ? 'scroll-mt-16' : 'scroll-mt-8'} group px-2 font-mono font-semibold break-all`}\n\t\t\t\t\t\tid={event.displayName}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Badges node={event} /> {event.displayName}\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t<Link className=\"float-left -ml-6 hidden pr-2 pb-2 group-hover:block\" href={`#${event.displayName}`}>\n\t\t\t\t\t\t\t\t<LinkIcon aria-hidden size={16} />\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t{event.typeParameters?.length ? (\n\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t{'<'}\n\t\t\t\t\t\t\t\t\t<TypeParameterNode node={event.typeParameters} version={version} />\n\t\t\t\t\t\t\t\t\t{'>'}\n\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t({event.parameters?.length ? <ParameterNode node={event.parameters} version={version} /> : null})\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</h3>\n\n\t\t\t\t\t<a\n\t\t\t\t\t\taria-label=\"Open source file in new tab\"\n\t\t\t\t\t\tclassName=\"min-w-min\"\n\t\t\t\t\t\thref={event.sourceLine ? `${event.sourceURL}#L${event.sourceLine}` : event.sourceURL}\n\t\t\t\t\t\trel=\"external noreferrer noopener\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Code2\n\t\t\t\t\t\t\taria-hidden\n\t\t\t\t\t\t\tclassName=\"text-neutral-500 hover:text-neutral-600 dark:text-neutral-400 dark:hover:text-neutral-300\"\n\t\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</a>\n\t\t\t\t</div>\n\n\t\t\t\t{event.summary?.deprecatedBlock.length ? (\n\t\t\t\t\t<DeprecatedNode deprecatedBlock={event.summary.deprecatedBlock} version={version} />\n\t\t\t\t) : null}\n\n\t\t\t\t{event.summary?.unstableBlock?.length ? (\n\t\t\t\t\t<UnstableNode unstableBlock={event.summary.unstableBlock} version={version} />\n\t\t\t\t) : null}\n\n\t\t\t\t{event.summary?.summarySection.length ? (\n\t\t\t\t\t<SummaryNode node={event.summary.summarySection} padding version={version} />\n\t\t\t\t) : null}\n\n\t\t\t\t{event.summary?.exampleBlocks.length ? (\n\t\t\t\t\t<ExampleNode node={event.summary.exampleBlocks} version={version} />\n\t\t\t\t) : null}\n\n\t\t\t\t{event.summary?.returnsBlock.length ? (\n\t\t\t\t\t<ReturnNode node={event.summary.returnsBlock} padding version={version} />\n\t\t\t\t) : null}\n\n\t\t\t\t{event.inheritedFrom ? (\n\t\t\t\t\t<InheritedFromNode node={event.inheritedFrom} packageName={packageName} version={version} />\n\t\t\t\t) : null}\n\n\t\t\t\t{event.summary?.seeBlocks.length ? <SeeNode node={event.summary.seeBlocks} padding version={version} /> : null}\n\t\t\t</div>\n\t\t\t<div aria-hidden className=\"p-4\">\n\t\t\t\t<div className=\"h-[2px] bg-neutral-300 dark:bg-neutral-700\" role=\"separator\" />\n\t\t\t</div>\n\t\t</>\n\t);\n}\n\nasync function OverloadNode({\n\tevent,\n\tpackageName,\n\tversion,\n}: {\n\treadonly event: any;\n\treadonly packageName: string;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<Tabs className=\"flex flex-col gap-4\">\n\t\t\t<TabList className=\"flex flex-wrap gap-2\">\n\t\t\t\t{event.overloads.map((overload: any) => (\n\t\t\t\t\t<Tab\n\t\t\t\t\t\tclassName=\"cursor-pointer rounded-full bg-neutral-800/10 px-2 py-1 font-sans text-sm leading-none font-normal whitespace-nowrap text-neutral-800 hover:bg-neutral-800/20 data-[selected]:bg-neutral-500 data-[selected]:text-neutral-100 dark:bg-neutral-200/10 dark:text-neutral-200 dark:hover:bg-neutral-200/20 dark:data-[selected]:bg-neutral-500/70\"\n\t\t\t\t\t\tid={`overload-${overload.displayName}-${overload.overloadIndex}`}\n\t\t\t\t\t\tkey={`overload-tab-${overload.displayName}-${overload.overloadIndex}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t<span>Overload {overload.overloadIndex}</span>\n\t\t\t\t\t</Tab>\n\t\t\t\t))}\n\t\t\t</TabList>\n\t\t\t{event.overloads.map((overload: any) => (\n\t\t\t\t<TabPanel\n\t\t\t\t\tclassName=\"flex flex-col gap-4\"\n\t\t\t\t\tid={`overload-${overload.displayName}-${overload.overloadIndex}`}\n\t\t\t\t\tkey={`overload-tab-panel-${overload.displayName}-${overload.overloadIndex}`}\n\t\t\t\t>\n\t\t\t\t\t<EventBodyNode event={overload} overload packageName={packageName} version={version} />\n\t\t\t\t</TabPanel>\n\t\t\t))}\n\t\t</Tabs>\n\t);\n}\n\nexport async function EventNode({\n\tnode,\n\tpackageName,\n\tversion,\n}: {\n\treadonly node: any;\n\treadonly packageName: string;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<Collapsible className=\"flex flex-col gap-4\" defaultOpen>\n\t\t\t<CollapsibleTrigger className=\"group flex place-content-between place-items-center rounded-md p-2 hover:bg-[#e7e7e9] dark:hover:bg-[#242428]\">\n\t\t\t\t<h2 className=\"flex place-items-center gap-2 text-xl font-bold\">\n\t\t\t\t\t<VscSymbolEvent aria-hidden className=\"flex-shrink-0\" size={24} /> Events\n\t\t\t\t</h2>\n\t\t\t\t<ChevronDown aria-hidden className='group-data-[state=\"open\"]:hidden' size={24} />\n\t\t\t\t<ChevronUp aria-hidden className='group-data-[state=\"closed\"]:hidden' size={24} />\n\t\t\t</CollapsibleTrigger>\n\n\t\t\t<CollapsibleContent>\n\t\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t\t{node.map((event: any) =>\n\t\t\t\t\t\tevent.overloads?.length ? (\n\t\t\t\t\t\t\t<OverloadNode\n\t\t\t\t\t\t\t\tevent={event}\n\t\t\t\t\t\t\t\tkey={`${event.displayName}-${event.overloadIndex}`}\n\t\t\t\t\t\t\t\tpackageName={packageName}\n\t\t\t\t\t\t\t\tversion={version}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<EventBodyNode\n\t\t\t\t\t\t\t\tevent={event}\n\t\t\t\t\t\t\t\tkey={`${event.displayName}-${event.overloadIndex}`}\n\t\t\t\t\t\t\t\tpackageName={packageName}\n\t\t\t\t\t\t\t\tversion={version}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t),\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</CollapsibleContent>\n\t\t</Collapsible>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/ExampleNode.tsx",
    "content": "import { DocNode } from './DocNode';\n\nexport async function ExampleNode({ node, version }: { readonly node: any; readonly version: string }) {\n\treturn (\n\t\t<div className=\"pl-4 break-words\">\n\t\t\t<span className=\"font-semibold\">Examples:</span>\n\t\t\t<DocNode node={node} version={version} />\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/ExcerptNode.tsx",
    "content": "import Link from 'next/link';\nimport { Fragment } from 'react';\nimport { BuiltinDocumentationLinks } from '@/util/builtinDocumentationLinks';\n\nexport async function ExcerptNode({ node, version }: { readonly node?: any; readonly version: string }) {\n\tconst createExcerpt = (excerpts: any, idx: number) => {\n\t\tconst excerpt = Array.isArray(excerpts) ? excerpts : (excerpts.excerpts ?? [excerpts]);\n\n\t\treturn (\n\t\t\t<span\n\t\t\t\tclassName={\n\t\t\t\t\texcerpts?.type === 'Extends' || excerpts?.type === 'Implements'\n\t\t\t\t\t\t? 'after:content-[\",_\"] last-of-type:after:content-none'\n\t\t\t\t\t\t: ''\n\t\t\t\t}\n\t\t\t\tkey={`${excerpt.text}-${idx}`}\n\t\t\t>\n\t\t\t\t{excerpt.map((excerpt: any, idx: number) => {\n\t\t\t\t\tif (excerpt.resolvedItem) {\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tclassName=\"text-base-blurple-400 hover:text-base-blurple-500 dark:hover:text-base-blurple-300\"\n\t\t\t\t\t\t\t\thref={`/docs/packages/${excerpt.resolvedItem.packageName}/${excerpt.resolvedItem.version ?? version}/${excerpt.resolvedItem.uri}`}\n\t\t\t\t\t\t\t\tkey={`${excerpt.resolvedItem.displayName}-${idx}`}\n\t\t\t\t\t\t\t\t// @ts-expect-error - unstable_dynamicOnHover is not part of the public types\n\t\t\t\t\t\t\t\tunstable_dynamicOnHover\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{excerpt.text}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (excerpt.href) {\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\tclassName=\"text-base-blurple-400 hover:text-base-blurple-500 dark:hover:text-base-blurple-300\"\n\t\t\t\t\t\t\t\thref={excerpt.href}\n\t\t\t\t\t\t\t\tkey={`${excerpt.text}-${idx}`}\n\t\t\t\t\t\t\t\trel=\"external noreferrer noopener\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{excerpt.text}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (excerpt.text in BuiltinDocumentationLinks) {\n\t\t\t\t\t\tconst href = BuiltinDocumentationLinks[excerpt.text as keyof typeof BuiltinDocumentationLinks];\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\tclassName=\"text-base-blurple-400 hover:text-base-blurple-500 dark:hover:text-base-blurple-300\"\n\t\t\t\t\t\t\t\thref={href}\n\t\t\t\t\t\t\t\tkey={`${excerpt.text}-${idx}`}\n\t\t\t\t\t\t\t\trel=\"external noreferrer noopener\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{excerpt.text}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn <Fragment key={`${excerpt.text}-${idx}`}>{excerpt.text}</Fragment>;\n\t\t\t\t})}\n\t\t\t</span>\n\t\t);\n\t};\n\n\treturn node?.map(createExcerpt) ?? null;\n}\n"
  },
  {
    "path": "apps/website/src/components/Footer.tsx",
    "content": "import Image from 'next/image';\nimport vercelLogo from '@/assets/powered-by-vercel.svg';\nimport workersLogo from '@/assets/powered-by-workers.png';\n\nexport function Footer() {\n\treturn (\n\t\t<footer className=\"md:pr-12 md:pl-12\">\n\t\t\t<div className=\"flex flex-col flex-wrap place-content-center gap-6 pt-12 sm:flex-row md:gap-12\">\n\t\t\t\t<div className=\"flex flex-wrap place-content-center place-items-center gap-4\">\n\t\t\t\t\t<a\n\t\t\t\t\t\tclassName=\"rounded\"\n\t\t\t\t\t\thref=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"\n\t\t\t\t\t\trel=\"external noopener noreferrer\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\ttitle=\"Vercel\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Image\n\t\t\t\t\t\t\talt=\"Vercel\"\n\t\t\t\t\t\t\tblurDataURL=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAABLCAQAAAA1k5H2AAAAi0lEQVR42u3SMQEAAAgDoC251a3gL2SgmfBYBRAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARCAgwWEOSWBnYbKggAAAABJRU5ErkJggg==\"\n\t\t\t\t\t\t\theight={44}\n\t\t\t\t\t\t\tplaceholder=\"blur\"\n\t\t\t\t\t\t\tsrc={vercelLogo}\n\t\t\t\t\t\t\twidth={212}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</a>\n\t\t\t\t\t<a\n\t\t\t\t\t\tclassName=\"rounded\"\n\t\t\t\t\t\thref=\"https://www.cloudflare.com\"\n\t\t\t\t\t\trel=\"external noopener noreferrer\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\ttitle=\"Cloudflare Workers\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Image\n\t\t\t\t\t\t\talt=\"Cloudflare\"\n\t\t\t\t\t\t\tblurDataURL=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAABLCAQAAAA1k5H2AAAAi0lEQVR42u3SMQEAAAgDoC251a3gL2SgmfBYBRAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARCAgwWEOSWBnYbKggAAAABJRU5ErkJggg==\"\n\t\t\t\t\t\t\theight={44}\n\t\t\t\t\t\t\tplaceholder=\"blur\"\n\t\t\t\t\t\t\tpriority\n\t\t\t\t\t\t\tsrc={workersLogo}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</a>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"flex flex-col gap-6 place-self-center sm:flex-row md:gap-12\">\n\t\t\t\t\t<div className=\"flex max-w-max flex-col gap-2\">\n\t\t\t\t\t\t<div className=\"text-lg font-semibold\">Community</div>\n\t\t\t\t\t\t<div className=\"flex flex-col gap-1\">\n\t\t\t\t\t\t\t<a className=\"rounded\" href=\"https://discord.gg/djs\" rel=\"external noopener noreferrer\" target=\"_blank\">\n\t\t\t\t\t\t\t\tDiscord\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\tclassName=\"rounded\"\n\t\t\t\t\t\t\t\thref=\"https://github.com/discordjs/discord.js/discussions\"\n\t\t\t\t\t\t\t\trel=\"external noopener noreferrer\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tGitHub discussions\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"flex max-w-max flex-col gap-2\">\n\t\t\t\t\t\t<div className=\"text-lg font-semibold\">Project</div>\n\t\t\t\t\t\t<div className=\"flex flex-col gap-1\">\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\tclassName=\"rounded\"\n\t\t\t\t\t\t\t\thref=\"https://github.com/discordjs/discord.js\"\n\t\t\t\t\t\t\t\trel=\"external noopener noreferrer\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tdiscord.js\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t<a className=\"rounded\" href=\"https://discord.js.org/docs\" rel=\"noopener noreferrer\" target=\"_blank\">\n\t\t\t\t\t\t\t\tdiscord.js documentation\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\tclassName=\"rounded\"\n\t\t\t\t\t\t\t\thref=\"https://discord-api-types.dev\"\n\t\t\t\t\t\t\t\trel=\"external noopener noreferrer\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tdiscord-api-types\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</footer>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/InformationNode.tsx",
    "content": "import { FileCode2 } from 'lucide-react';\nimport { Badges } from './Badges';\nimport { DocKind } from './DocKind';\nimport { InheritanceNode } from './InheritanceNode';\n\nexport async function InformationNode({ node, version }: { readonly node: any; readonly version: string }) {\n\treturn (\n\t\t<div className=\"flex place-content-between place-items-center gap-1\">\n\t\t\t<div className=\"flex flex-col gap-1\">\n\t\t\t\t<h1 className=\"text-xl\">\n\t\t\t\t\t<DocKind node={node} /> <span className=\"font-bold break-all\">{node.displayName}</span>\n\t\t\t\t</h1>\n\t\t\t\t{node.implements ? <InheritanceNode node={node.implements} text=\"implements\" version={version} /> : null}\n\t\t\t\t{node.extends ? <InheritanceNode node={node.extends} text=\"extends\" version={version} /> : null}\n\t\t\t\t<Badges node={node} />\n\t\t\t</div>\n\n\t\t\t<a\n\t\t\t\taria-label=\"Open source file in new tab\"\n\t\t\t\tclassName=\"min-w-min\"\n\t\t\t\thref={node.sourceLine ? `${node.sourceURL}#L${node.sourceLine}` : node.sourceURL}\n\t\t\t\trel=\"external noreferrer noopener\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t>\n\t\t\t\t<FileCode2\n\t\t\t\t\taria-hidden\n\t\t\t\t\tclassName=\"text-neutral-500 hover:text-neutral-600 dark:text-neutral-400 dark:hover:text-neutral-300\"\n\t\t\t\t\tsize={20}\n\t\t\t\t/>\n\t\t\t</a>\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/InheritanceNode.tsx",
    "content": "import { ExcerptNode } from './ExcerptNode';\n\nexport async function InheritanceNode({\n\ttext,\n\tnode,\n\tversion,\n}: {\n\treadonly node: any;\n\treadonly text: string;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<div>\n\t\t\t<h2 className=\"inline-block min-w-min text-sm text-neutral-500 italic dark:text-neutral-400\">{text}</h2>{' '}\n\t\t\t<span className=\"font-mono text-sm break-all\">\n\t\t\t\t<ExcerptNode node={node} version={version} />\n\t\t\t</span>\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/InheritedFromNode.tsx",
    "content": "import Link from 'next/link';\n\nexport async function InheritedFromNode({\n\tnode,\n\tpackageName,\n\tversion,\n}: {\n\treadonly node: any;\n\treadonly packageName: string;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<p className=\"pl-4 break-words\">\n\t\t\t<span className=\"font-semibold\">Inherited from:</span>{' '}\n\t\t\t<Link\n\t\t\t\tclassName=\"text-base-blurple-400 hover:text-base-blurple-500 dark:hover:text-base-blurple-300 font-mono\"\n\t\t\t\thref={`/docs/packages/${packageName}/${version}/${node}`}\n\t\t\t\t// @ts-expect-error - unstable_dynamicOnHover is not part of the public types\n\t\t\t\tunstable_dynamicOnHover\n\t\t\t>\n\t\t\t\t{node.slice(0, node.indexOf(':'))}\n\t\t\t</Link>\n\t\t</p>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/InstallButton.tsx",
    "content": "'use client';\n\nimport { Copy, CopyCheck } from 'lucide-react';\nimport { useEffect, useState } from 'react';\nimport { useCopyToClipboard } from 'usehooks-ts';\n\nexport function InstallButton({ className = '' }: { readonly className?: string }) {\n\tconst [interacted, setInteracted] = useState(false);\n\tconst [copiedText, copyToClipboard] = useCopyToClipboard();\n\n\tuseEffect(() => {\n\t\tconst timer = setTimeout(() => setInteracted(false), 2_000);\n\t\treturn () => clearTimeout(timer);\n\t}, [interacted]);\n\n\treturn (\n\t\t<button\n\t\t\tclassName={`cursor-copy rounded-sm border border-neutral-300 bg-white px-4 py-2 font-mono hover:bg-neutral-200 dark:border-neutral-700 dark:bg-transparent dark:hover:bg-neutral-800 ${className}`}\n\t\t\tonClick={async () => {\n\t\t\t\tsetInteracted(true);\n\t\t\t\tawait copyToClipboard('npm install discord.js');\n\t\t\t}}\n\t\t\ttype=\"button\"\n\t\t>\n\t\t\t<span className=\"text-base-blurple-400 font-semibold\">{'>'}</span> npm install discord.js{' '}\n\t\t\t{copiedText && interacted ? (\n\t\t\t\t<CopyCheck aria-hidden className=\"ml-1 inline-block text-green-500\" size={20} />\n\t\t\t) : (\n\t\t\t\t<Copy aria-hidden className=\"ml-1 inline-block\" size={20} />\n\t\t\t)}\n\t\t</button>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/MethodNode.tsx",
    "content": "import { VscSymbolMethod } from '@react-icons/all-files/vsc/VscSymbolMethod';\nimport { ChevronDown, ChevronUp, Code2, LinkIcon } from 'lucide-react';\nimport Link from 'next/link';\nimport { ENV } from '@/util/env';\nimport { Badges } from './Badges';\nimport { DeprecatedNode } from './DeprecatedNode';\nimport { ExampleNode } from './ExampleNode';\nimport { ExcerptNode } from './ExcerptNode';\nimport { InheritedFromNode } from './InheritedFromNode';\nimport { ParameterNode } from './ParameterNode';\nimport { ReturnNode } from './ReturnNode';\nimport { SeeNode } from './SeeNode';\nimport { SummaryNode } from './SummaryNode';\nimport { TypeParameterNode } from './TypeParameterNode';\nimport { UnstableNode } from './UnstableNode';\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from './ui/Collapsible';\nimport { Tab, TabList, TabPanel, Tabs } from './ui/Tabs';\n\nasync function MethodBodyNode({\n\tmethod,\n\tpackageName,\n\tversion,\n\toverload = false,\n}: {\n\treadonly method: any;\n\treadonly overload?: boolean;\n\treadonly packageName: string;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<>\n\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t<div className=\"flex place-content-between place-items-center gap-1\">\n\t\t\t\t\t<h3\n\t\t\t\t\t\tclassName={`${overload ? (ENV.IS_LOCAL_DEV || ENV.IS_PREVIEW ? 'scroll-mt-24' : 'scroll-mt-16') : ENV.IS_LOCAL_DEV || ENV.IS_PREVIEW ? 'scroll-mt-16' : 'scroll-mt-8'} group px-2 font-mono font-semibold break-all`}\n\t\t\t\t\t\tid={method.displayName}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Badges node={method} /> {method.displayName}\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t<Link className=\"float-left -ml-6 hidden pr-2 pb-2 group-hover:block\" href={`#${method.displayName}`}>\n\t\t\t\t\t\t\t\t<LinkIcon aria-hidden size={16} />\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t{method.typeParameters?.length ? (\n\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t{'<'}\n\t\t\t\t\t\t\t\t\t<TypeParameterNode node={method.typeParameters} version={version} />\n\t\t\t\t\t\t\t\t\t{'>'}\n\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t({method.parameters?.length ? <ParameterNode node={method.parameters} version={version} /> : null}\n\t\t\t\t\t\t\t) : <ExcerptNode node={method.returnTypeExcerpt} version={version} />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</h3>\n\n\t\t\t\t\t<a\n\t\t\t\t\t\taria-label=\"Open source file in new tab\"\n\t\t\t\t\t\tclassName=\"min-w-min\"\n\t\t\t\t\t\thref={method.sourceLine ? `${method.sourceURL}#L${method.sourceLine}` : method.sourceURL}\n\t\t\t\t\t\trel=\"external noreferrer noopener\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Code2\n\t\t\t\t\t\t\taria-hidden\n\t\t\t\t\t\t\tclassName=\"text-neutral-500 hover:text-neutral-600 dark:text-neutral-400 dark:hover:text-neutral-300\"\n\t\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</a>\n\t\t\t\t</div>\n\n\t\t\t\t{method.summary?.deprecatedBlock.length ? (\n\t\t\t\t\t<DeprecatedNode deprecatedBlock={method.summary.deprecatedBlock} version={version} />\n\t\t\t\t) : null}\n\n\t\t\t\t{method.summary?.unstableBlock?.length ? (\n\t\t\t\t\t<UnstableNode unstableBlock={method.summary.unstableBlock} version={version} />\n\t\t\t\t) : null}\n\n\t\t\t\t{method.summary?.summarySection.length ? (\n\t\t\t\t\t<SummaryNode node={method.summary.summarySection} padding version={version} />\n\t\t\t\t) : null}\n\n\t\t\t\t{method.summary?.exampleBlocks.length ? (\n\t\t\t\t\t<ExampleNode node={method.summary.exampleBlocks} version={version} />\n\t\t\t\t) : null}\n\n\t\t\t\t{method.summary?.returnsBlock.length ? (\n\t\t\t\t\t<ReturnNode node={method.summary.returnsBlock} padding version={version} />\n\t\t\t\t) : null}\n\n\t\t\t\t{method.inheritedFrom ? (\n\t\t\t\t\t<InheritedFromNode node={method.inheritedFrom} packageName={packageName} version={version} />\n\t\t\t\t) : null}\n\n\t\t\t\t{method.summary?.seeBlocks.length ? (\n\t\t\t\t\t<SeeNode node={method.summary.seeBlocks} padding version={version} />\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t\t<div aria-hidden className=\"p-4\">\n\t\t\t\t<div className=\"h-[2px] bg-neutral-300 dark:bg-neutral-700\" role=\"separator\" />\n\t\t\t</div>\n\t\t</>\n\t);\n}\n\nasync function OverloadNode({\n\tmethod,\n\tpackageName,\n\tversion,\n}: {\n\treadonly method: any;\n\treadonly packageName: string;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<Tabs className=\"flex flex-col gap-4\">\n\t\t\t<TabList className=\"flex flex-wrap gap-2\">\n\t\t\t\t{method.overloads.map((overload: any) => (\n\t\t\t\t\t<Tab\n\t\t\t\t\t\tclassName=\"cursor-pointer rounded-full bg-neutral-800/10 px-2 py-1 font-sans text-sm leading-none font-normal whitespace-nowrap text-neutral-800 hover:bg-neutral-800/20 data-[selected]:bg-neutral-500 data-[selected]:text-neutral-100 dark:bg-neutral-200/10 dark:text-neutral-200 dark:hover:bg-neutral-200/20 dark:data-[selected]:bg-neutral-500/70\"\n\t\t\t\t\t\tid={`overload-${overload.displayName}-${overload.overloadIndex}`}\n\t\t\t\t\t\tkey={`overload-tab-${overload.displayName}-${overload.overloadIndex}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t<span>Overload {overload.overloadIndex}</span>\n\t\t\t\t\t</Tab>\n\t\t\t\t))}\n\t\t\t</TabList>\n\t\t\t{method.overloads.map((overload: any) => (\n\t\t\t\t<TabPanel\n\t\t\t\t\tclassName=\"flex flex-col gap-4\"\n\t\t\t\t\tid={`overload-${overload.displayName}-${overload.overloadIndex}`}\n\t\t\t\t\tkey={`overload-tab-panel-${overload.displayName}-${overload.overloadIndex}`}\n\t\t\t\t>\n\t\t\t\t\t<MethodBodyNode method={overload} overload packageName={packageName} version={version} />\n\t\t\t\t</TabPanel>\n\t\t\t))}\n\t\t</Tabs>\n\t);\n}\n\nexport async function MethodNode({\n\tnode,\n\tpackageName,\n\tversion,\n}: {\n\treadonly node: any;\n\treadonly packageName: string;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<Collapsible className=\"flex flex-col gap-4\" defaultOpen>\n\t\t\t<CollapsibleTrigger className=\"group flex place-content-between place-items-center rounded-md p-2 hover:bg-[#e7e7e9] dark:hover:bg-[#242428]\">\n\t\t\t\t<h2 className=\"flex place-items-center gap-2 text-xl font-bold\">\n\t\t\t\t\t<VscSymbolMethod aria-hidden className=\"flex-shrink-0\" size={24} /> Methods\n\t\t\t\t</h2>\n\t\t\t\t<ChevronDown aria-hidden className='group-data-[state=\"open\"]:hidden' size={24} />\n\t\t\t\t<ChevronUp aria-hidden className='group-data-[state=\"closed\"]:hidden' size={24} />\n\t\t\t</CollapsibleTrigger>\n\n\t\t\t<CollapsibleContent>\n\t\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t\t{node.map((method: any) =>\n\t\t\t\t\t\tmethod.overloads?.length ? (\n\t\t\t\t\t\t\t<OverloadNode\n\t\t\t\t\t\t\t\tkey={`${method.displayName}-${method.overloadIndex}`}\n\t\t\t\t\t\t\t\tmethod={method}\n\t\t\t\t\t\t\t\tpackageName={packageName}\n\t\t\t\t\t\t\t\tversion={version}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<MethodBodyNode\n\t\t\t\t\t\t\t\tkey={`${method.displayName}-${method.overloadIndex}`}\n\t\t\t\t\t\t\t\tmethod={method}\n\t\t\t\t\t\t\t\tpackageName={packageName}\n\t\t\t\t\t\t\t\tversion={version}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t),\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</CollapsibleContent>\n\t\t</Collapsible>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/Navigation.tsx",
    "content": "'use client';\n\nimport { useQuery } from '@tanstack/react-query';\nimport { ChevronDown, ChevronUp, Loader2Icon } from 'lucide-react';\nimport { notFound, useParams } from 'next/navigation';\nimport { parseDocsPathParams } from '@/util/parseDocsPathParams';\nimport { resolveNodeKind } from './DocKind';\nimport { NavigationItem } from './NavigationItem';\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from './ui/Collapsible';\n\nexport function Navigation() {\n\tconst params = useParams<{\n\t\titem?: string[] | undefined;\n\t\tpackageName: string;\n\t\tversion: string;\n\t}>();\n\n\tconst { entryPoints: parsedEntrypoints } = parseDocsPathParams(params.item);\n\n\tconst {\n\t\tdata: node,\n\t\tstatus,\n\t\tisLoading,\n\t} = useQuery({\n\t\tqueryKey: ['sitemap', params.packageName, params.version, parsedEntrypoints.join('.')],\n\t\tqueryFn: async () => {\n\t\t\tconst response = await fetch(\n\t\t\t\t`/api/docs/sitemap?packageName=${params.packageName}&version=${params.version}&entryPoint=${parsedEntrypoints.join('.')}`,\n\t\t\t);\n\n\t\t\treturn response.json();\n\t\t},\n\t});\n\n\tif ((status === 'success' && !node) || status === 'error') {\n\t\tnotFound();\n\t}\n\n\tconst groupedNodes = node?.reduce((acc: any, node: any) => {\n\t\t(acc[node.kind.toLowerCase()] ||= []).push(node);\n\t\treturn acc;\n\t}, {});\n\n\tif (isLoading) {\n\t\treturn <Loader2Icon className=\"mx-auto h-10 w-10 animate-spin\" />;\n\t}\n\n\treturn (\n\t\t<nav className=\"flex flex-col gap-2 pr-3\">\n\t\t\t{groupedNodes?.class?.length ? (\n\t\t\t\t<Collapsible className=\"flex flex-col gap-2\" defaultOpen>\n\t\t\t\t\t<CollapsibleTrigger className=\"group flex place-content-between place-items-center rounded-md p-2 hover:bg-[#e7e7e9] dark:hover:bg-[#242428]\">\n\t\t\t\t\t\t<h4 className=\"font-semibold\">Classes</h4>\n\t\t\t\t\t\t<ChevronDown aria-hidden className='group-data-[state=\"open\"]:hidden' size={24} />\n\t\t\t\t\t\t<ChevronUp aria-hidden className='group-data-[state=\"closed\"]:hidden' size={24} />\n\t\t\t\t\t</CollapsibleTrigger>\n\t\t\t\t\t<CollapsibleContent>\n\t\t\t\t\t\t<div className=\"flex flex-col\">\n\t\t\t\t\t\t\t{groupedNodes.class.map((node: any, idx: number) => {\n\t\t\t\t\t\t\t\tconst kind = resolveNodeKind(node.kind);\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<NavigationItem\n\t\t\t\t\t\t\t\t\t\tkey={`${node.name}-${idx}`}\n\t\t\t\t\t\t\t\t\t\tnode={node}\n\t\t\t\t\t\t\t\t\t\tpackageName={params.packageName}\n\t\t\t\t\t\t\t\t\t\tversion={params.version}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<div className={`inline-block h-6 w-6 rounded-full text-center ${kind.background} ${kind.text}`}>\n\t\t\t\t\t\t\t\t\t\t\t{node.kind[0]}\n\t\t\t\t\t\t\t\t\t\t</div>{' '}\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-sans\">{node.name}</span>\n\t\t\t\t\t\t\t\t\t</NavigationItem>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CollapsibleContent>\n\t\t\t\t</Collapsible>\n\t\t\t) : null}\n\n\t\t\t{groupedNodes?.function?.length ? (\n\t\t\t\t<Collapsible className=\"flex flex-col gap-2\" defaultOpen>\n\t\t\t\t\t<CollapsibleTrigger className=\"group flex place-content-between place-items-center rounded-md p-2 hover:bg-[#e7e7e9] dark:hover:bg-[#242428]\">\n\t\t\t\t\t\t<h4 className=\"font-semibold\">Functions</h4>\n\t\t\t\t\t\t<ChevronDown aria-hidden className='group-data-[state=\"open\"]:hidden' size={24} />\n\t\t\t\t\t\t<ChevronUp aria-hidden className='group-data-[state=\"closed\"]:hidden' size={24} />\n\t\t\t\t\t</CollapsibleTrigger>\n\t\t\t\t\t<CollapsibleContent>\n\t\t\t\t\t\t<div className=\"flex flex-col\">\n\t\t\t\t\t\t\t{groupedNodes.function.map((node: any, idx: number) => {\n\t\t\t\t\t\t\t\tconst kind = resolveNodeKind(node.kind);\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<NavigationItem\n\t\t\t\t\t\t\t\t\t\tkey={`${node.name}-${idx}`}\n\t\t\t\t\t\t\t\t\t\tnode={node}\n\t\t\t\t\t\t\t\t\t\tpackageName={params.packageName}\n\t\t\t\t\t\t\t\t\t\tversion={params.version}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<div className={`inline-block h-6 w-6 rounded-full text-center ${kind.background} ${kind.text}`}>\n\t\t\t\t\t\t\t\t\t\t\t{node.kind[0]}\n\t\t\t\t\t\t\t\t\t\t</div>{' '}\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-sans\">{node.name}</span>\n\t\t\t\t\t\t\t\t\t</NavigationItem>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CollapsibleContent>\n\t\t\t\t</Collapsible>\n\t\t\t) : null}\n\n\t\t\t{groupedNodes?.enum?.length ? (\n\t\t\t\t<Collapsible className=\"flex flex-col gap-2\" defaultOpen>\n\t\t\t\t\t<CollapsibleTrigger className=\"group flex place-content-between place-items-center rounded-md p-2 hover:bg-[#e7e7e9] dark:hover:bg-[#242428]\">\n\t\t\t\t\t\t<h4 className=\"font-semibold\">Enums</h4>\n\t\t\t\t\t\t<ChevronDown aria-hidden className='group-data-[state=\"open\"]:hidden' size={24} />\n\t\t\t\t\t\t<ChevronUp aria-hidden className='group-data-[state=\"closed\"]:hidden' size={24} />\n\t\t\t\t\t</CollapsibleTrigger>\n\t\t\t\t\t<CollapsibleContent>\n\t\t\t\t\t\t<div className=\"flex flex-col\">\n\t\t\t\t\t\t\t{groupedNodes.enum.map((node: any, idx: number) => {\n\t\t\t\t\t\t\t\tconst kind = resolveNodeKind(node.kind);\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<NavigationItem\n\t\t\t\t\t\t\t\t\t\tkey={`${node.name}-${idx}`}\n\t\t\t\t\t\t\t\t\t\tnode={node}\n\t\t\t\t\t\t\t\t\t\tpackageName={params.packageName}\n\t\t\t\t\t\t\t\t\t\tversion={params.version}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<div className={`inline-block h-6 w-6 rounded-full text-center ${kind.background} ${kind.text}`}>\n\t\t\t\t\t\t\t\t\t\t\t{node.kind[0]}\n\t\t\t\t\t\t\t\t\t\t</div>{' '}\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-sans\">{node.name}</span>\n\t\t\t\t\t\t\t\t\t</NavigationItem>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CollapsibleContent>\n\t\t\t\t</Collapsible>\n\t\t\t) : null}\n\n\t\t\t{groupedNodes?.interface?.length ? (\n\t\t\t\t<Collapsible className=\"flex flex-col gap-2\" defaultOpen>\n\t\t\t\t\t<CollapsibleTrigger className=\"group flex place-content-between place-items-center rounded-md p-2 hover:bg-[#e7e7e9] dark:hover:bg-[#242428]\">\n\t\t\t\t\t\t<h4 className=\"font-semibold\">Interfaces</h4>\n\t\t\t\t\t\t<ChevronDown aria-hidden className='group-data-[state=\"open\"]:hidden' size={24} />\n\t\t\t\t\t\t<ChevronUp aria-hidden className='group-data-[state=\"closed\"]:hidden' size={24} />\n\t\t\t\t\t</CollapsibleTrigger>\n\t\t\t\t\t<CollapsibleContent>\n\t\t\t\t\t\t<div className=\"flex flex-col\">\n\t\t\t\t\t\t\t{groupedNodes.interface.map((node: any, idx: number) => {\n\t\t\t\t\t\t\t\tconst kind = resolveNodeKind(node.kind);\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<NavigationItem\n\t\t\t\t\t\t\t\t\t\tkey={`${node.name}-${idx}`}\n\t\t\t\t\t\t\t\t\t\tnode={node}\n\t\t\t\t\t\t\t\t\t\tpackageName={params.packageName}\n\t\t\t\t\t\t\t\t\t\tversion={params.version}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<div className={`inline-block h-6 w-6 rounded-full text-center ${kind.background} ${kind.text}`}>\n\t\t\t\t\t\t\t\t\t\t\t{node.kind[0]}\n\t\t\t\t\t\t\t\t\t\t</div>{' '}\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-sans\">{node.name}</span>\n\t\t\t\t\t\t\t\t\t</NavigationItem>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CollapsibleContent>\n\t\t\t\t</Collapsible>\n\t\t\t) : null}\n\n\t\t\t{groupedNodes?.typealias?.length ? (\n\t\t\t\t<Collapsible className=\"flex flex-col gap-2\" defaultOpen>\n\t\t\t\t\t<CollapsibleTrigger className=\"group flex place-content-between place-items-center rounded-md p-2 hover:bg-[#e7e7e9] dark:hover:bg-[#242428]\">\n\t\t\t\t\t\t<h4 className=\"font-semibold\">Types</h4>\n\t\t\t\t\t\t<ChevronDown aria-hidden className='group-data-[state=\"open\"]:hidden' size={24} />\n\t\t\t\t\t\t<ChevronUp aria-hidden className='group-data-[state=\"closed\"]:hidden' size={24} />\n\t\t\t\t\t</CollapsibleTrigger>\n\t\t\t\t\t<CollapsibleContent>\n\t\t\t\t\t\t<div className=\"flex flex-col\">\n\t\t\t\t\t\t\t{groupedNodes.typealias.map((node: any, idx: number) => {\n\t\t\t\t\t\t\t\tconst kind = resolveNodeKind(node.kind);\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<NavigationItem\n\t\t\t\t\t\t\t\t\t\tkey={`${node.name}-${idx}`}\n\t\t\t\t\t\t\t\t\t\tnode={node}\n\t\t\t\t\t\t\t\t\t\tpackageName={params.packageName}\n\t\t\t\t\t\t\t\t\t\tversion={params.version}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<div className={`inline-block h-6 w-6 rounded-full text-center ${kind.background} ${kind.text}`}>\n\t\t\t\t\t\t\t\t\t\t\t{node.kind[0]}\n\t\t\t\t\t\t\t\t\t\t</div>{' '}\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-sans\">{node.name}</span>\n\t\t\t\t\t\t\t\t\t</NavigationItem>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CollapsibleContent>\n\t\t\t\t</Collapsible>\n\t\t\t) : null}\n\n\t\t\t{groupedNodes?.variable?.length ? (\n\t\t\t\t<Collapsible className=\"flex flex-col gap-2\" defaultOpen>\n\t\t\t\t\t<CollapsibleTrigger className=\"group flex place-content-between place-items-center rounded-md p-2 hover:bg-[#e7e7e9] dark:hover:bg-[#242428]\">\n\t\t\t\t\t\t<h4 className=\"font-semibold\">Variables</h4>\n\t\t\t\t\t\t<ChevronDown aria-hidden className='group-data-[state=\"open\"]:hidden' size={24} />\n\t\t\t\t\t\t<ChevronUp aria-hidden className='group-data-[state=\"closed\"]:hidden' size={24} />\n\t\t\t\t\t</CollapsibleTrigger>\n\t\t\t\t\t<CollapsibleContent>\n\t\t\t\t\t\t<div className=\"flex flex-col\">\n\t\t\t\t\t\t\t{groupedNodes.variable.map((node: any, idx: number) => {\n\t\t\t\t\t\t\t\tconst kind = resolveNodeKind(node.kind);\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<NavigationItem\n\t\t\t\t\t\t\t\t\t\tkey={`${node.name}-${idx}`}\n\t\t\t\t\t\t\t\t\t\tnode={node}\n\t\t\t\t\t\t\t\t\t\tpackageName={params.packageName}\n\t\t\t\t\t\t\t\t\t\tversion={params.version}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<div className={`inline-block h-6 w-6 rounded-full text-center ${kind.background} ${kind.text}`}>\n\t\t\t\t\t\t\t\t\t\t\t{node.kind[0]}\n\t\t\t\t\t\t\t\t\t\t</div>{' '}\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-sans\">{node.name}</span>\n\t\t\t\t\t\t\t\t\t</NavigationItem>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CollapsibleContent>\n\t\t\t\t</Collapsible>\n\t\t\t) : null}\n\t\t</nav>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/NavigationItem.tsx",
    "content": "'use client';\n\nimport { useSetAtom } from 'jotai';\nimport Link from 'next/link';\nimport { usePathname, useRouter } from 'next/navigation';\nimport type { PropsWithChildren } from 'react';\nimport { isDrawerOpenAtom } from '@/stores/drawer';\nimport { cx } from '@/styles/cva';\n\nexport function NavigationItem({\n\tnode,\n\tpackageName,\n\tversion,\n\tchildren,\n}: PropsWithChildren<{\n\treadonly node: any;\n\treadonly packageName: string;\n\treadonly version: string;\n}>) {\n\tconst router = useRouter();\n\tconst pathname = usePathname();\n\tconst setDrawerOpen = useSetAtom(isDrawerOpenAtom);\n\n\tconst href = `/docs/packages/${packageName}/${version}/${node.href}`;\n\n\treturn (\n\t\t<Link\n\t\t\tclassName={cx(\n\t\t\t\t'dark:hover:text-base-neutral-40 hover:text-base-neutral-900 truncate rounded-lg p-2 font-mono text-[#676771] transition-colors hover:bg-[#e7e7e9] active:bg-[#e4e4e7] md:py-1 dark:text-[#83838b] dark:hover:bg-[#1d1d1e] dark:active:bg-[#27272b]',\n\t\t\t\tpathname === href &&\n\t\t\t\t\t'dark:text-base-neutral-40 text-base-neutral-900 bg-[#d9d9dc] font-medium dark:bg-[#323235] dark:hover:bg-[#323235]',\n\t\t\t)}\n\t\t\thref={href}\n\t\t\tonClick={() => setDrawerOpen(false)}\n\t\t\tonMouseEnter={() => router.prefetch(href)}\n\t\t\tonTouchStart={() => router.prefetch(href)}\n\t\t\tprefetch={false}\n\t\t\ttitle={node.name}\n\t\t\t// @ts-expect-error - unstable_dynamicOnHover is not part of the public types\n\t\t\tunstable_dynamicOnHover\n\t\t>\n\t\t\t{children}\n\t\t</Link>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/Outline.tsx",
    "content": "import { VscListSelection } from '@react-icons/all-files/vsc/VscListSelection';\nimport { VscSymbolEvent } from '@react-icons/all-files/vsc/VscSymbolEvent';\nimport { VscSymbolMethod } from '@react-icons/all-files/vsc/VscSymbolMethod';\nimport { VscSymbolProperty } from '@react-icons/all-files/vsc/VscSymbolProperty';\nimport { ChevronDown, ChevronUp } from 'lucide-react';\nimport Link from 'next/link';\nimport { Fragment } from 'react';\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from './ui/Collapsible';\n\nexport async function Outline({ node }: { readonly node: any }) {\n\tconst hasAny = node.members?.properties?.length || node.members?.events?.length || node.members?.methods?.length;\n\n\treturn hasAny ? (\n\t\t<Collapsible className=\"flex flex-col gap-4\" defaultOpen>\n\t\t\t<CollapsibleTrigger className=\"group flex place-content-between place-items-center rounded-md p-2 hover:bg-[#e7e7e9] dark:hover:bg-[#242428]\">\n\t\t\t\t<h2 className=\"flex place-items-center gap-2 text-xl font-bold\">\n\t\t\t\t\t<VscListSelection aria-hidden className=\"flex-shrink-0\" size={24} /> Table of contents\n\t\t\t\t</h2>\n\t\t\t\t<ChevronDown aria-hidden className='group-data-[state=\"open\"]:hidden' size={24} />\n\t\t\t\t<ChevronUp aria-hidden className='group-data-[state=\"closed\"]:hidden' size={24} />\n\t\t\t</CollapsibleTrigger>\n\n\t\t\t<CollapsibleContent>\n\t\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t\t<div className=\"grid gap-2 sm:grid-cols-2\">\n\t\t\t\t\t\t{node.members?.properties?.length ? (\n\t\t\t\t\t\t\t<Collapsible className=\"flex flex-col gap-2\" defaultOpen>\n\t\t\t\t\t\t\t\t<CollapsibleTrigger className=\"group flex place-content-between place-items-center rounded-md p-2 hover:bg-[#e7e7e9] dark:hover:bg-[#242428]\">\n\t\t\t\t\t\t\t\t\t<h2 className=\"flex place-items-center gap-2 text-xl font-bold\">\n\t\t\t\t\t\t\t\t\t\t<VscSymbolProperty aria-hidden className=\"flex-shrink-0\" size={24} />\n\t\t\t\t\t\t\t\t\t\tProperties\n\t\t\t\t\t\t\t\t\t</h2>\n\t\t\t\t\t\t\t\t\t<ChevronDown aria-hidden className='group-data-[state=\"open\"]:hidden' size={24} />\n\t\t\t\t\t\t\t\t\t<ChevronUp aria-hidden className='group-data-[state=\"closed\"]:hidden' size={24} />\n\t\t\t\t\t\t\t\t</CollapsibleTrigger>\n\n\t\t\t\t\t\t\t\t<CollapsibleContent>\n\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col px-4\">\n\t\t\t\t\t\t\t\t\t\t{node.members.properties.map((property: any, idx: number) => (\n\t\t\t\t\t\t\t\t\t\t\t<Fragment key={`${property.displayName}-${idx}`}>\n\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex place-content-between place-items-center\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"max-w-[25ch] grow truncate rounded-md p-2 font-mono transition-colors hover:bg-[#e7e7e9] md:max-w-none md:py-1 dark:hover:bg-[#242428]\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\thref={`#${property.displayName}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{property.displayName}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t</Fragment>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</CollapsibleContent>\n\t\t\t\t\t\t\t</Collapsible>\n\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t{node.members?.methods?.length ? (\n\t\t\t\t\t\t\t<Collapsible className=\"flex flex-col gap-2\" defaultOpen>\n\t\t\t\t\t\t\t\t<CollapsibleTrigger className=\"group flex place-content-between place-items-center rounded-md p-2 hover:bg-[#e7e7e9] dark:hover:bg-[#242428]\">\n\t\t\t\t\t\t\t\t\t<h2 className=\"flex place-items-center gap-2 text-xl font-bold\">\n\t\t\t\t\t\t\t\t\t\t<VscSymbolMethod aria-hidden className=\"flex-shrink-0\" size={24} />\n\t\t\t\t\t\t\t\t\t\tMethods\n\t\t\t\t\t\t\t\t\t</h2>\n\t\t\t\t\t\t\t\t\t<ChevronDown aria-hidden className='group-data-[state=\"open\"]:hidden' size={24} />\n\t\t\t\t\t\t\t\t\t<ChevronUp aria-hidden className='group-data-[state=\"closed\"]:hidden' size={24} />\n\t\t\t\t\t\t\t\t</CollapsibleTrigger>\n\n\t\t\t\t\t\t\t\t<CollapsibleContent>\n\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col px-4\">\n\t\t\t\t\t\t\t\t\t\t{node.members.methods.map((method: any, idx: number) => (\n\t\t\t\t\t\t\t\t\t\t\t<Fragment key={`${method.displayName}-${idx}`}>\n\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex place-content-between place-items-center\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"max-w-[25ch] grow truncate rounded-md p-2 font-mono transition-colors hover:bg-[#e7e7e9] md:max-w-none md:py-1 dark:hover:bg-[#242428]\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\thref={`#${method.displayName}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{method.displayName}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t</Fragment>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</CollapsibleContent>\n\t\t\t\t\t\t\t</Collapsible>\n\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t{node.members?.events?.length ? (\n\t\t\t\t\t\t\t<Collapsible className=\"flex flex-col gap-2\" defaultOpen>\n\t\t\t\t\t\t\t\t<CollapsibleTrigger className=\"group flex place-content-between place-items-center rounded-md p-2 hover:bg-[#e7e7e9] dark:hover:bg-[#242428]\">\n\t\t\t\t\t\t\t\t\t<h2 className=\"flex place-items-center gap-2 text-xl font-bold\">\n\t\t\t\t\t\t\t\t\t\t<VscSymbolEvent aria-hidden className=\"flex-shrink-0\" size={24} />\n\t\t\t\t\t\t\t\t\t\tEvents\n\t\t\t\t\t\t\t\t\t</h2>\n\t\t\t\t\t\t\t\t\t<ChevronDown aria-hidden className='group-data-[state=\"open\"]:hidden' size={24} />\n\t\t\t\t\t\t\t\t\t<ChevronUp aria-hidden className='group-data-[state=\"closed\"]:hidden' size={24} />\n\t\t\t\t\t\t\t\t</CollapsibleTrigger>\n\n\t\t\t\t\t\t\t\t<CollapsibleContent>\n\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col px-4\">\n\t\t\t\t\t\t\t\t\t\t{node.members.events.map((event: any, idx: number) => (\n\t\t\t\t\t\t\t\t\t\t\t<Fragment key={`${event.displayName}-${idx}`}>\n\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex place-content-between place-items-center\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"max-w-[25ch] grow truncate rounded-md p-2 font-mono transition-colors hover:bg-[#e7e7e9] md:max-w-none md:py-1 dark:hover:bg-[#242428]\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\thref={`#${event.displayName}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{event.displayName}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t</Fragment>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</CollapsibleContent>\n\t\t\t\t\t\t\t</Collapsible>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div aria-hidden className=\"p-4\">\n\t\t\t\t\t\t<div className=\"h-[2px] bg-neutral-300 dark:bg-neutral-700\" role=\"separator\" />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</CollapsibleContent>\n\t\t</Collapsible>\n\t) : null;\n}\n"
  },
  {
    "path": "apps/website/src/components/OverlayScrollbars.tsx",
    "content": "'use client';\n\nimport { OverlayScrollbars, ClickScrollPlugin } from 'overlayscrollbars';\nimport type { OverlayScrollbarsComponentProps } from 'overlayscrollbars-react';\nimport { OverlayScrollbarsComponent } from 'overlayscrollbars-react';\nimport { cx } from '@/styles/cva';\n\nOverlayScrollbars.plugin(ClickScrollPlugin);\n\nexport function Scrollbars(props: OverlayScrollbarsComponentProps) {\n\tconst { className, children, ...additionalProps } = props;\n\n\treturn (\n\t\t<OverlayScrollbarsComponent {...additionalProps} className={cx('', className)} defer>\n\t\t\t{children}\n\t\t</OverlayScrollbarsComponent>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/PackageSelect.tsx",
    "content": "'use client';\n\nimport { useParams, useRouter } from 'next/navigation';\nimport { Select, SelectList, SelectOption, SelectTrigger } from '@/components/ui/Select';\nimport { PACKAGES } from '@/util/constants';\n\nexport function PackageSelect() {\n\tconst router = useRouter();\n\tconst params = useParams<{\n\t\tpackageName: string;\n\t}>();\n\n\treturn (\n\t\t<Select aria-label=\"Select a package\" defaultSelectedKey={params.packageName} key={params.packageName}>\n\t\t\t<SelectTrigger className=\"bg-[#f3f3f4] dark:bg-[#121214]\" />\n\t\t\t<SelectList classNames={{ popover: 'bg-[#f3f3f4] dark:bg-[#28282d]' }} items={PACKAGES}>\n\t\t\t\t{(item) => (\n\t\t\t\t\t<SelectOption\n\t\t\t\t\t\tclassName=\"dark:pressed:bg-[#313135] bg-[#f3f3f4] dark:bg-[#28282d] dark:hover:bg-[#313135]\"\n\t\t\t\t\t\thref={`/docs/packages/${item.name}/stable`}\n\t\t\t\t\t\tid={item.name}\n\t\t\t\t\t\tkey={item.name}\n\t\t\t\t\t\tonHoverStart={() => router.prefetch(`/docs/packages/${item.name}/stable`)}\n\t\t\t\t\t\ttextValue={item.name}\n\t\t\t\t\t>\n\t\t\t\t\t\t{item.name}\n\t\t\t\t\t</SelectOption>\n\t\t\t\t)}\n\t\t\t</SelectList>\n\t\t</Select>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/ParameterNode.tsx",
    "content": "import { LinkIcon } from 'lucide-react';\nimport Link from 'next/link';\nimport { Fragment } from 'react';\nimport { Badges } from './Badges';\nimport { DocNode } from './DocNode';\nimport { ExcerptNode } from './ExcerptNode';\n\nexport async function ParameterNode({\n\tdescription = false,\n\tnode,\n\tversion,\n}: {\n\treadonly description?: boolean;\n\treadonly node: any;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<div className={`${description ? 'flex flex-col gap-4' : 'inline'}`}>\n\t\t\t{node.map((parameter: any, idx: number) => (\n\t\t\t\t<Fragment key={`${parameter.name}-${idx}`}>\n\t\t\t\t\t<div className={description ? 'group' : 'inline after:content-[\",_\"] last-of-type:after:content-none'}>\n\t\t\t\t\t\t<span className=\"font-mono font-semibold\">\n\t\t\t\t\t\t\t{description ? (\n\t\t\t\t\t\t\t\t<Link className=\"float-left -ml-6 hidden pr-2 pb-2 group-hover:block\" href={`#${parameter.name}`}>\n\t\t\t\t\t\t\t\t\t<LinkIcon aria-hidden size={16} />\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t{description ? <Badges node={parameter} /> : null}\n\t\t\t\t\t\t\t{parameter.name}\n\t\t\t\t\t\t\t{parameter.isOptional ? '?' : ''}: <ExcerptNode node={parameter.typeExcerpt} version={version} />\n\t\t\t\t\t\t\t{parameter.defaultValue ? ` = ${parameter.defaultValue}` : ''}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t{description && parameter.description?.length ? (\n\t\t\t\t\t\t\t<div className=\"mt-4 pl-4\">\n\t\t\t\t\t\t\t\t<DocNode node={parameter.description} version={version} />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</div>\n\t\t\t\t</Fragment>\n\t\t\t))}\n\t\t\t{description ? (\n\t\t\t\t<div aria-hidden className=\"p-4\">\n\t\t\t\t\t<div className=\"h-[2px] bg-neutral-300 dark:bg-neutral-700\" role=\"separator\" />\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/PropertyNode.tsx",
    "content": "import { VscSymbolProperty } from '@react-icons/all-files/vsc/VscSymbolProperty';\nimport { ChevronDown, ChevronUp, Code2, LinkIcon } from 'lucide-react';\nimport Link from 'next/link';\nimport { Fragment } from 'react';\nimport { ENV } from '@/util/env';\nimport { Badges } from './Badges';\nimport { DeprecatedNode } from './DeprecatedNode';\nimport { ExcerptNode } from './ExcerptNode';\nimport { InheritedFromNode } from './InheritedFromNode';\nimport { SeeNode } from './SeeNode';\nimport { SummaryNode } from './SummaryNode';\nimport { UnstableNode } from './UnstableNode';\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from './ui/Collapsible';\n\nexport async function PropertyNode({\n\tnode,\n\tpackageName,\n\tversion,\n}: {\n\treadonly node: any;\n\treadonly packageName: string;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<Collapsible className=\"flex flex-col gap-4\" defaultOpen>\n\t\t\t<CollapsibleTrigger className=\"group flex place-content-between place-items-center rounded-md p-2 hover:bg-[#e7e7e9] dark:hover:bg-[#242428]\">\n\t\t\t\t<h2 className=\"flex place-items-center gap-2 text-xl font-bold\">\n\t\t\t\t\t<VscSymbolProperty aria-hidden className=\"flex-shrink-0\" size={24} />\n\t\t\t\t\tProperties\n\t\t\t\t</h2>\n\t\t\t\t<ChevronDown aria-hidden className='group-data-[state=\"open\"]:hidden' size={24} />\n\t\t\t\t<ChevronUp aria-hidden className='group-data-[state=\"closed\"]:hidden' size={24} />\n\t\t\t</CollapsibleTrigger>\n\n\t\t\t<CollapsibleContent>\n\t\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t\t{node.map((property: any, idx: number) => (\n\t\t\t\t\t\t<Fragment key={`${property.displayName}-${idx}`}>\n\t\t\t\t\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t\t\t\t\t<div className=\"flex place-content-between place-items-center gap-1\">\n\t\t\t\t\t\t\t\t\t<h3\n\t\t\t\t\t\t\t\t\t\tclassName={`${ENV.IS_LOCAL_DEV || ENV.IS_PREVIEW ? 'scroll-mt-16' : 'scroll-mt-8'} group flex flex-col gap-2 px-2 font-mono font-semibold break-all`}\n\t\t\t\t\t\t\t\t\t\tid={property.displayName}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Badges node={property} />\n\t\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"float-left -ml-6 hidden pr-2 pb-2 group-hover:block\"\n\t\t\t\t\t\t\t\t\t\t\t\thref={`#${property.displayName}`}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<LinkIcon aria-hidden size={16} />\n\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t{property.displayName}\n\t\t\t\t\t\t\t\t\t\t\t{property.isOptional ? '?' : ''} : <ExcerptNode node={property.typeExcerpt} version={version} />{' '}\n\t\t\t\t\t\t\t\t\t\t\t{property.summary?.defaultValueBlock.length\n\t\t\t\t\t\t\t\t\t\t\t\t? `= ${property.summary.defaultValueBlock.reduce(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t(acc: string, def: { kind: string; text: string }) => `${acc}${def.text}`,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}`\n\t\t\t\t\t\t\t\t\t\t\t\t: ''}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t</h3>\n\n\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\taria-label=\"Open source file in new tab\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"min-w-min\"\n\t\t\t\t\t\t\t\t\t\thref={property.sourceLine ? `${property.sourceURL}#L${property.sourceLine}` : property.sourceURL}\n\t\t\t\t\t\t\t\t\t\trel=\"external noreferrer noopener\"\n\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Code2\n\t\t\t\t\t\t\t\t\t\t\taria-hidden\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"text-neutral-500 hover:text-neutral-600 dark:text-neutral-400 dark:hover:text-neutral-300\"\n\t\t\t\t\t\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t{property.summary?.deprecatedBlock.length ? (\n\t\t\t\t\t\t\t\t\t<DeprecatedNode deprecatedBlock={property.summary.deprecatedBlock} version={version} />\n\t\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t\t{property.summary?.unstableBlock?.length ? (\n\t\t\t\t\t\t\t\t\t<UnstableNode unstableBlock={property.summary.unstableBlock} version={version} />\n\t\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t\t{property.summary?.summarySection.length ? (\n\t\t\t\t\t\t\t\t\t<SummaryNode node={property.summary.summarySection} padding version={version} />\n\t\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t\t{property.inheritedFrom ? (\n\t\t\t\t\t\t\t\t\t<InheritedFromNode node={property.inheritedFrom} packageName={packageName} version={version} />\n\t\t\t\t\t\t\t\t) : null}\n\n\t\t\t\t\t\t\t\t{property.summary?.seeBlocks.length ? (\n\t\t\t\t\t\t\t\t\t<SeeNode node={property.summary.seeBlocks} padding version={version} />\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div aria-hidden className=\"p-4\">\n\t\t\t\t\t\t\t\t<div className=\"h-[2px] bg-neutral-300 dark:bg-neutral-700\" role=\"separator\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</Fragment>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</CollapsibleContent>\n\t\t</Collapsible>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/ReturnNode.tsx",
    "content": "import { DocNode } from './DocNode';\n\nexport async function ReturnNode({\n\tpadding = false,\n\tnode,\n\tversion,\n}: {\n\treadonly node: any;\n\treadonly padding?: boolean;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<p className={`break-words ${padding ? 'pl-4' : ''}`}>\n\t\t\t<span className=\"font-semibold\">Returns:</span> <DocNode node={node} version={version} />\n\t\t</p>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/SearchButton.tsx",
    "content": "'use client';\n\nimport { useSetAtom } from 'jotai';\nimport { Command, Search } from 'lucide-react';\nimport { isCmdKOpenAtom } from '@/stores/cmdk';\nimport { useSidebar } from './ui/Sidebar';\n\nexport function SearchButton() {\n\tconst { setOpenMobile } = useSidebar();\n\tconst setIsOpen = useSetAtom(isCmdKOpenAtom);\n\n\treturn (\n\t\t<button\n\t\t\taria-label=\"Open search\"\n\t\t\tclassName=\"bg-base-neutral-100 dark:bg-base-neutral-900 flex place-content-between place-items-center rounded-sm p-2\"\n\t\t\tonClick={() => {\n\t\t\t\tsetOpenMobile(false);\n\t\t\t\tsetIsOpen(true);\n\t\t\t}}\n\t\t\ttype=\"button\"\n\t\t>\n\t\t\t<span className=\"flex place-items-center gap-2\">\n\t\t\t\t<Search aria-hidden size={18} />\n\t\t\t\tSearch...\n\t\t\t</span>\n\t\t\t<span className=\"hidden place-items-center gap-1 md:flex\">\n\t\t\t\t<Command aria-hidden size={18} /> K\n\t\t\t</span>\n\t\t</button>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/SeeNode.tsx",
    "content": "import { DocNode } from './DocNode';\n\nexport async function SeeNode({\n\tpadding = false,\n\tnode,\n\tversion,\n}: {\n\treadonly node: any;\n\treadonly padding?: boolean;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<p className={`break-words ${padding ? 'pl-4' : ''}`}>\n\t\t\t<span className=\"font-semibold\">See also:</span> <DocNode node={node} version={version} />\n\t\t</p>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/Sidebar.tsx",
    "content": "'use client';\n\nimport { VscGithubInverted } from '@react-icons/all-files/vsc/VscGithubInverted';\nimport { useQuery } from '@tanstack/react-query';\nimport Link from 'next/link';\nimport { useParams } from 'next/navigation';\nimport { EntryPointSelect } from '@/components/EntrypointSelect';\nimport { PackageSelect } from '@/components/PackageSelect';\nimport { SearchButton } from '@/components/SearchButton';\nimport { ThemeSwitchNoSRR } from '@/components/ThemeSwitch';\nimport { VersionSelect } from '@/components/VersionSelect';\nimport { SidebarHeader as BasSidebarHeader } from '@/components/ui/Sidebar';\nimport { buttonStyles } from '@/styles/ui/button';\nimport { PACKAGES_WITH_ENTRY_POINTS } from '@/util/constants';\nimport type { EntryPoint } from '@/util/fetchEntryPoints';\n\nexport function SidebarHeader() {\n\tconst params = useParams<{\n\t\tpackageName: string;\n\t\tversion: string;\n\t}>();\n\n\tconst hasEntryPoints = PACKAGES_WITH_ENTRY_POINTS.includes(params.packageName);\n\n\tconst { data: entryPoints, isLoading: isLoadingEntryPoints } = useQuery<EntryPoint[]>({\n\t\tqueryKey: ['entryPoints', params.packageName, params.version],\n\t\tqueryFn: async () => {\n\t\t\tconst response = await fetch(`/api/docs/entrypoints?packageName=${params.packageName}&version=${params.version}`);\n\n\t\t\treturn response.json();\n\t\t},\n\t});\n\n\tconst { data: versions, isLoading: isLoadingVersions } = useQuery({\n\t\tqueryKey: ['versions', params.packageName],\n\t\tqueryFn: async () => {\n\t\t\tconst response = await fetch(`/api/docs/versions?packageName=${params.packageName}`);\n\n\t\t\treturn response.json();\n\t\t},\n\t});\n\n\treturn (\n\t\t<BasSidebarHeader className=\"bg-[#f3f3f4] p-4 dark:bg-[#121214]\">\n\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t<div className=\"flex place-content-between place-items-center p-1\">\n\t\t\t\t\t<Link\n\t\t\t\t\t\tclassName=\"text-xl font-bold\"\n\t\t\t\t\t\thref={`/docs/packages/${params.packageName}/${params.version}${hasEntryPoints ? `/${entryPoints?.[0]?.entryPoint ?? ''}` : ''}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t{params.packageName}\n\t\t\t\t\t</Link>\n\t\t\t\t\t<div className=\"flex place-items-center gap-2\">\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\taria-label=\"GitHub\"\n\t\t\t\t\t\t\tclassName={buttonStyles({ variant: 'filled', size: 'icon-sm' })}\n\t\t\t\t\t\t\thref=\"https://github.com/discordjs/discord.js\"\n\t\t\t\t\t\t\trel=\"external noopener noreferrer\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<VscGithubInverted aria-hidden data-slot=\"icon\" size={18} />\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t<ThemeSwitchNoSRR />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<PackageSelect />\n\t\t\t\t{/* <h3 className=\"p-1 text-lg font-semibold\">{version}</h3> */}\n\t\t\t\t<VersionSelect isLoading={isLoadingVersions} versions={versions ?? []} />\n\t\t\t\t{hasEntryPoints ? <EntryPointSelect entryPoints={entryPoints ?? []} isLoading={isLoadingEntryPoints} /> : null}\n\t\t\t\t<SearchButton />\n\t\t\t</div>\n\t\t</BasSidebarHeader>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/SummaryNode.tsx",
    "content": "import { DocNode } from './DocNode';\n\nexport async function SummaryNode({\n\tpadding = false,\n\tnode,\n\tversion,\n}: {\n\treadonly node: any;\n\treadonly padding?: boolean;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<p className={`break-words ${padding ? 'pl-4' : ''}`}>\n\t\t\t<DocNode node={node} version={version} />\n\t\t</p>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/SyntaxHighlighter.tsx",
    "content": "import { codeToHtml } from '@/util/shiki.bundle';\n\nexport async function SyntaxHighlighter({\n\tlang,\n\tcode,\n\tclassName = '',\n}: {\n\treadonly className?: string;\n\treadonly code: string;\n\treadonly lang: string;\n}) {\n\tconst codeHTML = await codeToHtml(code.trim(), {\n\t\tlang,\n\t\tthemes: {\n\t\t\tlight: 'github-light',\n\t\t\tdark: 'github-dark-dimmed',\n\t\t},\n\t});\n\n\treturn (\n\t\t<>\n\t\t\t{/* eslint-disable-next-line react/no-danger */}\n\t\t\t<div className={className} dangerouslySetInnerHTML={{ __html: codeHTML }} />\n\t\t</>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/ThemeSwitch.tsx",
    "content": "'use client';\n\nimport { VscColorMode } from '@react-icons/all-files/vsc/VscColorMode';\nimport dynamic from 'next/dynamic';\nimport { useTheme } from 'next-themes';\nimport { Button } from '@/components/ui/Button';\n\nexport function ThemeSwitch() {\n\tconst { resolvedTheme, setTheme } = useTheme();\n\tconst toggleTheme = () => setTheme(resolvedTheme === 'light' ? 'dark' : 'light');\n\n\treturn (\n\t\t<Button aria-label=\"Toggle theme\" onPress={() => toggleTheme()} size=\"icon-sm\" variant=\"filled\">\n\t\t\t<VscColorMode aria-hidden data-slot=\"icon\" size={18} />\n\t\t</Button>\n\t);\n}\n\nexport const ThemeSwitchNoSRR = dynamic(async () => ThemeSwitch, {\n\tssr: false,\n});\n"
  },
  {
    "path": "apps/website/src/components/TypeParameterNode.tsx",
    "content": "import { LinkIcon } from 'lucide-react';\nimport Link from 'next/link';\nimport { Fragment } from 'react';\nimport { cx } from '@/styles/cva';\nimport { ENV } from '@/util/env';\nimport { Badges } from './Badges';\nimport { DocNode } from './DocNode';\nimport { ExcerptNode } from './ExcerptNode';\n\nexport async function TypeParameterNode({\n\tdescription = false,\n\tnode,\n\tversion,\n}: {\n\treadonly description?: boolean;\n\treadonly node: any;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<div className={`${description ? 'flex flex-col gap-4' : 'inline-block'}`}>\n\t\t\t{node.map((typeParameter: any, idx: number) => (\n\t\t\t\t<Fragment key={`${typeParameter.name}-${idx}`}>\n\t\t\t\t\t<div className={description ? '' : 'inline after:content-[\",_\"] last-of-type:after:content-none'}>\n\t\t\t\t\t\t<h3\n\t\t\t\t\t\t\tclassName={cx(\n\t\t\t\t\t\t\t\tENV.IS_LOCAL_DEV || ENV.IS_PREVIEW ? 'scroll-mt-16' : 'scroll-mt-8',\n\t\t\t\t\t\t\t\t'group inline font-mono font-semibold break-words',\n\t\t\t\t\t\t\t\tdescription ? 'inline-block px-2' : '',\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\tid={typeParameter.name}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{description ? <Badges node={typeParameter} /> : null}\n\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t{description ? (\n\t\t\t\t\t\t\t\t\t<Link className=\"float-left -ml-6 hidden pr-2 pb-2 group-hover:block\" href={`#${typeParameter.name}`}>\n\t\t\t\t\t\t\t\t\t\t<LinkIcon aria-hidden size={16} />\n\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t{typeParameter.name}\n\t\t\t\t\t\t\t\t{typeParameter.isOptional ? '?' : ''}\n\t\t\t\t\t\t\t\t{typeParameter.constraintsExcerpt.length ? (\n\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t{' extends '}\n\t\t\t\t\t\t\t\t\t\t<ExcerptNode node={typeParameter.constraintsExcerpt} version={version} />\n\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t{typeParameter.defaultExcerpt.length ? (\n\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t{' = '}\n\t\t\t\t\t\t\t\t\t\t<ExcerptNode node={typeParameter.defaultExcerpt} version={version} />\n\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</h3>\n\n\t\t\t\t\t\t{description && typeParameter.description?.length ? (\n\t\t\t\t\t\t\t<div className=\"pl-4\">\n\t\t\t\t\t\t\t\t<DocNode node={typeParameter.description} version={version} />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</div>\n\t\t\t\t</Fragment>\n\t\t\t))}\n\t\t\t{description ? (\n\t\t\t\t<div aria-hidden className=\"p-4\">\n\t\t\t\t\t<div className=\"h-[2px] bg-neutral-300 dark:bg-neutral-700\" role=\"separator\" />\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/UnionMember.tsx",
    "content": "import { ExcerptNode } from './ExcerptNode';\n\nexport async function UnionMember({ node, version }: { readonly node: any; readonly version: string }) {\n\treturn (\n\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t{node.length > 1 ? <h2 className=\"flex place-items-center gap-2 p-2 text-xl font-bold\">Union Members</h2> : null}\n\n\t\t\t<span className=\"flex flex-col gap-4 px-2 font-mono text-sm break-words\">\n\t\t\t\t<ExcerptNode node={node} version={version} />\n\t\t\t</span>\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/UnstableNode.tsx",
    "content": "import { DocNode } from './DocNode';\nimport { Alert } from './ui/Alert';\n\nexport async function UnstableNode({\n\tunstableBlock,\n\tversion,\n}: {\n\treadonly unstableBlock: any;\n\treadonly version: string;\n}) {\n\treturn (\n\t\t<Alert title=\"Unstable\" type=\"danger\">\n\t\t\t<p className=\"break-words\">\n\t\t\t\t<DocNode node={unstableBlock} version={version} />\n\t\t\t</p>\n\t\t</Alert>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/VersionSelect.tsx",
    "content": "'use client';\n\nimport { Loader2Icon } from 'lucide-react';\nimport { useParams, useRouter } from 'next/navigation';\nimport { Select, SelectList, SelectOption, SelectTrigger } from '@/components/ui/Select';\nimport { DEFAULT_ENTRY_POINT, PACKAGES_WITH_ENTRY_POINTS } from '@/util/constants';\n\nexport function VersionSelect({\n\tversions,\n\tisLoading,\n}: {\n\treadonly isLoading: boolean;\n\treadonly versions: { readonly version: string }[];\n}) {\n\tconst router = useRouter();\n\tconst params = useParams<{ packageName: string; version: string }>();\n\n\tconst hasEntryPoints = PACKAGES_WITH_ENTRY_POINTS.includes(params.packageName);\n\n\treturn (\n\t\t<Select\n\t\t\taria-label={isLoading ? 'Loading versions...' : 'Select a version'}\n\t\t\tdefaultSelectedKey={params.version}\n\t\t\tkey={`${params.packageName}-${params.version}`}\n\t\t\tplaceholder={isLoading ? 'Loading versions...' : 'Select a version'}\n\t\t>\n\t\t\t<SelectTrigger\n\t\t\t\tclassName=\"bg-[#f3f3f4] dark:bg-[#121214]\"\n\t\t\t\tsuffix={\n\t\t\t\t\tisLoading ? (\n\t\t\t\t\t\t<Loader2Icon\n\t\t\t\t\t\t\taria-hidden\n\t\t\t\t\t\t\tclassName=\"size-6 shrink-0 animate-spin duration-200 forced-colors:text-[ButtonText] forced-colors:group-disabled:text-[GrayText]\"\n\t\t\t\t\t\t\tsize={24}\n\t\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<SelectList classNames={{ popover: 'bg-[#f3f3f4] dark:bg-[#28282d]' }} items={versions}>\n\t\t\t\t{(item) => (\n\t\t\t\t\t<SelectOption\n\t\t\t\t\t\tclassName=\"dark:pressed:bg-[#313135] bg-[#f3f3f4] dark:bg-[#28282d] dark:hover:bg-[#313135]\"\n\t\t\t\t\t\thref={`/docs/packages/${params.packageName}/${item.version}${hasEntryPoints ? ['', ...DEFAULT_ENTRY_POINT].join('/') : ''}`}\n\t\t\t\t\t\tid={item.version}\n\t\t\t\t\t\tkey={item.version}\n\t\t\t\t\t\tonHoverStart={() => router.prefetch(`/docs/packages/${params.packageName}/${item.version}`)}\n\t\t\t\t\t\ttextValue={item.version}\n\t\t\t\t\t>\n\t\t\t\t\t\t{item.version}\n\t\t\t\t\t</SelectOption>\n\t\t\t\t)}\n\t\t\t</SelectList>\n\t\t</Select>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/ui/Alert.tsx",
    "content": "import { VscFlame } from '@react-icons/all-files/vsc/VscFlame';\nimport { VscInfo } from '@react-icons/all-files/vsc/VscInfo';\nimport { VscWarning } from '@react-icons/all-files/vsc/VscWarning';\nimport type { PropsWithChildren } from 'react';\n\ninterface IAlert {\n\treadonly title?: string | undefined;\n\treadonly type: 'danger' | 'info' | 'success' | 'warning';\n}\n\nfunction resolveType(type: IAlert['type']) {\n\tswitch (type) {\n\t\tcase 'danger': {\n\t\t\treturn {\n\t\t\t\ttext: 'text-red-500',\n\t\t\t\tborder: 'border-red-500',\n\t\t\t\ticon: <VscWarning aria-hidden size={20} />,\n\t\t\t};\n\t\t}\n\n\t\tcase 'info': {\n\t\t\treturn {\n\t\t\t\ttext: 'text-blue-500',\n\t\t\t\tborder: 'border-blue-500',\n\t\t\t\ticon: <VscInfo aria-hidden size={20} />,\n\t\t\t};\n\t\t}\n\n\t\tcase 'success': {\n\t\t\treturn {\n\t\t\t\ttext: 'text-green-500',\n\t\t\t\tborder: 'border-green-500',\n\t\t\t\ticon: <VscFlame aria-hidden size={20} />,\n\t\t\t};\n\t\t}\n\n\t\tcase 'warning': {\n\t\t\treturn {\n\t\t\t\ttext: 'text-yellow-500',\n\t\t\t\tborder: 'border-yellow-500',\n\t\t\t\ticon: <VscWarning aria-hidden size={20} />,\n\t\t\t};\n\t\t}\n\t}\n}\n\nexport async function Alert({ title, type, children }: PropsWithChildren<IAlert>) {\n\tconst { text, border, icon } = resolveType(type);\n\n\treturn (\n\t\t<div className=\"mt-6 mb-4\" role=\"alert\">\n\t\t\t<div className=\"relative flex\">\n\t\t\t\t<div className=\"p-4\">{children}</div>\n\t\t\t\t<div className=\"pointer-events-none absolute flex h-full w-full\">\n\t\t\t\t\t<div className={`w-4 shrink-0 rounded-tl-md rounded-bl-md border-t-2 border-b-2 border-l-2 ${border}`} />\n\t\t\t\t\t<div className={`relative border-b-2 ${border}`}>\n\t\t\t\t\t\t<div className={`pointer-events-auto flex -translate-y-1/2 place-items-center gap-2 px-2 ${text}`}>\n\t\t\t\t\t\t\t{icon}\n\t\t\t\t\t\t\t{title ? <span className={`font-semibold ${text}`}>{title}</span> : null}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className={`flex-1 rounded-tr-md rounded-br-md border-t-2 border-r-2 border-b-2 ${border}`} />\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/ui/Button.tsx",
    "content": "'use client';\n\nimport type { VariantProps } from 'cva';\nimport { Button as RACButton, composeRenderProps } from 'react-aria-components';\nimport type { ButtonProps as RACButtonProps } from 'react-aria-components';\nimport { buttonStyles } from '@/styles/ui/button';\n\nexport type ButtonProps = RACButtonProps & VariantProps<typeof buttonStyles>;\n\nexport function Button(props: ButtonProps) {\n\treturn (\n\t\t<RACButton\n\t\t\t{...props}\n\t\t\tclassName={composeRenderProps(props.className, (className, renderProps) =>\n\t\t\t\tbuttonStyles({\n\t\t\t\t\t...renderProps,\n\t\t\t\t\tvariant: props.variant,\n\t\t\t\t\tsize: props.size,\n\t\t\t\t\tisDestructive: props.isDestructive,\n\t\t\t\t\tisDark: props.isDark,\n\t\t\t\t\tclassName,\n\t\t\t\t}),\n\t\t\t)}\n\t\t>\n\t\t\t{(values) => <>{typeof props.children === 'function' ? props.children(values) : props.children}</>}\n\t\t</RACButton>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/ui/Collapsible.tsx",
    "content": "'use client';\n\nexport { Collapsible, CollapsibleTrigger, CollapsibleContent } from '@radix-ui/react-collapsible';\n"
  },
  {
    "path": "apps/website/src/components/ui/Dialog.tsx",
    "content": "'use client';\n\nimport { XIcon } from 'lucide-react';\nimport { useEffect, useRef, type ComponentProps, type ComponentPropsWithoutRef, type Ref } from 'react';\nimport type { HeadingProps as RACHeadingProps } from 'react-aria-components';\nimport { Dialog as RACDialog, Heading as RACHeading, Text as RACText } from 'react-aria-components';\nimport { useMediaQuery } from 'usehooks-ts';\nimport { Button, type ButtonProps } from '@/components/ui/Button';\nimport { cx } from '@/styles/cva';\n\nexport function Dialog(props: ComponentProps<typeof RACDialog>) {\n\treturn (\n\t\t<RACDialog\n\t\t\t{...props}\n\t\t\tclassName={cx(\n\t\t\t\t'peer/dialog group/dialog relative flex max-h-[inherit] flex-col overflow-hidden outline-hidden [scrollbar-width:thin]',\n\t\t\t\tprops.className,\n\t\t\t)}\n\t\t\trole={props.role!}\n\t\t/>\n\t);\n}\n\nexport type DialogHeaderProps = ComponentPropsWithoutRef<'div'> & {\n\treadonly description?: string;\n\treadonly hasBorder?: boolean;\n\treadonly title?: string;\n};\n\nexport function DialogHeader({ hasBorder = false, ...props }: DialogHeaderProps) {\n\tconst headerRef = useRef<HTMLHeadingElement>(null);\n\n\tuseEffect(() => {\n\t\tconst header = headerRef.current;\n\t\tif (!header) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst observer = new ResizeObserver((entries) => {\n\t\t\tfor (const entry of entries) {\n\t\t\t\theader.parentElement?.style.setProperty('--dialog-header-height', `${entry.target.clientHeight}px`);\n\t\t\t}\n\t\t});\n\n\t\tobserver.observe(header);\n\t\treturn () => observer.unobserve(header);\n\t}, []);\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cx(\n\t\t\t\t'relative flex flex-col gap-1 p-6 pb-4 [&[data-slot=dialog-header]:has(+[data-slot=dialog-footer])]:pb-0',\n\t\t\t\thasBorder &&\n\t\t\t\t\t'border-base-neutral-100 dark:border-base-neutral-700 border-b [&[data-slot=dialog-header]:has(+[data-slot=dialog-footer])]:border-b',\n\t\t\t\tprops.className,\n\t\t\t)}\n\t\t\tdata-slot=\"dialog-header\"\n\t\t\tref={headerRef}\n\t\t>\n\t\t\t{props.title && <DialogTitle>{props.title}</DialogTitle>}\n\t\t\t{props.description && <DialogDescription>{props.description}</DialogDescription>}\n\t\t\t{!props.title && typeof props.children === 'string' ? <DialogTitle {...props} /> : props.children}\n\t\t</div>\n\t);\n}\n\nexport type DialogTitleProps = RACHeadingProps & {\n\treadonly ref?: Ref<HTMLHeadingElement>;\n};\n\nexport function DialogTitle({ level = 2, ...props }: DialogTitleProps) {\n\treturn (\n\t\t<RACHeading\n\t\t\t{...props}\n\t\t\tclassName={cx('text-base-label-md flex flex-1 place-items-center', props.className)}\n\t\t\tlevel={level}\n\t\t\tslot=\"title\"\n\t\t/>\n\t);\n}\n\nexport type DialogDescriptionProps = ComponentProps<'div'>;\n\nexport function DialogDescription(props: DialogDescriptionProps) {\n\treturn <RACText {...props} className={cx('text-sm', props.className)} slot=\"description\" />;\n}\n\nexport type DialogBodyProps = ComponentProps<'div'>;\n\nexport function DialogBody(props: DialogBodyProps) {\n\treturn (\n\t\t<div\n\t\t\t{...props}\n\t\t\tclassName={cx(\n\t\t\t\t'isolate flex max-h-[calc(var(--visual-viewport-height)-var(--visual-viewport-vertical-padding)-var(--dialog-header-height,0px)-var(--dialog-footer-height,0px))] flex-1 flex-col gap-6 overflow-auto px-6 py-1',\n\t\t\t\tprops.className,\n\t\t\t)}\n\t\t\tdata-slot=\"dialog-body\"\n\t\t/>\n\t);\n}\n\nexport type DialogFooterProps = ComponentProps<'div'> & {\n\treadonly hasBorder?: boolean;\n};\n\nexport function DialogFooter({ hasBorder = false, ...props }: DialogFooterProps) {\n\tconst footerRef = useRef<HTMLDivElement>(null);\n\n\tuseEffect(() => {\n\t\tconst footer = footerRef.current;\n\n\t\tif (!footer) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst observer = new ResizeObserver((entries) => {\n\t\t\tfor (const entry of entries) {\n\t\t\t\tfooter.parentElement?.style.setProperty('--dialog-footer-height', `${entry.target.clientHeight}px`);\n\t\t\t}\n\t\t});\n\n\t\tobserver.observe(footer);\n\t\treturn () => {\n\t\t\tobserver.unobserve(footer);\n\t\t};\n\t}, []);\n\n\treturn (\n\t\t<div\n\t\t\t{...props}\n\t\t\tclassName={cx(\n\t\t\t\t'isolate mt-auto flex flex-col-reverse place-content-between gap-3 p-6 sm:flex-row sm:place-content-end sm:place-items-center',\n\t\t\t\thasBorder && 'border-base-neutral-100 dark:border-base-neutral-700 border-t',\n\t\t\t\tprops.className,\n\t\t\t)}\n\t\t\tdata-slot=\"dialog-footer\"\n\t\t\tref={footerRef}\n\t\t/>\n\t);\n}\n\nexport type DialogCloseProps = ButtonProps;\n\nexport function DialogClose(props: DialogCloseProps) {\n\treturn <Button {...props} slot=\"close\" />;\n}\n\nexport type CloseButtonIndicatorProps = Omit<ButtonProps, 'children'> & {\n\treadonly className?: string;\n\treadonly isDismissable?: boolean | undefined;\n};\n\nexport function DialogCloseIndicator(props: CloseButtonIndicatorProps) {\n\tconst isMobile = useMediaQuery('(max-width: 600px)', { initializeWithValue: false });\n\n\treturn props.isDismissable ? (\n\t\t<Button\n\t\t\t{...props}\n\t\t\t{...(isMobile ? { autoFocus: true } : {})}\n\t\t\taria-label=\"Close\"\n\t\t\tclassName={cx(\n\t\t\t\t'close text-base-neutral-500 hover:text-base-neutral-700 focus-visible:text-base-neutral-700 pressed:text-base-neutral-900 dark:text-base-neutral-400 dark:hover:text-base-neutral-200 dark:focus-visible:text-base-neutral-200 dark:pressed:text-base-neutral-500 disabled:text-base-neutral-300 dark:disabled:text-base-neutral-300 absolute top-3 right-4 z-50 rounded-full',\n\t\t\t\tprops.className,\n\t\t\t)}\n\t\t\tsize=\"icon-xs\"\n\t\t\tslot=\"close\"\n\t\t\tvariant=\"unset\"\n\t\t>\n\t\t\t<XIcon aria-hidden className=\"size-4.5 stroke-[1.5]\" />\n\t\t</Button>\n\t) : null;\n}\n\nexport { Button as DialogTrigger } from '@/components/ui/Button';\n"
  },
  {
    "path": "apps/website/src/components/ui/Dropdown.tsx",
    "content": "'use client';\n\nimport { CheckIcon } from 'lucide-react';\nimport type { ComponentProps } from 'react';\nimport {\n\tCollection as RACCollection,\n\tcomposeRenderProps,\n\tHeader as RACHeader,\n\tListBoxItem as RACListBoxItem,\n\tListBoxSection as RACListBoxSection,\n\tSeparator as RACSeparator,\n\tText as RACText,\n} from 'react-aria-components';\nimport type {\n\tSectionProps as RACDropdownSectionProps,\n\tListBoxItemProps as RACListBoxItemProps,\n\tTextProps as RACTextProps,\n\tSeparatorProps as RACSeparatorProps,\n} from 'react-aria-components';\nimport { Keyboard } from '@/components/ui/Keyboard';\nimport { cva, cx } from '@/styles/cva';\n\nexport type DropdownSectionProps<Type extends object> = RACDropdownSectionProps<Type> & {\n\treadonly title?: string;\n};\n\nexport function DropdownSection<Type extends object>(props: DropdownSectionProps<Type>) {\n\treturn (\n\t\t<RACListBoxSection\n\t\t\t{...props}\n\t\t\tclassName={cx(\n\t\t\t\t'col-span-full grid grid-cols-[auto_1fr] supports-[grid-template-columns:subgrid]:grid-cols-subgrid',\n\t\t\t\tprops.className,\n\t\t\t)}\n\t\t>\n\t\t\t{props.title && (\n\t\t\t\t<RACHeader className=\"text-base-label-sm text-base-neutral-600 dark:text-base-neutral-300 col-span-full px-3 py-2\">\n\t\t\t\t\t{props.title}\n\t\t\t\t</RACHeader>\n\t\t\t)}\n\t\t\t<RACCollection items={props.items!}>{props.children}</RACCollection>\n\t\t</RACListBoxSection>\n\t);\n}\n\nexport function DropdownLabel(props: RACTextProps) {\n\treturn <RACText {...props} className={cx('col-start-1', props.className)} slot=\"label\" />;\n}\n\nexport const dropdownItemStyles = cva({\n\tbase: [\n\t\t'col-span-full grid grid-cols-[auto_1fr_1.5rem_0.5rem_auto] not-has-data-[slot=dropdown-item-details]:items-center has-data-[slot=dropdown-item-details]:**:data-[slot=checked-icon]:mt-[1.5px] supports-[grid-template-columns:subgrid]:grid-cols-subgrid',\n\t\t'group forced-color:text-[Highlight] text-base-md relative h-10 cursor-default rounded-sm px-3 py-2.5 outline-0 forced-color-adjust-none select-none has-data-[slot=dropdown-item-details]:h-[inherit] has-data-[slot=dropdown-item-details]:place-content-center forced-colors:text-[LinkText]',\n\t\t'text-base-neutral-900 dark:text-base-neutral-40 bg-base-neutral-0 dark:bg-base-neutral-800',\n\t\t'hover:bg-base-neutral-80 dark:hover:bg-base-neutral-700/72',\n\t\t'focus-visible:bg-base-neutral-80 dark:focus-visible:bg-base-neutral-700/72',\n\t\t'pressed:bg-base-neutral-100 dark:pressed:bg-base-neutral-700/72',\n\t\t'**:data-[slot=avatar]:mr-2 **:data-[slot=avatar]:size-6 **:data-[slot=avatar]:*:mr-2 **:data-[slot=avatar]:*:size-6 sm:**:data-[slot=avatar]:size-5 sm:**:data-[slot=avatar]:*:size-5',\n\t\t'**:data-[slot=icon]:size-4.5 **:data-[slot=icon]:shrink-0',\n\t\t'data-destructive:text-base-sunset-600 dark:data-destructive:text-base-sunset-400 data-destructive:hover:bg-base-sunset-100 dark:data-destructive:hover:bg-base-sunset-800 data-destructive:hover:text-base-sunset-700 dark:data-destructive:hover:text-base-sunset-300 data-destructive:focus-visible:bg-base-sunset-100 dark:data-destructive:focus-visible:bg-base-sunset-800 data-destructive:focus-visible:hover:text-base-sunset-700 dark:data-destructive:focus-visible:text-base-sunset-300 data-destructive:pressed:bg-base-sunset-200 dark:data-destructive:pressed:bg-base-sunset-700 data-destructive:pressed:text-base-sunset-800 dark:data-destructive:pressed:text-base-sunset-100',\n\t\t'*:data-[slot=icon]:mr-2 data-[slot=menu-radio]:*:data-[slot=icon]:size-4.5',\n\t\t'forced-colors:**:data-[slot=icon]:text-[CanvasText] forced-colors:group-data-focused:**:data-[slot=icon]:text-[Canvas]',\n\t\t'[&>[slot=label]+[data-slot=icon]]:absolute [&>[slot=label]+[data-slot=icon]]:right-0',\n\t],\n\tvariants: {\n\t\tisFocused: {\n\t\t\ttrue: 'forced-colors:bg-[Highlight] forced-colors:text-[HighlightText]',\n\t\t\tfalse: '',\n\t\t},\n\t\tisDisabled: {\n\t\t\ttrue: 'opacity-50 forced-colors:text-[GrayText]',\n\t\t},\n\t},\n});\n\nexport type DropdownItemProps = RACListBoxItemProps & {\n\treadonly classNames?: {\n\t\treadonly selected?: string;\n\t};\n};\n\nexport function DropdownItem(props: DropdownItemProps) {\n\tconst textValue = props.textValue ?? (typeof props.children === 'string' ? props.children : undefined);\n\n\treturn (\n\t\t<RACListBoxItem\n\t\t\t{...props}\n\t\t\tclassName={composeRenderProps(props.className, (className, renderProps) =>\n\t\t\t\tdropdownItemStyles({\n\t\t\t\t\t...renderProps,\n\t\t\t\t\tclassName,\n\t\t\t\t}),\n\t\t\t)}\n\t\t\ttextValue={textValue!}\n\t\t>\n\t\t\t{composeRenderProps(props.children, (children, { isSelected }) => (\n\t\t\t\t<>\n\t\t\t\t\t{typeof children === 'string' ? <DropdownLabel>{children}</DropdownLabel> : children}\n\t\t\t\t\t{isSelected && (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName={cx(\n\t\t\t\t\t\t\t\t'bg-base-blurple-400 dark:bg-base-blurple-400 flex size-[18px] place-content-center place-items-center place-self-start rounded-full',\n\t\t\t\t\t\t\t\tprops.classNames?.selected,\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\tdata-slot=\"checked-icon\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<CheckIcon aria-hidden className=\"text-base-neutral-40 size-3.5\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</>\n\t\t\t))}\n\t\t</RACListBoxItem>\n\t);\n}\n\nexport type DropdownItemDetailProps = RACTextProps & {\n\treadonly classNames?: {\n\t\treadonly description?: RACTextProps['className'];\n\t\treadonly label?: RACTextProps['className'];\n\t};\n\treadonly description?: RACTextProps['children'];\n\treadonly label?: RACTextProps['children'];\n};\n\nexport function DropdownItemDetails(props: DropdownItemDetailProps) {\n\treturn (\n\t\t<div {...props} className=\"col-start-1 flex flex-col gap-1\" data-slot=\"dropdown-item-details\">\n\t\t\t{props.label && (\n\t\t\t\t<RACText\n\t\t\t\t\t{...props}\n\t\t\t\t\tclassName={cx('text-base-md max-w-[25ch] truncate', props.classNames?.label)}\n\t\t\t\t\tslot={props.slot ?? 'label'}\n\t\t\t\t>\n\t\t\t\t\t{props.label}\n\t\t\t\t</RACText>\n\t\t\t)}\n\t\t\t{props.description && (\n\t\t\t\t<RACText\n\t\t\t\t\t{...props}\n\t\t\t\t\tclassName={cx('text-base-sm text-base-neutral-600 dark:text-base-neutral-300', props.classNames?.description)}\n\t\t\t\t\tslot={props.slot ?? 'description'}\n\t\t\t\t>\n\t\t\t\t\t{props.description}\n\t\t\t\t</RACText>\n\t\t\t)}\n\t\t\t{!props.title && props.children}\n\t\t</div>\n\t);\n}\n\nexport function DropdownSeparator(props: RACSeparatorProps) {\n\treturn (\n\t\t<RACSeparator\n\t\t\t{...props}\n\t\t\tclassName={cx(\n\t\t\t\t'bg-base-neutral-100 dark:bg-base-neutral-700 col-span-full mx-3 my-2 h-px forced-colors:bg-[ButtonBorder]',\n\t\t\t\tprops.className,\n\t\t\t)}\n\t\t\torientation=\"horizontal\"\n\t\t/>\n\t);\n}\n\nexport function DropdownKeyboard(props: ComponentProps<typeof Keyboard>) {\n\treturn <Keyboard {...props} className={cx('absolute right-2 pl-2', props.className)} />;\n}\n"
  },
  {
    "path": "apps/website/src/components/ui/Field.tsx",
    "content": "'use client';\n\nimport { AlertCircleIcon } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport type {\n\tLabelProps as RACLabelProps,\n\tTextProps as RACTextProps,\n\tFieldErrorProps as RACFieldErrorProps,\n\tGroupProps as RACGroupProps,\n\tInputProps as RACInputProps,\n} from 'react-aria-components';\nimport {\n\tLabel as RACLabel,\n\tText as RACText,\n\tFieldError as RACFieldError,\n\tGroup as RACGroup,\n\tInput as RACInput,\n\tcomposeRenderProps,\n} from 'react-aria-components';\nimport { compose, cva, cx } from '@/styles/cva';\nimport { focusRing } from '@/styles/ui/focusRing';\nimport { composeTailwindRenderProps } from '@/styles/util';\n\nexport function Label(props: RACLabelProps) {\n\treturn (\n\t\t<RACLabel\n\t\t\t{...props}\n\t\t\tclassName={cx(\n\t\t\t\t'text-base-neutral-800 dark:text-base-neutral-100 group-invalid:text-base-sunset-500 group-disabled:text-base-neutral-900 dark:group-disabled:text-base-neutral-40 text-base-label-md w-fit group-disabled:opacity-38',\n\t\t\t\tprops.className,\n\t\t\t)}\n\t\t/>\n\t);\n}\n\nexport function Description(props: RACTextProps) {\n\treturn (\n\t\t<RACText\n\t\t\t{...props}\n\t\t\tclassName={cx('text-base-neutral-600 dark:text-base-neutral-300 text-base-sm text-pretty', props.className)}\n\t\t\tslot=\"description\"\n\t\t/>\n\t);\n}\n\nexport function FieldError(props: RACFieldErrorProps) {\n\treturn (\n\t\t<RACFieldError\n\t\t\t{...props}\n\t\t\tclassName={composeTailwindRenderProps(\n\t\t\t\tprops.className,\n\t\t\t\t'text-base-sunset-500 text-base-sm flex place-items-center gap-1.5 forced-colors:text-[Mark]',\n\t\t\t)}\n\t\t>\n\t\t\t<AlertCircleIcon aria-hidden className=\"shrink-0\" data-slot=\"icon\" size={18} strokeWidth={1.5} />\n\t\t\t{props.children as ReactNode}\n\t\t</RACFieldError>\n\t);\n}\n\nexport const fieldGroupStyles = compose(\n\tfocusRing,\n\tcva({\n\t\tbase: [\n\t\t\t'group relative flex h-10 place-items-center overflow-hidden rounded-sm border transition duration-200 ease-out forced-colors:outline-[Highlight]',\n\t\t\t'bg-base-neutral-0 border-base-neutral-300 dark:bg-base-neutral-800 dark:border-base-neutral-500',\n\t\t\t'hover:border-base-neutral-200 dark:hover:border-base-neutral-600',\n\t\t\t'focus-within:border-base-neutral-200 dark:focus-within:border-base-neutral-600',\n\t\t\t'disabled:opacity-38 forced-colors:disabled:border forced-colors:disabled:border-[GrayText]',\n\t\t\t'group-invalid:border-base-sunset-500 forced-colors:group-invalid:border-[Mark]',\n\t\t\t'group-invalid:hover:border-base-sunset-200 dark:group-invalid:hover:border-base-sunset-700',\n\t\t\t'group-invalid:focus-within:border-base-sunset-200 dark:group-invalid:focus-within:border-base-sunset-700',\n\t\t\t'[&>[role=progressbar]:first-child]:ml-2 [&>[role=progressbar]:last-child]:mr-2',\n\t\t\t'**:data-[slot=icon]:size-6 **:data-[slot=icon]:shrink-0 **:[button]:shrink-0',\n\t\t\t'[&>button:has([data-slot=icon])]:absolute [&>button:has([data-slot=icon]):first-child]:left-0 [&>button:has([data-slot=icon]):last-child]:right-0',\n\t\t\t'*:data-[slot=icon]:text-base-neutral-800 dark:*:data-[slot=icon]:text-base-neutral-100 *:data-[slot=icon]:pointer-events-none *:data-[slot=icon]:absolute *:data-[slot=icon]:top-[calc(var(--spacing)_*_1.7)] *:data-[slot=icon]:z-10 *:data-[slot=icon]:size-6',\n\t\t\t'[&>[data-slot=icon]:first-child]:left-2 [&>[data-slot=icon]:last-child]:right-2',\n\t\t\t'[&:has([data-slot=icon]+input)]:pl-7.5 [&:has(input+[data-slot=icon])]:pr-7.5',\n\t\t\t'[&:has([data-slot=icon]+[role=group])]:pl-7.5 [&:has([role=group]+[data-slot=icon])]:pr-7.5',\n\t\t\t'has-[[data-slot=icon]:last-child]:[&_input]:pr-7.5',\n\t\t\t'*:[button]:size-6 *:[button]:p-0',\n\t\t\t'[&>button:first-child]:ml-2 [&>button:last-child]:mr-2',\n\t\t],\n\t\tvariants: {\n\t\t\tisFocusWithin: {\n\t\t\t\ttrue: 'outline-2',\n\t\t\t\tfalse: 'outline-0',\n\t\t\t},\n\t\t},\n\t}),\n);\n\nexport function FieldGroup(props: RACGroupProps) {\n\treturn (\n\t\t<RACGroup\n\t\t\t{...props}\n\t\t\tclassName={composeRenderProps(props.className, (className, renderProps) =>\n\t\t\t\tfieldGroupStyles({\n\t\t\t\t\t...renderProps,\n\t\t\t\t\tclassName,\n\t\t\t\t}),\n\t\t\t)}\n\t\t/>\n\t);\n}\n\nexport function Input(props: RACInputProps) {\n\treturn (\n\t\t<RACInput\n\t\t\t{...props}\n\t\t\tclassName={composeTailwindRenderProps(\n\t\t\t\tprops.className,\n\t\t\t\t'text-base-neutral-900 placeholder:text-base-neutral-400 dark:placeholder:text-base-neutral-500 dark:text-base-neutral-40 text-base-lg sm:text-base-md w-full min-w-0 bg-transparent px-3 py-2.5 outline-hidden focus:outline-hidden [&::-ms-reveal]:hidden [&::-webkit-search-cancel-button]:hidden',\n\t\t\t)}\n\t\t/>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/ui/Keyboard.tsx",
    "content": "'use client';\n\nimport type { ComponentProps } from 'react';\nimport { Keyboard as RACKeyboard } from 'react-aria-components';\nimport { cx } from '@/styles/cva';\n\ntype KeyboardProps = ComponentProps<'div'> & {\n\treadonly classNames?: {\n\t\treadonly base?: string;\n\t\treadonly kbd?: string;\n\t};\n\treadonly keys: string[] | string;\n};\n\nexport function Keyboard(props: KeyboardProps) {\n\treturn (\n\t\t<RACKeyboard\n\t\t\t{...props}\n\t\t\tclassName={cx(\n\t\t\t\t'hidden group-disabled:opacity-50 lg:inline-flex forced-colors:group-focus:text-[HighlightText]',\n\t\t\t\tprops.classNames?.base,\n\t\t\t)}\n\t\t>\n\t\t\t{(Array.isArray(props.keys) ? props.keys : props.keys.split('')).map((char, idx) => (\n\t\t\t\t<kbd\n\t\t\t\t\tclassName={cx(\n\t\t\t\t\t\t'inline-grid min-h-5 min-w-[2ch] place-content-center text-center font-sans text-[.75rem] uppercase',\n\t\t\t\t\t\tidx > 0 && char.length > 1 && 'pl-1',\n\t\t\t\t\t\tprops.classNames?.kbd,\n\t\t\t\t\t)}\n\t\t\t\t\tkey={idx}\n\t\t\t\t>\n\t\t\t\t\t{char}\n\t\t\t\t</kbd>\n\t\t\t))}\n\t\t</RACKeyboard>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/ui/ListBox.tsx",
    "content": "'use client';\n\nimport { CheckIcon, MenuIcon } from 'lucide-react';\nimport type { ComponentProps } from 'react';\nimport type { ListBoxItemProps as RACListBoxItemProps, ListBoxProps as RACListBoxProps } from 'react-aria-components';\nimport { ListBoxItem as RACListBoxItem, ListBox as RACListBox, composeRenderProps } from 'react-aria-components';\nimport { DropdownLabel, DropdownSection, dropdownItemStyles } from '@/components/ui/Dropdown';\nimport { cx } from '@/styles/cva';\n\nexport function ListBox<Type extends object>(props: RACListBoxProps<Type>) {\n\treturn (\n\t\t<RACListBox\n\t\t\t{...props}\n\t\t\tclassName={composeRenderProps(props.className, (className) =>\n\t\t\t\tcx(\n\t\t\t\t\t[\n\t\t\t\t\t\t'border-base-neutral-200 dark:border-base-neutral-600 shadow-base-sm flex max-h-96 w-full min-w-40 flex-col gap-x-1 overflow-y-auto rounded-sm border p-2 outline-hidden [scrollbar-width:thin]',\n\t\t\t\t\t\t\"grid grid-cols-[1fr_auto] overflow-auto *:[[role='group']+[role=group]]:mt-4 *:[[role='group']+[role=separator]]:mt-1\",\n\t\t\t\t\t],\n\t\t\t\t\tclassName,\n\t\t\t\t),\n\t\t\t)}\n\t\t/>\n\t);\n}\n\nexport type ListBoxItemProps<Type extends object> = RACListBoxItemProps<Type> & {\n\treadonly className?: string;\n};\n\nexport function ListBoxItem<Type extends object>(props: ListBoxItemProps<Type>) {\n\tconst textValue = props.textValue ?? (typeof props.children === 'string' ? props.children : undefined);\n\n\treturn (\n\t\t<RACListBoxItem\n\t\t\t{...props}\n\t\t\tclassName={composeRenderProps(props.className, (className, renderProps) =>\n\t\t\t\tdropdownItemStyles({\n\t\t\t\t\t...renderProps,\n\t\t\t\t\tclassName,\n\t\t\t\t}),\n\t\t\t)}\n\t\t\ttextValue={textValue!}\n\t\t>\n\t\t\t{({ allowsDragging, isSelected, isFocused, isDragging }) => (\n\t\t\t\t<>\n\t\t\t\t\t{allowsDragging && (\n\t\t\t\t\t\t<MenuIcon\n\t\t\t\t\t\t\tclassName={cx('size-4 shrink-0 transition', isFocused && '', isDragging && '', isSelected && '')}\n\t\t\t\t\t\t\tsize={16}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t\t{isSelected && <CheckIcon className=\"-mx-0.5 mr-2\" data-slot=\"checked-icon\" size={16} />}\n\t\t\t\t\t{typeof props.children === 'string' ? <DropdownLabel>{props.children}</DropdownLabel> : props.children}\n\t\t\t\t</>\n\t\t\t)}\n\t\t</RACListBoxItem>\n\t);\n}\n\nexport type ListBoxSectionProps = ComponentProps<typeof DropdownSection>;\n\nexport function ListBoxSection(props: ListBoxSectionProps) {\n\treturn <DropdownSection {...props} className={cx(props.className, 'gap-1')} />;\n}\n\nexport { DropdownItemDetails as ListBoxItemDetails } from '@/components/ui/Dropdown';\n"
  },
  {
    "path": "apps/website/src/components/ui/Popover.tsx",
    "content": "'use client';\n\nimport type { CSSProperties, ReactNode } from 'react';\nimport type {\n\tDialogProps as RACDialogProps,\n\tPopoverProps as RACPopoverProps,\n\tModalOverlayProps as RACModalOverlayProps,\n\tDialogTriggerProps as RACDialogTriggerProps,\n} from 'react-aria-components';\nimport {\n\tModal as RACModal,\n\tModalOverlay as RACModalOverlay,\n\tOverlayArrow as RACOverlayArrow,\n\tPopoverContext as RACPopoverContext,\n\tDialogTrigger as RACDialogTrigger,\n\tPopover as RACPopover,\n\tcomposeRenderProps,\n\tuseSlottedContext,\n} from 'react-aria-components';\nimport { useMediaQuery } from 'usehooks-ts';\nimport type { DialogBodyProps, DialogFooterProps, DialogHeaderProps, DialogTitleProps } from '@/components/ui/Dialog';\nimport { Dialog, DialogBody, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/Dialog';\nimport { cva, cx } from '@/styles/cva';\n\nexport function Popover(props: RACDialogTriggerProps) {\n\treturn <RACDialogTrigger {...props} />;\n}\n\nexport function PopoverTitle({ level = 2, ...props }: DialogTitleProps) {\n\treturn <DialogTitle {...props} className={cx('sm:leading-none', level === 2 && 'sm:text-lg', props.className)} />;\n}\n\nexport function PopoverHeader(props: DialogHeaderProps) {\n\treturn <DialogHeader {...props} className={cx('sm:p-4', props.className)} />;\n}\n\nexport function PopoverBody(props: DialogBodyProps) {\n\treturn <DialogBody {...props} className={cx('gap-0 sm:px-4 sm:pt-0', props.className)} />;\n}\n\nexport function PopoverFooter(props: DialogFooterProps) {\n\treturn <DialogFooter {...props} className={cx('sm:p-4', props.className)} />;\n}\n\nconst contentStyles = cva({\n\tbase: 'peer/popover-content border-base-neutral-200 dark:border-base-neutral-600 shadow-base-sm bg-base-neutral-0 dark:bg-base-neutral-800 text-base-md max-w-xs rounded-sm border bg-clip-padding transition-transform [scrollbar-width:thin] sm:max-w-3xl dark:backdrop-saturate-200 forced-colors:bg-[Canvas]',\n\tvariants: {\n\t\tisPicker: {\n\t\t\ttrue: 'max-h-72 min-w-(--trigger-width) overflow-y-auto',\n\t\t\tfalse: 'min-w-80',\n\t\t},\n\t\tisMenu: {\n\t\t\ttrue: '',\n\t\t},\n\t\tisEntering: {\n\t\t\ttrue: 'fade-in animate-in data-[placement=left]:slide-in-from-right-1 data-[placement=right]:slide-in-from-left-1 data-[placement=top]:slide-in-from-bottom-1 data-[placement=bottom]:slide-in-from-top-1 duration-150 ease-out',\n\t\t},\n\t\tisExiting: {\n\t\t\ttrue: 'fade-out animate-out data-[placement=left]:slide-out-to-right-1 data-[placement=right]:slide-out-to-left-1 data-[placement=top]:slide-out-to-bottom-1 data-[placement=bottom]:slide-out-to-top-1 duration-100 ease-in',\n\t\t},\n\t},\n});\n\nconst drawerStyles = cva({\n\tbase: 'fixed top-auto bottom-0 z-50 max-h-full w-full max-w-2xl border border-b-transparent bg-neutral-100 outline-hidden dark:bg-neutral-900',\n\tvariants: {\n\t\tisMenu: {\n\t\t\ttrue: 'p-0 [&_[role=dialog]]:*:not-has-[[data-slot=dialog-body]]:px-1',\n\t\t\tfalse: '',\n\t\t},\n\t\tisEntering: {\n\t\t\ttrue: [\n\t\t\t\t'[will-change:transform] [transition:transform_0.5s_cubic-bezier(0.32,_0.72,_0,_1)]',\n\t\t\t\t'fade-in-0 slide-in-from-bottom-56 animate-in duration-200',\n\t\t\t\t'[transition:translate3d(0,_100%,_0)]',\n\t\t\t\t'sm:slide-in-from-bottom-auto sm:slide-in-from-top-[20%]',\n\t\t\t],\n\t\t},\n\t\tisExiting: {\n\t\t\ttrue: 'slide-out-to-bottom-56 animate-out duration-200 ease-in',\n\t\t},\n\t},\n});\n\nexport type PopoverContentProps = Omit<RACModalOverlayProps, 'className'> &\n\tOmit<RACPopoverProps, 'children' | 'className'> &\n\tPick<RACDialogProps, 'aria-label' | 'aria-labelledby'> & {\n\t\treadonly children: ReactNode;\n\t\treadonly className?: string | ((values: { defaultClassName?: string }) => string);\n\t\treadonly respectScreen?: boolean;\n\t\treadonly showArrow?: boolean;\n\t\treadonly style?: CSSProperties;\n\t};\n\nexport function PopoverContent({ respectScreen = true, showArrow = true, ...props }: PopoverContentProps) {\n\tconst isMobile = useMediaQuery('(max-width: 600px)', { initializeWithValue: false });\n\tconst popoverContext = useSlottedContext(RACPopoverContext);\n\tconst isMenuTrigger = popoverContext?.trigger === 'MenuTrigger';\n\tconst isSubmenuTrigger = popoverContext?.trigger === 'SubmenuTrigger';\n\tconst isMenu = isMenuTrigger || isSubmenuTrigger;\n\tconst isComboBoxTrigger = popoverContext?.trigger === 'ComboBox';\n\tconst offset = props.offset ?? (showArrow ? 6 : 4);\n\tconst effectiveOffset = isSubmenuTrigger ? offset - 2 : offset;\n\n\treturn isMobile && respectScreen ? (\n\t\t<RACModalOverlay\n\t\t\t{...props}\n\t\t\tclassName=\"fixed top-0 left-0 isolate z-50 h-(--visual-viewport-height) w-full [--visual-viewport-vertical-padding:16px]\"\n\t\t\tisDismissable\n\t\t>\n\t\t\t<RACModal\n\t\t\t\tclassName={composeRenderProps(props.className as string, (className, renderProps) =>\n\t\t\t\t\tdrawerStyles({ ...renderProps, isMenu, className }),\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<Dialog aria-label={props['aria-label'] ?? 'List item'} role=\"dialog\">\n\t\t\t\t\t{props.children}\n\t\t\t\t</Dialog>\n\t\t\t</RACModal>\n\t\t</RACModalOverlay>\n\t) : (\n\t\t<RACPopover\n\t\t\t{...props}\n\t\t\tclassName={composeRenderProps(props.className as string, (className, renderProps) =>\n\t\t\t\tcontentStyles({\n\t\t\t\t\t...renderProps,\n\t\t\t\t\tclassName,\n\t\t\t\t}),\n\t\t\t)}\n\t\t\toffset={effectiveOffset}\n\t\t>\n\t\t\t{showArrow && (\n\t\t\t\t<RACOverlayArrow className=\"group\">\n\t\t\t\t\t<svg\n\t\t\t\t\t\tclassName=\"fill-base-neutral-0 dark:fill-base-neutral-800 stroke-base-neutral-200 dark:stroke-base-neutral-600 block group-data-[placement=bottom]:rotate-180 group-data-[placement=left]:-rotate-90 group-data-[placement=right]:rotate-90 forced-colors:fill-[Canvas] forced-colors:stroke-[ButtonBorder]\"\n\t\t\t\t\t\theight={12}\n\t\t\t\t\t\tviewBox=\"0 0 12 12\"\n\t\t\t\t\t\twidth={12}\n\t\t\t\t\t>\n\t\t\t\t\t\t<path d=\"M0 0 L6 6 L12 0\" />\n\t\t\t\t\t</svg>\n\t\t\t\t</RACOverlayArrow>\n\t\t\t)}\n\t\t\t{isComboBoxTrigger ? (\n\t\t\t\tprops.children\n\t\t\t) : (\n\t\t\t\t<Dialog aria-label={props['aria-label'] ?? 'List item'} role=\"dialog\">\n\t\t\t\t\t{props.children}\n\t\t\t\t</Dialog>\n\t\t\t)}\n\t\t</RACPopover>\n\t);\n}\n\nexport {\n\tDialogTrigger as PopoverTrigger,\n\tDialogDescription as PopoverDescription,\n\tDialogClose as PopoverClose,\n} from '@/components/ui/Dialog';\n"
  },
  {
    "path": "apps/website/src/components/ui/Select.tsx",
    "content": "'use client';\n\nimport { ChevronDownIcon } from 'lucide-react';\nimport type { ComponentProps, ReactNode } from 'react';\nimport type {\n\tListBoxProps as RACListBoxProps,\n\tSelectProps as RACSelectProps,\n\tValidationResult as RACValidationResult,\n} from 'react-aria-components';\nimport {\n\tButton as RACButton,\n\tSelect as RACSelect,\n\tSelectValue as RACSelectValue,\n\tcomposeRenderProps,\n} from 'react-aria-components';\nimport type { Button } from '@/components/ui/Button';\nimport { Description, FieldError, Label } from '@/components/ui/Field';\nimport { ListBox } from '@/components/ui/ListBox';\nimport { PopoverContent, type PopoverContentProps } from '@/components/ui/Popover';\nimport { compose, cva, cx } from '@/styles/cva';\nimport { focusRing } from '@/styles/ui/focusRing';\nimport { composeTailwindRenderProps } from '@/styles/util';\n\nconst selectTriggerStyles = compose(\n\tfocusRing,\n\tcva({\n\t\tbase: [\n\t\t\t'relative flex h-10 w-full place-items-center overflow-hidden rounded-sm border transition duration-200 ease-out forced-colors:outline-[Highlight]',\n\t\t\t'bg-base-neutral-0 border-base-neutral-300 dark:bg-base-neutral-800 dark:border-base-neutral-500',\n\t\t\t'hover:border-base-neutral-200 dark:hover:border-base-neutral-600',\n\t\t\t'focus-visible:border-base-neutral-200 dark:focus-visible:border-base-neutral-600',\n\t\t\t'group-open:border-base-neutral-200 dark:group-open:border-base-neutral-600 group-open:outline-2',\n\t\t\t'group-disabled:bg-base-neutral-100 group-disabled:border-base-neutral-100 dark:group-disabled:border-base-neutral-400 dark:group-disabled:bg-base-neutral-400 group-disabled:opacity-38 group-disabled:forced-colors:border group-disabled:forced-colors:border-[GrayText]',\n\t\t\t'group-invalid:border-base-sunset-500 forced-colors:group-invalid:border-[Mark]',\n\t\t\t'group-invalid:hover:border-base-sunset-200 dark:group-invalid:hover:border-base-sunset-700',\n\t\t\t'group-invalid:focus-visible:border-base-sunset-200 dark:group-invalid:focus-visible:border-base-sunset-700',\n\t\t\t'**:data-[slot=icon]:size-6 **:data-[slot=icon]:shrink-0 **:[button]:shrink-0',\n\t\t\t'[&>button:has([data-slot=icon])]:absolute [&>button:has([data-slot=icon]):first-child]:left-0 [&>button:has([data-slot=icon]):last-child]:right-0',\n\t\t\t'*:data-[slot=icon]:text-base-neutral-800 dark:*:data-[slot=icon]:text-base-neutral-100 *:data-[slot=icon]:pointer-events-none *:data-[slot=icon]:absolute *:data-[slot=icon]:top-[calc(var(--spacing)_*_1.7)] *:data-[slot=icon]:z-10 *:data-[slot=icon]:size-6',\n\t\t\t'[&>[data-slot=icon]:first-child]:left-2 [&>[data-slot=icon]:last-child]:right-2',\n\t\t\t'[&:has([data-slot=icon]+input)]:pl-7.5 [&:has(input+[data-slot=icon])]:pr-7.5',\n\t\t\t'[&:has([data-slot=icon]+[role=group])]:pl-7.5 [&:has([role=group]+[data-slot=icon])]:pr-7.5',\n\t\t\t'has-[[data-slot=icon]:last-child]:[&_input]:pr-7.5',\n\t\t\t'*:[button]:size-6 *:[button]:p-0',\n\t\t\t'[&>button:first-child]:ml-2 [&>button:last-child]:mr-2',\n\t\t],\n\t}),\n);\n\nexport type SelectProps<Type extends object> = RACSelectProps<Type> & {\n\treadonly className?: string;\n\treadonly description?: string;\n\treadonly errorMessage?: string | ((validation: RACValidationResult) => string) | undefined;\n\treadonly items?: Iterable<Type>;\n\treadonly label?: ReactNode | string;\n};\n\nexport function Select<Type extends object>(props: SelectProps<Type>) {\n\treturn (\n\t\t<RACSelect {...props} className={composeTailwindRenderProps(props.className, 'group flex w-full flex-col gap-1.5')}>\n\t\t\t{(values) => (\n\t\t\t\t<>\n\t\t\t\t\t{props.label && <Label>{props.label}</Label>}\n\t\t\t\t\t{typeof props.children === 'function' ? props.children(values) : props.children}\n\t\t\t\t\t{props.description && <Description>{props.description}</Description>}\n\t\t\t\t\t<FieldError>{props.errorMessage}</FieldError>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</RACSelect>\n\t);\n}\n\nexport type SelectListProps<Type extends object> = Pick<PopoverContentProps, 'placement'> &\n\tRACListBoxProps<Type> & {\n\t\treadonly classNames?: {\n\t\t\treadonly popover?: PopoverContentProps['className'];\n\t\t};\n\t\treadonly items?: Iterable<Type>;\n\t};\n\nexport function SelectList<Type extends object>(props: SelectListProps<Type>) {\n\treturn (\n\t\t<PopoverContent\n\t\t\tclassName={cx('w-(--trigger-width)', props.classNames?.popover)}\n\t\t\tplacement={props.placement!}\n\t\t\trespectScreen={false}\n\t\t\tshowArrow={false}\n\t\t>\n\t\t\t<ListBox {...props} className={cx('border-0', props.classNames?.popover)} items={props.items!}>\n\t\t\t\t{props.children}\n\t\t\t</ListBox>\n\t\t</PopoverContent>\n\t);\n}\n\nexport type SelectTriggerProps = ComponentProps<typeof Button> & {\n\treadonly className?: string;\n\treadonly prefix?: ReactNode;\n\treadonly suffix?: ReactNode;\n};\n\nexport function SelectTrigger(props: SelectTriggerProps) {\n\treturn (\n\t\t<RACButton\n\t\t\tclassName={composeRenderProps(props.className, (className, renderProps) =>\n\t\t\t\tselectTriggerStyles({\n\t\t\t\t\t...renderProps,\n\t\t\t\t\tclassName,\n\t\t\t\t}),\n\t\t\t)}\n\t\t>\n\t\t\t{props.prefix && <span className=\"-mr-1 ml-2 *:data-[slot=icon]:size-5.5\">{props.prefix}</span>}\n\t\t\t<RACSelectValue\n\t\t\t\tclassName=\"text-base-neutral-900 group-disabled:data-placeholder:text-base-neutral-900 dark:group-disabled:data-placeholder:text-base-neutral-40 dark:data-placeholder:text-base-neutral-500 dark:text-base-neutral-40 data-placeholder:text-base-neutral-400 text-base-lg sm:text-base-md grid flex-1 grid-cols-[auto_1fr] place-items-start items-center px-3 py-2.5 *:data-[slot=avatar]:*:-mx-0.5 *:data-[slot=avatar]:-mx-0.5 *:data-[slot=avatar]:*:mr-2 *:data-[slot=avatar]:mr-2 *:data-[slot=icon]:-mx-0.5 *:data-[slot=icon]:mr-1 *:data-[slot=icon]:size-5.5 [&_[slot=description]]:hidden *:[span]:col-start-2\"\n\t\t\t\tdata-slot=\"select-value\"\n\t\t\t/>\n\t\t\t{props.suffix && <span className=\"mr-10 ml-2 *:data-[slot=icon]:size-5.5\">{props.suffix}</span>}\n\t\t\t<ChevronDownIcon\n\t\t\t\taria-hidden\n\t\t\t\tclassName=\"size-6 shrink-0 duration-200 group-open:rotate-180 forced-colors:text-[ButtonText] forced-colors:group-disabled:text-[GrayText]\"\n\t\t\t\tdata-slot=\"icon\"\n\t\t\t\tsize={24}\n\t\t\t\tstrokeWidth={1.5}\n\t\t\t/>\n\t\t</RACButton>\n\t);\n}\n\nexport {\n\tDropdownSection as SelectSection,\n\tDropdownSeparator as SelectSeparator,\n\tDropdownLabel as SelectLabel,\n\tDropdownItemDetails as SelectOptionDetails,\n\tDropdownItem as SelectOption,\n} from '@/components/ui/Dropdown';\n"
  },
  {
    "path": "apps/website/src/components/ui/Sheet.tsx",
    "content": "import type { VariantProps } from 'cva';\nimport type { ComponentProps } from 'react';\nimport type {\n\tDialogProps as RACDialogProps,\n\tDialogTriggerProps as RACDialogTriggerProps,\n\tModalOverlayProps as RACModalOverlayProps,\n} from 'react-aria-components';\nimport {\n\tDialogTrigger as RACDialogTrigger,\n\tModal as RACModal,\n\tModalOverlay as RACModalOverlay,\n\tcomposeRenderProps,\n} from 'react-aria-components';\nimport { Dialog, DialogCloseIndicator } from '@/components/ui/Dialog';\nimport { cva } from '@/styles/cva';\n\nconst overlayStyles = cva({\n\tbase: 'fixed top-0 left-0 isolate z-50 flex h-(--visual-viewport-height) w-full place-content-center place-items-center bg-neutral-900/15 p-4 dark:bg-neutral-900/40',\n\tvariants: {\n\t\tisBlurred: {\n\t\t\ttrue: 'supports-backdrop-filter:backdrop-blur',\n\t\t},\n\t\tisEntering: {\n\t\t\ttrue: 'fade-in animate-in duration-300 ease-out',\n\t\t},\n\t\tisExiting: {\n\t\t\ttrue: 'fade-out animate-out duration-200 ease-in',\n\t\t},\n\t},\n});\n\ntype Sides = 'bottom' | 'left' | 'right' | 'top';\nconst generateCompoundVariants = (sides: Sides[]) =>\n\tsides.map((side) => ({\n\t\tside,\n\t\tisFloat: true,\n\t\tclassName:\n\t\t\tside === 'top'\n\t\t\t\t? 'top-2 inset-x-2 border-b-0'\n\t\t\t\t: side === 'bottom'\n\t\t\t\t\t? 'bottom-2 inset-x-2 border-t-0'\n\t\t\t\t\t: side === 'left'\n\t\t\t\t\t\t? 'left-2 inset-y-2 border-r-0'\n\t\t\t\t\t\t: 'right-2 inset-y-2 border-l-0',\n\t}));\n\nconst contentStyles = cva({\n\tbase: 'shadow-base-md border-base-neutral-200 dark:border-base-neutral-600 fixed z-50 grid gap-4 bg-neutral-100 transition ease-in-out dark:bg-neutral-900',\n\tvariants: {\n\t\tisEntering: {\n\t\t\ttrue: 'animate-in duration-300',\n\t\t},\n\t\tisExiting: {\n\t\t\ttrue: 'animate-out duration-200',\n\t\t},\n\t\tside: {\n\t\t\ttop: 'entering:slide-in-from-top exiting:slide-out-to-top inset-x-0 top-0 border-b',\n\t\t\tbottom: 'entering:slide-in-from-bottom exiting:slide-out-to-bottom inset-x-0 bottom-0 border-t',\n\t\t\tleft: 'entering:slide-in-from-left exiting:slide-out-to-left inset-y-0 left-0 h-auto w-full max-w-xs overflow-y-auto border-r',\n\t\t\tright:\n\t\t\t\t'entering:slide-in-from-right exiting:slide-out-to-right inset-y-0 right-0 h-auto w-full max-w-xs overflow-y-auto border-l',\n\t\t},\n\t\tisFloat: {\n\t\t\ttrue: '',\n\t\t\tfalse: '',\n\t\t},\n\t},\n\tcompoundVariants: generateCompoundVariants(['top', 'bottom', 'left', 'right']),\n});\n\nexport type SheetProps = RACDialogTriggerProps;\n\nexport function Sheet(props: SheetProps) {\n\treturn <RACDialogTrigger {...props} />;\n}\n\nexport type SheetContentProps = Omit<ComponentProps<typeof RACModal>, 'children' | 'className'> &\n\tOmit<RACModalOverlayProps, 'className'> &\n\tVariantProps<typeof overlayStyles> & {\n\t\treadonly 'aria-label'?: RACDialogProps['aria-label'];\n\t\treadonly 'aria-labelledby'?: RACDialogProps['aria-labelledby'];\n\t\treadonly classNames?: {\n\t\t\tcontent?: RACModalOverlayProps['className'];\n\t\t\toverlay?: RACModalOverlayProps['className'];\n\t\t};\n\t\treadonly closeButton?: boolean;\n\t\treadonly isBlurred?: boolean;\n\t\treadonly isFloat?: boolean;\n\t\treadonly role?: RACDialogProps['role'];\n\t\treadonly side?: Sides;\n\t};\n\nexport function SheetContent({\n\tisBlurred = false,\n\tisDismissable = true,\n\tside = 'right',\n\trole = 'dialog',\n\tcloseButton = true,\n\tisFloat = true,\n\t...props\n}: SheetContentProps) {\n\tconst _isDismissable = role === 'alertdialog' ? false : isDismissable;\n\n\treturn (\n\t\t<RACModalOverlay\n\t\t\t{...props}\n\t\t\tclassName={composeRenderProps(props.classNames?.overlay, (className, renderProps) =>\n\t\t\t\toverlayStyles({\n\t\t\t\t\t...renderProps,\n\t\t\t\t\tisBlurred,\n\t\t\t\t\tclassName,\n\t\t\t\t}),\n\t\t\t)}\n\t\t\tisDismissable={_isDismissable}\n\t\t>\n\t\t\t<RACModal\n\t\t\t\t{...props}\n\t\t\t\tclassName={composeRenderProps(props.classNames?.content, (className, renderProps) =>\n\t\t\t\t\tcontentStyles({\n\t\t\t\t\t\t...renderProps,\n\t\t\t\t\t\tside,\n\t\t\t\t\t\tisFloat,\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t}),\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{(values) => (\n\t\t\t\t\t<Dialog aria-label={props['aria-label'] ?? undefined!} className=\"h-full\" role={role}>\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t{typeof props.children === 'function' ? props.children(values) : props.children}\n\t\t\t\t\t\t\t{closeButton && <DialogCloseIndicator className=\"top-2.5 right-2.5\" isDismissable={_isDismissable} />}\n\t\t\t\t\t\t</>\n\t\t\t\t\t</Dialog>\n\t\t\t\t)}\n\t\t\t</RACModal>\n\t\t</RACModalOverlay>\n\t);\n}\n\nexport {\n\tDialogTrigger as SheetTrigger,\n\tDialogBody as SheetBody,\n\tDialogClose as SheetClose,\n\tDialogDescription as SheetDescription,\n\tDialogFooter as SheetFooter,\n\tDialogHeader as SheetHeader,\n\tDialogTitle as SheetTitle,\n} from '@/components/ui/Dialog';\n"
  },
  {
    "path": "apps/website/src/components/ui/Sidebar.tsx",
    "content": "'use client';\n\nimport { MenuIcon, SidebarIcon, XIcon } from 'lucide-react';\nimport {\n\tcreateContext,\n\tuse,\n\tuseCallback,\n\tuseEffect,\n\tuseLayoutEffect,\n\tuseMemo,\n\tuseState,\n\ttype ComponentProps,\n} from 'react';\nimport { chain } from 'react-aria';\nimport { useMediaQuery } from 'usehooks-ts';\nimport { Button, type ButtonProps } from '@/components/ui/Button';\nimport { SheetBody, SheetContent, type SheetContentProps } from '@/components/ui/Sheet';\nimport { cva, cx } from '@/styles/cva';\n\nconst SIDEBAR_COOKIE_NAME = 'sidebar:state';\nconst SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;\n\ninterface SidebarContextProps {\n\tisMobile: boolean;\n\topen: boolean;\n\topenMobile: boolean;\n\tsetOpen(open: boolean | ((open: boolean) => boolean)): void;\n\tsetOpenMobile(open: boolean | ((open: boolean) => boolean)): void;\n\tstate: 'collapsed' | 'expanded';\n}\n\nconst SidebarContext = createContext<SidebarContextProps | null>(null);\n\nexport function useSidebar() {\n\tconst context = use(SidebarContext);\n\tif (!context) {\n\t\tthrow new Error('useSidebar must be used within a Sidebar.');\n\t}\n\n\treturn context;\n}\n\nexport type SidebarProviderProps = ComponentProps<'div'> & {\n\treadonly defaultOpen?: boolean;\n\treadonly isOpen?: boolean;\n\tonOpenChange?(open: boolean): void;\n\treadonly shortcut?: string;\n};\n\nexport function SidebarProvider({\n\tdefaultOpen = false,\n\tisOpen: openProp,\n\tonOpenChange: setOpenProp,\n\tshortcut = 'b',\n\t...props\n}: SidebarProviderProps) {\n\tconst isMobile = useMediaQuery('(max-width: 767px)', { initializeWithValue: false });\n\tconst [openMobile, setOpenMobile] = useState(false);\n\n\tconst [internalOpenState, setInternalOpenState] = useState(defaultOpen);\n\tconst open = openProp ?? internalOpenState;\n\tconst setOpen = useCallback(\n\t\t(value: boolean | ((value: boolean) => boolean)) => {\n\t\t\tconst openState = typeof value === 'function' ? value(open) : value;\n\n\t\t\tif (isMobile) {\n\t\t\t\tsetOpenMobile((open) => !open);\n\t\t\t} else if (setOpenProp) {\n\t\t\t\tsetOpenProp(openState);\n\t\t\t} else {\n\t\t\t\tsetInternalOpenState(openState);\n\t\t\t}\n\n\t\t\t// eslint-disable-next-line react-compiler/react-compiler\n\t\t\tdocument.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;\n\t\t},\n\t\t[setOpenProp, open, isMobile, setOpenMobile],\n\t);\n\n\tuseEffect(() => {\n\t\tconst handleKeyDown = (event: KeyboardEvent) => {\n\t\t\tif (event.key === shortcut && (event.metaKey || event.ctrlKey)) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tsetOpen((open) => !open);\n\t\t\t}\n\t\t};\n\n\t\twindow.addEventListener('keydown', handleKeyDown);\n\t\treturn () => window.removeEventListener('keydown', handleKeyDown);\n\t}, [shortcut, setOpen]);\n\n\tconst state = open ? 'expanded' : 'collapsed';\n\n\tconst contextValue = useMemo<SidebarContextProps>(\n\t\t() => ({\n\t\t\tstate,\n\t\t\topen,\n\t\t\tsetOpen,\n\t\t\topenMobile,\n\t\t\tsetOpenMobile,\n\t\t\tisMobile,\n\t\t}),\n\t\t[state, open, setOpen, openMobile, setOpenMobile, isMobile],\n\t);\n\n\treturn (\n\t\t<SidebarContext value={contextValue}>\n\t\t\t<div\n\t\t\t\t{...props}\n\t\t\t\tclassName={cx(\n\t\t\t\t\t'@container/sidebar **:data-[slot=icon]:shrink-0',\n\t\t\t\t\t'[--sidebar-width-dock:3.25rem] [--sidebar-width-mobile:20rem] [--sidebar-width:20rem]',\n\t\t\t\t\t'[--sidebar-border:var(--color-base-neutral-200)]',\n\t\t\t\t\t'dark:[--sidebar-border:var(--color-base-neutral-600)]',\n\t\t\t\t\t'flex min-h-dvh w-full',\n\t\t\t\t\t'group/sidebar-root has-data-[sidebar-intent=inset]:bg-[#f3f3f4] dark:has-data-[sidebar-intent=inset]:bg-[#121214]',\n\t\t\t\t\t'[@-moz-document_url-prefix()]:overflow-x-hidden',\n\t\t\t\t\tprops.className,\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{props.children}\n\t\t\t</div>\n\t\t</SidebarContext>\n\t);\n}\n\nconst sidebarGapStyles = cva({\n\tbase: [\n\t\t'w-(--sidebar-width) group-data-[sidebar-collapsible=hidden]/sidebar-container:w-0',\n\t\t'relative h-dvh bg-transparent transition-[width] duration-100 ease-linear',\n\t\t'group-data-[sidebar-side=right]/sidebar-container:rotate-180',\n\t],\n\tvariants: {\n\t\tintent: {\n\t\t\tdefault: 'group-data-[sidebar-collapsible=dock]/sidebar-container:w-(--sidebar-width-dock)',\n\t\t\tfleet: 'group-data-[sidebar-collapsible=dock]/sidebar-container:w-(--sidebar-width-dock)',\n\t\t\tfloat:\n\t\t\t\t'group-data-[sidebar-collapsible=dock]/sidebar-container:w-[calc(var(--sidebar-width-dock)+theme(spacing.4))]',\n\t\t\tinset:\n\t\t\t\t'group-data-[sidebar-collapsible=dock]/sidebar-container:w-[calc(var(--sidebar-width-dock)+theme(spacing.2))]',\n\t\t},\n\t},\n});\n\nconst sidebarStyles = cva({\n\tbase: [\n\t\t'fixed inset-y-0 z-10 hidden h-dvh w-(--sidebar-width) transition-[left,right,width] duration-100 ease-linear md:flex',\n\t\t'min-h-dvh bg-[#f3f3f4] dark:bg-[#121214]',\n\t\t'**:data-[slot=disclosure]:border-0 **:data-[slot=disclosure]:px-2.5',\n\t\t'has-data-[sidebar-intent=default]:shadow-base-md',\n\t\t'[@-moz-document_url-prefix()]:h-full [@-moz-document_url-prefix()]:min-h-full',\n\t],\n\tvariants: {\n\t\tside: {\n\t\t\tleft: 'left-0 group-data-[sidebar-collapsible=hidden]/sidebar-container:left-[calc(var(--sidebar-width)*-1)]',\n\t\t\tright: 'right-0 group-data-[sidebar-collapsible=hidden]/sidebar-container:right-[calc(var(--sidebar-width)*-1)]',\n\t\t},\n\t\tintent: {\n\t\t\tdefault: [\n\t\t\t\t'group-data-[sidebar-collapsible=dock]/sidebar-container:w-(--sidebar-width-dock) group-data-[sidebar-side=left]/sidebar-container:border-(--sidebar-border) group-data-[sidebar-side=right]/sidebar-container:border-(--sidebar-border)',\n\t\t\t\t'group-data-[sidebar-side=left]/sidebar-container:border-r group-data-[sidebar-side=right]/sidebar-container:border-l',\n\t\t\t],\n\t\t\tfleet: [\n\t\t\t\t'group-data-[sidebar-collapsible=dock]/sidebar-container:w-(--sidebar-width-dock)',\n\t\t\t\t'**:data-sidebar-disclosure:gap-y-0 **:data-sidebar-disclosure:px-0 **:data-sidebar-section:gap-y-0 **:data-sidebar-section:px-0',\n\t\t\t\t'group-data-[sidebar-side=left]/sidebar-container:border-r group-data-[sidebar-side=right]/sidebar-container:border-l',\n\t\t\t],\n\t\t\tfloat: 'bg-bg p-2 group-data-[sidebar-collapsible=dock]/sidebar-container:w-[calc(var+theme(spacing.4)+2px)]',\n\t\t\tinset: [\n\t\t\t\t'p-2 group-data-[sidebar-collapsible=dock]/sidebar-container:w-[calc(var(--sidebar-width-dock)+theme(spacing.2)+2px)]',\n\t\t\t],\n\t\t},\n\t},\n});\n\nexport type SidebarProps = ComponentProps<'div'> &\n\tSheetContentProps & {\n\t\treadonly closeButton?: boolean;\n\t\treadonly collapsible?: 'dock' | 'hidden' | 'none';\n\t\treadonly intent?: 'default' | 'fleet' | 'float' | 'inset';\n\t\treadonly side?: 'left' | 'right';\n\t};\n\nexport function Sidebar({\n\tcloseButton = true,\n\tcollapsible = 'hidden',\n\tside = 'left',\n\tintent = 'default',\n\t...props\n}: SidebarProps) {\n\tconst { isMobile, state, open, openMobile, setOpenMobile } = useSidebar();\n\tconst [needsScrollbarGutter, setNeedsScrollbarGutter] = useState(false);\n\n\tuseLayoutEffect(() => {\n\t\tif (collapsible === 'none' || isMobile || side !== 'right') {\n\t\t\treturn;\n\t\t}\n\n\t\tconst scrollbarVisible = (element: HTMLElement) => element.scrollHeight > element.clientHeight;\n\n\t\tconst observer = new MutationObserver((mutations) => {\n\t\t\tif (mutations[0]?.type === 'attributes' && scrollbarVisible(document.documentElement) && open) {\n\t\t\t\tif (getComputedStyle(document.documentElement).paddingRight === '0px') {\n\t\t\t\t\tsetNeedsScrollbarGutter(false);\n\t\t\t\t} else {\n\t\t\t\t\tsetNeedsScrollbarGutter(true);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tsetNeedsScrollbarGutter(false);\n\t\t\t}\n\t\t});\n\n\t\tobserver.observe(document.documentElement, {\n\t\t\tattributes: true,\n\t\t\tattributeFilter: ['style'],\n\t\t});\n\n\t\treturn () => {\n\t\t\tobserver.disconnect();\n\t\t};\n\t}, [collapsible, isMobile, open, side]);\n\n\tif (collapsible === 'none') {\n\t\treturn (\n\t\t\t<div\n\t\t\t\t{...props}\n\t\t\t\tclassName={cx('flex h-full w-(--sidebar-width) flex-col border-r border-(--sidebar-border)', props.className)}\n\t\t\t\tdata-sidebar-collapsible=\"none\"\n\t\t\t\tdata-sidebar-intent={intent}\n\t\t\t/>\n\t\t);\n\t}\n\n\tif (isMobile) {\n\t\treturn (\n\t\t\t<SheetContent\n\t\t\t\t{...props}\n\t\t\t\taria-label=\"Sidebar\"\n\t\t\t\tcloseButton={closeButton}\n\t\t\t\tdata-sidebar-intent=\"default\"\n\t\t\t\tisFloat={intent === 'float'}\n\t\t\t\tisOpen={openMobile}\n\t\t\t\tonOpenChange={setOpenMobile}\n\t\t\t\tside={side}\n\t\t\t>\n\t\t\t\t<SheetBody className=\"gap-0 p-0\">{props.children}</SheetBody>\n\t\t\t</SheetContent>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div\n\t\t\t{...props}\n\t\t\tclassName=\"group/sidebar-container peer hidden md:block\"\n\t\t\tdata-sidebar-collapsible={state === 'collapsed' ? collapsible : ''}\n\t\t\tdata-sidebar-intent={intent}\n\t\t\tdata-sidebar-side={side}\n\t\t\tdata-sidebar-state={state}\n\t\t>\n\t\t\t<div aria-hidden className={sidebarGapStyles({ intent })} />\n\t\t\t<div\n\t\t\t\t{...props}\n\t\t\t\tclassName={sidebarStyles({\n\t\t\t\t\tside,\n\t\t\t\t\tintent,\n\t\t\t\t\tclassName: cx(props.className, needsScrollbarGutter && 'right-[11px]', 'transition-[left,width]'),\n\t\t\t\t})}\n\t\t\t>\n\t\t\t\t<div\n\t\t\t\t\tclassName={cx(\n\t\t\t\t\t\t'flex h-full w-full flex-col',\n\t\t\t\t\t\t'group-data-[sidebar-intent=inset]/sidebar-container:bg-sidebar dark:group-data-[sidebar-intent=inset]/sidebar-container:bg-bg',\n\t\t\t\t\t\t'group-data-[sidebar-intent=float]/sidebar-container:bg-sidebar group-data-[sidebar-intent=float]/sidebar-container:shadow-base-md group-data-[sidebar-intent=float]/sidebar-container:rounded-lg group-data-[sidebar-intent=float]/sidebar-container:border group-data-[sidebar-intent=float]/sidebar-container:border-(--sidebar-border)',\n\t\t\t\t\t)}\n\t\t\t\t\tdata-sidebar=\"default\"\n\t\t\t\t>\n\t\t\t\t\t{props.children}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport function SidebarInsetAnchor({\n\tcollapsible = 'hidden',\n\tside = 'left',\n\tintent = 'default',\n\t...props\n}: SidebarProps) {\n\tconst { state } = useSidebar();\n\n\treturn (\n\t\t<div\n\t\t\t{...props}\n\t\t\tclassName=\"group/sidebar-container peer hidden\"\n\t\t\tdata-sidebar-collapsible={state === 'collapsed' ? collapsible : ''}\n\t\t\tdata-sidebar-intent={intent}\n\t\t\tdata-sidebar-side={side}\n\t\t\tdata-sidebar-state={state}\n\t\t/>\n\t);\n}\n\nconst sidebarHeaderStyles = cva({\n\tbase: 'dark:bg-base-neutral-800 bg-base-neutral-0 flex flex-col **:data-[slot=sidebar-label-mask]:hidden',\n\tvariants: {\n\t\tcollapsed: {\n\t\t\ttrue: 'mt-2 p-12 group-data-[sidebar-intent=float]/sidebar-container:mt-2 md:mx-auto md:size-9 md:items-center md:justify-center md:rounded-lg md:p-0 md:hover:bg-(--sidebar-accent)',\n\t\t\tfalse: 'px-6 pt-8 pb-4',\n\t\t},\n\t\thasBorder: {\n\t\t\ttrue: 'border-base-neutral-100 dark:border-base-neutral-700 border-b',\n\t\t\tfalse: null,\n\t\t},\n\t},\n});\n\nexport type SidebarHeaderProps = ComponentProps<'div'> & {\n\treadonly hasBorder?: boolean;\n};\n\nexport function SidebarHeader({ hasBorder = false, ...props }: SidebarHeaderProps) {\n\tconst { state } = use(SidebarContext)!;\n\n\treturn (\n\t\t<div\n\t\t\t{...props}\n\t\t\tclassName={sidebarHeaderStyles({ collapsed: state === 'collapsed', hasBorder, className: props.className })}\n\t\t\tdata-sidebar-header=\"true\"\n\t\t/>\n\t);\n}\n\nconst sidebarFooterStyles = cva({\n\tbase: [\n\t\t'flex flex-col p-6',\n\t\t'in-data-[sidebar-intent=fleet]:mt-0 in-data-[sidebar-intent=fleet]:p-0',\n\t\t'in-data-[sidebar-intent=fleet]:**:data-[slot=menu-trigger]:rounded-none',\n\t\t'**:data-[slot=menu-trigger]:relative **:data-[slot=menu-trigger]:overflow-hidden',\n\t\t'**:data-[slot=menu-trigger]:rounded-lg',\n\t\t'sm:**:data-[slot=menu-trigger]:text-base-md **:data-[slot=menu-trigger]:flex **:data-[slot=menu-trigger]:cursor-default **:data-[slot=menu-trigger]:items-center **:data-[slot=menu-trigger]:p-2 **:data-[slot=menu-trigger]:outline-hidden',\n\t\t'**:data-[slot=menu-trigger]:hover:text-fg **:data-[slot=menu-trigger]:hover:bg-(--sidebar-accent)',\n\t],\n\tvariants: {\n\t\tcollapsed: {\n\t\t\ttrue: [\n\t\t\t\t'**:data-[slot=avatar]:size-6 **:data-[slot=avatar]:*:size-6',\n\t\t\t\t'**:data-[slot=chevron]:hidden **:data-[slot=menu-label]:hidden',\n\t\t\t\t'**:data-[slot=menu-trigger]:grid **:data-[slot=menu-trigger]:size-8 **:data-[slot=menu-trigger]:place-content-center',\n\t\t\t],\n\t\t\tfalse: [\n\t\t\t\t'**:data-[slot=avatar]:size-8 **:data-[slot=avatar]:*:size-8 **:data-[slot=menu-trigger]:**:data-[slot=avatar]:mr-2',\n\t\t\t\t'**:data-[slot=menu-trigger]:pressed:**:data-[slot=chevron]:rotate-180 **:data-[slot=menu-trigger]:w-full **:data-[slot=menu-trigger]:**:data-[slot=chevron]:ml-auto **:data-[slot=menu-trigger]:**:data-[slot=chevron]:transition-transform',\n\t\t\t],\n\t\t},\n\t\thasBorder: {\n\t\t\ttrue: 'border-base-neutral-100 dark:border-base-neutral-700 border-t',\n\t\t\tfalse: null,\n\t\t},\n\t},\n});\n\nexport type SidebarFooterProps = ComponentProps<'div'> & {\n\treadonly hasBorder?: boolean;\n};\n\nexport function SidebarFooter({ hasBorder = false, ...props }: SidebarFooterProps) {\n\tconst { state, isMobile } = useSidebar();\n\tconst collapsed = state === 'collapsed' && !isMobile;\n\n\treturn (\n\t\t<div\n\t\t\t{...props}\n\t\t\tclassName={sidebarFooterStyles({ collapsed, hasBorder, className: props.className })}\n\t\t\tdata-sidebar-footer=\"true\"\n\t\t/>\n\t);\n}\n\nexport function SidebarContent(props: ComponentProps<'div'>) {\n\tconst { state } = useSidebar();\n\n\treturn (\n\t\t<div\n\t\t\t{...props}\n\t\t\tclassName={cx(\n\t\t\t\t'dark:bg-base-neutral-800 bg-base-neutral-0 flex min-h-0 flex-1 scroll-mb-96 flex-col overflow-auto p-6 *:data-sidebar-section:border-l-0',\n\t\t\t\tstate === 'collapsed' && 'place-items-center',\n\t\t\t\tprops.className,\n\t\t\t)}\n\t\t\tdata-sidebar-content=\"true\"\n\t\t/>\n\t);\n}\n\nexport function SidebarInset(props: ComponentProps<'main'>) {\n\treturn (\n\t\t<main\n\t\t\t{...props}\n\t\t\tclassName={cx(\n\t\t\t\t'relative flex min-h-dvh w-full flex-1 flex-col peer-data-[sidebar-intent=inset]:border peer-data-[sidebar-intent=inset]:border-transparent',\n\t\t\t\t'bg-bg dark:peer-data-[sidebar-intent=inset]:bg-sidebar peer-data-[sidebar-intent=inset]:overflow-hidden',\n\t\t\t\t'md:peer-data-[sidebar-intent=inset]:shadow-base-md peer-data-[sidebar-intent=inset]:min-h-[calc(100dvh-theme(spacing.4))] md:peer-data-[sidebar-intent=inset]:m-2 md:peer-data-[sidebar-intent=inset]:rounded-xl md:peer-data-[sidebar-intent=inset]:peer-data-[sidebar-side=left]:ml-0 md:peer-data-[sidebar-intent=inset]:peer-data-[sidebar-side=right]:mr-0 md:peer-data-[sidebar-state=collapsed]:peer-data-[sidebar-intent=inset]:peer-data-[sidebar-side=left]:ml-2 md:peer-data-[sidebar-state=collapsed]:peer-data-[sidebar-intent=inset]:peer-data-[sidebar-side=right]:mr-2',\n\t\t\t\tprops.className,\n\t\t\t)}\n\t\t/>\n\t);\n}\n\nexport function SidebarTrigger({ onPress, children, ...props }: ButtonProps) {\n\tconst { setOpen } = useSidebar();\n\n\treturn (\n\t\t<Button\n\t\t\t{...props}\n\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\taria-label={props['aria-label'] || 'Toggle Sidebar'}\n\t\t\tdata-sidebar-trigger=\"true\"\n\t\t\tonPress={(event) => {\n\t\t\t\tonPress?.(event);\n\t\t\t\tsetOpen((open) => !open);\n\t\t\t}}\n\t\t>\n\t\t\t{children || (\n\t\t\t\t<>\n\t\t\t\t\t<SidebarIcon aria-hidden className=\"hidden md:inline\" data-slot=\"icon\" size={18} />\n\t\t\t\t\t<MenuIcon aria-hidden className=\"inline md:hidden\" data-slot=\"icon\" size={18} />\n\t\t\t\t\t<span className=\"sr-only\">Toggle Sidebar</span>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</Button>\n\t);\n}\n\nexport type CloseButtonIndicatorProps = Omit<ButtonProps, 'children'> & {\n\treadonly className?: string;\n\treadonly isDismissable?: boolean | undefined;\n};\n\nexport function SidebarCloseIndicator({ isDismissable = true, ...props }: CloseButtonIndicatorProps) {\n\tconst { setOpen } = useSidebar();\n\n\treturn (\n\t\t<Button\n\t\t\t{...props}\n\t\t\taria-label=\"Close\"\n\t\t\tclassName={cx(\n\t\t\t\t'close text-base-neutral-500 hover:text-base-neutral-700 focus-visible:text-base-neutral-700 pressed:text-base-neutral-900 dark:text-base-neutral-400 dark:hover:text-base-neutral-200 dark:focus-visible:text-base-neutral-200 dark:pressed:text-base-neutral-500 disabled:text-base-neutral-300 dark:disabled:text-base-neutral-300 z-50 rounded-full',\n\t\t\t\tprops.className,\n\t\t\t)}\n\t\t\tonPress={isDismissable ? chain(() => setOpen((open) => !open), props.onPress) : props.onPress!}\n\t\t\tsize=\"icon-xs\"\n\t\t\tslot={props.slot === null ? null : (props.slot ?? 'close')}\n\t\t\tvariant=\"unset\"\n\t\t>\n\t\t\t<XIcon aria-hidden className=\"size-4.5 stroke-[1.5]\" />\n\t\t</Button>\n\t);\n}\n\nexport function SidebarRail({ className, ref, ...props }: ComponentProps<'button'>) {\n\tconst { setOpen } = useSidebar();\n\n\treturn (\n\t\t<button\n\t\t\taria-label=\"Toggle Sidebar\"\n\t\t\tclassName={cx(\n\t\t\t\t'absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 outline-hidden transition-all ease-linear group-data-[sidebar-side=left]/sidebar-container:-right-4 group-data-[sidebar-side=right]/sidebar-container:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] data-hovered:after:bg-transparent sm:flex',\n\t\t\t\t'in-data-[sidebar-side=left]:cursor-w-resize in-data-[sidebar-side=right]:cursor-e-resize',\n\t\t\t\t'[[data-sidebar-side=left][data-sidebar-state=collapsed]_&]:cursor-e-resize [[data-sidebar-side=right][data-sidebar-state=collapsed]_&]:cursor-w-resize',\n\t\t\t\t'group-data-[sidebar-collapsible=hidden]/sidebar-container:hover:bg-secondary group-data-[sidebar-collapsible=hidden]/sidebar-container:translate-x-0 group-data-[sidebar-collapsible=hidden]/sidebar-container:after:left-full',\n\t\t\t\t'[[data-sidebar-side=left][data-sidebar-collapsible=hidden]_&]:-right-2 [[data-sidebar-side=right][data-sidebar-collapsible=hidden]_&]:-left-2',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tdata-sidebar=\"rail\"\n\t\t\tonClick={() => setOpen((open) => !open)}\n\t\t\tref={ref}\n\t\t\ttabIndex={-1}\n\t\t\ttitle=\"Toggle Sidebar\"\n\t\t\ttype=\"button\"\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n"
  },
  {
    "path": "apps/website/src/components/ui/Tabs.tsx",
    "content": "'use client';\n\nexport { Tabs, TabList, Tab, TabPanel } from 'react-aria-components';\n"
  },
  {
    "path": "apps/website/src/hooks/useSystemThemeFallback.ts",
    "content": "'use client';\n\nimport { useEffect } from 'react';\n\nexport function useSystemThemeFallback() {\n\tuseEffect(() => {\n\t\tconst theme = localStorage.getItem('theme');\n\t\tif (theme === 'auto') {\n\t\t\tlocalStorage.setItem('theme', 'system');\n\t\t}\n\t}, []);\n}\n"
  },
  {
    "path": "apps/website/src/hooks/useUnregisterServiceWorker.ts",
    "content": "'use client';\n\nimport { useEffect } from 'react';\n\nexport function useUnregisterServiceWorker() {\n\tuseEffect(() => {\n\t\t// eslint-disable-next-line promise/prefer-await-to-then\n\t\tvoid navigator.serviceWorker?.getRegistrations().then((registrations) => {\n\t\t\tfor (const registration of registrations) {\n\t\t\t\tvoid registration.unregister();\n\t\t\t}\n\t\t});\n\t}, []);\n}\n"
  },
  {
    "path": "apps/website/src/middleware.ts",
    "content": "import { NextResponse, type NextRequest } from 'next/server';\nimport { PACKAGES } from '@/util/constants';\nimport { fetchLatestVersion } from '@/util/fetchLatestVersion';\n\nexport default async function middleware(request: NextRequest) {\n\tif (request.nextUrl.pathname === '/docs') {\n\t\tconst latestVersion = await fetchLatestVersion('discord.js');\n\t\treturn NextResponse.redirect(new URL(`/docs/packages/discord.js/${latestVersion}`, request.url));\n\t}\n\n\tif (PACKAGES.some((pkg) => request.nextUrl.pathname.includes(pkg.name))) {\n\t\t// eslint-disable-next-line prefer-named-capture-group\n\t\tconst packageName = /\\/docs\\/packages\\/([^/]+)\\/.*/.exec(request.nextUrl.pathname)?.[1] ?? 'discord.js';\n\t\tconst latestVersion = await fetchLatestVersion(packageName);\n\t\treturn NextResponse.redirect(new URL(request.nextUrl.pathname.replace('stable', latestVersion), request.url));\n\t}\n\n\treturn NextResponse.next();\n}\n\nexport const config = {\n\tmatcher: ['/docs', '/docs/packages/:package/stable/:member*'],\n};\n"
  },
  {
    "path": "apps/website/src/stores/cmdk.ts",
    "content": "import { atom } from 'jotai';\n\nexport const isCmdKOpenAtom = atom(false);\n"
  },
  {
    "path": "apps/website/src/stores/drawer.ts",
    "content": "import { atom } from 'jotai';\n\nexport const isDrawerOpenAtom = atom(false);\n"
  },
  {
    "path": "apps/website/src/styles/base.css",
    "content": "@import 'tailwindcss';\n\n@plugin 'tailwindcss-react-aria-components';\n@import 'tw-animate-css';\n@plugin '@tailwindcss/typography';\n\n@custom-variant dark (&:where(.dark, .dark *));\n\n@theme {\n\t--font-sans: var(--font-geist-sans);\n\t--font-mono: var(--font-geist-mono);\n\n\t--color-base-neutral-0: #ffffff;\n\t--color-base-neutral-40: #fcfcfc;\n\t--color-base-neutral-60: #fafafa;\n\t--color-base-neutral-80: #f0f0f0;\n\t--color-base-neutral-100: #e6e6e6;\n\t--color-base-neutral-200: #cccccc;\n\t--color-base-neutral-300: #b3b3b3;\n\t--color-base-neutral-400: #999999;\n\t--color-base-neutral-500: #808080;\n\t--color-base-neutral-600: #666666;\n\t--color-base-neutral-700: #4c4c4c;\n\t--color-base-neutral-800: #333333;\n\t--color-base-neutral-900: #191919;\n\n\t--color-base-blurple-50: #e0e3ff;\n\t--color-base-blurple-100: #cdd2ff;\n\t--color-base-blurple-200: #9ea7ff;\n\t--color-base-blurple-300: #7782fa;\n\t--color-base-blurple-400: #5865f2;\n\t--color-base-blurple-500: #3d48c3;\n\t--color-base-blurple-600: #293294;\n\t--color-base-blurple-700: #1a2165;\n\t--color-base-blurple-800: #0e1137;\n\t--color-base-blurple-900: #020208;\n\n\t--color-base-sunset-100: #ffe1df;\n\t--color-base-sunset-200: #ffc3bf;\n\t--color-base-sunset-300: #ffa69e;\n\t--color-base-sunset-400: #ff887e;\n\t--color-base-sunset-500: #ff6a5e;\n\t--color-base-sunset-600: #cc554b;\n\t--color-base-sunset-700: #994038;\n\t--color-base-sunset-800: #662a26;\n\t--color-base-sunset-900: #331513;\n\n\t--color-base-tangerine-100: #fdefd2;\n\t--color-base-tangerine-200: #fce0a5;\n\t--color-base-tangerine-300: #fad078;\n\t--color-base-tangerine-400: #f9c14b;\n\t--color-base-tangerine-500: #f7b11e;\n\t--color-base-tangerine-600: #c68e18;\n\t--color-base-tangerine-700: #946a12;\n\t--color-base-tangerine-800: #63470c;\n\t--color-base-tangerine-900: #312306;\n\n\t--color-base-green-lime-100: #ecefcc;\n\t--color-base-green-lime-200: #d9df99;\n\t--color-base-green-lime-300: #c6cf66;\n\t--color-base-green-lime-400: #b3bf33;\n\t--color-base-green-lime-500: #a0af00;\n\t--color-base-green-lime-600: #808c00;\n\t--color-base-green-lime-700: #606900;\n\t--color-base-green-lime-800: #404600;\n\t--color-base-green-lime-900: #202300;\n\n\t--color-base-crystal-100: #dfedff;\n\t--color-base-crystal-200: #bfdbff;\n\t--color-base-crystal-300: #9ec8ff;\n\t--color-base-crystal-400: #7eb6ff;\n\t--color-base-crystal-500: #5ea4ff;\n\t--color-base-crystal-600: #4b83cc;\n\t--color-base-crystal-700: #386299;\n\t--color-base-crystal-800: #264266;\n\t--color-base-crystal-900: #132133;\n\n\t--text-base-heading-xl: 2.813rem;\n\t--text-base-heading-xl--line-height: 3.25rem;\n\t--text-base-heading-xl--letter-spacing: 0;\n\t--text-base-heading-xl--font-weight: 400;\n\t--text-base-heading-lg: 2.25rem;\n\t--text-base-heading-lg--line-height: 2.75rem;\n\t--text-base-heading-lg--letter-spacing: 0;\n\t--text-base-heading-lg--font-weight: 400;\n\t--text-base-heading-md: 2rem;\n\t--text-base-heading-md--line-height: 2.5rem;\n\t--text-base-heading-md--letter-spacing: 0;\n\t--text-base-heading-md--font-weight: 400;\n\t--text-base-heading-sm: 1.75rem;\n\t--text-base-heading-sm--line-height: 2.25rem;\n\t--text-base-heading-sm--letter-spacing: 0;\n\t--text-base-heading-sm--font-weight: 400;\n\t--text-base-heading-xs: 1.5rem;\n\t--text-base-heading-xs--line-height: 2rem;\n\t--text-base-heading-xs--letter-spacing: 0;\n\t--text-base-heading-xs--font-weight: 400;\n\t--text-base-label-xl: 1.125rem;\n\t--text-base-label-xl--line-height: 1.75rem;\n\t--text-base-label-xl--letter-spacing: 0.5px;\n\t--text-base-label-xl--font-weight: 500;\n\t--text-base-label-lg: 1rem;\n\t--text-base-label-lg--line-height: 1.5rem;\n\t--text-base-label-lg--letter-spacing: 0.5px;\n\t--text-base-label-lg--font-weight: 500;\n\t--text-base-label-md: 1rem;\n\t--text-base-label-md--line-height: 1.5rem;\n\t--text-base-label-md--letter-spacing: 0.5px;\n\t--text-base-label-md--font-weight: 500;\n\t/* --text-base-label-md: 0.875rem;\n\t--text-base-label-md--line-height: 1.25rem;\n\t--text-base-label-md--letter-spacing: 0.1px;\n\t--text-base-label-md--font-weight: 500; */\n\t--text-base-label-sm: 0.75rem;\n\t--text-base-label-sm--line-height: 1rem;\n\t--text-base-label-sm--letter-spacing: 0.5px;\n\t--text-base-label-sm--font-weight: 500;\n\t--text-base-label-xs: 0.688rem;\n\t--text-base-label-xs--line-height: 1rem;\n\t--text-base-label-xs--letter-spacing: 0.5px;\n\t--text-base-label-xs--font-weight: 500;\n\t--text-base-xl: 1.125rem;\n\t--text-base-xl--line-height: 1.75rem;\n\t--text-base-xl--letter-spacing: 0.5px;\n\t--text-base-xl--font-weight: 400;\n\t--text-base-lg: 1rem;\n\t--text-base-lg--line-height: 1.5rem;\n\t--text-base-lg--letter-spacing: 0.5px;\n\t--text-base-lg--font-weight: 400;\n\t--text-base-md: 1rem;\n\t--text-base-md--line-height: 1.5rem;\n\t--text-base-md--letter-spacing: 0.5px;\n\t--text-base-md--font-weight: 400;\n\t/* --text-base-md: 0.875rem;\n\t--text-base-md--line-height: 1.25rem;\n\t--text-base-md--letter-spacing: 0.25px;\n\t--text-base-md--font-weight: 400; */\n\t--text-base-sm: 0.75rem;\n\t--text-base-sm--line-height: 1rem;\n\t--text-base-sm--letter-spacing: 0.4px;\n\t--text-base-sm--font-weight: 400;\n\t--text-base-xs: 0.688rem;\n\t--text-base-xs--line-height: 1rem;\n\t--text-base-xs--letter-spacing: 0.5px;\n\t--text-base-xs--font-weight: 400;\n\n\t--shadow-base-sm: 0 1px 4px 0 #19191929;\n\t--shadow-base-md: 0 3px 3px 0 #19191929;\n\t--shadow-base-lg: 0 3px 6px 0 #1919193d;\n\t--shadow-base-xl: 0 6px 6px 0 #1919193d;\n\t--shadow-base-2xl: 0 8px 8px 0 #19191952;\n}\n\n@layer base {\n\t* {\n\t\tfont-family: var(--font-roboto);\n\t\ttext-rendering: optimizeLegibility;\n\n\t\tscrollbar-width: thin;\n\t}\n\n\thtml.dark .os-scrollbar-handle {\n\t\t--os-handle-bg: rgba(255, 255, 255, 0.5);\n\t\t--os-handle-bg-hover: rgba(255, 255, 255, 0.7);\n\t\t--os-handle-bg-active: rgba(255, 255, 255, 0.7);\n\t}\n\n\t.os-scrollbar-handle {\n\t\t--os-handle-bg: rgba(0, 0, 0, 0.5);\n\t\t--os-handle-bg-hover: rgba(0, 0, 0, 0.7);\n\t\t--os-handle-bg-active: rgba(0, 0, 0, 0.7);\n\t}\n\n\thtml.dark .shiki,\n\thtml.dark .shiki span {\n\t\tcolor: var(--shiki-dark) !important;\n\t\tfont-style: var(--shiki-dark-font-style) !important;\n\t\tfont-weight: var(--shiki-dark-font-weight) !important;\n\t\ttext-decoration: var(--shiki-dark-text-decoration) !important;\n\t}\n\n\tpre {\n\t\t@apply bg-[#f3f3f4]! dark:bg-[#121214]!;\n\t}\n\n\tcode {\n\t\tfont-family: var(--font-geist-mono);\n\t}\n\n\tcode > .line {\n\t\tpadding: 0 1rem;\n\t}\n}\n\n@utility scrollbar-hidden {\n\tscrollbar-width: none;\n}\n\n[cmdk-overlay] {\n\tposition: fixed;\n\tinset: 0;\n\theight: 100dvh;\n\twidth: 100vw;\n\t@apply bg-base-neutral-900/72 z-30;\n}\n\n[cmdk-dialog] {\n\tposition: fixed;\n\tleft: 50%;\n\ttop: 0;\n\tz-index: 50;\n\ttransform: translate(-50%, 0);\n\twidth: 100%;\n\tmax-width: 536px;\n\theight: 100dvh;\n\t@apply h-auto outline-0 md:top-16 md:p-4;\n}\n\n[cmdk-list-sizer] {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 0.5rem;\n\twidth: 100%;\n}\n\n[cmdk-group-heading] {\n\t@apply text-base-label-sm text-base-neutral-600 dark:text-base-neutral-300 h-8 px-3 py-2;\n}\n"
  },
  {
    "path": "apps/website/src/styles/cva.ts",
    "content": "import { defineConfig } from 'cva';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\nconst twMergeConfig = {\n\tclassGroups: {\n\t\t'font-size': [\n\t\t\t'text-base-xs',\n\t\t\t'text-base-sm',\n\t\t\t'text-base-md',\n\t\t\t'text-base-lg',\n\t\t\t'text-base-xl',\n\t\t\t'text-base-label-xs',\n\t\t\t'text-base-label-sm',\n\t\t\t'text-base-label-md',\n\t\t\t'text-base-label-lg',\n\t\t\t'text-base-label-xl',\n\t\t\t'text-base-heading-xs',\n\t\t\t'text-base-heading-sm',\n\t\t\t'text-base-heading-md',\n\t\t\t'text-base-heading-lg',\n\t\t\t'text-base-heading-xl',\n\t\t],\n\t},\n};\n\nconst twMerge = extendTailwindMerge({\n\textend: twMergeConfig,\n});\n\nexport const { cva, cx, compose } = defineConfig({\n\thooks: {\n\t\tonComplete: (className) => twMerge(className),\n\t},\n});\n"
  },
  {
    "path": "apps/website/src/styles/ui/button.ts",
    "content": "import { compose, cva } from '@/styles/cva';\nimport { focusRing } from '@/styles/ui/focusRing';\n\nexport const buttonStyles = compose(\n\tfocusRing,\n\tcva({\n\t\tbase: [\n\t\t\t'text-base-label-md relative inline-flex place-content-center place-items-center gap-2 border border-transparent',\n\t\t\t'*:data-[slot=icon]:size-4.5 *:data-[slot=icon]:shrink-0 print:hidden',\n\t\t],\n\t\tvariants: {\n\t\t\tvariant: {\n\t\t\t\tunset: null,\n\t\t\t\toutline: [\n\t\t\t\t\t'h-10 rounded-sm px-4 py-2.5',\n\t\t\t\t\t'border-base-neutral-300 text-base-neutral-800 bg-base-neutral-0 dark:bg-base-neutral-800 dark:border-base-neutral-500 dark:text-base-neutral-100',\n\t\t\t\t\t'hover:bg-base-neutral-700 hover:text-base-neutral-40 dark:hover:bg-base-neutral-100 dark:hover:text-base-neutral-900 hover:border-transparent',\n\t\t\t\t\t'focus-visible:bg-base-neutral-700 focus-visible:text-base-neutral-40 dark:focus-visible:bg-base-neutral-100 dark:focus-visible:text-base-neutral-900 focus-visible:border-transparent',\n\t\t\t\t\t'pressed:bg-base-neutral-800 pressed:text-base-neutral-40 pressed:border-transparent dark:pressed:bg-base-neutral-60 dark:pressed:text-base-neutral-900',\n\t\t\t\t\t'disabled:bg-base-neutral-40 disabled:text-base-neutral-900 disabled:border-base-neutral-300 dark:disabled:bg-base-neutral-800 dark:disabled:text-base-neutral-40',\n\t\t\t\t],\n\t\t\t\tdiscreet: [\n\t\t\t\t\t'h-10 rounded-sm px-4 py-2.5',\n\t\t\t\t\t'text-base-neutral-800 dark:text-base-neutral-100 bg-transparent',\n\t\t\t\t\t'hover:bg-base-neutral-100 dark:hover:bg-base-neutral-700',\n\t\t\t\t\t'focus-visible:bg-base-neutral-100 dark:focus-visible:bg-base-neutral-700',\n\t\t\t\t\t'pressed:bg-base-neutral-200 dark:pressed:bg-base-neutral-600',\n\t\t\t\t\t'disabled:text-base-neutral-900 dark:disabled:text-base-neutral-40',\n\t\t\t\t],\n\t\t\t\tfilled: [\n\t\t\t\t\t'h-10 rounded-sm px-4 py-2.5',\n\t\t\t\t\t'bg-base-neutral-700 text-base-neutral-40 dark:bg-base-neutral-100 dark:text-base-neutral-900',\n\t\t\t\t\t'hover:bg-base-neutral-500 dark:hover:bg-base-neutral-300',\n\t\t\t\t\t'focus-visible:bg-base-neutral-500 dark:focus-visible:bg-base-neutral-300',\n\t\t\t\t\t'pressed:bg-base-neutral-400 pressed:text-base-neutral-800 dark:pressed:bg-base-neutral-400',\n\t\t\t\t\t'disabled:bg-base-neutral-200 disabled:text-base-neutral-900 dark:disabled:bg-base-neutral-400 dark:disabled:text-base-neutral-40',\n\t\t\t\t],\n\t\t\t\ttonal: [\n\t\t\t\t\t'h-10 rounded-sm px-4 py-2.5',\n\t\t\t\t\t'bg-base-neutral-500 text-base-neutral-40 dark:bg-base-neutral-400 dark:text-base-neutral-900',\n\t\t\t\t\t'hover:bg-base-neutral-700 dark:hover:bg-base-neutral-200',\n\t\t\t\t\t'focus-visible:bg-base-neutral-700 dark:focus-visible:bg-base-neutral-200',\n\t\t\t\t\t'pressed:bg-base-neutral-800 dark:pressed:bg-base-neutral-100',\n\t\t\t\t\t'disabled:bg-base-neutral-200 disabled:text-base-neutral-900 dark:disabled:bg-base-neutral-700 dark:disabled:text-base-neutral-40',\n\t\t\t\t],\n\t\t\t\t'secondary-outline': [\n\t\t\t\t\t'h-10 rounded-sm px-4 py-2.5',\n\t\t\t\t\t'border-base-blurple-200 text-base-neutral-800 bg-base-neutral-0 dark:bg-base-neutral-800 dark:border-base-blurple-500 dark:text-base-neutral-40',\n\t\t\t\t\t'hover:bg-base-blurple-400 hover:text-base-neutral-900 hover:border-transparent',\n\t\t\t\t\t'focus-visible:bg-base-blurple-400 focus-visible:text-base-neutral-900 focus-visible:border-transparent',\n\t\t\t\t\t'pressed:bg-base-blurple-500 pressed:text-base-neutral-40 pressed:border-transparent dark:pressed:bg-base-blurple-300 dark:pressed:text-base-neutral-900',\n\t\t\t\t\t'disabled:bg-base-neutral-0 disabled:text-base-neutral-900 disabled:border-base-neutral-200 dark:text-base-neutral-40 dark:disabled:bg-base-neutral-800 dark:disabled:border-base-neutral-700',\n\t\t\t\t],\n\t\t\t\t'secondary-discreet': [\n\t\t\t\t\t'h-10 rounded-sm px-4 py-2.5',\n\t\t\t\t\t'text-base-blurple-500 dark:text-base-blurple-300 bg-transparent',\n\t\t\t\t\t'hover:bg-base-blurple-50 hover:text-base-blurple-600 dark:hover:bg-base-blurple-700 dark:hover:text-base-blurple-200',\n\t\t\t\t\t'focus-visible:bg-base-blurple-50 focus-visible:text-base-blurple-600 dark:focus-visible:bg-base-blurple-700 dark:focus-visible:text-base-blurple-200',\n\t\t\t\t\t'pressed:bg-base-blurple-100 pressed:text-base-blurple-700 dark:pressed:bg-base-blurple-600 dark:pressed:text-base-blurple-50',\n\t\t\t\t\t'disabled:text-base-neutral-900 dark:disabled:text-base-neutral-40',\n\t\t\t\t],\n\t\t\t\t'secondary-filled': [\n\t\t\t\t\t'h-10 rounded-sm px-4 py-2.5',\n\t\t\t\t\t'bg-base-blurple-400 text-base-neutral-900',\n\t\t\t\t\t'hover:bg-base-blurple-200 dark:hover:bg-base-blurple-600 dark:hover:text-base-neutral-200',\n\t\t\t\t\t'focus-visible:bg-base-blurple-200 dark:focus-visible:bg-base-blurple-600 dark:focus-visible:text-base-neutral-200',\n\t\t\t\t\t'pressed:bg-base-blurple-100 dark:pressed:bg-base-blurple-700 dark:pressed:text-base-neutral-100',\n\t\t\t\t\t'disabled:bg-base-neutral-200 disabled:text-base-neutral-900 dark:disabled:bg-base-neutral-700 dark:disabled:text-base-neutral-40',\n\t\t\t\t],\n\t\t\t\t'secondary-tonal': [\n\t\t\t\t\t'h-10 rounded-sm px-4 py-2.5',\n\t\t\t\t\t'bg-base-blurple-200 text-base-neutral-900 dark:bg-base-blurple-600 dark:text-base-neutral-40',\n\t\t\t\t\t'hover:bg-base-blurple-400 dark:hover:text-base-neutral-900',\n\t\t\t\t\t'focus-visible:bg-base-blurple-400 dark:focus-visible:text-base-neutral-900',\n\t\t\t\t\t'pressed:bg-base-blurple-500 pressed:text-base-neutral-40 dark:pressed:bg-base-blurple-300 dark:pressed:text-base-neutral-900',\n\t\t\t\t\t'disabled:bg-base-neutral-200 disabled:text-base-neutral-900 dark:disabled:bg-base-neutral-700 dark:disabled:text-base-neutral-40',\n\t\t\t\t],\n\t\t\t\t'crystal-tonal': [\n\t\t\t\t\t'h-10 rounded-sm px-4 py-2.5',\n\t\t\t\t\t'bg-base-crystal-300 text-base-neutral-900 dark:bg-base-crystal-700 dark:text-base-neutral-40',\n\t\t\t\t\t'hover:bg-base-crystal-500 dark:hover:text-base-neutral-900',\n\t\t\t\t\t'focus-visible:bg-base-crystal-500 dark:focus-visible:text-base-neutral-900',\n\t\t\t\t\t'pressed:bg-base-crystal-600 pressed:text-base-neutral-40 dark:pressed:bg-base-crystal-400 dark:pressed:text-base-neutral-900',\n\t\t\t\t\t'disabled:bg-base-neutral-200 disabled:text-base-neutral-900 dark:disabled:bg-base-neutral-700 dark:disabled:text-base-neutral-40',\n\t\t\t\t],\n\t\t\t\ttooltip: [\n\t\t\t\t\t'size-6 shrink-0 rounded-full p-0.5',\n\t\t\t\t\t'text-base-neutral-800 dark:text-base-neutral-100',\n\t\t\t\t\t'hover:text-base-crystal-500 dark:hover:text-base-crystal-300',\n\t\t\t\t\t'focus-visible:text-base-crystal-500 dark:focus-visible:text-base-crystal-300',\n\t\t\t\t\t'disabled:text-base-neutral-900 dark:disabled:text-base-neutral-40',\n\t\t\t\t],\n\t\t\t},\n\t\t\tsize: {\n\t\t\t\tdefault: null,\n\t\t\t\ticon: null,\n\t\t\t\tsm: null,\n\t\t\t\txs: null,\n\t\t\t\t'icon-sm': null,\n\t\t\t\t'icon-xs': null,\n\t\t\t},\n\t\t\tisDestructive: {\n\t\t\t\ttrue: null,\n\t\t\t},\n\t\t\tisDark: {\n\t\t\t\ttrue: null,\n\t\t\t},\n\t\t\tisDisabled: {\n\t\t\t\ttrue: 'cursor-default opacity-38 forced-colors:text-[GrayText] forced-colors:group-disabled:text-[GrayText] forced-colors:disabled:text-[GrayText]',\n\t\t\t\tfalse: 'cursor-pointer',\n\t\t\t},\n\t\t\tisPending: {\n\t\t\t\ttrue: 'cursor-default',\n\t\t\t},\n\t\t},\n\t\tcompoundVariants: [\n\t\t\t{\n\t\t\t\tvariant: 'discreet',\n\t\t\t\tisDestructive: true,\n\t\t\t\tclassName: [\n\t\t\t\t\t'text-base-sunset-600 dark:text-base-sunset-400',\n\t\t\t\t\t'hover:bg-base-sunset-100 hover:text-base-sunset-700 dark:hover:bg-base-sunset-800 dark:hover:text-base-sunset-300',\n\t\t\t\t\t'focus-visible:bg-base-sunset-100 focus-visible:text-base-sunset-700 dark:focus-visible:bg-base-sunset-700 dark:focus-visible:text-base-sunset-300',\n\t\t\t\t\t'pressed:bg-base-sunset-200 pressed:text-base-sunset-800 dark:pressed:bg-base-sunset-700 dark:pressed:text-base-sunset-100',\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tvariant: [\n\t\t\t\t\t'filled',\n\t\t\t\t\t'outline',\n\t\t\t\t\t'discreet',\n\t\t\t\t\t'tonal',\n\t\t\t\t\t'secondary-filled',\n\t\t\t\t\t'secondary-outline',\n\t\t\t\t\t'secondary-discreet',\n\t\t\t\t\t'secondary-tonal',\n\t\t\t\t\t'crystal-tonal',\n\t\t\t\t\t'unset',\n\t\t\t\t],\n\t\t\t\tsize: 'icon',\n\t\t\t\tclassName: 'size-10 shrink-0 rounded-full p-2.5',\n\t\t\t},\n\t\t\t{\n\t\t\t\tvariant: ['filled', 'outline'],\n\t\t\t\tsize: 'sm',\n\t\t\t\tclassName: 'h-8 px-3 py-1.5',\n\t\t\t},\n\t\t\t{\n\t\t\t\tvariant: 'filled',\n\t\t\t\tsize: 'sm',\n\t\t\t\tisDark: true,\n\t\t\t\tclassName: [\n\t\t\t\t\t'h-8 px-3 py-1.5',\n\t\t\t\t\t'bg-base-neutral-900 dark:bg-base-neutral-40',\n\t\t\t\t\t'hover:bg-base-neutral-700 dark:hover:bg-base-neutral-200',\n\t\t\t\t\t'focus-visible:bg-base-neutral-700 dark:focus-visible:bg-base-neutral-200',\n\t\t\t\t\t'pressed:bg-base-neutral-600 pressed:text-base-neutral-40 dark:pressed:bg-base-neutral-300 dark:pressed:text-base-neutral-900',\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tvariant: 'filled',\n\t\t\t\tsize: 'xs',\n\t\t\t\tisDark: true,\n\t\t\t\tclassName: [\n\t\t\t\t\t'h-6 gap-1 px-2 py-1',\n\t\t\t\t\t'bg-base-neutral-900 dark:bg-base-neutral-40',\n\t\t\t\t\t'hover:bg-base-neutral-700 dark:hover:bg-base-neutral-200',\n\t\t\t\t\t'focus-visible:bg-base-neutral-700 dark:focus-visible:bg-base-neutral-200',\n\t\t\t\t\t'pressed:bg-base-neutral-600 pressed:text-base-neutral-40 dark:pressed:bg-base-neutral-300 dark:pressed:text-base-neutral-900',\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tvariant: ['filled', 'discreet', 'secondary-tonal', 'crystal-tonal', 'unset'],\n\t\t\t\tsize: 'icon-sm',\n\t\t\t\tclassName: 'size-8 shrink-0 rounded-full p-1.5',\n\t\t\t},\n\t\t\t{\n\t\t\t\tvariant: 'outline',\n\t\t\t\tsize: 'icon-sm',\n\t\t\t\tclassName: 'size-8 shrink-0 rounded-sm p-1.5',\n\t\t\t},\n\t\t\t{\n\t\t\t\tvariant: ['discreet', 'unset'],\n\t\t\t\tsize: 'icon-xs',\n\t\t\t\tclassName: 'size-6 shrink-0 rounded-full p-0.5',\n\t\t\t},\n\t\t],\n\t\tdefaultVariants: {\n\t\t\tvariant: 'outline',\n\t\t\tsize: 'default',\n\t\t},\n\t}),\n);\n"
  },
  {
    "path": "apps/website/src/styles/ui/focusRing.ts",
    "content": "import { cva } from 'cva';\n\nexport const focusRing = cva({\n\tbase: 'outline-base-blurple-400 dark:outline-base-blurple-400 outline-offset-2 forced-colors:outline-[Highlight]',\n\tvariants: {\n\t\tisFocusVisible: {\n\t\t\ttrue: 'outline-2',\n\t\t\tfalse: 'outline-0',\n\t\t},\n\t},\n});\n"
  },
  {
    "path": "apps/website/src/styles/util.ts",
    "content": "import { composeRenderProps } from 'react-aria-components';\nimport { cx } from '@/styles/cva';\n\nexport function composeTailwindRenderProps<Type>(\n\tclassName: string | ((v: Type) => string) | undefined,\n\ttw: string,\n): string | ((v: Type) => string) {\n\treturn composeRenderProps(className, (className) => cx(tw, className));\n}\n"
  },
  {
    "path": "apps/website/src/util/builtinDocumentationLinks.ts",
    "content": "export const BuiltinDocumentationLinks = {\n\t// Built-in types\n\tbigint: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/BigInt',\n\tboolean: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean',\n\tnull: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/null',\n\tnumber: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number',\n\tstring: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String',\n\tsymbol: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Symbol',\n\tundefined: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined',\n\n\t// Built-in classes\n\tAbortSignal: 'https://developer.mozilla.org/docs/Web/API/AbortSignal',\n\tAgent: 'https://undici.nodejs.org/#/docs/api/Agent',\n\tArray: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array',\n\tArrayBuffer: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer',\n\tAsyncGenerator: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator',\n\tAsyncIterable: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Iteration_protocols',\n\tAsyncIterableIterator: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Iteration_protocols',\n\tBuffer: 'https://nodejs.org/api/buffer.html#class-buffer',\n\tChildProcess: 'https://nodejs.org/api/child_process.html#class-childprocess',\n\tDate: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date',\n\tDispatcher: 'https://undici.nodejs.org/#/docs/api/Dispatcher',\n\tError: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error',\n\tFunction: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function',\n\tGenerator: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Generator',\n\tIncomingMessage: 'https://nodejs.org/api/http.html#class-httpincomingmessage',\n\tIterable: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Iteration_protocols',\n\tIterableIterator: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Iteration_protocols',\n\tIterator: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Iterator',\n\tMap: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Map',\n\tMessagePort: 'https://nodejs.org/api/worker_threads.html#class-messageport',\n\tPromise: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise',\n\tRangeError: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError',\n\tReadable: 'https://nodejs.org/api/stream.html#class-streamreadable',\n\tReadableStream: 'https://developer.mozilla.org/docs/Web/API/ReadableStream',\n\tRegExp: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RegExp',\n\tResponse: 'https://developer.mozilla.org/docs/Web/API/Response',\n\tServerResponse: 'https://nodejs.org/api/http.html#class-httpserverresponse',\n\tSet: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Set',\n\tStream: 'https://nodejs.org/api/stream.html#stream',\n\tSymbolConstructor: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Symbol',\n\tTypeError: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/TypeError',\n\tURL: 'https://developer.mozilla.org/docs/Web/API/URL',\n\tURLSearchParams: 'https://developer.mozilla.org/docs/Web/API/URLSearchParams',\n\tWeakMap: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WeakMap',\n\tWeakRef: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WeakRef',\n\tWeakSet: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WeakSet',\n\tWebSocket: 'https://developer.mozilla.org/docs/Web/API/WebSocket',\n\tWorker: 'https://nodejs.org/api/worker_threads.html#class-worker',\n\t'NodeJS.Timeout': 'https://nodejs.org/api/timers.html#class-timeout',\n\n\t// Typed arrays\n\tBigInt64Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array',\n\tBigUint64Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/BigUint64Array',\n\tFloat32Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Float32Array',\n\tFloat64Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Float64Array',\n\tInt16Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Int16Array',\n\tInt32Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Int32Array',\n\tInt8Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Int8Array',\n\tUint16Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint16Array',\n\tUint32Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array',\n\tUint8Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array',\n\tUint8ClampedArray: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray',\n\n\t// TypeScript types\n\tany: 'https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any',\n\tnever: 'https://www.typescriptlang.org/docs/handbook/2/functions.html#never',\n\tobject: 'https://www.typescriptlang.org/docs/handbook/2/functions.html#object',\n\tReadonlyArray: 'https://www.typescriptlang.org/docs/handbook/2/objects.html#the-readonlyarray-type',\n\tReadonlyMap:\n\t\t'https://github.com/microsoft/TypeScript/blob/1416053b9e85ca2344a7a6aa10456d633ea1cd65/src/lib/es2015.collection.d.ts#L38-L43',\n\tReadonlySet:\n\t\t'https://github.com/microsoft/TypeScript/blob/1416053b9e85ca2344a7a6aa10456d633ea1cd65/src/lib/es2015.collection.d.ts#L104-L108',\n\tunknown: 'https://www.typescriptlang.org/docs/handbook/2/functions.html#unknown',\n\tvoid: 'https://www.typescriptlang.org/docs/handbook/2/functions.html#void',\n\n\t// TypeScript utility types\n\tAwaited: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#awaitedtype',\n\tPartial: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype',\n\tRequired: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredtype',\n\tReadonly: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype',\n\tRecord: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type',\n\tPick: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys',\n\tOmit: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys',\n\tExclude: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#excludeuniontype-excludedmembers',\n\tExtract: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#extracttype-union',\n\tNonNullable: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#nonnullabletype',\n\tParameters: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#parameterstype',\n\tConstructorParameters: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#constructorparameterstype',\n\tReturnType: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype',\n\tInstanceType: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#instancetypetype',\n\tThisParameterType: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#thisparametertypetype',\n\tOmitThisParameter: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#omitthisparametertype',\n\tThisType: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#thistypetype',\n\tUppercase: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#uppercasestringtype',\n\tLowercase: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#lowercasestringtype',\n\tCapitalize: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#capitalizestringtype',\n\tUncapitalize: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#uncapitalizestringtype',\n\n\t// External Libraries\n\tAsyncEventEmitter: 'https://github.com/vladfrangu/async_event_emitter',\n\tAsyncQueue: 'https://www.sapphirejs.dev/docs/Documentation/api-utilities/classes/sapphire_async_queue.AsyncQueue',\n\tRedis: 'https://redis.github.io/ioredis/classes/Redis.html',\n\t'prism.opus.Encoder': 'https://amishshah.github.io/prism-media/opus.Encoder.html',\n\t'prism.VolumeTransformer': 'https://amishshah.github.io/prism-media/core.VolumeTransformer.html',\n} as const;\n"
  },
  {
    "path": "apps/website/src/util/constants.ts",
    "content": "export const PACKAGES = [\n\t{ name: 'discord.js' },\n\t{ name: 'discord-api-types' },\n\t{ name: 'brokers' },\n\t{ name: 'builders' },\n\t{ name: 'collection' },\n\t{ name: 'core' },\n\t{ name: 'formatters' },\n\t{ name: 'next' },\n\t{ name: 'proxy' },\n\t{ name: 'rest' },\n\t{ name: 'structures' },\n\t{ name: 'util' },\n\t{ name: 'voice' },\n\t{ name: 'ws' },\n];\n\nexport const PACKAGES_WITH_ENTRY_POINTS = ['discord-api-types'];\n\nexport const DEFAULT_ENTRY_POINT = ['v10'];\n\nexport const DESCRIPTION =\n\t\"discord.js is a powerful Node.js module that allows you to interact with the Discord API very easily. It takes a much more object-oriented approach than most other JS Discord libraries, making your bot's code significantly tidier and easier to comprehend.\";\n"
  },
  {
    "path": "apps/website/src/util/env.ts",
    "content": "export const ENV = {\n\tIS_LOCAL_DEV: process.env.VERCEL_ENV === 'development' || process.env.NEXT_PUBLIC_LOCAL_DEV === 'true',\n\tIS_PREVIEW: process.env.VERCEL_ENV === 'preview',\n\tPORT: process.env.PORT ?? 3_000,\n};\n"
  },
  {
    "path": "apps/website/src/util/fetchDependencies.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { ENV } from './env';\n\nexport async function fetchDependencies({\n\tpackageName,\n\tversion,\n}: {\n\treadonly packageName: string;\n\treadonly version: string;\n}) {\n\tif (ENV.IS_LOCAL_DEV) {\n\t\ttry {\n\t\t\tconst fileContent = await readFile(\n\t\t\t\tjoin(process.cwd(), `../../packages/${packageName}/docs/${packageName}/split/${version}.dependencies.api.json`),\n\t\t\t\t'utf8',\n\t\t\t);\n\n\t\t\tconst parsedDependencies = JSON.parse(fileContent);\n\n\t\t\treturn Object.entries<string>(parsedDependencies)\n\t\t\t\t.filter(([key]) => key.startsWith('@discordjs/') && !key.includes('api-extractor'))\n\t\t\t\t.map(([key, value]) => `${key.replace('@discordjs/', '').replaceAll('.', '-')}-${sanitizeVersion(value)}`);\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t}\n\n\ttry {\n\t\tconst fileContent = await fetch(\n\t\t\t`${process.env.CF_R2_DOCS_BUCKET_URL}/${packageName}/${version}.dependencies.api.json`,\n\t\t\t{ cache: 'no-store' },\n\t\t);\n\t\tconst parsedDependencies = await fileContent.json();\n\n\t\treturn Object.entries<string>(parsedDependencies)\n\t\t\t.filter(([key]) => key.startsWith('@discordjs/') && !key.includes('api-extractor'))\n\t\t\t.map(([key, value]) => `${key.replace('@discordjs/', '').replaceAll('.', '-')}-${sanitizeVersion(value)}`);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nfunction sanitizeVersion(version: string) {\n\treturn version.replaceAll('.', '-').replace(/^[\\^~]/, '');\n}\n"
  },
  {
    "path": "apps/website/src/util/fetchEntryPoints.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { PACKAGES_WITH_ENTRY_POINTS } from './constants';\nimport { ENV } from './env';\n\nexport async function fetchEntryPoints(packageName: string, version: string): Promise<EntryPoint[] | null> {\n\tconst hasEntryPoint = PACKAGES_WITH_ENTRY_POINTS.includes(packageName);\n\n\tif (!hasEntryPoint) {\n\t\treturn [];\n\t}\n\n\tif (ENV.IS_LOCAL_DEV) {\n\t\ttry {\n\t\t\tconst fileContent = await readFile(\n\t\t\t\tjoin(\n\t\t\t\t\tprocess.cwd(),\n\t\t\t\t\t`${hasEntryPoint ? `../../../discord-api-types` : `../../packages/${packageName}`}/docs/${packageName}/split/${version}.entrypoints.api.json`,\n\t\t\t\t),\n\t\t\t\t'utf8',\n\t\t\t);\n\n\t\t\treturn JSON.parse(fileContent);\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tconst fileContent = await fetch(\n\t\t`${process.env.CF_R2_DOCS_BUCKET_URL}/${packageName}/${version}.entrypoints.api.json`,\n\t\t{ cache: 'no-store' },\n\t);\n\n\tif (!fileContent.ok) {\n\t\treturn null;\n\t}\n\n\treturn fileContent.json();\n}\n\nexport interface EntryPoint {\n\treadonly entryPoint: string;\n}\n"
  },
  {
    "path": "apps/website/src/util/fetchLatestVersion.ts",
    "content": "import { Cloudflare } from 'cloudflare';\nimport { PACKAGES_WITH_ENTRY_POINTS, DEFAULT_ENTRY_POINT } from '@/util/constants';\nimport { ENV } from '@/util/env';\n\nconst client = new Cloudflare({\n\tapiToken: process.env.CF_D1_DOCS_API_KEY,\n});\n\nexport async function fetchLatestVersion(packageName: string): Promise<string> {\n\tconst hasEntryPoints = PACKAGES_WITH_ENTRY_POINTS.includes(packageName);\n\n\tif (ENV.IS_LOCAL_DEV) {\n\t\tif (hasEntryPoints) {\n\t\t\treturn ['main', ...DEFAULT_ENTRY_POINT].join('/');\n\t\t}\n\n\t\treturn 'main';\n\t}\n\n\ttry {\n\t\tconst data = await client.d1.database.query(process.env.CF_D1_DOCS_ID!, {\n\t\t\taccount_id: process.env.CF_ACCOUNT_ID!,\n\t\t\tsql: `WITH parsed AS (\n\t\t\t\t\t\tSELECT\n\t\t\t\t\t\t\tversion,\n\t\t\t\t\t\t\tCAST(substr(version, 1, instr(version, '.') - 1) AS INTEGER) AS major,\n\t\t\t\t\t\t\tsubstr(version, instr(version, '.') + 1) AS rest\n\t\t\t\t\t\tFROM documentation\n\t\t\t\t\t\tWHERE name = ? AND version != 'main'\n\t\t\t\t\t\t),\n\t\t\t\t\t\tparsed2 AS (\n\t\t\t\t\t\t\tSELECT\n\t\t\t\t\t\t\t\tversion,\n\t\t\t\t\t\t\t\tmajor,\n\t\t\t\t\t\t\t\tCAST(substr(rest, 1, instr(rest, '.') - 1) AS INTEGER) AS minor,\n\t\t\t\t\t\t\t\tCAST(substr(rest, instr(rest, '.') + 1) AS INTEGER) AS patch\n\t\t\t\t\t\t\tFROM parsed\n\t\t\t\t\t\t)\n\t\t\t\t\t\tSELECT version\n\t\t\t\t\t\tFROM parsed2\n\t\t\t\t\t\tORDER BY major DESC, minor DESC, patch DESC\n\t\t\t\t\t\tLIMIT 1;`,\n\t\t\tparams: [packageName],\n\t\t});\n\n\t\treturn `${((data.result[0]?.results ?? []) as { version: string }[])[0]?.version ?? 'main'}${hasEntryPoints ? ['', ...DEFAULT_ENTRY_POINT].join('/') : ''}`;\n\t} catch {\n\t\treturn '';\n\t}\n}\n"
  },
  {
    "path": "apps/website/src/util/fetchNode.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { PACKAGES_WITH_ENTRY_POINTS } from './constants';\nimport { ENV } from './env';\n\nexport async function fetchNode({\n\tentryPoint,\n\titem,\n\tpackageName,\n\tversion,\n}: {\n\treadonly entryPoint?: string | undefined;\n\treadonly item: any;\n\treadonly packageName: string;\n\treadonly version: string;\n}) {\n\tconst hasEntryPoint = PACKAGES_WITH_ENTRY_POINTS.includes(packageName);\n\tconst normalizedEntryPoint = entryPoint ? `${entryPoint}.` : '';\n\tconst normalizeItem = item.replaceAll(':', '.').toLowerCase();\n\n\tif (ENV.IS_LOCAL_DEV) {\n\t\ttry {\n\t\t\tconst fileContent = await readFile(\n\t\t\t\tjoin(\n\t\t\t\t\tprocess.cwd(),\n\t\t\t\t\t`${hasEntryPoint || normalizedEntryPoint ? `../../../discord-api-types` : `../../packages/${packageName}`}/docs/${packageName}/split/${version}.${normalizedEntryPoint}${normalizeItem}.api.json`,\n\t\t\t\t),\n\t\t\t\t'utf8',\n\t\t\t);\n\n\t\t\treturn JSON.parse(fileContent);\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tconst fileContent = await fetch(\n\t\t`${process.env.CF_R2_DOCS_BUCKET_URL}/${packageName}/${version}.${normalizedEntryPoint}${normalizeItem}.api.json`,\n\t\t{ cache: 'no-store' },\n\t);\n\n\tif (!fileContent.ok) {\n\t\treturn null;\n\t}\n\n\treturn fileContent.json();\n}\n"
  },
  {
    "path": "apps/website/src/util/fetchSitemap.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { PACKAGES_WITH_ENTRY_POINTS } from './constants';\nimport { ENV } from './env';\n\nexport async function fetchSitemap({\n\tentryPoint,\n\tpackageName,\n\tversion,\n}: {\n\treadonly entryPoint?: string | null | undefined;\n\treadonly packageName: string;\n\treadonly version: string;\n}) {\n\tconst hasEntryPoint = PACKAGES_WITH_ENTRY_POINTS.includes(packageName);\n\tconst normalizedEntryPoint = entryPoint ? `${entryPoint}.` : '';\n\n\tif (ENV.IS_LOCAL_DEV) {\n\t\ttry {\n\t\t\tconst fileContent = await readFile(\n\t\t\t\tjoin(\n\t\t\t\t\tprocess.cwd(),\n\t\t\t\t\t`${hasEntryPoint || normalizedEntryPoint ? `../../../discord-api-types` : `../../packages/${packageName}`}/docs/${packageName}/split/${version}.${normalizedEntryPoint}sitemap.api.json`,\n\t\t\t\t),\n\t\t\t\t'utf8',\n\t\t\t);\n\n\t\t\treturn JSON.parse(fileContent);\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tconst fileContent = await fetch(\n\t\t`${process.env.CF_R2_DOCS_BUCKET_URL}/${packageName}/${version}.${normalizedEntryPoint}sitemap.api.json`,\n\t\t{ cache: 'no-store' },\n\t);\n\n\tif (!fileContent.ok) {\n\t\treturn null;\n\t}\n\n\treturn fileContent.json();\n}\n"
  },
  {
    "path": "apps/website/src/util/fetchVersions.ts",
    "content": "import type Cloudflare from 'cloudflare';\nimport { ENV } from './env';\n\nexport async function fetchVersions(packageName: string) {\n\tif (ENV.IS_LOCAL_DEV) {\n\t\treturn [{ version: 'main' }];\n\t}\n\n\ttry {\n\t\tconst response = await fetch(\n\t\t\t`https://api.cloudflare.com/client/v4/accounts/${process.env.CF_ACCOUNT_ID}/d1/database/${process.env.CF_D1_DOCS_ID}/query`,\n\t\t\t{\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${process.env.CF_D1_DOCS_API_KEY}`,\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t},\n\t\t\t\tmethod: 'POST',\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tsql: `WITH parsed AS (\n\t\t\t\t\t\t\t\tSELECT\n\t\t\t\t\t\t\t\t\t\tversion,\n\t\t\t\t\t\t\t\t\t\tCASE \n\t\t\t\t\t\t\t\t\t\t\t\tWHEN version = 'main' THEN NULL \n\t\t\t\t\t\t\t\t\t\t\t\tELSE CAST(substr(version, 1, instr(version, '.') - 1) AS INTEGER)\n\t\t\t\t\t\t\t\t\t\tEND AS major,\n\t\t\t\t\t\t\t\t\t\tCASE \n\t\t\t\t\t\t\t\t\t\t\t\tWHEN version = 'main' THEN NULL \n\t\t\t\t\t\t\t\t\t\t\t\tELSE substr(version, instr(version, '.') + 1)\n\t\t\t\t\t\t\t\t\t\tEND AS rest\n\t\t\t\t\t\t\t\tFROM documentation\n\t\t\t\t\t\t\t\tWHERE name = ?\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tparsed2 AS (\n\t\t\t\t\t\t\t\t\t\tSELECT\n\t\t\t\t\t\t\t\t\t\t\t\tversion,\n\t\t\t\t\t\t\t\t\t\t\t\tmajor,\n\t\t\t\t\t\t\t\t\t\t\t\tCASE \n\t\t\t\t\t\t\t\t\t\t\t\t\t\tWHEN version = 'main' THEN NULL \n\t\t\t\t\t\t\t\t\t\t\t\t\t\tELSE CAST(substr(rest, 1, instr(rest, '.') - 1) AS INTEGER)\n\t\t\t\t\t\t\t\t\t\t\t\tEND AS minor,\n\t\t\t\t\t\t\t\t\t\t\t\tCASE \n\t\t\t\t\t\t\t\t\t\t\t\t\t\tWHEN version = 'main' THEN NULL \n\t\t\t\t\t\t\t\t\t\t\t\t\t\tELSE CAST(substr(rest, instr(rest, '.') + 1) AS INTEGER)\n\t\t\t\t\t\t\t\t\t\t\t\tEND AS patch\n\t\t\t\t\t\t\t\t\t\tFROM parsed\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tSELECT version\n\t\t\t\t\t\t\t\tFROM parsed2\n\t\t\t\t\t\t\t\tORDER BY \n\t\t\t\t\t\t\t\t\t\tCASE WHEN version = 'main' THEN 0 ELSE 1 END,\n\t\t\t\t\t\t\t\t\t\tmajor DESC, \n\t\t\t\t\t\t\t\t\t\tminor DESC, \n\t\t\t\t\t\t\t\t\t\tpatch DESC;`,\n\t\t\t\t\tparams: [packageName],\n\t\t\t\t}),\n\t\t\t},\n\t\t);\n\n\t\tconst data = (await response.json()) as Cloudflare.D1Resource.Database.QueryResultsSinglePage;\n\t\treturn (data.result[0]?.results ?? []) as { version: string }[];\n\t} catch {\n\t\treturn [];\n\t}\n}\n"
  },
  {
    "path": "apps/website/src/util/parseDocsPathParams.ts",
    "content": "import { DEFAULT_ENTRY_POINT } from './constants';\n\nexport function parseDocsPathParams(item: string[] | undefined): {\n\tentryPoints: string[];\n\tfoundItem: string | undefined;\n} {\n\tif (!item?.length) {\n\t\treturn { entryPoints: [], foundItem: undefined };\n\t}\n\n\tconst lastElement = item.at(-1);\n\tconst hasTypeMarker = lastElement?.includes('%3A');\n\n\treturn {\n\t\tentryPoints: hasTypeMarker ? item.slice(0, -1) : lastElement?.length === 0 ? DEFAULT_ENTRY_POINT : item,\n\t\tfoundItem: hasTypeMarker ? lastElement : undefined,\n\t};\n}\n"
  },
  {
    "path": "apps/website/src/util/resolveNodeKind.tsx",
    "content": "import { VscSymbolClass } from '@react-icons/all-files/vsc/VscSymbolClass';\nimport { VscSymbolEnum } from '@react-icons/all-files/vsc/VscSymbolEnum';\nimport { VscSymbolEnumMember } from '@react-icons/all-files/vsc/VscSymbolEnumMember';\nimport { VscSymbolEvent } from '@react-icons/all-files/vsc/VscSymbolEvent';\nimport { VscSymbolInterface } from '@react-icons/all-files/vsc/VscSymbolInterface';\nimport { VscSymbolMethod } from '@react-icons/all-files/vsc/VscSymbolMethod';\nimport { VscSymbolParameter } from '@react-icons/all-files/vsc/VscSymbolParameter';\nimport { VscSymbolProperty } from '@react-icons/all-files/vsc/VscSymbolProperty';\nimport { VscSymbolVariable } from '@react-icons/all-files/vsc/VscSymbolVariable';\n\nexport function resolveKind(item: any, size = 24) {\n\tswitch (item) {\n\t\tcase 'Class':\n\t\t\treturn <VscSymbolClass aria-hidden className=\"flex-shrink-0\" size={size} />;\n\t\tcase 'Enum':\n\t\t\treturn <VscSymbolEnum aria-hidden className=\"flex-shrink-0\" size={size} />;\n\t\tcase 'EnumMember':\n\t\t\treturn <VscSymbolEnumMember aria-hidden className=\"flex-shrink-0\" size={size} />;\n\t\tcase 'Interface':\n\t\t\treturn <VscSymbolInterface aria-hidden className=\"flex-shrink-0\" size={size} />;\n\t\tcase 'Property':\n\t\tcase 'PropertySignature':\n\t\t\treturn <VscSymbolProperty aria-hidden className=\"flex-shrink-0\" size={size} />;\n\t\tcase 'TypeAlias':\n\t\tcase 'Variable':\n\t\t\treturn <VscSymbolVariable aria-hidden className=\"flex-shrink-0\" size={size} />;\n\t\tcase 'Event':\n\t\t\treturn <VscSymbolEvent aria-hidden className=\"flex-shrink-0\" size={size} />;\n\t\tcase 'Parameter':\n\t\tcase 'TypeParameter':\n\t\t\treturn <VscSymbolParameter aria-hidden className=\"flex-shrink-0\" size={size} />;\n\t\tdefault:\n\t\t\treturn <VscSymbolMethod aria-hidden className=\"flex-shrink-0\" size={size} />;\n\t}\n}\n"
  },
  {
    "path": "apps/website/src/util/shiki.bundle.ts",
    "content": "/* Generate by @shikijs/codegen */\nimport type {\n\tDynamicImportLanguageRegistration,\n\tDynamicImportThemeRegistration,\n\tHighlighterGeneric,\n} from 'shiki/types';\nimport { createSingletonShorthands, createdBundledHighlighter } from 'shiki/core';\nimport { createJavaScriptRegexEngine } from 'shiki/engine-javascript.mjs';\n\ntype BundledLanguage = 'typescript' | 'ts' | 'javascript' | 'js' | 'shellscript' | 'bash' | 'sh' | 'shell' | 'zsh';\ntype BundledTheme = 'github-light' | 'github-dark-dimmed';\ntype Highlighter = HighlighterGeneric<BundledLanguage, BundledTheme>;\n\nconst bundledLanguages = {\n\ttypescript: () => import('shiki/langs/typescript.mjs'),\n\tts: () => import('shiki/langs/typescript.mjs'),\n\tjavascript: () => import('shiki/langs/javascript.mjs'),\n\tjs: () => import('shiki/langs/javascript.mjs'),\n\tshellscript: () => import('shiki/langs/shellscript.mjs'),\n\tbash: () => import('shiki/langs/shellscript.mjs'),\n\tsh: () => import('shiki/langs/shellscript.mjs'),\n\tshell: () => import('shiki/langs/shellscript.mjs'),\n\tzsh: () => import('shiki/langs/shellscript.mjs'),\n} as Record<BundledLanguage, DynamicImportLanguageRegistration>;\n\nconst bundledThemes = {\n\t'github-light': () => import('shiki/themes/github-light.mjs'),\n\t'github-dark-dimmed': () => import('shiki/themes/github-dark-dimmed.mjs'),\n} as Record<BundledTheme, DynamicImportThemeRegistration>;\n\nconst createHighlighter = /* @__PURE__ */ createdBundledHighlighter<BundledLanguage, BundledTheme>({\n\tlangs: bundledLanguages,\n\tthemes: bundledThemes,\n\tengine: () => createJavaScriptRegexEngine(),\n});\n\nconst {\n\tcodeToHtml,\n\tcodeToHast,\n\tcodeToTokensBase,\n\tcodeToTokens,\n\tcodeToTokensWithThemes,\n\tgetSingletonHighlighter,\n\tgetLastGrammarState,\n} = /* @__PURE__ */ createSingletonShorthands<BundledLanguage, BundledTheme>(createHighlighter);\n\nexport {\n\tbundledLanguages,\n\tbundledThemes,\n\tcodeToHast,\n\tcodeToHtml,\n\tcodeToTokens,\n\tcodeToTokensBase,\n\tcodeToTokensWithThemes,\n\tcreateHighlighter,\n\tgetLastGrammarState,\n\tgetSingletonHighlighter,\n};\nexport type { BundledLanguage, BundledTheme, Highlighter };\n"
  },
  {
    "path": "apps/website/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.tsx\",\n\t\t\"*.js\",\n\t\t\"*.jsx\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.tsx\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.jsx\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "apps/website/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t// Modules\n\t\t\"baseUrl\": \".\",\n\n\t\t// Emit\n\t\t\"declaration\": false,\n\t\t\"declarationMap\": false,\n\t\t\"noEmit\": true,\n\t\t\"outDir\": \"dist\",\n\n\t\t// Interop Constraints\n\t\t\"esModuleInterop\": true,\n\t\t\"allowJs\": true,\n\t\t\"incremental\": true,\n\t\t\"skipLibCheck\": true,\n\n\t\t// Language and Environment\n\t\t\"jsx\": \"preserve\",\n\t\t\"lib\": [\"ESNext\", \"DOM\", \"DOM.Iterable\"],\n\n\t\t\"plugins\": [\n\t\t\t{\n\t\t\t\t\"name\": \"next\"\n\t\t\t}\n\t\t],\n\n\t\t\"paths\": {\n\t\t\t\"@/*\": [\"./src/*\"]\n\t\t}\n\t},\n\t\"include\": [\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.tsx\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.jsx\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"next-env.d.ts\",\n\t\t\".next/types/**/*.ts\",\n\t\t\"vitest.shims.d.ts\",\n\t\t\"__tests__/**/*.ts\",\n\t\t\"__tests__/**/*.tsx\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "apps/website/wrangler.jsonc",
    "content": "{\n\t\"$schema\": \"node_modules/wrangler/config-schema.json\",\n\t\"main\": \".open-next/worker.js\",\n\t\"name\": \"discordjs-website\",\n\t\"keep_names\": false,\n\t\"compatibility_date\": \"2025-10-04\",\n\t\"compatibility_flags\": [\"nodejs_compat\"],\n\t\"assets\": {\n\t\t\"directory\": \".open-next/assets\",\n\t\t\"binding\": \"ASSETS\",\n\t},\n\t\"observability\": {\n\t\t\"logs\": {\n\t\t\t\"enabled\": true,\n\t\t\t\"head_sampling_rate\": 1,\n\t\t\t\"invocation_logs\": true,\n\t\t},\n\t},\n}\n"
  },
  {
    "path": "biome.json",
    "content": "{\n\t\"$schema\": \"https://biomejs.dev/schemas/1.5.3/schema.json\",\n\t\"formatter\": {\n\t\t\"enabled\": true,\n\t\t\"formatWithErrors\": false,\n\t\t\"indentStyle\": \"tab\",\n\t\t\"indentWidth\": 2,\n\t\t\"lineWidth\": 120,\n\t\t\"lineEnding\": \"lf\",\n\t\t\"ignore\": [\n\t\t\t\".turbo\",\n\t\t\t\".vercel\",\n\t\t\t\".next\",\n\t\t\t\"coverage\",\n\t\t\t\"dist\",\n\t\t\t\"dist-docs\",\n\t\t\t\"docs\",\n\t\t\t\"CHANGELOG.md\",\n\t\t\t\"tsup.config.bundled*\"\n\t\t]\n\t},\n\t\"javascript\": {\n\t\t\"formatter\": {\n\t\t\t\"enabled\": true,\n\t\t\t\"quoteStyle\": \"single\",\n\t\t\t\"quoteProperties\": \"asNeeded\",\n\t\t\t\"trailingComma\": \"all\",\n\t\t\t\"semicolons\": \"always\"\n\t\t}\n\t},\n\t\"files\": {\n\t\t\"ignoreUnknown\": true,\n\t\t\"maxSize\": 1000000\n\t}\n}\n"
  },
  {
    "path": "codecov.yml",
    "content": "codecov:\n  notify:\n    after_n_builds: 6\n  strict_yaml_branch: main\n\ncoverage:\n  range: '50...90'\n  status:\n    project:\n      default:\n        target: auto\n        threshold: 5%\n        informational: true\n    patch: off\n\nflag_management:\n  default_rules:\n    carryforward: true\n    statuses:\n      - type: project\n        target: auto\n        threshold: 2%\n        informational: true\n\ncomment:\n  require_changes: true\n  after_n_builds: 6\n"
  },
  {
    "path": "eslint.config.js",
    "content": "import unocss from '@unocss/eslint-plugin';\nimport { defineConfig } from 'eslint/config';\nimport common from 'eslint-config-neon/common';\nimport edge from 'eslint-config-neon/edge';\nimport jsxa11y from 'eslint-config-neon/jsx-a11y';\nimport next from 'eslint-config-neon/next';\nimport node from 'eslint-config-neon/node';\nimport prettier from 'eslint-config-neon/prettier';\nimport react from 'eslint-config-neon/react';\nimport typescript from 'eslint-config-neon/typescript';\nimport { createTypeScriptImportResolver } from 'eslint-import-resolver-typescript';\nimport reactCompiler from 'eslint-plugin-react-compiler';\n// import oxlint from 'eslint-plugin-oxlint';\nimport merge from 'lodash.merge';\n\nconst commonFiles = '{js,mjs,cjs,ts,mts,cts,jsx,tsx}';\n\nconst commonRuleset = merge(...common, { files: [`**/*${commonFiles}`] });\n\nconst nodeRuleset = merge(...node, {\n\tfiles: [`**/*${commonFiles}`],\n\trules: {\n\t\t'no-restricted-globals': 0,\n\t\t'n/prefer-global/buffer': [2, 'never'],\n\t\t'n/prefer-global/console': [2, 'always'],\n\t\t'n/prefer-global/process': [2, 'never'],\n\t\t'n/prefer-global/text-decoder': [2, 'always'],\n\t\t'n/prefer-global/text-encoder': [2, 'always'],\n\t\t'n/prefer-global/url-search-params': [2, 'always'],\n\t\t'n/prefer-global/url': [2, 'always'],\n\t},\n});\n\nconst nodeBinRuleset = {\n\tfiles: [`**/bin/*{js,mjs,cjs,ts,mts,cts}`],\n\trules: {\n\t\t'n/shebang': [0],\n\t},\n};\n\nconst typeScriptRuleset = merge(...typescript, {\n\tfiles: [`**/*${commonFiles}`],\n\tignores: [`packages/discord.js/**/*.{js,mjs,cjs}`],\n\tlanguageOptions: {\n\t\tparserOptions: {\n\t\t\twarnOnUnsupportedTypeScriptVersion: false,\n\t\t\tallowAutomaticSingleRunInference: true,\n\t\t\tproject: ['tsconfig.eslint.json', 'apps/*/tsconfig.eslint.json', 'packages/*/tsconfig.eslint.json'],\n\t\t},\n\t},\n\trules: {\n\t\t'@typescript-eslint/consistent-type-definitions': [2, 'interface'],\n\t\t'@typescript-eslint/naming-convention': [\n\t\t\t2,\n\t\t\t{\n\t\t\t\tselector: 'typeParameter',\n\t\t\t\tformat: ['PascalCase'],\n\t\t\t\tcustom: {\n\t\t\t\t\tregex: '^\\\\w{3,}',\n\t\t\t\t\tmatch: true,\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t},\n\tsettings: {\n\t\t'import-x/resolver-next': [\n\t\t\tcreateTypeScriptImportResolver({\n\t\t\t\tnoWarnOnMultipleProjects: true,\n\t\t\t\tproject: ['tsconfig.eslint.json', 'apps/*/tsconfig.eslint.json', 'packages/*/tsconfig.eslint.json'],\n\t\t\t}),\n\t\t],\n\t},\n});\n\nconst nextAppsGlob = `apps/{guide,website}/**/*${commonFiles}`;\n\nconst reactRuleset = merge(...react, {\n\tfiles: [nextAppsGlob, `packages/ui/**/*${commonFiles}`],\n\tplugins: {\n\t\t'react-compiler': reactCompiler,\n\t},\n\trules: {\n\t\t'react/jsx-handler-names': 0,\n\t\t'react-refresh/only-export-components': [0, { allowConstantExport: true }],\n\t\t'react-compiler/react-compiler': 2,\n\t\t'jsdoc/no-bad-blocks': 0,\n\t\t'tsdoc/syntax': 0,\n\t\t'@typescript-eslint/unbound-method': 0,\n\t},\n});\n\nconst jsxa11yRuleset = merge(...jsxa11y, { files: [nextAppsGlob, `packages/ui/**/*${commonFiles}`] });\n\nconst nextRuleset = merge(...next, { files: [nextAppsGlob] });\n\nconst edgeRuleset = merge(...edge, { files: [nextAppsGlob] });\n\nconst prettierRuleset = merge(...prettier, { files: [`**/*${commonFiles}`] });\n\n// const oxlintRuleset = merge({ rules: oxlint.rules }, { files: [`**/*${commonFiles}`] });\n\nexport default defineConfig(\n\t{\n\t\tignores: [\n\t\t\t'**/node_modules/',\n\t\t\t'.git/',\n\t\t\t'**/dist/',\n\t\t\t'**/template/',\n\t\t\t'**/coverage/',\n\t\t\t'**/storybook-static/',\n\t\t\t'**/.next/',\n\t\t\t'**/shiki.bundle.ts',\n\t\t],\n\t},\n\tcommonRuleset,\n\tnodeRuleset,\n\tnodeBinRuleset,\n\ttypeScriptRuleset,\n\t{\n\t\tfiles: ['**/*{ts,mts,cts,tsx}'],\n\t\trules: { 'jsdoc/no-undefined-types': 0 },\n\t},\n\t{\n\t\tfiles: [`packages/{api-extractor,brokers,create-discord-bot,docgen,ws}/**/*${commonFiles}`],\n\t\trules: { 'n/no-sync': 0 },\n\t},\n\t{\n\t\tfiles: [`packages/api-extractor/**/*${commonFiles}`],\n\t\trules: {\n\t\t\t'consistent-this': 0,\n\t\t\t'unicorn/no-this-assignment': 0,\n\t\t\t'@typescript-eslint/no-duplicate-type-constituents': 0,\n\t\t\t'@typescript-eslint/no-this-alias': 0,\n\t\t},\n\t},\n\t{\n\t\tfiles: [`packages/api-extractor-model/**/*${commonFiles}`],\n\t\trules: {\n\t\t\t'@typescript-eslint/no-namespace': 0,\n\t\t\t'no-prototype-builtins': 0,\n\t\t\t'consistent-this': 0,\n\t\t\t'unicorn/no-this-assignment': 0,\n\t\t\t'@typescript-eslint/no-this-alias': 0,\n\t\t},\n\t},\n\t{\n\t\tfiles: [`packages/{api-extractor,api-extractor-model,api-extractor-utils}/**/*${commonFiles}`],\n\t\trules: {\n\t\t\t'@typescript-eslint/naming-convention': 0,\n\t\t\t'@typescript-eslint/no-empty-interface': 0,\n\t\t\t'@typescript-eslint/no-empty-object-type': 0,\n\t\t\t'@typescript-eslint/switch-exhaustiveness-check': 0,\n\t\t\t'@typescript-eslint/prefer-nullish-coalescing': 0,\n\t\t},\n\t},\n\t{\n\t\tfiles: [`packages/builders/**/*${commonFiles}`],\n\t\trules: {\n\t\t\t'@typescript-eslint/no-empty-object-type': 0,\n\t\t\t'jsdoc/valid-types': 0,\n\t\t},\n\t},\n\t{\n\t\tfiles: [`packages/discord.js/**/*.{js,cjs}`],\n\t\tlanguageOptions: {\n\t\t\tsourceType: 'commonjs',\n\t\t\tparserOptions: {\n\t\t\t\tecmaFeatures: {\n\t\t\t\t\timpliedStrict: false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tsettings: {\n\t\t\tjsdoc: {\n\t\t\t\ttagNamePreference: {\n\t\t\t\t\taugments: 'extends',\n\t\t\t\t\tfires: 'emits',\n\t\t\t\t\tfunction: 'method',\n\t\t\t\t},\n\t\t\t\tpreferredTypes: {\n\t\t\t\t\tobject: 'Object',\n\t\t\t\t\tnull: 'void',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\trules: {\n\t\t\t'jsdoc/no-undefined-types': 0,\n\t\t\t'jsdoc/no-defaults': 0,\n\t\t\t'no-eq-null': 0,\n\t\t\tstrict: ['error', 'global'],\n\n\t\t\t'no-restricted-syntax': [\n\t\t\t\t'error',\n\t\t\t\t{\n\t\t\t\t\tselector: \"AssignmentExpression[left.object.name='module'][left.property.name='exports']\",\n\t\t\t\t\tmessage: 'Use named exports instead of module.exports',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tselector:\n\t\t\t\t\t\t\"VariableDeclarator[init.callee.name='require'][init.arguments.0.value=/^\\\\./]:not([id.type='ObjectPattern'])\",\n\t\t\t\t\tmessage: 'Use object destructuring when requiring local modules',\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t},\n\t{\n\t\tfiles: [`packages/discord.js/src/client/websocket/handlers/*.js`],\n\t\trules: {\n\t\t\t'no-restricted-syntax': [\n\t\t\t\t'error',\n\t\t\t\t{\n\t\t\t\t\tselector:\n\t\t\t\t\t\t\"VariableDeclarator[init.callee.name='require'][init.arguments.0.value=/^\\\\./]:not([id.type='ObjectPattern'])\",\n\t\t\t\t\tmessage: 'Use object destructuring when requiring local modules',\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t},\n\t{\n\t\tfiles: [`packages/discord.js/typings/*{d.ts,test-d.ts,d.mts,test-d.mts}`],\n\t\trules: {\n\t\t\t'@typescript-eslint/no-unsafe-declaration-merging': 0,\n\t\t\t'@typescript-eslint/no-empty-object-type': 0,\n\t\t\t'@typescript-eslint/no-use-before-define': 0,\n\t\t\t'@typescript-eslint/consistent-type-imports': 0,\n\t\t\t'@stylistic/lines-between-class-members': 0,\n\t\t\t'@typescript-eslint/no-duplicate-type-constituents': 0,\n\t\t\t'no-restricted-syntax': [\n\t\t\t\t2,\n\t\t\t\t{\n\t\t\t\t\tselector:\n\t\t\t\t\t\t'MethodDefinition[key.name!=on][key.name!=once][key.name!=off] > TSEmptyBodyFunctionExpression > Identifier :not(TSTypeOperator[operator=readonly]) > TSArrayType',\n\t\t\t\t\tmessage: 'Array parameters on methods must be readonly',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tselector:\n\t\t\t\t\t\t'MethodDefinition > TSEmptyBodyFunctionExpression > Identifier TSTypeReference > Identifier[name=Collection]',\n\t\t\t\t\tmessage: 'Parameters of type Collection on methods must use ReadonlyCollection',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tselector: 'TSDeclareFunction > Identifier :not(TSTypeOperator[operator=readonly]) > TSArrayType',\n\t\t\t\t\tmessage: 'Array parameters on functions must be readonly',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tselector: 'TSDeclareFunction Identifier TSTypeReference > Identifier[name=Collection]',\n\t\t\t\t\tmessage: 'Parameters of type Collection on functions must use ReadonlyCollection',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tselector: 'TSInterfaceDeclaration TSPropertySignature :not(TSTypeOperator[operator=readonly]) > TSArrayType',\n\t\t\t\t\tmessage: 'Array properties on interfaces must be readonly',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tselector: 'TSInterfaceDeclaration TSPropertySignature TSTypeReference > Identifier[name=Collection]',\n\t\t\t\t\tmessage: 'Interface properties of type Collection must use ReadonlyCollection',\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t},\n\t{\n\t\tfiles: [`packages/rest/**/*${commonFiles}`],\n\t\trules: {\n\t\t\t'unicorn/prefer-node-protocol': 0,\n\t\t},\n\t},\n\t{\n\t\tfiles: [`packages/structures/**/*${commonFiles}`],\n\t\trules: {\n\t\t\t'@typescript-eslint/no-empty-interface': 0,\n\t\t\t'@typescript-eslint/no-empty-object-type': 0,\n\t\t\t'@typescript-eslint/no-unsafe-declaration-merging': 0,\n\t\t},\n\t},\n\t{\n\t\tfiles: [`packages/voice/**/*${commonFiles}`],\n\t\trules: {\n\t\t\t'@typescript-eslint/no-unsafe-declaration-merging': 0,\n\t\t},\n\t},\n\treactRuleset,\n\tjsxa11yRuleset,\n\t{\n\t\tfiles: [`packages/ui/**/*${commonFiles}`],\n\t\tplugins: { '@unocss': unocss },\n\t\trules: {\n\t\t\t'@unocss/order': 2,\n\t\t},\n\t},\n\tnextRuleset,\n\tedgeRuleset,\n\t{\n\t\tfiles: ['**/*{js,mjs,cjs,jsx}'],\n\t\trules: { 'tsdoc/syntax': 0 },\n\t},\n\tprettierRuleset,\n\t// oxlintRuleset,\n);\n"
  },
  {
    "path": "package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/discord.js\",\n\t\"version\": \"0.0.0\",\n\t\"description\": \"A powerful library for interacting with the Discord API\",\n\t\"private\": true,\n\t\"scripts\": {\n\t\t\"build\": \"turbo run build --concurrency=4\",\n\t\t\"build:affected\": \"turbo run build --filter=...[origin/main] --concurrency=4\",\n\t\t\"build:apps\": \"turbo run build:local --filter=...{apps/*} --concurrency=4\",\n\t\t\"build:apps:affected\": \"turbo run build:local --filter=...{apps/*}[origin/main] --concurrency=4\",\n\t\t\"test\": \"turbo run test --concurrency=4\",\n\t\t\"test:affected\": \"turbo run test --filter=...[origin/main] --concurrency=4\",\n\t\t\"lint\": \"turbo run lint --concurrency=4\",\n\t\t\"lint:affected\": \"turbo run lint --filter=...[origin/main] --concurrency=4\",\n\t\t\"format\": \"turbo run format --concurrency=4\",\n\t\t\"format:affected\": \"turbo run format --filter=...[origin/main] --concurrency=4\",\n\t\t\"fmt\": \"turbo run format --concurrency=4\",\n\t\t\"fmt:affected\": \"turbo run format --filter=...[origin/main] --concurrency=4\",\n\t\t\"docs\": \"turbo run docs --concurrency=4\",\n\t\t\"docs:affected\": \"turbo run docs --filter=...[origin/main] --concurrency=4\",\n\t\t\"prepare\": \"is-ci || husky\",\n\t\t\"update\": \"pnpm --recursive update --interactive\",\n\t\t\"update:latest\": \"pnpm --recursive update --interactive --latest\",\n\t\t\"create-package\": \"turbo gen create-package --args\",\n\t\t\"release\": \"bun ./packages/actions/src/releasePackages/index.ts\"\n\t},\n\t\"type\": \"module\",\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"Amish Shah <amishshah.2k@gmail.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\"\n\t],\n\t\"keywords\": [\n\t\t\"discord\",\n\t\t\"api\",\n\t\t\"bot\",\n\t\t\"client\",\n\t\t\"node\",\n\t\t\"discordapp\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"devDependencies\": {\n\t\t\"@commitlint/cli\": \"^20.4.2\",\n\t\t\"@commitlint/config-angular\": \"^20.4.2\",\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@favware/npm-deprecate\": \"^2.0.0\",\n\t\t\"@types/lodash.merge\": \"^4.6.9\",\n\t\t\"@unocss/eslint-plugin\": \"^66.6.0\",\n\t\t\"@vitest/coverage-v8\": \"^4.0.18\",\n\t\t\"conventional-changelog-cli\": \"^5.0.0\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-import-resolver-typescript\": \"^4.4.4\",\n\t\t\"eslint-plugin-react-compiler\": \"19.1.0-rc.2\",\n\t\t\"husky\": \"^9.1.7\",\n\t\t\"is-ci\": \"^4.1.0\",\n\t\t\"lint-staged\": \"^16.2.7\",\n\t\t\"lodash.merge\": \"^4.6.2\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"typescript-eslint\": \"^8.56.0\",\n\t\t\"unocss\": \"^66.6.0\",\n\t\t\"vercel\": \"^49.2.0\",\n\t\t\"vitest\": \"^4.0.18\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"packageManager\": \"pnpm@10.30.1\"\n}\n"
  },
  {
    "path": "packages/actions/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/actions/.lintstagedrc.cjs",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/actions/.prettierignore",
    "content": ".turbo\ncoverage\ndist\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/actions/.prettierrc.cjs",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/actions/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2022 Noel Buechler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/actions/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested.  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/actions\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/actions/__tests__/formatTag.test.ts",
    "content": "import { describe, test, expect } from 'vitest';\nimport { formatTag } from '../src/index.js';\n\ndescribe('Format Tag', () => {\n\ttest('GIVEN tag with a prefix THEN format tag to not contain the prefix', () => {\n\t\texpect(formatTag('@discordjs/rest@0.4.0')).toEqual({\n\t\t\tisSubpackage: true,\n\t\t\tpackage: 'rest',\n\t\t\tsemver: '0.4.0',\n\t\t});\n\t\texpect(formatTag('@discordjs/collection@0.6.0')).toEqual({\n\t\t\tisSubpackage: true,\n\t\t\tpackage: 'collection',\n\t\t\tsemver: '0.6.0',\n\t\t});\n\t\texpect(formatTag('@discordjs/proxy@0.1.0')).toEqual({\n\t\t\tisSubpackage: true,\n\t\t\tpackage: 'proxy',\n\t\t\tsemver: '0.1.0',\n\t\t});\n\t\texpect(formatTag('@discordjs/builders@0.13.0')).toEqual({\n\t\t\tisSubpackage: true,\n\t\t\tpackage: 'builders',\n\t\t\tsemver: '0.13.0',\n\t\t});\n\t\texpect(formatTag('@discordjs/voice@0.9.0')).toEqual({\n\t\t\tisSubpackage: true,\n\t\t\tpackage: 'voice',\n\t\t\tsemver: '0.9.0',\n\t\t});\n\t});\n\n\ttest('GIVEN tag with no prefix THEN return tag', () => {\n\t\texpect(formatTag('13.5.1')).toEqual({\n\t\t\tisSubpackage: false,\n\t\t\tpackage: 'discord.js',\n\t\t\tsemver: '13.5.1',\n\t\t});\n\t\texpect(formatTag('13.7.0')).toEqual({\n\t\t\tisSubpackage: false,\n\t\t\tpackage: 'discord.js',\n\t\t\tsemver: '13.7.0',\n\t\t});\n\t\texpect(formatTag('create-discord-bot@1.0.0')).toEqual({\n\t\t\tisSubpackage: false,\n\t\t\tpackage: 'create-discord-bot',\n\t\t\tsemver: '1.0.0',\n\t\t});\n\t});\n\n\ttest('GIVEN no or invalid tag THEN return null', () => {\n\t\texpect(formatTag('')).toEqual(null);\n\t\texpect(formatTag('abc')).toEqual(null);\n\t});\n});\n"
  },
  {
    "path": "packages/actions/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/actions\",\n\t\"version\": \"0.1.0\",\n\t\"description\": \"A set of actions that we use for our workflows\",\n\t\"private\": true,\n\t\"scripts\": {\n\t\t\"test\": \"vitest run --config ../../vitest.config.ts\",\n\t\t\"build\": \"tsc --noEmit --lib ESNext,DOM && tsup\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src __tests__\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src __tests__\",\n\t\t\"fmt\": \"pnpm run format\"\n\t},\n\t\"type\": \"module\",\n\t\"directories\": {\n\t\t\"lib\": \"src\",\n\t\t\"test\": \"__tests__\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"api\",\n\t\t\"bot\",\n\t\t\"client\",\n\t\t\"node\",\n\t\t\"discordjs\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/actions\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"@actions/core\": \"^2.0.3\",\n\t\t\"@actions/github\": \"^6.0.1\",\n\t\t\"@actions/glob\": \"^0.5.1\",\n\t\t\"@aws-sdk/client-s3\": \"^3.994.0\",\n\t\t\"@discordjs/scripts\": \"workspace:^\",\n\t\t\"cloudflare\": \"^5.2.0\",\n\t\t\"commander\": \"^14.0.3\",\n\t\t\"meilisearch\": \"^0.54.0\",\n\t\t\"p-limit\": \"^7.3.0\",\n\t\t\"p-queue\": \"^9.1.0\",\n\t\t\"tslib\": \"^2.8.1\",\n\t\t\"undici\": \"7.22.0\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@npm/types\": \"^2.1.0\",\n\t\t\"@types/bun\": \"^1.3.9\",\n\t\t\"@types/node\": \"^24.10.13\",\n\t\t\"@vitest/coverage-v8\": \"^4.0.18\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"terser\": \"^5.46.0\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vitest\": \"^4.0.18\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t}\n}\n"
  },
  {
    "path": "packages/actions/src/deprecateVersion/action.yml",
    "content": "name: Deprecate package version\ndescription: Deprecates package versions.\ninputs:\n  package:\n    description: Package name\n    required: true\n  version:\n    description: Version to deprecate\n    required: true\n  message:\n    description: Deprecation message\n    required: false\n    default: This version is deprecated. Please use a newer version.\n  node-auth-token:\n    description: npm authentication token\n    required: true\nruns:\n  using: composite\n  steps:\n    - name: Deprecate version\n      shell: bash\n      run: |\n        pnpm exec npm-deprecate --name \"${{ inputs.version }}\" --message \"${{ inputs.message }}\" --package \"${{ inputs.package }}\"\n      env:\n        NODE_AUTH_TOKEN: ${{ inputs.node-auth-token }}\n"
  },
  {
    "path": "packages/actions/src/formatTag/action.yml",
    "content": "name: 'Format Tag'\ndescription: 'Formats a git tag to remove potentially prefixes'\ninputs:\n  tag:\n    description: 'The input tag'\n    required: true\noutputs:\n  subpackage:\n    description: 'Whether this tag is a subpackage tag'\n  package:\n    description: 'The package string that was extracted from this tag'\n  semver:\n    description: 'The semver string that was extracted from this tag'\nruns:\n  using: node20\n  main: ../../dist/formatTag/index.js\n"
  },
  {
    "path": "packages/actions/src/formatTag/formatTag.ts",
    "content": "export function formatTag(tag: string) {\n\tconst parsed = /(?:^@.*\\/(?<package>.*)@v?)?(?<semver>\\d+.\\d+.\\d+)-?.*/.exec(tag);\n\tconst parsedPackage = /(?<package>.*)@v?-?.*/.exec(tag);\n\n\tif (parsed?.groups) {\n\t\tconst isSubpackage = typeof parsed.groups.package === 'string';\n\t\tconst pkg = isSubpackage ? parsed.groups.package : (parsedPackage?.groups?.package ?? 'discord.js');\n\t\tconst semver = parsed.groups.semver;\n\n\t\treturn {\n\t\t\tisSubpackage,\n\t\t\tpackage: pkg,\n\t\t\tsemver,\n\t\t};\n\t}\n\n\treturn null;\n}\n"
  },
  {
    "path": "packages/actions/src/formatTag/index.ts",
    "content": "import { getInput, setOutput } from '@actions/core';\nimport { formatTag } from './formatTag.js';\n\nconst tag = getInput('tag', { required: true });\nconst parsed = formatTag(tag);\n\nif (parsed) {\n\tsetOutput('subpackage', parsed.isSubpackage);\n\tsetOutput('package', parsed.package);\n\tsetOutput('semver', parsed.semver);\n}\n"
  },
  {
    "path": "packages/actions/src/index.ts",
    "content": "export * from './formatTag/formatTag.js';\n"
  },
  {
    "path": "packages/actions/src/pnpmCache/action.yml",
    "content": "name: 'pnpm install'\ndescription: 'Run pnpm install with cache enabled'\nruns:\n  using: 'composite'\n  steps:\n    - name: Set up swap space\n      if: runner.os == 'Linux'\n      uses: pierotofy/set-swap-space@v1.0\n      with:\n        swap-size-gb: 10\n\n    - uses: pnpm/action-setup@v4.1.0\n      name: Install pnpm\n      with:\n        run_install: false\n\n    - name: Expose pnpm config(s) through \"$GITHUB_OUTPUT\"\n      id: pnpm-config\n      shell: bash\n      run: |\n        echo \"STORE_PATH=$(pnpm store path)\" >> $GITHUB_OUTPUT\n\n    - name: Cache rotation keys\n      id: cache-rotation\n      shell: bash\n      run: |\n        echo \"YEAR_MONTH=$(/bin/date -u \"+%Y%m\")\" >> $GITHUB_OUTPUT\n\n    - uses: actions/cache@v4\n      name: Setup pnpm cache\n      with:\n        path: ${{ steps.pnpm-config.outputs.STORE_PATH }}\n        key: ${{ runner.os }}-pnpm-store-cache-${{ steps.cache-rotation.outputs.YEAR_MONTH }}-${{ hashFiles('**/pnpm-lock.yaml') }}\n        restore-keys: |\n          ${{ runner.os }}-pnpm-store-cache-${{ steps.cache-rotation.outputs.YEAR_MONTH }}-\n\n    - name: Install dependencies\n      shell: bash\n      run: |\n        pnpm install --frozen-lockfile --prefer-offline --loglevel error\n      env:\n        HUSKY: '0'\n"
  },
  {
    "path": "packages/actions/src/releasePackages/action.yml",
    "content": "name: 'Release Packages'\ndescription: 'Tags and releases any unreleased packages'\ninputs:\n  dev:\n    description: 'Releases development versions of packages (skips tagging and github releases)'\n    default: 'false'\n  dry:\n    description: 'Perform a dry run that skips publishing and outputs logs indicating what would have happened'\n    default: 'false'\n  package:\n    description: 'The published name of a single package to release'\n  exclude:\n    description: 'Comma separated list of packages to exclude from release (if not depended upon)'\n  tag:\n    description: 'The tag to use, generally a feature name'\nruns:\n  using: composite\n  steps:\n    - uses: oven-sh/setup-bun@v2\n    - run: bun $GITHUB_ACTION_PATH/index.ts\n      shell: bash\n      env:\n        INPUT_DEV: ${{ inputs.dev }}\n        INPUT_DRY: ${{ inputs.dry }}\n        INPUT_PACKAGE: ${{ inputs.package }}\n        INPUT_EXCLUDE: ${{ inputs.exclude }}\n        INPUT_TAG: ${{ inputs.tag }}\n"
  },
  {
    "path": "packages/actions/src/releasePackages/generateReleaseTree.ts",
    "content": "import { info, warning } from '@actions/core';\nimport type { PackageJSON, PackumentVersion } from '@npm/types';\nimport { $, file, write } from 'bun';\n\ninterface pnpmTreeDependency {\n\tfrom: string;\n\tpath: string;\n\tversion: string;\n}\n\ninterface pnpmTree {\n\tdependencies?: Record<string, pnpmTreeDependency>;\n\tname?: string;\n\tpath: string;\n\tprivate?: boolean;\n\tunsavedDependencies?: Record<string, pnpmTreeDependency>;\n\tversion?: string;\n}\n\nexport interface ReleaseEntry {\n\tchangelog?: string;\n\tdependsOn?: string[];\n\tname: string;\n\tversion: string;\n}\n\nasync function fetchDevVersion(pkg: string, tag: string) {\n\ttry {\n\t\tconst res = await fetch(`https://registry.npmjs.org/${pkg}/${tag}`);\n\t\tif (!res.ok) return null;\n\t\tconst packument = (await res.json()) as PackumentVersion;\n\t\treturn packument.version;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function getReleaseEntries(dry: boolean, devTag?: string) {\n\tconst releaseEntries: ReleaseEntry[] = [];\n\tconst packageList: pnpmTree[] =\n\t\tawait $`pnpm list --recursive --only-projects --filter {packages/\\*} --prod --json`.json();\n\n\tconst commitHash = (await $`git rev-parse --short HEAD`.text()).trim();\n\tconst timestamp = Math.round(Date.now() / 1_000);\n\n\tfor (const pkg of packageList) {\n\t\t// Don't release private packages ever (npm will error anyways)\n\t\tif (pkg.private) continue;\n\t\t// Just in case\n\t\tif (!pkg.version || !pkg.name) continue;\n\n\t\tconst release: ReleaseEntry = {\n\t\t\tname: pkg.name,\n\t\t\tversion: pkg.version,\n\t\t};\n\n\t\tif (devTag) {\n\t\t\t// Replace workspace dependencies with * to pin to associated dev versions\n\t\t\tif (!dry) {\n\t\t\t\tconst pkgJsonString = await file(`${pkg.path}/package.json`).text();\n\t\t\t\tawait write(`${pkg.path}/package.json`, pkgJsonString.replaceAll(/workspace:[\\^~]/g, 'workspace:*'));\n\t\t\t}\n\n\t\t\tconst devVersion = await fetchDevVersion(pkg.name, devTag);\n\t\t\tif (devVersion?.endsWith(commitHash)) {\n\t\t\t\t// Write the currently released dev version so when pnpm publish runs on dependents they depend on the dev versions\n\t\t\t\tif (dry) {\n\t\t\t\t\tinfo(`[DRY] ${pkg.name}@${devVersion} already released. Editing package.json version.`);\n\t\t\t\t} else {\n\t\t\t\t\tconst pkgJson = (await file(`${pkg.path}/package.json`).json()) as PackageJSON;\n\t\t\t\t\tpkgJson.version = devVersion;\n\t\t\t\t\tawait write(`${pkg.path}/package.json`, JSON.stringify(pkgJson, null, '\\t'));\n\t\t\t\t}\n\n\t\t\t\trelease.version = devVersion;\n\t\t\t} else if (dry) {\n\t\t\t\tinfo(`[DRY] Bumping ${pkg.name} via git-cliff.`);\n\t\t\t\trelease.version = `${pkg.version}.DRY-${devTag}.${timestamp}-${commitHash}`;\n\t\t\t} else {\n\t\t\t\tawait $`pnpm --filter=${pkg.name} run release --preid \"${devTag}.${timestamp}-${commitHash}\" --skip-changelog`;\n\t\t\t\t// Read again instead of parsing the output to be sure we're matching when checking against npm\n\t\t\t\tconst pkgJson = (await file(`${pkg.path}/package.json`).json()) as PackageJSON;\n\t\t\t\trelease.version = pkgJson.version;\n\t\t\t}\n\t\t}\n\t\t// Only need changelog for releases published to github\n\t\telse {\n\t\t\ttry {\n\t\t\t\t// Find and parse changelog to post in github release\n\t\t\t\tconst changelogFile = await file(`${pkg.path}/CHANGELOG.md`).text();\n\n\t\t\t\tlet changelogLines: string[] = [];\n\t\t\t\tlet foundChangelog = false;\n\n\t\t\t\tfor (const line of changelogFile.split('\\n')) {\n\t\t\t\t\tif (line.startsWith('# [')) {\n\t\t\t\t\t\tif (foundChangelog) {\n\t\t\t\t\t\t\tif (changelogLines.at(-1) === '') {\n\t\t\t\t\t\t\t\tchangelogLines = changelogLines.slice(2, -1);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check changelog release version and assume no changelog if version does not match\n\t\t\t\t\t\tif (!line.startsWith(`# [${release.name === 'discord.js' ? `` : `${release.name}@`}${release.version}]`)) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfoundChangelog = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (foundChangelog) {\n\t\t\t\t\t\tchangelogLines.push(line);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\trelease.changelog = changelogLines.join('\\n');\n\t\t\t} catch (error) {\n\t\t\t\t// Probably just no changelog file but log just in case\n\t\t\t\twarning(`Error parsing changelog for ${pkg.name}, will use auto generated: ${error}`);\n\t\t\t}\n\t\t}\n\n\t\tif (pkg.dependencies) {\n\t\t\trelease.dependsOn = Object.keys(pkg.dependencies);\n\t\t}\n\n\t\treleaseEntries.push(release);\n\t}\n\n\treturn releaseEntries;\n}\n\nexport async function generateReleaseTree(dry: boolean, devTag?: string, packageName?: string, exclude?: string[]) {\n\tlet releaseEntries = await getReleaseEntries(dry, devTag);\n\t// Try to early return if the package doesn't have deps\n\tif (packageName && packageName !== 'all') {\n\t\tconst releaseEntry = releaseEntries.find((entry) => entry.name === packageName);\n\t\tif (!releaseEntry) {\n\t\t\tthrow new Error(`Package ${packageName} not releaseable`);\n\t\t}\n\n\t\tif (!releaseEntry.dependsOn) {\n\t\t\treturn [[releaseEntry]];\n\t\t}\n\t}\n\n\t// Generate the whole tree first, then prune if specified\n\tconst releaseTree: ReleaseEntry[][] = [];\n\tconst didRelease = new Set<string>();\n\n\twhile (releaseEntries.length) {\n\t\tconst nextBranch: ReleaseEntry[] = [];\n\t\tconst unreleased: ReleaseEntry[] = [];\n\t\tfor (const entry of releaseEntries) {\n\t\t\tif (!entry.dependsOn) {\n\t\t\t\tnextBranch.push(entry);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst allDepsReleased = entry.dependsOn.every((dep) => didRelease.has(dep));\n\t\t\tif (allDepsReleased) {\n\t\t\t\tnextBranch.push(entry);\n\t\t\t} else {\n\t\t\t\tunreleased.push(entry);\n\t\t\t}\n\t\t}\n\n\t\t// Update didRelease in a second loop to avoid loop order issues\n\t\tfor (const release of nextBranch) {\n\t\t\tdidRelease.add(release.name);\n\t\t}\n\n\t\tif (releaseEntries.length === unreleased.length) {\n\t\t\tthrow new Error(\n\t\t\t\t`One or more packages have dependents that can't be released: ${unreleased.map((entry) => entry.name).join(',')}`,\n\t\t\t);\n\t\t}\n\n\t\treleaseTree.push(nextBranch);\n\t\treleaseEntries = unreleased;\n\t}\n\n\t// Prune exclusions\n\tif ((!packageName || packageName === 'all') && Array.isArray(exclude) && exclude.length) {\n\t\tconst neededPackages = new Set<string>();\n\t\tconst excludedReleaseTree: ReleaseEntry[][] = [];\n\n\t\tfor (const releaseBranch of releaseTree.reverse()) {\n\t\t\tconst newThisBranch: ReleaseEntry[] = [];\n\n\t\t\tfor (const entry of releaseBranch) {\n\t\t\t\tif (exclude.includes(entry.name) && !neededPackages.has(entry.name)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tnewThisBranch.push(entry);\n\t\t\t\tfor (const dep of entry.dependsOn ?? []) {\n\t\t\t\t\tneededPackages.add(dep);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (newThisBranch.length) excludedReleaseTree.unshift(newThisBranch);\n\t\t}\n\n\t\treturn excludedReleaseTree;\n\t}\n\n\tif (!packageName || packageName === 'all') {\n\t\treturn releaseTree;\n\t}\n\n\t// Prune the tree for the specified package\n\tconst neededPackages = new Set<string>([packageName]);\n\tconst packageReleaseTree: ReleaseEntry[][] = [];\n\n\tfor (const releaseBranch of releaseTree.reverse()) {\n\t\tconst newThisBranch: ReleaseEntry[] = [];\n\n\t\tfor (const entry of releaseBranch) {\n\t\t\tif (neededPackages.has(entry.name)) {\n\t\t\t\tnewThisBranch.push(entry);\n\t\t\t\tfor (const dep of entry.dependsOn ?? []) {\n\t\t\t\t\tneededPackages.add(dep);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (newThisBranch.length) packageReleaseTree.unshift(newThisBranch);\n\t}\n\n\treturn packageReleaseTree;\n}\n"
  },
  {
    "path": "packages/actions/src/releasePackages/index.ts",
    "content": "import { getInput, startGroup, endGroup, getBooleanInput, summary } from '@actions/core';\nimport { program } from 'commander';\nimport { generateReleaseTree } from './generateReleaseTree.js';\nimport { releasePackage } from './releasePackage.js';\n\nfunction npmPackageLink(packageName: string) {\n\treturn `https://npmjs.com/package/${packageName}` as const;\n}\n\nconst excludeInput = getInput('exclude');\nlet dryInput = false;\nlet devInput = false;\n\ntry {\n\tdevInput = getBooleanInput('dev');\n} catch {\n\t// We're not running in actions\n}\n\ntry {\n\tdryInput = getBooleanInput('dry');\n} catch {\n\t// We're not running in actions or the input isn't set (cron)\n}\n\nprogram\n\t.name('release packages')\n\t.description('releases monorepo packages with proper sequencing')\n\t.argument('[package]', \"release a specific package (and it's dependencies)\", getInput('package'))\n\t.option(\n\t\t'-e, --exclude <packages...>',\n\t\t'exclude specific packages from releasing (will still release if necessary for another package)',\n\t\texcludeInput ? excludeInput.split(',') : [],\n\t)\n\t.option('--dry', 'skips actual publishing and outputs logs instead', dryInput)\n\t.option('--dev', 'publishes development versions and skips tagging / github releases', devInput)\n\t.option('--tag <tag>', 'tag to use for dev releases (defaults to \"dev\")', getInput('tag'))\n\t.parse();\n\nconst {\n\texclude,\n\tdry,\n\tdev,\n\ttag: inputTag,\n} = program.opts<{ dev: boolean; dry: boolean; exclude: string[]; tag: string }>();\n\n// All this because getInput('tag') will return empty string when not set :P\nif (!dev && inputTag.length) {\n\tthrow new Error('The --tag option can only be used with --dev');\n}\n\nconst tag = inputTag.length ? inputTag : dev ? 'dev' : undefined;\nconst [packageName] = program.processedArgs as [string];\nconst tree = await generateReleaseTree(dry, tag, packageName, exclude);\n\ninterface ReleaseResult {\n\tidentifier: string;\n\turl: string;\n}\n\nconst publishedPackages: ReleaseResult[] = [];\nconst skippedPackages: ReleaseResult[] = [];\n\nfor (const branch of tree) {\n\tstartGroup(`Releasing ${branch.map((entry) => `${entry.name}@${entry.version}`).join(', ')}`);\n\n\tawait Promise.all(\n\t\tbranch.map(async (release) => {\n\t\t\tconst published = await releasePackage(release, dry, tag);\n\t\t\tconst identifier = `${release.name}@${release.version}`;\n\n\t\t\tif (published) {\n\t\t\t\tpublishedPackages.push({ identifier, url: npmPackageLink(release.name) });\n\t\t\t} else {\n\t\t\t\tskippedPackages.push({ identifier, url: npmPackageLink(release.name) });\n\t\t\t}\n\t\t}),\n\t);\n\n\tendGroup();\n}\n\nconst result = summary.addHeading('Release summary');\n\nif (dry) {\n\tresult.addRaw('\\n\\n> [!NOTE]\\n> This is a dry run.\\n\\n');\n}\n\nresult.addHeading('Released', 2);\n\nif (publishedPackages.length === 0) {\n\tresult.addRaw('\\n_None_\\n\\n');\n} else {\n\tresult.addRaw('\\n');\n\n\tfor (const { identifier, url } of publishedPackages) {\n\t\tresult.addRaw(`- [${identifier}](${url})\\n`);\n\t}\n\n\tresult.addRaw(`\\n`);\n}\n\nresult.addHeading('Skipped', 2);\n\nif (skippedPackages.length === 0) {\n\tresult.addRaw('\\n_None_\\n\\n');\n} else {\n\tresult.addRaw('\\n');\n\n\tfor (const { identifier, url } of skippedPackages) {\n\t\tresult.addRaw(`- [${identifier}](${url})\\n`);\n\t}\n\n\tresult.addRaw(`\\n`);\n}\n\nawait result.write();\n"
  },
  {
    "path": "packages/actions/src/releasePackages/releasePackage.ts",
    "content": "import process from 'node:process';\nimport { info, warning } from '@actions/core';\nimport { getOctokit, context } from '@actions/github';\nimport { $ } from 'bun';\nimport type { ReleaseEntry } from './generateReleaseTree.js';\n\nlet octokit: ReturnType<typeof getOctokit> | undefined;\n\nif (process.env.GITHUB_TOKEN) {\n\toctokit = getOctokit(process.env.GITHUB_TOKEN);\n}\n\nasync function checkRegistry(release: ReleaseEntry) {\n\tconst res = await fetch(`https://registry.npmjs.org/${release.name}/${release.version}`);\n\treturn res.ok;\n}\n\nasync function gitTagAndRelease(release: ReleaseEntry, dry: boolean) {\n\tconst tagName = `${release.name === 'discord.js' ? `` : `${release.name}@`}${release.version}`;\n\n\tif (dry) {\n\t\tinfo(`[DRY] Release would be \"${tagName}\", skipping release creation.`);\n\t\treturn;\n\t}\n\n\tconst commitHash = (await $`git rev-parse HEAD`.text()).trim();\n\n\ttry {\n\t\tawait octokit?.rest.repos.createRelease({\n\t\t\t...context.repo,\n\t\t\ttag_name: tagName,\n\t\t\ttarget_commitish: commitHash,\n\t\t\tname: tagName,\n\t\t\tbody: release.changelog ?? '',\n\t\t\tgenerate_release_notes: release.changelog === undefined,\n\t\t\tmake_latest: release.name === 'discord.js' ? 'true' : 'false',\n\t\t});\n\t} catch (error) {\n\t\twarning(`Failed to create github release: ${error}`);\n\t}\n}\n\nexport async function releasePackage(release: ReleaseEntry, dry: boolean, devTag?: string, doGitRelease = !devTag) {\n\t// Sanity check against the registry first\n\tif (await checkRegistry(release)) {\n\t\tinfo(`${release.name}@${release.version} already published, skipping.`);\n\t\treturn false;\n\t}\n\n\tif (dry) {\n\t\tinfo(`[DRY] Releasing ${release.name}@${release.version}`);\n\t} else {\n\t\tawait $`pnpm --filter=${release.name} publish --provenance --no-git-checks ${devTag ? `--tag=${devTag}` : ''}`;\n\t}\n\n\t// && !devTag just to be sure\n\tif (doGitRelease && !devTag) await gitTagAndRelease(release, dry);\n\n\tif (dry) return true;\n\n\tconst before = performance.now();\n\n\t// Poll registry to ensure next publishes won't fail\n\tawait new Promise<void>((resolve, reject) => {\n\t\tconst interval = setInterval(async () => {\n\t\t\tif (await checkRegistry(release)) {\n\t\t\t\tclearInterval(interval);\n\t\t\t\tresolve();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (performance.now() > before + 5 * 60 * 1_000) {\n\t\t\t\tclearInterval(interval);\n\t\t\t\treject(new Error(`Release for ${release.name} failed.`));\n\t\t\t}\n\t\t}, 15_000);\n\t});\n\n\tif (devTag) {\n\t\t// Send and forget, deprecations are less important than releasing other dev versions and can be done manually\n\t\tvoid $`pnpm exec npm-deprecate --name \"*${devTag}*\" --message \"This version is deprecated. Please use a newer version.\" --package ${release.name}`\n\t\t\t.nothrow()\n\t\t\t// eslint-disable-next-line promise/prefer-await-to-then\n\t\t\t.then(() => {});\n\t}\n\n\t// Evil, but I can't think of a cleaner mechanism\n\tif (release.name === 'create-discord-bot') {\n\t\tawait $`pnpm --filter=create-discord-bot run rename-to-app`;\n\t\t// eslint-disable-next-line require-atomic-updates\n\t\trelease.name = 'create-discord-app';\n\t\tawait releasePackage(release, dry, devTag, false);\n\t}\n\n\treturn true;\n}\n"
  },
  {
    "path": "packages/actions/src/uploadCoverage/action.yml",
    "content": "name: 'Upload Coverage'\ndescription: 'Uploads code coverage reports to codecov with separate flags for separate packages'\ninputs:\n  codecov_token:\n    description: 'Codecov token.'\n    required: true\nruns:\n  using: 'composite'\n  steps:\n    - name: Upload Brokers Coverage\n      if: ${{ hashFiles('packages/brokers/coverage/cobertura-coverage.xml') != '' }}\n      uses: codecov/codecov-action@v4\n      with:\n        files: ./packages/brokers/coverage/cobertura-coverage.xml\n        disable_search: true\n        flags: brokers\n        token: ${{ inputs.CODECOV_TOKEN }}\n\n    - name: Upload Builders Coverage\n      if: ${{ hashFiles('packages/builders/coverage/cobertura-coverage.xml') != '' }}\n      uses: codecov/codecov-action@v4\n      with:\n        files: ./packages/builders/coverage/cobertura-coverage.xml\n        disable_search: true\n        flags: builders\n        token: ${{ inputs.CODECOV_TOKEN }}\n\n    - name: Upload Collection Coverage\n      if: ${{ hashFiles('packages/collection/coverage/cobertura-coverage.xml') != '' }}\n      uses: codecov/codecov-action@v4\n      with:\n        files: ./packages/collection/coverage/cobertura-coverage.xml\n        disable_search: true\n        flags: collection\n        token: ${{ inputs.CODECOV_TOKEN }}\n\n    - name: Upload Core Coverage\n      if: ${{ hashFiles('packages/core/coverage/cobertura-coverage.xml') != '' }}\n      uses: codecov/codecov-action@v4\n      with:\n        files: ./packages/core/coverage/cobertura-coverage.xml\n        disable_search: true\n        flags: core\n        token: ${{ inputs.CODECOV_TOKEN }}\n\n    - name: Upload Discord.js Coverage\n      if: ${{ hashFiles('packages/discord.js/coverage/cobertura-coverage.xml') != '' }}\n      uses: codecov/codecov-action@v4\n      with:\n        files: ./packages/discord.js/coverage/cobertura-coverage.xml\n        disable_search: true\n        flags: discord.js\n        token: ${{ inputs.CODECOV_TOKEN }}\n\n    - name: Upload Formatters Coverage\n      if: ${{ hashFiles('packages/formatters/coverage/cobertura-coverage.xml') != '' }}\n      uses: codecov/codecov-action@v4\n      with:\n        files: ./packages/formatters/coverage/cobertura-coverage.xml\n        disable_search: true\n        flags: formatters\n        token: ${{ inputs.CODECOV_TOKEN }}\n\n    - name: Upload Next Coverage\n      if: ${{ hashFiles('packages/next/coverage/cobertura-coverage.xml') != '' }}\n      uses: codecov/codecov-action@v4\n      with:\n        files: ./packages/next/coverage/cobertura-coverage.xml\n        disable_search: true\n        flags: next\n        token: ${{ inputs.CODECOV_TOKEN }}\n\n    - name: Upload Proxy Coverage\n      if: ${{ hashFiles('packages/proxy/coverage/cobertura-coverage.xml') != '' }}\n      uses: codecov/codecov-action@v4\n      with:\n        files: ./packages/proxy/coverage/cobertura-coverage.xml\n        disable_search: true\n        flags: proxy\n        token: ${{ inputs.CODECOV_TOKEN }}\n\n    - name: Upload Rest Coverage\n      if: ${{ hashFiles('packages/rest/coverage/cobertura-coverage.xml') != '' }}\n      uses: codecov/codecov-action@v4\n      with:\n        files: ./packages/rest/coverage/cobertura-coverage.xml\n        disable_search: true\n        flags: rest\n        token: ${{ inputs.CODECOV_TOKEN }}\n\n    - name: Upload Structures Coverage\n      if: ${{ hashFiles('packages/structures/coverage/cobertura-coverage.xml') != '' }}\n      uses: codecov/codecov-action@v4\n      with:\n        files: ./packages/structures/coverage/cobertura-coverage.xml\n        disable_search: true\n        flags: structures\n        token: ${{ inputs.CODECOV_TOKEN }}\n\n    - name: Upload Util Coverage\n      if: ${{ hashFiles('packages/util/coverage/cobertura-coverage.xml') != '' }}\n      uses: codecov/codecov-action@v4\n      with:\n        files: ./packages/util/coverage/cobertura-coverage.xml\n        disable_search: true\n        flags: util\n        token: ${{ inputs.CODECOV_TOKEN }}\n\n    - name: Upload Voice Coverage\n      if: ${{ hashFiles('packages/voice/coverage/cobertura-coverage.xml') != '' }}\n      uses: codecov/codecov-action@v4\n      with:\n        files: ./packages/voice/coverage/cobertura-coverage.xml\n        disable_search: true\n        flags: voice\n        token: ${{ inputs.CODECOV_TOKEN }}\n\n    - name: Upload WS Coverage\n      if: ${{ hashFiles('packages/ws/coverage/cobertura-coverage.xml') != '' }}\n      uses: codecov/codecov-action@v4\n      with:\n        files: ./packages/ws/coverage/cobertura-coverage.xml\n        disable_search: true\n        flags: ws\n        token: ${{ inputs.CODECOV_TOKEN }}\n\n    - name: Upload Utilities Coverage\n      if: ${{ hashFiles('packages/actions/coverage/cobertura-coverage.xml') != '' }}\n      uses: codecov/codecov-action@v4\n      with:\n        files: ./packages/actions/coverage/cobertura-coverage.xml\n        disable_search: true\n        flags: utilities\n        token: ${{ inputs.CODECOV_TOKEN }}\n"
  },
  {
    "path": "packages/actions/src/uploadDocumentation/action.yml",
    "content": "name: 'Upload documentation'\ndescription: 'Uploads the docs.api.json file to a neon postgresql database'\ninputs:\n  package:\n    description: 'The package string'\n  version:\n    description: 'The semver string'\nruns:\n  using: node20\n  main: ../../dist/uploadDocumentation/index.js\n"
  },
  {
    "path": "packages/actions/src/uploadDocumentation/index.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport process from 'node:process';\nimport { getInput, setFailed } from '@actions/core';\nimport { create } from '@actions/glob';\nimport { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';\nimport Cloudflare from 'cloudflare';\nimport pLimit from 'p-limit';\n\nif (\n\t!process.env.CF_R2_DOCS_URL ||\n\t!process.env.CF_R2_DOCS_ACCESS_KEY_ID ||\n\t!process.env.CF_R2_DOCS_SECRET_ACCESS_KEY ||\n\t!process.env.CF_R2_DOCS_BUCKET ||\n\t!process.env.CF_R2_DOCS_BUCKET_URL ||\n\t!process.env.CF_D1_DOCS_API_KEY ||\n\t!process.env.CF_D1_DOCS_ID ||\n\t!process.env.CF_ACCOUNT_ID\n) {\n\tsetFailed('Missing environment variables');\n}\n\nconst pkg = getInput('package') || '*';\nconst version = getInput('version') || 'main';\n\nconst S3 = new S3Client({\n\tregion: 'auto',\n\tendpoint: process.env.CF_R2_DOCS_URL!,\n\tcredentials: {\n\t\taccessKeyId: process.env.CF_R2_DOCS_ACCESS_KEY_ID!,\n\t\tsecretAccessKey: process.env.CF_R2_DOCS_SECRET_ACCESS_KEY!,\n\t},\n\trequestChecksumCalculation: 'WHEN_REQUIRED',\n\tresponseChecksumValidation: 'WHEN_REQUIRED',\n});\n\nconst client = new Cloudflare({\n\tapiToken: process.env.CF_D1_DOCS_API_KEY,\n});\n\nconst limit = pLimit(10);\nconst promises = [];\n\nconst globber = await create(`packages/${pkg}/docs/docs.api.json`);\nconsole.log('Glob: ', await globber.glob());\nfor await (const file of globber.globGenerator()) {\n\tconst data = await readFile(file, 'utf8');\n\ttry {\n\t\tpromises.push(\n\t\t\tlimit(async () => {\n\t\t\t\tconsole.log(`Uploading ${file} with ${version}...`);\n\t\t\t\tconst json = JSON.parse(data);\n\t\t\t\tconst name = json.name ?? json.n;\n\n\t\t\t\tconst key = `${name.replace('@discordjs/', '')}/${version}.json`;\n\n\t\t\t\tawait S3.send(\n\t\t\t\t\tnew PutObjectCommand({\n\t\t\t\t\t\tBucket: process.env.CF_R2_DOCS_BUCKET,\n\t\t\t\t\t\tKey: key,\n\t\t\t\t\t\tBody: data,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tawait client.d1.database.raw(process.env.CF_D1_DOCS_ID!, {\n\t\t\t\t\taccount_id: process.env.CF_ACCOUNT_ID!,\n\t\t\t\t\tsql: `insert into documentation (name, version, url) values (?, ?, ?) on conflict (name, version) do update set url = excluded.url;`,\n\t\t\t\t\tparams: [name.replace('@discordjs/', ''), version, process.env.CF_R2_DOCS_BUCKET_URL + '/' + key],\n\t\t\t\t});\n\t\t\t}),\n\t\t);\n\t} catch (error) {\n\t\tconsole.log(error);\n\t}\n}\n\ntry {\n\tawait Promise.all(promises);\n} catch (error) {\n\tconsole.log(error);\n}\n"
  },
  {
    "path": "packages/actions/src/uploadReadmeFiles/action.yml",
    "content": "name: 'Upload README.md files'\ndescription: 'Uploads the README.md files for packages that have api-extractor.json to the website.'\nruns:\n  using: node24\n  main: ../../dist/uploadReadmeFiles/index.js\n"
  },
  {
    "path": "packages/actions/src/uploadReadmeFiles/index.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport process from 'node:process';\nimport { info, setFailed } from '@actions/core';\nimport { create } from '@actions/glob';\nimport { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';\n\nif (\n\t!process.env.CF_R2_READMES_ACCESS_KEY_ID ||\n\t!process.env.CF_R2_READMES_SECRET_ACCESS_KEY ||\n\t!process.env.CF_R2_READMES_BUCKET ||\n\t!process.env.CF_R2_READMES_URL\n) {\n\tsetFailed('Missing environment variables.');\n\tprocess.exit(1);\n}\n\nconst S3READMEFiles = new S3Client({\n\tregion: 'auto',\n\tendpoint: process.env.CF_R2_READMES_URL,\n\tcredentials: {\n\t\taccessKeyId: process.env.CF_R2_READMES_ACCESS_KEY_ID,\n\t\tsecretAccessKey: process.env.CF_R2_READMES_SECRET_ACCESS_KEY,\n\t},\n\trequestChecksumCalculation: 'WHEN_REQUIRED',\n\tresponseChecksumValidation: 'WHEN_REQUIRED',\n});\n\nconst promises = [];\n\n// Find all packages with an api-extractor.json file.\nconst globber = await create('packages/*/api-extractor.json');\n\nfor await (const apiExtractorFile of globber.globGenerator()) {\n\tconst readmePath = apiExtractorFile.replace('/api-extractor.json', '/README.md');\n\tconst packageName = apiExtractorFile.split('/').at(-2)!;\n\tconst readmeKey = `${packageName}/home-README.md`;\n\tinfo(`Uploading ${readmePath}...`);\n\n\tpromises.push(\n\t\t// eslint-disable-next-line promise/prefer-await-to-then\n\t\treadFile(readmePath, 'utf8').then(async (readmeData) =>\n\t\t\tS3READMEFiles.send(\n\t\t\t\tnew PutObjectCommand({\n\t\t\t\t\tBucket: process.env.CF_R2_READMES_BUCKET,\n\t\t\t\t\tKey: readmeKey,\n\t\t\t\t\tBody: readmeData,\n\t\t\t\t}),\n\t\t\t),\n\t\t),\n\t);\n}\n\ntry {\n\tawait Promise.all(promises);\n\tinfo('All README.md files uploaded successfully!');\n} catch (error) {\n\tsetFailed(`Failed to upload README files: ${error}`);\n\tprocess.exit(1);\n}\n"
  },
  {
    "path": "packages/actions/src/uploadSearchIndices/action.yml",
    "content": "name: 'Upload search indices'\ndescription: 'Uploads the search indices to a meilisearch database'\nruns:\n  using: node20\n  main: ../../dist/uploadSearchIndices/index.js\n"
  },
  {
    "path": "packages/actions/src/uploadSearchIndices/index.ts",
    "content": "import process from 'node:process';\nimport { setFailed } from '@actions/core';\nimport { generateAllIndices } from '@discordjs/scripts';\nimport Cloudflare from 'cloudflare';\nimport { type EnqueuedTask, MeiliSearch } from 'meilisearch';\nimport pLimit from 'p-limit';\nimport { fetch } from 'undici';\n\nif (!process.env.CF_D1_DOCS_API_KEY || !process.env.CF_D1_DOCS_ID || !process.env.CF_ACCOUNT_ID) {\n\tsetFailed('Missing Cloudflare D1 environment variables.');\n\tprocess.exit(1);\n}\n\nif (!process.env.SEARCH_API_URL) {\n\tsetFailed('SEARCH_API_URL is not set');\n\tprocess.exit(1);\n}\n\nif (!process.env.SEARCH_API_KEY) {\n\tsetFailed('SEARCH_API_KEY is not set');\n\tprocess.exit(1);\n}\n\nconst cf = new Cloudflare({\n\tapiToken: process.env.CF_D1_DOCS_API_KEY,\n});\n\nconst client = new MeiliSearch({\n\thost: process.env.SEARCH_API_URL,\n\tapiKey: process.env.SEARCH_API_KEY,\n});\n\nconst limit = pLimit(5);\n\ntry {\n\tconsole.log('Generating all indices...');\n\tconst indices = await generateAllIndices({\n\t\tfetchPackageVersions: async (pkg) => {\n\t\t\tconsole.info(`Fetching versions for ${pkg}...`);\n\n\t\t\tconst { result } = await cf.d1.database.query(process.env.CF_D1_DOCS_ID!, {\n\t\t\t\taccount_id: process.env.CF_ACCOUNT_ID!,\n\t\t\t\tsql: `select version from documentation where name = ? order by version desc;`,\n\t\t\t\tparams: [pkg],\n\t\t\t});\n\n\t\t\treturn ((result[0]?.results as { version: string }[] | undefined) ?? []).map((row) => row.version);\n\t\t},\n\t\tfetchPackageVersionDocs: async (pkg, version) => {\n\t\t\tconsole.log(`Fetching data for ${pkg} ${version}...`);\n\n\t\t\tconst { result } = await cf.d1.database.query(process.env.CF_D1_DOCS_ID!, {\n\t\t\t\taccount_id: process.env.CF_ACCOUNT_ID!,\n\t\t\t\tsql: `select url from documentation where name = ? and version = ?;`,\n\t\t\t\tparams: [pkg, version],\n\t\t\t});\n\n\t\t\tconst res = await fetch(((result[0]?.results as { url: string }[] | undefined) ?? [])[0]?.url ?? '');\n\t\t\treturn res.json();\n\t\t},\n\t\twriteToFile: false,\n\t});\n\tconsole.log('Generated all indices.');\n\n\tconsole.log('Uploading indices...');\n\n\tconst promises = indices.map(async (index) =>\n\t\tlimit(async () => {\n\t\t\tconsole.log(`Uploading ${index.index}...`);\n\t\t\tlet task: EnqueuedTask | undefined;\n\t\t\ttry {\n\t\t\t\ttask = await client.createIndex(index.index);\n\t\t\t} catch {}\n\n\t\t\tif (task) {\n\t\t\t\tawait client.tasks.waitForTask(task, { timeout: 10_000 });\n\t\t\t}\n\n\t\t\tconst searchIndex = client.index(index.index);\n\t\t\tawait searchIndex.updateSettings({ sortableAttributes: ['type'] });\n\n\t\t\tawait searchIndex.addDocuments(index.data);\n\t\t}),\n\t);\n\n\tawait Promise.all(promises);\n\n\tconsole.log('Uploaded all indices.');\n} catch (error) {\n\tconst err = error as Error;\n\tconsole.error(err);\n\tsetFailed(err.message);\n\tprocess.exit(1);\n}\n"
  },
  {
    "path": "packages/actions/src/uploadSplitDocumentation/action.yml",
    "content": "name: 'Upload split documentation'\ndescription: 'Splits and uploads the docs.api.json file into more fine-grained [item].api.json files'\ninputs:\n  package:\n    description: 'The package string'\n  version:\n    description: 'The semver string'\nruns:\n  using: node20\n  main: ../../dist/uploadSplitDocumentation/index.js\n"
  },
  {
    "path": "packages/actions/src/uploadSplitDocumentation/index.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport { basename, dirname, relative, sep } from 'node:path';\nimport process from 'node:process';\nimport { setTimeout as sleep } from 'node:timers/promises';\nimport { setFailed, getInput } from '@actions/core';\nimport { create } from '@actions/glob';\nimport { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';\nimport PQueue from 'p-queue';\n\nif (\n\t!process.env.CF_R2_DOCS_URL ||\n\t!process.env.CF_R2_DOCS_ACCESS_KEY_ID ||\n\t!process.env.CF_R2_DOCS_SECRET_ACCESS_KEY ||\n\t!process.env.CF_R2_DOCS_BUCKET\n) {\n\tsetFailed('Missing environment variables');\n}\n\nconst pkg = getInput('package') || '*';\nconst version = getInput('version') || 'main';\n\nconst queue = new PQueue({ concurrency: 10, interval: 60_000, intervalCap: 1_000 });\nconst promises = [];\nconst failedUploads: string[] = [];\n\nconst S3 = new S3Client({\n\tregion: 'auto',\n\tendpoint: process.env.CF_R2_DOCS_URL!,\n\tcredentials: {\n\t\taccessKeyId: process.env.CF_R2_DOCS_ACCESS_KEY_ID!,\n\t\tsecretAccessKey: process.env.CF_R2_DOCS_SECRET_ACCESS_KEY!,\n\t},\n\trequestChecksumCalculation: 'WHEN_REQUIRED',\n\tresponseChecksumValidation: 'WHEN_REQUIRED',\n});\n\nconst globber = await create(`packages/${pkg}/docs/${pkg}/split/*.api.json`);\nconsole.log('Glob: ', await globber.glob());\nfor await (const file of globber.globGenerator()) {\n\tconst data = await readFile(file, 'utf8');\n\tconst pkgName = dirname(relative(process.cwd(), file)).split(sep)[1];\n\ttry {\n\t\tpromises.push(\n\t\t\tqueue.add(async () => {\n\t\t\t\tconsole.log(`Uploading ${file} with ${version} from ${pkgName}...`);\n\t\t\t\tconst name = basename(file).replace('main.', '');\n\t\t\t\tasync function upload(retries = 0) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait S3.send(\n\t\t\t\t\t\t\tnew PutObjectCommand({\n\t\t\t\t\t\t\t\tBucket: process.env.CF_R2_DOCS_BUCKET,\n\t\t\t\t\t\t\t\tKey: `${pkgName}/${version}.${name}`,\n\t\t\t\t\t\t\t\tBody: data,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tif (retries > 3) {\n\t\t\t\t\t\t\tconsole.error(`Could not upload ${file} after 3 retries`, error);\n\t\t\t\t\t\t\tfailedUploads.push(name);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (typeof error === 'object' && error && 'retryAfter' in error && typeof error.retryAfter === 'number') {\n\t\t\t\t\t\t\tawait sleep(error.retryAfter * 1_000);\n\t\t\t\t\t\t\treturn upload(retries + 1);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconsole.error(`Could not upload ${file}`, error);\n\t\t\t\t\t\t\tfailedUploads.push(name);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tawait upload();\n\t\t\t}),\n\t\t);\n\t} catch (error) {\n\t\tconsole.log(error);\n\t}\n}\n\ntry {\n\tawait Promise.all(promises);\n\tif (failedUploads.length) {\n\t\tsetFailed(`Failed to upload ${failedUploads.length} files: ${failedUploads.join(', ')}`);\n\t}\n} catch (error) {\n\tconsole.log(error);\n}\n"
  },
  {
    "path": "packages/actions/src/yarnCache/action.yml",
    "content": "name: 'yarn install'\ndescription: 'Run yarn install with node_modules linker and cache enabled'\nruns:\n  using: 'composite'\n  steps:\n    - name: Set up swap space\n      if: runner.os == 'Linux'\n      uses: pierotofy/set-swap-space@v1.0\n      with:\n        swap-size-gb: 10\n\n    - name: Expose yarn config as \"$GITHUB_OUTPUT\"\n      id: yarn-config\n      shell: bash\n      env:\n        YARN_ENABLE_GLOBAL_CACHE: 'false'\n      run: |\n        echo \"CACHE_FOLDER=$(yarn config get cacheFolder)\" >> $GITHUB_OUTPUT\n        echo \"CURRENT_NODE_VERSION=\"node-$(node --version)\"\" >> $GITHUB_OUTPUT\n        echo \"CURRENT_BRANCH=$(echo ${GITHUB_REF#refs/heads/} | sed -r 's,/,-,g')\" >> $GITHUB_OUTPUT\n        echo \"NPM_GLOBAL_CACHE_FOLDER=$(npm config get cache)\" >> $GITHUB_OUTPUT\n\n    - name: Restore yarn cache\n      uses: actions/cache@v4\n      id: yarn-download-cache\n      with:\n        path: ${{ steps.yarn-config.outputs.CACHE_FOLDER }}\n        key: yarn-download-cache-default-${{ hashFiles(yarn.lock, .yarnrc.yml) }}\n        restore-keys: |\n          yarn-download-cache-default-\n\n    - name: Restore global npm cache folder\n      id: npm-global-cache\n      uses: actions/cache@v4\n      with:\n        path: ${{ steps.yarn-config.outputs.NPM_GLOBAL_CACHE_FOLDER }}\n        key: npm-global-cache-default-${{ runner.os }}-${{ steps.yarn-config.outputs.CURRENT_NODE_VERSION }}-${{ hashFiles(yarn.lock, .yarnrc.yml) }}\n\n    - name: Install dependencies\n      shell: bash\n      run: |\n        yarn install --immutable --inline-builds\n      env:\n        YARN_ENABLE_GLOBAL_CACHE: 'false'\n        YARN_ENABLE_MIRROR: 'false'\n        YARN_NM_MODE: 'hardlinks-local'\n        YARN_INSTALL_STATE_PATH: '.yarn/ci-cache/install-state.gz'\n        HUSKY: '0'\n"
  },
  {
    "path": "packages/actions/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/actions/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\"node\"],\n\t\t\"skipLibCheck\": true\n\t},\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/actions/tsconfig.test.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"noEmit\": true,\n\t\t\"skipLibCheck\": true\n\t},\n\t\"include\": [\"__tests__/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/actions/tsup.config.ts",
    "content": "import { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tentry: [\n\t\t'src/index.ts',\n\t\t'src/formatTag/index.ts',\n\t\t'src/releasePackages/index.ts',\n\t\t'src/uploadDocumentation/index.ts',\n\t\t'src/uploadReadmeFiles/index.ts',\n\t\t'src/uploadSearchIndices/index.ts',\n\t\t'src/uploadSplitDocumentation/index.ts',\n\t],\n\tdts: false,\n\tformat: 'esm',\n\tminify: 'terser',\n\ttarget: 'esnext',\n});\n"
  },
  {
    "path": "packages/api-extractor/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/api-extractor/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/api-extractor/.npmignore",
    "content": "# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO.\n\n# Ignore all files by default, to avoid accidentally publishing unintended files.\n*\n\n# Use negative patterns to bring back the specific things we want to publish.\n!/bin/**\n!/lib/**\n!/lib-*/**\n!/dist/**\n!ThirdPartyNotice.txt\n\n# Ignore certain patterns that should not get published.\n/dist/*.stats.*\n/lib/**/test/\n/lib-*/**/test/\n*.test.js\n\n# NOTE: These don't need to be specified, because NPM includes them automatically.\n#\n# package.json\n# README (and its variants)\n# CHANGELOG (and its variants)\n# LICENSE / LICENCE\n\n#--------------------------------------------\n# DO NOT MODIFY THE TEMPLATE ABOVE THIS LINE\n#--------------------------------------------\n\n# (Add your project-specific overrides here)\n\n!/extends/*.json\n"
  },
  {
    "path": "packages/api-extractor/.prettierignore",
    "content": ".turbo\ncoverage\ndist\nCHANGELOG.md\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/api-extractor/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/api-extractor/CHANGELOG.json",
    "content": "{\n\t\"name\": \"@microsoft/api-extractor\",\n\t\"entries\": [\n\t\t{\n\t\t\t\"version\": \"7.38.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.38.1\",\n\t\t\t\"date\": \"Mon, 30 Oct 2023 23:36:38 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.17.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.38.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.38.0\",\n\t\t\t\"date\": \"Sun, 01 Oct 2023 02:56:29 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add a new message \\\"ae-undocumented\\\" to support logging of undocumented API items\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.37.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.37.3\",\n\t\t\t\"date\": \"Sat, 30 Sep 2023 00:20:51 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Don't strip out @alpha items when generating API reports.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.37.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.37.2\",\n\t\t\t\"date\": \"Thu, 28 Sep 2023 20:53:16 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.28.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.61.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.37.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.37.1\",\n\t\t\t\"date\": \"Tue, 26 Sep 2023 09:30:33 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update type-only imports to include the type modifier.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.28.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.60.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.5.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.16.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.37.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.37.0\",\n\t\t\t\"date\": \"Fri, 15 Sep 2023 00:36:58 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update @types/node from 14 to 18\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.28.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.60.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.5.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.16.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.3.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.36.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.36.4\",\n\t\t\t\"date\": \"Tue, 08 Aug 2023 07:10:39 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.27.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.4.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.15.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.3.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.36.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.36.3\",\n\t\t\t\"date\": \"Wed, 19 Jul 2023 00:20:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updated semver dependency\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.27.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.6`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.36.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.36.2\",\n\t\t\t\"date\": \"Wed, 12 Jul 2023 15:20:39 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add api-extractor support for .d.mts and .d.cts files\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.36.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.36.1\",\n\t\t\t\"date\": \"Thu, 06 Jul 2023 00:16:19 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.27.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.5`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.36.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.36.0\",\n\t\t\t\"date\": \"Mon, 19 Jun 2023 22:40:21 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Use the `IRigConfig` interface in the `IExtractorConfigLoadForFolderOptions` object insteacd of the `RigConfig` class.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.4.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.35.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.35.4\",\n\t\t\t\"date\": \"Thu, 15 Jun 2023 00:21:01 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.27.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.21`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.15.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.3.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.35.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.35.3\",\n\t\t\t\"date\": \"Tue, 13 Jun 2023 01:49:01 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.15.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.35.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.35.2\",\n\t\t\t\"date\": \"Wed, 07 Jun 2023 22:45:16 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.27.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.20`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.14.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.3.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.35.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.35.1\",\n\t\t\t\"date\": \"Mon, 29 May 2023 15:21:15 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.27.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.35.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.35.0\",\n\t\t\t\"date\": \"Mon, 22 May 2023 06:34:32 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade the TypeScript dependency to ~5.0.4\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.27.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.19`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.13.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.3.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.34.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.34.9\",\n\t\t\t\"date\": \"Fri, 12 May 2023 00:23:05 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.26.9`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.34.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.34.8\",\n\t\t\t\"date\": \"Thu, 04 May 2023 00:20:28 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.26.8`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.34.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.34.7\",\n\t\t\t\"date\": \"Mon, 01 May 2023 15:23:20 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.26.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.58.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.34.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.34.6\",\n\t\t\t\"date\": \"Sat, 29 Apr 2023 00:23:03 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.26.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.57.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.34.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.34.5\",\n\t\t\t\"date\": \"Thu, 27 Apr 2023 17:18:42 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.26.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.56.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.34.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.34.4\",\n\t\t\t\"date\": \"Fri, 10 Feb 2023 01:18:50 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.26.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.55.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.18`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.13.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.2.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.34.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.34.3\",\n\t\t\t\"date\": \"Sun, 05 Feb 2023 03:02:02 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.26.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.55.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.34.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.34.2\",\n\t\t\t\"date\": \"Wed, 01 Feb 2023 02:16:34 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.26.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.55.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.34.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.34.1\",\n\t\t\t\"date\": \"Mon, 30 Jan 2023 16:22:30 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.26.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.54.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.34.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.34.0\",\n\t\t\t\"date\": \"Wed, 25 Jan 2023 07:26:55 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add new .api.json field `isAbstract` to track `abstract` modifier in ApiClass, ApiMethod, and ApiProperty via ApiAbstractMixin (GitHub #3661)\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.26.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.33.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.33.8\",\n\t\t\t\"date\": \"Wed, 18 Jan 2023 22:44:12 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Use ts.getCheckFlags to fix TS 5.0\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.33.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.33.7\",\n\t\t\t\"date\": \"Fri, 09 Dec 2022 16:18:28 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.25.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.53.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.33.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.33.6\",\n\t\t\t\"date\": \"Tue, 08 Nov 2022 01:20:55 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.13.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.33.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.33.5\",\n\t\t\t\"date\": \"Wed, 26 Oct 2022 00:16:16 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update the @microsoft/tsdoc dependency version to 0.14.2.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.25.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.33.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.33.4\",\n\t\t\t\"date\": \"Mon, 17 Oct 2022 22:14:21 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.13.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.33.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.33.3\",\n\t\t\t\"date\": \"Mon, 17 Oct 2022 15:16:00 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix a regression where the \\\"fileUrlPath\\\" property would contain a malformed path when API Extractor is run on Windows.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.33.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.33.2\",\n\t\t\t\"date\": \"Fri, 14 Oct 2022 15:26:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix references from computed properties #3629\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.33.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.33.1\",\n\t\t\t\"date\": \"Thu, 13 Oct 2022 00:20:15 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.25.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.53.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.33.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.33.0\",\n\t\t\t\"date\": \"Tue, 11 Oct 2022 23:49:12 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Extract the original source file path for relevant API items and add a new projectFolderUrl setting to the api-extractor.json config that allows one to specify what URL their project folder can be found at.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.25.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.32.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.32.1\",\n\t\t\t\"date\": \"Mon, 10 Oct 2022 15:23:44 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.24.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.53.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.17`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.12.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.1.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.32.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.32.0\",\n\t\t\t\"date\": \"Thu, 29 Sep 2022 07:13:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update parser to TypeScript 4.8.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.24.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.53.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.16`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.12.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.1.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.31.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.31.2\",\n\t\t\t\"date\": \"Wed, 21 Sep 2022 20:21:10 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.24.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.52.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.31.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.31.1\",\n\t\t\t\"date\": \"Thu, 15 Sep 2022 00:18:51 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.24.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.51.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.15`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.12.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.0.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.31.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.31.0\",\n\t\t\t\"date\": \"Tue, 13 Sep 2022 00:16:55 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where aliased classes sometimes had incorrect canonical references in *.api.json (GitHub  #3593)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.30.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.30.1\",\n\t\t\t\"date\": \"Mon, 12 Sep 2022 22:27:48 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix a recent regression where items exported from both the entry point and from an exported namespace appeared only once in the API doc model (GitHub #3619)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.30.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.30.0\",\n\t\t\t\"date\": \"Fri, 02 Sep 2022 17:48:42 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add new \\\"apiReport.includeForgottenExports\\\" and \\\"docModel.includeForgottenExports\\\" properties to control whether forgotten exports are included in the API report and doc model files.\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix incorrect declaration references for symbols not exported from the package's entry point.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.24.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.29.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.29.5\",\n\t\t\t\"date\": \"Wed, 24 Aug 2022 03:01:22 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.23.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.51.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.29.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.29.4\",\n\t\t\t\"date\": \"Wed, 24 Aug 2022 00:14:38 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Remove use of LegacyAdapters.sortStable\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.23.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.51.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.29.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.29.3\",\n\t\t\t\"date\": \"Fri, 19 Aug 2022 00:17:19 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.23.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.50.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.29.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.29.2\",\n\t\t\t\"date\": \"Wed, 10 Aug 2022 09:52:12 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix incorrect declaration references for local symbols within namespaces\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.29.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.29.1\",\n\t\t\t\"date\": \"Wed, 10 Aug 2022 08:12:16 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix a regression where .api.json excerpts were sometimes missing tokens (GitHub #3561), and generally improve the quality of excerpt generation\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.29.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.29.0\",\n\t\t\t\"date\": \"Wed, 03 Aug 2022 18:40:35 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade TypeScript dependency to 4.7\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.23.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.50.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.14`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.12.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.0.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.28.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.28.7\",\n\t\t\t\"date\": \"Mon, 01 Aug 2022 02:45:32 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.22.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.50.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.28.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.28.6\",\n\t\t\t\"date\": \"Thu, 21 Jul 2022 23:30:27 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.22.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.28.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.28.5\",\n\t\t\t\"date\": \"Thu, 21 Jul 2022 00:16:14 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.22.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.28.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.28.4\",\n\t\t\t\"date\": \"Fri, 08 Jul 2022 15:17:46 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update api-extractor-template.json to \\\"testMode\\\" and \\\"enumMemberOrder\\\" comment sections.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.28.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.28.3\",\n\t\t\t\"date\": \"Mon, 04 Jul 2022 15:15:13 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Make enumMemberOrder configuration field optional\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.28.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.28.2\",\n\t\t\t\"date\": \"Thu, 30 Jun 2022 04:48:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve logic that determines whether an API item is readonly\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.21.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.28.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.28.1\",\n\t\t\t\"date\": \"Tue, 28 Jun 2022 22:47:13 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.20.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.49.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.28.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.28.0\",\n\t\t\t\"date\": \"Tue, 28 Jun 2022 00:23:32 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add support for the \\\"ignoreMissingEntryPoint\\\" ExtractorConfig option to allow for loading an ExtractorConfig before the target project is built.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.20.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.48.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.13`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.12.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.6.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.27.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.27.1\",\n\t\t\t\"date\": \"Mon, 27 Jun 2022 18:43:09 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.20.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.47.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.27.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.27.0\",\n\t\t\t\"date\": \"Sat, 25 Jun 2022 21:00:40 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"API Extractor now populates an initializerTokenRange field for ApiProperty and ApiVariable items.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.20.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.26.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.26.1\",\n\t\t\t\"date\": \"Sat, 25 Jun 2022 01:54:29 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.19.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.46.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.26.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.26.0\",\n\t\t\t\"date\": \"Fri, 24 Jun 2022 07:16:47 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Include new configuration option for preserving enum member order\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.19.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.25.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.25.3\",\n\t\t\t\"date\": \"Thu, 23 Jun 2022 22:14:24 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.12.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.25.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.25.2\",\n\t\t\t\"date\": \"Fri, 17 Jun 2022 09:17:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.18.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.7`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.25.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.25.1\",\n\t\t\t\"date\": \"Fri, 17 Jun 2022 00:16:18 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"none\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix a mistake in the config/api-extractor.json template's default.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.18.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.12`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.11.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.6.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.25.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.25.0\",\n\t\t\t\"date\": \"Tue, 07 Jun 2022 09:37:04 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add an \\\"isReadonly\\\" field to the doc model to indicate whether a property or variable is readonly\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add an \\\"isProtected\\\" field to the doc model to indicate protected class members\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.18.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.24.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.24.2\",\n\t\t\t\"date\": \"Wed, 25 May 2022 22:25:07 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where API Extractor would fail to run on a project where `\\\"moduleResolution\\\"` is set to `\\\"Node16\\\"` in `tsconfig.json`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.24.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.24.1\",\n\t\t\t\"date\": \"Thu, 19 May 2022 15:13:20 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix a recent regression that produced an error \\\"Cannot read properties of undefined\\\" (GitHub #3423)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.24.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.24.0\",\n\t\t\t\"date\": \"Sat, 14 May 2022 03:01:27 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Throw an error early if API Extractor will attempt to process non-.d.ts files\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Generate API doc model nodes for setters without getters\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Address edge case in excerptBuilder token range logic\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.23.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.23.2\",\n\t\t\t\"date\": \"Tue, 10 May 2022 01:20:43 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.17.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.11.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.23.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.23.1\",\n\t\t\t\"date\": \"Wed, 04 May 2022 23:29:13 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update the global variable analyzer to add support for changes to the TypeScript internals coming in v4.7\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.23.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.23.0\",\n\t\t\t\"date\": \"Sat, 23 Apr 2022 02:13:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update to TypeScript 4.6\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.17.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.11`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.10.10`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.6.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.22.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.22.2\",\n\t\t\t\"date\": \"Fri, 15 Apr 2022 00:12:36 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.17.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.10`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.10.9`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.5.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.22.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.22.1\",\n\t\t\t\"date\": \"Wed, 13 Apr 2022 15:12:40 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.17.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.22.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.22.0\",\n\t\t\t\"date\": \"Tue, 12 Apr 2022 23:29:34 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add an alphaTrimmedFilePath option that adds support for generating a DTS rollup that inclues @alpha, @beta, and @public members.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.21.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.21.3\",\n\t\t\t\"date\": \"Tue, 12 Apr 2022 02:58:32 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update TSDoc dependencies.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.16.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.21.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.21.2\",\n\t\t\t\"date\": \"Sat, 09 Apr 2022 19:07:47 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix ambient modules bug caused by #3321.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.21.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.21.1\",\n\t\t\t\"date\": \"Sat, 09 Apr 2022 02:24:26 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Rename the \\\"master\\\" branch to \\\"main\\\".\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.16.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.9`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.10.8`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.5.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.21.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.21.0\",\n\t\t\t\"date\": \"Fri, 08 Apr 2022 20:05:59 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add support for projects that use tsconfig.json \\\"baseUrl\\\" and \\\"paths\\\" settings to remap imports of local files (GitHub #3291)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.20.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.20.1\",\n\t\t\t\"date\": \"Wed, 06 Apr 2022 22:35:23 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where .api.json excerpt text included extra whitespace (GitHub #3316)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.20.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.20.0\",\n\t\t\t\"date\": \"Thu, 31 Mar 2022 02:06:05 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updated api-extractor to extract whether a parameter is optional.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.16.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.19.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.19.5\",\n\t\t\t\"date\": \"Tue, 15 Mar 2022 19:15:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.15.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.8`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.10.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.5.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.19.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.19.4\",\n\t\t\t\"date\": \"Wed, 05 Jan 2022 16:07:47 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.15.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.19.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.19.3\",\n\t\t\t\"date\": \"Mon, 27 Dec 2021 16:10:40 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.15.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.44.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.10.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.5.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.19.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.19.2\",\n\t\t\t\"date\": \"Thu, 09 Dec 2021 20:34:41 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.15.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.44.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.19.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.19.1\",\n\t\t\t\"date\": \"Thu, 09 Dec 2021 00:21:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.15.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.19.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.19.0\",\n\t\t\t\"date\": \"Wed, 08 Dec 2021 16:14:05 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update to TypeScript 4.5\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.14.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.21\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.21\",\n\t\t\t\"date\": \"Mon, 06 Dec 2021 16:08:33 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.18`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.44.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.10.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.5.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.20\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.20\",\n\t\t\t\"date\": \"Fri, 03 Dec 2021 03:05:22 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.17`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.44.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.19\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.19\",\n\t\t\t\"date\": \"Sat, 06 Nov 2021 00:09:13 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.16`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.43.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.18\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.18\",\n\t\t\t\"date\": \"Fri, 05 Nov 2021 15:09:18 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.15`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.43.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.10.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.4.5`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.17\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.17\",\n\t\t\t\"date\": \"Wed, 27 Oct 2021 00:08:15 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update the package.json repository field to include the directory property.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.14`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.43.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.10.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.4.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.16\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.16\",\n\t\t\t\"date\": \"Wed, 13 Oct 2021 15:09:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.13`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.42.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.10.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.4.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.15\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.15\",\n\t\t\t\"date\": \"Fri, 08 Oct 2021 08:08:34 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.12`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.42.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.14\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.14\",\n\t\t\t\"date\": \"Thu, 07 Oct 2021 07:13:35 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.11`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.42.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.10.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.4.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.13\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.13\",\n\t\t\t\"date\": \"Tue, 05 Oct 2021 15:08:38 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.10`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.42.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.12\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.12\",\n\t\t\t\"date\": \"Mon, 04 Oct 2021 15:10:18 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.10.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.11\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.11\",\n\t\t\t\"date\": \"Fri, 24 Sep 2021 00:09:29 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.9`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.41.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.10\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.10\",\n\t\t\t\"date\": \"Thu, 23 Sep 2021 00:10:40 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade the `@types/node` dependency to version to version 12.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.8`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.40.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.9.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.4.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.9\",\n\t\t\t\"date\": \"Tue, 14 Sep 2021 01:17:04 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.40.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.8\",\n\t\t\t\"date\": \"Mon, 13 Sep 2021 15:07:05 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.40.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.7\",\n\t\t\t\"date\": \"Fri, 27 Aug 2021 00:07:25 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.3.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.6\",\n\t\t\t\"date\": \"Fri, 20 Aug 2021 15:08:10 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.9.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.5\",\n\t\t\t\"date\": \"Wed, 11 Aug 2021 00:07:21 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.40.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.4\",\n\t\t\t\"date\": \"Wed, 14 Jul 2021 15:06:29 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where the .d.ts rollup sometimes used \\\"default\\\" as an identifier name causing a syntax error (GitHub #2804)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.3\",\n\t\t\t\"date\": \"Tue, 13 Jul 2021 23:00:33 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Revert a workaround for TypeScript issue #44422 which was fixed in 4.3.3\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.2\",\n\t\t\t\"date\": \"Mon, 12 Jul 2021 23:08:26 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.39.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.2.13`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.8.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.4.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.1\",\n\t\t\t\"date\": \"Thu, 08 Jul 2021 23:41:16 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix a recent regression that reported \\\"Internal Error: indentDocComment cannot be nested\\\" (GitHub #2797)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.18.0\",\n\t\t\t\"date\": \"Thu, 08 Jul 2021 06:00:48 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add support for import() type expressions (GitHub #1050) -- Thank you @javier-garcia-meteologica and @adventure-yunfei for solving this difficult problem!\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve formatting of declarations in .d.ts rollup and .api.md files, fixing some indentation issues\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.17.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.17.1\",\n\t\t\t\"date\": \"Thu, 01 Jul 2021 15:08:27 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.8.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.17.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.17.0\",\n\t\t\t\"date\": \"Wed, 30 Jun 2021 15:06:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Added support for \\\"import * as module from './local/module';\\\" (GitHub #1029) -- Big thanks to @adventure-yunfei, @mckn, @rbuckton, and @octogonz who all helped with this difficult PR!\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Include /// directives in API report\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.16.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.16.1\",\n\t\t\t\"date\": \"Fri, 04 Jun 2021 19:59:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.39.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.16.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.16.0\",\n\t\t\t\"date\": \"Fri, 04 Jun 2021 15:08:20 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade the bundled compiler engine to TypeScript 4.3\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.15.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.15.2\",\n\t\t\t\"date\": \"Wed, 19 May 2021 00:11:39 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.38.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.15.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.15.1\",\n\t\t\t\"date\": \"Mon, 03 May 2021 15:10:29 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.37.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.15.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.15.0\",\n\t\t\t\"date\": \"Thu, 29 Apr 2021 23:26:50 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade the bundled compiler engine to TypeScript 4.2\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.14.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.14.0\",\n\t\t\t\"date\": \"Tue, 20 Apr 2021 04:59:51 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Projects can now define custom tags using a tsdoc.json file\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.13.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.13.5\",\n\t\t\t\"date\": \"Mon, 12 Apr 2021 15:10:28 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.12.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.36.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.2.12`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.7.10`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.3.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.13.4\",\n\t\t\t\"date\": \"Thu, 08 Apr 2021 06:05:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.12.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.13.3\",\n\t\t\t\"date\": \"Tue, 06 Apr 2021 15:14:22 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.12.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.36.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.2.11`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.7.9`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.3.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.13.2\",\n\t\t\t\"date\": \"Thu, 04 Mar 2021 01:11:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.2.10`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.13.1\",\n\t\t\t\"date\": \"Fri, 05 Feb 2021 16:10:42 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.12.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.36.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.13.0\",\n\t\t\t\"date\": \"Wed, 13 Jan 2021 01:11:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade the bundled compiler engine to TypeScript 4.1\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.12.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.12.1\",\n\t\t\t\"date\": \"Thu, 10 Dec 2020 23:25:49 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade to TSDoc 0.12.24\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.12.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.35.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.2.9`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.7.8`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.3.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.12.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.12.0\",\n\t\t\t\"date\": \"Wed, 18 Nov 2020 08:19:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"The \\\"isOptional\\\" .api.json field is now applied to both methods and properties\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.12.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.11.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.11.5\",\n\t\t\t\"date\": \"Wed, 18 Nov 2020 06:21:57 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update .api.json file format to store a new field \\\"isOptional\\\" for documenting optional properties\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.11.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.11.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.11.4\",\n\t\t\t\"date\": \"Wed, 11 Nov 2020 01:08:58 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.10.10`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.35.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.2.8`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.7.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.3.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.11.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.11.3\",\n\t\t\t\"date\": \"Tue, 10 Nov 2020 23:13:12 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.10.9`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.35.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.11.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.11.2\",\n\t\t\t\"date\": \"Fri, 30 Oct 2020 06:38:38 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.10.8`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.2.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.7.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.3.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.11.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.11.1\",\n\t\t\t\"date\": \"Fri, 30 Oct 2020 00:10:14 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.10.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.2.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.7.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.2.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.11.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.11.0\",\n\t\t\t\"date\": \"Thu, 29 Oct 2020 06:14:19 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade the bundled compiler engine to TypeScript 4.0\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.10.6`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.10.6\",\n\t\t\t\"date\": \"Wed, 28 Oct 2020 01:18:03 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.10.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.2.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.7.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.2.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.10.5\",\n\t\t\t\"date\": \"Tue, 27 Oct 2020 15:10:13 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.10.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.10.4\",\n\t\t\t\"date\": \"Tue, 06 Oct 2020 00:24:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.10.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.2.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.7.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.2.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.10.3\",\n\t\t\t\"date\": \"Mon, 05 Oct 2020 22:36:57 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.10.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.2.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.7.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.2.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.10.2\",\n\t\t\t\"date\": \"Mon, 05 Oct 2020 15:10:42 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.2.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.10.1\",\n\t\t\t\"date\": \"Wed, 30 Sep 2020 18:39:17 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update to build with @rushstack/heft-node-rig\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.10.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.2.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.7.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.1.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.10.0\",\n\t\t\t\"date\": \"Wed, 30 Sep 2020 06:53:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an InternalError reported when a declaration referred to itself using \\\"tyepof\\\"\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update README.md\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"API Extractor now supports the config/rig.json system, as defined by @rushstack/rig-package\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add IExtractorConfigPrepareOptions.projectFolderLookupToken\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade compiler; the API now requires TypeScript 3.9 or newer\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.10.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/rig-package\\\" to `0.2.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.7.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.1.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.22\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.22\",\n\t\t\t\"date\": \"Tue, 22 Sep 2020 05:45:56 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.9.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.33.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.6.10`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.1.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.21\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.21\",\n\t\t\t\"date\": \"Tue, 22 Sep 2020 01:45:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.9.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.33.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.6.9`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.1.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.20\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.20\",\n\t\t\t\"date\": \"Tue, 22 Sep 2020 00:08:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.9.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.33.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.6.8`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.0.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.19\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.19\",\n\t\t\t\"date\": \"Sat, 19 Sep 2020 04:37:26 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.9.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.33.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.6.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.4.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.18\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.18\",\n\t\t\t\"date\": \"Sat, 19 Sep 2020 03:33:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.9.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.33.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.6.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.4.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.17\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.17\",\n\t\t\t\"date\": \"Fri, 18 Sep 2020 22:57:24 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.9.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.33.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.6.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.4.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.16\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.16\",\n\t\t\t\"date\": \"Fri, 18 Sep 2020 21:49:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.9.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.33.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.15\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.15\",\n\t\t\t\"date\": \"Sun, 13 Sep 2020 01:53:20 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.9.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.14\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.14\",\n\t\t\t\"date\": \"Fri, 11 Sep 2020 02:13:35 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.8.22`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.32.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.13\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.13\",\n\t\t\t\"date\": \"Mon, 07 Sep 2020 07:37:37 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.8.21`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.31.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.12\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.12\",\n\t\t\t\"date\": \"Sat, 05 Sep 2020 18:56:34 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.8.20`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.11\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.11\",\n\t\t\t\"date\": \"Thu, 27 Aug 2020 11:27:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.8.19`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.30.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.6.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.3.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.10\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.10\",\n\t\t\t\"date\": \"Mon, 24 Aug 2020 07:35:20 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.8.18`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.29.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.6.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.2.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.9\",\n\t\t\t\"date\": \"Sat, 22 Aug 2020 05:55:42 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.8.17`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.29.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.6.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.2.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.8\",\n\t\t\t\"date\": \"Fri, 21 Aug 2020 01:21:18 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.6.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.7\",\n\t\t\t\"date\": \"Thu, 20 Aug 2020 15:13:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.6.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.6\",\n\t\t\t\"date\": \"Tue, 18 Aug 2020 23:59:42 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.8.16`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.28.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.5.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.5\",\n\t\t\t\"date\": \"Mon, 17 Aug 2020 04:53:23 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"none\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add keywords to package.json for discoverability\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.8.15`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.27.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.4.8`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.1.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.4\",\n\t\t\t\"date\": \"Wed, 12 Aug 2020 00:10:05 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updated project to build with Heft\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.8.14`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.26.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" to `4.4.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.0.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.3\",\n\t\t\t\"date\": \"Wed, 05 Aug 2020 18:27:32 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" to `7.8.13`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.26.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.2\",\n\t\t\t\"date\": \"Thu, 09 Jul 2020 04:58:36 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue with handling of \\\"export { default } from 'package';\\\" (GitHub #2014)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.1\",\n\t\t\t\"date\": \"Fri, 03 Jul 2020 15:09:04 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.8.11` to `7.8.12`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.24.4` to `3.25.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.9.0\",\n\t\t\t\"date\": \"Fri, 03 Jul 2020 05:46:41 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where chained compiler errors were not formatted correctly\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Log the TypeScript bundled compiler version, and warn if it is outdated\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add support for ECMAScript private fields (new in TypeScript 3.8)\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add support for \\\"import type\\\" imports (new in TypeScript 3.8)\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade the bundled compiler engine to TypeScript 3.9\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" from `4.4.5` to `4.4.6`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.15\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.15\",\n\t\t\t\"date\": \"Thu, 25 Jun 2020 06:43:35 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.8.10` to `7.8.11`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.24.3` to `3.24.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" from `4.4.4` to `4.4.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `1.0.1` to `1.0.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.14\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.14\",\n\t\t\t\"date\": \"Wed, 24 Jun 2020 09:50:48 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.8.9` to `7.8.10`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.24.2` to `3.24.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" from `4.4.3` to `4.4.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `1.0.0` to `1.0.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.13\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.13\",\n\t\t\t\"date\": \"Wed, 24 Jun 2020 09:04:28 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.8.8` to `7.8.9`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.24.1` to `3.24.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" from `4.4.2` to `4.4.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.8` to `1.0.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.12\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.12\",\n\t\t\t\"date\": \"Mon, 15 Jun 2020 22:17:17 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where documentation hyperlinks were sometimes missing when using the \\\"bundledPackages\\\" feature (GitHub #1933)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.11\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.11\",\n\t\t\t\"date\": \"Wed, 10 Jun 2020 20:48:30 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.8.7` to `7.8.8`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.24.0` to `3.24.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.10\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.10\",\n\t\t\t\"date\": \"Mon, 01 Jun 2020 08:34:17 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" from `4.4.1` to `4.4.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.9\",\n\t\t\t\"date\": \"Sat, 30 May 2020 02:59:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.8.6` to `7.8.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.23.1` to `3.24.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.8\",\n\t\t\t\"date\": \"Thu, 28 May 2020 05:59:02 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.8.5` to `7.8.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.23.0` to `3.23.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.7\",\n\t\t\t\"date\": \"Wed, 27 May 2020 05:15:10 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.8.4` to `7.8.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.22.1` to `3.23.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" from `4.4.0` to `4.4.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.7` to `0.5.8`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.6\",\n\t\t\t\"date\": \"Tue, 26 May 2020 23:00:25 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.8.3` to `7.8.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.22.0` to `3.22.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.5\",\n\t\t\t\"date\": \"Fri, 22 May 2020 15:08:42 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.8.2` to `7.8.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.21.0` to `3.22.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.4\",\n\t\t\t\"date\": \"Thu, 21 May 2020 23:09:44 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.8.1` to `7.8.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.20.0` to `3.21.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.3\",\n\t\t\t\"date\": \"Thu, 21 May 2020 15:41:59 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.8.0` to `7.8.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.19.7` to `3.20.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.2\",\n\t\t\t\"date\": \"Tue, 19 May 2020 15:08:19 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Report an error to indicate that \\\"import()\\\" types are not supported\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.1\",\n\t\t\t\"date\": \"Fri, 15 May 2020 08:10:59 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" from `4.3.14` to `4.4.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.8.0\",\n\t\t\t\"date\": \"Wed, 06 May 2020 08:23:45 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Version update only\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.7.11` to `7.8.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.13\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.7.13\",\n\t\t\t\"date\": \"Wed, 08 Apr 2020 04:07:33 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.7.10` to `7.7.11`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.19.6` to `3.19.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" from `4.3.13` to `4.3.14`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.6` to `0.5.7`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.12\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.7.12\",\n\t\t\t\"date\": \"Sun, 29 Mar 2020 00:04:12 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve analysis of types exposed via global variables (fixes GitHub issues #1765, #1095, and #1316)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.11\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.7.11\",\n\t\t\t\"date\": \"Sat, 28 Mar 2020 00:37:16 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade to TSdoc 0.12.19 to fix an issue where `<h1>` wasn't allowed as an HTML tag in a doc comment\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.7.9` to `7.7.10`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.19.5` to `3.19.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" from `4.3.12` to `4.3.13`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.5` to `0.5.6`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.10\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.7.10\",\n\t\t\t\"date\": \"Wed, 18 Mar 2020 15:07:47 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade cyclic dependencies\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.7.8` to `7.7.9`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.19.4` to `3.19.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" from `4.3.11` to `4.3.12`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.4` to `0.5.5`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.7.9\",\n\t\t\t\"date\": \"Tue, 17 Mar 2020 23:55:58 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack`\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.7.7` to `7.7.8`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.19.3` to `3.19.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/ts-command-line\\\" from `4.3.10` to `4.3.11`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.7.8\",\n\t\t\t\"date\": \"Tue, 28 Jan 2020 02:23:44 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.7.6` to `7.7.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.19.2` to `3.19.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.7.7\",\n\t\t\t\"date\": \"Thu, 23 Jan 2020 01:07:56 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.7.5` to `7.7.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.19.1` to `3.19.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.7.6\",\n\t\t\t\"date\": \"Tue, 21 Jan 2020 21:56:13 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.7.4` to `7.7.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.19.0` to `3.19.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.3.9` to `4.3.10`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.3` to `0.5.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.7.5\",\n\t\t\t\"date\": \"Sun, 19 Jan 2020 02:26:52 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade Node typings to Node 10\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.7.3` to `7.7.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.18.3` to `3.19.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.3.8` to `4.3.9`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.2` to `0.5.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.7.4\",\n\t\t\t\"date\": \"Fri, 17 Jan 2020 01:08:23 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.7.2` to `7.7.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.18.2` to `3.18.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.3.7` to `4.3.8`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.1` to `0.5.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.7.3\",\n\t\t\t\"date\": \"Tue, 14 Jan 2020 01:34:15 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where \\\"ae-incompatible-release-tags\\\" was sometimes reported incorectly for property setters (GitHub #1681)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.7.2\",\n\t\t\t\"date\": \"Thu, 09 Jan 2020 06:44:12 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an error \\\"Cannot read property 'externalModuleIndicator' of undefined\\\" (GitHub #1652)\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.7.1` to `7.7.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.18.1` to `3.18.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.3.6` to `4.3.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.0` to `0.5.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.7.1\",\n\t\t\t\"date\": \"Wed, 08 Jan 2020 00:11:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.7.0` to `7.7.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.18.0` to `3.18.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.3.5` to `4.3.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.4.2` to `0.5.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.7.0\",\n\t\t\t\"date\": \"Tue, 03 Dec 2019 03:17:43 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve declaration reference syntax to allow linking to overloaded functions/methods\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue with TypeScript 3.7, which now emits separate signatures for property getters/setters\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.6.0` to `7.7.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.6.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.6.2\",\n\t\t\t\"date\": \"Sun, 24 Nov 2019 00:54:04 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.5.6` to `7.6.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.6.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.6.1\",\n\t\t\t\"date\": \"Wed, 20 Nov 2019 06:14:28 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where the newlineKind setting wasn't being applied correctly\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.6.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.6.0\",\n\t\t\t\"date\": \"Fri, 15 Nov 2019 04:50:50 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Make newline type for generated files configurable\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.5.5` to `7.5.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.17.1` to `3.18.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.5.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.5.6\",\n\t\t\t\"date\": \"Mon, 11 Nov 2019 16:07:56 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.5.4` to `7.5.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.17.0` to `3.17.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.3.4` to `4.3.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.4.1` to `0.4.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.5.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.5.5\",\n\t\t\t\"date\": \"Wed, 06 Nov 2019 22:44:18 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add support for TypeScript 3.7\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.5.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.5.4\",\n\t\t\t\"date\": \"Tue, 05 Nov 2019 06:49:28 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where API reports sometimes were ordered differently depending on the version of NodeJS (GitHub #1552)\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.5.3` to `7.5.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.16.0` to `3.17.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.5.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.5.3\",\n\t\t\t\"date\": \"Tue, 05 Nov 2019 01:08:39 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.5.2` to `7.5.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.5.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.5.2\",\n\t\t\t\"date\": \"Tue, 22 Oct 2019 06:24:44 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.5.1` to `7.5.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.15.1` to `3.16.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.3.3` to `4.3.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.4.0` to `0.4.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.5.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.5.1\",\n\t\t\t\"date\": \"Fri, 18 Oct 2019 15:15:01 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.3.2` to `4.3.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.5.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.5.0\",\n\t\t\t\"date\": \"Sun, 06 Oct 2019 00:27:39 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Allow separate release tags for overloaded functions and methods\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add new api-extractor.json config setting \\\"bundledPackages\\\"\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.4.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.4.7\",\n\t\t\t\"date\": \"Fri, 04 Oct 2019 00:15:22 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where IExtractorConfigPrepareOptions.packageJson was ignored (GitHub #1559)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.4.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.4.6\",\n\t\t\t\"date\": \"Sun, 29 Sep 2019 23:56:29 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update repository URL\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.5.0` to `7.5.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.15.0` to `3.15.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.3.1` to `4.3.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.4.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.4.5\",\n\t\t\t\"date\": \"Wed, 25 Sep 2019 15:15:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.4.2` to `7.5.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.4.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.4.4\",\n\t\t\t\"date\": \"Tue, 24 Sep 2019 02:58:49 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.3.0` to `4.3.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.4.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.4.3\",\n\t\t\t\"date\": \"Mon, 23 Sep 2019 15:14:55 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.4.1` to `7.4.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.14.2` to `3.15.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.2.8` to `4.3.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.4.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.4.2\",\n\t\t\t\"date\": \"Wed, 11 Sep 2019 19:56:23 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add support for an exported name that conflicts with a global name (GitHub #1350)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.4.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.4.1\",\n\t\t\t\"date\": \"Tue, 10 Sep 2019 22:32:23 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update documentation\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.4.0` to `7.4.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.14.1` to `3.14.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.2.7` to `4.2.8`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.4.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.4.0\",\n\t\t\t\"date\": \"Tue, 10 Sep 2019 20:38:33 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add support for generating declaration references\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.3.4` to `7.4.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.11\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.3.11\",\n\t\t\t\"date\": \"Wed, 04 Sep 2019 18:28:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.3.3` to `7.3.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.14.0` to `3.14.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.10\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.3.10\",\n\t\t\t\"date\": \"Wed, 04 Sep 2019 15:15:37 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update TSDoc dependency to 0.12.14\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.3.2` to `7.3.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.3.9\",\n\t\t\t\"date\": \"Fri, 30 Aug 2019 00:14:32 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix a problem where Unicode API names were not handled correctly\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.3.8\",\n\t\t\t\"date\": \"Mon, 12 Aug 2019 15:15:14 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.2.6` to `4.2.7`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.3.7\",\n\t\t\t\"date\": \"Thu, 08 Aug 2019 15:14:17 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.3.1` to `7.3.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.13.0` to `3.14.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.3.6\",\n\t\t\t\"date\": \"Thu, 08 Aug 2019 00:49:05 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where a function with only one declaration was assigned an overloadIndex of 0 instead of 1\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.3.0` to `7.3.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.3.5\",\n\t\t\t\"date\": \"Mon, 05 Aug 2019 22:04:32 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Security updates.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.3.4\",\n\t\t\t\"date\": \"Tue, 23 Jul 2019 01:13:01 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"ApiItem.name is now quoted when it contains invalid identifier characters, to avoid conflicts with an ECMAScript symbol expression\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.3.3\",\n\t\t\t\"date\": \"Mon, 22 Jul 2019 19:13:10 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update to use new api-extractor-model\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.2.0` to `7.3.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.3.2\",\n\t\t\t\"date\": \"Fri, 12 Jul 2019 19:12:46 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Clarify docs for \\\"--typescript-compiler-folder\\\"\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.3.1\",\n\t\t\t\"date\": \"Thu, 11 Jul 2019 19:13:08 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add support for TypeScript 3.5\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.3.0\",\n\t\t\t\"date\": \"Tue, 09 Jul 2019 19:13:24 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add a \\\"--diagnostics\\\" command-line option to help when troubleshooting problems\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.2.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.2.3\",\n\t\t\t\"date\": \"Mon, 08 Jul 2019 19:12:18 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix a problem when analyzing .d.ts files that appear in the same folder as the corresponding .ts file (GitHub #1310)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.2.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.2.2\",\n\t\t\t\"date\": \"Sat, 29 Jun 2019 02:30:10 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix GitHub issue #1304 where \\\"IExtractorInvokeOptions.typescriptCompilerFolder\\\" did not work with TypeScript 3.4\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.2.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.2.1\",\n\t\t\t\"date\": \"Wed, 12 Jun 2019 19:12:33 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.2.5` to `4.2.6`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.2.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.2.0\",\n\t\t\t\"date\": \"Tue, 11 Jun 2019 00:48:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Generate ApiTypeParameter entries and type alias types\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.1.3` to `7.2.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.1.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.1.8\",\n\t\t\t\"date\": \"Wed, 05 Jun 2019 19:12:34 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where TSDoc index selectors (ApiParameterListMixin.overloadIndex) started from 0, whereas TSDoc requires a nonzero number\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.1.2` to `7.1.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.1.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.1.7\",\n\t\t\t\"date\": \"Tue, 04 Jun 2019 05:51:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade api-extractor-model to remove ApiConstructor.isStatic, since TypeScript constructors cannot be static\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve handling of symbolic property and method names.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.1.1` to `7.1.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.1.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.1.6\",\n\t\t\t\"date\": \"Mon, 27 May 2019 04:13:44 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix incorrect path resolution for the \\\"extends\\\" field when loading tsconfig.json\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.1.0` to `7.1.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.2.4` to `4.2.5`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.1.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.1.5\",\n\t\t\t\"date\": \"Mon, 13 May 2019 02:08:35 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Broaden support for default imports\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.1.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.1.4\",\n\t\t\t\"date\": \"Mon, 06 May 2019 20:46:21 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.2.3` to `4.2.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.1.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.1.3\",\n\t\t\t\"date\": \"Mon, 06 May 2019 19:34:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add a new setting \\\"omitTrimmingComments\\\" to prevent extra comments from being emitted in the .d.ts rollup\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.1.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.1.2\",\n\t\t\t\"date\": \"Mon, 06 May 2019 19:11:16 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where ExtractorResult.warningCount was not incremented for messages handled by IExtractorInvokeOptions.messageCallback (GitHub #1258)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.1.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.1.1\",\n\t\t\t\"date\": \"Tue, 30 Apr 2019 23:08:02 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where API signatures were sometimes truncated in the .api.json file (GitHub #1249)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.1.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.1.0\",\n\t\t\t\"date\": \"Tue, 16 Apr 2019 11:01:37 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Initial stable release of API Extractor 7\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.0.28` to `7.1.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.42\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.42\",\n\t\t\t\"date\": \"Fri, 12 Apr 2019 06:13:16 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix a regression that prevented certain types of warnings from being reported\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.41\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.41\",\n\t\t\t\"date\": \"Thu, 11 Apr 2019 07:14:01 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"THIS IS A RELEASE CANDIDATE FOR API-EXTRACTOR 7\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"(Breaking change) Rename \\\"mainEntryPointFile\\\" to \\\"mainEntryPointFilePath\\\" so all settings use a consistent naming convention\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"(Breaking change) Paths that appear in api-extractor.json are now resolved relative to the config file unless prefixed with the `<projectFolder>` token\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add a new api-extractor.json setting \\\"tsconfigFilePath\\\" for customizing the tsconfig.json path\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Replace ExtractorConfig.packageJsonFullPath with ExtractorConfig.packageFolder\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade API Extractor to use TypeScript 3.4 for analysis\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.40\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.40\",\n\t\t\t\"date\": \"Tue, 09 Apr 2019 05:31:01 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve the \\\"--local\\\" option to automatically create the API report file if it is missing\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.39\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.39\",\n\t\t\t\"date\": \"Mon, 08 Apr 2019 19:12:52 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Rename \\\"addToApiReviewFile\\\" setting to \\\"addToApiReportFile\\\"\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.38\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.38\",\n\t\t\t\"date\": \"Sat, 06 Apr 2019 02:05:51 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"(Breaking change) Removed the ILogger API and renamed ExtractorMessageLogLevel to ExtractorLogLevel\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"(Breaking change) Extractor console output is now modeled as ExtractorMessage objects and can be customized/filtered/handled by IExtractorInvokeOptions.messageCallback\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.37\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.37\",\n\t\t\t\"date\": \"Fri, 05 Apr 2019 04:16:16 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Introduce \\\"api-extractor init\\\" command-line that helps enable API Extractor for a new project\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"(Breaking change) Major redesign of the API used to invoke API Extractor\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"(Breaking change) Major redesign of the api-extractor.json config file format\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add a CompilerState API that allows an optimization where multiple invocations of Extractor can reuse the same TypeScript compiler analysis\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.36\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.36\",\n\t\t\t\"date\": \"Wed, 03 Apr 2019 02:58:33 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where .d.ts.map file were sometimes mapped to the wrong location\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.35\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.35\",\n\t\t\t\"date\": \"Sat, 30 Mar 2019 22:27:16 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Reintroduce the generated documentation notice for internal constructors\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add limited support for resolving @inheritDoc references to external packages by postprocessing them in api-documenter\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.34\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.34\",\n\t\t\t\"date\": \"Thu, 28 Mar 2019 19:14:27 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Validate `@link` tags and report a warning if the link cannot be resolved\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.33\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.33\",\n\t\t\t\"date\": \"Tue, 26 Mar 2019 20:54:18 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Reintroduce support for `@inheritDoc` tags\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.32\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.32\",\n\t\t\t\"date\": \"Sat, 23 Mar 2019 03:48:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"If the TSDoc summary is missing for a class constructor, then automatically generate it\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Reintroduce support for the `@preapproved` TSDoc tag\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.31\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.31\",\n\t\t\t\"date\": \"Thu, 21 Mar 2019 04:59:11 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Reintroduce \\\"ae-internal-missing-underscore\\\" warning for API items marked as `@internal` but whose name does not start with an underscore\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.30\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.30\",\n\t\t\t\"date\": \"Thu, 21 Mar 2019 01:15:32 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve the API review file generation to include imports and support multiple exports\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.29\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.29\",\n\t\t\t\"date\": \"Wed, 20 Mar 2019 19:14:49 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"API Extractor can now analyze packages whose package.json file is missing the \\\"version\\\" field\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.0.27` to `7.0.28`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.12.1` to `3.13.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.28\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.28\",\n\t\t\t\"date\": \"Mon, 18 Mar 2019 04:28:43 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Rename the \\\"ae-inconsistent-release-tags\\\" warning to \\\"ae-different-release-tags\\\"\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Introduce a new warning \\\"ae-incompatible-release-tags\\\" that checks for API signatures that reference types with incompatible release tags\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where this error was sometimes reported incorrectly: \\\"The messages.extractorMessageReporting table contains an unrecognized identifier ___\\\"\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.0.26` to `7.0.27`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.12.0` to `3.12.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.27\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.27\",\n\t\t\t\"date\": \"Fri, 15 Mar 2019 19:13:25 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"(Breaking change) The file extension for API review files has changed from \\\".api.ts\\\" to \\\"api.md\\\".  For details see https://github.com/microsoft/web-build-tools/issues/1123\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.26\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.26\",\n\t\t\t\"date\": \"Wed, 13 Mar 2019 19:13:14 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Refactor code to move the IndentedWriter API from api-extractor-model to api-documenter\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.0.25` to `7.0.26`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.25\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.25\",\n\t\t\t\"date\": \"Wed, 13 Mar 2019 01:14:05 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade TSDoc\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.0.24` to `7.0.25`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.24\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.24\",\n\t\t\t\"date\": \"Mon, 11 Mar 2019 16:13:36 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where spurious TSDoc warnings were issued because the TSDoc parser was configured improperly\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Move the .api.json related APIs into a new NPM package @microsoft/api-extractor-model\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/api-extractor-model\\\" from `7.0.23` to `7.0.24`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.23\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.23\",\n\t\t\t\"date\": \"Tue, 05 Mar 2019 17:13:11 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Issue a warning when an exported type refers to another local type that is not exported (ae-forgotten-export)\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"The export analyzer now correctly handles symbols imported using \\\"import x = require('y');\\\" notation\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.22\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.22\",\n\t\t\t\"date\": \"Mon, 04 Mar 2019 17:13:19 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Every error/warning message reported by API Extractor now has an associated message identifier\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add a new section to api-extractor.json for configuring how errors get reported, with ability to suppress individual errors\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Reintroduce the ability to report issues by writing warnings into the API review file\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where members of type literals were incorrectly being flagged as \\\"(undocumented)\\\"\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Error messages now cite the original .ts source file, if a source map is present. (To enable this, specify `\\\"declarationMap\\\": true` in tsconfig.json.)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.21\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.21\",\n\t\t\t\"date\": \"Wed, 27 Feb 2019 22:13:58 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.11.1` to `3.12.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.20\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.20\",\n\t\t\t\"date\": \"Wed, 27 Feb 2019 17:13:17 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.11.0` to `3.11.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.19\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.19\",\n\t\t\t\"date\": \"Mon, 18 Feb 2019 17:13:23 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"New way to resolve & generate TSDoc metadata file\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.10.0` to `3.11.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.18\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.18\",\n\t\t\t\"date\": \"Tue, 12 Feb 2019 17:13:12 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add a workaround for the issue where .d.ts rollups sometimes define names that conflict with a global symbol (the full solution is tracked by GitHub #1095)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.17\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.17\",\n\t\t\t\"date\": \"Mon, 11 Feb 2019 10:32:37 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where API Extractor neglected to analyze \\\"typeof\\\" expressions\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where declarations inside a namespace were sometimes being incorrectly emitted as top-level exports of the .d.ts rollup\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.16\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.16\",\n\t\t\t\"date\": \"Mon, 11 Feb 2019 08:55:57 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Redesign the analyzer so that when an external symbol is reexported by the working package, the local object (AstImport) and external object (AstSymbol) are kept separate\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix a number of bugs where external symbols were misinterpreted as being part of the local project\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Eliminate a number of errors involving unusual language constructs, by avoiding analysis of external symbols unless it's really necessary\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Simplify the AstSymbol.nominalAnalysis concept and associated code\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve .d.ts rollup trimming to handle reexported symbols correctly\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.15\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.15\",\n\t\t\t\"date\": \"Mon, 11 Feb 2019 03:31:55 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"The `--debug` parameter now automatically breaks in the debugger when InternalError is thrown\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.9.0` to `3.10.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.14\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.14\",\n\t\t\t\"date\": \"Thu, 31 Jan 2019 17:03:49 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade to TSDoc 0.12.5, which allows `$` in `@param` names\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add \\\"testMode\\\" option in api-extractor.json to eliminate spurious diffs in test files when the version number gets bumped\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Normalize newlines for excerpt strings in the .api.json file\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.13\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.13\",\n\t\t\t\"date\": \"Sat, 19 Jan 2019 03:47:47 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Move the skipLibCheck into the config file.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.12\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.12\",\n\t\t\t\"date\": \"Sat, 19 Jan 2019 01:17:51 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where files using \\\"export=\\\" were incorrectly interpreted as having ambient declarations\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.11\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.11\",\n\t\t\t\"date\": \"Fri, 18 Jan 2019 00:52:21 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add support for circular references between files that use `export * from \\\"____\\\";`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.10\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.10\",\n\t\t\t\"date\": \"Thu, 17 Jan 2019 00:37:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add support for exports of the form `export * from \\\"____\\\";`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve the analyzer to allow a declaration to be exported more than once\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix inconsistent newlines in .api.ts files\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.9\",\n\t\t\t\"date\": \"Thu, 10 Jan 2019 01:57:52 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue with rolling up default exports (https://github.com/microsoft/web-build-tools/issues/1007)\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.8.3` to `3.9.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.8\",\n\t\t\t\"date\": \"Thu, 20 Dec 2018 17:04:08 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where it was possible to import forgotten declarations from a .d.ts rollup, even though they did not have an explicit \\\"export\\\" modifier\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.7\",\n\t\t\t\"date\": \"Wed, 19 Dec 2018 05:57:33 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Extend ApiModel to support new item kinds: ApiCallSignature, ApiConstructor, ApiConstructSignature, ApiFunction, ApiIndexSignature, ApiTypeAlias, and ApiVariable\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.8.2` to `3.8.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.6\",\n\t\t\t\"date\": \"Fri, 14 Dec 2018 19:43:46 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update web site URLs\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.5\",\n\t\t\t\"date\": \"Thu, 13 Dec 2018 02:58:10 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Remove unused jju dependency\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.8.1` to `3.8.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.4\",\n\t\t\t\"date\": \"Wed, 12 Dec 2018 17:04:19 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Reintroduce support for \\\"extends\\\" and \\\"implements\\\" heritage clauses\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Redesign the Excerpt API to support multiple subranges (e.g. for a list of \\\"implements\\\" clauses)\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.8.0` to `3.8.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.3\",\n\t\t\t\"date\": \"Fri, 07 Dec 2018 17:04:56 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Added more API documentation\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.7.1` to `3.8.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.2.2` to `4.2.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.2\",\n\t\t\t\"date\": \"Wed, 05 Dec 2018 19:57:03 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"fix reexported types from an external package for dts rollup\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.1\",\n\t\t\t\"date\": \"Wed, 05 Dec 2018 17:04:18 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where .d.ts trimming did not properly handle variable declarations (GitHub #976)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v7.0.0\",\n\t\t\t\"date\": \"Thu, 29 Nov 2018 07:02:09 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"major\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"THIS IS A BETA RELEASE - We are bumping the version to \\\"7.0.0\\\" to simplify dogfooding. This release is not yet ready for general usage.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.7.0` to `3.7.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.3.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.3.0\",\n\t\t\t\"date\": \"Wed, 28 Nov 2018 19:29:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Support \\\"extends\\\" field in api-extractor.json config files for easier management of monorepos with many projects\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.2.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.2.0\",\n\t\t\t\"date\": \"Wed, 28 Nov 2018 02:17:11 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Introduce a new build output \\\"dist/tsdoc-metdata.json\\\", which completely replaces the old \\\"tsdocFlavor\\\" field in package.json\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.6.0` to `3.7.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.1.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.1.6\",\n\t\t\t\"date\": \"Fri, 16 Nov 2018 21:37:10 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add support for emitting `/// <reference lib=\\\"___\\\" />` directives in .d.ts rollups (GitHub issue #946)\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.5.2` to `3.6.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.1.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.1.5\",\n\t\t\t\"date\": \"Fri, 16 Nov 2018 00:59:00 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where .d.ts trimming did not work for exported variable declarations (GitHub #936)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.1.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.1.4\",\n\t\t\t\"date\": \"Fri, 09 Nov 2018 23:07:39 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade to TSDoc 0.21.2, which improves trimming of link text in `@link` tags\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.1.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.1.3\",\n\t\t\t\"date\": \"Wed, 07 Nov 2018 21:04:35 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.5.1` to `3.5.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.1.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.1.2\",\n\t\t\t\"date\": \"Mon, 05 Nov 2018 17:04:24 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade to @microsoft/tsdoc 0.12.0\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.5.0` to `3.5.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.1.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.1.1\",\n\t\t\t\"date\": \"Thu, 01 Nov 2018 19:32:52 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where EcmaScript symbols (\\\"computed property names\\\") were missing from .d.ts rollups\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.1.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.1.0\",\n\t\t\t\"date\": \"Wed, 31 Oct 2018 17:00:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Added an api to invoke api extractor processor by supplying api extractor json config file.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.0.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.0.9\",\n\t\t\t\"date\": \"Thu, 25 Oct 2018 23:20:40 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.4.0` to `3.5.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.0.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.0.8\",\n\t\t\t\"date\": \"Thu, 25 Oct 2018 08:56:02 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix issue where `DocErrorText.text` returned `[object Object]` instead of the text \"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.0.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.0.7\",\n\t\t\t\"date\": \"Wed, 24 Oct 2018 16:03:10 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.3.1` to `3.4.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.0.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.0.6\",\n\t\t\t\"date\": \"Thu, 18 Oct 2018 01:32:20 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix isAbsolute check for mainDtsRollupPath\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.0.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.0.5\",\n\t\t\t\"date\": \"Wed, 17 Oct 2018 21:04:49 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.3.0` to `3.3.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.0.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.0.4\",\n\t\t\t\"date\": \"Wed, 17 Oct 2018 14:43:24 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix a regression where namespaces were sometimes incorrectly handled in \\\"conservative\\\" mode\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update the command line to look for api-extractor.json in both the \\\"./config\\\" folder and the project folder\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Allow type references in namespaces when namespaceSupport=conservative\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.0.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.0.3\",\n\t\t\t\"date\": \"Thu, 11 Oct 2018 23:26:07 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where `import x from \\\".\\\"` was sometimes not processed correctly\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.0.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.0.2\",\n\t\t\t\"date\": \"Tue, 09 Oct 2018 06:58:01 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix a regression where API Extractor was sometimes reporting incorrect line numbers\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.0.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.0.1\",\n\t\t\t\"date\": \"Mon, 08 Oct 2018 16:04:27 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.2.0` to `3.3.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"6.0.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v6.0.0\",\n\t\t\t\"date\": \"Sun, 07 Oct 2018 06:15:56 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"major\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"(Breaking change) API Extractor 6 introduces support for TSDoc doc comment syntax!  Please see https://api-extractor.com/ for documentation.  To learn more about the TSDoc standard, check out https://github.com/microsoft/tsdoc\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.1.0` to `3.2.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.13.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.13.1\",\n\t\t\t\"date\": \"Fri, 28 Sep 2018 16:05:35 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.0.1` to `3.1.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.13.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.13.0\",\n\t\t\t\"date\": \"Wed, 26 Sep 2018 21:39:40 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add new command line option --skip-lib-check\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.12.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.12.2\",\n\t\t\t\"date\": \"Mon, 24 Sep 2018 23:06:40 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Allow doc comments to use TSDoc's \\\"@defaultvalue\\\" tag (but the value is not yet passed to the documentation pipeline)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.12.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.12.1\",\n\t\t\t\"date\": \"Fri, 21 Sep 2018 16:04:42 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where TypeScript errors are often logged as \\\"[Object object]\\\" instead of the actual error message.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.12.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.12.0\",\n\t\t\t\"date\": \"Thu, 20 Sep 2018 23:57:21 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add new feature: Support using a different version of the TypeScript compiler.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.11.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.11.2\",\n\t\t\t\"date\": \"Tue, 18 Sep 2018 21:04:55 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where parameters mentioned in comments were attempting to be analyzed by api-extractor.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.11.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.11.1\",\n\t\t\t\"date\": \"Thu, 06 Sep 2018 01:25:25 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update \\\"repository\\\" field in package.json\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.0.0` to `3.0.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.2.1` to `4.2.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.11.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.11.0\",\n\t\t\t\"date\": \"Mon, 03 Sep 2018 16:04:45 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade api-extractor to internally use TypeScript 3.0.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.10.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.10.8\",\n\t\t\t\"date\": \"Wed, 29 Aug 2018 06:36:50 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `2.2.1` to `3.0.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.10.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.10.7\",\n\t\t\t\"date\": \"Thu, 23 Aug 2018 18:18:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Republish all packages in web-build-tools to resolve GitHub issue #782\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `2.2.0` to `2.2.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.2.0` to `4.2.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.10.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.10.6\",\n\t\t\t\"date\": \"Wed, 22 Aug 2018 20:58:58 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `2.1.1` to `2.2.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.10.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.10.5\",\n\t\t\t\"date\": \"Wed, 22 Aug 2018 16:03:25 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `2.1.0` to `2.1.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.10.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.10.4\",\n\t\t\t\"date\": \"Tue, 21 Aug 2018 16:04:38 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"fix namespace name for export statement`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.10.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.10.3\",\n\t\t\t\"date\": \"Thu, 09 Aug 2018 21:03:22 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `2.0.0` to `2.1.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.10.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.10.2\",\n\t\t\t\"date\": \"Thu, 09 Aug 2018 16:04:24 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update lodash.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.10.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.10.1\",\n\t\t\t\"date\": \"Thu, 26 Jul 2018 16:04:17 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `1.5.0` to `2.0.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.10.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.10.0\",\n\t\t\t\"date\": \"Tue, 17 Jul 2018 16:02:52 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add support for new \\\"@eventproperty\\\" AEDoc tag, which indicates that a class/interface property should be documented as an event\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.9.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.9.1\",\n\t\t\t\"date\": \"Tue, 03 Jul 2018 21:03:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `1.4.1` to `1.5.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.9.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.9.0\",\n\t\t\t\"date\": \"Sat, 23 Jun 2018 02:21:20 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add new IMarkupHtmlTag API\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"AEDoc now allows HTML tags inside doc comments, which can be disabled using a backslash escape\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.8.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.8.1\",\n\t\t\t\"date\": \"Thu, 21 Jun 2018 08:27:29 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `1.4.0` to `1.4.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.8.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.8.0\",\n\t\t\t\"date\": \"Tue, 19 Jun 2018 19:35:11 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"For namespaceSupport=permissive, allow arbitrary nesting of namespaces\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where multi-line type literals sometimes had inconsistent newlines in the *.api.json file\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.7.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.7.3\",\n\t\t\t\"date\": \"Fri, 08 Jun 2018 08:43:52 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `1.3.2` to `1.4.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.1.0` to `4.2.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.7.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.7.2\",\n\t\t\t\"date\": \"Thu, 31 May 2018 01:39:33 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `1.3.1` to `1.3.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.7.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.7.1\",\n\t\t\t\"date\": \"Tue, 15 May 2018 02:26:45 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `1.3.0` to `1.3.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.7.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.7.0\",\n\t\t\t\"date\": \"Tue, 15 May 2018 00:18:10 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add support for new AEDoc tags @sealed, @virtual, and @override\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.6.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.6.8\",\n\t\t\t\"date\": \"Fri, 04 May 2018 00:42:38 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix the formatting of a log message.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `1.2.0` to `1.3.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.6.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.6.7\",\n\t\t\t\"date\": \"Tue, 01 May 2018 22:03:20 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where the *.d.ts rollup trimming did not trim import statements\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.6.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.6.6\",\n\t\t\t\"date\": \"Fri, 27 Apr 2018 03:04:32 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `4.0.0` to `4.1.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.6.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.6.5\",\n\t\t\t\"date\": \"Thu, 19 Apr 2018 21:25:56 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `3.1.1` to `4.0.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.6.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.6.4\",\n\t\t\t\"date\": \"Thu, 19 Apr 2018 17:02:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix errors in schema documentation\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.6.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.6.3\",\n\t\t\t\"date\": \"Tue, 03 Apr 2018 16:05:29 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `1.1.0` to `1.2.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.6.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.6.2\",\n\t\t\t\"date\": \"Mon, 02 Apr 2018 16:05:24 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Refactor to use new @microsoft/node-core-library\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `1.0.0` to `1.1.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.6.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.6.1\",\n\t\t\t\"date\": \"Tue, 27 Mar 2018 01:34:25 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update build config so API Extractor builds using the latest version of itself\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.6.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.6.0\",\n\t\t\t\"date\": \"Sun, 25 Mar 2018 01:26:19 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"In preparation for initial release, the \\\"Package Typings\\\" feature was renamed to \\\"DTS Rollup\\\"\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where the @packagedocumentation comment was sometimes getting mixed into the middle of the rollup *.d.ts file\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve the api-extractor.json config file so that *.d.ts rollups go in separate folders, and trimming can now be disabled\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.5.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.5.2\",\n\t\t\t\"date\": \"Fri, 23 Mar 2018 00:34:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade colors to version ~1.2.1\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `3.1.0` to `3.1.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.5.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.5.1\",\n\t\t\t\"date\": \"Tue, 20 Mar 2018 02:44:45 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve packageTypings generator to trim nested members according to their release tag\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix a bug where packageTypings failed to handle merged declarations properly\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.5.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.5.0\",\n\t\t\t\"date\": \"Sat, 17 Mar 2018 02:54:22 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Overhaul the packageTypings generator analysis to get ready for the upcoming nested member trimming\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Breaking change: Any projects using the package typings feature must now have a \\\"tsdoc\\\" section in their package.json\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add \\\"--debug\\\" flag for debugging\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.8.0` to `1.0.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.4.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.4.0\",\n\t\t\t\"date\": \"Thu, 15 Mar 2018 20:00:50 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add a new setting validationRules.missingReleaseTags to optionally remove the requirement that every API item should have a release tag\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add new API \\\"Markup.formatApiItemReference()\\\"\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where the automatically generated documentation for class constructors sometimes had a broken hyperlink\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `3.0.7` to `3.1.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.3.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.3.9\",\n\t\t\t\"date\": \"Thu, 15 Mar 2018 16:05:43 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.7.3` to `0.8.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.3.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.3.8\",\n\t\t\t\"date\": \"Mon, 12 Mar 2018 20:36:19 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Locked down some \\\"@types/\\\" dependency versions to avoid upgrade conflicts\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `3.0.6` to `3.0.7`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.3.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.3.7\",\n\t\t\t\"date\": \"Tue, 06 Mar 2018 17:04:51 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add preliminary support for preview and public outputs for packageTypings generator\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.3.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.3.6\",\n\t\t\t\"date\": \"Fri, 02 Mar 2018 01:13:59 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.7.2` to `0.7.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `3.0.5` to `3.0.6`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.3.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.3.5\",\n\t\t\t\"date\": \"Tue, 27 Feb 2018 22:05:57 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.7.1` to `0.7.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `3.0.4` to `3.0.5`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.3.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.3.4\",\n\t\t\t\"date\": \"Wed, 21 Feb 2018 22:04:19 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.7.0` to `0.7.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `3.0.3` to `3.0.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.3.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.3.3\",\n\t\t\t\"date\": \"Wed, 21 Feb 2018 03:13:28 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.6.1` to `0.7.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `3.0.2` to `3.0.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.3.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.3.2\",\n\t\t\t\"date\": \"Sat, 17 Feb 2018 02:53:49 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix several bugs with the way that imports were being deduplicated by the packageTypings feature\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.6.0` to `0.6.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `3.0.1` to `3.0.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.3.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.3.1\",\n\t\t\t\"date\": \"Fri, 16 Feb 2018 22:05:23 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.5.1` to `0.6.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `3.0.0` to `3.0.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.3.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.3.0\",\n\t\t\t\"date\": \"Fri, 16 Feb 2018 17:05:11 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where the packageTypings feature sometimes emitted \\\"default\\\" instead of the class name\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve the packageTypings feature to support triple-slash references to typings\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where the packageTypings feature didn't handle some import/export patterns\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.5.0` to `0.5.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.3.10` to `3.0.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.2.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.2.7\",\n\t\t\t\"date\": \"Wed, 07 Feb 2018 17:05:11 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.4.10` to `0.5.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.3.9` to `2.3.10`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.2.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.2.6\",\n\t\t\t\"date\": \"Fri, 26 Jan 2018 22:05:30 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.4.9` to `0.4.10`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.3.8` to `2.3.9`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.2.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.2.5\",\n\t\t\t\"date\": \"Fri, 26 Jan 2018 17:53:38 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Force a patch bump in case the previous version was an empty package\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.4.8` to `0.4.9`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.3.7` to `2.3.8`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.2.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.2.4\",\n\t\t\t\"date\": \"Fri, 26 Jan 2018 00:36:51 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.4.7` to `0.4.8`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.3.6` to `2.3.7`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.2.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.2.3\",\n\t\t\t\"date\": \"Tue, 23 Jan 2018 17:05:28 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.4.6` to `0.4.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.3.5` to `2.3.6`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.2.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.2.2\",\n\t\t\t\"date\": \"Thu, 18 Jan 2018 03:23:46 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Enable package typings generated by api-extractor\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.4.5` to `0.4.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.3.4` to `2.3.5`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.2.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.2.1\",\n\t\t\t\"date\": \"Thu, 18 Jan 2018 00:48:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.4.4` to `0.4.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.3.3` to `2.3.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.2.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.2.0\",\n\t\t\t\"date\": \"Thu, 18 Jan 2018 00:27:23 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve the packageTypings feature to support abstract classes and \\\"import * as X\\\" imports\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.4.3` to `0.4.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.1.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.1.3\",\n\t\t\t\"date\": \"Wed, 17 Jan 2018 10:49:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.4.2` to `0.4.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.3.2` to `2.3.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.1.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.1.2\",\n\t\t\t\"date\": \"Fri, 12 Jan 2018 03:35:22 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"4589070d63c8c1d5d77bfa5e52b4f9fd2734e19f\",\n\t\t\t\t\t\t\"comment\": \"Add some incremental improvements for the experimental PackageTypingsGenerator feature\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.4.1` to `0.4.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.3.1` to `2.3.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.1.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.1.1\",\n\t\t\t\"date\": \"Thu, 11 Jan 2018 22:31:51 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.4.0` to `0.4.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.3.0` to `2.3.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.1.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.1.0\",\n\t\t\t\"date\": \"Wed, 10 Jan 2018 20:40:01 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"Nicholas Pape <nickpape-msft@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"1271a0dc21fedb882e7953f491771724f80323a1\",\n\t\t\t\t\t\t\"comment\": \"Upgrade to Node 8\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"e6afac460ac96fa5e7a54d6ccab84aca4546cc5e\",\n\t\t\t\t\t\t\"comment\": \"Continued progress for the experimental PackageTypingsGenerator\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.3.26` to `0.4.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.2.14` to `2.3.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.0.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.0.1\",\n\t\t\t\"date\": \"Tue, 09 Jan 2018 17:05:51 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"Nicholas Pape <nickpape-msft@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"d00b6549d13610fbb6f84be3478b532be9da0747\",\n\t\t\t\t\t\t\"comment\": \"Get web-build-tools building with pnpm\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.3.25` to `0.3.26`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.2.13` to `2.2.14`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"5.0.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v5.0.0\",\n\t\t\t\"date\": \"Sun, 07 Jan 2018 05:12:08 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"major\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"aa0c67382d4dee0cde40ee84a581dbdcdabe77ef\",\n\t\t\t\t\t\t\"comment\": \"API Extractor now processes *.d.ts files instead of *.ts files\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"aa0c67382d4dee0cde40ee84a581dbdcdabe77ef\",\n\t\t\t\t\t\t\"comment\": \"Introduced new tag @packagedocumentation which replaces the earlier approach that used a \\\"packageDescription\\\" variable\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.3.24` to `0.3.25`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.2.12` to `2.2.13`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.3.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.3.7\",\n\t\t\t\"date\": \"Fri, 05 Jan 2018 20:26:45 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.3.23` to `0.3.24`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.2.11` to `2.2.12`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.3.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.3.6\",\n\t\t\t\"date\": \"Fri, 05 Jan 2018 00:48:41 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"Nicholas Pape <nickpape-msft@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"b942f54445bf01dbdb98aaa5f0007f5b95315b58\",\n\t\t\t\t\t\t\"comment\": \"Update Jest to ~21.2.1\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.3.22` to `0.3.23`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.2.10` to `2.2.11`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.3.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.3.5\",\n\t\t\t\"date\": \"Fri, 22 Dec 2017 17:04:46 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"e27707503756cbfb2e9332833b987009c32b8198\",\n\t\t\t\t\t\t\"comment\": \"Fixed an issue where warnings would cause the api-extractor tool to return a nonzero exit code for a \\\"--local\\\" build; warnings should not fail the build in this scenario\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.3.21` to `0.3.22`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.2.9` to `2.2.10`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.3.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.3.4\",\n\t\t\t\"date\": \"Tue, 12 Dec 2017 03:33:26 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.3.20` to `0.3.21`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.2.8` to `2.2.9`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.3.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.3.3\",\n\t\t\t\"date\": \"Thu, 30 Nov 2017 23:59:09 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.3.19` to `0.3.20`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.2.7` to `2.2.8`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.3.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.3.2\",\n\t\t\t\"date\": \"Thu, 30 Nov 2017 23:12:21 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.3.18` to `0.3.19`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.2.6` to `2.2.7`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.3.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.3.1\",\n\t\t\t\"date\": \"Wed, 29 Nov 2017 17:05:37 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.3.17` to `0.3.18`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.2.5` to `2.2.6`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.3.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.3.0\",\n\t\t\t\"date\": \"Tue, 28 Nov 2017 23:43:55 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"aa6a9d0000c787f37623ae434cccbb5f0fdb7f29\",\n\t\t\t\t\t\t\"comment\": \"Add Extractor.processProject() whose return value indicates success\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"aa6a9d0000c787f37623ae434cccbb5f0fdb7f29\",\n\t\t\t\t\t\t\"comment\": \"Deprecate Extractor.analyzeProject() API\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.3.16` to `0.3.17`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.2.4` to `2.2.5`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.2.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.2.6\",\n\t\t\t\"date\": \"Mon, 13 Nov 2017 17:04:50 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.3.15` to `0.3.16`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.2.3` to `2.2.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.2.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.2.5\",\n\t\t\t\"date\": \"Mon, 06 Nov 2017 17:04:18 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.3.14` to `0.3.15`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.2.2` to `2.2.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.2.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.2.4\",\n\t\t\t\"date\": \"Thu, 02 Nov 2017 16:05:24 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"QZ <qz2017@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"2c58095f2f13492887cc1278c9a0cff49af9735b\",\n\t\t\t\t\t\t\"comment\": \"lock the reference version between web build tools projects\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `0.3.13` to `0.3.14`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `2.2.1` to `2.2.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.2.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.2.3\",\n\t\t\t\"date\": \"Wed, 01 Nov 2017 21:06:08 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"e449bd6cdc3c179461be68e59590c25021cd1286\",\n\t\t\t\t\t\t\"comment\": \"Upgrade cyclic dependencies\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.3.12` to `~0.3.13`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `~2.2.0` to `~2.2.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.2.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.2.2\",\n\t\t\t\"date\": \"Tue, 31 Oct 2017 21:04:04 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.3.11` to `~0.3.12`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `~2.1.4` to `~2.2.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.2.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.2.1\",\n\t\t\t\"date\": \"Tue, 31 Oct 2017 16:04:55 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.3.10` to `~0.3.11`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `~2.1.3` to `~2.1.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.2.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.2.0\",\n\t\t\t\"date\": \"Wed, 25 Oct 2017 20:03:59 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"6cc203e0282130eb7c9a40906c1a8861c763d56c\",\n\t\t\t\t\t\t\"comment\": \"Improved the way API JSON represents documentation markup; this is a file format change\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.3.9` to `~0.3.10`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `~2.1.2` to `~2.1.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.1.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.1.2\",\n\t\t\t\"date\": \"Tue, 24 Oct 2017 18:17:12 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.3.8` to `~0.3.9`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `~2.1.1` to `~2.1.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.1.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.1.1\",\n\t\t\t\"date\": \"Mon, 23 Oct 2017 21:53:12 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"5de032b254b632b8af0d0dd98913acef589f88d5\",\n\t\t\t\t\t\t\"comment\": \"Updated cyclic dependencies\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.3.7` to `~0.3.8`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/ts-command-line\\\" from `~2.1.0` to `~2.1.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.1.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.1.0\",\n\t\t\t\"date\": \"Fri, 20 Oct 2017 19:57:12 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"3c4f7aeb43999a968da41a8a2a2acbc3410f4ae9\",\n\t\t\t\t\t\t\"comment\": \"Fixed an issue where properties were sometimes marked as readonly; a remark is automatically generated for classes with internal constructors\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"e37c63a2810a22957806bfe6a607b6c925244b7a\",\n\t\t\t\t\t\t\"comment\": \"Add policies.namespaceSupport option to API Extractor config\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.3.6` to `~0.3.7`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.0.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.0.1\",\n\t\t\t\"date\": \"Fri, 20 Oct 2017 01:52:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"7f9f66ba071e2bcf77f224f784c14efbe627ba40\",\n\t\t\t\t\t\t\"comment\": \"Rename ApiExtractor class to Extractor\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.3.5` to `~0.3.6`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"4.0.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v4.0.0\",\n\t\t\t\"date\": \"Fri, 20 Oct 2017 01:04:44 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"major\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"3ff332dc81aafca27952120afc1be0788239b741\",\n\t\t\t\t\t\t\"comment\": \"Redesigned interface for invoking API Extractor\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.3.4` to `~0.3.5`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"3.4.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v3.4.2\",\n\t\t\t\"date\": \"Thu, 05 Oct 2017 01:05:02 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.3.2` to `~0.3.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"3.4.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v3.4.1\",\n\t\t\t\"date\": \"Fri, 29 Sep 2017 01:03:42 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"5d78825558e12fa828d114a655975c315aa1a566\",\n\t\t\t\t\t\t\"comment\": \"Removed IMarkupPage.docId\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.3.1` to `~0.3.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"3.4.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v3.4.0\",\n\t\t\t\"date\": \"Thu, 28 Sep 2017 01:04:28 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"8e0010db430e7d6b84d12f38c5c1669c94ccf30e\",\n\t\t\t\t\t\t\"comment\": \"The *.api.json \\\"linkDocElement\\\" type now always explicitly specifies the package name, rather than expecting the reader to infer it\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"8e0010db430e7d6b84d12f38c5c1669c94ccf30e\",\n\t\t\t\t\t\t\"comment\": \"The *.api.json file format now exposes \\\"signature\\\" information for properties, functions, and module variables\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"0309dea3eb9f78162f85d59ae4fbf5f1b6f4ea31\",\n\t\t\t\t\t\t\"comment\": \"Skipping two lines in an AEDoc comment now creates a paragraph separator for the generated documentation\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.3.0` to `~0.3.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"3.3.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v3.3.0\",\n\t\t\t\"date\": \"Fri, 22 Sep 2017 01:04:02 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"Nick Pape <nickpape@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"481a10f460a454fb5a3e336e3cf25a1c3f710645\",\n\t\t\t\t\t\t\"comment\": \"Upgrade to es6\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.2.11` to `~0.3.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"3.2.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v3.2.6\",\n\t\t\t\"date\": \"Wed, 20 Sep 2017 22:10:17 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.2.10` to `~0.2.11`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"3.2.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v3.2.5\",\n\t\t\t\"date\": \"Mon, 11 Sep 2017 13:04:55 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"d4271683f40917843650ddb537dcd21f1b3372be\",\n\t\t\t\t\t\t\"comment\": \"The isBeta and deprecatedMessage fields are now inherited in the *.api.json files\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"7de7daf14ea8299922e578125669ecfabbde8857\",\n\t\t\t\t\t\t\"comment\": \"Fix an issue where the *.api.json file was sometimes missing function parameters\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.2.9` to `~0.2.10`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"3.2.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v3.2.4\",\n\t\t\t\"date\": \"Fri, 08 Sep 2017 01:28:04 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"Nick Pape <nickpape@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"bb96549aa8508ff627a0cae5ee41ae0251f2777d\",\n\t\t\t\t\t\t\"comment\": \"Deprecate @types/es6-coll ections in favor of built-in typescript typings 'es2015.collection' a nd 'es2015.iterable'\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.2.7` to `~0.2.8`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"3.2.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v3.2.3\",\n\t\t\t\"date\": \"Thu, 07 Sep 2017 13:04:35 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"pgonzal <pgonzal@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"a8b0022b8912d6fb07d1e0dd6618f8842ad6e86c\",\n\t\t\t\t\t\t\"comment\": \"Fix incorrect schema/typings for enum members\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.2.6` to `~0.2.7`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"3.2.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v3.2.2\",\n\t\t\t\"date\": \"Thu, 07 Sep 2017 00:11:11 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"author\": \"Nick Pape <nickpape@users.noreply.github.com>\",\n\t\t\t\t\t\t\"commit\": \"4b7451b442c2078a96430f7a05caed37101aed52\",\n\t\t\t\t\t\t\"comment\": \" Add $schema field to all schemas\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.2.5` to `~0.2.6`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"3.2.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v3.2.1\",\n\t\t\t\"date\": \"Wed, 06 Sep 2017 13:03:42 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Converted IMarkupDocumentationLink to IMarkupApiLink, which exposes the underlying IApiItemReference rather than assuming a particular \\\"document ID\\\" model\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.2.4` to `~0.2.5`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"3.2.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v3.2.0\",\n\t\t\t\"date\": \"Tue, 05 Sep 2017 19:03:56 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add the constructor signature and package name to the exported API signature\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.2.3` to `~0.2.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"3.1.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v3.1.0\",\n\t\t\t\"date\": \"Sat, 02 Sep 2017 01:04:26 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Expanded the api-extractor API to expose interfaces for the *.api.json file fileformat\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.2.2` to `~0.2.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"3.0.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v3.0.0\",\n\t\t\t\"date\": \"Thu, 31 Aug 2017 18:41:18 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"major\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix compatibility issues with old releases, by incrementing the major version number\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.2.1` to `~0.2.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.3.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.3.7\",\n\t\t\t\"date\": \"Thu, 31 Aug 2017 17:46:25 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix issue where node-core-library was not an explicit dependency\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.2.0` to `~0.2.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.3.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.3.6\",\n\t\t\t\"date\": \"Wed, 30 Aug 2017 01:04:34 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `~0.1.3` to `~0.2.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.3.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.3.5\",\n\t\t\t\"date\": \"Thu, 24 Aug 2017 22:44:12 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update the schema validator.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.3.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.3.4\",\n\t\t\t\"date\": \"Thu, 24 Aug 2017 01:04:33 GMT\",\n\t\t\t\"comments\": {}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.3.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.3.3\",\n\t\t\t\"date\": \"Tue, 22 Aug 2017 13:04:22 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Added \\\"api-documenter\\\" code sample\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.3.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.3.2\",\n\t\t\t\"date\": \"Tue, 15 Aug 2017 01:29:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Introduce Span parser for upcoming *.d.ts generator\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.3.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.3.1\",\n\t\t\t\"date\": \"Thu, 27 Jul 2017 01:04:48 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade to the TS2.4 version of the build tools.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.3.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.3.0\",\n\t\t\t\"date\": \"Tue, 25 Jul 2017 20:03:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade to TypeScript 2.4\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.2.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.2.0\",\n\t\t\t\"date\": \"Wed, 21 Jun 2017 04:19:35 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add two new features: An error is reported if a top-level definition is missing its release tag. The constructor summary will now be autogenerated if omitted.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.0.10\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.0.10\",\n\t\t\t\"date\": \"Tue, 20 Jun 2017 01:04:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve the wording of many error messages\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix a bug with parsing of @link tags\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Issue warnings for @internal definitions that are not prefixed with an underscore\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.0.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.0.9\",\n\t\t\t\"date\": \"Sat, 17 Jun 2017 01:02:59 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"The unsupported @summary tag is now reported as an error\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Use a cache to speed up package.json lookups\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.0.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.0.8\",\n\t\t\t\"date\": \"Wed, 14 Jun 2017 13:03:40 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Definitions marked as @beta are now included in the *.api.json files for documentation\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.0.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.0.7\",\n\t\t\t\"date\": \"Thu, 08 Jun 2017 05:15:52 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updated README.md\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.0.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.0.6\",\n\t\t\t\"date\": \"Mon, 15 May 2017 21:59:43 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Added support for Namespace with ApiNamespace\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.0.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.0.5\",\n\t\t\t\"date\": \"Sat, 22 Apr 2017 01:02:03 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Added check for API names that are not supported (only letters and numbers supported)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.0.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.0.4\",\n\t\t\t\"date\": \"Wed, 19 Apr 2017 20:18:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Remove ES6 Promise & @types/es6-promise typings\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.0.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.0.3\",\n\t\t\t\"date\": \"Fri, 14 Apr 2017 17:44:08 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Added collect references ability to detect determine type information of return types and parameter types.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.0.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.0.2\",\n\t\t\t\"date\": \"Fri, 07 Apr 2017 21:43:16 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Adjusted the version specifier for typescript to ~2.2.2\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.0.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.0.1\",\n\t\t\t\"date\": \"Thu, 06 Apr 2017 01:32:23 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Removed hard coding of @public for ApiPackage\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"2.0.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v2.0.0\",\n\t\t\t\"date\": \"Mon, 20 Mar 2017 21:52:20 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"major\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fixing whitespace, also a variable that was shadowing another variable.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.19\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.19\",\n\t\t\t\"date\": \"Mon, 20 Mar 2017 04:20:13 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Reverting change.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.18\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.18\",\n\t\t\t\"date\": \"Mon, 20 Mar 2017 03:50:55 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Reverting previous change, which causes a regression in SPFx yeoman sc enario.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.17\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.17\",\n\t\t\t\"date\": \"Mon, 20 Mar 2017 00:54:03 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fixing lint whitespace issues.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.16\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.16\",\n\t\t\t\"date\": \"Sun, 19 Mar 2017 19:10:30 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fixing variable that was shadowing another variable.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.15\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.15\",\n\t\t\t\"date\": \"Wed, 15 Mar 2017 01:32:09 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.14\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.14\",\n\t\t\t\"date\": \"Sat, 18 Feb 2017 02:32:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Seperated the ApiItem initialization into 3 stages: create documentation that doesn't require resolution, then complete initialization by resolving links and inheritdocs. This allows us to ignore harmless cycles like type references\\\"\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.13\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.13\",\n\t\t\t\"date\": \"Thu, 16 Feb 2017 22:10:39 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fixed Api-Extractor error message, changed apostrophe to backtick.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.12\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.12\",\n\t\t\t\"date\": \"Thu, 16 Feb 2017 18:56:57 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Added support for local API definition resolution\\\"\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.11\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.11\",\n\t\t\t\"date\": \"Sat, 11 Feb 2017 02:32:35 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Changed dependency for ApiDocumentation to abstract the resolving of API definition references.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.10\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.10\",\n\t\t\t\"date\": \"Fri, 10 Feb 2017 20:01:30 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \" Added support to not throw error, instead report error if no type is declared on properties and parameters\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.9\",\n\t\t\t\"date\": \"Tue, 07 Feb 2017 20:37:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fixing issue where undocumented comment was not being emitted.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.8\",\n\t\t\t\"date\": \"Sat, 04 Feb 2017 02:32:05 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Moved ApiItem references within ApiDocumentation, to ApiItem caller.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.7\",\n\t\t\t\"date\": \"Thu, 02 Feb 2017 14:05:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Refactored ApiDocumentation creation to resolve references method.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.6\",\n\t\t\t\"date\": \"Wed, 01 Feb 2017 20:09:30 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Added ApiItemKind enum and refactored child classes.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.5\",\n\t\t\t\"date\": \"Fri, 27 Jan 2017 20:04:15 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Changed name of Analyzer to Extractor, added support for external api json doc loading.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.4\",\n\t\t\t\"date\": \"Fri, 27 Jan 2017 02:35:10 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Added ExternalApiHelper class to be used in generating api documentation json files for external types.\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Added description for packages implementation.\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Added config folder with file to enable api-extractor on itself. rebuild project on previous build.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.3\",\n\t\t\t\"date\": \"Tue, 24 Jan 2017 01:36:35 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Json schema was updated to reflect feature additions to linkDocElement. The linkDocElement can now be of type 'code' which refers to an API definition reference.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.2\",\n\t\t\t\"date\": \"Fri, 20 Jan 2017 01:46:41 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-library-build\\\" from `~2.1.0` to `~2.2.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.1\",\n\t\t\t\"date\": \"Thu, 19 Jan 2017 20:04:40 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Check for missing JSDoc sequences changed.\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improved error messages\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.1.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.1.0\",\n\t\t\t\"date\": \"Wed, 18 Jan 2017 20:04:29 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating API Extractor to work with TypeScript 2.1\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.0.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.0.2\",\n\t\t\t\"date\": \"Mon, 16 Jan 2017 20:04:15 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"@link capability for href and API definition references\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.0.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.0.1\",\n\t\t\t\"date\": \"Fri, 13 Jan 2017 06:46:05 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-library-build\\\" from `~2.0.0` to `~2.1.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"1.0.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor_v1.0.0\",\n\t\t\t\"date\": \"Wed, 11 Jan 2017 14:11:26 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"major\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Introducing API Extractor\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "packages/api-extractor/CHANGELOG.md",
    "content": "# Change Log - @microsoft/api-extractor\n\nThis log was last generated on Mon, 30 Oct 2023 23:36:38 GMT and should not be manually modified.\n\n## 7.38.1\nMon, 30 Oct 2023 23:36:38 GMT\n\n_Version update only_\n\n## 7.38.0\nSun, 01 Oct 2023 02:56:29 GMT\n\n### Minor changes\n\n- Add a new message \"ae-undocumented\" to support logging of undocumented API items\n\n## 7.37.3\nSat, 30 Sep 2023 00:20:51 GMT\n\n### Patches\n\n- Don't strip out @alpha items when generating API reports.\n\n## 7.37.2\nThu, 28 Sep 2023 20:53:16 GMT\n\n_Version update only_\n\n## 7.37.1\nTue, 26 Sep 2023 09:30:33 GMT\n\n### Patches\n\n- Update type-only imports to include the type modifier.\n\n## 7.37.0\nFri, 15 Sep 2023 00:36:58 GMT\n\n### Minor changes\n\n- Update @types/node from 14 to 18\n\n## 7.36.4\nTue, 08 Aug 2023 07:10:39 GMT\n\n_Version update only_\n\n## 7.36.3\nWed, 19 Jul 2023 00:20:31 GMT\n\n### Patches\n\n- Updated semver dependency\n\n## 7.36.2\nWed, 12 Jul 2023 15:20:39 GMT\n\n### Patches\n\n- Add api-extractor support for .d.mts and .d.cts files\n\n## 7.36.1\nThu, 06 Jul 2023 00:16:19 GMT\n\n_Version update only_\n\n## 7.36.0\nMon, 19 Jun 2023 22:40:21 GMT\n\n### Minor changes\n\n- Use the `IRigConfig` interface in the `IExtractorConfigLoadForFolderOptions` object insteacd of the `RigConfig` class.\n\n## 7.35.4\nThu, 15 Jun 2023 00:21:01 GMT\n\n_Version update only_\n\n## 7.35.3\nTue, 13 Jun 2023 01:49:01 GMT\n\n_Version update only_\n\n## 7.35.2\nWed, 07 Jun 2023 22:45:16 GMT\n\n_Version update only_\n\n## 7.35.1\nMon, 29 May 2023 15:21:15 GMT\n\n_Version update only_\n\n## 7.35.0\nMon, 22 May 2023 06:34:32 GMT\n\n### Minor changes\n\n- Upgrade the TypeScript dependency to ~5.0.4\n\n## 7.34.9\nFri, 12 May 2023 00:23:05 GMT\n\n_Version update only_\n\n## 7.34.8\nThu, 04 May 2023 00:20:28 GMT\n\n_Version update only_\n\n## 7.34.7\nMon, 01 May 2023 15:23:20 GMT\n\n_Version update only_\n\n## 7.34.6\nSat, 29 Apr 2023 00:23:03 GMT\n\n_Version update only_\n\n## 7.34.5\nThu, 27 Apr 2023 17:18:42 GMT\n\n_Version update only_\n\n## 7.34.4\nFri, 10 Feb 2023 01:18:50 GMT\n\n_Version update only_\n\n## 7.34.3\nSun, 05 Feb 2023 03:02:02 GMT\n\n_Version update only_\n\n## 7.34.2\nWed, 01 Feb 2023 02:16:34 GMT\n\n_Version update only_\n\n## 7.34.1\nMon, 30 Jan 2023 16:22:30 GMT\n\n_Version update only_\n\n## 7.34.0\nWed, 25 Jan 2023 07:26:55 GMT\n\n### Minor changes\n\n- Add new .api.json field `isAbstract` to track `abstract` modifier in ApiClass, ApiMethod, and ApiProperty via ApiAbstractMixin (GitHub #3661)\n\n## 7.33.8\nWed, 18 Jan 2023 22:44:12 GMT\n\n### Patches\n\n- Use ts.getCheckFlags to fix TS 5.0\n\n## 7.33.7\nFri, 09 Dec 2022 16:18:28 GMT\n\n_Version update only_\n\n## 7.33.6\nTue, 08 Nov 2022 01:20:55 GMT\n\n_Version update only_\n\n## 7.33.5\nWed, 26 Oct 2022 00:16:16 GMT\n\n### Patches\n\n- Update the @microsoft/tsdoc dependency version to 0.14.2.\n\n## 7.33.4\nMon, 17 Oct 2022 22:14:21 GMT\n\n_Version update only_\n\n## 7.33.3\nMon, 17 Oct 2022 15:16:00 GMT\n\n### Patches\n\n- Fix a regression where the \"fileUrlPath\" property would contain a malformed path when API Extractor is run on Windows.\n\n## 7.33.2\nFri, 14 Oct 2022 15:26:31 GMT\n\n### Patches\n\n- Fix references from computed properties #3629\n\n## 7.33.1\nThu, 13 Oct 2022 00:20:15 GMT\n\n_Version update only_\n\n## 7.33.0\nTue, 11 Oct 2022 23:49:12 GMT\n\n### Minor changes\n\n- Extract the original source file path for relevant API items and add a new projectFolderUrl setting to the api-extractor.json config that allows one to specify what URL their project folder can be found at.\n\n## 7.32.1\nMon, 10 Oct 2022 15:23:44 GMT\n\n_Version update only_\n\n## 7.32.0\nThu, 29 Sep 2022 07:13:06 GMT\n\n### Minor changes\n\n- Update parser to TypeScript 4.8.\n\n## 7.31.2\nWed, 21 Sep 2022 20:21:10 GMT\n\n_Version update only_\n\n## 7.31.1\nThu, 15 Sep 2022 00:18:51 GMT\n\n_Version update only_\n\n## 7.31.0\nTue, 13 Sep 2022 00:16:55 GMT\n\n### Minor changes\n\n- Fix an issue where aliased classes sometimes had incorrect canonical references in *.api.json (GitHub  #3593)\n\n## 7.30.1\nMon, 12 Sep 2022 22:27:48 GMT\n\n### Patches\n\n- Fix a recent regression where items exported from both the entry point and from an exported namespace appeared only once in the API doc model (GitHub #3619)\n\n## 7.30.0\nFri, 02 Sep 2022 17:48:42 GMT\n\n### Minor changes\n\n- Add new \"apiReport.includeForgottenExports\" and \"docModel.includeForgottenExports\" properties to control whether forgotten exports are included in the API report and doc model files.\n- Fix incorrect declaration references for symbols not exported from the package's entry point.\n\n## 7.29.5\nWed, 24 Aug 2022 03:01:22 GMT\n\n_Version update only_\n\n## 7.29.4\nWed, 24 Aug 2022 00:14:38 GMT\n\n### Patches\n\n- Remove use of LegacyAdapters.sortStable\n\n## 7.29.3\nFri, 19 Aug 2022 00:17:19 GMT\n\n_Version update only_\n\n## 7.29.2\nWed, 10 Aug 2022 09:52:12 GMT\n\n### Patches\n\n- Fix incorrect declaration references for local symbols within namespaces\n\n## 7.29.1\nWed, 10 Aug 2022 08:12:16 GMT\n\n### Patches\n\n- Fix a regression where .api.json excerpts were sometimes missing tokens (GitHub #3561), and generally improve the quality of excerpt generation\n\n## 7.29.0\nWed, 03 Aug 2022 18:40:35 GMT\n\n### Minor changes\n\n- Upgrade TypeScript dependency to 4.7\n\n## 7.28.7\nMon, 01 Aug 2022 02:45:32 GMT\n\n_Version update only_\n\n## 7.28.6\nThu, 21 Jul 2022 23:30:27 GMT\n\n_Version update only_\n\n## 7.28.5\nThu, 21 Jul 2022 00:16:14 GMT\n\n_Version update only_\n\n## 7.28.4\nFri, 08 Jul 2022 15:17:46 GMT\n\n### Patches\n\n- Update api-extractor-template.json to \"testMode\" and \"enumMemberOrder\" comment sections.\n\n## 7.28.3\nMon, 04 Jul 2022 15:15:13 GMT\n\n### Patches\n\n- Make enumMemberOrder configuration field optional\n\n## 7.28.2\nThu, 30 Jun 2022 04:48:53 GMT\n\n### Patches\n\n- Improve logic that determines whether an API item is readonly\n\n## 7.28.1\nTue, 28 Jun 2022 22:47:13 GMT\n\n_Version update only_\n\n## 7.28.0\nTue, 28 Jun 2022 00:23:32 GMT\n\n### Minor changes\n\n- Add support for the \"ignoreMissingEntryPoint\" ExtractorConfig option to allow for loading an ExtractorConfig before the target project is built.\n\n## 7.27.1\nMon, 27 Jun 2022 18:43:09 GMT\n\n_Version update only_\n\n## 7.27.0\nSat, 25 Jun 2022 21:00:40 GMT\n\n### Minor changes\n\n- API Extractor now populates an initializerTokenRange field for ApiProperty and ApiVariable items.\n\n## 7.26.1\nSat, 25 Jun 2022 01:54:29 GMT\n\n_Version update only_\n\n## 7.26.0\nFri, 24 Jun 2022 07:16:47 GMT\n\n### Minor changes\n\n- Include new configuration option for preserving enum member order\n\n## 7.25.3\nThu, 23 Jun 2022 22:14:24 GMT\n\n_Version update only_\n\n## 7.25.2\nFri, 17 Jun 2022 09:17:54 GMT\n\n_Version update only_\n\n## 7.25.1\nFri, 17 Jun 2022 00:16:18 GMT\n\n_Version update only_\n\n## 7.25.0\nTue, 07 Jun 2022 09:37:04 GMT\n\n### Minor changes\n\n- Add an \"isReadonly\" field to the doc model to indicate whether a property or variable is readonly\n- Add an \"isProtected\" field to the doc model to indicate protected class members\n\n## 7.24.2\nWed, 25 May 2022 22:25:07 GMT\n\n### Patches\n\n- Fix an issue where API Extractor would fail to run on a project where `\"moduleResolution\"` is set to `\"Node16\"` in `tsconfig.json`\n\n## 7.24.1\nThu, 19 May 2022 15:13:20 GMT\n\n### Patches\n\n- Fix a recent regression that produced an error \"Cannot read properties of undefined\" (GitHub #3423)\n\n## 7.24.0\nSat, 14 May 2022 03:01:27 GMT\n\n### Minor changes\n\n- Throw an error early if API Extractor will attempt to process non-.d.ts files\n- Generate API doc model nodes for setters without getters\n\n### Patches\n\n- Address edge case in excerptBuilder token range logic\n\n## 7.23.2\nTue, 10 May 2022 01:20:43 GMT\n\n_Version update only_\n\n## 7.23.1\nWed, 04 May 2022 23:29:13 GMT\n\n### Patches\n\n- Update the global variable analyzer to add support for changes to the TypeScript internals coming in v4.7\n\n## 7.23.0\nSat, 23 Apr 2022 02:13:06 GMT\n\n### Minor changes\n\n- Update to TypeScript 4.6\n\n## 7.22.2\nFri, 15 Apr 2022 00:12:36 GMT\n\n_Version update only_\n\n## 7.22.1\nWed, 13 Apr 2022 15:12:40 GMT\n\n_Version update only_\n\n## 7.22.0\nTue, 12 Apr 2022 23:29:34 GMT\n\n### Minor changes\n\n- Add an alphaTrimmedFilePath option that adds support for generating a DTS rollup that inclues @alpha, @beta, and @public members.\n\n## 7.21.3\nTue, 12 Apr 2022 02:58:32 GMT\n\n### Patches\n\n- Update TSDoc dependencies.\n\n## 7.21.2\nSat, 09 Apr 2022 19:07:47 GMT\n\n### Patches\n\n- Fix ambient modules bug caused by #3321.\n\n## 7.21.1\nSat, 09 Apr 2022 02:24:26 GMT\n\n### Patches\n\n- Rename the \"master\" branch to \"main\".\n\n## 7.21.0\nFri, 08 Apr 2022 20:05:59 GMT\n\n### Minor changes\n\n- Add support for projects that use tsconfig.json \"baseUrl\" and \"paths\" settings to remap imports of local files (GitHub #3291)\n\n## 7.20.1\nWed, 06 Apr 2022 22:35:23 GMT\n\n### Patches\n\n- Fix an issue where .api.json excerpt text included extra whitespace (GitHub #3316)\n\n## 7.20.0\nThu, 31 Mar 2022 02:06:05 GMT\n\n### Minor changes\n\n- Updated api-extractor to extract whether a parameter is optional.\n\n## 7.19.5\nTue, 15 Mar 2022 19:15:53 GMT\n\n_Version update only_\n\n## 7.19.4\nWed, 05 Jan 2022 16:07:47 GMT\n\n_Version update only_\n\n## 7.19.3\nMon, 27 Dec 2021 16:10:40 GMT\n\n_Version update only_\n\n## 7.19.2\nThu, 09 Dec 2021 20:34:41 GMT\n\n_Version update only_\n\n## 7.19.1\nThu, 09 Dec 2021 00:21:54 GMT\n\n_Version update only_\n\n## 7.19.0\nWed, 08 Dec 2021 16:14:05 GMT\n\n### Minor changes\n\n- Update to TypeScript 4.5\n\n## 7.18.21\nMon, 06 Dec 2021 16:08:33 GMT\n\n_Version update only_\n\n## 7.18.20\nFri, 03 Dec 2021 03:05:22 GMT\n\n_Version update only_\n\n## 7.18.19\nSat, 06 Nov 2021 00:09:13 GMT\n\n_Version update only_\n\n## 7.18.18\nFri, 05 Nov 2021 15:09:18 GMT\n\n_Version update only_\n\n## 7.18.17\nWed, 27 Oct 2021 00:08:15 GMT\n\n### Patches\n\n- Update the package.json repository field to include the directory property.\n\n## 7.18.16\nWed, 13 Oct 2021 15:09:54 GMT\n\n_Version update only_\n\n## 7.18.15\nFri, 08 Oct 2021 08:08:34 GMT\n\n_Version update only_\n\n## 7.18.14\nThu, 07 Oct 2021 07:13:35 GMT\n\n_Version update only_\n\n## 7.18.13\nTue, 05 Oct 2021 15:08:38 GMT\n\n_Version update only_\n\n## 7.18.12\nMon, 04 Oct 2021 15:10:18 GMT\n\n_Version update only_\n\n## 7.18.11\nFri, 24 Sep 2021 00:09:29 GMT\n\n_Version update only_\n\n## 7.18.10\nThu, 23 Sep 2021 00:10:40 GMT\n\n### Patches\n\n- Upgrade the `@types/node` dependency to version to version 12.\n\n## 7.18.9\nTue, 14 Sep 2021 01:17:04 GMT\n\n_Version update only_\n\n## 7.18.8\nMon, 13 Sep 2021 15:07:05 GMT\n\n_Version update only_\n\n## 7.18.7\nFri, 27 Aug 2021 00:07:25 GMT\n\n_Version update only_\n\n## 7.18.6\nFri, 20 Aug 2021 15:08:10 GMT\n\n_Version update only_\n\n## 7.18.5\nWed, 11 Aug 2021 00:07:21 GMT\n\n_Version update only_\n\n## 7.18.4\nWed, 14 Jul 2021 15:06:29 GMT\n\n### Patches\n\n- Fix an issue where the .d.ts rollup sometimes used \"default\" as an identifier name causing a syntax error (GitHub #2804)\n\n## 7.18.3\nTue, 13 Jul 2021 23:00:33 GMT\n\n### Patches\n\n- Revert a workaround for TypeScript issue #44422 which was fixed in 4.3.3\n\n## 7.18.2\nMon, 12 Jul 2021 23:08:26 GMT\n\n_Version update only_\n\n## 7.18.1\nThu, 08 Jul 2021 23:41:16 GMT\n\n### Patches\n\n- Fix a recent regression that reported \"Internal Error: indentDocComment cannot be nested\" (GitHub #2797)\n\n## 7.18.0\nThu, 08 Jul 2021 06:00:48 GMT\n\n### Minor changes\n\n- Add support for import() type expressions (GitHub #1050) -- Thank you @javier-garcia-meteologica and @adventure-yunfei for solving this difficult problem!\n- Improve formatting of declarations in .d.ts rollup and .api.md files, fixing some indentation issues\n\n## 7.17.1\nThu, 01 Jul 2021 15:08:27 GMT\n\n_Version update only_\n\n## 7.17.0\nWed, 30 Jun 2021 15:06:54 GMT\n\n### Minor changes\n\n- Added support for \"import * as module from './local/module';\" (GitHub #1029) -- Big thanks to @adventure-yunfei, @mckn, @rbuckton, and @octogonz who all helped with this difficult PR!\n\n### Patches\n\n- Include /// directives in API report\n\n## 7.16.1\nFri, 04 Jun 2021 19:59:53 GMT\n\n_Version update only_\n\n## 7.16.0\nFri, 04 Jun 2021 15:08:20 GMT\n\n### Minor changes\n\n- Upgrade the bundled compiler engine to TypeScript 4.3\n\n## 7.15.2\nWed, 19 May 2021 00:11:39 GMT\n\n_Version update only_\n\n## 7.15.1\nMon, 03 May 2021 15:10:29 GMT\n\n_Version update only_\n\n## 7.15.0\nThu, 29 Apr 2021 23:26:50 GMT\n\n### Minor changes\n\n- Upgrade the bundled compiler engine to TypeScript 4.2\n\n## 7.14.0\nTue, 20 Apr 2021 04:59:51 GMT\n\n### Minor changes\n\n- Projects can now define custom tags using a tsdoc.json file\n\n## 7.13.5\nMon, 12 Apr 2021 15:10:28 GMT\n\n_Version update only_\n\n## 7.13.4\nThu, 08 Apr 2021 06:05:31 GMT\n\n_Version update only_\n\n## 7.13.3\nTue, 06 Apr 2021 15:14:22 GMT\n\n_Version update only_\n\n## 7.13.2\nThu, 04 Mar 2021 01:11:31 GMT\n\n_Version update only_\n\n## 7.13.1\nFri, 05 Feb 2021 16:10:42 GMT\n\n_Version update only_\n\n## 7.13.0\nWed, 13 Jan 2021 01:11:06 GMT\n\n### Minor changes\n\n- Upgrade the bundled compiler engine to TypeScript 4.1\n\n## 7.12.1\nThu, 10 Dec 2020 23:25:49 GMT\n\n### Patches\n\n- Upgrade to TSDoc 0.12.24\n\n## 7.12.0\nWed, 18 Nov 2020 08:19:54 GMT\n\n### Minor changes\n\n- The \"isOptional\" .api.json field is now applied to both methods and properties\n\n## 7.11.5\nWed, 18 Nov 2020 06:21:57 GMT\n\n### Patches\n\n- Update .api.json file format to store a new field \"isOptional\" for documenting optional properties\n\n## 7.11.4\nWed, 11 Nov 2020 01:08:58 GMT\n\n_Version update only_\n\n## 7.11.3\nTue, 10 Nov 2020 23:13:12 GMT\n\n_Version update only_\n\n## 7.11.2\nFri, 30 Oct 2020 06:38:38 GMT\n\n_Version update only_\n\n## 7.11.1\nFri, 30 Oct 2020 00:10:14 GMT\n\n_Version update only_\n\n## 7.11.0\nThu, 29 Oct 2020 06:14:19 GMT\n\n### Minor changes\n\n- Upgrade the bundled compiler engine to TypeScript 4.0\n\n## 7.10.6\nWed, 28 Oct 2020 01:18:03 GMT\n\n_Version update only_\n\n## 7.10.5\nTue, 27 Oct 2020 15:10:13 GMT\n\n_Version update only_\n\n## 7.10.4\nTue, 06 Oct 2020 00:24:06 GMT\n\n_Version update only_\n\n## 7.10.3\nMon, 05 Oct 2020 22:36:57 GMT\n\n_Version update only_\n\n## 7.10.2\nMon, 05 Oct 2020 15:10:42 GMT\n\n_Version update only_\n\n## 7.10.1\nWed, 30 Sep 2020 18:39:17 GMT\n\n### Patches\n\n- Update to build with @rushstack/heft-node-rig\n\n## 7.10.0\nWed, 30 Sep 2020 06:53:53 GMT\n\n### Minor changes\n\n- API Extractor now supports the config/rig.json system, as defined by @rushstack/rig-package\n- Add IExtractorConfigPrepareOptions.projectFolderLookupToken\n- Upgrade compiler; the API now requires TypeScript 3.9 or newer\n\n### Patches\n\n- Fix an InternalError reported when a declaration referred to itself using \"tyepof\"\n- Update README.md\n\n## 7.9.22\nTue, 22 Sep 2020 05:45:56 GMT\n\n_Version update only_\n\n## 7.9.21\nTue, 22 Sep 2020 01:45:31 GMT\n\n_Version update only_\n\n## 7.9.20\nTue, 22 Sep 2020 00:08:53 GMT\n\n_Version update only_\n\n## 7.9.19\nSat, 19 Sep 2020 04:37:26 GMT\n\n_Version update only_\n\n## 7.9.18\nSat, 19 Sep 2020 03:33:06 GMT\n\n_Version update only_\n\n## 7.9.17\nFri, 18 Sep 2020 22:57:24 GMT\n\n_Version update only_\n\n## 7.9.16\nFri, 18 Sep 2020 21:49:54 GMT\n\n_Version update only_\n\n## 7.9.15\nSun, 13 Sep 2020 01:53:20 GMT\n\n_Version update only_\n\n## 7.9.14\nFri, 11 Sep 2020 02:13:35 GMT\n\n_Version update only_\n\n## 7.9.13\nMon, 07 Sep 2020 07:37:37 GMT\n\n_Version update only_\n\n## 7.9.12\nSat, 05 Sep 2020 18:56:34 GMT\n\n_Version update only_\n\n## 7.9.11\nThu, 27 Aug 2020 11:27:06 GMT\n\n_Version update only_\n\n## 7.9.10\nMon, 24 Aug 2020 07:35:20 GMT\n\n_Version update only_\n\n## 7.9.9\nSat, 22 Aug 2020 05:55:42 GMT\n\n_Version update only_\n\n## 7.9.8\nFri, 21 Aug 2020 01:21:18 GMT\n\n_Version update only_\n\n## 7.9.7\nThu, 20 Aug 2020 15:13:53 GMT\n\n_Version update only_\n\n## 7.9.6\nTue, 18 Aug 2020 23:59:42 GMT\n\n_Version update only_\n\n## 7.9.5\nMon, 17 Aug 2020 04:53:23 GMT\n\n_Version update only_\n\n## 7.9.4\nWed, 12 Aug 2020 00:10:05 GMT\n\n### Patches\n\n- Updated project to build with Heft\n\n## 7.9.3\nWed, 05 Aug 2020 18:27:32 GMT\n\n_Version update only_\n\n## 7.9.2\nThu, 09 Jul 2020 04:58:36 GMT\n\n### Patches\n\n- Fix an issue with handling of \"export { default } from 'package';\" (GitHub #2014)\n\n## 7.9.1\nFri, 03 Jul 2020 15:09:04 GMT\n\n_Version update only_\n\n## 7.9.0\nFri, 03 Jul 2020 05:46:41 GMT\n\n### Minor changes\n\n- Add support for ECMAScript private fields (new in TypeScript 3.8)\n- Add support for \"import type\" imports (new in TypeScript 3.8)\n- Upgrade the bundled compiler engine to TypeScript 3.9\n\n### Patches\n\n- Fix an issue where chained compiler errors were not formatted correctly\n- Log the TypeScript bundled compiler version, and warn if it is outdated\n\n## 7.8.15\nThu, 25 Jun 2020 06:43:35 GMT\n\n_Version update only_\n\n## 7.8.14\nWed, 24 Jun 2020 09:50:48 GMT\n\n_Version update only_\n\n## 7.8.13\nWed, 24 Jun 2020 09:04:28 GMT\n\n_Version update only_\n\n## 7.8.12\nMon, 15 Jun 2020 22:17:17 GMT\n\n### Patches\n\n- Fix an issue where documentation hyperlinks were sometimes missing when using the \"bundledPackages\" feature (GitHub #1933)\n\n## 7.8.11\nWed, 10 Jun 2020 20:48:30 GMT\n\n_Version update only_\n\n## 7.8.10\nMon, 01 Jun 2020 08:34:17 GMT\n\n_Version update only_\n\n## 7.8.9\nSat, 30 May 2020 02:59:54 GMT\n\n_Version update only_\n\n## 7.8.8\nThu, 28 May 2020 05:59:02 GMT\n\n_Version update only_\n\n## 7.8.7\nWed, 27 May 2020 05:15:10 GMT\n\n_Version update only_\n\n## 7.8.6\nTue, 26 May 2020 23:00:25 GMT\n\n_Version update only_\n\n## 7.8.5\nFri, 22 May 2020 15:08:42 GMT\n\n_Version update only_\n\n## 7.8.4\nThu, 21 May 2020 23:09:44 GMT\n\n_Version update only_\n\n## 7.8.3\nThu, 21 May 2020 15:41:59 GMT\n\n_Version update only_\n\n## 7.8.2\nTue, 19 May 2020 15:08:19 GMT\n\n### Patches\n\n- Report an error to indicate that \"import()\" types are not supported\n\n## 7.8.1\nFri, 15 May 2020 08:10:59 GMT\n\n_Version update only_\n\n## 7.8.0\nWed, 06 May 2020 08:23:45 GMT\n\n### Minor changes\n\n- Version update only\n\n## 7.7.13\nWed, 08 Apr 2020 04:07:33 GMT\n\n_Version update only_\n\n## 7.7.12\nSun, 29 Mar 2020 00:04:12 GMT\n\n### Patches\n\n- Improve analysis of types exposed via global variables (fixes GitHub issues #1765, #1095, and #1316)\n\n## 7.7.11\nSat, 28 Mar 2020 00:37:16 GMT\n\n### Patches\n\n- Upgrade to TSdoc 0.12.19 to fix an issue where `<h1>` wasn't allowed as an HTML tag in a doc comment\n\n## 7.7.10\nWed, 18 Mar 2020 15:07:47 GMT\n\n### Patches\n\n- Upgrade cyclic dependencies\n\n## 7.7.9\nTue, 17 Mar 2020 23:55:58 GMT\n\n### Patches\n\n- Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack`\n\n## 7.7.8\nTue, 28 Jan 2020 02:23:44 GMT\n\n_Version update only_\n\n## 7.7.7\nThu, 23 Jan 2020 01:07:56 GMT\n\n_Version update only_\n\n## 7.7.6\nTue, 21 Jan 2020 21:56:13 GMT\n\n_Version update only_\n\n## 7.7.5\nSun, 19 Jan 2020 02:26:52 GMT\n\n### Patches\n\n- Upgrade Node typings to Node 10\n\n## 7.7.4\nFri, 17 Jan 2020 01:08:23 GMT\n\n_Version update only_\n\n## 7.7.3\nTue, 14 Jan 2020 01:34:15 GMT\n\n### Patches\n\n- Fix an issue where \"ae-incompatible-release-tags\" was sometimes reported incorectly for property setters (GitHub #1681)\n\n## 7.7.2\nThu, 09 Jan 2020 06:44:12 GMT\n\n### Patches\n\n- Fix an error \"Cannot read property 'externalModuleIndicator' of undefined\" (GitHub #1652)\n\n## 7.7.1\nWed, 08 Jan 2020 00:11:31 GMT\n\n_Version update only_\n\n## 7.7.0\nTue, 03 Dec 2019 03:17:43 GMT\n\n### Minor changes\n\n- Improve declaration reference syntax to allow linking to overloaded functions/methods\n- Fix an issue with TypeScript 3.7, which now emits separate signatures for property getters/setters\n\n## 7.6.2\nSun, 24 Nov 2019 00:54:04 GMT\n\n_Version update only_\n\n## 7.6.1\nWed, 20 Nov 2019 06:14:28 GMT\n\n### Patches\n\n- Fix an issue where the newlineKind setting wasn't being applied correctly\n\n## 7.6.0\nFri, 15 Nov 2019 04:50:50 GMT\n\n### Minor changes\n\n- Make newline type for generated files configurable\n\n## 7.5.6\nMon, 11 Nov 2019 16:07:56 GMT\n\n_Version update only_\n\n## 7.5.5\nWed, 06 Nov 2019 22:44:18 GMT\n\n### Patches\n\n- Add support for TypeScript 3.7\n\n## 7.5.4\nTue, 05 Nov 2019 06:49:28 GMT\n\n### Patches\n\n- Fix an issue where API reports sometimes were ordered differently depending on the version of NodeJS (GitHub #1552)\n\n## 7.5.3\nTue, 05 Nov 2019 01:08:39 GMT\n\n_Version update only_\n\n## 7.5.2\nTue, 22 Oct 2019 06:24:44 GMT\n\n_Version update only_\n\n## 7.5.1\nFri, 18 Oct 2019 15:15:01 GMT\n\n_Version update only_\n\n## 7.5.0\nSun, 06 Oct 2019 00:27:39 GMT\n\n### Minor changes\n\n- Allow separate release tags for overloaded functions and methods\n- Add new api-extractor.json config setting \"bundledPackages\"\n\n## 7.4.7\nFri, 04 Oct 2019 00:15:22 GMT\n\n### Patches\n\n- Fix an issue where IExtractorConfigPrepareOptions.packageJson was ignored (GitHub #1559)\n\n## 7.4.6\nSun, 29 Sep 2019 23:56:29 GMT\n\n### Patches\n\n- Update repository URL\n\n## 7.4.5\nWed, 25 Sep 2019 15:15:31 GMT\n\n_Version update only_\n\n## 7.4.4\nTue, 24 Sep 2019 02:58:49 GMT\n\n_Version update only_\n\n## 7.4.3\nMon, 23 Sep 2019 15:14:55 GMT\n\n_Version update only_\n\n## 7.4.2\nWed, 11 Sep 2019 19:56:23 GMT\n\n### Patches\n\n- Add support for an exported name that conflicts with a global name (GitHub #1350)\n\n## 7.4.1\nTue, 10 Sep 2019 22:32:23 GMT\n\n### Patches\n\n- Update documentation\n\n## 7.4.0\nTue, 10 Sep 2019 20:38:33 GMT\n\n### Minor changes\n\n- Add support for generating declaration references\n\n## 7.3.11\nWed, 04 Sep 2019 18:28:06 GMT\n\n_Version update only_\n\n## 7.3.10\nWed, 04 Sep 2019 15:15:37 GMT\n\n### Patches\n\n- Update TSDoc dependency to 0.12.14\n\n## 7.3.9\nFri, 30 Aug 2019 00:14:32 GMT\n\n### Patches\n\n- Fix a problem where Unicode API names were not handled correctly\n\n## 7.3.8\nMon, 12 Aug 2019 15:15:14 GMT\n\n_Version update only_\n\n## 7.3.7\nThu, 08 Aug 2019 15:14:17 GMT\n\n_Version update only_\n\n## 7.3.6\nThu, 08 Aug 2019 00:49:05 GMT\n\n### Patches\n\n- Fix an issue where a function with only one declaration was assigned an overloadIndex of 0 instead of 1\n\n## 7.3.5\nMon, 05 Aug 2019 22:04:32 GMT\n\n### Patches\n\n- Security updates.\n\n## 7.3.4\nTue, 23 Jul 2019 01:13:01 GMT\n\n### Patches\n\n- ApiItem.name is now quoted when it contains invalid identifier characters, to avoid conflicts with an ECMAScript symbol expression\n\n## 7.3.3\nMon, 22 Jul 2019 19:13:10 GMT\n\n### Patches\n\n- Update to use new api-extractor-model\n\n## 7.3.2\nFri, 12 Jul 2019 19:12:46 GMT\n\n### Patches\n\n- Clarify docs for \"--typescript-compiler-folder\"\n\n## 7.3.1\nThu, 11 Jul 2019 19:13:08 GMT\n\n### Patches\n\n- Add support for TypeScript 3.5\n\n## 7.3.0\nTue, 09 Jul 2019 19:13:24 GMT\n\n### Minor changes\n\n- Add a \"--diagnostics\" command-line option to help when troubleshooting problems\n\n## 7.2.3\nMon, 08 Jul 2019 19:12:18 GMT\n\n### Patches\n\n- Fix a problem when analyzing .d.ts files that appear in the same folder as the corresponding .ts file (GitHub #1310)\n\n## 7.2.2\nSat, 29 Jun 2019 02:30:10 GMT\n\n### Patches\n\n- Fix GitHub issue #1304 where \"IExtractorInvokeOptions.typescriptCompilerFolder\" did not work with TypeScript 3.4\n\n## 7.2.1\nWed, 12 Jun 2019 19:12:33 GMT\n\n_Version update only_\n\n## 7.2.0\nTue, 11 Jun 2019 00:48:06 GMT\n\n### Minor changes\n\n- Generate ApiTypeParameter entries and type alias types\n\n## 7.1.8\nWed, 05 Jun 2019 19:12:34 GMT\n\n### Patches\n\n- Fix an issue where TSDoc index selectors (ApiParameterListMixin.overloadIndex) started from 0, whereas TSDoc requires a nonzero number\n\n## 7.1.7\nTue, 04 Jun 2019 05:51:53 GMT\n\n### Patches\n\n- Upgrade api-extractor-model to remove ApiConstructor.isStatic, since TypeScript constructors cannot be static\n- Improve handling of symbolic property and method names.\n\n## 7.1.6\nMon, 27 May 2019 04:13:44 GMT\n\n### Patches\n\n- Fix incorrect path resolution for the \"extends\" field when loading tsconfig.json\n\n## 7.1.5\nMon, 13 May 2019 02:08:35 GMT\n\n### Patches\n\n- Broaden support for default imports\n\n## 7.1.4\nMon, 06 May 2019 20:46:21 GMT\n\n_Version update only_\n\n## 7.1.3\nMon, 06 May 2019 19:34:54 GMT\n\n### Patches\n\n- Add a new setting \"omitTrimmingComments\" to prevent extra comments from being emitted in the .d.ts rollup\n\n## 7.1.2\nMon, 06 May 2019 19:11:16 GMT\n\n### Patches\n\n- Fix an issue where ExtractorResult.warningCount was not incremented for messages handled by IExtractorInvokeOptions.messageCallback (GitHub #1258)\n\n## 7.1.1\nTue, 30 Apr 2019 23:08:02 GMT\n\n### Patches\n\n- Fix an issue where API signatures were sometimes truncated in the .api.json file (GitHub #1249)\n\n## 7.1.0\nTue, 16 Apr 2019 11:01:37 GMT\n\n### Minor changes\n\n- Initial stable release of API Extractor 7\n\n## 7.0.42\nFri, 12 Apr 2019 06:13:16 GMT\n\n### Patches\n\n- Fix a regression that prevented certain types of warnings from being reported\n\n## 7.0.41\nThu, 11 Apr 2019 07:14:01 GMT\n\n### Patches\n\n- THIS IS A RELEASE CANDIDATE FOR API-EXTRACTOR 7\n- (Breaking change) Rename \"mainEntryPointFile\" to \"mainEntryPointFilePath\" so all settings use a consistent naming convention\n- (Breaking change) Paths that appear in api-extractor.json are now resolved relative to the config file unless prefixed with the `<projectFolder>` token\n- Add a new api-extractor.json setting \"tsconfigFilePath\" for customizing the tsconfig.json path\n- Replace ExtractorConfig.packageJsonFullPath with ExtractorConfig.packageFolder\n- Upgrade API Extractor to use TypeScript 3.4 for analysis\n\n## 7.0.40\nTue, 09 Apr 2019 05:31:01 GMT\n\n### Patches\n\n- Improve the \"--local\" option to automatically create the API report file if it is missing\n\n## 7.0.39\nMon, 08 Apr 2019 19:12:52 GMT\n\n### Patches\n\n- Rename \"addToApiReviewFile\" setting to \"addToApiReportFile\"\n\n## 7.0.38\nSat, 06 Apr 2019 02:05:51 GMT\n\n### Patches\n\n- (Breaking change) Removed the ILogger API and renamed ExtractorMessageLogLevel to ExtractorLogLevel\n- (Breaking change) Extractor console output is now modeled as ExtractorMessage objects and can be customized/filtered/handled by IExtractorInvokeOptions.messageCallback\n\n## 7.0.37\nFri, 05 Apr 2019 04:16:16 GMT\n\n### Patches\n\n- Introduce \"api-extractor init\" command-line that helps enable API Extractor for a new project\n- (Breaking change) Major redesign of the API used to invoke API Extractor\n- (Breaking change) Major redesign of the api-extractor.json config file format\n- Add a CompilerState API that allows an optimization where multiple invocations of Extractor can reuse the same TypeScript compiler analysis\n\n## 7.0.36\nWed, 03 Apr 2019 02:58:33 GMT\n\n### Patches\n\n- Fix an issue where .d.ts.map file were sometimes mapped to the wrong location\n\n## 7.0.35\nSat, 30 Mar 2019 22:27:16 GMT\n\n### Patches\n\n- Reintroduce the generated documentation notice for internal constructors\n- Add limited support for resolving @inheritDoc references to external packages by postprocessing them in api-documenter\n\n## 7.0.34\nThu, 28 Mar 2019 19:14:27 GMT\n\n### Patches\n\n- Validate `@link` tags and report a warning if the link cannot be resolved\n\n## 7.0.33\nTue, 26 Mar 2019 20:54:18 GMT\n\n### Patches\n\n- Reintroduce support for `@inheritDoc` tags\n\n## 7.0.32\nSat, 23 Mar 2019 03:48:31 GMT\n\n### Patches\n\n- If the TSDoc summary is missing for a class constructor, then automatically generate it\n- Reintroduce support for the `@preapproved` TSDoc tag\n\n## 7.0.31\nThu, 21 Mar 2019 04:59:11 GMT\n\n### Patches\n\n- Reintroduce \"ae-internal-missing-underscore\" warning for API items marked as `@internal` but whose name does not start with an underscore\n\n## 7.0.30\nThu, 21 Mar 2019 01:15:32 GMT\n\n### Patches\n\n- Improve the API review file generation to include imports and support multiple exports\n\n## 7.0.29\nWed, 20 Mar 2019 19:14:49 GMT\n\n### Patches\n\n- API Extractor can now analyze packages whose package.json file is missing the \"version\" field\n\n## 7.0.28\nMon, 18 Mar 2019 04:28:43 GMT\n\n### Patches\n\n- Rename the \"ae-inconsistent-release-tags\" warning to \"ae-different-release-tags\"\n- Introduce a new warning \"ae-incompatible-release-tags\" that checks for API signatures that reference types with incompatible release tags\n- Fix an issue where this error was sometimes reported incorrectly: \"The messages.extractorMessageReporting table contains an unrecognized identifier ___\"\n\n## 7.0.27\nFri, 15 Mar 2019 19:13:25 GMT\n\n### Patches\n\n- (Breaking change) The file extension for API review files has changed from \".api.ts\" to \"api.md\".  For details see https://github.com/microsoft/web-build-tools/issues/1123\n\n## 7.0.26\nWed, 13 Mar 2019 19:13:14 GMT\n\n### Patches\n\n- Refactor code to move the IndentedWriter API from api-extractor-model to api-documenter\n\n## 7.0.25\nWed, 13 Mar 2019 01:14:05 GMT\n\n### Patches\n\n- Upgrade TSDoc\n\n## 7.0.24\nMon, 11 Mar 2019 16:13:36 GMT\n\n### Patches\n\n- Fix an issue where spurious TSDoc warnings were issued because the TSDoc parser was configured improperly\n- Move the .api.json related APIs into a new NPM package @microsoft/api-extractor-model\n\n## 7.0.23\nTue, 05 Mar 2019 17:13:11 GMT\n\n### Patches\n\n- Issue a warning when an exported type refers to another local type that is not exported (ae-forgotten-export)\n- The export analyzer now correctly handles symbols imported using \"import x = require('y');\" notation\n\n## 7.0.22\nMon, 04 Mar 2019 17:13:19 GMT\n\n### Patches\n\n- Every error/warning message reported by API Extractor now has an associated message identifier\n- Add a new section to api-extractor.json for configuring how errors get reported, with ability to suppress individual errors\n- Reintroduce the ability to report issues by writing warnings into the API review file\n- Fix an issue where members of type literals were incorrectly being flagged as \"(undocumented)\"\n- Error messages now cite the original .ts source file, if a source map is present. (To enable this, specify `\"declarationMap\": true` in tsconfig.json.)\n\n## 7.0.21\nWed, 27 Feb 2019 22:13:58 GMT\n\n_Version update only_\n\n## 7.0.20\nWed, 27 Feb 2019 17:13:17 GMT\n\n_Version update only_\n\n## 7.0.19\nMon, 18 Feb 2019 17:13:23 GMT\n\n### Minor changes\n\n- New way to resolve & generate TSDoc metadata file\n\n## 7.0.18\nTue, 12 Feb 2019 17:13:12 GMT\n\n### Patches\n\n- Add a workaround for the issue where .d.ts rollups sometimes define names that conflict with a global symbol (the full solution is tracked by GitHub #1095)\n\n## 7.0.17\nMon, 11 Feb 2019 10:32:37 GMT\n\n### Patches\n\n- Fix an issue where API Extractor neglected to analyze \"typeof\" expressions\n- Fix an issue where declarations inside a namespace were sometimes being incorrectly emitted as top-level exports of the .d.ts rollup\n\n## 7.0.16\nMon, 11 Feb 2019 08:55:57 GMT\n\n### Patches\n\n- Redesign the analyzer so that when an external symbol is reexported by the working package, the local object (AstImport) and external object (AstSymbol) are kept separate\n- Fix a number of bugs where external symbols were misinterpreted as being part of the local project\n- Eliminate a number of errors involving unusual language constructs, by avoiding analysis of external symbols unless it's really necessary\n- Simplify the AstSymbol.nominalAnalysis concept and associated code\n- Improve .d.ts rollup trimming to handle reexported symbols correctly\n\n## 7.0.15\nMon, 11 Feb 2019 03:31:55 GMT\n\n### Patches\n\n- The `--debug` parameter now automatically breaks in the debugger when InternalError is thrown\n\n## 7.0.14\nThu, 31 Jan 2019 17:03:49 GMT\n\n### Patches\n\n- Upgrade to TSDoc 0.12.5, which allows `$` in `@param` names\n- Add \"testMode\" option in api-extractor.json to eliminate spurious diffs in test files when the version number gets bumped\n- Normalize newlines for excerpt strings in the .api.json file\n\n## 7.0.13\nSat, 19 Jan 2019 03:47:47 GMT\n\n### Patches\n\n- Move the skipLibCheck into the config file.\n\n## 7.0.12\nSat, 19 Jan 2019 01:17:51 GMT\n\n### Patches\n\n- Fix an issue where files using \"export=\" were incorrectly interpreted as having ambient declarations\n\n## 7.0.11\nFri, 18 Jan 2019 00:52:21 GMT\n\n### Patches\n\n- Add support for circular references between files that use `export * from \"____\";`\n\n## 7.0.10\nThu, 17 Jan 2019 00:37:54 GMT\n\n### Patches\n\n- Add support for exports of the form `export * from \"____\";`\n- Improve the analyzer to allow a declaration to be exported more than once\n- Fix inconsistent newlines in .api.ts files\n\n## 7.0.9\nThu, 10 Jan 2019 01:57:52 GMT\n\n### Patches\n\n- Fix an issue with rolling up default exports (https://github.com/microsoft/web-build-tools/issues/1007)\n\n## 7.0.8\nThu, 20 Dec 2018 17:04:08 GMT\n\n### Patches\n\n- Fix an issue where it was possible to import forgotten declarations from a .d.ts rollup, even though they did not have an explicit \"export\" modifier\n\n## 7.0.7\nWed, 19 Dec 2018 05:57:33 GMT\n\n### Patches\n\n- Extend ApiModel to support new item kinds: ApiCallSignature, ApiConstructor, ApiConstructSignature, ApiFunction, ApiIndexSignature, ApiTypeAlias, and ApiVariable\n\n## 7.0.6\nFri, 14 Dec 2018 19:43:46 GMT\n\n### Patches\n\n- Update web site URLs\n\n## 7.0.5\nThu, 13 Dec 2018 02:58:10 GMT\n\n### Patches\n\n- Remove unused jju dependency\n\n## 7.0.4\nWed, 12 Dec 2018 17:04:19 GMT\n\n### Patches\n\n- Reintroduce support for \"extends\" and \"implements\" heritage clauses\n- Redesign the Excerpt API to support multiple subranges (e.g. for a list of \"implements\" clauses)\n\n## 7.0.3\nFri, 07 Dec 2018 17:04:56 GMT\n\n### Patches\n\n- Added more API documentation\n\n## 7.0.2\nWed, 05 Dec 2018 19:57:03 GMT\n\n### Patches\n\n- fix reexported types from an external package for dts rollup\n\n## 7.0.1\nWed, 05 Dec 2018 17:04:18 GMT\n\n### Patches\n\n- Fix an issue where .d.ts trimming did not properly handle variable declarations (GitHub #976)\n\n## 7.0.0\nThu, 29 Nov 2018 07:02:09 GMT\n\n### Breaking changes\n\n- THIS IS A BETA RELEASE - We are bumping the version to \"7.0.0\" to simplify dogfooding. This release is not yet ready for general usage.\n\n## 6.3.0\nWed, 28 Nov 2018 19:29:53 GMT\n\n### Minor changes\n\n- Support \"extends\" field in api-extractor.json config files for easier management of monorepos with many projects\n\n## 6.2.0\nWed, 28 Nov 2018 02:17:11 GMT\n\n### Minor changes\n\n- Introduce a new build output \"dist/tsdoc-metdata.json\", which completely replaces the old \"tsdocFlavor\" field in package.json\n\n## 6.1.6\nFri, 16 Nov 2018 21:37:10 GMT\n\n### Patches\n\n- Add support for emitting `/// <reference lib=\"___\" />` directives in .d.ts rollups (GitHub issue #946)\n\n## 6.1.5\nFri, 16 Nov 2018 00:59:00 GMT\n\n### Patches\n\n- Fix an issue where .d.ts trimming did not work for exported variable declarations (GitHub #936)\n\n## 6.1.4\nFri, 09 Nov 2018 23:07:39 GMT\n\n### Patches\n\n- Upgrade to TSDoc 0.21.2, which improves trimming of link text in `@link` tags\n\n## 6.1.3\nWed, 07 Nov 2018 21:04:35 GMT\n\n_Version update only_\n\n## 6.1.2\nMon, 05 Nov 2018 17:04:24 GMT\n\n### Patches\n\n- Upgrade to @microsoft/tsdoc 0.12.0\n\n## 6.1.1\nThu, 01 Nov 2018 19:32:52 GMT\n\n### Patches\n\n- Fix an issue where EcmaScript symbols (\"computed property names\") were missing from .d.ts rollups\n\n## 6.1.0\nWed, 31 Oct 2018 17:00:54 GMT\n\n### Minor changes\n\n- Added an api to invoke api extractor processor by supplying api extractor json config file.\n\n## 6.0.9\nThu, 25 Oct 2018 23:20:40 GMT\n\n_Version update only_\n\n## 6.0.8\nThu, 25 Oct 2018 08:56:02 GMT\n\n### Patches\n\n- Fix issue where `DocErrorText.text` returned `[object Object]` instead of the text \n\n## 6.0.7\nWed, 24 Oct 2018 16:03:10 GMT\n\n_Version update only_\n\n## 6.0.6\nThu, 18 Oct 2018 01:32:20 GMT\n\n### Patches\n\n- Fix isAbsolute check for mainDtsRollupPath\n\n## 6.0.5\nWed, 17 Oct 2018 21:04:49 GMT\n\n_Version update only_\n\n## 6.0.4\nWed, 17 Oct 2018 14:43:24 GMT\n\n### Patches\n\n- Fix a regression where namespaces were sometimes incorrectly handled in \"conservative\" mode\n- Update the command line to look for api-extractor.json in both the \"./config\" folder and the project folder\n- Allow type references in namespaces when namespaceSupport=conservative\n\n## 6.0.3\nThu, 11 Oct 2018 23:26:07 GMT\n\n### Patches\n\n- Fix an issue where `import x from \".\"` was sometimes not processed correctly\n\n## 6.0.2\nTue, 09 Oct 2018 06:58:01 GMT\n\n### Patches\n\n- Fix a regression where API Extractor was sometimes reporting incorrect line numbers\n\n## 6.0.1\nMon, 08 Oct 2018 16:04:27 GMT\n\n_Version update only_\n\n## 6.0.0\nSun, 07 Oct 2018 06:15:56 GMT\n\n### Breaking changes\n\n- (Breaking change) API Extractor 6 introduces support for TSDoc doc comment syntax!  Please see https://api-extractor.com/ for documentation.  To learn more about the TSDoc standard, check out https://github.com/microsoft/tsdoc\n\n## 5.13.1\nFri, 28 Sep 2018 16:05:35 GMT\n\n_Version update only_\n\n## 5.13.0\nWed, 26 Sep 2018 21:39:40 GMT\n\n### Minor changes\n\n- Add new command line option --skip-lib-check\n\n## 5.12.2\nMon, 24 Sep 2018 23:06:40 GMT\n\n### Patches\n\n- Allow doc comments to use TSDoc's \"@defaultvalue\" tag (but the value is not yet passed to the documentation pipeline)\n\n## 5.12.1\nFri, 21 Sep 2018 16:04:42 GMT\n\n### Patches\n\n- Fix an issue where TypeScript errors are often logged as \"[Object object]\" instead of the actual error message.\n\n## 5.12.0\nThu, 20 Sep 2018 23:57:21 GMT\n\n### Minor changes\n\n- Add new feature: Support using a different version of the TypeScript compiler.\n\n## 5.11.2\nTue, 18 Sep 2018 21:04:55 GMT\n\n### Patches\n\n- Fix an issue where parameters mentioned in comments were attempting to be analyzed by api-extractor.\n\n## 5.11.1\nThu, 06 Sep 2018 01:25:25 GMT\n\n### Patches\n\n- Update \"repository\" field in package.json\n\n## 5.11.0\nMon, 03 Sep 2018 16:04:45 GMT\n\n### Minor changes\n\n- Upgrade api-extractor to internally use TypeScript 3.0.\n\n## 5.10.8\nWed, 29 Aug 2018 06:36:50 GMT\n\n_Version update only_\n\n## 5.10.7\nThu, 23 Aug 2018 18:18:53 GMT\n\n### Patches\n\n- Republish all packages in web-build-tools to resolve GitHub issue #782\n\n## 5.10.6\nWed, 22 Aug 2018 20:58:58 GMT\n\n_Version update only_\n\n## 5.10.5\nWed, 22 Aug 2018 16:03:25 GMT\n\n_Version update only_\n\n## 5.10.4\nTue, 21 Aug 2018 16:04:38 GMT\n\n### Patches\n\n- fix namespace name for export statement`\n\n## 5.10.3\nThu, 09 Aug 2018 21:03:22 GMT\n\n_Version update only_\n\n## 5.10.2\nThu, 09 Aug 2018 16:04:24 GMT\n\n### Patches\n\n- Update lodash.\n\n## 5.10.1\nThu, 26 Jul 2018 16:04:17 GMT\n\n_Version update only_\n\n## 5.10.0\nTue, 17 Jul 2018 16:02:52 GMT\n\n### Minor changes\n\n- Add support for new \"@eventproperty\" AEDoc tag, which indicates that a class/interface property should be documented as an event\n\n## 5.9.1\nTue, 03 Jul 2018 21:03:31 GMT\n\n_Version update only_\n\n## 5.9.0\nSat, 23 Jun 2018 02:21:20 GMT\n\n### Minor changes\n\n- Add new IMarkupHtmlTag API\n- AEDoc now allows HTML tags inside doc comments, which can be disabled using a backslash escape\n\n## 5.8.1\nThu, 21 Jun 2018 08:27:29 GMT\n\n_Version update only_\n\n## 5.8.0\nTue, 19 Jun 2018 19:35:11 GMT\n\n### Minor changes\n\n- For namespaceSupport=permissive, allow arbitrary nesting of namespaces\n\n### Patches\n\n- Fix an issue where multi-line type literals sometimes had inconsistent newlines in the *.api.json file\n\n## 5.7.3\nFri, 08 Jun 2018 08:43:52 GMT\n\n_Version update only_\n\n## 5.7.2\nThu, 31 May 2018 01:39:33 GMT\n\n_Version update only_\n\n## 5.7.1\nTue, 15 May 2018 02:26:45 GMT\n\n_Version update only_\n\n## 5.7.0\nTue, 15 May 2018 00:18:10 GMT\n\n### Minor changes\n\n- Add support for new AEDoc tags @sealed, @virtual, and @override\n\n## 5.6.8\nFri, 04 May 2018 00:42:38 GMT\n\n### Patches\n\n- Fix the formatting of a log message.\n\n## 5.6.7\nTue, 01 May 2018 22:03:20 GMT\n\n### Patches\n\n- Fix an issue where the *.d.ts rollup trimming did not trim import statements\n\n## 5.6.6\nFri, 27 Apr 2018 03:04:32 GMT\n\n_Version update only_\n\n## 5.6.5\nThu, 19 Apr 2018 21:25:56 GMT\n\n_Version update only_\n\n## 5.6.4\nThu, 19 Apr 2018 17:02:06 GMT\n\n### Patches\n\n- Fix errors in schema documentation\n\n## 5.6.3\nTue, 03 Apr 2018 16:05:29 GMT\n\n_Version update only_\n\n## 5.6.2\nMon, 02 Apr 2018 16:05:24 GMT\n\n### Patches\n\n- Refactor to use new @microsoft/node-core-library\n\n## 5.6.1\nTue, 27 Mar 2018 01:34:25 GMT\n\n### Patches\n\n- Update build config so API Extractor builds using the latest version of itself\n\n## 5.6.0\nSun, 25 Mar 2018 01:26:19 GMT\n\n### Minor changes\n\n- Improve the api-extractor.json config file so that *.d.ts rollups go in separate folders, and trimming can now be disabled\n\n### Patches\n\n- In preparation for initial release, the \"Package Typings\" feature was renamed to \"DTS Rollup\"\n- Fix an issue where the @packagedocumentation comment was sometimes getting mixed into the middle of the rollup *.d.ts file\n\n## 5.5.2\nFri, 23 Mar 2018 00:34:53 GMT\n\n### Patches\n\n- Upgrade colors to version ~1.2.1\n\n## 5.5.1\nTue, 20 Mar 2018 02:44:45 GMT\n\n### Patches\n\n- Improve packageTypings generator to trim nested members according to their release tag\n- Fix a bug where packageTypings failed to handle merged declarations properly\n\n## 5.5.0\nSat, 17 Mar 2018 02:54:22 GMT\n\n### Minor changes\n\n- Overhaul the packageTypings generator analysis to get ready for the upcoming nested member trimming\n- Breaking change: Any projects using the package typings feature must now have a \"tsdoc\" section in their package.json\n\n### Patches\n\n- Add \"--debug\" flag for debugging\n\n## 5.4.0\nThu, 15 Mar 2018 20:00:50 GMT\n\n### Minor changes\n\n- Add a new setting validationRules.missingReleaseTags to optionally remove the requirement that every API item should have a release tag\n- Add new API \"Markup.formatApiItemReference()\"\n\n### Patches\n\n- Fix an issue where the automatically generated documentation for class constructors sometimes had a broken hyperlink\n\n## 5.3.9\nThu, 15 Mar 2018 16:05:43 GMT\n\n_Version update only_\n\n## 5.3.8\nMon, 12 Mar 2018 20:36:19 GMT\n\n### Patches\n\n- Locked down some \"@types/\" dependency versions to avoid upgrade conflicts\n\n## 5.3.7\nTue, 06 Mar 2018 17:04:51 GMT\n\n### Patches\n\n- Add preliminary support for preview and public outputs for packageTypings generator\n\n## 5.3.6\nFri, 02 Mar 2018 01:13:59 GMT\n\n_Version update only_\n\n## 5.3.5\nTue, 27 Feb 2018 22:05:57 GMT\n\n_Version update only_\n\n## 5.3.4\nWed, 21 Feb 2018 22:04:19 GMT\n\n_Version update only_\n\n## 5.3.3\nWed, 21 Feb 2018 03:13:28 GMT\n\n_Version update only_\n\n## 5.3.2\nSat, 17 Feb 2018 02:53:49 GMT\n\n### Patches\n\n- Fix several bugs with the way that imports were being deduplicated by the packageTypings feature\n\n## 5.3.1\nFri, 16 Feb 2018 22:05:23 GMT\n\n_Version update only_\n\n## 5.3.0\nFri, 16 Feb 2018 17:05:11 GMT\n\n### Minor changes\n\n- Fix an issue where the packageTypings feature didn't handle some import/export patterns\n\n### Patches\n\n- Fix an issue where the packageTypings feature sometimes emitted \"default\" instead of the class name\n- Improve the packageTypings feature to support triple-slash references to typings\n\n## 5.2.7\nWed, 07 Feb 2018 17:05:11 GMT\n\n_Version update only_\n\n## 5.2.6\nFri, 26 Jan 2018 22:05:30 GMT\n\n_Version update only_\n\n## 5.2.5\nFri, 26 Jan 2018 17:53:38 GMT\n\n### Patches\n\n- Force a patch bump in case the previous version was an empty package\n\n## 5.2.4\nFri, 26 Jan 2018 00:36:51 GMT\n\n_Version update only_\n\n## 5.2.3\nTue, 23 Jan 2018 17:05:28 GMT\n\n_Version update only_\n\n## 5.2.2\nThu, 18 Jan 2018 03:23:46 GMT\n\n### Patches\n\n- Enable package typings generated by api-extractor\n\n## 5.2.1\nThu, 18 Jan 2018 00:48:06 GMT\n\n_Version update only_\n\n## 5.2.0\nThu, 18 Jan 2018 00:27:23 GMT\n\n### Minor changes\n\n- Improve the packageTypings feature to support abstract classes and \"import * as X\" imports\n\n## 5.1.3\nWed, 17 Jan 2018 10:49:31 GMT\n\n_Version update only_\n\n## 5.1.2\nFri, 12 Jan 2018 03:35:22 GMT\n\n### Patches\n\n- Add some incremental improvements for the experimental PackageTypingsGenerator feature\n\n## 5.1.1\nThu, 11 Jan 2018 22:31:51 GMT\n\n_Version update only_\n\n## 5.1.0\nWed, 10 Jan 2018 20:40:01 GMT\n\n### Minor changes\n\n- Upgrade to Node 8\n\n### Patches\n\n- Continued progress for the experimental PackageTypingsGenerator\n\n## 5.0.1\nTue, 09 Jan 2018 17:05:51 GMT\n\n### Patches\n\n- Get web-build-tools building with pnpm\n\n## 5.0.0\nSun, 07 Jan 2018 05:12:08 GMT\n\n### Breaking changes\n\n- API Extractor now processes *.d.ts files instead of *.ts files\n\n### Minor changes\n\n- Introduced new tag @packagedocumentation which replaces the earlier approach that used a \"packageDescription\" variable\n\n## 4.3.7\nFri, 05 Jan 2018 20:26:45 GMT\n\n_Version update only_\n\n## 4.3.6\nFri, 05 Jan 2018 00:48:41 GMT\n\n### Patches\n\n- Update Jest to ~21.2.1\n\n## 4.3.5\nFri, 22 Dec 2017 17:04:46 GMT\n\n### Patches\n\n- Fixed an issue where warnings would cause the api-extractor tool to return a nonzero exit code for a \"--local\" build; warnings should not fail the build in this scenario\n\n## 4.3.4\nTue, 12 Dec 2017 03:33:26 GMT\n\n_Version update only_\n\n## 4.3.3\nThu, 30 Nov 2017 23:59:09 GMT\n\n_Version update only_\n\n## 4.3.2\nThu, 30 Nov 2017 23:12:21 GMT\n\n_Version update only_\n\n## 4.3.1\nWed, 29 Nov 2017 17:05:37 GMT\n\n_Version update only_\n\n## 4.3.0\nTue, 28 Nov 2017 23:43:55 GMT\n\n### Minor changes\n\n- Add Extractor.processProject() whose return value indicates success\n\n### Patches\n\n- Deprecate Extractor.analyzeProject() API\n\n## 4.2.6\nMon, 13 Nov 2017 17:04:50 GMT\n\n_Version update only_\n\n## 4.2.5\nMon, 06 Nov 2017 17:04:18 GMT\n\n_Version update only_\n\n## 4.2.4\nThu, 02 Nov 2017 16:05:24 GMT\n\n### Patches\n\n- lock the reference version between web build tools projects\n\n## 4.2.3\nWed, 01 Nov 2017 21:06:08 GMT\n\n### Patches\n\n- Upgrade cyclic dependencies\n\n## 4.2.2\nTue, 31 Oct 2017 21:04:04 GMT\n\n_Version update only_\n\n## 4.2.1\nTue, 31 Oct 2017 16:04:55 GMT\n\n_Version update only_\n\n## 4.2.0\nWed, 25 Oct 2017 20:03:59 GMT\n\n### Minor changes\n\n- Improved the way API JSON represents documentation markup; this is a file format change\n\n## 4.1.2\nTue, 24 Oct 2017 18:17:12 GMT\n\n_Version update only_\n\n## 4.1.1\nMon, 23 Oct 2017 21:53:12 GMT\n\n### Patches\n\n- Updated cyclic dependencies\n\n## 4.1.0\nFri, 20 Oct 2017 19:57:12 GMT\n\n### Minor changes\n\n- Add policies.namespaceSupport option to API Extractor config\n\n### Patches\n\n- Fixed an issue where properties were sometimes marked as readonly; a remark is automatically generated for classes with internal constructors\n\n## 4.0.1\nFri, 20 Oct 2017 01:52:54 GMT\n\n### Patches\n\n- Rename ApiExtractor class to Extractor\n\n## 4.0.0\nFri, 20 Oct 2017 01:04:44 GMT\n\n### Breaking changes\n\n- Redesigned interface for invoking API Extractor\n\n## 3.4.2\nThu, 05 Oct 2017 01:05:02 GMT\n\n_Version update only_\n\n## 3.4.1\nFri, 29 Sep 2017 01:03:42 GMT\n\n### Patches\n\n- Removed IMarkupPage.docId\n\n## 3.4.0\nThu, 28 Sep 2017 01:04:28 GMT\n\n### Minor changes\n\n- Skipping two lines in an AEDoc comment now creates a paragraph separator for the generated documentation\n\n### Patches\n\n- The *.api.json \"linkDocElement\" type now always explicitly specifies the package name, rather than expecting the reader to infer it\n- The *.api.json file format now exposes \"signature\" information for properties, functions, and module variables\n\n## 3.3.0\nFri, 22 Sep 2017 01:04:02 GMT\n\n### Minor changes\n\n- Upgrade to es6\n\n## 3.2.6\nWed, 20 Sep 2017 22:10:17 GMT\n\n_Version update only_\n\n## 3.2.5\nMon, 11 Sep 2017 13:04:55 GMT\n\n### Patches\n\n- The isBeta and deprecatedMessage fields are now inherited in the *.api.json files\n- Fix an issue where the *.api.json file was sometimes missing function parameters\n\n## 3.2.4\nFri, 08 Sep 2017 01:28:04 GMT\n\n### Patches\n\n- Deprecate @types/es6-coll ections in favor of built-in typescript typings 'es2015.collection' a nd 'es2015.iterable'\n\n## 3.2.3\nThu, 07 Sep 2017 13:04:35 GMT\n\n### Patches\n\n- Fix incorrect schema/typings for enum members\n\n## 3.2.2\nThu, 07 Sep 2017 00:11:11 GMT\n\n### Patches\n\n-  Add $schema field to all schemas\n\n## 3.2.1\nWed, 06 Sep 2017 13:03:42 GMT\n\n### Patches\n\n- Converted IMarkupDocumentationLink to IMarkupApiLink, which exposes the underlying IApiItemReference rather than assuming a particular \"document ID\" model\n\n## 3.2.0\nTue, 05 Sep 2017 19:03:56 GMT\n\n### Minor changes\n\n- Add the constructor signature and package name to the exported API signature\n\n## 3.1.0\nSat, 02 Sep 2017 01:04:26 GMT\n\n### Minor changes\n\n- Expanded the api-extractor API to expose interfaces for the *.api.json file fileformat\n\n## 3.0.0\nThu, 31 Aug 2017 18:41:18 GMT\n\n### Breaking changes\n\n- Fix compatibility issues with old releases, by incrementing the major version number\n\n## 2.3.7\nThu, 31 Aug 2017 17:46:25 GMT\n\n### Patches\n\n- Fix issue where node-core-library was not an explicit dependency\n\n## 2.3.6\nWed, 30 Aug 2017 01:04:34 GMT\n\n_Version update only_\n\n## 2.3.5\nThu, 24 Aug 2017 22:44:12 GMT\n\n### Patches\n\n- Update the schema validator.\n\n## 2.3.4\nThu, 24 Aug 2017 01:04:33 GMT\n\n_Version update only_\n\n## 2.3.3\nTue, 22 Aug 2017 13:04:22 GMT\n\n### Patches\n\n- Added \"api-documenter\" code sample\n\n## 2.3.2\nTue, 15 Aug 2017 01:29:31 GMT\n\n### Patches\n\n- Introduce Span parser for upcoming *.d.ts generator\n\n## 2.3.1\nThu, 27 Jul 2017 01:04:48 GMT\n\n### Patches\n\n- Upgrade to the TS2.4 version of the build tools.\n\n## 2.3.0\nTue, 25 Jul 2017 20:03:31 GMT\n\n### Minor changes\n\n- Upgrade to TypeScript 2.4\n\n## 2.2.0\nWed, 21 Jun 2017 04:19:35 GMT\n\n### Minor changes\n\n- Add two new features: An error is reported if a top-level definition is missing its release tag. The constructor summary will now be autogenerated if omitted.\n\n## 2.0.10\nTue, 20 Jun 2017 01:04:54 GMT\n\n### Patches\n\n- Improve the wording of many error messages\n- Fix a bug with parsing of @link tags\n- Issue warnings for @internal definitions that are not prefixed with an underscore\n\n## 2.0.9\nSat, 17 Jun 2017 01:02:59 GMT\n\n### Patches\n\n- The unsupported @summary tag is now reported as an error\n- Use a cache to speed up package.json lookups\n\n## 2.0.8\nWed, 14 Jun 2017 13:03:40 GMT\n\n### Patches\n\n- Definitions marked as @beta are now included in the *.api.json files for documentation\n\n## 2.0.7\nThu, 08 Jun 2017 05:15:52 GMT\n\n### Patches\n\n- Updated README.md\n\n## 2.0.6\nMon, 15 May 2017 21:59:43 GMT\n\n### Patches\n\n- Added support for Namespace with ApiNamespace\n\n## 2.0.5\nSat, 22 Apr 2017 01:02:03 GMT\n\n### Patches\n\n- Added check for API names that are not supported (only letters and numbers supported)\n\n## 2.0.4\nWed, 19 Apr 2017 20:18:06 GMT\n\n### Patches\n\n- Remove ES6 Promise & @types/es6-promise typings\n\n## 2.0.3\nFri, 14 Apr 2017 17:44:08 GMT\n\n### Patches\n\n- Added collect references ability to detect determine type information of return types and parameter types.\n\n## 2.0.2\nFri, 07 Apr 2017 21:43:16 GMT\n\n### Patches\n\n- Adjusted the version specifier for typescript to ~2.2.2\n\n## 2.0.1\nThu, 06 Apr 2017 01:32:23 GMT\n\n### Patches\n\n- Removed hard coding of @public for ApiPackage\n\n## 2.0.0\nMon, 20 Mar 2017 21:52:20 GMT\n\n### Breaking changes\n\n- Fixing whitespace, also a variable that was shadowing another variable.\n\n## 1.1.19\nMon, 20 Mar 2017 04:20:13 GMT\n\n### Patches\n\n- Reverting change.\n\n## 1.1.18\nMon, 20 Mar 2017 03:50:55 GMT\n\n### Patches\n\n- Reverting previous change, which causes a regression in SPFx yeoman sc enario.\n\n## 1.1.17\nMon, 20 Mar 2017 00:54:03 GMT\n\n### Patches\n\n- Fixing lint whitespace issues.\n\n## 1.1.16\nSun, 19 Mar 2017 19:10:30 GMT\n\n### Patches\n\n- Fixing variable that was shadowing another variable.\n\n## 1.1.15\nWed, 15 Mar 2017 01:32:09 GMT\n\n### Patches\n\n- Locking `@types` packages. Synchronizing version specifiers for dependencies with other `web-build-tools` projects.\n\n## 1.1.14\nSat, 18 Feb 2017 02:32:06 GMT\n\n### Patches\n\n- Seperated the ApiItem initialization into 3 stages: create documentation that doesn't require resolution, then complete initialization by resolving links and inheritdocs. This allows us to ignore harmless cycles like type references\"\n\n## 1.1.13\nThu, 16 Feb 2017 22:10:39 GMT\n\n### Patches\n\n- Fixed Api-Extractor error message, changed apostrophe to backtick.\n\n## 1.1.12\nThu, 16 Feb 2017 18:56:57 GMT\n\n### Patches\n\n- Added support for local API definition resolution\"\n\n## 1.1.11\nSat, 11 Feb 2017 02:32:35 GMT\n\n### Patches\n\n- Changed dependency for ApiDocumentation to abstract the resolving of API definition references.\n\n## 1.1.10\nFri, 10 Feb 2017 20:01:30 GMT\n\n### Patches\n\n-  Added support to not throw error, instead report error if no type is declared on properties and parameters\n\n## 1.1.9\nTue, 07 Feb 2017 20:37:06 GMT\n\n### Patches\n\n- Fixing issue where undocumented comment was not being emitted.\n\n## 1.1.8\nSat, 04 Feb 2017 02:32:05 GMT\n\n### Patches\n\n- Moved ApiItem references within ApiDocumentation, to ApiItem caller.\n\n## 1.1.7\nThu, 02 Feb 2017 14:05:53 GMT\n\n### Patches\n\n- Refactored ApiDocumentation creation to resolve references method.\n\n## 1.1.6\nWed, 01 Feb 2017 20:09:30 GMT\n\n### Patches\n\n- Added ApiItemKind enum and refactored child classes.\n\n## 1.1.5\nFri, 27 Jan 2017 20:04:15 GMT\n\n### Patches\n\n- Changed name of Analyzer to Extractor, added support for external api json doc loading.\n\n## 1.1.4\nFri, 27 Jan 2017 02:35:10 GMT\n\n### Patches\n\n- Added ExternalApiHelper class to be used in generating api documentation json files for external types.\n- Added description for packages implementation.\n- Added config folder with file to enable api-extractor on itself. rebuild project on previous build.\n\n## 1.1.3\nTue, 24 Jan 2017 01:36:35 GMT\n\n### Patches\n\n- Json schema was updated to reflect feature additions to linkDocElement. The linkDocElement can now be of type 'code' which refers to an API definition reference.\n\n## 1.1.2\nFri, 20 Jan 2017 01:46:41 GMT\n\n_Version update only_\n\n## 1.1.1\nThu, 19 Jan 2017 20:04:40 GMT\n\n### Patches\n\n- Check for missing JSDoc sequences changed.\n- Improved error messages\n\n## 1.1.0\nWed, 18 Jan 2017 20:04:29 GMT\n\n### Minor changes\n\n- Updating API Extractor to work with TypeScript 2.1\n\n## 1.0.2\nMon, 16 Jan 2017 20:04:15 GMT\n\n### Patches\n\n- @link capability for href and API definition references\n\n## 1.0.1\nFri, 13 Jan 2017 06:46:05 GMT\n\n_Version update only_\n\n## 1.0.0\nWed, 11 Jan 2017 14:11:26 GMT\n\n### Breaking changes\n\n- Introducing API Extractor\n\n"
  },
  {
    "path": "packages/api-extractor/LICENSE",
    "content": "@microsoft/api-extractor\n\nCopyright (c) Microsoft Corporation. All rights reserved.\n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "packages/api-extractor/README.md",
    "content": "# @discordjs/api-extractor\n\n![API Extractor](https://github.com/microsoft/rushstack/raw/main/common/wiki-images/api-extractor-title.png?raw=true)\n<br />\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; https://api-extractor.com/\n\n<!-- ------------------------------------------------------------------ -->\n<!-- Text below this line should stay in sync with the web site content -->\n<!-- ------------------------------------------------------------------ -->\n\n**API Extractor** helps you build better [TypeScript](https://www.typescriptlang.org/) library packages. Suppose for example that your company has published an NPM package called \"**awesome-widgets**\" that exports many classes and interfaces. As developers start to depend on your library, you may encounter issues such as...\n\n- **Accidental breaks:** People keep reporting that their code won't compile after a supposedly \"minor\" update. To address this, you boldly propose that every **awesome-widgets** pull request must be approved by an experienced developer from your team. But that proves unrealistic -- nobody has time to look at every single PR! What you really need is a way to detect PRs that change API contracts, and flag them for review. That would focus attention in the right place... but how to do that?\n\n- **Missing exports:** Suppose the **awesome-widgets** package exports an API function `AwesomeButton.draw()` that requires a parameter of type `DrawStyle`, but you forgot to export this enum. Things seem fine at first, but when a developer tries to call that function, they discover that there's no way to specify the `DrawStyle`. How to avoid these oversights?\n\n- **Accidental exports:** You meant for your `DrawHelper` class to be kept internal, but one day you realize it's being exported. When you try to remove it, consumers complain that they're using it. How do we avoid this in the future?\n\n- **Alpha/Beta graduation:** You want to release previews of new APIs that are not ready for prime time yet. But if you did a major SemVer bump every time these definitions evolve, the villagers would be after you with torches and pitchforks! A better approach is to designate certain classes/members as **alpha** quality, then promote them to **beta** and finally to **public** as they mature. But how to indicate this to your consumers? (And how to detect scoping mistakes? A **public** function should never return a **beta** result.)\n\n- **\\*.d.ts rollup:** You webpacked your library into a nice **\\*.js** bundle file -- so why ship your typings as a messy tree of **lib/\\*.d.ts** files full of private definitions? Can't we consolidate them into a tidy **\\*.d.ts** rollup file? And if you publish internal/beta/public releases, each release type should get its own **\\*.d.ts** file with appropriate trimming. Developers building a production project don't want to see a bunch of **internal** and **beta** members in their VS Code IntelliSense!\n\n- **Online documentation:** You have faithfully annotated each TypeScript member with nice [TSDoc](https://github.com/microsoft/tsdoc) descriptions. Now that your library has shipped, it's time to set up [a nicely formatted](https://docs.microsoft.com/en-us/javascript/api/sp-http) API reference. What tool to use?\n\n**API Extractor** provides an integrated, professional-quality solution for all these problems. It is invoked at build time by your toolchain and leverages the TypeScript compiler engine to:\n\n- Detect a project's exported API surface\n- Capture the contracts in a concise report designed to facilitate review\n- Warn about common mistakes (e.g. missing exports, inconsistent visibility, etc.)\n- Generate \\*.d.ts rollups with trimming according to release type\n- Output API documentation in a portable format that's easy to integrate with your content pipeline\n\nBest of all, **API Extractor** is free and open source. Join the community and create a pull request!\n\n<!-- ------------------------------------------------------------------ -->\n<!-- Text above this line should stay in sync with the web site content -->\n<!-- ------------------------------------------------------------------ -->\n\n## Getting Started\n\nFor more details and support resources, please visit: https://api-extractor.com/\n\n## Links\n\n- [CHANGELOG.md](https://github.com/discordjs/discord.js/blob/main/packages/api-extractor/CHANGELOG.md) - Find\n  out what's new in the latest version\n- [API Reference](https://rushstack.io/pages/api/api-extractor/)\n\nAPI Extractor is part of the [Rush Stack](https://rushstack.io/) family of projects.\n"
  },
  {
    "path": "packages/api-extractor/bin/api-extractor",
    "content": "#!/usr/bin/env node\nrequire('../dist/start.js');\n"
  },
  {
    "path": "packages/api-extractor/config/api-extractor.json",
    "content": "{\n\t\"$schema\": \"https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json\",\n\n\t\"mainEntryPointFilePath\": \"<projectFolder>/lib/index.d.ts\",\n\n\t\"apiReport\": {\n\t\t\"enabled\": true,\n\t\t\"reportFolder\": \"<projectFolder>/docs/review\"\n\t},\n\n\t\"docModel\": {\n\t\t\"enabled\": true,\n\t\t\"apiJsonFilePath\": \"<projectFolder>/docs/<unscopedPackageName>.api.json\"\n\t},\n\n\t\"dtsRollup\": {\n\t\t\"enabled\": true,\n\t\t\"untrimmedFilePath\": \"<projectFolder>/dist/rollup.d.ts\"\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/config/jest.config.json",
    "content": "{\n\t// By default, don't hide console output\n\t\"silent\": false,\n\n\t// In order for HeftJestReporter to receive console.log() events, we must set verbose=false\n\t\"verbose\": false,\n\n\t// If mocks are not cleared between tests, it opens the door to accidental reliance on\n\t// ordering of tests or describe blocks, eventually resulting in intermittent failures.\n\t//\n\t// We suggest this setting for any heft project (in a monorepo or not).\n\t\"clearMocks\": true,\n\n\t// \"Adding '<rootDir>/dist' here enables dist/__mocks__ to be used for mocking Node.js system modules\n\t\"roots\": [\"<rootDir>/dist\"],\n\n\t\"testMatch\": [\"<rootDir>/dist/**/*.test.{cjs,js}\"],\n\t\"testPathIgnorePatterns\": [\"/node_modules/\"],\n\n\t\"collectCoverageFrom\": [\n\t\t\"dist/**/*.{cjs,js}\",\n\t\t\"!dist/**/*.d.ts\",\n\t\t\"!dist/**/*.test.{cjs,js}\",\n\t\t\"!dist/**/test/**\",\n\t\t\"!dist/**/__tests__/**\",\n\t\t\"!dist/**/__fixtures__/**\",\n\t\t\"!dist/**/__mocks__/**\"\n\t],\n\t\"coveragePathIgnorePatterns\": [\"/node_modules/\"],\n\n\t\"testEnvironment\": \"jest-environment-node\",\n\n\t\"testEnvironmentOptions\": {\n\t\t\"url\": \"http://localhost/\",\n\t\t\"customExportConditions\": [\"require\", \"node\"]\n\t},\n\n\t// Retain pre-Jest 29 snapshot behavior\n\t\"snapshotFormat\": {\n\t\t\"escapeString\": true,\n\t\t\"printBasicPrototype\": true\n\t},\n\n\t// Instruct jest not to run the transformer pipeline by default on JS files. The output files from TypeScript\n\t// will already be fully transformed, so this avoids redundant file system operations.\n\t\"transformIgnorePatterns\": [\"\\\\.c?js$\"],\n\n\t// The modulePathIgnorePatterns below accepts these sorts of paths:\n\t//   - <rootDir>/dist\n\t//   - <rootDir>/dist/file.js\n\t// ...and ignores anything else under <rootDir>\n\t\"modulePathIgnorePatterns\": [],\n\n\t// Prefer .cjs to .js to catch explicit commonjs output. Optimize for local files, which will be .js\n\t\"moduleFileExtensions\": [\"cjs\", \"js\", \"json\", \"node\"],\n\n\t// Enable code coverage for Jest\n\t\"collectCoverage\": true,\n\t\"coverageDirectory\": \"<rootDir>/coverage\",\n\t\"coverageReporters\": [\"cobertura\", \"html\"],\n\n\t// Use v8 coverage provider to avoid Babel\n\t\"coverageProvider\": \"v8\"\n}\n"
  },
  {
    "path": "packages/api-extractor/extends/tsdoc-base.json",
    "content": "/**\n * This file defines the TSDoc custom tags for use with API Extractor.\n *\n * If your project has a custom tsdoc.json file, then it should use the \"extends\" field to\n * inherit the definitions from this file.  For example:\n *\n * ```\n * {\n *   \"$schema\": \"https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json\",\n *   \"extends\": [ \"@discordjs/api-extractor/extends/tsdoc-config.json\" ],\n *   . . .\n * }\n * ```\n *\n * For details about this config file, please see: https://tsdoc.org/pages/packages/tsdoc-config/\n */\n{\n\t\"$schema\": \"https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json\",\n\n\t/**\n\t * The \"AEDoc\" custom tags:\n\t */\n\t\"tagDefinitions\": [\n\t\t{\n\t\t\t\"tagName\": \"@betaDocumentation\",\n\t\t\t\"syntaxKind\": \"modifier\"\n\t\t},\n\t\t{\n\t\t\t\"tagName\": \"@internalRemarks\",\n\t\t\t\"syntaxKind\": \"block\"\n\t\t},\n\t\t{\n\t\t\t\"tagName\": \"@preapproved\",\n\t\t\t\"syntaxKind\": \"modifier\"\n\t\t},\n\t\t{\n\t\t\t\"tagName\": \"@mixes\",\n\t\t\t\"syntaxKind\": \"block\"\n\t\t}\n\t],\n\n\t/**\n\t * TSDoc tags implemented by API Extractor:\n\t */\n\t\"supportForTags\": {\n\t\t\"@alpha\": true,\n\t\t\"@beta\": true,\n\t\t\"@defaultValue\": true,\n\t\t\"@decorator\": true,\n\t\t\"@deprecated\": true,\n\t\t\"@eventProperty\": true,\n\t\t\"@example\": true,\n\t\t\"@experimental\": true,\n\t\t\"@inheritDoc\": true,\n\t\t\"@internal\": true,\n\t\t\"@label\": true,\n\t\t\"@link\": true,\n\t\t\"@override\": true,\n\t\t\"@packageDocumentation\": true,\n\t\t\"@param\": true,\n\t\t\"@privateRemarks\": true,\n\t\t\"@public\": true,\n\t\t\"@readonly\": true,\n\t\t\"@remarks\": true,\n\t\t\"@returns\": true,\n\t\t\"@sealed\": true,\n\t\t\"@see\": true,\n\t\t\"@throws\": true,\n\t\t\"@typeParam\": true,\n\t\t\"@virtual\": true,\n\n\t\t\"@betaDocumentation\": true,\n\t\t\"@internalRemarks\": true,\n\t\t\"@mixes\": true,\n\t\t\"@preapproved\": true\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/package.json",
    "content": "{\n\t\"name\": \"@discordjs/api-extractor\",\n\t\"version\": \"7.52.7\",\n\t\"description\": \"Analyze the exported API for a TypeScript library and generate reviews, documentation, and .d.ts rollups\",\n\t\"private\": true,\n\t\"keywords\": [\n\t\t\"typescript\",\n\t\t\"API\",\n\t\t\"JSDoc\",\n\t\t\"AEDoc\",\n\t\t\"TSDoc\",\n\t\t\"generate\",\n\t\t\"documentation\",\n\t\t\"declaration\",\n\t\t\"dts\",\n\t\t\".d.ts\",\n\t\t\"rollup\",\n\t\t\"bundle\",\n\t\t\"compiler\",\n\t\t\"alpha\",\n\t\t\"beta\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/api-extractor\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"bin\": {\n\t\t\"api-extractor\": \"./bin/api-extractor\"\n\t},\n\t\"license\": \"MIT\",\n\t\"scripts\": {\n\t\t\"build\": \"tsc --noEmit && tsup && pnpm run copy-files\",\n\t\t\"copy-files\": \"cpy \\\"src/schemas/*.json\\\" \\\"dist/schemas\\\" && cpy \\\"extends/*.json\\\" \\\"dist/extends\\\"\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"dependencies\": {\n\t\t\"@discordjs/api-extractor-model\": \"workspace:^\",\n\t\t\"@microsoft/tsdoc\": \"~0.15.1\",\n\t\t\"@microsoft/tsdoc-config\": \"~0.17.1\",\n\t\t\"@rushstack/node-core-library\": \"5.13.1\",\n\t\t\"@rushstack/ts-command-line\": \"5.0.1\",\n\t\t\"colors\": \"~1.4.0\",\n\t\t\"lodash\": \"~4.17.21\",\n\t\t\"resolve\": \"~1.22.11\",\n\t\t\"semver\": \"~7.6.3\",\n\t\t\"source-map\": \"~0.6.1\",\n\t\t\"typescript\": \"~5.5.4\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@types/lodash\": \"^4.17.23\",\n\t\t\"@types/node\": \"^24.10.13\",\n\t\t\"@types/resolve\": \"^1.20.6\",\n\t\t\"@types/semver\": \"^7.7.1\",\n\t\t\"cpy-cli\": \"^6.0.0\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.2.9\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"terser\": \"^5.46.0\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.7\"\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/aedoc/PackageDocComment.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as ts from 'typescript';\nimport { ExtractorMessageId } from '../api/ExtractorMessageId.js';\nimport type { Collector } from '../collector/Collector.js';\n\nexport class PackageDocComment {\n\t/**\n\t * For the given source file, see if it starts with a TSDoc comment containing the `@packageDocumentation` tag.\n\t */\n\tpublic static tryFindInSourceFile(sourceFile: ts.SourceFile, collector: Collector): ts.TextRange | undefined {\n\t\t// The @packageDocumentation comment is special because it is not attached to an AST\n\t\t// definition.  Instead, it is part of the \"trivia\" tokens that the compiler treats\n\t\t// as irrelevant white space.\n\t\t//\n\t\t// WARNING: If the comment doesn't precede an export statement, the compiler will omit\n\t\t// it from the *.d.ts file, and API Extractor won't find it.  If this happens, you need\n\t\t// to rearrange your statements to ensure it is passed through.\n\t\t//\n\t\t// This implementation assumes that the \"@packageDocumentation\" will be in the first TSDoc comment\n\t\t// that appears in the entry point *.d.ts file.  We could possibly look in other places,\n\t\t// but the above warning suggests enforcing a standardized layout.  This design choice is open\n\t\t// to feedback.\n\t\tlet packageCommentRange: ts.TextRange | undefined; // empty string\n\n\t\tfor (const commentRange of ts.getLeadingCommentRanges(sourceFile.text, sourceFile.getFullStart()) ?? []) {\n\t\t\tif (commentRange.kind === ts.SyntaxKind.MultiLineCommentTrivia) {\n\t\t\t\tconst commentBody: string = sourceFile.text.slice(commentRange.pos, commentRange.end);\n\n\t\t\t\t// Choose the first JSDoc-style comment\n\t\t\t\tif (/^\\s*\\/\\*\\*/.test(commentBody)) {\n\t\t\t\t\t// But only if it looks like it's trying to be @packageDocumentation\n\t\t\t\t\t// (The TSDoc parser will validate this more rigorously)\n\t\t\t\t\tif (/@packagedocumentation/i.test(commentBody)) {\n\t\t\t\t\t\tpackageCommentRange = commentRange;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!packageCommentRange) {\n\t\t\t// If we didn't find the @packageDocumentation tag in the expected place, is it in some\n\t\t\t// wrong place?  This sanity check helps people to figure out why there comment isn't working.\n\t\t\tfor (const statement of sourceFile.statements) {\n\t\t\t\tconst ranges: ts.CommentRange[] = [];\n\t\t\t\tranges.push(...(ts.getLeadingCommentRanges(sourceFile.text, statement.getFullStart()) ?? []));\n\t\t\t\tranges.push(...(ts.getTrailingCommentRanges(sourceFile.text, statement.getEnd()) ?? []));\n\n\t\t\t\tfor (const commentRange of ranges) {\n\t\t\t\t\tconst commentBody: string = sourceFile.text.slice(commentRange.pos, commentRange.end);\n\n\t\t\t\t\tif (/@packagedocumentation/i.test(commentBody)) {\n\t\t\t\t\t\tcollector.messageRouter.addAnalyzerIssueForPosition(\n\t\t\t\t\t\t\tExtractorMessageId.MisplacedPackageTag,\n\t\t\t\t\t\t\t'The @packageDocumentation comment must appear at the top of entry point *.d.ts file',\n\t\t\t\t\t\t\tsourceFile,\n\t\t\t\t\t\t\tcommentRange.pos,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn packageCommentRange;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/AstDeclaration.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError } from '@rushstack/node-core-library';\nimport * as ts from 'typescript';\nimport type { AstEntity } from './AstEntity.js';\nimport type { AstSymbol } from './AstSymbol.js';\nimport { Span } from './Span.js';\n\n/**\n * Constructor options for AstDeclaration\n */\nexport interface IAstDeclarationOptions {\n\treadonly astSymbol: AstSymbol;\n\treadonly declaration: ts.Declaration;\n\treadonly parent: AstDeclaration | undefined;\n}\n\n/**\n * The AstDeclaration and AstSymbol classes are API Extractor's equivalent of the compiler's\n * ts.Declaration and ts.Symbol objects.  They are created by the `AstSymbolTable` class.\n *\n * @remarks\n * The AstDeclaration represents one or more syntax components of a symbol.  Usually there is\n * only one AstDeclaration per AstSymbol, but certain TypeScript constructs can have multiple\n * declarations (e.g. overloaded functions, merged declarations, etc.).\n *\n * Because of this, the `AstDeclaration` manages the parent/child nesting hierarchy (e.g. with\n * declaration merging, each declaration has its own children) and becomes the main focus\n * of analyzing AEDoc and emitting *.d.ts files.\n *\n * The AstDeclarations correspond to items from the compiler's ts.Node hierarchy, but\n * omitting/skipping any nodes that don't match the AstDeclaration.isSupportedSyntaxKind()\n * criteria.  This simplification makes the other API Extractor stages easier to implement.\n */\nexport class AstDeclaration {\n\tpublic readonly declaration: ts.Declaration;\n\n\tpublic readonly astSymbol: AstSymbol;\n\n\t/**\n\t * The parent, if this object is nested inside another AstDeclaration.\n\t */\n\tpublic readonly parent: AstDeclaration | undefined;\n\n\t/**\n\t * A bit set of TypeScript modifiers such as \"private\", \"protected\", etc.\n\t */\n\tpublic readonly modifierFlags: ts.ModifierFlags;\n\n\t/**\n\t * Additional information that is calculated later by the `Collector`.  The actual type is `DeclarationMetadata`,\n\t * but we declare it as `unknown` because consumers must obtain this object by calling\n\t * `Collector.fetchDeclarationMetadata()`.\n\t */\n\tpublic declarationMetadata: unknown;\n\n\t/**\n\t * Additional information that is calculated later by the `Collector`.  The actual type is `ApiItemMetadata`,\n\t * but we declare it as `unknown` because consumers must obtain this object by calling\n\t * `Collector.fetchApiItemMetadata()`.\n\t */\n\tpublic apiItemMetadata: unknown;\n\n\t// NOTE: This array becomes immutable after astSymbol.analyze() sets astSymbol.analyzed=true\n\tprivate readonly _analyzedChildren: AstDeclaration[] = [];\n\n\tprivate readonly _analyzedReferencedAstEntitiesSet: Set<AstEntity> = new Set<AstEntity>();\n\n\t// Reverse lookup used by findChildrenWithName()\n\tprivate _childrenByName: Map<string, AstDeclaration[]> | undefined = undefined;\n\n\tpublic constructor(options: IAstDeclarationOptions) {\n\t\tthis.declaration = options.declaration;\n\t\tthis.astSymbol = options.astSymbol;\n\t\tthis.parent = options.parent;\n\n\t\tthis.astSymbol._notifyDeclarationAttach(this);\n\n\t\tif (this.parent) {\n\t\t\tthis.parent._notifyChildAttach(this);\n\t\t}\n\n\t\tthis.modifierFlags = ts.getCombinedModifierFlags(this.declaration);\n\n\t\t// Check for ECMAScript private fields, for example:\n\t\t//\n\t\t//    class Person { #name: string; }\n\t\t//\n\t\tconst declarationName: ts.DeclarationName | undefined = ts.getNameOfDeclaration(this.declaration);\n\t\tif (declarationName && ts.isPrivateIdentifier(declarationName)) {\n\t\t\tthis.modifierFlags |= ts.ModifierFlags.Private;\n\t\t}\n\t}\n\n\t/**\n\t * Returns the children for this AstDeclaration.\n\t *\n\t * @remarks\n\t * The collection will be empty until AstSymbol.analyzed is true.\n\t */\n\tpublic get children(): readonly AstDeclaration[] {\n\t\treturn this.astSymbol.analyzed ? this._analyzedChildren : [];\n\t}\n\n\t/**\n\t * Returns the AstEntity objects referenced by this node.\n\t *\n\t * @remarks\n\t * NOTE: The collection will be empty until AstSymbol.analyzed is true.\n\t *\n\t * Since we assume references are always collected by a traversal starting at the\n\t * root of the nesting declarations, this array omits the following items because they\n\t * would be redundant:\n\t * - symbols corresponding to parents of this declaration (e.g. a method that returns its own class)\n\t * - symbols already listed in the referencedAstSymbols property for parents of this declaration\n\t *   (e.g. a method that returns its own class's base class)\n\t * - symbols that are referenced only by nested children of this declaration\n\t *   (e.g. if a method returns an enum, this doesn't imply that the method's class references that enum)\n\t */\n\tpublic get referencedAstEntities(): readonly AstEntity[] {\n\t\treturn this.astSymbol.analyzed ? [...this._analyzedReferencedAstEntitiesSet] : [];\n\t}\n\n\t/**\n\t * This is an internal callback used when the AstSymbolTable attaches a new\n\t * child AstDeclaration to this object.\n\t *\n\t * @internal\n\t */\n\tpublic _notifyChildAttach(child: AstDeclaration): void {\n\t\tif (child.parent !== this) {\n\t\t\tthrow new InternalError('Invalid call to notifyChildAttach()');\n\t\t}\n\n\t\tif (this.astSymbol.analyzed) {\n\t\t\tthrow new InternalError('_notifyChildAttach() called after analysis is already complete');\n\t\t}\n\n\t\tthis._analyzedChildren.push(child);\n\t}\n\n\t/**\n\t * Returns a diagnostic dump of the tree, which reports the hierarchy of\n\t * AstDefinition objects.\n\t */\n\tpublic getDump(indent: string = ''): string {\n\t\tconst declarationKind: string = ts.SyntaxKind[this.declaration.kind];\n\t\tlet result: string = indent + `+ ${this.astSymbol.localName} (${declarationKind})`;\n\t\tif (this.astSymbol.nominalAnalysis) {\n\t\t\tresult += ' (nominal)';\n\t\t}\n\n\t\tresult += '\\n';\n\n\t\tfor (const referencedAstEntity of this._analyzedReferencedAstEntitiesSet.values()) {\n\t\t\tresult += indent + `  ref: ${referencedAstEntity.localName}\\n`;\n\t\t}\n\n\t\tfor (const child of this.children) {\n\t\t\tresult += child.getDump(indent + '  ');\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns a diagnostic dump using Span.getDump(), which reports the detailed\n\t * compiler structure.\n\t */\n\tpublic getSpanDump(indent: string = ''): string {\n\t\tconst span: Span = new Span(this.declaration);\n\t\treturn span.getDump(indent);\n\t}\n\n\t/**\n\t * This is an internal callback used when AstSymbolTable.analyze() discovers a new\n\t * type reference associated with this declaration.\n\t *\n\t * @internal\n\t */\n\tpublic _notifyReferencedAstEntity(referencedAstEntity: AstEntity): void {\n\t\tif (this.astSymbol.analyzed) {\n\t\t\tthrow new InternalError('_notifyReferencedAstEntity() called after analysis is already complete');\n\t\t}\n\n\t\tfor (let current: AstDeclaration | undefined = this; current; current = current.parent) {\n\t\t\t// Don't add references to symbols that are already referenced by a parent\n\t\t\tif (current._analyzedReferencedAstEntitiesSet.has(referencedAstEntity)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Don't add the symbols of parents either\n\t\t\tif (referencedAstEntity === current.astSymbol) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tthis._analyzedReferencedAstEntitiesSet.add(referencedAstEntity);\n\t}\n\n\t/**\n\t * Visits all the current declaration and all children recursively in a depth-first traversal,\n\t * and performs the specified action for each one.\n\t */\n\tpublic forEachDeclarationRecursive(action: (astDeclaration: AstDeclaration) => void): void {\n\t\taction(this);\n\t\tfor (const child of this.children) {\n\t\t\tchild.forEachDeclarationRecursive(action);\n\t\t}\n\t}\n\n\t/**\n\t * Returns the list of child declarations whose `AstSymbol.localName` matches the provided `name`.\n\t *\n\t * @remarks\n\t * This is an efficient O(1) lookup.\n\t */\n\tpublic findChildrenWithName(name: string): readonly AstDeclaration[] {\n\t\t// The children property returns:\n\t\t//\n\t\t//    return this.astSymbol.analyzed ? this._analyzedChildren : [];\n\t\t//\n\t\tif (!this.astSymbol.analyzed || this._analyzedChildren.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif (this._childrenByName === undefined) {\n\t\t\t// Build the lookup table\n\t\t\tconst childrenByName: Map<string, AstDeclaration[]> = new Map<string, AstDeclaration[]>();\n\n\t\t\tfor (const child of this._analyzedChildren) {\n\t\t\t\tconst childName: string = child.astSymbol.localName;\n\t\t\t\tlet array: AstDeclaration[] | undefined = childrenByName.get(childName);\n\t\t\t\tif (array === undefined) {\n\t\t\t\t\tarray = [];\n\t\t\t\t\tchildrenByName.set(childName, array);\n\t\t\t\t}\n\n\t\t\t\tarray.push(child);\n\t\t\t}\n\n\t\t\tthis._childrenByName = childrenByName;\n\t\t}\n\n\t\treturn this._childrenByName.get(name) ?? [];\n\t}\n\n\t/**\n\t * This function determines which ts.Node kinds will generate an AstDeclaration.\n\t * These correspond to the definitions that we can add AEDoc to.\n\t */\n\tpublic static isSupportedSyntaxKind(kind: ts.SyntaxKind): boolean {\n\t\t// (alphabetical order)\n\t\tswitch (kind) {\n\t\t\tcase ts.SyntaxKind.CallSignature:\n\t\t\tcase ts.SyntaxKind.ClassDeclaration:\n\t\t\tcase ts.SyntaxKind.ConstructSignature: // Example: \"new(x: number): IMyClass\"\n\t\t\tcase ts.SyntaxKind.Constructor: // Example: \"constructor(x: number)\"\n\t\t\tcase ts.SyntaxKind.EnumDeclaration:\n\t\t\tcase ts.SyntaxKind.EnumMember:\n\t\t\tcase ts.SyntaxKind.FunctionDeclaration: // Example: \"(x: number): number\"\n\t\t\tcase ts.SyntaxKind.GetAccessor:\n\t\t\tcase ts.SyntaxKind.SetAccessor:\n\t\t\tcase ts.SyntaxKind.IndexSignature: // Example: \"[key: string]: string\"\n\t\t\tcase ts.SyntaxKind.InterfaceDeclaration:\n\t\t\tcase ts.SyntaxKind.MethodDeclaration:\n\t\t\tcase ts.SyntaxKind.MethodSignature:\n\t\t\tcase ts.SyntaxKind.ModuleDeclaration: // Used for both \"module\" and \"namespace\" declarations\n\t\t\tcase ts.SyntaxKind.PropertyDeclaration:\n\t\t\tcase ts.SyntaxKind.PropertySignature:\n\t\t\tcase ts.SyntaxKind.TypeAliasDeclaration: // Example: \"type Shape = Circle | Square\"\n\t\t\tcase ts.SyntaxKind.VariableDeclaration:\n\t\t\t\treturn true;\n\n\t\t\t// NOTE: Prior to TypeScript 3.7, in the emitted .d.ts files, the compiler would merge a GetAccessor/SetAccessor\n\t\t\t// pair into a single PropertyDeclaration.\n\n\t\t\t// NOTE: In contexts where a source file is treated as a module, we do create \"nominal analysis\"\n\t\t\t// AstSymbol objects corresponding to a ts.SyntaxKind.SourceFile node.  However, a source file\n\t\t\t// is NOT considered a nesting structure, and it does NOT act as a root for the declarations\n\t\t\t// appearing in the file.  This is because the *.d.ts generator is in the business of rolling up\n\t\t\t// source files, and thus wants to ignore them in general.\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/AstEntity.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * `AstEntity` is the abstract base class for analyzer objects that can become a `CollectorEntity`.\n *\n * @remarks\n *\n * The subclasses are:\n * ```\n * - AstEntity\n *   - AstSymbol\n *   - AstSyntheticEntity\n *     - AstImport\n *     - AstNamespaceImport\n * ```\n */\nexport abstract class AstEntity {\n\t/**\n\t * The original name of the symbol, as exported from the module (i.e. source file)\n\t * containing the original TypeScript definition.  Constructs such as\n\t * `import { X as Y } from` may introduce other names that differ from the local name.\n\t *\n\t * @remarks\n\t * For the most part, `localName` corresponds to `followedSymbol.name`, but there\n\t * are some edge cases.  For example, the ts.Symbol.name for `export default class X { }`\n\t * is actually `\"default\"`, not `\"X\"`.\n\t */\n\tpublic abstract readonly localName: string;\n}\n\n/**\n * `AstSyntheticEntity` is the abstract base class for analyzer objects whose emitted declarations\n * are not text transformations performed by the `Span` helper.\n *\n * @remarks\n * Most of API Extractor's output is produced by using the using the `Span` utility to regurgitate strings from\n * the input .d.ts files.  If we need to rename an identifier, the `Span` visitor can pick out an interesting\n * node and rewrite its string, but otherwise the transformation operates on dumb text and not compiler concepts.\n * (Historically we did this because the compiler's emitter was an internal API, but it still has some advantages,\n * for example preserving syntaxes generated by an older compiler to avoid incompatibilities.)\n *\n * This strategy does not work for cases where the output looks very different from the input.  Today these\n * cases are always kinds of `import` statements, but that may change in the future.\n */\nexport abstract class AstSyntheticEntity extends AstEntity {}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/AstImport.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError } from '@rushstack/node-core-library';\nimport { AstSyntheticEntity } from './AstEntity.js';\nimport type { AstSymbol } from './AstSymbol.js';\n\n/**\n * Indicates the import kind for an `AstImport`.\n */\nexport enum AstImportKind {\n\t/**\n\t * An import statement such as `import X from \"y\";`.\n\t */\n\tDefaultImport,\n\n\t/**\n\t * An import statement such as `import { X } from \"y\";`.\n\t */\n\tNamedImport,\n\n\t/**\n\t * An import statement such as `import * as x from \"y\";`.\n\t */\n\tStarImport,\n\n\t/**\n\t * An import statement such as `import x = require(\"y\");`.\n\t */\n\tEqualsImport,\n\n\t/**\n\t * An import statement such as `interface foo { foo: import(\"bar\").a.b.c }`.\n\t */\n\tImportType,\n}\n\n/**\n * Constructor parameters for AstImport\n *\n * @privateRemarks\n * Our naming convention is to use I____Parameters for constructor options and\n * I____Options for general function options.  However the word \"parameters\" is\n * confusingly similar to the terminology for function parameters modeled by API Extractor,\n * so we use I____Options for both cases in this code base.\n */\nexport interface IAstImportOptions {\n\treadonly exportName: string;\n\treadonly importKind: AstImportKind;\n\treadonly isTypeOnly: boolean;\n\treadonly modulePath: string;\n}\n\n/**\n * For a symbol that was imported from an external package, this tracks the import\n * statement that was used to reach it.\n */\nexport class AstImport extends AstSyntheticEntity {\n\tpublic readonly importKind: AstImportKind;\n\n\t/**\n\t * The name of the external package (and possibly module path) that this definition\n\t * was imported from.\n\t *\n\t * Example: \"\\@rushstack/node-core-library/lib/FileSystem\"\n\t */\n\tpublic readonly modulePath: string;\n\n\t/**\n\t * The name of the symbol being imported.\n\t *\n\t * @remarks\n\t *\n\t * The name depends on the type of import:\n\t *\n\t * ```ts\n\t * // For AstImportKind.DefaultImport style, exportName would be \"X\" in this example:\n\t * import X from \"y\";\n\t *\n\t * // For AstImportKind.NamedImport style, exportName would be \"X\" in this example:\n\t * import { X } from \"y\";\n\t *\n\t * // For AstImportKind.StarImport style, exportName would be \"x\" in this example:\n\t * import * as x from \"y\";\n\t *\n\t * // For AstImportKind.EqualsImport style, exportName would be \"x\" in this example:\n\t * import x = require(\"y\");\n\t *\n\t * // For AstImportKind.ImportType style, exportName would be \"a.b.c\" in this example:\n\t * interface foo { foo: import('bar').a.b.c };\n\t * ```\n\t */\n\tpublic readonly exportName: string;\n\n\t/**\n\t * Whether it is a type-only import, for example:\n\t *\n\t * ```ts\n\t * import type { X } from \"y\";\n\t * ```\n\t *\n\t * This is set to true ONLY if the type-only form is used in *every* reference to this AstImport.\n\t */\n\tpublic isTypeOnlyEverywhere: boolean;\n\n\t/**\n\t * If this import statement refers to an API from an external package that is tracked by API Extractor\n\t * (according to `PackageMetadataManager.isAedocSupportedFor()`), then this property will return the\n\t * corresponding AstSymbol.  Otherwise, it is undefined.\n\t */\n\tpublic astSymbol: AstSymbol | undefined;\n\n\t/**\n\t * If modulePath and exportName are defined, then this is a dictionary key\n\t * that combines them with a colon (\":\").\n\t *\n\t * Example: \"\\@rushstack/node-core-library/lib/FileSystem:FileSystem\"\n\t */\n\tpublic readonly key: string;\n\n\tpublic constructor(options: IAstImportOptions) {\n\t\tsuper();\n\n\t\tthis.importKind = options.importKind;\n\t\tthis.modulePath = options.modulePath;\n\t\tthis.exportName = options.exportName;\n\n\t\t// We start with this assumption, but it may get changed later if non-type-only import is encountered.\n\t\tthis.isTypeOnlyEverywhere = options.isTypeOnly;\n\n\t\tthis.key = AstImport.getKey(options);\n\t}\n\n\t/**\n\t * {@inheritdoc AstEntity.localName}\n\t */\n\tpublic get localName(): string {\n\t\t// abstract\n\t\treturn this.exportName;\n\t}\n\n\t/**\n\t * Calculates the lookup key used with `AstImport.key`\n\t */\n\tpublic static getKey(options: IAstImportOptions): string {\n\t\tswitch (options.importKind) {\n\t\t\tcase AstImportKind.DefaultImport:\n\t\t\t\treturn `${options.modulePath}:${options.exportName}`;\n\t\t\tcase AstImportKind.NamedImport:\n\t\t\t\treturn `${options.modulePath}:${options.exportName}`;\n\t\t\tcase AstImportKind.StarImport:\n\t\t\t\treturn `${options.modulePath}:*`;\n\t\t\tcase AstImportKind.EqualsImport:\n\t\t\t\treturn `${options.modulePath}:=`;\n\t\t\tcase AstImportKind.ImportType: {\n\t\t\t\tconst subKey: string = options.exportName\n\t\t\t\t\t? options.exportName.includes('.') // Equivalent to a named export\n\t\t\t\t\t\t? options.exportName.split('.')[0]!\n\t\t\t\t\t\t: options.exportName\n\t\t\t\t\t: '*';\n\t\t\t\treturn `${options.modulePath}:${subKey}`;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tthrow new InternalError('Unknown AstImportKind');\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/AstModule.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type * as ts from 'typescript';\nimport type { AstEntity } from './AstEntity.js';\nimport type { AstSymbol } from './AstSymbol.js';\n\n/**\n * Represents information collected by {@link AstSymbolTable.fetchAstModuleExportInfo}\n */\nexport interface IAstModuleExportInfo {\n\treadonly exportedLocalEntities: Map<string, AstEntity>;\n\treadonly starExportedExternalModules: Set<AstModule>;\n\treadonly visitedAstModules: Set<AstModule>;\n}\n\n/**\n * Constructor parameters for AstModule\n *\n * @privateRemarks\n * Our naming convention is to use I____Parameters for constructor options and\n * I____Options for general function options.  However the word \"parameters\" is\n * confusingly similar to the terminology for function parameters modeled by API Extractor,\n * so we use I____Options for both cases in this code base.\n */\nexport interface IAstModuleOptions {\n\texternalModulePath: string | undefined;\n\tmoduleSymbol: ts.Symbol;\n\tsourceFile: ts.SourceFile;\n}\n\n/**\n * An internal data structure that represents a source file that is analyzed by AstSymbolTable.\n */\nexport class AstModule {\n\t/**\n\t * The source file that declares this TypeScript module.  In most cases, the source file's\n\t * top-level exports constitute the module.\n\t */\n\tpublic readonly sourceFile: ts.SourceFile;\n\n\t/**\n\t * The symbol for the module.  Typically this corresponds to ts.SourceFile itself, however\n\t * in some cases the ts.SourceFile may contain multiple modules declared using the `module` keyword.\n\t */\n\tpublic readonly moduleSymbol: ts.Symbol;\n\n\t/**\n\t * Example:  \"\\@rushstack/node-core-library/lib/FileSystem\"\n\t * but never: \"./FileSystem\"\n\t */\n\tpublic readonly externalModulePath: string | undefined;\n\n\t/**\n\t * A list of other `AstModule` objects that appear in `export * from \"___\";` statements.\n\t */\n\tpublic readonly starExportedModules: Set<AstModule>;\n\n\t/**\n\t * A partial map of entities exported by this module.  The key is the exported name.\n\t */\n\tpublic readonly cachedExportedEntities: Map<string, AstEntity>; // exportName --> entity\n\n\t/**\n\t * Additional state calculated by `AstSymbolTable.fetchWorkingPackageModule()`.\n\t */\n\tpublic astModuleExportInfo: IAstModuleExportInfo | undefined;\n\n\tpublic constructor(options: IAstModuleOptions) {\n\t\tthis.sourceFile = options.sourceFile;\n\t\tthis.moduleSymbol = options.moduleSymbol;\n\n\t\tthis.externalModulePath = options.externalModulePath;\n\n\t\tthis.starExportedModules = new Set<AstModule>();\n\n\t\tthis.cachedExportedEntities = new Map<string, AstSymbol>();\n\n\t\tthis.astModuleExportInfo = undefined;\n\t}\n\n\t/**\n\t * If false, then this source file is part of the working package being processed by the `Collector`.\n\t */\n\tpublic get isExternal(): boolean {\n\t\treturn this.externalModulePath !== undefined;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/AstNamespaceExport.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { AstNamespaceImport, type IAstNamespaceImportOptions } from './AstNamespaceImport';\n\nexport interface IAstNamespaceExportOptions extends IAstNamespaceImportOptions {}\n\n/**\n * `AstNamespaceExport` represents a namespace that is created implicitly and exported by a statement\n * such as `export * as example from \"./file\";`\n *\n * @remarks\n *\n * A typical input looks like this:\n * ```ts\n * // Suppose that example.ts exports two functions f1() and f2().\n * export * as example from \"./file\";\n * ```\n *\n * API Extractor's .d.ts rollup will transform it into an explicit namespace, like this:\n * ```ts\n * declare f1(): void;\n * declare f2(): void;\n *\n * export declare namespace example {\n *   export {\n *     f1,\n *     f2\n *   }\n * }\n * ```\n *\n * The current implementation does not attempt to relocate f1()/f2() to be inside the `namespace`\n * because other type signatures may reference them directly (without using the namespace qualifier).\n * The AstNamespaceExports behaves the same as AstNamespaceImport, it just also has the inline export for the craeted namespace.\n */\n\nexport class AstNamespaceExport extends AstNamespaceImport {\n\tpublic constructor(options: IAstNamespaceExportOptions) {\n\t\tsuper(options);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/AstNamespaceImport.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type * as ts from 'typescript';\nimport type { Collector } from '../collector/Collector.js';\nimport { AstSyntheticEntity } from './AstEntity.js';\nimport type { AstModule, IAstModuleExportInfo } from './AstModule.js';\n\nexport interface IAstNamespaceImportOptions {\n\treadonly astModule: AstModule;\n\treadonly declaration: ts.Declaration;\n\treadonly namespaceName: string;\n\treadonly symbol: ts.Symbol;\n}\n\n/**\n * `AstNamespaceImport` represents a namespace that is created implicitly by a statement\n * such as `import * as example from \"./file\";`\n *\n * @remarks\n *\n * A typical input looks like this:\n * ```ts\n * // Suppose that example.ts exports two functions f1() and f2().\n * import * as example from \"./file\";\n * export { example };\n * ```\n *\n * API Extractor's .d.ts rollup will transform it into an explicit namespace, like this:\n * ```ts\n * declare f1(): void;\n * declare f2(): void;\n *\n * declare namespace example {\n *   export {\n *     f1,\n *     f2\n *   }\n * }\n * ```\n *\n * The current implementation does not attempt to relocate f1()/f2() to be inside the `namespace`\n * because other type signatures may reference them directly (without using the namespace qualifier).\n * The `declare namespace example` is a synthetic construct represented by `AstNamespaceImport`.\n */\nexport class AstNamespaceImport extends AstSyntheticEntity {\n\t/**\n\t * Returns true if the AstSymbolTable.analyze() was called for this object.\n\t * See that function for details.\n\t */\n\tpublic analyzed: boolean = false;\n\n\t/**\n\t * For example, if the original statement was `import * as example from \"./file\";`\n\t * then `astModule` refers to the `./file.d.ts` file.\n\t */\n\tpublic readonly astModule: AstModule;\n\n\t/**\n\t * For example, if the original statement was `import * as example from \"./file\";`\n\t * then `namespaceName` would be `example`.\n\t */\n\tpublic readonly namespaceName: string;\n\n\t/**\n\t * The original `ts.SyntaxKind.NamespaceImport` which can be used as a location for error messages.\n\t */\n\tpublic readonly declaration: ts.Declaration;\n\n\t/**\n\t * The original `ts.SymbolFlags.Namespace` symbol.\n\t */\n\tpublic readonly symbol: ts.Symbol;\n\n\tpublic constructor(options: IAstNamespaceImportOptions) {\n\t\tsuper();\n\t\tthis.astModule = options.astModule;\n\t\tthis.namespaceName = options.namespaceName;\n\t\tthis.declaration = options.declaration;\n\t\tthis.symbol = options.symbol;\n\t}\n\n\t/**\n\t * {@inheritdoc AstEntity.localName}\n\t */\n\tpublic get localName(): string {\n\t\t// abstract\n\t\treturn this.namespaceName;\n\t}\n\n\tpublic fetchAstModuleExportInfo(collector: Collector): IAstModuleExportInfo {\n\t\tconst astModuleExportInfo: IAstModuleExportInfo = collector.astSymbolTable.fetchAstModuleExportInfo(this.astModule);\n\t\treturn astModuleExportInfo;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/AstReferenceResolver.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as tsdoc from '@microsoft/tsdoc';\nimport * as ts from 'typescript';\nimport type { Collector } from '../collector/Collector.js';\nimport type { DeclarationMetadata } from '../collector/DeclarationMetadata.js';\nimport type { IWorkingPackageEntryPoint, WorkingPackage } from '../collector/WorkingPackage.js';\nimport type { AstDeclaration } from './AstDeclaration.js';\nimport type { AstEntity } from './AstEntity.js';\nimport type { AstModule } from './AstModule.js';\nimport { AstSymbol } from './AstSymbol.js';\nimport type { AstSymbolTable } from './AstSymbolTable.js';\n\n/**\n * Used by `AstReferenceResolver` to report a failed resolution.\n *\n * @privateRemarks\n * This class is similar to an `Error` object, but the intent of `ResolverFailure` is to describe\n * why a reference could not be resolved.  This information could be used to throw an actual `Error` object,\n * but normally it is handed off to the `MessageRouter` instead.\n */\nexport class ResolverFailure {\n\t/**\n\t * Details about why the failure occurred.\n\t */\n\tpublic readonly reason: string;\n\n\tpublic constructor(reason: string) {\n\t\tthis.reason = reason;\n\t}\n}\n\n/**\n * This resolves a TSDoc declaration reference by walking the `AstSymbolTable` compiler state.\n *\n * @remarks\n *\n * This class is analogous to `ModelReferenceResolver` from the `@microsoft/api-extractor-model` project,\n * which resolves declaration references by walking the hierarchy loaded from an .api.json file.\n */\nexport class AstReferenceResolver {\n\tprivate readonly _collector: Collector;\n\n\tprivate readonly _astSymbolTable: AstSymbolTable;\n\n\tprivate readonly _workingPackage: WorkingPackage;\n\n\tpublic constructor(collector: Collector) {\n\t\tthis._collector = collector;\n\t\tthis._astSymbolTable = collector.astSymbolTable;\n\t\tthis._workingPackage = collector.workingPackage;\n\t}\n\n\tpublic resolve(\n\t\tdeclarationReference: tsdoc.DocDeclarationReference,\n\t\tentryPoint: IWorkingPackageEntryPoint,\n\t): AstDeclaration | ResolverFailure {\n\t\t// Is it referring to the working package?\n\t\tif (\n\t\t\tdeclarationReference.packageName !== undefined &&\n\t\t\tdeclarationReference.packageName !== this._workingPackage.name\n\t\t) {\n\t\t\treturn new ResolverFailure('External package references are not supported');\n\t\t}\n\n\t\t// Is it a path-based import?\n\t\tif (declarationReference.importPath) {\n\t\t\treturn new ResolverFailure('Import paths are not supported');\n\t\t}\n\n\t\tconst astModule: AstModule = this._astSymbolTable.fetchAstModuleFromWorkingPackage(entryPoint.sourceFile);\n\n\t\tif (declarationReference.memberReferences.length === 0) {\n\t\t\treturn new ResolverFailure('Package references are not supported');\n\t\t}\n\n\t\tconst rootMemberReference: tsdoc.DocMemberReference = declarationReference.memberReferences[0]!;\n\n\t\tconst exportName: ResolverFailure | string = this._getMemberReferenceIdentifier(rootMemberReference);\n\t\tif (exportName instanceof ResolverFailure) {\n\t\t\treturn exportName;\n\t\t}\n\n\t\tconst rootAstEntity: AstEntity | undefined = this._astSymbolTable.tryGetExportOfAstModule(exportName, astModule);\n\n\t\tif (rootAstEntity === undefined) {\n\t\t\treturn new ResolverFailure(`The package \"${this._workingPackage.name}\" does not have an export \"${exportName}\"`);\n\t\t}\n\n\t\tif (!(rootAstEntity instanceof AstSymbol)) {\n\t\t\treturn new ResolverFailure('This type of declaration is not supported yet by the resolver');\n\t\t}\n\n\t\tlet currentDeclaration: AstDeclaration | ResolverFailure = this._selectDeclaration(\n\t\t\trootAstEntity.astDeclarations,\n\t\t\trootMemberReference,\n\t\t\trootAstEntity.localName,\n\t\t);\n\n\t\tif (currentDeclaration instanceof ResolverFailure) {\n\t\t\treturn currentDeclaration;\n\t\t}\n\n\t\tfor (let index = 1; index < declarationReference.memberReferences.length; ++index) {\n\t\t\tconst memberReference: tsdoc.DocMemberReference = declarationReference.memberReferences[index]!;\n\n\t\t\tconst memberName: ResolverFailure | string = this._getMemberReferenceIdentifier(memberReference);\n\t\t\tif (memberName instanceof ResolverFailure) {\n\t\t\t\treturn memberName;\n\t\t\t}\n\n\t\t\tconst matchingChildren: readonly AstDeclaration[] = currentDeclaration.findChildrenWithName(memberName);\n\t\t\tif (matchingChildren.length === 0) {\n\t\t\t\treturn new ResolverFailure(`No member was found with name \"${memberName}\"`);\n\t\t\t}\n\n\t\t\tconst selectedDeclaration: AstDeclaration | ResolverFailure = this._selectDeclaration(\n\t\t\t\tmatchingChildren,\n\t\t\t\tmemberReference,\n\t\t\t\tmemberName,\n\t\t\t);\n\n\t\t\tif (selectedDeclaration instanceof ResolverFailure) {\n\t\t\t\treturn selectedDeclaration;\n\t\t\t}\n\n\t\t\tcurrentDeclaration = selectedDeclaration;\n\t\t}\n\n\t\treturn currentDeclaration;\n\t}\n\n\tprivate _getMemberReferenceIdentifier(memberReference: tsdoc.DocMemberReference): ResolverFailure | string {\n\t\tif (memberReference.memberSymbol !== undefined) {\n\t\t\treturn new ResolverFailure('ECMAScript symbol selectors are not supported');\n\t\t}\n\n\t\tif (memberReference.memberIdentifier === undefined) {\n\t\t\treturn new ResolverFailure('The member identifier is missing in the root member reference');\n\t\t}\n\n\t\treturn memberReference.memberIdentifier.identifier;\n\t}\n\n\tprivate _selectDeclaration(\n\t\tastDeclarations: readonly AstDeclaration[],\n\t\tmemberReference: tsdoc.DocMemberReference,\n\t\tastSymbolName: string,\n\t): AstDeclaration | ResolverFailure {\n\t\tconst memberSelector: tsdoc.DocMemberSelector | undefined = memberReference.selector;\n\n\t\tif (memberSelector === undefined) {\n\t\t\tif (astDeclarations.length === 1) {\n\t\t\t\treturn astDeclarations[0]!;\n\t\t\t} else {\n\t\t\t\t// If we found multiple matches, but the extra ones are all ancillary declarations,\n\t\t\t\t// then return the main declaration.\n\t\t\t\tconst nonAncillaryMatch: AstDeclaration | undefined = this._tryDisambiguateAncillaryMatches(astDeclarations);\n\t\t\t\tif (nonAncillaryMatch) {\n\t\t\t\t\treturn nonAncillaryMatch;\n\t\t\t\t}\n\n\t\t\t\treturn new ResolverFailure(\n\t\t\t\t\t`The reference is ambiguous because \"${astSymbolName}\"` +\n\t\t\t\t\t\t` has more than one declaration; you need to add a TSDoc member reference selector`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tswitch (memberSelector.selectorKind) {\n\t\t\tcase tsdoc.SelectorKind.System:\n\t\t\t\treturn this._selectUsingSystemSelector(astDeclarations, memberSelector, astSymbolName);\n\t\t\tcase tsdoc.SelectorKind.Index:\n\t\t\t\treturn this._selectUsingIndexSelector(astDeclarations, memberSelector, astSymbolName);\n\t\t\tdefault:\n\t\t\t\treturn new ResolverFailure(`The selector \"${memberSelector.selector}\" is not a supported selector type`);\n\t\t}\n\t}\n\n\tprivate _selectUsingSystemSelector(\n\t\tastDeclarations: readonly AstDeclaration[],\n\t\tmemberSelector: tsdoc.DocMemberSelector,\n\t\tastSymbolName: string,\n\t): AstDeclaration | ResolverFailure {\n\t\tconst selectorName: string = memberSelector.selector;\n\n\t\tlet selectorSyntaxKind: ts.SyntaxKind;\n\n\t\tswitch (selectorName) {\n\t\t\tcase 'class':\n\t\t\t\tselectorSyntaxKind = ts.SyntaxKind.ClassDeclaration;\n\t\t\t\tbreak;\n\t\t\tcase 'enum':\n\t\t\t\tselectorSyntaxKind = ts.SyntaxKind.EnumDeclaration;\n\t\t\t\tbreak;\n\t\t\tcase 'function':\n\t\t\t\tselectorSyntaxKind = ts.SyntaxKind.FunctionDeclaration;\n\t\t\t\tbreak;\n\t\t\tcase 'interface':\n\t\t\t\tselectorSyntaxKind = ts.SyntaxKind.InterfaceDeclaration;\n\t\t\t\tbreak;\n\t\t\tcase 'namespace':\n\t\t\t\tselectorSyntaxKind = ts.SyntaxKind.ModuleDeclaration;\n\t\t\t\tbreak;\n\t\t\tcase 'type':\n\t\t\t\tselectorSyntaxKind = ts.SyntaxKind.TypeAliasDeclaration;\n\t\t\t\tbreak;\n\t\t\tcase 'variable':\n\t\t\t\tselectorSyntaxKind = ts.SyntaxKind.VariableDeclaration;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn new ResolverFailure(`Unsupported system selector \"${selectorName}\"`);\n\t\t}\n\n\t\tconst matches: AstDeclaration[] = astDeclarations.filter((x) => x.declaration.kind === selectorSyntaxKind);\n\t\tif (matches.length === 0) {\n\t\t\treturn new ResolverFailure(\n\t\t\t\t`A declaration for \"${astSymbolName}\" was not found that matches the TSDoc selector \"${selectorName}\"`,\n\t\t\t);\n\t\t}\n\n\t\tif (matches.length > 1) {\n\t\t\t// If we found multiple matches, but the extra ones are all ancillary declarations,\n\t\t\t// then return the main declaration.\n\t\t\tconst nonAncillaryMatch: AstDeclaration | undefined = this._tryDisambiguateAncillaryMatches(matches);\n\t\t\tif (nonAncillaryMatch) {\n\t\t\t\treturn nonAncillaryMatch;\n\t\t\t}\n\n\t\t\treturn new ResolverFailure(\n\t\t\t\t`More than one declaration \"${astSymbolName}\" matches the TSDoc selector \"${selectorName}\"`,\n\t\t\t);\n\t\t}\n\n\t\treturn matches[0]!;\n\t}\n\n\tprivate _selectUsingIndexSelector(\n\t\tastDeclarations: readonly AstDeclaration[],\n\t\tmemberSelector: tsdoc.DocMemberSelector,\n\t\tastSymbolName: string,\n\t): AstDeclaration | ResolverFailure {\n\t\tconst selectorOverloadIndex: number = Number.parseInt(memberSelector.selector, 10);\n\n\t\tconst matches: AstDeclaration[] = [];\n\t\tfor (const astDeclaration of astDeclarations) {\n\t\t\tconst overloadIndex: number = this._collector.getOverloadIndex(astDeclaration);\n\t\t\tif (overloadIndex === selectorOverloadIndex) {\n\t\t\t\tmatches.push(astDeclaration);\n\t\t\t}\n\t\t}\n\n\t\tif (matches.length === 0) {\n\t\t\treturn new ResolverFailure(\n\t\t\t\t`An overload for \"${astSymbolName}\" was not found that matches the` +\n\t\t\t\t\t` TSDoc selector \":${selectorOverloadIndex}\"`,\n\t\t\t);\n\t\t}\n\n\t\tif (matches.length > 1) {\n\t\t\t// If we found multiple matches, but the extra ones are all ancillary declarations,\n\t\t\t// then return the main declaration.\n\t\t\tconst nonAncillaryMatch: AstDeclaration | undefined = this._tryDisambiguateAncillaryMatches(matches);\n\t\t\tif (nonAncillaryMatch) {\n\t\t\t\treturn nonAncillaryMatch;\n\t\t\t}\n\n\t\t\treturn new ResolverFailure(\n\t\t\t\t`More than one declaration for \"${astSymbolName}\" matches the TSDoc selector \":${selectorOverloadIndex}\"`,\n\t\t\t);\n\t\t}\n\n\t\treturn matches[0]!;\n\t}\n\n\t/**\n\t * This resolves an ambiguous match in the case where the extra matches are all ancillary declarations,\n\t * except for one match that is the main declaration.\n\t */\n\tprivate _tryDisambiguateAncillaryMatches(matches: readonly AstDeclaration[]): AstDeclaration | undefined {\n\t\tlet result: AstDeclaration | undefined;\n\n\t\tfor (const match of matches) {\n\t\t\tconst declarationMetadata: DeclarationMetadata = this._collector.fetchDeclarationMetadata(match);\n\t\t\tif (!declarationMetadata.isAncillary) {\n\t\t\t\tif (result) {\n\t\t\t\t\treturn undefined; // more than one match\n\t\t\t\t}\n\n\t\t\t\tresult = match;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/AstSymbol.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError } from '@rushstack/node-core-library';\nimport type * as ts from 'typescript';\nimport type { AstDeclaration } from './AstDeclaration.js';\nimport { AstEntity } from './AstEntity.js';\n\n/**\n * Constructor options for AstSymbol\n */\nexport interface IAstSymbolOptions {\n\treadonly followedSymbol: ts.Symbol;\n\treadonly isExternal: boolean;\n\treadonly localName: string;\n\treadonly nominalAnalysis: boolean;\n\treadonly parentAstSymbol: AstSymbol | undefined;\n\treadonly rootAstSymbol: AstSymbol | undefined;\n}\n\n/**\n * The AstDeclaration and AstSymbol classes are API Extractor's equivalent of the compiler's\n * ts.Declaration and ts.Symbol objects.  They are created by the `AstSymbolTable` class.\n *\n * @remarks\n * The AstSymbol represents the ts.Symbol information for an AstDeclaration.  For example,\n * if a method has 3 overloads, each overloaded signature will have its own AstDeclaration,\n * but they will all share a common AstSymbol.\n *\n * For nested definitions, the AstSymbol has a unique parent (i.e. AstSymbol.rootAstSymbol),\n * but the parent/children for each AstDeclaration may be different.  Consider this example:\n *\n * ```ts\n * export namespace N {\n *   export function f(): void { }\n * }\n *\n * export interface N {\n *   g(): void;\n * }\n * ```\n *\n * Note how the parent/child relationships are different for the symbol tree versus\n * the declaration tree, and the declaration tree has two roots:\n *\n * ```\n * AstSymbol tree:            AstDeclaration tree:\n * - N                        - N (namespace)\n *   - f                        - f\n *   - g                      - N (interface)\n *                              - g\n * ```\n */\nexport class AstSymbol extends AstEntity {\n\t/**\n\t * {@inheritdoc AstEntity.localName}\n\t */\n\tpublic readonly localName: string; // abstract\n\n\t/**\n\t * If true, then the `followedSymbol` (i.e. original declaration) of this symbol\n\t * is not part of the working package.  The working package may still export this symbol,\n\t * but if so it should be emitted as an alias such as `export { X } from \"package1\";`.\n\t */\n\tpublic readonly isExternal: boolean;\n\n\t/**\n\t * The compiler symbol where this type was defined, after following any aliases.\n\t *\n\t * @remarks\n\t * This is a normal form that can be reached from any symbol alias by calling\n\t * `TypeScriptHelpers.followAliases()`.  It can be compared to determine whether two\n\t * symbols refer to the same underlying type.\n\t */\n\tpublic readonly followedSymbol: ts.Symbol;\n\n\t/**\n\t * If true, then this AstSymbol represents a foreign object whose structure will be\n\t * ignored.  The AstDeclaration objects will not have any parent or children, and its references\n\t * will not be analyzed.\n\t *\n\t * Nominal symbols are tracked e.g. when they are reexported by the working package.\n\t */\n\tpublic readonly nominalAnalysis: boolean;\n\n\t/**\n\t * Returns the symbol of the parent of this AstSymbol, or undefined if there is no parent.\n\t *\n\t * @remarks\n\t * If a symbol has multiple declarations, we assume (as an axiom) that their parent\n\t * declarations will belong to the same symbol.  This means that the \"parent\" of a\n\t * symbol is a well-defined concept.  However, the \"children\" of a symbol are not very\n\t * meaningful, because different declarations may have different nested members,\n\t * so we usually need to traverse declarations to find children.\n\t */\n\tpublic readonly parentAstSymbol: AstSymbol | undefined;\n\n\t/**\n\t * Returns the symbol of the root of the AstDeclaration hierarchy.\n\t *\n\t * @remarks\n\t * NOTE: If this AstSymbol is the root, then rootAstSymbol will point to itself.\n\t */\n\tpublic readonly rootAstSymbol: AstSymbol;\n\n\t/**\n\t * Additional information that is calculated later by the `Collector`.  The actual type is `SymbolMetadata`,\n\t * but we declare it as `unknown` because consumers must obtain this object by calling\n\t * `Collector.fetchSymbolMetadata()`.\n\t */\n\tpublic symbolMetadata: unknown;\n\n\tprivate readonly _astDeclarations: AstDeclaration[];\n\n\t// This flag is unused if this is not the root symbol.\n\t// Being \"analyzed\" is a property of the root symbol.\n\tprivate _analyzed: boolean = false;\n\n\tpublic constructor(options: IAstSymbolOptions) {\n\t\tsuper();\n\n\t\tthis.followedSymbol = options.followedSymbol;\n\t\tthis.localName = options.localName;\n\t\tthis.isExternal = options.isExternal;\n\t\tthis.nominalAnalysis = options.nominalAnalysis;\n\t\tthis.parentAstSymbol = options.parentAstSymbol;\n\t\tthis.rootAstSymbol = options.rootAstSymbol ?? this;\n\t\tthis._astDeclarations = [];\n\t}\n\n\t/**\n\t * The one or more declarations for this symbol.\n\t *\n\t * @remarks\n\t * For example, if this symbol is a method, then the declarations might be\n\t * various method overloads.  If this symbol is a namespace, then the declarations\n\t * might be separate namespace blocks with the same name that get combined via\n\t * declaration merging.\n\t */\n\tpublic get astDeclarations(): readonly AstDeclaration[] {\n\t\treturn this._astDeclarations;\n\t}\n\n\t/**\n\t * Returns true if the AstSymbolTable.analyze() was called for this object.\n\t * See that function for details.\n\t *\n\t * @remarks\n\t * AstSymbolTable.analyze() is always performed on the root AstSymbol.  This function\n\t * returns true if-and-only-if the root symbol was analyzed.\n\t */\n\tpublic get analyzed(): boolean {\n\t\treturn this.rootAstSymbol._analyzed;\n\t}\n\n\t/**\n\t * This is an internal callback used when the AstSymbolTable attaches a new\n\t * AstDeclaration to this object.\n\t *\n\t * @internal\n\t */\n\tpublic _notifyDeclarationAttach(astDeclaration: AstDeclaration): void {\n\t\tif (this.analyzed) {\n\t\t\tthrow new InternalError('_notifyDeclarationAttach() called after analysis is already complete');\n\t\t}\n\n\t\tthis._astDeclarations.push(astDeclaration);\n\t}\n\n\t/**\n\t * This is an internal callback used when the AstSymbolTable.analyze()\n\t * has processed this object.\n\t *\n\t * @internal\n\t */\n\tpublic _notifyAnalyzed(): void {\n\t\tif (this.parentAstSymbol) {\n\t\t\tthrow new InternalError('_notifyAnalyzed() called for an AstSymbol which is not the root');\n\t\t}\n\n\t\tthis._analyzed = true;\n\t}\n\n\t/**\n\t * Helper that calls AstDeclaration.forEachDeclarationRecursive() for each AstDeclaration.\n\t */\n\tpublic forEachDeclarationRecursive(action: (astDeclaration: AstDeclaration) => void): void {\n\t\tfor (const astDeclaration of this.astDeclarations) {\n\t\t\tastDeclaration.forEachDeclarationRecursive(action);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/AstSymbolTable.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n// for ts.SymbolFlags\n\nimport { type PackageJsonLookup, InternalError } from '@rushstack/node-core-library';\nimport * as ts from 'typescript';\nimport type { MessageRouter } from '../collector/MessageRouter';\nimport { AstDeclaration } from './AstDeclaration.js';\nimport type { AstEntity } from './AstEntity.js';\nimport type { AstModule, IAstModuleExportInfo } from './AstModule.js';\nimport { AstNamespaceImport } from './AstNamespaceImport.js';\nimport { AstSymbol } from './AstSymbol.js';\nimport { ExportAnalyzer } from './ExportAnalyzer.js';\nimport { PackageMetadataManager } from './PackageMetadataManager.js';\nimport { SourceFileLocationFormatter } from './SourceFileLocationFormatter.js';\nimport { SyntaxHelpers } from './SyntaxHelpers.js';\nimport { TypeScriptHelpers } from './TypeScriptHelpers.js';\nimport { TypeScriptInternals, type IGlobalVariableAnalyzer } from './TypeScriptInternals.js';\n\n/**\n * Options for `AstSymbolTable._fetchAstSymbol()`\n */\nexport interface IFetchAstSymbolOptions {\n\t/**\n\t * True while populating the `AstSymbolTable`; false if we're doing a passive lookup\n\t * without adding anything new to the table\n\t */\n\taddIfMissing: boolean;\n\t/**\n\t * The symbol after any symbol aliases have been followed using TypeScriptHelpers.followAliases()\n\t */\n\tfollowedSymbol: ts.Symbol;\n\n\t/**\n\t * If true, symbols with AstSymbol.nominalAnalysis=true will be returned.\n\t * Otherwise `undefined` will be returned for such symbols.\n\t */\n\tincludeNominalAnalysis: boolean;\n\n\t/**\n\t * True if followedSymbol is not part of the working package\n\t */\n\tisExternal: boolean;\n\n\t/**\n\t * A hint to help `_fetchAstSymbol()` determine the `AstSymbol.localName`.\n\t */\n\tlocalName?: string;\n}\n\n/**\n * AstSymbolTable is the workhorse that builds AstSymbol and AstDeclaration objects.\n * It maintains a cache of already constructed objects.  AstSymbolTable constructs\n * AstModule objects, but otherwise the state that it maintains is agnostic of\n * any particular entry point.  (For example, it does not track whether a given AstSymbol\n * is \"exported\" or not.)\n *\n * Internally, AstSymbolTable relies on ExportAnalyzer to crawl import statements and determine where symbols\n * are declared (i.e. the AstImport information needed to import them).\n */\nexport class AstSymbolTable {\n\tprivate readonly _program: ts.Program;\n\n\tprivate readonly _typeChecker: ts.TypeChecker;\n\n\tprivate readonly _messageRouter: MessageRouter;\n\n\tprivate readonly _globalVariableAnalyzer: IGlobalVariableAnalyzer;\n\n\tprivate readonly _packageMetadataManager: PackageMetadataManager;\n\n\tprivate readonly _exportAnalyzer: ExportAnalyzer;\n\n\tprivate readonly _alreadyWarnedGlobalNames: Set<string>;\n\n\t/**\n\t * A mapping from ts.Symbol --\\> AstSymbol\n\t * NOTE: The AstSymbol.followedSymbol will always be a lookup key, but additional keys\n\t * are possible.\n\t *\n\t * After following type aliases, we use this map to look up the corresponding AstSymbol.\n\t */\n\tprivate readonly _astSymbolsBySymbol: Map<ts.Symbol, AstSymbol> = new Map<ts.Symbol, AstSymbol>();\n\n\t/**\n\t * A mapping from ts.Declaration --\\> AstDeclaration\n\t */\n\tprivate readonly _astDeclarationsByDeclaration: Map<ts.Node, AstDeclaration> = new Map<ts.Node, AstDeclaration>();\n\n\t// Note that this is a mapping from specific AST nodes that we analyzed, based on the underlying symbol\n\t// for that node.\n\tprivate readonly _entitiesByNode: Map<ts.Identifier | ts.ImportTypeNode, AstEntity | undefined> = new Map<\n\t\tts.Identifier,\n\t\tAstEntity | undefined\n\t>();\n\n\tpublic constructor(\n\t\tprogram: ts.Program,\n\t\ttypeChecker: ts.TypeChecker,\n\t\tpackageJsonLookup: PackageJsonLookup,\n\t\tbundledPackageNames: ReadonlySet<string>,\n\t\tmessageRouter: MessageRouter,\n\t) {\n\t\tthis._program = program;\n\t\tthis._typeChecker = typeChecker;\n\t\tthis._messageRouter = messageRouter;\n\t\tthis._globalVariableAnalyzer = TypeScriptInternals.getGlobalVariableAnalyzer(program);\n\t\tthis._packageMetadataManager = new PackageMetadataManager(packageJsonLookup, messageRouter);\n\n\t\tthis._exportAnalyzer = new ExportAnalyzer(this._program, this._typeChecker, bundledPackageNames, {\n\t\t\tanalyze: this.analyze.bind(this),\n\t\t\tfetchAstSymbol: this._fetchAstSymbol.bind(this),\n\t\t});\n\n\t\tthis._alreadyWarnedGlobalNames = new Set<string>();\n\t}\n\n\t/**\n\t * Used to analyze an entry point that belongs to the working package.\n\t */\n\tpublic fetchAstModuleFromWorkingPackage(sourceFile: ts.SourceFile): AstModule {\n\t\treturn this._exportAnalyzer.fetchAstModuleFromSourceFile(sourceFile, undefined, false);\n\t}\n\n\t/**\n\t * This crawls the specified entry point and collects the full set of exported AstSymbols.\n\t */\n\tpublic fetchAstModuleExportInfo(astModule: AstModule): IAstModuleExportInfo {\n\t\treturn this._exportAnalyzer.fetchAstModuleExportInfo(astModule);\n\t}\n\n\t/**\n\t * Attempts to retrieve an export by name from the specified `AstModule`.\n\t * Returns undefined if no match was found.\n\t */\n\tpublic tryGetExportOfAstModule(exportName: string, astModule: AstModule): AstEntity | undefined {\n\t\treturn this._exportAnalyzer.tryGetExportOfAstModule(exportName, astModule);\n\t}\n\n\t/**\n\t * Ensures that AstSymbol.analyzed is true for the provided symbol.  The operation\n\t * starts from the root symbol and then fills out all children of all declarations, and\n\t * also calculates AstDeclaration.referencedAstSymbols for all declarations.\n\t * If the symbol is not imported, any non-imported references are also analyzed.\n\t *\n\t * @remarks\n\t * This is an expensive operation, so we only perform it for top-level exports of an\n\t * the AstModule.  For example, if some code references a nested class inside\n\t * a namespace from another library, we do not analyze any of that class's siblings\n\t * or members.  (We do always construct its parents however, since AstDefinition.parent\n\t * is immutable, and needed e.g. to calculate release tag inheritance.)\n\t */\n\tpublic analyze(astEntity: AstEntity): void {\n\t\tif (astEntity instanceof AstSymbol) {\n\t\t\tthis._analyzeAstSymbol(astEntity);\n\t\t\treturn;\n\t\t}\n\n\t\tif (astEntity instanceof AstNamespaceImport) {\n\t\t\tthis._analyzeAstNamespaceImport(astEntity);\n\t\t}\n\t}\n\n\t/**\n\t * For a given astDeclaration, this efficiently finds the child corresponding to the\n\t * specified ts.Node.  It is assumed that AstDeclaration.isSupportedSyntaxKind() would return true for\n\t * that node type, and that the node is an immediate child of the provided AstDeclaration.\n\t */\n\t// NOTE: This could be a method of AstSymbol if it had a backpointer to its AstSymbolTable.\n\tpublic getChildAstDeclarationByNode(node: ts.Node, parentAstDeclaration: AstDeclaration): AstDeclaration {\n\t\tif (!parentAstDeclaration.astSymbol.analyzed) {\n\t\t\tthrow new Error('getChildDeclarationByNode() cannot be used for an AstSymbol that was not analyzed');\n\t\t}\n\n\t\tconst childAstDeclaration: AstDeclaration | undefined = this._astDeclarationsByDeclaration.get(node);\n\t\tif (!childAstDeclaration) {\n\t\t\tthrow new Error('Child declaration not found for the specified node');\n\t\t}\n\n\t\tif (childAstDeclaration.parent !== parentAstDeclaration) {\n\t\t\tthrow new InternalError('The found child is not attached to the parent AstDeclaration');\n\t\t}\n\n\t\treturn childAstDeclaration;\n\t}\n\n\t/**\n\t * For a given ts.Identifier that is part of an AstSymbol that we analyzed, return the AstEntity that\n\t * it refers to.  Returns undefined if it doesn't refer to anything interesting.\n\t *\n\t * @remarks\n\t * Throws an Error if the ts.Identifier is not part of node tree that was analyzed.\n\t */\n\tpublic tryGetEntityForNode(identifier: ts.Identifier | ts.ImportTypeNode): AstEntity | undefined {\n\t\tif (!this._entitiesByNode.has(identifier)) {\n\t\t\tthrow new InternalError('tryGetEntityForIdentifier() called for an identifier that was not analyzed');\n\t\t}\n\n\t\treturn this._entitiesByNode.get(identifier);\n\t}\n\n\t/**\n\t * Builds an AstSymbol.localName for a given ts.Symbol.  In the current implementation, the localName is\n\t * a TypeScript-like expression that may be a string literal or ECMAScript symbol expression.\n\t *\n\t * ```ts\n\t * class X {\n\t *   // localName=\"identifier\"\n\t *   public identifier: number = 1;\n\t *   // localName=\"\\\"identifier\\\"\"\n\t *   public \"quoted string!\": number = 2;\n\t *   // localName=\"[MyNamespace.MySymbol]\"\n\t *   public [MyNamespace.MySymbol]: number = 3;\n\t * }\n\t * ```\n\t */\n\tpublic static getLocalNameForSymbol(symbol: ts.Symbol): string {\n\t\t// TypeScript binds well-known ECMAScript symbols like \"[Symbol.iterator]\" as \"__@iterator\".\n\t\t// Decode it back into \"[Symbol.iterator]\".\n\t\tconst wellKnownSymbolName: string | undefined = TypeScriptHelpers.tryDecodeWellKnownSymbolName(symbol.escapedName);\n\t\tif (wellKnownSymbolName) {\n\t\t\treturn wellKnownSymbolName;\n\t\t}\n\n\t\tconst isUniqueSymbol: boolean = TypeScriptHelpers.isUniqueSymbolName(symbol.escapedName);\n\n\t\t// We will try to obtain the name from a declaration; otherwise we'll fall back to the symbol name.\n\t\tlet unquotedName: string = symbol.name;\n\n\t\tfor (const declaration of symbol.declarations ?? []) {\n\t\t\t// Handle cases such as \"export default class X { }\" where the symbol name is \"default\"\n\t\t\t// but the local name is \"X\".\n\t\t\tconst localSymbol: ts.Symbol | undefined = TypeScriptInternals.tryGetLocalSymbol(declaration);\n\t\t\tif (localSymbol) {\n\t\t\t\tunquotedName = localSymbol.name;\n\t\t\t}\n\n\t\t\t// If it is a non-well-known symbol, then return the late-bound name.  For example, \"X.Y.z\" in this example:\n\t\t\t//\n\t\t\t//   namespace X {\n\t\t\t//     export namespace Y {\n\t\t\t//       export const z: unique symbol = Symbol(\"z\");\n\t\t\t//     }\n\t\t\t//  }\n\t\t\t//\n\t\t\t//  class C {\n\t\t\t//    public [X.Y.z](): void { }\n\t\t\t//  }\n\t\t\t//\n\t\t\tif (isUniqueSymbol) {\n\t\t\t\tconst declarationName: ts.DeclarationName | undefined = ts.getNameOfDeclaration(declaration);\n\t\t\t\tif (declarationName && ts.isComputedPropertyName(declarationName)) {\n\t\t\t\t\tconst lateBoundName: string | undefined = TypeScriptHelpers.tryGetLateBoundName(declarationName);\n\t\t\t\t\tif (lateBoundName) {\n\t\t\t\t\t\t// Here the string may contain an expression such as \"[X.Y.z]\".  Names starting with \"[\" are always\n\t\t\t\t\t\t// expressions.  If a string literal contains those characters, the code below will JSON.stringify() it\n\t\t\t\t\t\t// to avoid a collision.\n\t\t\t\t\t\treturn lateBoundName;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Otherwise that name may come from a quoted string or pseudonym like `__constructor`.\n\t\t// If the string is not a safe identifier, then we must add quotes.\n\t\t// Note that if it was quoted but did not need to be quoted, here we will remove the quotes.\n\t\tif (!SyntaxHelpers.isSafeUnquotedMemberIdentifier(unquotedName)) {\n\t\t\t// For API Extractor's purposes, a canonical form is more appropriate than trying to reflect whatever\n\t\t\t// appeared in the source code.  The code is not even guaranteed to be consistent, for example:\n\t\t\t//\n\t\t\t//   class X {\n\t\t\t//     public \"f1\"(x: string): void;\n\t\t\t//     public f1(x: boolean): void;\n\t\t\t//     public 'f1'(x: string | boolean): void { }\n\t\t\t//   }\n\t\t\treturn JSON.stringify(unquotedName);\n\t\t}\n\n\t\treturn unquotedName;\n\t}\n\n\tprivate _analyzeAstNamespaceImport(astNamespaceImport: AstNamespaceImport): void {\n\t\tif (astNamespaceImport.analyzed) {\n\t\t\treturn;\n\t\t}\n\n\t\t// mark before actual analyzing, to handle module cyclic reexport\n\t\tastNamespaceImport.analyzed = true;\n\n\t\tconst exportedLocalEntities: Map<string, AstEntity> = this.fetchAstModuleExportInfo(\n\t\t\tastNamespaceImport.astModule,\n\t\t).exportedLocalEntities;\n\n\t\tfor (const exportedEntity of exportedLocalEntities.values()) {\n\t\t\tthis.analyze(exportedEntity);\n\t\t}\n\t}\n\n\tprivate _analyzeAstSymbol(astSymbol: AstSymbol): void {\n\t\tif (astSymbol.analyzed) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (astSymbol.nominalAnalysis) {\n\t\t\t// We don't analyze nominal symbols\n\t\t\tastSymbol._notifyAnalyzed();\n\t\t\treturn;\n\t\t}\n\n\t\t// Start at the root of the tree\n\t\tconst rootAstSymbol: AstSymbol = astSymbol.rootAstSymbol;\n\n\t\t// Calculate the full child tree for each definition\n\t\tfor (const astDeclaration of rootAstSymbol.astDeclarations) {\n\t\t\tthis._analyzeChildTree(astDeclaration.declaration, astDeclaration);\n\t\t}\n\n\t\trootAstSymbol._notifyAnalyzed();\n\n\t\tif (!astSymbol.isExternal) {\n\t\t\t// If this symbol is non-external (i.e. it belongs to the working package), then we also analyze any\n\t\t\t// referencedAstSymbols that are non-external.  For example, this ensures that forgotten exports\n\t\t\t// get analyzed.\n\t\t\trootAstSymbol.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => {\n\t\t\t\tfor (const referencedAstEntity of astDeclaration.referencedAstEntities) {\n\t\t\t\t\t// Walk up to the root of the tree, looking for any imports along the way\n\t\t\t\t\tif (referencedAstEntity instanceof AstSymbol && !referencedAstEntity.isExternal) {\n\t\t\t\t\t\tthis._analyzeAstSymbol(referencedAstEntity);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (referencedAstEntity instanceof AstNamespaceImport && !referencedAstEntity.astModule.isExternal) {\n\t\t\t\t\t\tthis._analyzeAstNamespaceImport(referencedAstEntity);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Used by analyze to recursively analyze the entire child tree.\n\t */\n\tprivate _analyzeChildTree(node: ts.Node, governingAstDeclaration: AstDeclaration): void {\n\t\tswitch (node.kind) {\n\t\t\tcase ts.SyntaxKind.JSDocComment: // Skip JSDoc comments - TS considers @param tags TypeReference nodes\n\t\t\t\treturn;\n\n\t\t\t// Is this a reference to another AstSymbol?\n\t\t\tcase ts.SyntaxKind.TypeReference: // general type references\n\t\t\tcase ts.SyntaxKind.ExpressionWithTypeArguments: // special case for e.g. the \"extends\" keyword\n\t\t\tcase ts.SyntaxKind.ComputedPropertyName: // used for EcmaScript \"symbols\", e.g. \"[toPrimitive]\".\n\t\t\tcase ts.SyntaxKind.TypeQuery: // represents for \"typeof X\" as a type\n\t\t\t\t{\n\t\t\t\t\t// Sometimes the type reference will involve multiple identifiers, e.g. \"a.b.C\".\n\t\t\t\t\t// In this case, we only need to worry about importing the first identifier,\n\t\t\t\t\t// so do a depth-first search for it:\n\t\t\t\t\tconst identifierNode: ts.Identifier | undefined = TypeScriptHelpers.findFirstChildNode(\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\tts.SyntaxKind.Identifier,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (identifierNode) {\n\t\t\t\t\t\tlet referencedAstEntity: AstEntity | undefined = this._entitiesByNode.get(identifierNode);\n\t\t\t\t\t\tif (!referencedAstEntity) {\n\t\t\t\t\t\t\tconst symbol: ts.Symbol | undefined = this._typeChecker.getSymbolAtLocation(identifierNode);\n\t\t\t\t\t\t\tif (!symbol) {\n\t\t\t\t\t\t\t\tthrow new Error('Symbol not found for identifier: ' + identifierNode.getText());\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Normally we expect getSymbolAtLocation() to take us to a declaration within the same source\n\t\t\t\t\t\t\t// file, or else to an explicit \"import\" statement within the same source file.  But in certain\n\t\t\t\t\t\t\t// situations (e.g. a global variable) the symbol will refer to a declaration in some other\n\t\t\t\t\t\t\t// source file.  We'll call that case a \"displaced symbol\".\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// For more info, see this discussion:\n\t\t\t\t\t\t\t// https://github.com/microsoft/rushstack/issues/1765#issuecomment-595559849\n\t\t\t\t\t\t\tlet displacedSymbol = true;\n\t\t\t\t\t\t\tfor (const declaration of symbol.declarations ?? []) {\n\t\t\t\t\t\t\t\tif (declaration.getSourceFile() === identifierNode.getSourceFile()) {\n\t\t\t\t\t\t\t\t\tdisplacedSymbol = false;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (displacedSymbol) {\n\t\t\t\t\t\t\t\tif (this._globalVariableAnalyzer.hasGlobalName(identifierNode.text)) {\n\t\t\t\t\t\t\t\t\t// If the displaced symbol is a global variable, then API Extractor simply ignores it.\n\t\t\t\t\t\t\t\t\t// Ambient declarations typically describe the runtime environment (provided by an API consumer),\n\t\t\t\t\t\t\t\t\t// so we don't bother analyzing them as an API contract.  (There are probably some packages\n\t\t\t\t\t\t\t\t\t// that include interesting global variables in their API, but API Extractor doesn't support\n\t\t\t\t\t\t\t\t\t// that yet; it would be a feature request.)\n\n\t\t\t\t\t\t\t\t\tif (this._messageRouter.showDiagnostics && !this._alreadyWarnedGlobalNames.has(identifierNode.text)) {\n\t\t\t\t\t\t\t\t\t\tthis._alreadyWarnedGlobalNames.add(identifierNode.text);\n\t\t\t\t\t\t\t\t\t\tthis._messageRouter.logDiagnostic(\n\t\t\t\t\t\t\t\t\t\t\t`Ignoring reference to global variable \"${identifierNode.text}\"` +\n\t\t\t\t\t\t\t\t\t\t\t\t` in ` +\n\t\t\t\t\t\t\t\t\t\t\t\tSourceFileLocationFormatter.formatDeclaration(identifierNode),\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t// If you encounter this, please report a bug with a repro.  We're interested to know\n\t\t\t\t\t\t\t\t\t// how it can occur.\n\t\t\t\t\t\t\t\t\tthrow new InternalError(`Unable to follow symbol for \"${identifierNode.text}\"`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\treferencedAstEntity = this._exportAnalyzer.fetchReferencedAstEntity(\n\t\t\t\t\t\t\t\t\tsymbol,\n\t\t\t\t\t\t\t\t\tgoverningAstDeclaration.astSymbol.isExternal,\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tthis._entitiesByNode.set(identifierNode, referencedAstEntity);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (referencedAstEntity) {\n\t\t\t\t\t\t\tgoverningAstDeclaration._notifyReferencedAstEntity(referencedAstEntity);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\t// Is this the identifier for the governingAstDeclaration?\n\t\t\tcase ts.SyntaxKind.Identifier:\n\t\t\t\t{\n\t\t\t\t\tconst identifierNode: ts.Identifier = node as ts.Identifier;\n\t\t\t\t\tif (!this._entitiesByNode.has(identifierNode)) {\n\t\t\t\t\t\tconst symbol: ts.Symbol | undefined = this._typeChecker.getSymbolAtLocation(identifierNode);\n\n\t\t\t\t\t\tlet referencedAstEntity: AstEntity | undefined;\n\n\t\t\t\t\t\tif (symbol === governingAstDeclaration.astSymbol.followedSymbol) {\n\t\t\t\t\t\t\treferencedAstEntity = this._fetchEntityForNode(identifierNode, governingAstDeclaration);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis._entitiesByNode.set(identifierNode, referencedAstEntity);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.ImportType:\n\t\t\t\t{\n\t\t\t\t\tconst importTypeNode: ts.ImportTypeNode = node as ts.ImportTypeNode;\n\t\t\t\t\tlet referencedAstEntity: AstEntity | undefined = this._entitiesByNode.get(importTypeNode);\n\n\t\t\t\t\tif (!this._entitiesByNode.has(importTypeNode)) {\n\t\t\t\t\t\treferencedAstEntity = this._fetchEntityForNode(importTypeNode, governingAstDeclaration);\n\n\t\t\t\t\t\tif (!referencedAstEntity) {\n\t\t\t\t\t\t\t// This should never happen\n\t\t\t\t\t\t\tthrow new Error('Failed to fetch entity for import() type node: ' + importTypeNode.getText());\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis._entitiesByNode.set(importTypeNode, referencedAstEntity);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (referencedAstEntity) {\n\t\t\t\t\t\tgoverningAstDeclaration._notifyReferencedAstEntity(referencedAstEntity);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// Is this node declaring a new AstSymbol?\n\t\tconst newGoverningAstDeclaration: AstDeclaration | undefined = this._fetchAstDeclaration(\n\t\t\tnode,\n\t\t\tgoverningAstDeclaration.astSymbol.isExternal,\n\t\t);\n\n\t\tfor (const childNode of node.getChildren()) {\n\t\t\tthis._analyzeChildTree(childNode, newGoverningAstDeclaration ?? governingAstDeclaration);\n\t\t}\n\t}\n\n\tprivate _fetchEntityForNode(\n\t\tnode: ts.Identifier | ts.ImportTypeNode,\n\t\tgoverningAstDeclaration: AstDeclaration,\n\t): AstEntity | undefined {\n\t\tlet referencedAstEntity: AstEntity | undefined = this._entitiesByNode.get(node);\n\t\tif (!referencedAstEntity) {\n\t\t\tif (node.kind === ts.SyntaxKind.ImportType) {\n\t\t\t\treferencedAstEntity = this._exportAnalyzer.fetchReferencedAstEntityFromImportTypeNode(\n\t\t\t\t\tnode,\n\t\t\t\t\tgoverningAstDeclaration.astSymbol.isExternal,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tconst symbol: ts.Symbol | undefined = this._typeChecker.getSymbolAtLocation(node);\n\t\t\t\tif (!symbol) {\n\t\t\t\t\tthrow new Error('Symbol not found for identifier: ' + node.getText());\n\t\t\t\t}\n\n\t\t\t\treferencedAstEntity = this._exportAnalyzer.fetchReferencedAstEntity(\n\t\t\t\t\tsymbol,\n\t\t\t\t\tgoverningAstDeclaration.astSymbol.isExternal,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis._entitiesByNode.set(node, referencedAstEntity);\n\t\t}\n\n\t\treturn referencedAstEntity;\n\t}\n\n\tprivate _fetchAstDeclaration(node: ts.Node, isExternal: boolean): AstDeclaration | undefined {\n\t\tif (!AstDeclaration.isSupportedSyntaxKind(node.kind)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst symbol: ts.Symbol | undefined = TypeScriptHelpers.getSymbolForDeclaration(\n\t\t\tnode as ts.Declaration,\n\t\t\tthis._typeChecker,\n\t\t);\n\t\tif (!symbol) {\n\t\t\tthrow new InternalError('Unable to find symbol for node');\n\t\t}\n\n\t\tconst astSymbol: AstSymbol | undefined = this._fetchAstSymbol({\n\t\t\tfollowedSymbol: symbol,\n\t\t\tisExternal,\n\t\t\tincludeNominalAnalysis: true,\n\t\t\taddIfMissing: true,\n\t\t});\n\n\t\tif (!astSymbol) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst astDeclaration: AstDeclaration | undefined = this._astDeclarationsByDeclaration.get(node);\n\n\t\tif (!astDeclaration) {\n\t\t\tthrow new InternalError('Unable to find constructed AstDeclaration');\n\t\t}\n\n\t\treturn astDeclaration;\n\t}\n\n\tprivate _fetchAstSymbol(options: IFetchAstSymbolOptions): AstSymbol | undefined {\n\t\tconst followedSymbol: ts.Symbol = options.followedSymbol;\n\n\t\t// Filter out symbols representing constructs that we don't care about\n\t\tconst arbitraryDeclaration: ts.Declaration | undefined = TypeScriptHelpers.tryGetADeclaration(followedSymbol);\n\t\tif (!arbitraryDeclaration) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (\n\t\t\tfollowedSymbol.flags & (ts.SymbolFlags.TypeParameter | ts.SymbolFlags.TypeLiteral | ts.SymbolFlags.Transient) &&\n\t\t\t!TypeScriptInternals.isLateBoundSymbol(followedSymbol)\n\t\t) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// API Extractor doesn't analyze ambient declarations at all\n\t\tif (\n\t\t\tTypeScriptHelpers.isAmbient(followedSymbol, this._typeChecker) && // We make a special exemption for ambient declarations that appear in a source file containing\n\t\t\t// an \"export=\" declaration that allows them to be imported as non-ambient.\n\t\t\t!this._exportAnalyzer.isImportableAmbientSourceFile(arbitraryDeclaration.getSourceFile())\n\t\t) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Make sure followedSymbol isn't an alias for something else\n\t\tif (TypeScriptHelpers.isFollowableAlias(followedSymbol, this._typeChecker)) {\n\t\t\t// We expect the caller to have already followed any aliases\n\t\t\tthrow new InternalError('AstSymbolTable._fetchAstSymbol() cannot be called with a symbol alias');\n\t\t}\n\n\t\tlet astSymbol: AstSymbol | undefined = this._astSymbolsBySymbol.get(followedSymbol);\n\n\t\tif (!astSymbol) {\n\t\t\t// None of the above lookups worked, so create a new entry...\n\t\t\tlet nominalAnalysis = false;\n\n\t\t\tif (options.isExternal) {\n\t\t\t\t// If the file is from an external package that does not support AEDoc, normally we ignore it completely.\n\t\t\t\t// But in some cases (e.g. checking star exports of an external package) we need an AstSymbol to\n\t\t\t\t// represent it, but we don't need to analyze its sibling/children.\n\t\t\t\tconst followedSymbolSourceFileName: string = arbitraryDeclaration.getSourceFile().fileName;\n\n\t\t\t\tif (!this._packageMetadataManager.isAedocSupportedFor(followedSymbolSourceFileName)) {\n\t\t\t\t\tnominalAnalysis = true;\n\n\t\t\t\t\tif (!options.includeNominalAnalysis) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet parentAstSymbol: AstSymbol | undefined;\n\n\t\t\tif (!nominalAnalysis) {\n\t\t\t\tfor (const declaration of followedSymbol.declarations ?? []) {\n\t\t\t\t\tif (!AstDeclaration.isSupportedSyntaxKind(declaration.kind)) {\n\t\t\t\t\t\tthrow new InternalError(\n\t\t\t\t\t\t\t`The \"${followedSymbol.name}\" symbol has a` +\n\t\t\t\t\t\t\t\t` ts.SyntaxKind.${ts.SyntaxKind[declaration.kind]} declaration which is not (yet?)` +\n\t\t\t\t\t\t\t\t` supported by API Extractor`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// We always fetch the entire chain of parents for each declaration.\n\t\t\t\t// (Children/siblings are only analyzed on demand.)\n\n\t\t\t\t// Key assumptions behind this squirrely logic:\n\t\t\t\t//\n\t\t\t\t// IF a given symbol has two declarations D1 and D2; AND\n\t\t\t\t// If D1 has a parent P1, then\n\t\t\t\t// - D2 will also have a parent P2; AND\n\t\t\t\t// - P1 and P2's symbol will be the same\n\t\t\t\t// - but P1 and P2 may be different (e.g. merged namespaces containing merged interfaces)\n\n\t\t\t\t// Is there a parent AstSymbol?  First we check to see if there is a parent declaration:\n\t\t\t\tif (arbitraryDeclaration) {\n\t\t\t\t\tconst arbitraryParentDeclaration: ts.Node | undefined =\n\t\t\t\t\t\tthis._tryFindFirstAstDeclarationParent(arbitraryDeclaration);\n\n\t\t\t\t\tif (arbitraryParentDeclaration) {\n\t\t\t\t\t\tconst parentSymbol: ts.Symbol = TypeScriptHelpers.getSymbolForDeclaration(\n\t\t\t\t\t\t\tarbitraryParentDeclaration as ts.Declaration,\n\t\t\t\t\t\t\tthis._typeChecker,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tparentAstSymbol = this._fetchAstSymbol({\n\t\t\t\t\t\t\tfollowedSymbol: parentSymbol,\n\t\t\t\t\t\t\tisExternal: options.isExternal,\n\t\t\t\t\t\t\tincludeNominalAnalysis: false,\n\t\t\t\t\t\t\taddIfMissing: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (!parentAstSymbol) {\n\t\t\t\t\t\t\tthrow new InternalError('Unable to construct a parent AstSymbol for ' + followedSymbol.name);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst localName: string | undefined = options.localName ?? AstSymbolTable.getLocalNameForSymbol(followedSymbol);\n\n\t\t\tastSymbol = new AstSymbol({\n\t\t\t\tfollowedSymbol,\n\t\t\t\tlocalName,\n\t\t\t\tisExternal: options.isExternal,\n\t\t\t\tnominalAnalysis,\n\t\t\t\tparentAstSymbol,\n\t\t\t\trootAstSymbol: parentAstSymbol ? parentAstSymbol.rootAstSymbol : undefined,\n\t\t\t});\n\n\t\t\tthis._astSymbolsBySymbol.set(followedSymbol, astSymbol);\n\n\t\t\t// Okay, now while creating the declarations we will wire them up to the\n\t\t\t// their corresponding parent declarations\n\t\t\tfor (const declaration of followedSymbol.declarations ?? []) {\n\t\t\t\tlet parentAstDeclaration: AstDeclaration | undefined;\n\t\t\t\tif (parentAstSymbol) {\n\t\t\t\t\tconst parentDeclaration: ts.Node | undefined = this._tryFindFirstAstDeclarationParent(declaration);\n\n\t\t\t\t\tif (!parentDeclaration) {\n\t\t\t\t\t\tthrow new InternalError('Missing parent declaration');\n\t\t\t\t\t}\n\n\t\t\t\t\tparentAstDeclaration = this._astDeclarationsByDeclaration.get(parentDeclaration);\n\t\t\t\t\tif (!parentAstDeclaration) {\n\t\t\t\t\t\tthrow new InternalError('Missing parent AstDeclaration');\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst astDeclaration: AstDeclaration = new AstDeclaration({\n\t\t\t\t\tdeclaration,\n\t\t\t\t\tastSymbol,\n\t\t\t\t\tparent: parentAstDeclaration,\n\t\t\t\t});\n\n\t\t\t\tthis._astDeclarationsByDeclaration.set(declaration, astDeclaration);\n\t\t\t}\n\t\t}\n\n\t\tif (options.isExternal !== astSymbol.isExternal) {\n\t\t\tthrow new InternalError(\n\t\t\t\t`Cannot assign isExternal=${options.isExternal} for` +\n\t\t\t\t\t` the symbol ${astSymbol.localName} because it was previously registered` +\n\t\t\t\t\t` with isExternal=${astSymbol.isExternal}`,\n\t\t\t);\n\t\t}\n\n\t\treturn astSymbol;\n\t}\n\n\t/**\n\t * Returns the first parent satisfying isAstDeclaration(), or undefined if none is found.\n\t */\n\tprivate _tryFindFirstAstDeclarationParent(node: ts.Node): ts.Node | undefined {\n\t\tlet currentNode: ts.Node | undefined = node.parent;\n\t\twhile (currentNode) {\n\t\t\tif (AstDeclaration.isSupportedSyntaxKind(currentNode.kind)) {\n\t\t\t\treturn currentNode;\n\t\t\t}\n\n\t\t\tcurrentNode = currentNode.parent;\n\t\t}\n\n\t\treturn undefined;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/ExportAnalyzer.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError } from '@rushstack/node-core-library';\nimport * as ts from 'typescript';\nimport type { AstEntity } from './AstEntity.js';\nimport { AstImport, type IAstImportOptions, AstImportKind } from './AstImport.js';\nimport { AstModule, type IAstModuleExportInfo } from './AstModule.js';\nimport { AstNamespaceExport } from './AstNamespaceExport.js';\nimport { AstNamespaceImport } from './AstNamespaceImport.js';\nimport { AstSymbol } from './AstSymbol.js';\nimport type { IFetchAstSymbolOptions } from './AstSymbolTable.js';\nimport { SourceFileLocationFormatter } from './SourceFileLocationFormatter.js';\nimport { SyntaxHelpers } from './SyntaxHelpers.js';\nimport { TypeScriptHelpers } from './TypeScriptHelpers.js';\nimport { TypeScriptInternals } from './TypeScriptInternals.js';\n\n/**\n * Exposes the minimal APIs from AstSymbolTable that are needed by ExportAnalyzer.\n *\n * In particular, we want ExportAnalyzer to be able to call AstSymbolTable._fetchAstSymbol() even though it\n * is a very private API that should not be exposed to any other components.\n */\nexport interface IAstSymbolTable {\n\tanalyze(astEntity: AstEntity): void;\n\n\tfetchAstSymbol(options: IFetchAstSymbolOptions): AstSymbol | undefined;\n}\n\n/**\n * Used with ExportAnalyzer.fetchAstModuleBySourceFile() to provide contextual information about how the source file\n * was imported.\n */\ninterface IAstModuleReference {\n\t/**\n\t * For example, if we are following a statement like `import { X } from 'some-package'`, this will be the\n\t * string `\"some-package\"`.\n\t */\n\tmoduleSpecifier: string;\n\n\t/**\n\t * For example, if we are following a statement like `import { X } from 'some-package'`, this will be the\n\t * symbol for `X`.\n\t */\n\tmoduleSpecifierSymbol: ts.Symbol;\n}\n\n/**\n * The ExportAnalyzer is an internal part of AstSymbolTable that has been moved out into its own source file\n * because it is a complex and mostly self-contained algorithm.\n *\n * Its job is to build up AstModule objects by crawling import statements to discover where declarations come from.\n * This is conceptually the same as the compiler's own TypeChecker.getExportsOfModule(), except that when\n * ExportAnalyzer encounters a declaration that was imported from an external package, it remembers how it was imported\n * (i.e. the AstImport object).  Today the compiler API does not expose this information, which is crucial for\n * generating .d.ts rollups.\n */\nexport class ExportAnalyzer {\n\tprivate readonly _program: ts.Program;\n\n\tprivate readonly _typeChecker: ts.TypeChecker;\n\n\tprivate readonly _bundledPackageNames: ReadonlySet<string>;\n\n\tprivate readonly _astSymbolTable: IAstSymbolTable;\n\n\tprivate readonly _astModulesByModuleSymbol: Map<ts.Symbol, AstModule> = new Map<ts.Symbol, AstModule>();\n\n\t// Used with isImportableAmbientSourceFile()\n\tprivate readonly _importableAmbientSourceFiles: Set<ts.SourceFile> = new Set<ts.SourceFile>();\n\n\tprivate readonly _astImportsByKey: Map<string, AstImport> = new Map<string, AstImport>();\n\n\tprivate readonly _astNamespaceImportByModule: Map<AstModule, AstNamespaceImport> = new Map();\n\n\tpublic constructor(\n\t\tprogram: ts.Program,\n\t\ttypeChecker: ts.TypeChecker,\n\t\tbundledPackageNames: ReadonlySet<string>,\n\t\tastSymbolTable: IAstSymbolTable,\n\t) {\n\t\tthis._program = program;\n\t\tthis._typeChecker = typeChecker;\n\t\tthis._bundledPackageNames = bundledPackageNames;\n\t\tthis._astSymbolTable = astSymbolTable;\n\t}\n\n\t/**\n\t * For a given source file, this analyzes all of its exports and produces an AstModule object.\n\t *\n\t * @param sourceFile - the sourceFile\n\t * @param moduleReference - contextual information about the import statement that took us to this source file.\n\t * or `undefined` if this source file is the initial entry point\n\t * @param isExternal - whether the given `moduleReference` is external.\n\t */\n\tpublic fetchAstModuleFromSourceFile(\n\t\tsourceFile: ts.SourceFile,\n\t\tmoduleReference: IAstModuleReference | undefined,\n\t\tisExternal: boolean,\n\t): AstModule {\n\t\tconst moduleSymbol: ts.Symbol = this._getModuleSymbolFromSourceFile(sourceFile, moduleReference);\n\n\t\t// Don't traverse into a module that we already processed before:\n\t\t// The compiler allows m1 to have \"export * from 'm2'\" and \"export * from 'm3'\",\n\t\t// even if m2 and m3 both have \"export * from 'm4'\".\n\t\tlet astModule: AstModule | undefined = this._astModulesByModuleSymbol.get(moduleSymbol);\n\t\tif (!astModule) {\n\t\t\t// (If moduleReference === undefined, then this is the entry point of the local project being analyzed.)\n\t\t\tconst externalModulePath: string | undefined =\n\t\t\t\tmoduleReference !== undefined && isExternal ? moduleReference.moduleSpecifier : undefined;\n\n\t\t\tastModule = new AstModule({ sourceFile, moduleSymbol, externalModulePath });\n\n\t\t\tthis._astModulesByModuleSymbol.set(moduleSymbol, astModule);\n\n\t\t\tif (astModule.isExternal) {\n\t\t\t\t// It's an external package, so do the special simplified analysis that doesn't crawl into referenced modules\n\t\t\t\tfor (const exportedSymbol of this._typeChecker.getExportsOfModule(moduleSymbol)) {\n\t\t\t\t\tif (externalModulePath === undefined) {\n\t\t\t\t\t\tthrow new InternalError('Failed assertion: externalModulePath=undefined but astModule.isExternal=true');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst followedSymbol: ts.Symbol = TypeScriptHelpers.followAliases(exportedSymbol, this._typeChecker);\n\n\t\t\t\t\t// Ignore virtual symbols that don't have any declarations\n\t\t\t\t\tconst arbitraryDeclaration: ts.Declaration | undefined = TypeScriptHelpers.tryGetADeclaration(followedSymbol);\n\t\t\t\t\tif (arbitraryDeclaration) {\n\t\t\t\t\t\tconst astSymbol: AstSymbol | undefined = this._astSymbolTable.fetchAstSymbol({\n\t\t\t\t\t\t\tfollowedSymbol,\n\t\t\t\t\t\t\tisExternal: astModule.isExternal,\n\t\t\t\t\t\t\tincludeNominalAnalysis: true,\n\t\t\t\t\t\t\taddIfMissing: true,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (!astSymbol) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Unsupported export ${JSON.stringify(exportedSymbol.name)}:\\n` +\n\t\t\t\t\t\t\t\t\tSourceFileLocationFormatter.formatDeclaration(arbitraryDeclaration),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tastModule.cachedExportedEntities.set(exportedSymbol.name, astSymbol);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (moduleSymbol.exports) {\n\t\t\t\t// The module is part of the local project, so do the full analysis\n\t\t\t\t// The \"export * from 'module-name';\" declarations are all attached to a single virtual symbol\n\t\t\t\t// whose name is InternalSymbolName.ExportStar\n\t\t\t\tconst exportStarSymbol: ts.Symbol | undefined = moduleSymbol.exports.get(ts.InternalSymbolName.ExportStar);\n\t\t\t\tif (exportStarSymbol) {\n\t\t\t\t\tfor (const exportStarDeclaration of exportStarSymbol.getDeclarations() ?? []) {\n\t\t\t\t\t\tif (ts.isExportDeclaration(exportStarDeclaration)) {\n\t\t\t\t\t\t\tconst starExportedModule: AstModule | undefined = this._fetchSpecifierAstModule(\n\t\t\t\t\t\t\t\texportStarDeclaration,\n\t\t\t\t\t\t\t\texportStarSymbol,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tif (starExportedModule !== undefined) {\n\t\t\t\t\t\t\t\tastModule.starExportedModules.add(starExportedModule);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Ignore ExportDeclaration nodes that don't match the expected pattern\n\t\t\t\t\t\t\t// Should we report a warning?\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn astModule;\n\t}\n\n\t/**\n\t * Retrieves the symbol for the module corresponding to the ts.SourceFile that is being imported/exported.\n\t *\n\t * @remarks\n\t * The `module` keyword can be used to declare multiple TypeScript modules inside a single source file.\n\t * (This is a deprecated construct and mainly used for typings such as `@types/node`.)  In this situation,\n\t * `moduleReference` helps us to fish out the correct module symbol.\n\t */\n\tprivate _getModuleSymbolFromSourceFile(\n\t\tsourceFile: ts.SourceFile,\n\t\tmoduleReference: IAstModuleReference | undefined,\n\t): ts.Symbol {\n\t\tconst moduleSymbol: ts.Symbol | undefined = TypeScriptInternals.tryGetSymbolForDeclaration(\n\t\t\tsourceFile,\n\t\t\tthis._typeChecker,\n\t\t);\n\t\tif (moduleSymbol !== undefined) {\n\t\t\t// This is the normal case.  The SourceFile acts is a module and has a symbol.\n\t\t\treturn moduleSymbol;\n\t\t}\n\n\t\tif (\n\t\t\tmoduleReference !== undefined && // But there is also an elaborate case where the source file contains one or more \"module\" declarations,\n\t\t\t// and our moduleReference took us to one of those.\n\n\t\t\t(moduleReference.moduleSpecifierSymbol.flags & ts.SymbolFlags.Alias) !== 0\n\t\t) {\n\t\t\t// Follow the import/export declaration to one hop the exported item inside the target module\n\t\t\tlet followedSymbol: ts.Symbol | undefined = this._typeChecker.getImmediateAliasedSymbol(\n\t\t\t\tmoduleReference.moduleSpecifierSymbol,\n\t\t\t);\n\n\t\t\tif (followedSymbol === undefined) {\n\t\t\t\t// This is a workaround for a compiler bug where getImmediateAliasedSymbol() sometimes returns undefined\n\t\t\t\tfollowedSymbol = this._typeChecker.getAliasedSymbol(moduleReference.moduleSpecifierSymbol);\n\t\t\t}\n\n\t\t\tif (followedSymbol !== undefined && followedSymbol !== moduleReference.moduleSpecifierSymbol) {\n\t\t\t\t// The parent of the exported symbol will be the module that we're importing from\n\t\t\t\tconst parent: ts.Symbol | undefined = TypeScriptInternals.getSymbolParent(followedSymbol);\n\t\t\t\tif (\n\t\t\t\t\tparent !== undefined && // Make sure the thing we found is a module\n\t\t\t\t\t(parent.flags & ts.SymbolFlags.ValueModule) !== 0\n\t\t\t\t) {\n\t\t\t\t\t// Record that that this is an ambient module that can also be imported from\n\t\t\t\t\tthis._importableAmbientSourceFiles.add(sourceFile);\n\t\t\t\t\treturn parent;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthrow new InternalError('Unable to determine module for: ' + sourceFile.fileName);\n\t}\n\n\t/**\n\t * Implementation of {@link AstSymbolTable.fetchAstModuleExportInfo}.\n\t */\n\tpublic fetchAstModuleExportInfo(entryPointAstModule: AstModule): IAstModuleExportInfo {\n\t\tif (entryPointAstModule.isExternal) {\n\t\t\tthrow new Error('fetchAstModuleExportInfo() is not supported for external modules');\n\t\t}\n\n\t\tif (entryPointAstModule.astModuleExportInfo === undefined) {\n\t\t\tconst astModuleExportInfo: IAstModuleExportInfo = {\n\t\t\t\tvisitedAstModules: new Set<AstModule>(),\n\t\t\t\texportedLocalEntities: new Map<string, AstEntity>(),\n\t\t\t\tstarExportedExternalModules: new Set<AstModule>(),\n\t\t\t};\n\n\t\t\tthis._collectAllExportsRecursive(astModuleExportInfo, entryPointAstModule);\n\n\t\t\tentryPointAstModule.astModuleExportInfo = astModuleExportInfo;\n\t\t}\n\n\t\treturn entryPointAstModule.astModuleExportInfo;\n\t}\n\n\t/**\n\t * Returns true if the module specifier refers to an external package.  Ignores packages listed in the\n\t * \"bundledPackages\" setting from the api-extractor.json config file.\n\t */\n\tprivate _isExternalModulePath(\n\t\timportOrExportDeclaration: ts.ExportDeclaration | ts.ImportDeclaration | ts.ImportTypeNode,\n\t\tmoduleSpecifier: string,\n\t): boolean {\n\t\tconst specifier: ts.Expression | ts.TypeNode | undefined = ts.isImportTypeNode(importOrExportDeclaration)\n\t\t\t? importOrExportDeclaration.argument\n\t\t\t: importOrExportDeclaration.moduleSpecifier;\n\t\tconst mode: ts.ModuleKind.CommonJS | ts.ModuleKind.ESNext | undefined =\n\t\t\tspecifier && ts.isStringLiteralLike(specifier)\n\t\t\t\t? this._program.getModeForUsageLocation(importOrExportDeclaration.getSourceFile(), specifier)\n\t\t\t\t: undefined;\n\n\t\tconst resolvedModule: ts.ResolvedModuleFull | undefined = TypeScriptInternals.getResolvedModule(\n\t\t\tthis._program,\n\t\t\timportOrExportDeclaration.getSourceFile(),\n\t\t\tmoduleSpecifier,\n\t\t\tmode,\n\t\t);\n\n\t\tif (resolvedModule === undefined) {\n\t\t\t// The TS compiler API `getResolvedModule` cannot resolve ambient modules. Thus, to match API Extractor's\n\t\t\t// previous behavior, simply treat all ambient modules as external. This bug is tracked by\n\t\t\t// https://github.com/microsoft/rushstack/issues/3335.\n\t\t\treturn true;\n\t\t}\n\n\t\t// Either something like `jquery` or `@microsoft/api-extractor`.\n\t\tconst packageName: string | undefined = resolvedModule.packageId?.name;\n\t\tif (packageName !== undefined && this._bundledPackageNames.has(packageName)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (resolvedModule.isExternalLibraryImport === undefined) {\n\t\t\t// This presumably means the compiler couldn't figure out whether the module was external, but we're not\n\t\t\t// sure how this can happen.\n\t\t\tthrow new InternalError(\n\t\t\t\t`Cannot determine whether the module ${JSON.stringify(moduleSpecifier)} is external\\n` +\n\t\t\t\t\tSourceFileLocationFormatter.formatDeclaration(importOrExportDeclaration),\n\t\t\t);\n\t\t}\n\n\t\treturn resolvedModule.isExternalLibraryImport;\n\t}\n\n\t/**\n\t * Returns true if when we analyzed sourceFile, we found that it contains an \"export=\" statement that allows\n\t * it to behave /either/ as an ambient module /or/ as a regular importable module.  In this case,\n\t * `AstSymbolTable._fetchAstSymbol()` will analyze its symbols even though `TypeScriptHelpers.isAmbient()`\n\t * returns true.\n\t */\n\tpublic isImportableAmbientSourceFile(sourceFile: ts.SourceFile): boolean {\n\t\treturn this._importableAmbientSourceFiles.has(sourceFile);\n\t}\n\n\tprivate _collectAllExportsRecursive(astModuleExportInfo: IAstModuleExportInfo, astModule: AstModule): void {\n\t\tconst { visitedAstModules, starExportedExternalModules, exportedLocalEntities } = astModuleExportInfo;\n\t\tif (visitedAstModules.has(astModule)) {\n\t\t\treturn;\n\t\t}\n\n\t\tvisitedAstModules.add(astModule);\n\n\t\tif (astModule.isExternal) {\n\t\t\tstarExportedExternalModules.add(astModule);\n\t\t} else {\n\t\t\t// Fetch each of the explicit exports for this module\n\t\t\tif (astModule.moduleSymbol.exports) {\n\t\t\t\tfor (const [exportName, exportSymbol] of astModule.moduleSymbol.exports.entries()) {\n\t\t\t\t\tswitch (exportName) {\n\t\t\t\t\t\tcase ts.InternalSymbolName.ExportStar:\n\t\t\t\t\t\tcase ts.InternalSymbolName.ExportEquals:\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t// Don't collect the \"export default\" symbol unless this is the entry point module\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t(exportName !== ts.InternalSymbolName.Default || visitedAstModules.size === 1) &&\n\t\t\t\t\t\t\t\t!exportedLocalEntities.has(exportSymbol.name)\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tconst astEntity: AstEntity = this._getExportOfAstModule(exportSymbol.name, astModule);\n\n\t\t\t\t\t\t\t\tif (astEntity instanceof AstSymbol && !astEntity.isExternal) {\n\t\t\t\t\t\t\t\t\tthis._astSymbolTable.analyze(astEntity);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (astEntity instanceof AstNamespaceImport && !astEntity.astModule.isExternal) {\n\t\t\t\t\t\t\t\t\tthis._astSymbolTable.analyze(astEntity);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\texportedLocalEntities.set(exportSymbol.name, astEntity);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const starExportedModule of astModule.starExportedModules) {\n\t\t\t\tthis._collectAllExportsRecursive(astModuleExportInfo, starExportedModule);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * For a given symbol (which was encountered in the specified sourceFile), this fetches the AstEntity that it\n\t * refers to.  For example, if a particular interface describes the return value of a function, this API can help\n\t * us determine a TSDoc declaration reference for that symbol (if the symbol is exported).\n\t */\n\tpublic fetchReferencedAstEntity(symbol: ts.Symbol, referringModuleIsExternal: boolean): AstEntity | undefined {\n\t\tif ((symbol.flags & ts.SymbolFlags.FunctionScopedVariable) !== 0) {\n\t\t\t// If a symbol refers back to part of its own definition, don't follow that rabbit hole\n\t\t\t// Example:\n\t\t\t//\n\t\t\t// function f(x: number): typeof x {\n\t\t\t//    return 123;\n\t\t\t// }\n\t\t\treturn undefined;\n\t\t}\n\n\t\tlet current: ts.Symbol = symbol;\n\n\t\tif (referringModuleIsExternal) {\n\t\t\tcurrent = TypeScriptHelpers.followAliases(symbol, this._typeChecker);\n\t\t} else {\n\t\t\tfor (;;) {\n\t\t\t\t// Is this symbol an import/export that we need to follow to find the real declaration?\n\t\t\t\tfor (const declaration of current.declarations ?? []) {\n\t\t\t\t\tlet matchedAstEntity: AstEntity | undefined;\n\t\t\t\t\tmatchedAstEntity = this._tryMatchExportDeclaration(declaration, current);\n\t\t\t\t\tif (matchedAstEntity !== undefined) {\n\t\t\t\t\t\treturn matchedAstEntity;\n\t\t\t\t\t}\n\n\t\t\t\t\tmatchedAstEntity = this._tryMatchImportDeclaration(declaration, current);\n\t\t\t\t\tif (matchedAstEntity !== undefined) {\n\t\t\t\t\t\treturn matchedAstEntity;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!(current.flags & ts.SymbolFlags.Alias)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tconst currentAlias: ts.Symbol | undefined = this._typeChecker.getImmediateAliasedSymbol(current);\n\t\t\t\t// Stop if we reach the end of the chain\n\t\t\t\tif (!currentAlias || currentAlias === current) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcurrent = currentAlias;\n\t\t\t}\n\t\t}\n\n\t\t// Otherwise, assume it is a normal declaration\n\t\tconst astSymbol: AstSymbol | undefined = this._astSymbolTable.fetchAstSymbol({\n\t\t\tfollowedSymbol: current,\n\t\t\tisExternal: referringModuleIsExternal,\n\t\t\tincludeNominalAnalysis: false,\n\t\t\taddIfMissing: true,\n\t\t});\n\n\t\treturn astSymbol;\n\t}\n\n\tpublic fetchReferencedAstEntityFromImportTypeNode(\n\t\tnode: ts.ImportTypeNode,\n\t\treferringModuleIsExternal: boolean,\n\t): AstEntity | undefined {\n\t\tconst externalModulePath: string | undefined = this._tryGetExternalModulePath(node);\n\n\t\tif (externalModulePath) {\n\t\t\tlet exportName: string;\n\t\t\tif (node.qualifier) {\n\t\t\t\t// Example input:\n\t\t\t\t//   import('api-extractor-lib1-test').Lib1GenericType<number>\n\t\t\t\t//\n\t\t\t\t// Extracted qualifier:\n\t\t\t\t//   Lib1GenericType\n\t\t\t\texportName = node.qualifier.getText().trim();\n\t\t\t} else {\n\t\t\t\t// Example input:\n\t\t\t\t//   import('api-extractor-lib1-test')\n\t\t\t\t//\n\t\t\t\t// Extracted qualifier:\n\t\t\t\t//   apiExtractorLib1Test\n\n\t\t\t\texportName = SyntaxHelpers.makeCamelCaseIdentifier(externalModulePath);\n\t\t\t}\n\n\t\t\treturn this._fetchAstImport(undefined, {\n\t\t\t\timportKind: AstImportKind.ImportType,\n\t\t\t\texportName,\n\t\t\t\tmodulePath: externalModulePath,\n\t\t\t\tisTypeOnly: false,\n\t\t\t});\n\t\t}\n\n\t\t// Internal reference: AstSymbol\n\t\tconst rightMostToken: ts.Identifier | ts.ImportTypeNode = node.qualifier\n\t\t\t? node.qualifier.kind === ts.SyntaxKind.QualifiedName\n\t\t\t\t? node.qualifier.right\n\t\t\t\t: node.qualifier\n\t\t\t: node;\n\n\t\t// There is no symbol property in a ImportTypeNode, obtain the associated export symbol\n\t\tconst exportSymbol: ts.Symbol | undefined = this._typeChecker.getSymbolAtLocation(rightMostToken);\n\t\tif (!exportSymbol) {\n\t\t\tthrow new InternalError(\n\t\t\t\t`Symbol not found for identifier: ${node.getText()}\\n` + SourceFileLocationFormatter.formatDeclaration(node),\n\t\t\t);\n\t\t}\n\n\t\tlet followedSymbol: ts.Symbol = exportSymbol;\n\t\tfor (;;) {\n\t\t\tconst referencedAstEntity: AstEntity | undefined = this.fetchReferencedAstEntity(\n\t\t\t\tfollowedSymbol,\n\t\t\t\treferringModuleIsExternal,\n\t\t\t);\n\n\t\t\tif (referencedAstEntity) {\n\t\t\t\treturn referencedAstEntity;\n\t\t\t}\n\n\t\t\tconst followedSymbolNode: ts.ImportTypeNode | ts.Node | undefined =\n\t\t\t\tfollowedSymbol.declarations && (followedSymbol.declarations[0] as ts.Node | undefined);\n\n\t\t\tif (followedSymbolNode?.kind === ts.SyntaxKind.ImportType) {\n\t\t\t\treturn this.fetchReferencedAstEntityFromImportTypeNode(\n\t\t\t\t\tfollowedSymbolNode as ts.ImportTypeNode,\n\t\t\t\t\treferringModuleIsExternal,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (!(followedSymbol.flags & ts.SymbolFlags.Alias)) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst currentAlias: ts.Symbol = this._typeChecker.getAliasedSymbol(followedSymbol);\n\t\t\tif (!currentAlias || currentAlias === followedSymbol) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tfollowedSymbol = currentAlias;\n\t\t}\n\n\t\tconst astSymbol: AstSymbol | undefined = this._astSymbolTable.fetchAstSymbol({\n\t\t\tfollowedSymbol,\n\t\t\tisExternal: referringModuleIsExternal,\n\t\t\tincludeNominalAnalysis: false,\n\t\t\taddIfMissing: true,\n\t\t});\n\n\t\treturn astSymbol;\n\t}\n\n\tprivate _tryMatchExportDeclaration(declaration: ts.Declaration, declarationSymbol: ts.Symbol): AstEntity | undefined {\n\t\tconst exportDeclaration: ts.ExportDeclaration | undefined = TypeScriptHelpers.findFirstParent<ts.ExportDeclaration>(\n\t\t\tdeclaration,\n\t\t\tts.SyntaxKind.ExportDeclaration,\n\t\t);\n\n\t\tif (exportDeclaration) {\n\t\t\tlet exportName: string | undefined;\n\n\t\t\tif (declaration.kind === ts.SyntaxKind.ExportSpecifier) {\n\t\t\t\t// EXAMPLE:\n\t\t\t\t// \"export { A } from './file-a';\"\n\t\t\t\t//\n\t\t\t\t// ExportDeclaration:\n\t\t\t\t//   ExportKeyword:  pre=[export] sep=[ ]\n\t\t\t\t//   NamedExports:\n\t\t\t\t//     FirstPunctuation:  pre=[{] sep=[ ]\n\t\t\t\t//     SyntaxList:\n\t\t\t\t//       ExportSpecifier:  <------------- declaration\n\t\t\t\t//         Identifier:  pre=[A] sep=[ ]\n\t\t\t\t//     CloseBraceToken:  pre=[}] sep=[ ]\n\t\t\t\t//   FromKeyword:  pre=[from] sep=[ ]\n\t\t\t\t//   StringLiteral:  pre=['./file-a']\n\t\t\t\t//   SemicolonToken:  pre=[;]\n\n\t\t\t\t// Example: \" ExportName as RenamedName\"\n\t\t\t\tconst exportSpecifier: ts.ExportSpecifier = declaration as ts.ExportSpecifier;\n\t\t\t\texportName = (exportSpecifier.propertyName ?? exportSpecifier.name).getText().trim();\n\t\t\t} else if (declaration.kind === ts.SyntaxKind.NamespaceExport) {\n\t\t\t\t// EXAMPLE:\n\t\t\t\t// \"export * as theLib from 'the-lib';\"\n\t\t\t\t//\n\t\t\t\t// ExportDeclaration:\n\t\t\t\t//   ExportKeyword:  pre=[export] sep=[ ]\n\t\t\t\t//   NamespaceExport:\n\t\t\t\t//     AsteriskToken:  pre=[*] sep=[ ]\n\t\t\t\t//     AsKeyword:  pre=[as] sep=[ ]\n\t\t\t\t//     Identifier:  pre=[theLib] sep=[ ]\n\t\t\t\t//   FromKeyword:  pre=[from] sep=[ ]\n\t\t\t\t//   StringLiteral:  pre=['the-lib']\n\t\t\t\t//   SemicolonToken:  pre=[;]\n\n\t\t\t\t// Issue tracking this feature: https://github.com/microsoft/rushstack/issues/2780\n\t\t\t\tconst astModule: AstModule = this._fetchSpecifierAstModule(exportDeclaration, declarationSymbol);\n\t\t\t\treturn this._getAstNamespaceExport(astModule, declarationSymbol, declaration);\n\t\t\t\t// throw new Error(\n\t\t\t\t// \t`The \"export * as ___\" syntax is not supported yet; as a workaround,` +\n\t\t\t\t// \t\t` use \"import * as ___\" with a separate \"export { ___ }\" declaration\\n` +\n\t\t\t\t// \t\tSourceFileLocationFormatter.formatDeclaration(declaration),\n\t\t\t\t// );\n\t\t\t} else {\n\t\t\t\tthrow new InternalError(\n\t\t\t\t\t`Unimplemented export declaration kind: ${declaration.getText()}\\n` +\n\t\t\t\t\t\tSourceFileLocationFormatter.formatDeclaration(declaration),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Ignore \"export { A }\" without a module specifier\n\t\t\tif (exportDeclaration.moduleSpecifier) {\n\t\t\t\tconst externalModulePath: string | undefined = this._tryGetExternalModulePath(exportDeclaration);\n\n\t\t\t\t// if (declaration.kind === ts.SyntaxKind.NamespaceExport) {\n\t\t\t\t// \tif (externalModulePath === undefined) {\n\t\t\t\t// \t\tconst astModule: AstModule = this._fetchSpecifierAstModule(exportDeclaration, declarationSymbol);\n\t\t\t\t// \t\tlet namespaceImport: AstNamespaceImport | undefined = this._astNamespaceImportByModule.get(astModule);\n\t\t\t\t// \t\tif (namespaceImport === undefined) {\n\t\t\t\t// \t\t\tnamespaceImport = new AstNamespaceImport({\n\t\t\t\t// \t\t\t\tnamespaceName: declarationSymbol.name,\n\t\t\t\t// \t\t\t\tastModule,\n\t\t\t\t// \t\t\t\tdeclaration,\n\t\t\t\t// \t\t\t\tsymbol: declarationSymbol,\n\t\t\t\t// \t\t\t});\n\t\t\t\t// \t\t\tthis._astNamespaceImportByModule.set(astModule, namespaceImport);\n\t\t\t\t// \t\t}\n\n\t\t\t\t// \t\treturn namespaceImport;\n\t\t\t\t// \t}\n\n\t\t\t\t// \t// Here importSymbol=undefined because {@inheritDoc} and such are not going to work correctly for\n\t\t\t\t// \t// a package or source file.\n\t\t\t\t// \treturn this._fetchAstImport(undefined, {\n\t\t\t\t// \t\timportKind: AstImportKind.StarImport,\n\t\t\t\t// \t\texportName,\n\t\t\t\t// \t\tmodulePath: externalModulePath,\n\t\t\t\t// \t\tisTypeOnly: exportDeclaration.isTypeOnly,\n\t\t\t\t// \t});\n\t\t\t\t// }\n\n\t\t\t\tif (externalModulePath !== undefined) {\n\t\t\t\t\treturn this._fetchAstImport(declarationSymbol, {\n\t\t\t\t\t\timportKind: AstImportKind.NamedImport,\n\t\t\t\t\t\tmodulePath: externalModulePath,\n\t\t\t\t\t\texportName,\n\t\t\t\t\t\tisTypeOnly: false,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn this._getExportOfSpecifierAstModule(exportName, exportDeclaration, declarationSymbol);\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate _getAstNamespaceExport(\n\t\tastModule: AstModule,\n\t\tdeclarationSymbol: ts.Symbol,\n\t\tdeclaration: ts.Declaration,\n\t): AstNamespaceExport {\n\t\tconst imoprtNamespace: AstNamespaceImport = this._getAstNamespaceImport(astModule, declarationSymbol, declaration);\n\n\t\treturn new AstNamespaceExport({\n\t\t\tnamespaceName: imoprtNamespace.localName,\n\t\t\tastModule,\n\t\t\tdeclaration,\n\t\t\tsymbol: declarationSymbol,\n\t\t});\n\t}\n\n\tprivate _tryMatchImportDeclaration(declaration: ts.Declaration, declarationSymbol: ts.Symbol): AstEntity | undefined {\n\t\tconst importDeclaration: ts.ImportDeclaration | undefined = TypeScriptHelpers.findFirstParent<ts.ImportDeclaration>(\n\t\t\tdeclaration,\n\t\t\tts.SyntaxKind.ImportDeclaration,\n\t\t);\n\n\t\tif (importDeclaration) {\n\t\t\tconst externalModulePath: string | undefined = this._tryGetExternalModulePath(importDeclaration);\n\n\t\t\tif (declaration.kind === ts.SyntaxKind.NamespaceImport) {\n\t\t\t\t// EXAMPLE:\n\t\t\t\t// \"import * as theLib from 'the-lib';\"\n\t\t\t\t//\n\t\t\t\t// ImportDeclaration:\n\t\t\t\t//   ImportKeyword:  pre=[import] sep=[ ]\n\t\t\t\t//   ImportClause:\n\t\t\t\t//     NamespaceImport:  <------------- declaration\n\t\t\t\t//       AsteriskToken:  pre=[*] sep=[ ]\n\t\t\t\t//       AsKeyword:  pre=[as] sep=[ ]\n\t\t\t\t//       Identifier:  pre=[theLib] sep=[ ]\n\t\t\t\t//   FromKeyword:  pre=[from] sep=[ ]\n\t\t\t\t//   StringLiteral:  pre=['the-lib']\n\t\t\t\t//   SemicolonToken:  pre=[;]\n\n\t\t\t\tif (externalModulePath === undefined) {\n\t\t\t\t\tconst astModule: AstModule = this._fetchSpecifierAstModule(importDeclaration, declarationSymbol);\n\t\t\t\t\treturn this._getAstNamespaceImport(astModule, declarationSymbol, declaration);\n\t\t\t\t}\n\n\t\t\t\t// Here importSymbol=undefined because {@inheritDoc} and such are not going to work correctly for\n\t\t\t\t// a package or source file.\n\t\t\t\treturn this._fetchAstImport(undefined, {\n\t\t\t\t\timportKind: AstImportKind.StarImport,\n\t\t\t\t\texportName: declarationSymbol.name,\n\t\t\t\t\tmodulePath: externalModulePath,\n\t\t\t\t\tisTypeOnly: ExportAnalyzer._getIsTypeOnly(importDeclaration),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (declaration.kind === ts.SyntaxKind.ImportSpecifier) {\n\t\t\t\t// EXAMPLE:\n\t\t\t\t// \"import { A, B } from 'the-lib';\"\n\t\t\t\t//\n\t\t\t\t// ImportDeclaration:\n\t\t\t\t//   ImportKeyword:  pre=[import] sep=[ ]\n\t\t\t\t//   ImportClause:\n\t\t\t\t//     NamedImports:\n\t\t\t\t//       FirstPunctuation:  pre=[{] sep=[ ]\n\t\t\t\t//       SyntaxList:\n\t\t\t\t//         ImportSpecifier:  <------------- declaration\n\t\t\t\t//           Identifier:  pre=[A]\n\t\t\t\t//         CommaToken:  pre=[,] sep=[ ]\n\t\t\t\t//         ImportSpecifier:\n\t\t\t\t//           Identifier:  pre=[B] sep=[ ]\n\t\t\t\t//       CloseBraceToken:  pre=[}] sep=[ ]\n\t\t\t\t//   FromKeyword:  pre=[from] sep=[ ]\n\t\t\t\t//   StringLiteral:  pre=['the-lib']\n\t\t\t\t//   SemicolonToken:  pre=[;]\n\n\t\t\t\t// Example: \" ExportName as RenamedName\"\n\t\t\t\tconst importSpecifier: ts.ImportSpecifier = declaration as ts.ImportSpecifier;\n\t\t\t\tconst exportName: string = (importSpecifier.propertyName ?? importSpecifier.name).getText().trim();\n\n\t\t\t\tif (externalModulePath !== undefined) {\n\t\t\t\t\treturn this._fetchAstImport(declarationSymbol, {\n\t\t\t\t\t\timportKind: AstImportKind.NamedImport,\n\t\t\t\t\t\tmodulePath: externalModulePath,\n\t\t\t\t\t\texportName,\n\t\t\t\t\t\tisTypeOnly: ExportAnalyzer._getIsTypeOnly(importDeclaration),\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn this._getExportOfSpecifierAstModule(exportName, importDeclaration, declarationSymbol);\n\t\t\t} else if (declaration.kind === ts.SyntaxKind.ImportClause) {\n\t\t\t\t// EXAMPLE:\n\t\t\t\t// \"import A, { B } from './A';\"\n\t\t\t\t//\n\t\t\t\t// ImportDeclaration:\n\t\t\t\t//   ImportKeyword:  pre=[import] sep=[ ]\n\t\t\t\t//   ImportClause:  <------------- declaration (referring to A)\n\t\t\t\t//     Identifier:  pre=[A]\n\t\t\t\t//     CommaToken:  pre=[,] sep=[ ]\n\t\t\t\t//     NamedImports:\n\t\t\t\t//       FirstPunctuation:  pre=[{] sep=[ ]\n\t\t\t\t//       SyntaxList:\n\t\t\t\t//         ImportSpecifier:\n\t\t\t\t//           Identifier:  pre=[B] sep=[ ]\n\t\t\t\t//       CloseBraceToken:  pre=[}] sep=[ ]\n\t\t\t\t//   FromKeyword:  pre=[from] sep=[ ]\n\t\t\t\t//   StringLiteral:  pre=['./A']\n\t\t\t\t//   SemicolonToken:  pre=[;]\n\n\t\t\t\tconst importClause: ts.ImportClause = declaration as ts.ImportClause;\n\t\t\t\tconst exportName: string = importClause.name\n\t\t\t\t\t? importClause.name.getText().trim()\n\t\t\t\t\t: ts.InternalSymbolName.Default;\n\n\t\t\t\tif (externalModulePath !== undefined) {\n\t\t\t\t\treturn this._fetchAstImport(declarationSymbol, {\n\t\t\t\t\t\timportKind: AstImportKind.DefaultImport,\n\t\t\t\t\t\tmodulePath: externalModulePath,\n\t\t\t\t\t\texportName,\n\t\t\t\t\t\tisTypeOnly: ExportAnalyzer._getIsTypeOnly(importDeclaration),\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn this._getExportOfSpecifierAstModule(ts.InternalSymbolName.Default, importDeclaration, declarationSymbol);\n\t\t\t} else {\n\t\t\t\tthrow new InternalError(\n\t\t\t\t\t`Unimplemented import declaration kind: ${declaration.getText()}\\n` +\n\t\t\t\t\t\tSourceFileLocationFormatter.formatDeclaration(declaration),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\tts.isImportEqualsDeclaration(declaration) && // EXAMPLE:\n\t\t\t// import myLib = require('my-lib');\n\t\t\t//\n\t\t\t// ImportEqualsDeclaration:\n\t\t\t//   ImportKeyword:  pre=[import] sep=[ ]\n\t\t\t//   Identifier:  pre=[myLib] sep=[ ]\n\t\t\t//   FirstAssignment:  pre=[=] sep=[ ]\n\t\t\t//   ExternalModuleReference:\n\t\t\t//     RequireKeyword:  pre=[require]\n\t\t\t//     OpenParenToken:  pre=[(]\n\t\t\t//     StringLiteral:  pre=['my-lib']\n\t\t\t//     CloseParenToken:  pre=[)]\n\t\t\t//   SemicolonToken:  pre=[;]\n\t\t\tts.isExternalModuleReference(declaration.moduleReference) &&\n\t\t\tts.isStringLiteralLike(declaration.moduleReference.expression)\n\t\t) {\n\t\t\tconst variableName: string = TypeScriptInternals.getTextOfIdentifierOrLiteral(declaration.name);\n\t\t\tconst externalModuleName: string = TypeScriptInternals.getTextOfIdentifierOrLiteral(\n\t\t\t\tdeclaration.moduleReference.expression,\n\t\t\t);\n\n\t\t\treturn this._fetchAstImport(declarationSymbol, {\n\t\t\t\timportKind: AstImportKind.EqualsImport,\n\t\t\t\tmodulePath: externalModuleName,\n\t\t\t\texportName: variableName,\n\t\t\t\tisTypeOnly: false,\n\t\t\t});\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate _getAstNamespaceImport(\n\t\tastModule: AstModule,\n\t\tdeclarationSymbol: ts.Symbol,\n\t\tdeclaration: ts.Declaration,\n\t): AstNamespaceImport {\n\t\tlet namespaceImport: AstNamespaceImport | undefined = this._astNamespaceImportByModule.get(astModule);\n\t\tif (namespaceImport === undefined) {\n\t\t\tnamespaceImport = new AstNamespaceImport({\n\t\t\t\tnamespaceName: declarationSymbol.name,\n\t\t\t\tastModule,\n\t\t\t\tdeclaration,\n\t\t\t\tsymbol: declarationSymbol,\n\t\t\t});\n\t\t\tthis._astNamespaceImportByModule.set(astModule, namespaceImport);\n\t\t}\n\n\t\treturn namespaceImport;\n\t}\n\n\tprivate static _getIsTypeOnly(importDeclaration: ts.ImportDeclaration): boolean {\n\t\tif (importDeclaration.importClause) {\n\t\t\treturn Boolean(importDeclaration.importClause.isTypeOnly);\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tprivate _getExportOfSpecifierAstModule(\n\t\texportName: string,\n\t\timportOrExportDeclaration: ts.ExportDeclaration | ts.ImportDeclaration,\n\t\texportSymbol: ts.Symbol,\n\t): AstEntity {\n\t\tconst specifierAstModule: AstModule = this._fetchSpecifierAstModule(importOrExportDeclaration, exportSymbol);\n\t\tconst astEntity: AstEntity = this._getExportOfAstModule(exportName, specifierAstModule);\n\t\treturn astEntity;\n\t}\n\n\tprivate _getExportOfAstModule(exportName: string, astModule: AstModule): AstEntity {\n\t\tconst visitedAstModules: Set<AstModule> = new Set<AstModule>();\n\t\tconst astEntity: AstEntity | undefined = this._tryGetExportOfAstModule(exportName, astModule, visitedAstModules);\n\t\tif (astEntity === undefined) {\n\t\t\tthrow new InternalError(\n\t\t\t\t`Unable to analyze the export ${JSON.stringify(exportName)} in\\n` + astModule.sourceFile.fileName,\n\t\t\t);\n\t\t}\n\n\t\treturn astEntity;\n\t}\n\n\t/**\n\t * Implementation of {@link AstSymbolTable.tryGetExportOfAstModule}.\n\t */\n\tpublic tryGetExportOfAstModule(exportName: string, astModule: AstModule): AstEntity | undefined {\n\t\tconst visitedAstModules: Set<AstModule> = new Set<AstModule>();\n\t\treturn this._tryGetExportOfAstModule(exportName, astModule, visitedAstModules);\n\t}\n\n\tprivate _tryGetExportOfAstModule(\n\t\texportName: string,\n\t\tastModule: AstModule,\n\t\tvisitedAstModules: Set<AstModule>,\n\t): AstEntity | undefined {\n\t\tif (visitedAstModules.has(astModule)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tvisitedAstModules.add(astModule);\n\n\t\tlet astEntity: AstEntity | undefined = astModule.cachedExportedEntities.get(exportName);\n\t\tif (astEntity !== undefined) {\n\t\t\treturn astEntity;\n\t\t}\n\n\t\t// Try the explicit exports\n\t\tconst escapedExportName: ts.__String = ts.escapeLeadingUnderscores(exportName);\n\t\tif (astModule.moduleSymbol.exports) {\n\t\t\tconst exportSymbol: ts.Symbol | undefined = astModule.moduleSymbol.exports.get(escapedExportName);\n\t\t\tif (exportSymbol) {\n\t\t\t\tastEntity = this.fetchReferencedAstEntity(exportSymbol, astModule.isExternal);\n\n\t\t\t\tif (astEntity !== undefined) {\n\t\t\t\t\tastModule.cachedExportedEntities.set(exportName, astEntity); // cache for next time\n\t\t\t\t\treturn astEntity;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Try each of the star imports\n\t\tfor (const starExportedModule of astModule.starExportedModules) {\n\t\t\tastEntity = this._tryGetExportOfAstModule(exportName, starExportedModule, visitedAstModules);\n\n\t\t\tif (astEntity !== undefined) {\n\t\t\t\tif (starExportedModule.externalModulePath !== undefined) {\n\t\t\t\t\t// This entity was obtained from an external module, so return an AstImport instead\n\t\t\t\t\tconst astSymbol: AstSymbol = astEntity as AstSymbol;\n\t\t\t\t\treturn this._fetchAstImport(astSymbol.followedSymbol, {\n\t\t\t\t\t\timportKind: AstImportKind.NamedImport,\n\t\t\t\t\t\tmodulePath: starExportedModule.externalModulePath,\n\t\t\t\t\t\texportName,\n\t\t\t\t\t\tisTypeOnly: false,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn astEntity;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate _tryGetExternalModulePath(\n\t\timportOrExportDeclaration: ts.ExportDeclaration | ts.ImportDeclaration | ts.ImportTypeNode,\n\t): string | undefined {\n\t\tconst moduleSpecifier: string = this._getModuleSpecifier(importOrExportDeclaration);\n\t\tif (this._isExternalModulePath(importOrExportDeclaration, moduleSpecifier)) {\n\t\t\treturn moduleSpecifier;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Given an ImportDeclaration of the form `export { X } from \"___\";`, this interprets the module specifier (`\"___\"`)\n\t * and fetches the corresponding AstModule object.\n\t */\n\tprivate _fetchSpecifierAstModule(\n\t\timportOrExportDeclaration: ts.ExportDeclaration | ts.ImportDeclaration,\n\t\texportSymbol: ts.Symbol,\n\t): AstModule {\n\t\tconst moduleSpecifier: string = this._getModuleSpecifier(importOrExportDeclaration);\n\t\tconst mode: ts.ModuleKind.CommonJS | ts.ModuleKind.ESNext | undefined =\n\t\t\timportOrExportDeclaration.moduleSpecifier && ts.isStringLiteralLike(importOrExportDeclaration.moduleSpecifier)\n\t\t\t\t? this._program.getModeForUsageLocation(\n\t\t\t\t\t\timportOrExportDeclaration.getSourceFile(),\n\t\t\t\t\t\timportOrExportDeclaration.moduleSpecifier,\n\t\t\t\t\t)\n\t\t\t\t: undefined;\n\t\tconst resolvedModule: ts.ResolvedModuleFull | undefined = TypeScriptInternals.getResolvedModule(\n\t\t\tthis._program,\n\t\t\timportOrExportDeclaration.getSourceFile(),\n\t\t\tmoduleSpecifier,\n\t\t\tmode,\n\t\t);\n\n\t\tif (resolvedModule === undefined) {\n\t\t\t// Encountered in https://github.com/microsoft/rushstack/issues/1914.\n\t\t\t//\n\t\t\t// It's also possible for this to occur with ambient modules. However, in practice this doesn't happen\n\t\t\t// as API Extractor treats all ambient modules as external per the logic in `_isExternalModulePath`, and\n\t\t\t// thus this code path is never reached for ambient modules.\n\t\t\tthrow new InternalError(\n\t\t\t\t`getResolvedModule() could not resolve module name ${JSON.stringify(moduleSpecifier)}\\n` +\n\t\t\t\t\tSourceFileLocationFormatter.formatDeclaration(importOrExportDeclaration),\n\t\t\t);\n\t\t}\n\n\t\t// Map the filename back to the corresponding SourceFile. This circuitous approach is needed because\n\t\t// we have no way to access the compiler's internal resolveExternalModuleName() function\n\t\tconst moduleSourceFile: ts.SourceFile | undefined = this._program.getSourceFile(resolvedModule.resolvedFileName);\n\t\tif (!moduleSourceFile) {\n\t\t\t// This should not happen, since getResolvedModule() specifically looks up names that the compiler\n\t\t\t// found in export declarations for this source file\n\t\t\tthrow new InternalError(\n\t\t\t\t`getSourceFile() failed to locate ${JSON.stringify(resolvedModule.resolvedFileName)}\\n` +\n\t\t\t\t\tSourceFileLocationFormatter.formatDeclaration(importOrExportDeclaration),\n\t\t\t);\n\t\t}\n\n\t\tconst isExternal: boolean = this._isExternalModulePath(importOrExportDeclaration, moduleSpecifier);\n\t\tconst moduleReference: IAstModuleReference = {\n\t\t\tmoduleSpecifier,\n\t\t\tmoduleSpecifierSymbol: exportSymbol,\n\t\t};\n\t\tconst specifierAstModule: AstModule = this.fetchAstModuleFromSourceFile(\n\t\t\tmoduleSourceFile,\n\t\t\tmoduleReference,\n\t\t\tisExternal,\n\t\t);\n\n\t\treturn specifierAstModule;\n\t}\n\n\tprivate _fetchAstImport(importSymbol: ts.Symbol | undefined, options: IAstImportOptions): AstImport {\n\t\tconst key: string = AstImport.getKey(options);\n\n\t\tlet astImport: AstImport | undefined = this._astImportsByKey.get(key);\n\n\t\tif (astImport) {\n\t\t\t// If we encounter at least one import that does not use the type-only form,\n\t\t\t// then the .d.ts rollup will NOT use \"import type\".\n\t\t\tif (!options.isTypeOnly) {\n\t\t\t\tastImport.isTypeOnlyEverywhere = false;\n\t\t\t}\n\t\t} else {\n\t\t\tastImport = new AstImport(options);\n\t\t\tthis._astImportsByKey.set(key, astImport);\n\n\t\t\tif (importSymbol) {\n\t\t\t\tconst followedSymbol: ts.Symbol = TypeScriptHelpers.followAliases(importSymbol, this._typeChecker);\n\n\t\t\t\tastImport.astSymbol = this._astSymbolTable.fetchAstSymbol({\n\t\t\t\t\tfollowedSymbol,\n\t\t\t\t\tisExternal: true,\n\t\t\t\t\tincludeNominalAnalysis: false,\n\t\t\t\t\taddIfMissing: true,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn astImport;\n\t}\n\n\tprivate _getModuleSpecifier(\n\t\timportOrExportDeclaration: ts.ExportDeclaration | ts.ImportDeclaration | ts.ImportTypeNode,\n\t): string {\n\t\t// The name of the module, which could be like \"./SomeLocalFile' or like 'external-package/entry/point'\n\t\tconst moduleSpecifier: string | undefined = TypeScriptHelpers.getModuleSpecifier(importOrExportDeclaration);\n\n\t\tif (!moduleSpecifier) {\n\t\t\tthrow new InternalError(\n\t\t\t\t'Unable to parse module specifier\\n' + SourceFileLocationFormatter.formatDeclaration(importOrExportDeclaration),\n\t\t\t);\n\t\t}\n\n\t\treturn moduleSpecifier;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/PackageMetadataManager.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n/* eslint-disable sonarjs/no-nested-switch */\nimport path from 'node:path';\nimport {\n\ttype PackageJsonLookup,\n\tFileSystem,\n\tJsonFile,\n\ttype NewlineKind,\n\ttype INodePackageJson,\n\ttype JsonObject,\n\ttype IPackageJsonExports,\n} from '@rushstack/node-core-library';\nimport semver from 'semver';\nimport { ConsoleMessageId } from '../api/ConsoleMessageId.js';\nimport { Extractor } from '../api/Extractor.js';\nimport type { MessageRouter } from '../collector/MessageRouter.js';\n\n/**\n * Represents analyzed information for a package.json file.\n * This object is constructed and returned by PackageMetadataManager.\n */\nexport class PackageMetadata {\n\t/**\n\t * The absolute path to the package.json file being analyzed.\n\t */\n\tpublic readonly packageJsonPath: string;\n\n\t/**\n\t * The parsed contents of package.json.  Note that PackageJsonLookup\n\t * only includes essential fields.\n\t */\n\tpublic readonly packageJson: INodePackageJson;\n\n\t/**\n\t * If true, then the package's documentation comments can be assumed\n\t * to contain API Extractor compatible TSDoc tags.\n\t */\n\tpublic readonly aedocSupported: boolean;\n\n\tpublic constructor(packageJsonPath: string, packageJson: INodePackageJson, aedocSupported: boolean) {\n\t\tthis.packageJsonPath = packageJsonPath;\n\t\tthis.packageJson = packageJson;\n\t\tthis.aedocSupported = aedocSupported;\n\t}\n}\n\nconst TSDOC_METADATA_FILENAME = 'tsdoc-metadata.json' as const;\n\n/**\n * 1. If package.json a `\"tsdocMetadata\": \"./path1/path2/tsdoc-metadata.json\"` field\n * then that takes precedence. This convention will be rarely needed, since the other rules below generally\n * produce a good result.\n */\nfunction _tryResolveTsdocMetadataFromTsdocMetadataField({ tsdocMetadata }: INodePackageJson): string | undefined {\n\treturn tsdocMetadata;\n}\n\n/**\n * 2. If package.json contains a `\"exports\": { \".\": { \"types\": \"./path1/path2/index.d.ts\" } }` field,\n * then we look for the file under \"./path1/path2/tsdoc-metadata.json\"\n *\n * This always looks for a \".\" and then a \"*\" entry in the exports field, and then evaluates for\n * a \"types\" field in that entry.\n */\n\nfunction _tryResolveTsdocMetadataFromExportsField({ exports }: INodePackageJson): string | undefined {\n\tswitch (typeof exports) {\n\t\tcase 'string': {\n\t\t\treturn `${path.dirname(exports)}/${TSDOC_METADATA_FILENAME}`;\n\t\t}\n\n\t\tcase 'object': {\n\t\t\tif (Array.isArray(exports)) {\n\t\t\t\tconst [firstExport] = exports;\n\t\t\t\t// Take the first entry in the array\n\t\t\t\tif (firstExport) {\n\t\t\t\t\treturn `${path.dirname(firstExport)}/${TSDOC_METADATA_FILENAME}`;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst rootExport: IPackageJsonExports | string | null | undefined = exports['.'] ?? exports['*'];\n\t\t\t\tswitch (typeof rootExport) {\n\t\t\t\t\tcase 'string': {\n\t\t\t\t\t\treturn `${path.dirname(rootExport)}/${TSDOC_METADATA_FILENAME}`;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 'object': {\n\t\t\t\t\t\tlet typesExport: IPackageJsonExports | string | undefined = rootExport?.types;\n\t\t\t\t\t\twhile (typesExport) {\n\t\t\t\t\t\t\tswitch (typeof typesExport) {\n\t\t\t\t\t\t\t\tcase 'string': {\n\t\t\t\t\t\t\t\t\treturn `${path.dirname(typesExport)}/${TSDOC_METADATA_FILENAME}`;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcase 'object': {\n\t\t\t\t\t\t\t\t\ttypesExport = typesExport?.types;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\n/**\n * 3. If package.json contains a `typesVersions` field, look for the version\n * matching the highest minimum version that either includes a \".\" or \"*\" entry.\n */\nfunction _tryResolveTsdocMetadataFromTypesVersionsField({ typesVersions }: INodePackageJson): string | undefined {\n\tif (typesVersions) {\n\t\tlet highestMinimumMatchingSemver: semver.SemVer | undefined;\n\t\tlet latestMatchingPath: string | undefined;\n\t\tfor (const [version, paths] of Object.entries(typesVersions)) {\n\t\t\tlet range: semver.Range;\n\t\t\ttry {\n\t\t\t\trange = new semver.Range(version);\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst minimumMatchingSemver: semver.SemVer | null = semver.minVersion(range);\n\t\t\tif (\n\t\t\t\tminimumMatchingSemver &&\n\t\t\t\t(!highestMinimumMatchingSemver || semver.gt(minimumMatchingSemver, highestMinimumMatchingSemver))\n\t\t\t) {\n\t\t\t\tconst pathEntry: string[] | undefined = paths['.'] ?? paths['*'];\n\t\t\t\tconst firstPath: string | undefined = pathEntry?.[0];\n\t\t\t\tif (firstPath) {\n\t\t\t\t\thighestMinimumMatchingSemver = minimumMatchingSemver;\n\t\t\t\t\tlatestMatchingPath = firstPath;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (latestMatchingPath) {\n\t\t\treturn `${path.dirname(latestMatchingPath)}/${TSDOC_METADATA_FILENAME}`;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\n/**\n * 4. If package.json contains a `\"types\": \"./path1/path2/index.d.ts\"` or a `\"typings\": \"./path1/path2/index.d.ts\"`\n * field, then we look for the file under \"./path1/path2/tsdoc-metadata.json\".\n *\n * @remarks\n * `types` takes precedence over `typings`.\n */\nfunction _tryResolveTsdocMetadataFromTypesOrTypingsFields({ typings, types }: INodePackageJson): string | undefined {\n\tconst typesField: string | undefined = types ?? typings;\n\tif (typesField) {\n\t\treturn `${path.dirname(typesField)}/${TSDOC_METADATA_FILENAME}`;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * 5. If package.json contains a `\"main\": \"./path1/path2/index.js\"` field, then we look for the file under\n * \"./path1/path2/tsdoc-metadata.json\".\n */\nfunction _tryResolveTsdocMetadataFromMainField({ main }: INodePackageJson): string | undefined {\n\tif (main) {\n\t\treturn `${path.dirname(main)}/${TSDOC_METADATA_FILENAME}`;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * This class maintains a cache of analyzed information obtained from package.json\n * files.  It is built on top of the PackageJsonLookup class.\n *\n * @remarks\n *\n * IMPORTANT: Don't use PackageMetadataManager to analyze source files from the current project:\n * 1. Files such as tsdoc-metadata.json may not have been built yet, and thus may contain incorrect information.\n * 2. The current project is not guaranteed to have a package.json file at all.  For example, API Extractor can\n *    be invoked on a bare .d.ts file.\n *\n * Use ts.program.isSourceFileFromExternalLibrary() to test source files before passing the to PackageMetadataManager.\n */\nexport class PackageMetadataManager {\n\tpublic static tsdocMetadataFilename: string = TSDOC_METADATA_FILENAME;\n\n\tprivate readonly _packageJsonLookup: PackageJsonLookup;\n\n\tprivate readonly _messageRouter: MessageRouter;\n\n\tprivate readonly _packageMetadataByPackageJsonPath: Map<string, PackageMetadata> = new Map<string, PackageMetadata>();\n\n\tpublic constructor(packageJsonLookup: PackageJsonLookup, messageRouter: MessageRouter) {\n\t\tthis._packageJsonLookup = packageJsonLookup;\n\t\tthis._messageRouter = messageRouter;\n\t}\n\n\t/**\n\t * This feature is still being standardized: https://github.com/microsoft/tsdoc/issues/7\n\t * In the future we will use the \\@microsoft/tsdoc library to read this file.\n\t */\n\tprivate static _resolveTsdocMetadataPathFromPackageJson(\n\t\tpackageFolder: string,\n\t\tpackageJson: INodePackageJson,\n\t): string {\n\t\tconst tsdocMetadataRelativePath: string =\n\t\t\t_tryResolveTsdocMetadataFromTsdocMetadataField(packageJson) ??\n\t\t\t_tryResolveTsdocMetadataFromExportsField(packageJson) ??\n\t\t\t_tryResolveTsdocMetadataFromTypesVersionsField(packageJson) ??\n\t\t\t_tryResolveTsdocMetadataFromTypesOrTypingsFields(packageJson) ??\n\t\t\t_tryResolveTsdocMetadataFromMainField(packageJson) ??\n\t\t\t// As a final fallback, place the file in the root of the package.\n\t\t\tTSDOC_METADATA_FILENAME;\n\n\t\t// Always resolve relative to the package folder.\n\t\tconst tsdocMetadataPath: string = path.resolve(\n\t\t\tpackageFolder,\n\t\t\t// This non-null assertion is safe because the last entry in TSDOC_METADATA_RESOLUTION_FUNCTIONS\n\t\t\t// returns a non-undefined value.\n\t\t\ttsdocMetadataRelativePath!,\n\t\t);\n\t\treturn tsdocMetadataPath;\n\t}\n\n\t/**\n\t * @param packageFolder - The package folder\n\t * @param packageJson - The package JSON\n\t * @param tsdocMetadataPath - An explicit path that can be configured in api-extractor.json.\n\t * If this parameter is not an empty string, it overrides the normal path calculation.\n\t * @returns the absolute path to the TSDoc metadata file\n\t */\n\tpublic static resolveTsdocMetadataPath(\n\t\tpackageFolder: string,\n\t\tpackageJson: INodePackageJson,\n\t\ttsdocMetadataPath?: string,\n\t): string {\n\t\tif (tsdocMetadataPath) {\n\t\t\treturn path.resolve(packageFolder, tsdocMetadataPath);\n\t\t}\n\n\t\treturn PackageMetadataManager._resolveTsdocMetadataPathFromPackageJson(packageFolder, packageJson);\n\t}\n\n\t/**\n\t * Writes the TSDoc metadata file to the specified output file.\n\t */\n\tpublic static writeTsdocMetadataFile(tsdocMetadataPath: string, newlineKind: NewlineKind): void {\n\t\tconst fileObject: JsonObject = {\n\t\t\ttsdocVersion: '0.12',\n\t\t\ttoolPackages: [\n\t\t\t\t{\n\t\t\t\t\tpackageName: '@discordjs/api-extractor',\n\t\t\t\t\tpackageVersion: Extractor.version,\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\n\t\tconst fileContent: string =\n\t\t\t'// This file is read by tools that parse documentation comments conforming to the TSDoc standard.\\n' +\n\t\t\t'// It should be published with your NPM package.  It should not be tracked by Git.\\n' +\n\t\t\tJsonFile.stringify(fileObject);\n\n\t\tFileSystem.writeFile(tsdocMetadataPath, fileContent, {\n\t\t\tconvertLineEndings: newlineKind,\n\t\t\tensureFolderExists: true,\n\t\t});\n\t}\n\n\t/**\n\t * Finds the package.json in a parent folder of the specified source file, and\n\t * returns a PackageMetadata object.  If no package.json was found, then undefined\n\t * is returned.  The results are cached.\n\t */\n\tpublic tryFetchPackageMetadata(sourceFilePath: string): PackageMetadata | undefined {\n\t\tconst packageJsonFilePath: string | undefined =\n\t\t\tthis._packageJsonLookup.tryGetPackageJsonFilePathFor(sourceFilePath);\n\t\tif (!packageJsonFilePath) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tlet packageMetadata: PackageMetadata | undefined = this._packageMetadataByPackageJsonPath.get(packageJsonFilePath);\n\n\t\tif (!packageMetadata) {\n\t\t\tconst packageJson: INodePackageJson = this._packageJsonLookup.loadNodePackageJson(packageJsonFilePath);\n\n\t\t\tconst packageJsonFolder: string = path.dirname(packageJsonFilePath);\n\n\t\t\tlet aedocSupported = false;\n\n\t\t\tconst tsdocMetadataPath: string = PackageMetadataManager._resolveTsdocMetadataPathFromPackageJson(\n\t\t\t\tpackageJsonFolder,\n\t\t\t\tpackageJson,\n\t\t\t);\n\n\t\t\tif (FileSystem.exists(tsdocMetadataPath)) {\n\t\t\t\tthis._messageRouter.logVerbose(ConsoleMessageId.FoundTSDocMetadata, 'Found metadata in ' + tsdocMetadataPath);\n\t\t\t\t// If the file exists at all, assume it was written by API Extractor\n\t\t\t\taedocSupported = true;\n\t\t\t}\n\n\t\t\tpackageMetadata = new PackageMetadata(packageJsonFilePath, packageJson, aedocSupported);\n\t\t\tthis._packageMetadataByPackageJsonPath.set(packageJsonFilePath, packageMetadata);\n\t\t}\n\n\t\treturn packageMetadata;\n\t}\n\n\t/**\n\t * Returns true if the source file is part of a package whose .d.ts files support AEDoc annotations.\n\t */\n\tpublic isAedocSupportedFor(sourceFilePath: string): boolean {\n\t\tconst packageMetadata: PackageMetadata | undefined = this.tryFetchPackageMetadata(sourceFilePath);\n\t\tif (!packageMetadata) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn packageMetadata.aedocSupported;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/SourceFileLocationFormatter.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as path from 'node:path';\nimport { Path, Text } from '@rushstack/node-core-library';\nimport type * as ts from 'typescript';\n\nexport interface ISourceFileLocationFormatOptions {\n\tsourceFileColumn?: number | undefined;\n\tsourceFileLine?: number | undefined;\n\tworkingPackageFolderPath?: string | undefined;\n}\n\nexport class SourceFileLocationFormatter {\n\t/**\n\t * Returns a string such as this, based on the context information in the provided node:\n\t *   \"[C:\\\\Folder\\\\File.ts#123]\"\n\t */\n\tpublic static formatDeclaration(node: ts.Node, workingPackageFolderPath?: string): string {\n\t\tconst sourceFile: ts.SourceFile = node.getSourceFile();\n\t\tconst lineAndCharacter: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n\n\t\treturn SourceFileLocationFormatter.formatPath(sourceFile.fileName, {\n\t\t\tsourceFileLine: lineAndCharacter.line + 1,\n\t\t\tsourceFileColumn: lineAndCharacter.character + 1,\n\t\t\tworkingPackageFolderPath,\n\t\t});\n\t}\n\n\tpublic static formatPath(sourceFilePath: string, options?: ISourceFileLocationFormatOptions): string {\n\t\tconst ioptions = options ?? {};\n\n\t\tlet result = '';\n\n\t\t// Make the path relative to the workingPackageFolderPath\n\t\tlet scrubbedPath: string = sourceFilePath;\n\n\t\tif (\n\t\t\tioptions.workingPackageFolderPath && // If it's under the working folder, make it a relative path\n\t\t\tPath.isUnderOrEqual(sourceFilePath, ioptions.workingPackageFolderPath)\n\t\t) {\n\t\t\tscrubbedPath = path.relative(ioptions.workingPackageFolderPath, sourceFilePath);\n\t\t}\n\n\t\t// Convert it to a Unix-style path\n\t\tscrubbedPath = Text.replaceAll(scrubbedPath, '\\\\', '/');\n\t\tresult += scrubbedPath;\n\n\t\tif (ioptions.sourceFileLine) {\n\t\t\tresult += `:${ioptions.sourceFileLine}`;\n\n\t\t\tif (ioptions.sourceFileColumn) {\n\t\t\t\tresult += `:${ioptions.sourceFileColumn}`;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/Span.ts",
    "content": "/* eslint-disable promise/prefer-await-to-callbacks */\n// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError, Sort, Text } from '@rushstack/node-core-library';\nimport * as ts from 'typescript';\nimport { IndentedWriter } from '../generators/IndentedWriter.js';\n\ninterface IWriteModifiedTextOptions {\n\tindentDocCommentState: IndentDocCommentState;\n\tseparatorOverride: string | undefined;\n\twriter: IndentedWriter;\n}\n\nenum IndentDocCommentState {\n\t/**\n\t * `indentDocComment` was not requested for this subtree.\n\t */\n\tInactive = 0,\n\t/**\n\t * `indentDocComment` was requested and we are looking for the opening `/` `*`\n\t */\n\tAwaitingOpenDelimiter = 1,\n\t/**\n\t * `indentDocComment` was requested and we are looking for the closing `*` `/`\n\t */\n\tAwaitingCloseDelimiter = 2,\n\t/**\n\t * `indentDocComment` was requested and we have finished indenting the comment.\n\t */\n\tDone = 3,\n}\n\n/**\n * Choices for SpanModification.indentDocComment.\n */\nexport enum IndentDocCommentScope {\n\t/**\n\t * Do not detect and indent comments.\n\t */\n\tNone = 0,\n\n\t/**\n\t * Look for one doc comment in the {@link Span.prefix} text only.\n\t */\n\tPrefixOnly = 1,\n\n\t/**\n\t * Look for one doc comment potentially distributed across the Span and its children.\n\t */\n\tSpanAndChildren = 2,\n}\n\n/**\n * Specifies various transformations that will be performed by Span.getModifiedText().\n */\nexport class SpanModification {\n\t/**\n\t * If true, all of the child spans will be omitted from the Span.getModifiedText() output.\n\t *\n\t * @remarks\n\t * Also, the modify() operation will not recurse into these spans.\n\t */\n\tpublic omitChildren: boolean = false;\n\n\t/**\n\t * If true, then the Span.separator will be removed from the Span.getModifiedText() output.\n\t */\n\tpublic omitSeparatorAfter: boolean = false;\n\n\t/**\n\t * If true, then Span.getModifiedText() will sort the immediate children according to their Span.sortKey\n\t * property.  The separators will also be fixed up to ensure correct indentation.  If the Span.sortKey is undefined\n\t * for some items, those items will not be moved, i.e. their array indexes will be unchanged.\n\t */\n\tpublic sortChildren: boolean = false;\n\n\t/**\n\t * Used if the parent span has Span.sortChildren=true.\n\t */\n\tpublic sortKey: string | undefined;\n\n\t/**\n\t * Optionally configures getModifiedText() to search for a \"/*\" doc comment and indent it.\n\t * At most one comment is detected.\n\t *\n\t * @remarks\n\t * The indentation can be applied to the `Span.modifier.prefix` only, or it can be applied to the\n\t * full subtree of nodes (as needed for `ts.SyntaxKind.JSDocComment` trees).  However the enabled\n\t * scopes must not overlap.\n\t *\n\t * This feature is enabled selectively because (1) we do not want to accidentally match `/*` appearing\n\t * in a string literal or other expression that is not a comment, and (2) parsing comments is relatively\n\t * expensive.\n\t */\n\tpublic indentDocComment: IndentDocCommentScope = IndentDocCommentScope.None;\n\n\tprivate readonly _span: Span;\n\n\tprivate _prefix: string | undefined;\n\n\tprivate _suffix: string | undefined;\n\n\tpublic constructor(span: Span) {\n\t\tthis._span = span;\n\t\tthis.reset();\n\t}\n\n\t/**\n\t * Allows the Span.prefix text to be changed.\n\t */\n\tpublic get prefix(): string {\n\t\treturn this._prefix ?? this._span.prefix;\n\t}\n\n\tpublic set prefix(value: string) {\n\t\tthis._prefix = value;\n\t}\n\n\t/**\n\t * Allows the Span.suffix text to be changed.\n\t */\n\tpublic get suffix(): string {\n\t\treturn this._suffix ?? this._span.suffix;\n\t}\n\n\tpublic set suffix(value: string) {\n\t\tthis._suffix = value;\n\t}\n\n\t/**\n\t * Reverts any modifications made to this object.\n\t */\n\tpublic reset(): void {\n\t\tthis.omitChildren = false;\n\t\tthis.omitSeparatorAfter = false;\n\t\tthis.sortChildren = false;\n\t\tthis.sortKey = undefined;\n\t\tthis._prefix = undefined;\n\t\tthis._suffix = undefined;\n\t\tif (this._span.kind === ts.SyntaxKind.JSDocComment) {\n\t\t\tthis.indentDocComment = IndentDocCommentScope.SpanAndChildren;\n\t\t}\n\t}\n\n\t/**\n\t * Effectively deletes the Span from the tree, by skipping its children, skipping its separator,\n\t * and setting its prefix/suffix to the empty string.\n\t */\n\tpublic skipAll(): void {\n\t\tthis.prefix = '';\n\t\tthis.suffix = '';\n\t\tthis.omitChildren = true;\n\t\tthis.omitSeparatorAfter = true;\n\t}\n}\n\n/**\n * The Span class provides a simple way to rewrite TypeScript source files\n * based on simple syntax transformations, i.e. without having to process deeper aspects\n * of the underlying grammar.  An example transformation might be deleting JSDoc comments\n * from a source file.\n *\n * @remarks\n * TypeScript's abstract syntax tree (AST) is represented using Node objects.\n * The Node text ignores its surrounding whitespace, and does not have an ordering guarantee.\n * For example, a JSDocComment node can be a child of a FunctionDeclaration node, even though\n * the actual comment precedes the function in the input stream.\n *\n * The Span class is a wrapper for a single Node, that provides access to every character\n * in the input stream, such that Span.getText() will exactly reproduce the corresponding\n * full Node.getText() output.\n *\n * A Span is comprised of these parts, which appear in sequential order:\n * - A prefix\n * - A collection of child spans\n * - A suffix\n * - A separator (e.g. whitespace between this span and the next item in the tree)\n *\n * These parts can be modified via Span.modification.  The modification is applied by\n * calling Span.getModifiedText().\n */\nexport class Span {\n\tpublic readonly node: ts.Node;\n\n\t// To improve performance, substrings are not allocated until actually needed\n\tpublic readonly startIndex: number;\n\n\tpublic readonly endIndex: number;\n\n\tpublic readonly children: Span[];\n\n\tpublic readonly modification: SpanModification;\n\n\tprivate readonly _parent: Span | undefined;\n\n\tprivate readonly _previousSibling: Span | undefined;\n\n\tprivate readonly _nextSibling: Span | undefined;\n\n\tprivate readonly _separatorStartIndex: number;\n\n\tprivate readonly _separatorEndIndex: number;\n\n\tpublic constructor(node: ts.Node) {\n\t\tthis.node = node;\n\t\tthis.startIndex = node.kind === ts.SyntaxKind.SourceFile ? node.getFullStart() : node.getStart();\n\t\tthis.endIndex = node.end;\n\t\tthis._separatorStartIndex = 0;\n\t\tthis._separatorEndIndex = 0;\n\t\tthis.children = [];\n\t\tthis.modification = new SpanModification(this);\n\n\t\tlet previousChildSpan: Span | undefined;\n\n\t\tfor (const childNode of this.node.getChildren() || []) {\n\t\t\tconst childSpan: Span = new Span(childNode);\n\t\t\t// @ts-expect-error assigning private readonly properties on creation only\n\t\t\tchildSpan._parent = this;\n\t\t\t// @ts-expect-error assigning private readonly properties on creation only\n\t\t\tchildSpan._previousSibling = previousChildSpan;\n\n\t\t\tif (previousChildSpan) {\n\t\t\t\t// @ts-expect-error assigning private readonly properties on creation only\n\t\t\t\tpreviousChildSpan._nextSibling = childSpan;\n\t\t\t}\n\n\t\t\tthis.children.push(childSpan);\n\n\t\t\t// Normalize the bounds so that a child is never outside its parent\n\t\t\tif (childSpan.startIndex < this.startIndex) {\n\t\t\t\tthis.startIndex = childSpan.startIndex;\n\t\t\t}\n\n\t\t\tif (childSpan.endIndex > this.endIndex) {\n\t\t\t\t// This has never been observed empirically, but here's how we would handle it\n\t\t\t\tthis.endIndex = childSpan.endIndex;\n\t\t\t\tthrow new InternalError('Unexpected AST case');\n\t\t\t}\n\n\t\t\tif (previousChildSpan && previousChildSpan.endIndex < childSpan.startIndex) {\n\t\t\t\t// There is some leftover text after previous child -- assign it as the separator for\n\t\t\t\t// the preceding span.  If the preceding span has no suffix, then assign it to the\n\t\t\t\t// deepest preceding span with no suffix.  This heuristic simplifies the most\n\t\t\t\t// common transformations, and otherwise it can be fished out using getLastInnerSeparator().\n\t\t\t\tlet separatorRecipient: Span = previousChildSpan;\n\t\t\t\twhile (separatorRecipient.children.length > 0) {\n\t\t\t\t\tconst lastChild: Span = separatorRecipient.children[separatorRecipient.children.length - 1]!;\n\t\t\t\t\tif (lastChild.endIndex !== separatorRecipient.endIndex) {\n\t\t\t\t\t\t// There is a suffix, so we cannot push the separator any further down, or else\n\t\t\t\t\t\t// it would get printed before this suffix.\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tseparatorRecipient = lastChild;\n\t\t\t\t}\n\n\t\t\t\t// @ts-expect-error assigning private readonly properties on creation only\n\t\t\t\tseparatorRecipient._separatorStartIndex = previousChildSpan.endIndex;\n\t\t\t\t// @ts-expect-error assigning private readonly properties on creation only\n\t\t\t\tseparatorRecipient._separatorEndIndex = childSpan.startIndex;\n\t\t\t}\n\n\t\t\tpreviousChildSpan = childSpan;\n\t\t}\n\t}\n\n\tpublic get kind(): ts.SyntaxKind {\n\t\treturn this.node.kind;\n\t}\n\n\t/**\n\t * The parent Span, if any.\n\t * NOTE: This will be undefined for a root Span, even though the corresponding Node\n\t * may have a parent in the AST.\n\t */\n\tpublic get parent(): Span | undefined {\n\t\treturn this._parent;\n\t}\n\n\t/**\n\t * If the current object is this.parent.children[i], then previousSibling corresponds\n\t * to this.parent.children[i-1] if it exists.\n\t * NOTE: This will be undefined for a root Span, even though the corresponding Node\n\t * may have a previous sibling in the AST.\n\t */\n\tpublic get previousSibling(): Span | undefined {\n\t\treturn this._previousSibling;\n\t}\n\n\t/**\n\t * If the current object is this.parent.children[i], then previousSibling corresponds\n\t * to this.parent.children[i+1] if it exists.\n\t * NOTE: This will be undefined for a root Span, even though the corresponding Node\n\t * may have a previous sibling in the AST.\n\t */\n\tpublic get nextSibling(): Span | undefined {\n\t\treturn this._nextSibling;\n\t}\n\n\t/**\n\t * The text associated with the underlying Node, up to its first child.\n\t */\n\tpublic get prefix(): string {\n\t\tif (this.children.length) {\n\t\t\t// Everything up to the first child\n\t\t\treturn this._getSubstring(this.startIndex, this.children[0]!.startIndex);\n\t\t} else {\n\t\t\treturn this._getSubstring(this.startIndex, this.endIndex);\n\t\t}\n\t}\n\n\t/**\n\t * The text associated with the underlying Node, after its last child.\n\t * If there are no children, this is always an empty string.\n\t */\n\tpublic get suffix(): string {\n\t\tif (this.children.length) {\n\t\t\t// Everything after the last child\n\t\t\treturn this._getSubstring(this.children[this.children.length - 1]!.endIndex, this.endIndex);\n\t\t} else {\n\t\t\treturn '';\n\t\t}\n\t}\n\n\t/**\n\t * Whitespace that appeared after this node, and before the \"next\" node in the tree.\n\t * Here we mean \"next\" according to an inorder traversal, not necessarily a sibling.\n\t */\n\tpublic get separator(): string {\n\t\treturn this._getSubstring(this._separatorStartIndex, this._separatorEndIndex);\n\t}\n\n\t/**\n\t * Returns the separator of this Span, or else recursively calls getLastInnerSeparator()\n\t * on the last child.\n\t */\n\tpublic getLastInnerSeparator(): string {\n\t\tif (this.separator) {\n\t\t\treturn this.separator;\n\t\t}\n\n\t\tif (this.children.length > 0) {\n\t\t\treturn this.children[this.children.length - 1]!.getLastInnerSeparator();\n\t\t}\n\n\t\treturn '';\n\t}\n\n\t/**\n\t * Returns the first parent node with the specified  SyntaxKind, or undefined if there is no match.\n\t */\n\tpublic findFirstParent(kindToMatch: ts.SyntaxKind): Span | undefined {\n\t\tlet current: Span | undefined = this;\n\n\t\twhile (current) {\n\t\t\tif (current.kind === kindToMatch) {\n\t\t\t\treturn current;\n\t\t\t}\n\n\t\t\tcurrent = current.parent;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Recursively invokes the callback on this Span and all its children.  The callback\n\t * can make changes to Span.modification for each node.\n\t */\n\tpublic forEach(callback: (span: Span) => void): void {\n\t\t// eslint-disable-next-line n/callback-return\n\t\tcallback(this);\n\t\tfor (const child of this.children) {\n\t\t\t// eslint-disable-next-line unicorn/no-array-for-each\n\t\t\tchild.forEach(callback);\n\t\t}\n\t}\n\n\t/**\n\t * Returns the original unmodified text represented by this Span.\n\t */\n\tpublic getText(): string {\n\t\tlet result = '';\n\t\tresult += this.prefix;\n\n\t\tfor (const child of this.children) {\n\t\t\tresult += child.getText();\n\t\t}\n\n\t\tresult += this.suffix;\n\t\tresult += this.separator;\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the text represented by this Span, after applying all requested modifications.\n\t */\n\tpublic getModifiedText(): string {\n\t\tconst writer: IndentedWriter = new IndentedWriter();\n\t\twriter.trimLeadingSpaces = true;\n\n\t\tthis._writeModifiedText({\n\t\t\twriter,\n\t\t\tseparatorOverride: undefined,\n\t\t\tindentDocCommentState: IndentDocCommentState.Inactive,\n\t\t});\n\n\t\treturn writer.getText();\n\t}\n\n\tpublic writeModifiedText(output: IndentedWriter): void {\n\t\tthis._writeModifiedText({\n\t\t\twriter: output,\n\t\t\tseparatorOverride: undefined,\n\t\t\tindentDocCommentState: IndentDocCommentState.Inactive,\n\t\t});\n\t}\n\n\t/**\n\t * Returns a diagnostic dump of the tree, showing the prefix/suffix/separator for\n\t * each node.\n\t */\n\tpublic getDump(indent: string = ''): string {\n\t\tlet result: string = indent + ts.SyntaxKind[this.node.kind] + ': ';\n\n\t\tif (this.prefix) {\n\t\t\tresult += ' pre=[' + this._getTrimmed(this.prefix) + ']';\n\t\t}\n\n\t\tif (this.suffix) {\n\t\t\tresult += ' suf=[' + this._getTrimmed(this.suffix) + ']';\n\t\t}\n\n\t\tif (this.separator) {\n\t\t\tresult += ' sep=[' + this._getTrimmed(this.separator) + ']';\n\t\t}\n\n\t\tresult += '\\n';\n\n\t\tfor (const child of this.children) {\n\t\t\tresult += child.getDump(indent + '  ');\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns a diagnostic dump of the tree, showing the SpanModification settings for each nodde.\n\t */\n\tpublic getModifiedDump(indent: string = ''): string {\n\t\tlet result: string = indent + ts.SyntaxKind[this.node.kind] + ': ';\n\n\t\tif (this.prefix) {\n\t\t\tresult += ' pre=[' + this._getTrimmed(this.modification.prefix) + ']';\n\t\t}\n\n\t\tif (this.suffix) {\n\t\t\tresult += ' suf=[' + this._getTrimmed(this.modification.suffix) + ']';\n\t\t}\n\n\t\tif (this.separator) {\n\t\t\tresult += ' sep=[' + this._getTrimmed(this.separator) + ']';\n\t\t}\n\n\t\tif (this.modification.indentDocComment !== IndentDocCommentScope.None) {\n\t\t\tresult += ' indentDocComment=' + IndentDocCommentScope[this.modification.indentDocComment];\n\t\t}\n\n\t\tif (this.modification.omitChildren) {\n\t\t\tresult += ' omitChildren';\n\t\t}\n\n\t\tif (this.modification.omitSeparatorAfter) {\n\t\t\tresult += ' omitSeparatorAfter';\n\t\t}\n\n\t\tif (this.modification.sortChildren) {\n\t\t\tresult += ' sortChildren';\n\t\t}\n\n\t\tif (this.modification.sortKey !== undefined) {\n\t\t\tresult += ` sortKey=\"${this.modification.sortKey}\"`;\n\t\t}\n\n\t\tresult += '\\n';\n\n\t\tif (this.modification.omitChildren) {\n\t\t\tresult += `${indent}  (${this.children.length} children)\\n`;\n\t\t} else {\n\t\t\tfor (const child of this.children) {\n\t\t\t\tresult += child.getModifiedDump(indent + '  ');\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Recursive implementation of `getModifiedText()` and `writeModifiedText()`.\n\t */\n\tprivate _writeModifiedText(options: IWriteModifiedTextOptions): void {\n\t\t// Apply indentation based on \"{\" and \"}\"\n\t\tif (this.prefix === '{') {\n\t\t\toptions.writer.increaseIndent();\n\t\t} else if (this.prefix === '}') {\n\t\t\toptions.writer.decreaseIndent();\n\t\t}\n\n\t\tif (this.modification.indentDocComment !== IndentDocCommentScope.None) {\n\t\t\tthis._beginIndentDocComment(options);\n\t\t}\n\n\t\tthis._write(this.modification.prefix, options);\n\n\t\tif (this.modification.indentDocComment === IndentDocCommentScope.PrefixOnly) {\n\t\t\tthis._endIndentDocComment(options);\n\t\t}\n\n\t\tlet sortedSubset: Span[] | undefined;\n\n\t\tif (!this.modification.omitChildren && this.modification.sortChildren) {\n\t\t\t// We will only sort the items with a sortKey\n\t\t\tconst filtered: Span[] = this.children.filter((x) => x.modification.sortKey !== undefined);\n\n\t\t\t// Is there at least one of them?\n\t\t\tif (filtered.length > 1) {\n\t\t\t\tsortedSubset = filtered;\n\t\t\t}\n\t\t}\n\n\t\tif (sortedSubset) {\n\t\t\t// This is the complicated special case that sorts an arbitrary subset of the child nodes,\n\t\t\t// preserving the surrounding nodes.\n\n\t\t\tconst sortedSubsetCount: number = sortedSubset.length;\n\t\t\t// Remember the separator for the first and last ones\n\t\t\tconst firstSeparator: string = sortedSubset[0]!.getLastInnerSeparator();\n\t\t\tconst lastSeparator: string = sortedSubset[sortedSubsetCount - 1]!.getLastInnerSeparator();\n\n\t\t\tSort.sortBy(sortedSubset, (x) => x.modification.sortKey);\n\n\t\t\tconst childOptions: IWriteModifiedTextOptions = { ...options };\n\n\t\t\tlet sortedSubsetIndex = 0;\n\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-for-of\n\t\t\tfor (let index = 0; index < this.children.length; ++index) {\n\t\t\t\tlet current: Span;\n\n\t\t\t\t// Is this an item that we sorted?\n\t\t\t\tif (this.children[index]!.modification.sortKey === undefined) {\n\t\t\t\t\t// No, take the next item from the original array\n\t\t\t\t\tcurrent = this.children[index]!;\n\t\t\t\t\tchildOptions.separatorOverride = undefined;\n\t\t\t\t} else {\n\t\t\t\t\t// Yes, take the next item from the sortedSubset\n\t\t\t\t\tcurrent = sortedSubset[sortedSubsetIndex++]!;\n\n\t\t\t\t\tif (sortedSubsetIndex < sortedSubsetCount) {\n\t\t\t\t\t\tchildOptions.separatorOverride = firstSeparator;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tchildOptions.separatorOverride = lastSeparator;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcurrent._writeModifiedText(childOptions);\n\t\t\t}\n\t\t} else {\n\t\t\t// This is the normal case that does not need to sort children\n\t\t\tconst childrenLength: number = this.children.length;\n\n\t\t\tif (!this.modification.omitChildren) {\n\t\t\t\tif (options.separatorOverride === undefined) {\n\t\t\t\t\t// The normal simple case\n\t\t\t\t\tfor (const child of this.children) {\n\t\t\t\t\t\tchild._writeModifiedText(options);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Special case where the separatorOverride is passed down to the \"last inner separator\" span\n\t\t\t\t\tfor (let index = 0; index < childrenLength; ++index) {\n\t\t\t\t\t\tconst child: Span = this.children[index]!;\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t// Only the last child inherits the separatorOverride, because only it can contain\n\t\t\t\t\t\t\t// the \"last inner separator\" span\n\t\t\t\t\t\t\tindex < childrenLength - 1 ||\n\t\t\t\t\t\t\t// If this.separator is specified, then we will write separatorOverride below, so don't pass it along\n\t\t\t\t\t\t\tthis.separator\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tconst childOptions: IWriteModifiedTextOptions = { ...options };\n\t\t\t\t\t\t\tchildOptions.separatorOverride = undefined;\n\t\t\t\t\t\t\tchild._writeModifiedText(childOptions);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tchild._writeModifiedText(options);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._write(this.modification.suffix, options);\n\n\t\t\tif (options.separatorOverride !== undefined) {\n\t\t\t\tif (this.separator || childrenLength === 0) {\n\t\t\t\t\tthis._write(options.separatorOverride, options);\n\t\t\t\t}\n\t\t\t} else if (!this.modification.omitSeparatorAfter) {\n\t\t\t\tthis._write(this.separator, options);\n\t\t\t}\n\t\t}\n\n\t\tif (this.modification.indentDocComment === IndentDocCommentScope.SpanAndChildren) {\n\t\t\tthis._endIndentDocComment(options);\n\t\t}\n\t}\n\n\tprivate _beginIndentDocComment(options: IWriteModifiedTextOptions): void {\n\t\tif (options.indentDocCommentState !== IndentDocCommentState.Inactive) {\n\t\t\tthrow new InternalError('indentDocComment cannot be nested');\n\t\t}\n\n\t\toptions.indentDocCommentState = IndentDocCommentState.AwaitingOpenDelimiter;\n\t}\n\n\tprivate _endIndentDocComment(options: IWriteModifiedTextOptions): void {\n\t\tif (options.indentDocCommentState === IndentDocCommentState.AwaitingCloseDelimiter) {\n\t\t\tthrow new InternalError('missing \"*/\" delimiter for comment block');\n\t\t}\n\n\t\toptions.indentDocCommentState = IndentDocCommentState.Inactive;\n\t}\n\n\t/**\n\t * Writes one chunk of `text` to the `options.writer`, applying the `indentDocComment` rewriting.\n\t */\n\tprivate _write(text: string, options: IWriteModifiedTextOptions): void {\n\t\tlet parsedText: string = text;\n\n\t\tif (options.indentDocCommentState === IndentDocCommentState.AwaitingOpenDelimiter) {\n\t\t\tlet index: number = parsedText.indexOf('/*');\n\t\t\tif (index >= 0) {\n\t\t\t\tindex += '/*'.length;\n\t\t\t\toptions.writer.write(parsedText.slice(0, Math.max(0, index)));\n\t\t\t\tparsedText = parsedText.slice(Math.max(0, index));\n\t\t\t\toptions.indentDocCommentState = IndentDocCommentState.AwaitingCloseDelimiter;\n\n\t\t\t\toptions.writer.increaseIndent(' ');\n\t\t\t}\n\t\t}\n\n\t\tif (options.indentDocCommentState === IndentDocCommentState.AwaitingCloseDelimiter) {\n\t\t\tlet index: number = parsedText.indexOf('*/');\n\t\t\tif (index >= 0) {\n\t\t\t\tindex += '*/'.length;\n\t\t\t\toptions.writer.write(parsedText.slice(0, Math.max(0, index)));\n\t\t\t\tparsedText = parsedText.slice(Math.max(0, index));\n\t\t\t\toptions.indentDocCommentState = IndentDocCommentState.Done;\n\n\t\t\t\toptions.writer.decreaseIndent();\n\t\t\t}\n\t\t}\n\n\t\toptions.writer.write(parsedText);\n\t}\n\n\tprivate _getTrimmed(text: string): string {\n\t\treturn Text.truncateWithEllipsis(Text.convertToLf(text), 100);\n\t}\n\n\tprivate _getSubstring(startIndex: number, endIndex: number): string {\n\t\tif (startIndex === endIndex) {\n\t\t\treturn '';\n\t\t}\n\n\t\treturn this.node.getSourceFile().text.slice(startIndex, endIndex);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/SyntaxHelpers.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as ts from 'typescript';\n\n/**\n * Helpers for validating various text string formats.\n */\nexport class SyntaxHelpers {\n\t/**\n\t * Tests whether the input string is safe to use as an ECMAScript identifier without quotes.\n\t *\n\t * @remarks\n\t * For example:\n\t *\n\t * ```ts\n\t * class X {\n\t *   public okay: number = 1;\n\t *   public \"not okay!\": number = 2;\n\t * }\n\t * ```\n\t *\n\t * A precise check is extremely complicated and highly dependent on the ECMAScript standard version\n\t * and how faithfully the interpreter implements it.  To keep things simple, `isSafeUnquotedMemberIdentifier()`\n\t * conservatively accepts any identifier that would be valid with ECMAScript 5, and returns false otherwise.\n\t */\n\tpublic static isSafeUnquotedMemberIdentifier(identifier: string): boolean {\n\t\tif (identifier.length === 0) {\n\t\t\treturn false; // cannot be empty\n\t\t}\n\n\t\tif (!ts.isIdentifierStart(identifier.codePointAt(0)!, ts.ScriptTarget.ES5)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let index = 1; index < identifier.length; index++) {\n\t\t\tif (!ts.isIdentifierPart(identifier.codePointAt(index)!, ts.ScriptTarget.ES5)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Given an arbitrary input string, return a regular TypeScript identifier name.\n\t *\n\t * @remarks\n\t * Example input:  \"api-extractor-lib1-test\"\n\t * Example output: \"apiExtractorLib1Test\"\n\t */\n\tpublic static makeCamelCaseIdentifier(input: string): string {\n\t\tconst parts: string[] = input.split(/\\W+/).filter((x) => x.length > 0);\n\t\tif (parts.length === 0) {\n\t\t\treturn '_';\n\t\t}\n\n\t\tfor (let index = 0; index < parts.length; ++index) {\n\t\t\tlet part: string = parts[index]!;\n\t\t\tif (part.toUpperCase() === part) {\n\t\t\t\t// Preserve existing case unless the part is all upper-case\n\t\t\t\tpart = part.toLowerCase();\n\t\t\t}\n\n\t\t\tif (index === 0) {\n\t\t\t\t// If the first part starts with a number, prepend \"_\"\n\t\t\t\tif (/\\d/.test(part.charAt(0))) {\n\t\t\t\t\tpart = '_' + part;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Capitalize the first letter of each part, except for the first one\n\t\t\t\tpart = part.charAt(0).toUpperCase() + part.slice(1);\n\t\t\t}\n\n\t\t\tparts[index] = part;\n\t\t}\n\n\t\treturn parts.join('');\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/TypeScriptHelpers.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError } from '@rushstack/node-core-library';\nimport * as ts from 'typescript';\nimport { SourceFileLocationFormatter } from './SourceFileLocationFormatter.js';\nimport { TypeScriptInternals } from './TypeScriptInternals.js';\n\nexport class TypeScriptHelpers {\n\t// Matches TypeScript's encoded names for well-known ECMAScript symbols like\n\t// \"__@iterator\" or \"__@toStringTag\".\n\tprivate static readonly _wellKnownSymbolNameRegExp: RegExp = /^__@(?<identifier>\\w+)$/;\n\n\t// Matches TypeScript's encoded names for late-bound symbols derived from `unique symbol` declarations\n\t// which have the form of \"__@<variableName>@<symbolId>\", i.e. \"__@someSymbol@12345\".\n\tprivate static readonly _uniqueSymbolNameRegExp: RegExp = /^__@.*@\\d+$/;\n\n\t/**\n\t * This traverses any symbol aliases to find the original place where an item was defined.\n\t * For example, suppose a class is defined as \"export default class MyClass \\{ \\}\"\n\t * but exported from the package's index.ts like this:\n\t *\n\t *    export \\{ default as _MyClass \\} from './MyClass';\n\t *\n\t * In this example, calling followAliases() on the _MyClass symbol will return the\n\t * original definition of MyClass, traversing any intermediary places where the\n\t * symbol was imported and re-exported.\n\t */\n\tpublic static followAliases(symbol: ts.Symbol, typeChecker: ts.TypeChecker): ts.Symbol {\n\t\tlet current: ts.Symbol = symbol;\n\t\tfor (;;) {\n\t\t\tif (!(current.flags & ts.SymbolFlags.Alias)) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst currentAlias: ts.Symbol = typeChecker.getAliasedSymbol(current);\n\t\t\tif (!currentAlias || currentAlias === current) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcurrent = currentAlias;\n\t\t}\n\n\t\treturn current;\n\t}\n\n\t/**\n\t * Returns true if TypeScriptHelpers.followAliases() would return something different\n\t * from the input `symbol`.\n\t */\n\tpublic static isFollowableAlias(symbol: ts.Symbol, typeChecker: ts.TypeChecker): boolean {\n\t\tif (!(symbol.flags & ts.SymbolFlags.Alias)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst alias: ts.Symbol = typeChecker.getAliasedSymbol(symbol);\n\n\t\treturn alias && alias !== symbol;\n\t}\n\n\t/**\n\t * Certain virtual symbols do not have any declarations.  For example, `ts.TypeChecker.getExportsOfModule()` can\n\t * sometimes return a \"prototype\" symbol for an object, even though there is no corresponding declaration in the\n\t * source code.  API Extractor generally ignores such symbols.\n\t */\n\tpublic static tryGetADeclaration(symbol: ts.Symbol): ts.Declaration | undefined {\n\t\tif (symbol.declarations && symbol.declarations.length > 0) {\n\t\t\treturn symbol.declarations[0];\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Returns true if the specified symbol is an ambient declaration.\n\t */\n\tpublic static isAmbient(symbol: ts.Symbol, typeChecker: ts.TypeChecker): boolean {\n\t\tconst followedSymbol: ts.Symbol = TypeScriptHelpers.followAliases(symbol, typeChecker);\n\n\t\tif (followedSymbol.declarations && followedSymbol.declarations.length > 0) {\n\t\t\tconst firstDeclaration: ts.Declaration = followedSymbol.declarations[0]!;\n\n\t\t\t// Test 1: Are we inside the sinister \"declare global {\" construct?\n\t\t\tconst highestModuleDeclaration: ts.ModuleDeclaration | undefined = TypeScriptHelpers.findHighestParent(\n\t\t\t\tfirstDeclaration,\n\t\t\t\tts.SyntaxKind.ModuleDeclaration,\n\t\t\t);\n\t\t\tif (highestModuleDeclaration?.name.getText().trim() === 'global') {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// Test 2: Otherwise, the main heuristic for ambient declarations is by looking at the\n\t\t\t// ts.SyntaxKind.SourceFile node to see whether it has a symbol or not (i.e. whether it\n\t\t\t// is acting as a module or not).\n\t\t\tconst sourceFile: ts.SourceFile = firstDeclaration.getSourceFile();\n\n\t\t\tif (typeChecker.getSymbolAtLocation(sourceFile)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Same semantics as tryGetSymbolForDeclaration(), but throws an exception if the symbol\n\t * cannot be found.\n\t */\n\tpublic static getSymbolForDeclaration(declaration: ts.Declaration, checker: ts.TypeChecker): ts.Symbol {\n\t\tconst symbol: ts.Symbol | undefined = TypeScriptInternals.tryGetSymbolForDeclaration(declaration, checker);\n\t\tif (!symbol) {\n\t\t\tthrow new InternalError(\n\t\t\t\t'Unable to determine semantic information for declaration:\\n' +\n\t\t\t\t\tSourceFileLocationFormatter.formatDeclaration(declaration),\n\t\t\t);\n\t\t}\n\n\t\treturn symbol;\n\t}\n\n\t// Return name of the module, which could be like \"./SomeLocalFile' or like 'external-package/entry/point'\n\tpublic static getModuleSpecifier(\n\t\tnodeWithModuleSpecifier: ts.ExportDeclaration | ts.ImportDeclaration | ts.ImportTypeNode,\n\t): string | undefined {\n\t\tif (nodeWithModuleSpecifier.kind === ts.SyntaxKind.ImportType) {\n\t\t\t// As specified internally in typescript:/src/compiler/types.ts#ValidImportTypeNode\n\t\t\tif (\n\t\t\t\tnodeWithModuleSpecifier.argument.kind !== ts.SyntaxKind.LiteralType ||\n\t\t\t\t(nodeWithModuleSpecifier.argument as ts.LiteralTypeNode).literal.kind !== ts.SyntaxKind.StringLiteral\n\t\t\t) {\n\t\t\t\tthrow new InternalError(\n\t\t\t\t\t`Invalid ImportTypeNode: ${nodeWithModuleSpecifier.getText()}\\n` +\n\t\t\t\t\t\tSourceFileLocationFormatter.formatDeclaration(nodeWithModuleSpecifier),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst literalTypeNode: ts.LiteralTypeNode = nodeWithModuleSpecifier.argument as ts.LiteralTypeNode;\n\t\t\tconst stringLiteral: ts.StringLiteral = literalTypeNode.literal as ts.StringLiteral;\n\t\t\treturn stringLiteral.text.trim();\n\t\t}\n\n\t\t// Node is a declaration\n\t\tif (nodeWithModuleSpecifier.moduleSpecifier && ts.isStringLiteralLike(nodeWithModuleSpecifier.moduleSpecifier)) {\n\t\t\treturn TypeScriptInternals.getTextOfIdentifierOrLiteral(nodeWithModuleSpecifier.moduleSpecifier);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Returns an ancestor of \"node\", such that the ancestor, any intermediary nodes,\n\t * and the starting node match a list of expected kinds.  Undefined is returned\n\t * if there aren't enough ancestors, or if the kinds are incorrect.\n\t *\n\t * For example, suppose child \"C\" has parents A --\\> B --\\> C.\n\t *\n\t * Calling _matchAncestor(C, [ExportSpecifier, NamedExports, ExportDeclaration])\n\t * would return A only if A is of kind ExportSpecifier, B is of kind NamedExports,\n\t * and C is of kind ExportDeclaration.\n\t *\n\t * Calling _matchAncestor(C, [ExportDeclaration]) would return C.\n\t */\n\tpublic static matchAncestor<T extends ts.Node>(node: ts.Node, kindsToMatch: ts.SyntaxKind[]): T | undefined {\n\t\t// (slice(0) clones an array)\n\t\tconst reversedParentKinds: ts.SyntaxKind[] = kindsToMatch.slice(0).reverse();\n\n\t\tlet current: ts.Node | undefined;\n\n\t\tfor (const parentKind of reversedParentKinds) {\n\t\t\tif (current) {\n\t\t\t\t// Then walk the parents\n\t\t\t\tcurrent = current.parent;\n\t\t\t} else {\n\t\t\t\t// The first time through, start with node\n\t\t\t\tcurrent = node;\n\t\t\t}\n\n\t\t\t// If we ran out of items, or if the kind doesn't match, then fail\n\t\t\tif (current?.kind !== parentKind) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\n\t\t// If we matched everything, then return the node that matched the last parentKinds item\n\t\treturn current as T;\n\t}\n\n\t/**\n\t * Does a depth-first search of the children of the specified node.  Returns the first child\n\t * with the specified kind, or undefined if there is no match.\n\t */\n\tpublic static findFirstChildNode<T extends ts.Node>(node: ts.Node, kindToMatch: ts.SyntaxKind): T | undefined {\n\t\tfor (const child of node.getChildren()) {\n\t\t\tif (child.kind === kindToMatch) {\n\t\t\t\treturn child as T;\n\t\t\t}\n\n\t\t\tconst recursiveMatch: T | undefined = TypeScriptHelpers.findFirstChildNode(child, kindToMatch);\n\t\t\tif (recursiveMatch) {\n\t\t\t\treturn recursiveMatch;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Returns the first parent node with the specified  SyntaxKind, or undefined if there is no match.\n\t */\n\tpublic static findFirstParent<T extends ts.Node>(node: ts.Node, kindToMatch: ts.SyntaxKind): T | undefined {\n\t\tlet current: ts.Node | undefined = node.parent;\n\n\t\twhile (current) {\n\t\t\tif (current.kind === kindToMatch) {\n\t\t\t\treturn current as T;\n\t\t\t}\n\n\t\t\tcurrent = current.parent;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Returns the highest parent node with the specified SyntaxKind, or undefined if there is no match.\n\t *\n\t * @remarks\n\t * Whereas findFirstParent() returns the first match, findHighestParent() returns the last match.\n\t */\n\tpublic static findHighestParent<T extends ts.Node>(node: ts.Node, kindToMatch: ts.SyntaxKind): T | undefined {\n\t\tlet current: ts.Node | undefined = node;\n\t\tlet highest: T | undefined;\n\n\t\tfor (;;) {\n\t\t\tcurrent = TypeScriptHelpers.findFirstParent<T>(current, kindToMatch);\n\t\t\tif (!current) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\thighest = current as T;\n\t\t}\n\n\t\treturn highest;\n\t}\n\n\t/**\n\t * Decodes the names that the compiler generates for a built-in ECMAScript symbol.\n\t *\n\t * @remarks\n\t * TypeScript binds well-known ECMAScript symbols like `[Symbol.iterator]` as `__@iterator`.\n\t * If `name` is of this form, then `tryGetWellKnownSymbolName()` converts it back into e.g. `[Symbol.iterator]`.\n\t * If the string does not start with `__@` then `undefined` is returned.\n\t */\n\tpublic static tryDecodeWellKnownSymbolName(name: ts.__String): string | undefined {\n\t\tconst match = TypeScriptHelpers._wellKnownSymbolNameRegExp.exec(name as string);\n\t\tif (match?.groups?.identifier) {\n\t\t\tconst identifier: string = match.groups.identifier;\n\t\t\treturn `[Symbol.${identifier}]`;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Returns whether the provided name was generated for a TypeScript `unique symbol`.\n\t */\n\tpublic static isUniqueSymbolName(name: ts.__String): boolean {\n\t\treturn TypeScriptHelpers._uniqueSymbolNameRegExp.test(name as string);\n\t}\n\n\t/**\n\t * Derives the string representation of a TypeScript late-bound symbol.\n\t */\n\tpublic static tryGetLateBoundName(declarationName: ts.ComputedPropertyName): string | undefined {\n\t\t// Create a node printer that ignores comments and indentation that we can use to convert\n\t\t// declarationName to a string.\n\t\tconst printer: ts.Printer = ts.createPrinter(\n\t\t\t{ removeComments: true },\n\t\t\t{\n\t\t\t\tonEmitNode(hint: ts.EmitHint, node: ts.Node, emitCallback: (hint: ts.EmitHint, node: ts.Node) => void): void {\n\t\t\t\t\tts.setEmitFlags(declarationName, ts.EmitFlags.NoIndentation | ts.EmitFlags.SingleLine);\n\t\t\t\t\temitCallback(hint, node);\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t\tconst sourceFile: ts.SourceFile = declarationName.getSourceFile();\n\t\tconst text: string = printer.printNode(ts.EmitHint.Unspecified, declarationName, sourceFile);\n\t\t// clean up any emit flags we've set on any nodes in the tree.\n\t\tts.disposeEmitNodes(sourceFile);\n\t\treturn text;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/analyzer/TypeScriptInternals.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError } from '@rushstack/node-core-library';\nimport * as ts from 'typescript';\n\n/**\n * Exposes the TypeScript compiler internals for detecting global variable names.\n */\nexport interface IGlobalVariableAnalyzer {\n\thasGlobalName(name: string): boolean;\n}\n\nexport class TypeScriptInternals {\n\t/**\n\t * Returns the Symbol for the provided Declaration.  This is a workaround for a missing\n\t * feature of the TypeScript Compiler API.   It is the only apparent way to reach\n\t * certain data structures, and seems to always work, but is not officially documented.\n\t *\n\t * @returns The associated Symbol.  If there is no semantic information (e.g. if the\n\t * declaration is an extra semicolon somewhere), then \"undefined\" is returned.\n\t */\n\tpublic static tryGetSymbolForDeclaration(\n\t\tdeclaration: ts.Declaration,\n\t\tchecker: ts.TypeChecker,\n\t): ts.Symbol | undefined {\n\t\tlet symbol: ts.Symbol | undefined = (declaration as any).symbol;\n\t\tif (symbol?.escapedName === ts.InternalSymbolName.Computed) {\n\t\t\tconst name: ts.DeclarationName | undefined = ts.getNameOfDeclaration(declaration);\n\t\t\tsymbol = (name && checker.getSymbolAtLocation(name)) || symbol;\n\t\t}\n\n\t\treturn symbol;\n\t}\n\n\t/**\n\t * Returns whether the provided Symbol is a TypeScript \"late-bound\" Symbol (i.e. was created by the Checker\n\t * for a computed property based on its type, rather than by the Binder).\n\t */\n\tpublic static isLateBoundSymbol(symbol: ts.Symbol): boolean {\n\t\treturn (\n\t\t\t(symbol.flags & ts.SymbolFlags.Transient) !== 0 &&\n\t\t\t(ts as any).getCheckFlags(symbol) === (ts as any).CheckFlags.Late\n\t\t);\n\t}\n\n\t/**\n\t * Retrieves the comment ranges associated with the specified node.\n\t */\n\tpublic static getJSDocCommentRanges(node: ts.Node, text: string): ts.CommentRange[] | undefined {\n\t\t// Compiler internal:\n\t\t// https://github.com/microsoft/TypeScript/blob/v2.4.2/src/compiler/utilities.ts#L616\n\n\t\treturn Reflect.apply((ts as any).getJSDocCommentRanges, this, [node, text]);\n\t}\n\n\t/**\n\t * Retrieves the (unescaped) value of an string literal, numeric literal, or identifier.\n\t */\n\tpublic static getTextOfIdentifierOrLiteral(node: ts.Identifier | ts.NumericLiteral | ts.StringLiteralLike): string {\n\t\t// Compiler internal:\n\t\t// https://github.com/microsoft/TypeScript/blob/v3.2.2/src/compiler/utilities.ts#L2721\n\n\t\treturn (ts as any).getTextOfIdentifierOrLiteral(node);\n\t}\n\n\t/**\n\t * Retrieves the (cached) module resolution information for a module name that was exported from a SourceFile.\n\t * The compiler populates this cache as part of analyzing the source file.\n\t */\n\tpublic static getResolvedModule(\n\t\tprogram: ts.Program,\n\t\tsourceFile: ts.SourceFile,\n\t\tmoduleNameText: string,\n\t\tmode: ts.ModuleKind.CommonJS | ts.ModuleKind.ESNext | undefined,\n\t): ts.ResolvedModuleFull | undefined {\n\t\t// Compiler internal:\n\t\t// https://github.com/microsoft/TypeScript/blob/v5.3.3/src/compiler/types.ts#L4698\n\t\tconst result: ts.ResolvedModuleWithFailedLookupLocations | undefined = (program as any).getResolvedModule(\n\t\t\tsourceFile,\n\t\t\tmoduleNameText,\n\t\t\tmode,\n\t\t);\n\t\treturn result?.resolvedModule;\n\t}\n\n\t/**\n\t * Returns ts.Symbol.parent if it exists.\n\t */\n\tpublic static getSymbolParent(symbol: ts.Symbol): ts.Symbol | undefined {\n\t\treturn (symbol as any).parent;\n\t}\n\n\t/**\n\t * In an statement like `export default class X { }`, the `Symbol.name` will be `default`\n\t * whereas the `localSymbol` is `X`.\n\t */\n\tpublic static tryGetLocalSymbol(declaration: ts.Declaration): ts.Symbol | undefined {\n\t\treturn (declaration as any).localSymbol;\n\t}\n\n\tpublic static getGlobalVariableAnalyzer(program: ts.Program): IGlobalVariableAnalyzer {\n\t\tconst anyProgram: any = program;\n\t\tconst typeCheckerInstance: any = anyProgram.getDiagnosticsProducingTypeChecker ?? anyProgram.getTypeChecker;\n\n\t\tif (!typeCheckerInstance) {\n\t\t\tthrow new InternalError('Missing Program.getDiagnosticsProducingTypeChecker or Program.getTypeChecker');\n\t\t}\n\n\t\tconst typeChecker: any = typeCheckerInstance();\n\t\tif (!typeChecker.getEmitResolver) {\n\t\t\tthrow new InternalError('Missing TypeChecker.getEmitResolver');\n\t\t}\n\n\t\tconst resolver: any = typeChecker.getEmitResolver();\n\t\tif (!resolver.hasGlobalName) {\n\t\t\tthrow new InternalError('Missing EmitResolver.hasGlobalName');\n\t\t}\n\n\t\treturn resolver;\n\t}\n\n\t/**\n\t * Returns whether a variable is declared with the const keyword\n\t */\n\tpublic static isVarConst(node: ts.VariableDeclaration | ts.VariableDeclarationList): boolean {\n\t\t// Compiler internal: https://github.com/microsoft/TypeScript/blob/71286e3d49c10e0e99faac360a6bbd40f12db7b6/src/compiler/utilities.ts#L925\n\t\treturn (ts as any).isVarConst(node);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/api/CompilerState.ts",
    "content": "/* eslint-disable no-case-declarations */\n// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as path from 'node:path';\nimport { JsonFile } from '@rushstack/node-core-library';\nimport colors from 'colors';\nimport * as ts from 'typescript';\nimport type { IExtractorInvokeOptions } from './Extractor.js';\nimport { ExtractorConfig } from './ExtractorConfig.js';\n\n/**\n * Options for {@link CompilerState.create}\n *\n * @public\n */\nexport interface ICompilerStateCreateOptions {\n\t/**\n\t * Additional .d.ts files to include in the analysis.\n\t */\n\tadditionalEntryPoints?: string[];\n\n\t/**\n\t * {@inheritDoc IExtractorInvokeOptions.typescriptCompilerFolder}\n\t */\n\ttypescriptCompilerFolder?: string | undefined;\n}\n\n/**\n * This class represents the TypeScript compiler state.  This allows an optimization where multiple invocations\n * of API Extractor can reuse the same TypeScript compiler analysis.\n *\n * @public\n */\nexport class CompilerState {\n\t/**\n\t * The TypeScript compiler's `Program` object, which represents a complete scope of analysis.\n\t */\n\tpublic readonly program: unknown;\n\n\tprivate constructor(properties: CompilerState) {\n\t\tthis.program = properties.program;\n\t}\n\n\t/**\n\t * Create a compiler state for use with the specified `IExtractorInvokeOptions`.\n\t */\n\tpublic static create(extractorConfig: ExtractorConfig, options?: ICompilerStateCreateOptions): CompilerState {\n\t\tlet tsconfig: {} | undefined = extractorConfig.overrideTsconfig;\n\t\tlet configBasePath: string = extractorConfig.projectFolder;\n\t\tif (!tsconfig) {\n\t\t\t// If it wasn't overridden, then load it from disk\n\t\t\ttsconfig = JsonFile.load(extractorConfig.tsconfigFilePath);\n\t\t\tconfigBasePath = path.resolve(path.dirname(extractorConfig.tsconfigFilePath));\n\t\t}\n\n\t\tconst commandLine: ts.ParsedCommandLine = ts.parseJsonConfigFileContent(tsconfig, ts.sys, configBasePath);\n\n\t\tif (!commandLine.options.skipLibCheck && extractorConfig.skipLibCheck) {\n\t\t\tcommandLine.options.skipLibCheck = true;\n\t\t\tconsole.log(\n\t\t\t\tcolors.cyan(\n\t\t\t\t\t'API Extractor was invoked with skipLibCheck. This is not recommended and may cause ' +\n\t\t\t\t\t\t'incorrect type analysis.',\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tconst inputFilePaths: string[] = commandLine.fileNames.concat(\n\t\t\textractorConfig.mainEntryPointFilePath.filePath,\n\t\t\textractorConfig.additionalEntryPoints.map((ep) => ep.filePath),\n\t\t);\n\t\tif (options?.additionalEntryPoints) {\n\t\t\tinputFilePaths.push(...options.additionalEntryPoints.map((entryPoint) => entryPoint));\n\t\t}\n\n\t\t// Append the entry points and remove any non-declaration files from the list\n\t\tconst analysisFilePaths: string[] = CompilerState._generateFilePathsForAnalysis(inputFilePaths);\n\n\t\tconst compilerHost: ts.CompilerHost = CompilerState._createCompilerHost(commandLine, options);\n\n\t\tconst program: ts.Program = ts.createProgram(analysisFilePaths, commandLine.options, compilerHost);\n\n\t\tif (commandLine.errors.length > 0) {\n\t\t\tconst errorText: string = ts.flattenDiagnosticMessageText(commandLine.errors[0]!.messageText, '\\n');\n\t\t\tthrow new Error(`Error parsing tsconfig.json content: ${errorText}`);\n\t\t}\n\n\t\treturn new CompilerState({\n\t\t\tprogram,\n\t\t});\n\t}\n\n\t/**\n\t * Given a list of absolute file paths, return a list containing only the declaration\n\t * files.  Duplicates are also eliminated.\n\t *\n\t * @remarks\n\t * The tsconfig.json settings specify the compiler's input (a set of *.ts source files,\n\t * plus some *.d.ts declaration files used for legacy typings).  However API Extractor\n\t * analyzes the compiler's output (a set of *.d.ts entry point files, plus any legacy\n\t * typings).  This requires API Extractor to generate a special file list when it invokes\n\t * the compiler.\n\t *\n\t * Duplicates are removed so that entry points can be appended without worrying whether they\n\t * may already appear in the tsconfig.json file list.\n\t */\n\tprivate static _generateFilePathsForAnalysis(inputFilePaths: string[]): string[] {\n\t\tconst analysisFilePaths: string[] = [];\n\n\t\tconst seenFiles: Set<string> = new Set<string>();\n\n\t\tfor (const inputFilePath of inputFilePaths) {\n\t\t\tconst inputFileToUpper: string = inputFilePath.toUpperCase();\n\t\t\tif (!seenFiles.has(inputFileToUpper)) {\n\t\t\t\tseenFiles.add(inputFileToUpper);\n\n\t\t\t\tif (!path.isAbsolute(inputFilePath)) {\n\t\t\t\t\tthrow new Error('Input file is not an absolute path: ' + inputFilePath);\n\t\t\t\t}\n\n\t\t\t\tif (ExtractorConfig.hasDtsFileExtension(inputFilePath)) {\n\t\t\t\t\tanalysisFilePaths.push(inputFilePath);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn analysisFilePaths;\n\t}\n\n\tprivate static _createCompilerHost(\n\t\tcommandLine: ts.ParsedCommandLine,\n\t\toptions: IExtractorInvokeOptions | undefined,\n\t): ts.CompilerHost {\n\t\t// Create a default CompilerHost that we will override\n\t\tconst compilerHost: ts.CompilerHost = ts.createCompilerHost(commandLine.options);\n\n\t\t// Save a copy of the original members.  Note that \"compilerHost\" cannot be the copy, because\n\t\t// createCompilerHost() captures that instance in a closure that is used by the members.\n\t\tconst defaultCompilerHost: ts.CompilerHost = { ...compilerHost };\n\n\t\tif (options?.typescriptCompilerFolder) {\n\t\t\t// Prevent a closure parameter\n\t\t\tconst typescriptCompilerLibFolder: string = path.join(options.typescriptCompilerFolder, 'lib');\n\t\t\tcompilerHost.getDefaultLibLocation = () => typescriptCompilerLibFolder;\n\t\t}\n\n\t\t// Used by compilerHost.fileExists()\n\t\t// .d.ts file path --> whether the file exists\n\t\tconst dtsExistsCache: Map<string, boolean> = new Map<string, boolean>();\n\n\t\t// Used by compilerHost.fileExists()\n\t\t// Example: \"c:/folder/file.part.ts\"\n\t\tconst fileExtensionRegExp = /^(?<pathWithoutExtension>.+)(?<fileExtension>\\.\\w+)$/i;\n\n\t\tcompilerHost.fileExists = (fileName: string): boolean => {\n\t\t\t// In certain deprecated setups, the compiler may write its output files (.js and .d.ts)\n\t\t\t// in the same folder as the corresponding input file (.ts or .tsx).  When following imports,\n\t\t\t// API Extractor wants to analyze the .d.ts file; however recent versions of the compiler engine\n\t\t\t// will instead choose the .ts file.  To work around this, we hook fileExists() to hide the\n\t\t\t// existence of those files.\n\n\t\t\t// Is \"fileName\" a .d.ts file?  The double extension \".d.ts\" needs to be matched specially.\n\t\t\tif (!ExtractorConfig.hasDtsFileExtension(fileName)) {\n\t\t\t\t// It's not a .d.ts file.  Is the file extension a potential source file?\n\t\t\t\tconst match: RegExpExecArray | null = fileExtensionRegExp.exec(fileName);\n\t\t\t\tif (match?.groups?.pathWithoutExtension && match.groups?.fileExtension) {\n\t\t\t\t\t// Example: \"c:/folder/file.part\"\n\t\t\t\t\tconst pathWithoutExtension: string = match.groups.pathWithoutExtension;\n\t\t\t\t\t// Example: \".ts\"\n\t\t\t\t\tconst fileExtension: string = match.groups.fileExtension;\n\n\t\t\t\t\tswitch (fileExtension.toLocaleLowerCase()) {\n\t\t\t\t\t\tcase '.ts':\n\t\t\t\t\t\tcase '.tsx':\n\t\t\t\t\t\tcase '.js':\n\t\t\t\t\t\tcase '.jsx':\n\t\t\t\t\t\t\t// Yes, this is a possible source file.  Is there a corresponding .d.ts file in the same folder?\n\t\t\t\t\t\t\tconst dtsFileName = `${pathWithoutExtension}.d.ts`;\n\n\t\t\t\t\t\t\tlet dtsFileExists: boolean | undefined = dtsExistsCache.get(dtsFileName);\n\t\t\t\t\t\t\tif (dtsFileExists === undefined) {\n\t\t\t\t\t\t\t\tdtsFileExists = defaultCompilerHost.fileExists!(dtsFileName);\n\t\t\t\t\t\t\t\tdtsExistsCache.set(dtsFileName, dtsFileExists);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (dtsFileExists) {\n\t\t\t\t\t\t\t\t// fileName is a potential source file and a corresponding .d.ts file exists.\n\t\t\t\t\t\t\t\t// Thus, API Extractor should ignore this file (so the .d.ts file will get analyzed instead).\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Fall through to the default implementation\n\t\t\treturn defaultCompilerHost.fileExists!(fileName);\n\t\t};\n\n\t\treturn compilerHost;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/api/ConsoleMessageId.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * Unique identifiers for console messages reported by API Extractor.\n *\n * @remarks\n *\n * These strings are possible values for the {@link ExtractorMessage.messageId} property\n * when the `ExtractorMessage.category` is {@link ExtractorMessageCategory.Console}.\n * @public\n */\nexport const enum ConsoleMessageId {\n\t/**\n\t * \"You have changed the public API signature for this project.  Updating ___\"\n\t */\n\tApiReportCopied = 'console-api-report-copied',\n\n\t/**\n\t * \"The API report file was missing, so a new file was created. Please add this file to Git: ___\"\n\t */\n\tApiReportCreated = 'console-api-report-created',\n\n\t/**\n\t * \"Unable to create the API report file. Please make sure the target folder exists: ___\"\n\t */\n\tApiReportFolderMissing = 'console-api-report-folder-missing',\n\n\t/**\n\t * \"You have changed the public API signature for this project.\n\t * Please copy the file ___ to ___, or perform a local build (which does this automatically).\n\t * See the Git repo documentation for more info.\"\n\t *\n\t * OR\n\t *\n\t * \"The API report file is missing.\n\t * Please copy the file ___ to ___, or perform a local build (which does this automatically).\n\t * See the Git repo documentation for more info.\"\n\t */\n\tApiReportNotCopied = 'console-api-report-not-copied',\n\n\t/**\n\t * \"The API report is up to date: ___\"\n\t */\n\tApiReportUnchanged = 'console-api-report-unchanged',\n\n\t/**\n\t * \"The target project appears to use TypeScript ___ which is newer than the bundled compiler engine;\n\t * consider upgrading API Extractor.\"\n\t */\n\tCompilerVersionNotice = 'console-compiler-version-notice',\n\n\t/**\n\t * Used for the information printed when the \"--diagnostics\" flag is enabled.\n\t */\n\tDiagnostics = 'console-diagnostics',\n\n\t/**\n\t * \"Found metadata in ___\"\n\t */\n\tFoundTSDocMetadata = 'console-found-tsdoc-metadata',\n\n\t/**\n\t * \"Analysis will use the bundled TypeScript version ___\"\n\t */\n\tPreamble = 'console-preamble',\n\n\t/**\n\t * \"Using custom TSDoc config from ___\"\n\t */\n\tUsingCustomTSDocConfig = 'console-using-custom-tsdoc-config',\n\n\t/**\n\t * \"Generating ___ API report: ___\"\n\t */\n\tWritingApiReport = 'console-writing-api-report',\n\n\t/**\n\t * \"Writing: ___\"\n\t */\n\tWritingDocModelFile = 'console-writing-doc-model-file',\n\n\t/**\n\t * \"Writing package typings: ___\"\n\t */\n\tWritingDtsRollup = 'console-writing-dts-rollup',\n}\n"
  },
  {
    "path": "packages/api-extractor/src/api/Extractor.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as path from 'node:path';\nimport type { ApiPackage } from '@discordjs/api-extractor-model';\nimport { TSDocConfigFile } from '@microsoft/tsdoc-config';\nimport {\n\tFileSystem,\n\ttype NewlineKind,\n\tPackageJsonLookup,\n\ttype IPackageJson,\n\ttype INodePackageJson,\n\tPath,\n} from '@rushstack/node-core-library';\nimport * as resolve from 'resolve';\nimport * as semver from 'semver';\nimport * as ts from 'typescript';\nimport { PackageMetadataManager } from '../analyzer/PackageMetadataManager.js';\nimport { Collector } from '../collector/Collector.js';\nimport { MessageRouter } from '../collector/MessageRouter.js';\nimport { SourceMapper } from '../collector/SourceMapper.js';\nimport { DocCommentEnhancer } from '../enhancers/DocCommentEnhancer.js';\nimport { ValidationEnhancer } from '../enhancers/ValidationEnhancer.js';\nimport { ApiModelGenerator } from '../generators/ApiModelGenerator.js';\nimport { ApiReportGenerator } from '../generators/ApiReportGenerator.js';\nimport { DtsRollupGenerator, DtsRollupKind } from '../generators/DtsRollupGenerator.js';\nimport { CompilerState } from './CompilerState.js';\nimport { ConsoleMessageId } from './ConsoleMessageId.js';\nimport { ExtractorConfig, type IExtractorConfigApiReport } from './ExtractorConfig.js';\nimport type { ExtractorMessage } from './ExtractorMessage.js';\n\n/**\n * Runtime options for Extractor.\n *\n * @public\n */\nexport interface IExtractorInvokeOptions {\n\t/**\n\t * An optional TypeScript compiler state.  This allows an optimization where multiple invocations of API Extractor\n\t * can reuse the same TypeScript compiler analysis.\n\t */\n\tcompilerState?: CompilerState;\n\n\t/**\n\t * Whether to minify the resulting doc model JSON, i.e. without any indentation or newlines.\n\t */\n\tdocModelMinify?: boolean;\n\n\t/**\n\t * Indicates that API Extractor is running as part of a local build, e.g. on developer's\n\t * machine.\n\t *\n\t * @remarks\n\t * This disables certain validation that would normally be performed for a ship/production build. For example,\n\t * the *.api.md report file is automatically updated in a local build.\n\t *\n\t * The default value is false.\n\t */\n\tlocalBuild?: boolean;\n\n\t/**\n\t * An optional callback function that will be called for each `ExtractorMessage` before it is displayed by\n\t * API Extractor.  The callback can customize the message, handle it, or discard it.\n\t *\n\t * @remarks\n\t * If a `messageCallback` is not provided, then by default API Extractor will print the messages to\n\t * the STDERR/STDOUT console.\n\t */\n\tmessageCallback?(this: void, message: ExtractorMessage): void;\n\n\t/**\n\t * If true, API Extractor will print diagnostic information used for troubleshooting problems.\n\t * These messages will be included as {@link ExtractorLogLevel.Verbose} output.\n\t *\n\t * @remarks\n\t * Setting `showDiagnostics=true` forces `showVerboseMessages=true`.\n\t */\n\tshowDiagnostics?: boolean;\n\n\t/**\n\t * If true, API Extractor will include {@link ExtractorLogLevel.Verbose} messages in its output.\n\t */\n\tshowVerboseMessages?: boolean;\n\n\t/**\n\t * Specifies an alternate folder path to be used when loading the TypeScript system typings.\n\t *\n\t * @remarks\n\t * API Extractor uses its own TypeScript compiler engine to analyze your project.  If your project\n\t * is built with a significantly different TypeScript version, sometimes API Extractor may report compilation\n\t * errors due to differences in the system typings (e.g. lib.dom.d.ts).  You can use the \"--typescriptCompilerFolder\"\n\t * option to specify the folder path where you installed the TypeScript package, and API Extractor's compiler will\n\t * use those system typings instead.\n\t */\n\ttypescriptCompilerFolder?: string | undefined;\n}\n\n/**\n * This object represents the outcome of an invocation of API Extractor.\n *\n * @public\n */\nexport class ExtractorResult {\n\t/**\n\t * The TypeScript compiler state that was used.\n\t */\n\tpublic readonly compilerState: CompilerState;\n\n\t/**\n\t * The API Extractor configuration that was used.\n\t */\n\tpublic readonly extractorConfig: ExtractorConfig;\n\n\t/**\n\t * Whether the invocation of API Extractor was successful.  For example, if `succeeded` is false, then the build task\n\t * would normally return a nonzero process exit code, indicating that the operation failed.\n\t *\n\t * @remarks\n\t *\n\t * Normally the operation \"succeeds\" if `errorCount` and `warningCount` are both zero.  However if\n\t * {@link IExtractorInvokeOptions.localBuild} is `true`, then the operation \"succeeds\" if `errorCount` is zero\n\t * (i.e. warnings are ignored).\n\t */\n\tpublic readonly succeeded: boolean;\n\n\t/**\n\t * Returns true if the API report was found to have changed.\n\t */\n\tpublic readonly apiReportChanged: boolean;\n\n\t/**\n\t * Reports the number of errors encountered during analysis.\n\t *\n\t * @remarks\n\t * This does not count exceptions, where unexpected issues prematurely abort the operation.\n\t */\n\tpublic readonly errorCount: number;\n\n\t/**\n\t * Reports the number of warnings encountered during analysis.\n\t *\n\t * @remarks\n\t * This does not count warnings that are emitted in the API report file.\n\t */\n\tpublic readonly warningCount: number;\n\n\t/**\n\t * @internal\n\t */\n\tpublic constructor(properties: ExtractorResult) {\n\t\tthis.compilerState = properties.compilerState;\n\t\tthis.extractorConfig = properties.extractorConfig;\n\t\tthis.succeeded = properties.succeeded;\n\t\tthis.apiReportChanged = properties.apiReportChanged;\n\t\tthis.errorCount = properties.errorCount;\n\t\tthis.warningCount = properties.warningCount;\n\t}\n}\n\n/**\n * The starting point for invoking the API Extractor tool.\n *\n * @public\n */\nexport class Extractor {\n\t/**\n\t * Returns the version number of the API Extractor NPM package.\n\t */\n\tpublic static get version(): string {\n\t\treturn Extractor._getPackageJson().version;\n\t}\n\n\t/**\n\t * Returns the package name of the API Extractor NPM package.\n\t */\n\tpublic static get packageName(): string {\n\t\treturn Extractor._getPackageJson().name;\n\t}\n\n\tprivate static _getPackageJson(): IPackageJson {\n\t\treturn PackageJsonLookup.loadOwnPackageJson(__dirname);\n\t}\n\n\t/**\n\t * Load the api-extractor.json config file from the specified path, and then invoke API Extractor.\n\t */\n\tpublic static loadConfigAndInvoke(configFilePath: string, options?: IExtractorInvokeOptions): ExtractorResult {\n\t\tconst extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare(configFilePath);\n\n\t\treturn Extractor.invoke(extractorConfig, options);\n\t}\n\n\t/**\n\t * Invoke API Extractor using an already prepared `ExtractorConfig` object.\n\t */\n\tpublic static invoke(extractorConfig: ExtractorConfig, options?: IExtractorInvokeOptions): ExtractorResult {\n\t\tconst ioptions = options ?? {};\n\n\t\tconst localBuild: boolean = ioptions.localBuild ?? false;\n\n\t\tlet compilerState: CompilerState | undefined;\n\t\tif (ioptions.compilerState) {\n\t\t\tcompilerState = ioptions.compilerState;\n\t\t} else {\n\t\t\tcompilerState = CompilerState.create(extractorConfig, ioptions);\n\t\t}\n\n\t\tconst sourceMapper: SourceMapper = new SourceMapper();\n\n\t\tconst messageRouter: MessageRouter = new MessageRouter({\n\t\t\tworkingPackageFolder: extractorConfig.packageFolder,\n\t\t\tmessageCallback: ioptions.messageCallback,\n\t\t\tmessagesConfig: extractorConfig.messages || {},\n\t\t\tshowVerboseMessages: Boolean(ioptions.showVerboseMessages),\n\t\t\tshowDiagnostics: Boolean(ioptions.showDiagnostics),\n\t\t\ttsdocConfiguration: extractorConfig.tsdocConfiguration,\n\t\t\tsourceMapper,\n\t\t});\n\n\t\tif (\n\t\t\textractorConfig.tsdocConfigFile.filePath &&\n\t\t\t!extractorConfig.tsdocConfigFile.fileNotFound &&\n\t\t\t!Path.isEqual(extractorConfig.tsdocConfigFile.filePath, ExtractorConfig._tsdocBaseFilePath)\n\t\t) {\n\t\t\tmessageRouter.logVerbose(\n\t\t\t\tConsoleMessageId.UsingCustomTSDocConfig,\n\t\t\t\t'Using custom TSDoc config from ' + extractorConfig.tsdocConfigFile.filePath,\n\t\t\t);\n\t\t}\n\n\t\tthis._checkCompilerCompatibility(extractorConfig, messageRouter);\n\n\t\tif (messageRouter.showDiagnostics) {\n\t\t\tmessageRouter.logDiagnostic('');\n\t\t\tmessageRouter.logDiagnosticHeader('Final prepared ExtractorConfig');\n\t\t\tmessageRouter.logDiagnostic(extractorConfig.getDiagnosticDump());\n\t\t\tmessageRouter.logDiagnosticFooter();\n\n\t\t\tmessageRouter.logDiagnosticHeader('Compiler options');\n\t\t\tconst serializedCompilerOptions: object = MessageRouter.buildJsonDumpObject(\n\t\t\t\t(compilerState.program as ts.Program).getCompilerOptions(),\n\t\t\t);\n\t\t\tmessageRouter.logDiagnostic(JSON.stringify(serializedCompilerOptions, undefined, 2));\n\t\t\tmessageRouter.logDiagnosticFooter();\n\n\t\t\tmessageRouter.logDiagnosticHeader('TSDoc configuration');\n\t\t\t// Convert the TSDocConfiguration into a tsdoc.json representation\n\t\t\tconst combinedConfigFile: TSDocConfigFile = TSDocConfigFile.loadFromParser(extractorConfig.tsdocConfiguration);\n\t\t\tconst serializedTSDocConfig: object = MessageRouter.buildJsonDumpObject(combinedConfigFile.saveToObject());\n\t\t\tmessageRouter.logDiagnostic(JSON.stringify(serializedTSDocConfig, undefined, 2));\n\t\t\tmessageRouter.logDiagnosticFooter();\n\t\t}\n\n\t\tconst collector: Collector = new Collector({\n\t\t\tprogram: compilerState.program as ts.Program,\n\t\t\tmessageRouter,\n\t\t\textractorConfig,\n\t\t\tsourceMapper,\n\t\t});\n\n\t\tcollector.analyze();\n\n\t\tDocCommentEnhancer.analyze(collector);\n\t\tValidationEnhancer.analyze(collector);\n\n\t\tconst modelBuilder: ApiModelGenerator = new ApiModelGenerator(collector, extractorConfig);\n\t\tconst apiPackage: ApiPackage = modelBuilder.buildApiPackage();\n\n\t\tif (messageRouter.showDiagnostics) {\n\t\t\tmessageRouter.logDiagnostic(''); // skip a line after any diagnostic messages\n\t\t}\n\n\t\tif (modelBuilder.docModelEnabled) {\n\t\t\tmessageRouter.logVerbose(ConsoleMessageId.WritingDocModelFile, 'Writing: ' + extractorConfig.apiJsonFilePath);\n\t\t\tapiPackage.saveToJsonFile(extractorConfig.apiJsonFilePath, {\n\t\t\t\ttoolPackage: Extractor.packageName,\n\t\t\t\ttoolVersion: Extractor.version,\n\t\t\t\tminify: options?.docModelMinify ?? false,\n\t\t\t\tnewlineConversion: extractorConfig.newlineKind,\n\t\t\t\tensureFolderExists: true,\n\t\t\t\ttestMode: extractorConfig.testMode,\n\t\t\t});\n\t\t}\n\n\t\tfunction writeApiReport(reportConfig: IExtractorConfigApiReport): boolean {\n\t\t\treturn Extractor._writeApiReport(\n\t\t\t\tcollector,\n\t\t\t\textractorConfig,\n\t\t\t\tmessageRouter,\n\t\t\t\textractorConfig.reportTempFolder,\n\t\t\t\textractorConfig.reportFolder,\n\t\t\t\treportConfig,\n\t\t\t\tlocalBuild,\n\t\t\t);\n\t\t}\n\n\t\tlet anyReportChanged = false;\n\t\tif (extractorConfig.apiReportEnabled) {\n\t\t\tfor (const reportConfig of extractorConfig.reportConfigs) {\n\t\t\t\tanyReportChanged = writeApiReport(reportConfig) || anyReportChanged;\n\t\t\t}\n\t\t}\n\n\t\tif (extractorConfig.rollupEnabled) {\n\t\t\tExtractor._generateRollupDtsFile(\n\t\t\t\tcollector,\n\t\t\t\textractorConfig.publicTrimmedFilePath,\n\t\t\t\tDtsRollupKind.PublicRelease,\n\t\t\t\textractorConfig.newlineKind,\n\t\t\t);\n\t\t\tExtractor._generateRollupDtsFile(\n\t\t\t\tcollector,\n\t\t\t\textractorConfig.alphaTrimmedFilePath,\n\t\t\t\tDtsRollupKind.AlphaRelease,\n\t\t\t\textractorConfig.newlineKind,\n\t\t\t);\n\t\t\tExtractor._generateRollupDtsFile(\n\t\t\t\tcollector,\n\t\t\t\textractorConfig.betaTrimmedFilePath,\n\t\t\t\tDtsRollupKind.BetaRelease,\n\t\t\t\textractorConfig.newlineKind,\n\t\t\t);\n\t\t\tExtractor._generateRollupDtsFile(\n\t\t\t\tcollector,\n\t\t\t\textractorConfig.untrimmedFilePath,\n\t\t\t\tDtsRollupKind.InternalRelease,\n\t\t\t\textractorConfig.newlineKind,\n\t\t\t);\n\t\t}\n\n\t\tif (extractorConfig.tsdocMetadataEnabled) {\n\t\t\t// Write the tsdoc-metadata.json file for this project\n\t\t\tPackageMetadataManager.writeTsdocMetadataFile(extractorConfig.tsdocMetadataFilePath, extractorConfig.newlineKind);\n\t\t}\n\n\t\t// Show all the messages that we collected during analysis\n\t\tmessageRouter.handleRemainingNonConsoleMessages();\n\n\t\t// Determine success\n\t\tlet succeeded: boolean;\n\t\tif (localBuild) {\n\t\t\t// For a local build, fail if there were errors (but ignore warnings)\n\t\t\tsucceeded = messageRouter.errorCount === 0;\n\t\t} else {\n\t\t\t// For a production build, fail if there were any errors or warnings\n\t\t\tsucceeded = messageRouter.errorCount + messageRouter.warningCount === 0;\n\t\t}\n\n\t\treturn new ExtractorResult({\n\t\t\tcompilerState,\n\t\t\textractorConfig,\n\t\t\tsucceeded,\n\t\t\tapiReportChanged: anyReportChanged,\n\t\t\terrorCount: messageRouter.errorCount,\n\t\t\twarningCount: messageRouter.warningCount,\n\t\t});\n\t}\n\n\t/**\n\t * Generates the API report at the specified release level, writes it to the specified file path, and compares\n\t * the output to the existing report (if one exists).\n\t *\n\t * @param collector - The collector to get the entities from.\n\t * @param extractorConfig - The configuration for extracting.\n\t * @param messageRouter - The message router to use.\n\t * @param reportTempDirectoryPath - The path to the directory under which the temp report file will be written prior\n\t * to comparison with an existing report.\n\t * @param reportDirectoryPath - The path to the directory under which the existing report file is located, and to\n\t * which the new report will be written post-comparison.\n\t * @param reportConfig - API report configuration, including its file name and {@link ApiReportVariant}.\n\t * @param localBuild - Whether the report is made locally.\n\t * @returns Whether or not the newly generated report differs from the existing report (if one exists).\n\t */\n\tprivate static _writeApiReport(\n\t\tcollector: Collector,\n\t\textractorConfig: ExtractorConfig,\n\t\tmessageRouter: MessageRouter,\n\t\treportTempDirectoryPath: string,\n\t\treportDirectoryPath: string,\n\t\treportConfig: IExtractorConfigApiReport,\n\t\tlocalBuild: boolean,\n\t): boolean {\n\t\tlet apiReportChanged = false;\n\n\t\tconst actualApiReportPathWithoutExtension: string = path\n\t\t\t.resolve(reportTempDirectoryPath, reportConfig.fileName)\n\t\t\t.replace(/\\.api\\.md$/, '');\n\n\t\tconst expectedApiReportPathWithoutExtension: string = path\n\t\t\t.resolve(reportDirectoryPath, reportConfig.fileName)\n\t\t\t.replace(/\\.api\\.md$/, '');\n\n\t\tconst actualApiReportContentMap: Map<string, string> = ApiReportGenerator.generateReviewFileContent(\n\t\t\tcollector,\n\t\t\treportConfig.variant,\n\t\t);\n\n\t\tfor (const [modulePath, actualApiReportContent] of actualApiReportContentMap) {\n\t\t\tconst actualEntryPointApiReportPath = `${actualApiReportPathWithoutExtension}${\n\t\t\t\tmodulePath ? '.' : ''\n\t\t\t}${modulePath}.api.md`;\n\t\t\tconst actualEntryPointApiReportShortPath: string =\n\t\t\t\textractorConfig._getShortFilePath(actualEntryPointApiReportPath);\n\t\t\tconst expectedEntryPointApiReportPath = `${expectedApiReportPathWithoutExtension}${\n\t\t\t\tmodulePath ? '.' : ''\n\t\t\t}${modulePath}.api.md`;\n\t\t\tconst expectedEntryPointApiReportShortPath: string = extractorConfig._getShortFilePath(\n\t\t\t\texpectedEntryPointApiReportPath,\n\t\t\t);\n\n\t\t\tcollector.messageRouter.logVerbose(\n\t\t\t\tConsoleMessageId.WritingApiReport,\n\t\t\t\t`Generating ${reportConfig.variant} API report: ${expectedEntryPointApiReportPath}`,\n\t\t\t);\n\n\t\t\t// Write the actual file\n\t\t\tFileSystem.writeFile(actualEntryPointApiReportPath, actualApiReportContent, {\n\t\t\t\tensureFolderExists: true,\n\t\t\t\tconvertLineEndings: extractorConfig.newlineKind,\n\t\t\t});\n\n\t\t\t// Compare it against the expected file\n\t\t\tif (FileSystem.exists(expectedEntryPointApiReportPath)) {\n\t\t\t\tconst expectedApiReportContent: string = FileSystem.readFile(expectedEntryPointApiReportPath);\n\n\t\t\t\tif (ApiReportGenerator.areEquivalentApiFileContents(actualApiReportContent, expectedApiReportContent)) {\n\t\t\t\t\tmessageRouter.logVerbose(\n\t\t\t\t\t\tConsoleMessageId.ApiReportUnchanged,\n\t\t\t\t\t\t`The API report is up to date: ${actualEntryPointApiReportShortPath}`,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tapiReportChanged = true;\n\n\t\t\t\t\tif (localBuild) {\n\t\t\t\t\t\t// For a local build, just copy the file automatically.\n\t\t\t\t\t\tmessageRouter.logWarning(\n\t\t\t\t\t\t\tConsoleMessageId.ApiReportCopied,\n\t\t\t\t\t\t\t`You have changed the API signature for this project. Updating ${actualEntryPointApiReportShortPath}`,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tFileSystem.writeFile(actualEntryPointApiReportPath, actualApiReportContent, {\n\t\t\t\t\t\t\tensureFolderExists: true,\n\t\t\t\t\t\t\tconvertLineEndings: extractorConfig.newlineKind,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// For a production build, issue a warning that will break the CI build.\n\t\t\t\t\t\tmessageRouter.logWarning(\n\t\t\t\t\t\t\tConsoleMessageId.ApiReportNotCopied,\n\t\t\t\t\t\t\t'You have changed the API signature for this project.' +\n\t\t\t\t\t\t\t\t` Please copy the file \"${actualEntryPointApiReportShortPath}\" to \"${expectedEntryPointApiReportShortPath}\",` +\n\t\t\t\t\t\t\t\t` or perform a local build (which does this automatically).` +\n\t\t\t\t\t\t\t\t` See the Git repo documentation for more info.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// The target file does not exist, so we are setting up the API review file for the first time.\n\t\t\t\t//\n\t\t\t\t// NOTE: People sometimes make a mistake where they move a project and forget to update the \"reportFolder\"\n\t\t\t\t// setting, which causes a new file to silently get written to the wrong place.  This can be confusing.\n\t\t\t\t// Thus we treat the initial creation of the file specially.\n\t\t\t\tapiReportChanged = true;\n\n\t\t\t\tif (localBuild) {\n\t\t\t\t\tconst expectedApiReportFolder: string = path.dirname(expectedEntryPointApiReportPath);\n\t\t\t\t\tif (FileSystem.exists(expectedApiReportFolder)) {\n\t\t\t\t\t\tFileSystem.writeFile(expectedEntryPointApiReportPath, actualApiReportContent, {\n\t\t\t\t\t\t\tconvertLineEndings: extractorConfig.newlineKind,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tmessageRouter.logWarning(\n\t\t\t\t\t\t\tConsoleMessageId.ApiReportCreated,\n\t\t\t\t\t\t\t'The API report file was missing, so a new file was created. Please add this file to Git:\\n' +\n\t\t\t\t\t\t\t\texpectedEntryPointApiReportPath,\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmessageRouter.logError(\n\t\t\t\t\t\t\tConsoleMessageId.ApiReportFolderMissing,\n\t\t\t\t\t\t\t'Unable to create the API report file. Please make sure the target folder exists:\\n' +\n\t\t\t\t\t\t\t\texpectedApiReportFolder,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// For a production build, issue a warning that will break the CI build.\n\t\t\t\t\tmessageRouter.logWarning(\n\t\t\t\t\t\tConsoleMessageId.ApiReportNotCopied,\n\t\t\t\t\t\t'The API report file is missing.' +\n\t\t\t\t\t\t\t` Please copy the file \"${actualEntryPointApiReportShortPath}\" to \"${expectedEntryPointApiReportShortPath}\",` +\n\t\t\t\t\t\t\t` or perform a local build (which does this automatically).` +\n\t\t\t\t\t\t\t` See the Git repo documentation for more info.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn apiReportChanged;\n\t}\n\n\tprivate static _checkCompilerCompatibility(extractorConfig: ExtractorConfig, messageRouter: MessageRouter): void {\n\t\tmessageRouter.logInfo(ConsoleMessageId.Preamble, `Analysis will use the bundled TypeScript version ${ts.version}`);\n\n\t\ttry {\n\t\t\tconst typescriptPath: string = resolve.sync('typescript', {\n\t\t\t\tbasedir: extractorConfig.projectFolder,\n\t\t\t\tpreserveSymlinks: false,\n\t\t\t});\n\t\t\tconst packageJsonLookup: PackageJsonLookup = new PackageJsonLookup();\n\t\t\tconst packageJson: INodePackageJson | undefined = packageJsonLookup.tryLoadNodePackageJsonFor(typescriptPath);\n\t\t\tif (packageJson?.version && semver.valid(packageJson.version)) {\n\t\t\t\t// Consider a newer MINOR release to be incompatible\n\t\t\t\tconst ourMajor: number = semver.major(ts.version);\n\t\t\t\tconst ourMinor: number = semver.minor(ts.version);\n\n\t\t\t\tconst theirMajor: number = semver.major(packageJson.version);\n\t\t\t\tconst theirMinor: number = semver.minor(packageJson.version);\n\n\t\t\t\tif (theirMajor > ourMajor || (theirMajor === ourMajor && theirMinor > ourMinor)) {\n\t\t\t\t\tmessageRouter.logInfo(\n\t\t\t\t\t\tConsoleMessageId.CompilerVersionNotice,\n\t\t\t\t\t\t`*** The target project appears to use TypeScript ${packageJson.version} which is newer than the` +\n\t\t\t\t\t\t\t` bundled compiler engine; consider upgrading API Extractor.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// The compiler detection heuristic is not expected to work in many configurations\n\t\t}\n\t}\n\n\tprivate static _generateRollupDtsFile(\n\t\tcollector: Collector,\n\t\toutputPath: string,\n\t\tdtsKind: DtsRollupKind,\n\t\tnewlineKind: NewlineKind,\n\t): void {\n\t\tif (outputPath !== '') {\n\t\t\tcollector.messageRouter.logVerbose(ConsoleMessageId.WritingDtsRollup, `Writing package typings: ${outputPath}`);\n\t\t\tDtsRollupGenerator.writeTypingsFile(collector, outputPath, dtsKind, newlineKind);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/api/ExtractorConfig.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as path from 'node:path';\nimport { EnumMemberOrder, ReleaseTag } from '@discordjs/api-extractor-model';\nimport { TSDocConfiguration, TSDocTagDefinition } from '@microsoft/tsdoc';\nimport { TSDocConfigFile } from '@microsoft/tsdoc-config';\nimport {\n\tJsonFile,\n\tJsonSchema,\n\tFileSystem,\n\tPackageJsonLookup,\n\ttype INodePackageJson,\n\tPackageName,\n\tText,\n\tInternalError,\n\tPath,\n\tNewlineKind,\n} from '@rushstack/node-core-library';\nimport type { MergeWithCustomizer } from 'lodash';\nimport cloneDeep from 'lodash/cloneDeep.js';\nimport mergeWith from 'lodash/mergeWith.js';\nimport * as resolve from 'resolve';\nimport { PackageMetadataManager } from '../analyzer/PackageMetadataManager.js';\nimport { MessageRouter } from '../collector/MessageRouter.js';\nimport type { IApiModelGenerationOptions } from '../generators/ApiModelGenerator';\nimport apiExtractorSchema from '../schemas/api-extractor.schema.json' assert { type: 'json' };\nimport type {\n\tApiReportVariant,\n\tIConfigApiReport,\n\tIConfigFile,\n\tIConfigEntryPoint,\n\tIExtractorMessagesConfig,\n} from './IConfigFile.js';\n\n/**\n * Tokens used during variable expansion of path fields from api-extractor.json.\n */\ninterface IExtractorConfigTokenContext {\n\t/**\n\t * The `<packageName>` token returns the project's full NPM package name including any NPM scope.\n\t * If there is no associated package.json file, then the value is `unknown-package`.\n\t *\n\t * Example: `@scope/my-project`\n\t */\n\tpackageName: string;\n\n\t/**\n\t * The `<projectFolder>` token returns the expanded `\"projectFolder\"` setting from api-extractor.json.\n\t */\n\tprojectFolder: string;\n\n\t/**\n\t * The `<unscopedPackageName>` token returns the project's NPM package name, without any NPM scope.\n\t * If there is no associated package.json file, then the value is `unknown-package`.\n\t *\n\t * Example: `my-project`\n\t */\n\tunscopedPackageName: string;\n}\n\n/**\n * Options for {@link ExtractorConfig.tryLoadForFolder}.\n *\n * @public\n */\nexport interface IExtractorConfigLoadForFolderOptions {\n\t/**\n\t * An already constructed `PackageJsonLookup` cache object to use.  If omitted, a temporary one will\n\t * be constructed.\n\t */\n\tpackageJsonLookup?: PackageJsonLookup;\n\n\t/**\n\t * An already constructed `RigConfig` object.  If omitted, then a new `RigConfig` object will be constructed.\n\t *\n\t * @deprecated this is unsupported in the discord.js version\n\t */\n\trigConfig?: never;\n\n\t/**\n\t * The folder path to start from when searching for api-extractor.json.\n\t */\n\tstartingFolder: string;\n}\n\n/**\n * Options for {@link ExtractorConfig.prepare}.\n *\n * @public\n */\nexport interface IExtractorConfigPrepareOptions {\n\t/**\n\t * A configuration object as returned by {@link ExtractorConfig.loadFile}.\n\t */\n\tconfigObject: IConfigFile;\n\n\t/**\n\t * The absolute path of the file that the `configObject` object was loaded from.  This is used for error messages\n\t * and when probing for `tsconfig.json`.\n\t *\n\t * @remarks\n\t *\n\t * If `configObjectFullPath` and `projectFolderLookupToken` are both unspecified, then the api-extractor.json\n\t * config file must explicitly specify a `projectFolder` setting rather than relying on the `<lookup>` token.\n\t */\n\tconfigObjectFullPath: string | undefined;\n\n\t/**\n\t * When preparing the configuration object, folder and file paths referenced in the configuration are checked\n\t * for existence, and an error is reported if they are not found.  This option can be used to disable this\n\t * check for the main entry point module. This may be useful when preparing a configuration file for an\n\t * un-built project.\n\t */\n\tignoreMissingEntryPoint?: boolean;\n\n\t/**\n\t * The parsed package.json file for the working package, or undefined if API Extractor was invoked without\n\t * a package.json file.\n\t *\n\t * @remarks\n\t *\n\t * If omitted, then the `<unscopedPackageName>` and `<packageName>` tokens will have default values.\n\t */\n\tpackageJson?: INodePackageJson | undefined;\n\n\t/**\n\t * The absolute path of the file that the `packageJson` object was loaded from, or undefined if API Extractor\n\t * was invoked without a package.json file.\n\t *\n\t * @remarks\n\t *\n\t * This is used for error messages and when resolving paths found in package.json.\n\t *\n\t * If `packageJsonFullPath` is specified but `packageJson` is omitted, the file will be loaded automatically.\n\t */\n\tpackageJsonFullPath: string | undefined;\n\n\t/**\n\t * The default value for the `projectFolder` setting is the `<lookup>` token, which uses a heuristic to guess\n\t * an appropriate project folder.  Use `projectFolderLookupValue` to manually specify the `<lookup>` token value\n\t * instead.\n\t *\n\t * @remarks\n\t * If the `projectFolder` setting is explicitly specified in api-extractor.json file, it should take precedence\n\t * over a value specified via the API.  Thus the `projectFolderLookupToken` option provides a way to override\n\t * the default value for `projectFolder` setting while still honoring a manually specified value.\n\t */\n\tprojectFolderLookupToken?: string | undefined;\n\n\t/**\n\t * Allow customization of the tsdoc.json config file.  If omitted, this file will be loaded from its default\n\t * location.  If the file does not exist, then the standard definitions will be used from\n\t * `@discordjs/api-extractor/extends/tsdoc-base.json`.\n\t */\n\ttsdocConfigFile?: TSDocConfigFile;\n}\n\n/**\n * Configuration for a single API report, including its {@link IExtractorConfigApiReport.variant}.\n *\n * @public\n */\nexport interface IExtractorConfigApiReport {\n\t/**\n\t * Name of the output report file.\n\t *\n\t * @remarks Relative to the configured report directory path.\n\t */\n\tfileName: string;\n\n\t/**\n\t * Report variant.\n\t * Determines which API items will be included in the report output, based on their tagged release levels.\n\t */\n\tvariant: ApiReportVariant;\n}\n\n/**\n * Default {@link IConfigApiReport.reportVariants}\n */\nconst defaultApiReportVariants: readonly ApiReportVariant[] = ['complete'];\n\n/**\n * Default {@link IConfigApiReport.tagsToReport}.\n *\n * @remarks\n * Note that this list is externally documented, and directly affects report output.\n * Also note that the order of tags in this list is significant, as it determines the order of tags in the report.\n * Any changes to this list should be considered breaking.\n */\nconst defaultTagsToReport: Readonly<Record<`@${string}`, boolean>> = {\n\t'@sealed': true,\n\t'@virtual': true,\n\t'@override': true,\n\t'@eventProperty': true,\n\t'@deprecated': true,\n};\n\ninterface IExtractorConfigParameters {\n\tadditionalEntryPoints: IConfigEntryPoint[];\n\talphaTrimmedFilePath: string;\n\tapiJsonFilePath: string;\n\tapiReportEnabled: boolean;\n\tapiReportIncludeForgottenExports: boolean;\n\tbetaTrimmedFilePath: string;\n\tbundledPackages: string[];\n\tdocModelGenerationOptions: IApiModelGenerationOptions | undefined;\n\tdocModelIncludeForgottenExports: boolean;\n\tenumMemberOrder: EnumMemberOrder;\n\tmainEntryPointFilePath: string;\n\tmainEntryPointName: string;\n\tmessages: IExtractorMessagesConfig;\n\tnewlineKind: NewlineKind;\n\tomitTrimmingComments: boolean;\n\toverrideTsconfig: {} | undefined;\n\tpackageFolder: string | undefined;\n\tpackageJson: INodePackageJson | undefined;\n\tprojectFolder: string;\n\tprojectFolderUrl: string | undefined;\n\tpublicTrimmedFilePath: string;\n\treportConfigs: readonly IExtractorConfigApiReport[];\n\treportFolder: string;\n\treportTempFolder: string;\n\trollupEnabled: boolean;\n\tskipLibCheck: boolean;\n\ttagsToReport: Readonly<Record<`@${string}`, boolean>>;\n\ttestMode: boolean;\n\ttsconfigFilePath: string;\n\ttsdocConfigFile: TSDocConfigFile;\n\ttsdocConfiguration: TSDocConfiguration;\n\ttsdocMetadataEnabled: boolean;\n\ttsdocMetadataFilePath: string;\n\tuntrimmedFilePath: string;\n}\n\n// Lodash merges array values by default, which is unintuitive for config files (and makes it impossible for derived configurations to overwrite arrays).\n// For example, given a base config containing an array property with value [\"foo\", \"bar\"] and a derived config that specifies [\"baz\"] for that property, lodash will produce [\"baz\", \"bar\"], which is unintuitive.\n// This customizer function ensures that arrays are always overwritten.\nconst mergeCustomizer: MergeWithCustomizer = (_objValue, srcValue) => {\n\tif (Array.isArray(srcValue)) {\n\t\treturn srcValue;\n\t}\n\n\t// Fall back to default merge behavior.\n\treturn undefined;\n};\n\n/**\n * The `ExtractorConfig` class loads, validates, interprets, and represents the api-extractor.json config file.\n *\n * @sealed\n * @public\n */\nexport class ExtractorConfig {\n\t/**\n\t * The JSON Schema for API Extractor config file (api-extractor.schema.json).\n\t */\n\tpublic static readonly jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(apiExtractorSchema);\n\n\t/**\n\t * The config file name \"api-extractor.json\".\n\t */\n\tpublic static readonly FILENAME = 'api-extractor.json' as const;\n\n\t/**\n\t * The full path to `extends/tsdoc-base.json` which contains the standard TSDoc configuration\n\t * for API Extractor.\n\t *\n\t * @internal\n\t */\n\tpublic static readonly _tsdocBaseFilePath: string = path.resolve(__dirname, './extends/tsdoc-base.json');\n\n\tprivate static readonly _defaultConfig: Partial<IConfigFile> = JsonFile.load(\n\t\tpath.join(__dirname, './schemas/api-extractor-defaults.json'),\n\t);\n\n\tprivate static readonly _declarationFileExtensionRegExp: RegExp = /\\.d\\.[cm]?ts$/i;\n\n\t/**\n\t * {@inheritDoc IConfigFile.projectFolder}\n\t */\n\tpublic readonly projectFolder: string;\n\n\t/**\n\t * The parsed package.json file for the working package, or undefined if API Extractor was invoked without\n\t * a package.json file.\n\t */\n\tpublic readonly packageJson: INodePackageJson | undefined;\n\n\t/**\n\t * The absolute path of the folder containing the package.json file for the working package, or undefined\n\t * if API Extractor was invoked without a package.json file.\n\t */\n\tpublic readonly packageFolder: string | undefined;\n\n\t/**\n\t * {@inheritDoc IConfigFile.mainEntryPointFilePath}\n\t */\n\tpublic readonly mainEntryPointFilePath: IConfigEntryPoint;\n\n\t/**\n\t * {@inheritDoc IConfigFile.additionalEntryPoints}\n\t */\n\tpublic readonly additionalEntryPoints: IConfigEntryPoint[];\n\n\t/**\n\t * {@inheritDoc IConfigFile.bundledPackages}\n\t */\n\tpublic readonly bundledPackages: string[];\n\n\t/**\n\t * {@inheritDoc IConfigCompiler.tsconfigFilePath}\n\t */\n\tpublic readonly tsconfigFilePath: string;\n\n\t/**\n\t * {@inheritDoc IConfigCompiler.overrideTsconfig}\n\t */\n\tpublic readonly overrideTsconfig: {} | undefined;\n\n\t/**\n\t * {@inheritDoc IConfigCompiler.skipLibCheck}\n\t */\n\tpublic readonly skipLibCheck: boolean;\n\n\t/**\n\t * {@inheritDoc IConfigApiReport.enabled}\n\t */\n\tpublic readonly apiReportEnabled: boolean;\n\n\t/**\n\t * List of configurations for report files to be generated.\n\t *\n\t * @remarks Derived from {@link IConfigApiReport.reportFileName} and {@link IConfigApiReport.reportVariants}.\n\t */\n\tpublic readonly reportConfigs: readonly IExtractorConfigApiReport[];\n\n\t/**\n\t * {@inheritDoc IConfigApiReport.reportFolder}\n\t */\n\tpublic readonly reportFolder: string;\n\n\t/**\n\t * {@inheritDoc IConfigApiReport.reportTempFolder}\n\t */\n\tpublic readonly reportTempFolder: string;\n\n\t/**\n\t * {@inheritDoc IConfigApiReport.tagsToReport}\n\t */\n\tpublic readonly tagsToReport: Readonly<Record<`@${string}`, boolean>>;\n\n\t/**\n\t * Gets the file path for the \"complete\" (default) report configuration, if one was specified.\n\t * Otherwise, returns an empty string.\n\t *\n\t * @deprecated Use {@link ExtractorConfig.reportConfigs} to access all report configurations.\n\t */\n\tpublic get reportFilePath(): string {\n\t\tconst completeConfig: IExtractorConfigApiReport | undefined = this._getCompleteReportConfig();\n\t\treturn completeConfig === undefined ? '' : path.join(this.reportFolder, completeConfig.fileName);\n\t}\n\n\t/**\n\t * Gets the temp file path for the \"complete\" (default) report configuration, if one was specified.\n\t * Otherwise, returns an empty string.\n\t *\n\t * @deprecated Use {@link ExtractorConfig.reportConfigs} to access all report configurations.\n\t */\n\tpublic get reportTempFilePath(): string {\n\t\tconst completeConfig: IExtractorConfigApiReport | undefined = this._getCompleteReportConfig();\n\t\treturn completeConfig === undefined ? '' : path.join(this.reportTempFolder, completeConfig.fileName);\n\t}\n\n\t/**\n\t * {@inheritDoc IConfigApiReport.includeForgottenExports}\n\t */\n\tpublic readonly apiReportIncludeForgottenExports: boolean;\n\n\t/**\n\t * If specified, the doc model is enabled and the specified options will be used.\n\t *\n\t * @beta\n\t */\n\tpublic readonly docModelGenerationOptions: IApiModelGenerationOptions | undefined;\n\n\t/**\n\t * {@inheritDoc IConfigDocModel.apiJsonFilePath}\n\t */\n\tpublic readonly apiJsonFilePath: string;\n\n\t/**\n\t * {@inheritDoc IConfigDocModel.includeForgottenExports}\n\t */\n\tpublic readonly docModelIncludeForgottenExports: boolean;\n\n\t/**\n\t * {@inheritDoc IConfigDocModel.projectFolderUrl}\n\t */\n\tpublic readonly projectFolderUrl: string | undefined;\n\n\t/**\n\t * {@inheritDoc IConfigDtsRollup.enabled}\n\t */\n\tpublic readonly rollupEnabled: boolean;\n\n\t/**\n\t * {@inheritDoc IConfigDtsRollup.untrimmedFilePath}\n\t */\n\tpublic readonly untrimmedFilePath: string;\n\n\t/**\n\t * {@inheritDoc IConfigDtsRollup.alphaTrimmedFilePath}\n\t */\n\tpublic readonly alphaTrimmedFilePath: string;\n\n\t/**\n\t * {@inheritDoc IConfigDtsRollup.betaTrimmedFilePath}\n\t */\n\tpublic readonly betaTrimmedFilePath: string;\n\n\t/**\n\t * {@inheritDoc IConfigDtsRollup.publicTrimmedFilePath}\n\t */\n\tpublic readonly publicTrimmedFilePath: string;\n\n\t/**\n\t * {@inheritDoc IConfigDtsRollup.omitTrimmingComments}\n\t */\n\tpublic readonly omitTrimmingComments: boolean;\n\n\t/**\n\t * {@inheritDoc IConfigTsdocMetadata.enabled}\n\t */\n\tpublic readonly tsdocMetadataEnabled: boolean;\n\n\t/**\n\t * {@inheritDoc IConfigTsdocMetadata.tsdocMetadataFilePath}\n\t */\n\tpublic readonly tsdocMetadataFilePath: string;\n\n\t/**\n\t * The tsdoc.json configuration that will be used when parsing doc comments.\n\t */\n\tpublic readonly tsdocConfigFile: TSDocConfigFile;\n\n\t/**\n\t * The `TSDocConfiguration` loaded from {@link ExtractorConfig.tsdocConfigFile}.\n\t */\n\tpublic readonly tsdocConfiguration: TSDocConfiguration;\n\n\t/**\n\t * Specifies what type of newlines API Extractor should use when writing output files.  By default, the output files\n\t * will be written with Windows-style newlines.\n\t */\n\tpublic readonly newlineKind: NewlineKind;\n\n\t/**\n\t * {@inheritDoc IConfigFile.messages}\n\t */\n\tpublic readonly messages: IExtractorMessagesConfig;\n\n\t/**\n\t * {@inheritDoc IConfigFile.testMode}\n\t */\n\tpublic readonly testMode: boolean;\n\n\t/**\n\t * {@inheritDoc IConfigFile.enumMemberOrder}\n\t */\n\tpublic readonly enumMemberOrder: EnumMemberOrder;\n\n\tprivate constructor({\n\t\tprojectFolder,\n\t\tpackageJson,\n\t\tpackageFolder,\n\t\tmainEntryPointName,\n\t\tmainEntryPointFilePath,\n\t\tadditionalEntryPoints,\n\t\tbundledPackages,\n\t\ttsconfigFilePath,\n\t\toverrideTsconfig,\n\t\tskipLibCheck,\n\t\tapiReportEnabled,\n\t\tapiReportIncludeForgottenExports,\n\t\treportConfigs,\n\t\treportFolder,\n\t\treportTempFolder,\n\t\ttagsToReport,\n\t\tdocModelGenerationOptions,\n\t\tapiJsonFilePath,\n\t\tdocModelIncludeForgottenExports,\n\t\tprojectFolderUrl,\n\t\trollupEnabled,\n\t\tuntrimmedFilePath,\n\t\talphaTrimmedFilePath,\n\t\tbetaTrimmedFilePath,\n\t\tpublicTrimmedFilePath,\n\t\tomitTrimmingComments,\n\t\ttsdocMetadataEnabled,\n\t\ttsdocMetadataFilePath,\n\t\ttsdocConfigFile,\n\t\ttsdocConfiguration,\n\t\tnewlineKind,\n\t\tmessages,\n\t\ttestMode,\n\t\tenumMemberOrder,\n\t}: IExtractorConfigParameters) {\n\t\tthis.projectFolder = projectFolder;\n\t\tthis.packageJson = packageJson;\n\t\tthis.packageFolder = packageFolder;\n\t\tthis.mainEntryPointFilePath = {\n\t\t\tmodulePath: mainEntryPointName,\n\t\t\tfilePath: mainEntryPointFilePath,\n\t\t};\n\t\tthis.additionalEntryPoints = additionalEntryPoints;\n\t\tthis.bundledPackages = bundledPackages;\n\t\tthis.tsconfigFilePath = tsconfigFilePath;\n\t\tthis.overrideTsconfig = overrideTsconfig;\n\t\tthis.skipLibCheck = skipLibCheck;\n\t\tthis.apiReportEnabled = apiReportEnabled;\n\t\tthis.reportConfigs = reportConfigs;\n\t\tthis.reportFolder = reportFolder;\n\t\tthis.reportTempFolder = reportTempFolder;\n\t\tthis.tagsToReport = tagsToReport;\n\t\tthis.apiReportIncludeForgottenExports = apiReportIncludeForgottenExports;\n\t\tthis.docModelGenerationOptions = docModelGenerationOptions;\n\t\tthis.apiJsonFilePath = apiJsonFilePath;\n\t\tthis.docModelIncludeForgottenExports = docModelIncludeForgottenExports;\n\t\tthis.projectFolderUrl = projectFolderUrl;\n\t\tthis.rollupEnabled = rollupEnabled;\n\t\tthis.untrimmedFilePath = untrimmedFilePath;\n\t\tthis.alphaTrimmedFilePath = alphaTrimmedFilePath;\n\t\tthis.betaTrimmedFilePath = betaTrimmedFilePath;\n\t\tthis.publicTrimmedFilePath = publicTrimmedFilePath;\n\t\tthis.omitTrimmingComments = omitTrimmingComments;\n\t\tthis.tsdocMetadataEnabled = tsdocMetadataEnabled;\n\t\tthis.tsdocMetadataFilePath = tsdocMetadataFilePath;\n\t\tthis.tsdocConfigFile = tsdocConfigFile;\n\t\tthis.tsdocConfiguration = tsdocConfiguration;\n\t\tthis.newlineKind = newlineKind;\n\t\tthis.messages = messages;\n\t\tthis.testMode = testMode;\n\t\tthis.enumMemberOrder = enumMemberOrder;\n\t}\n\n\t/**\n\t * Returns a JSON-like string representing the `ExtractorConfig` state, which can be printed to a console\n\t * for diagnostic purposes.\n\t *\n\t * @remarks\n\t * This is used by the \"--diagnostics\" command-line option.  The string is not intended to be deserialized;\n\t * its format may be changed at any time.\n\t */\n\tpublic getDiagnosticDump(): string {\n\t\t// Handle the simple JSON-serializable properties using buildJsonDumpObject()\n\t\tconst result: object = MessageRouter.buildJsonDumpObject(this, {\n\t\t\tkeyNamesToOmit: ['tsdocConfigFile', 'tsdocConfiguration'],\n\t\t});\n\n\t\t// Implement custom formatting for tsdocConfigFile and tsdocConfiguration\n\n\t\t(result as any).tsdocConfigFile = {\n\t\t\tfilePath: this.tsdocConfigFile.filePath,\n\t\t\tlog: this.tsdocConfigFile.log.messages.map((x) => x.toString()),\n\t\t};\n\n\t\treturn JSON.stringify(result, undefined, 2);\n\t}\n\n\t/**\n\t * Returns a simplified file path for use in error messages.\n\t *\n\t * @internal\n\t */\n\tpublic _getShortFilePath(absolutePath: string): string {\n\t\tif (!path.isAbsolute(absolutePath)) {\n\t\t\tthrow new InternalError('Expected absolute path: ' + absolutePath);\n\t\t}\n\n\t\tif (Path.isUnderOrEqual(absolutePath, this.projectFolder)) {\n\t\t\treturn Path.convertToSlashes(path.relative(this.projectFolder, absolutePath));\n\t\t}\n\n\t\treturn absolutePath;\n\t}\n\n\t/**\n\t * Searches for the api-extractor.json config file associated with the specified starting folder,\n\t * and loads the file if found.  This lookup supports\n\t * {@link https://www.npmjs.com/package/@rushstack/rig-package | rig packages}.\n\t *\n\t * @remarks\n\t * The search will first look for a package.json file in a parent folder of the starting folder;\n\t * if found, that will be used as the base folder instead of the starting folder.  If the config\n\t * file is not found in `<baseFolder>/api-extractor.json` or `<baseFolder>/config/api-extractor.json`,\n\t * then `<baseFolder/config/rig.json` will be checked to see whether a\n\t * {@link https://www.npmjs.com/package/@rushstack/rig-package | rig package} is referenced; if so then\n\t * the rig's api-extractor.json file will be used instead.  If a config file is found, it will be loaded\n\t * and returned with the `IExtractorConfigPrepareOptions` object. Otherwise, `undefined` is returned\n\t * to indicate that API Extractor does not appear to be configured for the specified folder.\n\t * @returns An options object that can be passed to {@link ExtractorConfig.prepare}, or `undefined`\n\t * if not api-extractor.json file was found.\n\t */\n\tpublic static tryLoadForFolder(\n\t\toptions: IExtractorConfigLoadForFolderOptions,\n\t): IExtractorConfigPrepareOptions | undefined {\n\t\tconst packageJsonLookup: PackageJsonLookup = options.packageJsonLookup ?? new PackageJsonLookup();\n\t\tconst startingFolder: string = options.startingFolder;\n\n\t\t// Figure out which project we're in and look for the config file at the project root\n\t\tconst packageJsonFullPath: string | undefined = packageJsonLookup.tryGetPackageJsonFilePathFor(startingFolder);\n\t\tconst packageFolder: string | undefined = packageJsonFullPath ? path.dirname(packageJsonFullPath) : undefined;\n\n\t\t// If there is no package, then just use the starting folder\n\t\tconst baseFolder: string = packageFolder ?? startingFolder;\n\n\t\tlet projectFolderLookupToken: string | undefined;\n\n\t\t// First try the standard \"config\" subfolder:\n\t\tlet configFilename: string = path.join(baseFolder, 'config', ExtractorConfig.FILENAME);\n\t\tif (FileSystem.exists(configFilename)) {\n\t\t\tif (FileSystem.exists(path.join(baseFolder, ExtractorConfig.FILENAME))) {\n\t\t\t\tthrow new Error(`Found conflicting ${ExtractorConfig.FILENAME} files in \".\" and \"./config\" folders`);\n\t\t\t}\n\t\t} else {\n\t\t\t// Otherwise try the top-level folder\n\t\t\tconfigFilename = path.join(baseFolder, ExtractorConfig.FILENAME);\n\n\t\t\tif (!FileSystem.exists(configFilename)) {\n\t\t\t\t// API Extractor does not seem to be configured for this folder\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\n\t\tconst configObjectFullPath: string = path.resolve(configFilename);\n\t\tconst configObject: IConfigFile = ExtractorConfig.loadFile(configObjectFullPath);\n\n\t\treturn {\n\t\t\tconfigObject,\n\t\t\tconfigObjectFullPath,\n\t\t\tpackageJsonFullPath,\n\t\t\tprojectFolderLookupToken,\n\t\t};\n\t}\n\n\t/**\n\t * Loads the api-extractor.json config file from the specified file path, and prepares an `ExtractorConfig` object.\n\t *\n\t * @remarks\n\t * Loads the api-extractor.json config file from the specified file path.   If the \"extends\" field is present,\n\t * the referenced file(s) will be merged.  For any omitted fields, the API Extractor default values are merged.\n\t *\n\t * The result is prepared using `ExtractorConfig.prepare()`.\n\t */\n\tpublic static loadFileAndPrepare(configJsonFilePath: string): ExtractorConfig {\n\t\tconst configObjectFullPath: string = path.resolve(configJsonFilePath);\n\t\tconst configObject: IConfigFile = ExtractorConfig.loadFile(configObjectFullPath);\n\n\t\tconst packageJsonLookup: PackageJsonLookup = new PackageJsonLookup();\n\t\tconst packageJsonFullPath: string | undefined =\n\t\t\tpackageJsonLookup.tryGetPackageJsonFilePathFor(configObjectFullPath);\n\n\t\tconst extractorConfig: ExtractorConfig = ExtractorConfig.prepare({\n\t\t\tconfigObject,\n\t\t\tconfigObjectFullPath,\n\t\t\tpackageJsonFullPath,\n\t\t});\n\n\t\treturn extractorConfig;\n\t}\n\n\t/**\n\t * Performs only the first half of {@link ExtractorConfig.loadFileAndPrepare}, providing an opportunity to\n\t * modify the object before it is passed to {@link ExtractorConfig.prepare}.\n\t *\n\t * @remarks\n\t * Loads the api-extractor.json config file from the specified file path.   If the \"extends\" field is present,\n\t * the referenced file(s) will be merged.  For any omitted fields, the API Extractor default values are merged.\n\t */\n\tpublic static loadFile(jsonFilePath: string): IConfigFile {\n\t\t// Set to keep track of config files which have been processed.\n\t\tconst visitedPaths: Set<string> = new Set<string>();\n\n\t\tlet currentConfigFilePath: string = path.resolve(jsonFilePath);\n\t\tlet configObject: Partial<IConfigFile> = {};\n\n\t\ttry {\n\t\t\tdo {\n\t\t\t\t// Check if this file was already processed.\n\t\t\t\tif (visitedPaths.has(currentConfigFilePath)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`The API Extractor \"extends\" setting contains a cycle.` +\n\t\t\t\t\t\t\t`  This file is included twice: \"${currentConfigFilePath}\"`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tvisitedPaths.add(currentConfigFilePath);\n\n\t\t\t\tconst currentConfigFolderPath: string = path.dirname(currentConfigFilePath);\n\n\t\t\t\t// Load the extractor config defined in extends property.\n\t\t\t\tconst baseConfig: IConfigFile = JsonFile.load(currentConfigFilePath);\n\n\t\t\t\tlet extendsField: string = baseConfig.extends ?? '';\n\n\t\t\t\t// Delete the \"extends\" field so it doesn't get merged\n\t\t\t\tdelete baseConfig.extends;\n\n\t\t\t\tif (extendsField) {\n\t\t\t\t\tif (/^\\.\\.?[/\\\\]/.test(extendsField)) {\n\t\t\t\t\t\t// EXAMPLE:  \"./subfolder/api-extractor-base.json\"\n\t\t\t\t\t\textendsField = path.resolve(currentConfigFolderPath, extendsField);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// EXAMPLE:  \"my-package/api-extractor-base.json\"\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// Resolve \"my-package\" from the perspective of the current folder.\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\textendsField = resolve.sync(extendsField, {\n\t\t\t\t\t\t\t\tbasedir: currentConfigFolderPath,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tthrow new Error(`Error resolving NodeJS path \"${extendsField}\": ${(error as Error).message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// This step has to be performed in advance, since the currentConfigFolderPath information will be lost\n\t\t\t\t// after lodash.merge() is performed.\n\t\t\t\tExtractorConfig._resolveConfigFileRelativePaths(baseConfig, currentConfigFolderPath);\n\n\t\t\t\t// Merge extractorConfig into baseConfig, mutating baseConfig\n\t\t\t\tmergeWith(baseConfig, configObject, mergeCustomizer);\n\t\t\t\tconfigObject = baseConfig;\n\n\t\t\t\tcurrentConfigFilePath = extendsField;\n\t\t\t} while (currentConfigFilePath);\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Error loading ${currentConfigFilePath}:\\n` + (error as Error).message);\n\t\t}\n\n\t\t// Lastly, apply the defaults\n\t\tconfigObject = mergeWith(cloneDeep(ExtractorConfig._defaultConfig), configObject, mergeCustomizer);\n\n\t\tExtractorConfig.jsonSchema.validateObject(configObject, jsonFilePath);\n\n\t\t// The schema validation should ensure that this object conforms to IConfigFile\n\t\treturn configObject as IConfigFile;\n\t}\n\n\tprivate static _resolveConfigFileRelativePaths(configFile: IConfigFile, currentConfigFolderPath: string): void {\n\t\tif (configFile.projectFolder) {\n\t\t\tconfigFile.projectFolder = ExtractorConfig._resolveConfigFileRelativePath(\n\t\t\t\t'projectFolder',\n\t\t\t\tconfigFile.projectFolder,\n\t\t\t\tcurrentConfigFolderPath,\n\t\t\t);\n\t\t}\n\n\t\tif (configFile.mainEntryPointFilePath) {\n\t\t\tconfigFile.mainEntryPointFilePath = ExtractorConfig._resolveConfigFileRelativePath(\n\t\t\t\t'mainEntryPointFilePath',\n\t\t\t\tconfigFile.mainEntryPointFilePath,\n\t\t\t\tcurrentConfigFolderPath,\n\t\t\t);\n\t\t}\n\n\t\tif (configFile.additionalEntryPoints) {\n\t\t\tconst entryPointWithAbsolutePath: IConfigEntryPoint[] = [];\n\t\t\tfor (const entryPoint of configFile.additionalEntryPoints) {\n\t\t\t\tconst absoluteFilePath: string = ExtractorConfig._resolveConfigFileRelativePath(\n\t\t\t\t\t'additionalEntryPoints',\n\t\t\t\t\tentryPoint.filePath,\n\t\t\t\t\tcurrentConfigFolderPath,\n\t\t\t\t);\n\n\t\t\t\tentryPointWithAbsolutePath.push({ ...entryPoint, filePath: absoluteFilePath });\n\t\t\t}\n\n\t\t\tconfigFile.additionalEntryPoints = entryPointWithAbsolutePath;\n\t\t}\n\n\t\tif (configFile.compiler?.tsconfigFilePath) {\n\t\t\tconfigFile.compiler.tsconfigFilePath = ExtractorConfig._resolveConfigFileRelativePath(\n\t\t\t\t'tsconfigFilePath',\n\t\t\t\tconfigFile.compiler.tsconfigFilePath,\n\t\t\t\tcurrentConfigFolderPath,\n\t\t\t);\n\t\t}\n\n\t\tif (configFile.apiReport) {\n\t\t\tif (configFile.apiReport.reportFolder) {\n\t\t\t\tconfigFile.apiReport.reportFolder = ExtractorConfig._resolveConfigFileRelativePath(\n\t\t\t\t\t'reportFolder',\n\t\t\t\t\tconfigFile.apiReport.reportFolder,\n\t\t\t\t\tcurrentConfigFolderPath,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (configFile.apiReport.reportTempFolder) {\n\t\t\t\tconfigFile.apiReport.reportTempFolder = ExtractorConfig._resolveConfigFileRelativePath(\n\t\t\t\t\t'reportTempFolder',\n\t\t\t\t\tconfigFile.apiReport.reportTempFolder,\n\t\t\t\t\tcurrentConfigFolderPath,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (configFile.docModel?.apiJsonFilePath) {\n\t\t\tconfigFile.docModel.apiJsonFilePath = ExtractorConfig._resolveConfigFileRelativePath(\n\t\t\t\t'apiJsonFilePath',\n\t\t\t\tconfigFile.docModel.apiJsonFilePath,\n\t\t\t\tcurrentConfigFolderPath,\n\t\t\t);\n\t\t}\n\n\t\tif (configFile.dtsRollup) {\n\t\t\tif (configFile.dtsRollup.untrimmedFilePath) {\n\t\t\t\tconfigFile.dtsRollup.untrimmedFilePath = ExtractorConfig._resolveConfigFileRelativePath(\n\t\t\t\t\t'untrimmedFilePath',\n\t\t\t\t\tconfigFile.dtsRollup.untrimmedFilePath,\n\t\t\t\t\tcurrentConfigFolderPath,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (configFile.dtsRollup.alphaTrimmedFilePath) {\n\t\t\t\tconfigFile.dtsRollup.alphaTrimmedFilePath = ExtractorConfig._resolveConfigFileRelativePath(\n\t\t\t\t\t'alphaTrimmedFilePath',\n\t\t\t\t\tconfigFile.dtsRollup.alphaTrimmedFilePath,\n\t\t\t\t\tcurrentConfigFolderPath,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (configFile.dtsRollup.betaTrimmedFilePath) {\n\t\t\t\tconfigFile.dtsRollup.betaTrimmedFilePath = ExtractorConfig._resolveConfigFileRelativePath(\n\t\t\t\t\t'betaTrimmedFilePath',\n\t\t\t\t\tconfigFile.dtsRollup.betaTrimmedFilePath,\n\t\t\t\t\tcurrentConfigFolderPath,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (configFile.dtsRollup.publicTrimmedFilePath) {\n\t\t\t\tconfigFile.dtsRollup.publicTrimmedFilePath = ExtractorConfig._resolveConfigFileRelativePath(\n\t\t\t\t\t'publicTrimmedFilePath',\n\t\t\t\t\tconfigFile.dtsRollup.publicTrimmedFilePath,\n\t\t\t\t\tcurrentConfigFolderPath,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (configFile.tsdocMetadata?.tsdocMetadataFilePath) {\n\t\t\tconfigFile.tsdocMetadata.tsdocMetadataFilePath = ExtractorConfig._resolveConfigFileRelativePath(\n\t\t\t\t'tsdocMetadataFilePath',\n\t\t\t\tconfigFile.tsdocMetadata.tsdocMetadataFilePath,\n\t\t\t\tcurrentConfigFolderPath,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate static _resolveConfigFileRelativePath(\n\t\t_fieldName: string,\n\t\tfieldValue: string,\n\t\tcurrentConfigFolderPath: string,\n\t): string {\n\t\tif (!path.isAbsolute(fieldValue) && !fieldValue.startsWith('<projectFolder>')) {\n\t\t\t// If the path is not absolute and does not start with \"<projectFolder>\", then resolve it relative\n\t\t\t// to the folder of the config file that it appears in\n\t\t\treturn path.join(currentConfigFolderPath, fieldValue);\n\t\t}\n\n\t\treturn fieldValue;\n\t}\n\n\t/**\n\t * Prepares an `ExtractorConfig` object using a configuration that is provided as a runtime object,\n\t * rather than reading it from disk.  This allows configurations to be constructed programmatically,\n\t * loaded from an alternate source, and/or customized after loading.\n\t */\n\tpublic static prepare(options: IExtractorConfigPrepareOptions): ExtractorConfig {\n\t\tconst filenameForErrors: string = options.configObjectFullPath ?? 'the configuration object';\n\t\tconst configObject: Partial<IConfigFile> = options.configObject;\n\n\t\tif (configObject.extends) {\n\t\t\tthrow new Error('The IConfigFile.extends field must be expanded before calling ExtractorConfig.prepare()');\n\t\t}\n\n\t\tif (options.configObjectFullPath && !path.isAbsolute(options.configObjectFullPath)) {\n\t\t\tthrow new Error('The \"configObjectFullPath\" setting must be an absolute path');\n\t\t}\n\n\t\tExtractorConfig.jsonSchema.validateObject(configObject, filenameForErrors);\n\n\t\tconst packageJsonFullPath: string | undefined = options.packageJsonFullPath;\n\t\tlet packageFolder: string | undefined;\n\t\tlet packageJson: INodePackageJson | undefined;\n\n\t\tif (packageJsonFullPath) {\n\t\t\tif (!/.json$/i.test(packageJsonFullPath)) {\n\t\t\t\t// Catch common mistakes e.g. where someone passes a folder path instead of a file path\n\t\t\t\tthrow new Error('The \"packageJsonFullPath\" setting does not have a .json file extension');\n\t\t\t}\n\n\t\t\tif (!path.isAbsolute(packageJsonFullPath)) {\n\t\t\t\tthrow new Error('The \"packageJsonFullPath\" setting must be an absolute path');\n\t\t\t}\n\n\t\t\tif (options.packageJson) {\n\t\t\t\tpackageJson = options.packageJson;\n\t\t\t} else {\n\t\t\t\tconst packageJsonLookup: PackageJsonLookup = new PackageJsonLookup();\n\t\t\t\tpackageJson = packageJsonLookup.loadNodePackageJson(packageJsonFullPath);\n\t\t\t}\n\n\t\t\tpackageFolder = path.dirname(packageJsonFullPath);\n\t\t}\n\n\t\t// \"tsdocConfigFile\" and \"tsdocConfiguration\" are prepared outside the try-catch block,\n\t\t// so that if exceptions are thrown, it will not get the \"Error parsing api-extractor.json:\" header\n\t\tlet extractorConfigParameters: Omit<IExtractorConfigParameters, 'tsdocConfigFile' | 'tsdocConfiguration'>;\n\n\t\ttry {\n\t\t\tif (!configObject.compiler) {\n\t\t\t\t// A merged configuration should have this\n\t\t\t\tthrow new Error('The \"compiler\" section is missing');\n\t\t\t}\n\n\t\t\tif (!configObject.projectFolder) {\n\t\t\t\t// A merged configuration should have this\n\t\t\t\tthrow new Error('The \"projectFolder\" setting is missing');\n\t\t\t}\n\n\t\t\tlet projectFolder: string;\n\t\t\tif (configObject.projectFolder.trim() === '<lookup>') {\n\t\t\t\tif (options.projectFolderLookupToken) {\n\t\t\t\t\t// Use the manually specified \"<lookup>\" value\n\t\t\t\t\tprojectFolder = options.projectFolderLookupToken;\n\n\t\t\t\t\tif (!FileSystem.exists(options.projectFolderLookupToken)) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t'The specified \"projectFolderLookupToken\" path does not exist: ' + options.projectFolderLookupToken,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (!options.configObjectFullPath) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t'The \"projectFolder\" setting uses the \"<lookup>\" token, but it cannot be expanded because' +\n\t\t\t\t\t\t\t\t' the \"configObjectFullPath\" setting was not specified',\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// \"The default value for `projectFolder` is the token `<lookup>`, which means the folder is determined\n\t\t\t\t\t// by traversing parent folders, starting from the folder containing api-extractor.json, and stopping\n\t\t\t\t\t// at the first folder that contains a tsconfig.json file.  If a tsconfig.json file cannot be found in\n\t\t\t\t\t// this way, then an error will be reported.\"\n\n\t\t\t\t\tlet currentFolder: string = path.dirname(options.configObjectFullPath);\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tconst tsconfigPath: string = path.join(currentFolder, 'tsconfig.json');\n\t\t\t\t\t\tif (FileSystem.exists(tsconfigPath)) {\n\t\t\t\t\t\t\tprojectFolder = currentFolder;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst parentFolder: string = path.dirname(currentFolder);\n\t\t\t\t\t\tif (parentFolder === '' || parentFolder === currentFolder) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t'The \"projectFolder\" setting uses the \"<lookup>\" token, but a tsconfig.json file cannot be' +\n\t\t\t\t\t\t\t\t\t' found in this folder or any parent folder.',\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcurrentFolder = parentFolder;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tExtractorConfig._rejectAnyTokensInPath(configObject.projectFolder, 'projectFolder');\n\n\t\t\t\tif (!FileSystem.exists(configObject.projectFolder)) {\n\t\t\t\t\tthrow new Error('The specified \"projectFolder\" path does not exist: ' + configObject.projectFolder);\n\t\t\t\t}\n\n\t\t\t\tprojectFolder = configObject.projectFolder;\n\t\t\t}\n\n\t\t\tconst tokenContext: IExtractorConfigTokenContext = {\n\t\t\t\tunscopedPackageName: 'unknown-package',\n\t\t\t\tpackageName: 'unknown-package',\n\t\t\t\tprojectFolder,\n\t\t\t};\n\n\t\t\tif (packageJson) {\n\t\t\t\ttokenContext.packageName = packageJson.name;\n\t\t\t\ttokenContext.unscopedPackageName = PackageName.getUnscopedName(packageJson.name);\n\t\t\t}\n\n\t\t\tif (!configObject.mainEntryPointFilePath) {\n\t\t\t\t// A merged configuration should have this\n\t\t\t\tthrow new Error('The \"mainEntryPointFilePath\" setting is missing');\n\t\t\t}\n\n\t\t\tconst mainEntryPointFilePath: string = ExtractorConfig._resolvePathWithTokens(\n\t\t\t\t'mainEntryPointFilePath',\n\t\t\t\tconfigObject.mainEntryPointFilePath,\n\t\t\t\ttokenContext,\n\t\t\t);\n\n\t\t\tconst mainEntryPointName = configObject.mainEntryPointName ?? '';\n\n\t\t\tif (!ExtractorConfig.hasDtsFileExtension(mainEntryPointFilePath)) {\n\t\t\t\tthrow new Error('The \"mainEntryPointFilePath\" value is not a declaration file: ' + mainEntryPointFilePath);\n\t\t\t}\n\n\t\t\tif (!options.ignoreMissingEntryPoint && !FileSystem.exists(mainEntryPointFilePath)) {\n\t\t\t\tthrow new Error('The \"mainEntryPointFilePath\" path does not exist: ' + mainEntryPointFilePath);\n\t\t\t}\n\n\t\t\tconst additionalEntryPoints: IConfigEntryPoint[] = [];\n\t\t\tfor (const entryPoint of configObject.additionalEntryPoints || []) {\n\t\t\t\tconst absoluteEntryPointFilePath: string = ExtractorConfig._resolvePathWithTokens(\n\t\t\t\t\t'entryPointFilePath',\n\t\t\t\t\tentryPoint.filePath,\n\t\t\t\t\ttokenContext,\n\t\t\t\t);\n\n\t\t\t\tif (!ExtractorConfig.hasDtsFileExtension(absoluteEntryPointFilePath)) {\n\t\t\t\t\tthrow new Error('The \"additionalEntryPoints\" value is not a declaration file: ' + absoluteEntryPointFilePath);\n\t\t\t\t}\n\n\t\t\t\tif (!FileSystem.exists(absoluteEntryPointFilePath)) {\n\t\t\t\t\tthrow new Error('The \"additionalEntryPoints\" path does not exist: ' + absoluteEntryPointFilePath);\n\t\t\t\t}\n\n\t\t\t\tadditionalEntryPoints.push({ ...entryPoint, filePath: absoluteEntryPointFilePath });\n\t\t\t}\n\n\t\t\tconst bundledPackages: string[] = configObject.bundledPackages ?? [];\n\t\t\tfor (const bundledPackage of bundledPackages) {\n\t\t\t\tif (!PackageName.isValidName(bundledPackage)) {\n\t\t\t\t\tthrow new Error(`The \"bundledPackages\" list contains an invalid package name: \"${bundledPackage}\"`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst tsconfigFilePath: string = ExtractorConfig._resolvePathWithTokens(\n\t\t\t\t'tsconfigFilePath',\n\t\t\t\tconfigObject.compiler.tsconfigFilePath,\n\t\t\t\ttokenContext,\n\t\t\t);\n\n\t\t\tif (configObject.compiler.overrideTsconfig === undefined) {\n\t\t\t\tif (!tsconfigFilePath) {\n\t\t\t\t\tthrow new Error('Either the \"tsconfigFilePath\" or \"overrideTsconfig\" setting must be specified');\n\t\t\t\t}\n\n\t\t\t\tif (!FileSystem.exists(tsconfigFilePath)) {\n\t\t\t\t\tthrow new Error('The file referenced by \"tsconfigFilePath\" does not exist: ' + tsconfigFilePath);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (configObject.apiReport?.tagsToReport) {\n\t\t\t\t_validateTagsToReport(configObject.apiReport.tagsToReport);\n\t\t\t}\n\n\t\t\tconst apiReportEnabled: boolean = configObject.apiReport?.enabled ?? false;\n\t\t\tconst apiReportIncludeForgottenExports: boolean = configObject.apiReport?.includeForgottenExports ?? false;\n\t\t\tlet reportFolder: string = tokenContext.projectFolder;\n\t\t\tlet reportTempFolder: string = tokenContext.projectFolder;\n\t\t\tconst reportConfigs: IExtractorConfigApiReport[] = [];\n\t\t\tlet tagsToReport: Record<`@${string}`, boolean> = {};\n\t\t\tif (apiReportEnabled) {\n\t\t\t\t// Undefined case checked above where we assign `apiReportEnabled`\n\t\t\t\tconst apiReportConfig: IConfigApiReport = configObject.apiReport!;\n\n\t\t\t\tconst reportFileNameSuffix = '.api.md';\n\t\t\t\tlet reportFileNameBase: string;\n\t\t\t\tif (apiReportConfig.reportFileName) {\n\t\t\t\t\tif (apiReportConfig.reportFileName.includes('/') || apiReportConfig.reportFileName.includes('\\\\')) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`The \"reportFileName\" setting contains invalid characters: \"${apiReportConfig.reportFileName}\"`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (apiReportConfig.reportFileName.endsWith(reportFileNameSuffix)) {\n\t\t\t\t\t\t// The system previously asked users to specify their filenames in a form containing the `.api.md` extension.\n\t\t\t\t\t\t// This guidance has changed, but to maintain backwards compatibility, we will temporarily support input\n\t\t\t\t\t\t// that ends with the `.api.md` extension specially, by stripping it out.\n\t\t\t\t\t\t// This should be removed in version 8, possibly replaced with an explicit error to help users\n\t\t\t\t\t\t// migrate their configs.\n\t\t\t\t\t\treportFileNameBase = apiReportConfig.reportFileName.slice(0, -reportFileNameSuffix.length);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// `.api.md` extension was not specified. Use provided file name base as is.\n\t\t\t\t\t\treportFileNameBase = apiReportConfig.reportFileName;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Default value\n\t\t\t\t\treportFileNameBase = '<unscopedPackageName>';\n\t\t\t\t}\n\n\t\t\t\tconst reportVariantKinds: readonly ApiReportVariant[] =\n\t\t\t\t\tapiReportConfig.reportVariants ?? defaultApiReportVariants;\n\n\t\t\t\tfor (const reportVariantKind of reportVariantKinds) {\n\t\t\t\t\t// Omit the variant kind from the \"complete\" report file name for simplicity and for backwards compatibility.\n\t\t\t\t\tconst fileNameWithTokens = `${reportFileNameBase}${\n\t\t\t\t\t\treportVariantKind === 'complete' ? '' : `.${reportVariantKind}`\n\t\t\t\t\t}${reportFileNameSuffix}`;\n\t\t\t\t\tconst normalizedFileName: string = ExtractorConfig._expandStringWithTokens(\n\t\t\t\t\t\t'reportFileName',\n\t\t\t\t\t\tfileNameWithTokens,\n\t\t\t\t\t\ttokenContext,\n\t\t\t\t\t);\n\n\t\t\t\t\treportConfigs.push({\n\t\t\t\t\t\tfileName: normalizedFileName,\n\t\t\t\t\t\tvariant: reportVariantKind,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (apiReportConfig.reportFolder) {\n\t\t\t\t\treportFolder = ExtractorConfig._resolvePathWithTokens(\n\t\t\t\t\t\t'reportFolder',\n\t\t\t\t\t\tapiReportConfig.reportFolder,\n\t\t\t\t\t\ttokenContext,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (apiReportConfig.reportTempFolder) {\n\t\t\t\t\treportTempFolder = ExtractorConfig._resolvePathWithTokens(\n\t\t\t\t\t\t'reportTempFolder',\n\t\t\t\t\t\tapiReportConfig.reportTempFolder,\n\t\t\t\t\t\ttokenContext,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\ttagsToReport = {\n\t\t\t\t\t...defaultTagsToReport,\n\t\t\t\t\t...apiReportConfig.tagsToReport,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tlet docModelGenerationOptions: IApiModelGenerationOptions | undefined;\n\t\t\tlet apiJsonFilePath = '';\n\t\t\tlet docModelIncludeForgottenExports = false;\n\t\t\tlet projectFolderUrl: string | undefined;\n\t\t\tif (configObject.docModel?.enabled) {\n\t\t\t\tapiJsonFilePath = ExtractorConfig._resolvePathWithTokens(\n\t\t\t\t\t'apiJsonFilePath',\n\t\t\t\t\tconfigObject.docModel.apiJsonFilePath,\n\t\t\t\t\ttokenContext,\n\t\t\t\t);\n\t\t\t\tdocModelIncludeForgottenExports = Boolean(configObject.docModel.includeForgottenExports);\n\t\t\t\tprojectFolderUrl = configObject.docModel.projectFolderUrl;\n\n\t\t\t\tconst releaseTagsToTrim: Set<ReleaseTag> = new Set<ReleaseTag>();\n\t\t\t\tconst releaseTagsToTrimOption: string[] = configObject.docModel.releaseTagsToTrim || ['@internal'];\n\t\t\t\tfor (const releaseTagToTrim of releaseTagsToTrimOption) {\n\t\t\t\t\tlet releaseTag: ReleaseTag;\n\t\t\t\t\tswitch (releaseTagToTrim) {\n\t\t\t\t\t\tcase '@internal': {\n\t\t\t\t\t\t\treleaseTag = ReleaseTag.Internal;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase '@alpha': {\n\t\t\t\t\t\t\treleaseTag = ReleaseTag.Alpha;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase '@beta': {\n\t\t\t\t\t\t\treleaseTag = ReleaseTag.Beta;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase '@public': {\n\t\t\t\t\t\t\treleaseTag = ReleaseTag.Public;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\tthrow new Error(`The release tag \"${releaseTagToTrim}\" is not supported`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treleaseTagsToTrim.add(releaseTag);\n\t\t\t\t}\n\n\t\t\t\tdocModelGenerationOptions = {\n\t\t\t\t\treleaseTagsToTrim,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tlet tsdocMetadataEnabled = false;\n\t\t\tlet tsdocMetadataFilePath = '';\n\t\t\tif (configObject.tsdocMetadata) {\n\t\t\t\ttsdocMetadataEnabled = Boolean(configObject.tsdocMetadata.enabled);\n\n\t\t\t\tif (tsdocMetadataEnabled) {\n\t\t\t\t\ttsdocMetadataFilePath = configObject.tsdocMetadata.tsdocMetadataFilePath ?? '';\n\n\t\t\t\t\tif (tsdocMetadataFilePath.trim() === '<lookup>') {\n\t\t\t\t\t\tif (!packageJson) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t'The \"<lookup>\" token cannot be used with the \"tsdocMetadataFilePath\" setting because' +\n\t\t\t\t\t\t\t\t\t' the \"packageJson\" option was not provided',\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!packageJsonFullPath) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t'The \"<lookup>\" token cannot be used with \"tsdocMetadataFilePath\" because' +\n\t\t\t\t\t\t\t\t\t'the \"packageJsonFullPath\" option was not provided',\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttsdocMetadataFilePath = PackageMetadataManager.resolveTsdocMetadataPath(\n\t\t\t\t\t\t\tpath.dirname(packageJsonFullPath),\n\t\t\t\t\t\t\tpackageJson,\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttsdocMetadataFilePath = ExtractorConfig._resolvePathWithTokens(\n\t\t\t\t\t\t\t'tsdocMetadataFilePath',\n\t\t\t\t\t\t\tconfigObject.tsdocMetadata.tsdocMetadataFilePath,\n\t\t\t\t\t\t\ttokenContext,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!tsdocMetadataFilePath) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t'The \"tsdocMetadata.enabled\" setting is enabled, but \"tsdocMetadataFilePath\" is not specified',\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet rollupEnabled = false;\n\t\t\tlet untrimmedFilePath = '';\n\t\t\tlet betaTrimmedFilePath = '';\n\t\t\tlet alphaTrimmedFilePath = '';\n\t\t\tlet publicTrimmedFilePath = '';\n\t\t\tlet omitTrimmingComments = false;\n\n\t\t\tif (configObject.dtsRollup) {\n\t\t\t\trollupEnabled = Boolean(configObject.dtsRollup.enabled);\n\n\t\t\t\t// d.ts rollup is not supported when there are more than one entry points.\n\t\t\t\tif (rollupEnabled && additionalEntryPoints.length > 0) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`It seems that you have dtsRollup enabled while you also have defined additionalEntryPoints.` +\n\t\t\t\t\t\t\t`dtsRollup is not supported when there are multiple entry points in your package`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tuntrimmedFilePath = ExtractorConfig._resolvePathWithTokens(\n\t\t\t\t\t'untrimmedFilePath',\n\t\t\t\t\tconfigObject.dtsRollup.untrimmedFilePath,\n\t\t\t\t\ttokenContext,\n\t\t\t\t);\n\t\t\t\talphaTrimmedFilePath = ExtractorConfig._resolvePathWithTokens(\n\t\t\t\t\t'alphaTrimmedFilePath',\n\t\t\t\t\tconfigObject.dtsRollup.alphaTrimmedFilePath,\n\t\t\t\t\ttokenContext,\n\t\t\t\t);\n\t\t\t\tbetaTrimmedFilePath = ExtractorConfig._resolvePathWithTokens(\n\t\t\t\t\t'betaTrimmedFilePath',\n\t\t\t\t\tconfigObject.dtsRollup.betaTrimmedFilePath,\n\t\t\t\t\ttokenContext,\n\t\t\t\t);\n\t\t\t\tpublicTrimmedFilePath = ExtractorConfig._resolvePathWithTokens(\n\t\t\t\t\t'publicTrimmedFilePath',\n\t\t\t\t\tconfigObject.dtsRollup.publicTrimmedFilePath,\n\t\t\t\t\ttokenContext,\n\t\t\t\t);\n\t\t\t\tomitTrimmingComments = Boolean(configObject.dtsRollup.omitTrimmingComments);\n\t\t\t}\n\n\t\t\tlet newlineKind: NewlineKind;\n\t\t\tswitch (configObject.newlineKind) {\n\t\t\t\tcase 'lf':\n\t\t\t\t\tnewlineKind = NewlineKind.Lf;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'os':\n\t\t\t\t\tnewlineKind = NewlineKind.OsDefault;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tnewlineKind = NewlineKind.CrLf;\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst enumMemberOrder: EnumMemberOrder = configObject.enumMemberOrder ?? EnumMemberOrder.ByName;\n\n\t\t\textractorConfigParameters = {\n\t\t\t\tprojectFolder,\n\t\t\t\tpackageJson,\n\t\t\t\tpackageFolder,\n\t\t\t\tmainEntryPointFilePath,\n\t\t\t\tmainEntryPointName,\n\t\t\t\tadditionalEntryPoints,\n\t\t\t\tbundledPackages,\n\t\t\t\ttsconfigFilePath,\n\t\t\t\toverrideTsconfig: configObject.compiler.overrideTsconfig,\n\t\t\t\tskipLibCheck: Boolean(configObject.compiler.skipLibCheck),\n\t\t\t\tapiReportEnabled,\n\t\t\t\treportConfigs,\n\t\t\t\treportFolder,\n\t\t\t\treportTempFolder,\n\t\t\t\tapiReportIncludeForgottenExports,\n\t\t\t\ttagsToReport,\n\t\t\t\tdocModelGenerationOptions,\n\t\t\t\tapiJsonFilePath,\n\t\t\t\tdocModelIncludeForgottenExports,\n\t\t\t\tprojectFolderUrl,\n\t\t\t\trollupEnabled,\n\t\t\t\tuntrimmedFilePath,\n\t\t\t\talphaTrimmedFilePath,\n\t\t\t\tbetaTrimmedFilePath,\n\t\t\t\tpublicTrimmedFilePath,\n\t\t\t\tomitTrimmingComments,\n\t\t\t\ttsdocMetadataEnabled,\n\t\t\t\ttsdocMetadataFilePath,\n\t\t\t\tnewlineKind,\n\t\t\t\tmessages: configObject.messages ?? {},\n\t\t\t\ttestMode: Boolean(configObject.testMode),\n\t\t\t\tenumMemberOrder,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Error parsing ${filenameForErrors}:\\n` + (error as Error).message);\n\t\t}\n\n\t\tlet tsdocConfigFile: TSDocConfigFile | undefined = options.tsdocConfigFile;\n\n\t\tif (!tsdocConfigFile) {\n\t\t\t// Example: \"my-project/tsdoc.json\"\n\t\t\tlet packageTSDocConfigPath: string = TSDocConfigFile.findConfigPathForFolder(\n\t\t\t\textractorConfigParameters.projectFolder,\n\t\t\t);\n\n\t\t\tif (!packageTSDocConfigPath || !FileSystem.exists(packageTSDocConfigPath)) {\n\t\t\t\t// If the project does not have a tsdoc.json config file, then use API Extractor's base file.\n\t\t\t\tpackageTSDocConfigPath = ExtractorConfig._tsdocBaseFilePath;\n\t\t\t\tif (!FileSystem.exists(packageTSDocConfigPath)) {\n\t\t\t\t\tthrow new InternalError('Unable to load the built-in TSDoc config file: ' + packageTSDocConfigPath);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttsdocConfigFile = TSDocConfigFile.loadFile(packageTSDocConfigPath);\n\t\t}\n\n\t\t// IMPORTANT: After calling TSDocConfigFile.loadFile(), we need to check for errors.\n\t\tif (tsdocConfigFile.hasErrors) {\n\t\t\tthrow new Error(tsdocConfigFile.getErrorSummary());\n\t\t}\n\n\t\tconst tsdocConfiguration: TSDocConfiguration = new TSDocConfiguration();\n\t\ttsdocConfigFile.configureParser(tsdocConfiguration);\n\n\t\t// IMPORTANT: After calling TSDocConfigFile.configureParser(), we need to check for errors a second time.\n\t\tif (tsdocConfigFile.hasErrors) {\n\t\t\tthrow new Error(tsdocConfigFile.getErrorSummary());\n\t\t}\n\n\t\treturn new ExtractorConfig({ ...extractorConfigParameters, tsdocConfigFile, tsdocConfiguration });\n\t}\n\n\t/**\n\t * Gets the report configuration for the \"complete\" (default) report configuration, if one was specified.\n\t */\n\tprivate _getCompleteReportConfig(): IExtractorConfigApiReport | undefined {\n\t\treturn this.reportConfigs.find((x) => x.variant === 'complete');\n\t}\n\n\tprivate static _resolvePathWithTokens(\n\t\tfieldName: string,\n\t\tvalue: string | undefined,\n\t\ttokenContext: IExtractorConfigTokenContext,\n\t): string {\n\t\tconst returnValue = ExtractorConfig._expandStringWithTokens(fieldName, value, tokenContext);\n\t\tif (returnValue !== '') {\n\t\t\treturn path.resolve(tokenContext.projectFolder, returnValue);\n\t\t}\n\n\t\treturn returnValue;\n\t}\n\n\tprivate static _expandStringWithTokens(\n\t\tfieldName: string,\n\t\tvalue: string | undefined,\n\t\ttokenContext: IExtractorConfigTokenContext,\n\t): string {\n\t\tlet returnValue = value ? value.trim() : '';\n\t\tif (returnValue !== '') {\n\t\t\treturnValue = Text.replaceAll(returnValue, '<unscopedPackageName>', tokenContext.unscopedPackageName);\n\t\t\treturnValue = Text.replaceAll(returnValue, '<packageName>', tokenContext.packageName);\n\n\t\t\tconst projectFolderToken = '<projectFolder>';\n\t\t\tif (returnValue.startsWith(projectFolderToken)) {\n\t\t\t\t// Replace \"<projectFolder>\" at the start of a string\n\t\t\t\treturnValue = path.join(tokenContext.projectFolder, returnValue.slice(projectFolderToken.length));\n\t\t\t}\n\n\t\t\tif (returnValue.includes(projectFolderToken)) {\n\t\t\t\t// If after all replacements, \"<projectFolder>\" appears somewhere in the string, report an error\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`The \"${fieldName}\" value incorrectly uses the \"<projectFolder>\" token.` +\n\t\t\t\t\t\t` It must appear at the start of the string.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (returnValue.includes('<lookup>')) {\n\t\t\t\tthrow new Error(`The \"${fieldName}\" value incorrectly uses the \"<lookup>\" token`);\n\t\t\t}\n\n\t\t\tExtractorConfig._rejectAnyTokensInPath(returnValue, fieldName);\n\t\t}\n\n\t\treturn returnValue;\n\t}\n\n\t/**\n\t * Returns true if the specified file path has the \".d.ts\" file extension.\n\t */\n\tpublic static hasDtsFileExtension(filePath: string): boolean {\n\t\treturn ExtractorConfig._declarationFileExtensionRegExp.test(filePath);\n\t}\n\n\t/**\n\t * Given a path string that may have originally contained expandable tokens such as `<projectFolder>\"`\n\t * this reports an error if any token-looking substrings remain after expansion (e.g. `c:\\blah\\<invalid>\\blah`).\n\t */\n\tprivate static _rejectAnyTokensInPath(value: string, fieldName: string): void {\n\t\tif (!value.includes('<') && !value.includes('>')) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Can we determine the name of a token?\n\t\tconst tokenRegExp = /(?<token><[^<]*?>)/;\n\t\tconst match: RegExpExecArray | null = tokenRegExp.exec(value);\n\t\tif (match?.groups?.token) {\n\t\t\tthrow new Error(`The \"${fieldName}\" value contains an unrecognized token \"${match.groups.token}\"`);\n\t\t}\n\n\t\tthrow new Error(`The \"${fieldName}\" value contains extra token characters (\"<\" or \">\"): ${value}`);\n\t}\n}\n\nconst releaseTags: Set<string> = new Set(['@public', '@alpha', '@beta', '@internal']);\n\n/**\n * Validate {@link ExtractorConfig.tagsToReport}.\n */\nfunction _validateTagsToReport(\n\ttagsToReport: Record<string, boolean>,\n): asserts tagsToReport is Record<`@${string}`, boolean> {\n\tconst includedReleaseTags: string[] = [];\n\tconst invalidTags: [string, string][] = []; // tag name, error\n\tfor (const tag of Object.keys(tagsToReport)) {\n\t\tif (releaseTags.has(tag)) {\n\t\t\t// If a release tags is specified, regardless of whether it is enabled, we will throw an error.\n\t\t\t// Release tags must not be specified.\n\t\t\tincludedReleaseTags.push(tag);\n\t\t}\n\n\t\t// If the tag is invalid, generate an error string from the inner error message.\n\t\ttry {\n\t\t\tTSDocTagDefinition.validateTSDocTagName(tag);\n\t\t} catch (error) {\n\t\t\tinvalidTags.push([tag, (error as Error).message]);\n\t\t}\n\t}\n\n\tconst errorMessages: string[] = [];\n\tfor (const includedReleaseTag of includedReleaseTags) {\n\t\terrorMessages.push(\n\t\t\t`${includedReleaseTag}: Release tags are always included in API reports and must not be specified`,\n\t\t);\n\t}\n\n\tfor (const [invalidTag, innerError] of invalidTags) {\n\t\terrorMessages.push(`${invalidTag}: ${innerError}`);\n\t}\n\n\tif (errorMessages.length > 0) {\n\t\tconst errorMessage: string = [`\"tagsToReport\" contained one or more invalid tags:`, ...errorMessages].join(\n\t\t\t'\\n\\t- ',\n\t\t);\n\t\tthrow new Error(errorMessage);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/api/ExtractorLogLevel.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * Used with {@link IConfigMessageReportingRule.logLevel} and {@link IExtractorInvokeOptions.messageCallback}.\n *\n * @remarks\n * This is part of the {@link IConfigFile} structure.\n * @public\n */\nexport const enum ExtractorLogLevel {\n\t/**\n\t * The message will be displayed as an error.\n\t *\n\t * @remarks\n\t * Errors typically cause the build to fail and return a nonzero exit code.\n\t */\n\tError = 'error',\n\n\t/**\n\t * The message will be displayed as an informational message.\n\t *\n\t * @remarks\n\t * Informational messages may contain newlines to ensure nice formatting of the output,\n\t * however word-wrapping is the responsibility of the message handler.\n\t */\n\tInfo = 'info',\n\n\t/**\n\t * The message will be discarded entirely.\n\t */\n\tNone = 'none',\n\n\t/**\n\t * The message will be displayed only when \"verbose\" output is requested, e.g. using the `--verbose`\n\t * command line option.\n\t */\n\tVerbose = 'verbose',\n\n\t/**\n\t * The message will be displayed as an warning.\n\t *\n\t * @remarks\n\t * Warnings typically cause a production build fail and return a nonzero exit code.  For a non-production build\n\t * (e.g. using the `--local` option with `api-extractor run`), the warning is displayed but the build will not fail.\n\t */\n\tWarning = 'warning',\n}\n"
  },
  {
    "path": "packages/api-extractor/src/api/ExtractorMessage.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type * as tsdoc from '@microsoft/tsdoc';\nimport { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter.js';\nimport type { ConsoleMessageId } from './ConsoleMessageId.js';\nimport { ExtractorLogLevel } from './ExtractorLogLevel.js';\nimport type { ExtractorMessageId } from './ExtractorMessageId.js';\n\n/**\n * Used by {@link ExtractorMessage.properties}.\n *\n * @public\n */\nexport interface IExtractorMessageProperties {\n\t/**\n\t * A declaration can have multiple names if it is exported more than once.\n\t * If an `ExtractorMessage` applies to a specific export name, this property can indicate that.\n\t *\n\t * @remarks\n\t *\n\t * Used by {@link ExtractorMessageId.InternalMissingUnderscore}.\n\t */\n\treadonly exportName?: string;\n}\n\n/**\n * Specifies a category of messages for use with {@link ExtractorMessage}.\n *\n * @public\n */\nexport const enum ExtractorMessageCategory {\n\t/**\n\t * Messages originating from the TypeScript compiler.\n\t *\n\t * @remarks\n\t * These strings begin with the prefix \"TS\" and have a numeric error code.\n\t * Example: `TS2551`\n\t */\n\tCompiler = 'Compiler',\n\n\t/**\n\t * Console messages communicate the progress of the overall operation.  They may include newlines to ensure\n\t * nice formatting.  They are output in real time, and cannot be routed to the API Report file.\n\t *\n\t * @remarks\n\t * These strings begin with the prefix \"console-\".\n\t * Example: `console-writing-typings-file`\n\t */\n\tConsole = 'console',\n\n\t/**\n\t * Messages related to API Extractor's analysis.\n\t *\n\t * @remarks\n\t * These strings begin with the prefix \"ae-\".\n\t * Example: `ae-extra-release-tag`\n\t */\n\tExtractor = 'Extractor',\n\n\t/**\n\t * Messages related to parsing of TSDoc comments.\n\t *\n\t * @remarks\n\t * These strings begin with the prefix \"tsdoc-\".\n\t * Example: `tsdoc-link-tag-unescaped-text`\n\t */\n\tTSDoc = 'TSDoc',\n}\n\n/**\n * Constructor options for `ExtractorMessage`.\n */\nexport interface IExtractorMessageOptions {\n\tcategory: ExtractorMessageCategory;\n\tlogLevel?: ExtractorLogLevel;\n\tmessageId: ConsoleMessageId | ExtractorMessageId | tsdoc.TSDocMessageId | string;\n\tproperties?: IExtractorMessageProperties | undefined;\n\tsourceFileColumn?: number;\n\tsourceFileLine?: number;\n\tsourceFilePath?: string;\n\ttext: string;\n}\n\n/**\n * This object is used to report an error or warning that occurred during API Extractor's analysis.\n *\n * @public\n */\nexport class ExtractorMessage {\n\tprivate _handled: boolean;\n\n\tprivate _logLevel: ExtractorLogLevel;\n\n\t/**\n\t * The category of issue.\n\t */\n\tpublic readonly category: ExtractorMessageCategory;\n\n\t/**\n\t * A text string that uniquely identifies the issue type.  This identifier can be used to suppress\n\t * or configure the reporting of issues, and also to search for help about an issue.\n\t */\n\tpublic readonly messageId: ConsoleMessageId | ExtractorMessageId | tsdoc.TSDocMessageId | string;\n\n\t/**\n\t * The text description of this issue.\n\t */\n\tpublic readonly text: string;\n\n\t/**\n\t * The absolute path to the affected input source file, if there is one.\n\t */\n\tpublic readonly sourceFilePath: string | undefined;\n\n\t/**\n\t * The line number where the issue occurred in the input source file.  This is not used if `sourceFilePath`\n\t * is undefined.  The first line number is 1.\n\t */\n\tpublic readonly sourceFileLine: number | undefined;\n\n\t/**\n\t * The column number where the issue occurred in the input source file.  This is not used if `sourceFilePath`\n\t * is undefined.  The first column number is 1.\n\t */\n\tpublic readonly sourceFileColumn: number | undefined;\n\n\t/**\n\t * Additional contextual information about the message that may be useful when reporting errors.\n\t * All properties are optional.\n\t */\n\tpublic readonly properties: IExtractorMessageProperties;\n\n\t/**\n\t * @internal\n\t */\n\tpublic constructor(options: IExtractorMessageOptions) {\n\t\tthis.category = options.category;\n\t\tthis.messageId = options.messageId;\n\t\tthis.text = options.text;\n\t\tthis.sourceFilePath = options.sourceFilePath;\n\t\tthis.sourceFileLine = options.sourceFileLine;\n\t\tthis.sourceFileColumn = options.sourceFileColumn;\n\t\tthis.properties = options.properties ?? {};\n\n\t\tthis._handled = false;\n\t\tthis._logLevel = options.logLevel ?? ExtractorLogLevel.None;\n\t}\n\n\t/**\n\t * If the {@link IExtractorInvokeOptions.messageCallback} sets this property to true, it will prevent the message\n\t * from being displayed by API Extractor.\n\t *\n\t * @remarks\n\t * If the `messageCallback` routes the message to a custom handler (e.g. a toolchain logger), it should\n\t * assign `handled = true` to prevent API Extractor from displaying it.  Assigning `handled = true` for all messages\n\t * would effectively disable all console output from the `Extractor` API.\n\t *\n\t * If `handled` is set to true, the message will still be included in the count of errors/warnings;\n\t * to discard a message entirely, instead assign `logLevel = none`.\n\t */\n\tpublic get handled(): boolean {\n\t\treturn this._handled;\n\t}\n\n\tpublic set handled(value: boolean) {\n\t\tif (this._handled && !value) {\n\t\t\tthrow new Error('One a message has been marked as handled, the \"handled\" property cannot be set to false');\n\t\t}\n\n\t\tthis._handled = value;\n\t}\n\n\t/**\n\t * Specifies how the message should be reported.\n\t *\n\t * @remarks\n\t * If the {@link IExtractorInvokeOptions.messageCallback} handles the message (i.e. sets `handled = true`),\n\t * it can use the `logLevel` to determine how to display the message.\n\t *\n\t * Alternatively, if API Extractor is handling the message, the `messageCallback` could assign `logLevel` to change\n\t * how it will be processed.  However, in general the recommended practice is to configure message routing\n\t * using the `messages` section in api-extractor.json.\n\t *\n\t * To discard a message entirely, assign `logLevel = none`.\n\t */\n\tpublic get logLevel(): ExtractorLogLevel {\n\t\treturn this._logLevel;\n\t}\n\n\tpublic set logLevel(value: ExtractorLogLevel) {\n\t\tswitch (value) {\n\t\t\tcase ExtractorLogLevel.Error:\n\t\t\tcase ExtractorLogLevel.Info:\n\t\t\tcase ExtractorLogLevel.None:\n\t\t\tcase ExtractorLogLevel.Verbose:\n\t\t\tcase ExtractorLogLevel.Warning:\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new Error('Invalid log level');\n\t\t}\n\n\t\tthis._logLevel = value;\n\t}\n\n\t/**\n\t * Returns the message formatted with its identifier and file position.\n\t *\n\t * @remarks\n\t * Example:\n\t * ```\n\t * src/folder/File.ts:123:4 - (ae-extra-release-tag) The doc comment should not contain more than one release tag.\n\t * ```\n\t */\n\tpublic formatMessageWithLocation(workingPackageFolderPath: string | undefined): string {\n\t\tlet result = '';\n\n\t\tif (this.sourceFilePath) {\n\t\t\tresult += SourceFileLocationFormatter.formatPath(this.sourceFilePath, {\n\t\t\t\tsourceFileLine: this.sourceFileLine,\n\t\t\t\tsourceFileColumn: this.sourceFileColumn,\n\t\t\t\tworkingPackageFolderPath,\n\t\t\t});\n\n\t\t\tif (result.length > 0) {\n\t\t\t\tresult += ' - ';\n\t\t\t}\n\t\t}\n\n\t\tresult += this.formatMessageWithoutLocation();\n\n\t\treturn result;\n\t}\n\n\tpublic formatMessageWithoutLocation(): string {\n\t\treturn `(${this.messageId}) ${this.text}`;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/api/ExtractorMessageId.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * Unique identifiers for messages reported by API Extractor during its analysis.\n *\n * @remarks\n *\n * These strings are possible values for the {@link ExtractorMessage.messageId} property\n * when the `ExtractorMessage.category` is {@link ExtractorMessageCategory.Extractor}.\n * @public\n */\nexport const enum ExtractorMessageId {\n\t/**\n\t * \"The `@inheritDoc` tag for ___ refers to its own declaration.\"\n\t */\n\tCyclicInheritDoc = 'ae-cyclic-inherit-doc',\n\n\t/**\n\t * \"This symbol has another declaration with a different release tag.\"\n\t */\n\tDifferentReleaseTags = 'ae-different-release-tags',\n\n\t/**\n\t * \"The doc comment should not contain more than one release tag.\"\n\t */\n\tExtraReleaseTag = 'ae-extra-release-tag',\n\n\t/**\n\t * \"The symbol ___ needs to be exported by the entry point ___.\"\n\t */\n\tForgottenExport = 'ae-forgotten-export',\n\n\t/**\n\t * \"The symbol ___ is marked as ___, but its signature references ___ which is marked as ___.\"\n\t */\n\tIncompatibleReleaseTags = 'ae-incompatible-release-tags',\n\n\t/**\n\t * \"The name ___ should be prefixed with an underscore because the declaration is marked as `@internal`.\"\n\t */\n\tInternalMissingUnderscore = 'ae-internal-missing-underscore',\n\n\t/**\n\t * \"Mixed release tags are not allowed for ___ because one of its declarations is marked as `@internal`.\"\n\t */\n\tInternalMixedReleaseTag = 'ae-internal-mixed-release-tag',\n\n\t/**\n\t * \"The `@packageDocumentation` comment must appear at the top of entry point *.d.ts file.\"\n\t */\n\tMisplacedPackageTag = 'ae-misplaced-package-tag',\n\n\t/**\n\t * \"The property ___ has a setter but no getter.\"\n\t */\n\tMissingGetter = 'ae-missing-getter',\n\n\t/**\n\t * \"___ is part of the package's API, but it is missing a release tag (`@alpha`, `@beta`, `@public`, or `@internal`).\"\n\t */\n\tMissingReleaseTag = 'ae-missing-release-tag',\n\n\t/**\n\t * \"The `@preapproved` tag cannot be applied to ___ without an `@internal` release tag.\"\n\t */\n\tPreapprovedBadReleaseTag = 'ae-preapproved-bad-release-tag',\n\n\t/**\n\t * \"The `@preapproved` tag cannot be applied to ___ because it is not a supported declaration type.\"\n\t */\n\tPreapprovedUnsupportedType = 'ae-preapproved-unsupported-type',\n\n\t/**\n\t * \"The doc comment for the property ___ must appear on the getter, not the setter.\"\n\t */\n\tSetterWithDocs = 'ae-setter-with-docs',\n\n\t/**\n\t * \"Missing documentation for ___.\"\n\t *\n\t * @remarks\n\t * The `ae-undocumented` message is only generated if the API report feature is enabled.\n\t *\n\t * Because the API report file already annotates undocumented items with `// (undocumented)`,\n\t * the `ae-undocumented` message is not logged by default.  To see it, add a setting such as:\n\t * ```json\n\t * \"messages\": {\n\t *   \"extractorMessageReporting\": {\n\t *     \"ae-undocumented\": {\n\t *       \"logLevel\": \"warning\"\n\t *     }\n\t *   }\n\t *  }\n\t * ```\n\t */\n\tUndocumented = 'ae-undocumented',\n\n\t/**\n\t * \"The `@inheritDoc` tag needs a TSDoc declaration reference; signature matching is not supported yet.\"\n\t *\n\t * @privateRemarks\n\t * In the future, we will implement signature matching so that you can write `@inheritDoc` and API Extractor\n\t * will find a corresponding member from a base class (or implemented interface).  Until then, the tag\n\t * always needs an explicit declaration reference such as `{@inhertDoc MyBaseClass.sameMethod}`.\n\t */\n\tUnresolvedInheritDocBase = 'ae-unresolved-inheritdoc-base',\n\n\t/**\n\t * \"The `@inheritDoc` reference could not be resolved.\"\n\t */\n\tUnresolvedInheritDocReference = 'ae-unresolved-inheritdoc-reference',\n\n\t/**\n\t * \"The `@link` reference could not be resolved.\"\n\t */\n\tUnresolvedLink = 'ae-unresolved-link',\n\n\t/**\n\t * \"Incorrect file type; API Extractor expects to analyze compiler outputs with the .d.ts file extension.\n\t * Troubleshooting tips: `https://api-extractor.com/link/dts-error`\"\n\t */\n\tWrongInputFileType = 'ae-wrong-input-file-type',\n}\n\nexport const allExtractorMessageIds: Set<string> = new Set<string>([\n\t'ae-extra-release-tag',\n\t'ae-undocumented',\n\t'ae-different-release-tags',\n\t'ae-incompatible-release-tags',\n\t'ae-missing-release-tag',\n\t'ae-misplaced-package-tag',\n\t'ae-forgotten-export',\n\t'ae-internal-missing-underscore',\n\t'ae-internal-mixed-release-tag',\n\t'ae-preapproved-unsupported-type',\n\t'ae-preapproved-bad-release-tag',\n\t'ae-unresolved-inheritdoc-reference',\n\t'ae-unresolved-inheritdoc-base',\n\t'ae-cyclic-inherit-doc',\n\t'ae-unresolved-link',\n\t'ae-setter-with-docs',\n\t'ae-missing-getter',\n\t'ae-wrong-input-file-type',\n]);\n"
  },
  {
    "path": "packages/api-extractor/src/api/IConfigFile.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { EnumMemberOrder } from '@discordjs/api-extractor-model';\nimport type { ExtractorLogLevel } from './ExtractorLogLevel.js';\n\n/**\n * Represents an entry point in the package\n * Example:\n * ```\n * {\n *   modulePath: 'Shape/Square',\n *   filePath: './dist/Shape/Square/index.d.ts'\n * }\n * ```\n */\nexport interface IConfigEntryPoint {\n\tfilePath: string;\n\tmodulePath: string;\n}\n\n/**\n * Determines how the TypeScript compiler engine will be invoked by API Extractor.\n *\n * @remarks\n * This is part of the {@link IConfigFile} structure.\n * @public\n */\nexport interface IConfigCompiler {\n\t/**\n\t * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk.\n\t *\n\t * @remarks\n\t * The value must conform to the TypeScript tsconfig schema:\n\t *\n\t * http://json.schemastore.org/tsconfig\n\t *\n\t * If omitted, then the tsconfig.json file will instead be read from the projectFolder.\n\t */\n\toverrideTsconfig?: {};\n\n\t/**\n\t * This option causes the compiler to be invoked with the `--skipLibCheck` option.\n\t *\n\t * @remarks\n\t * This option is not recommended and may cause API Extractor to produce incomplete or incorrect declarations,\n\t * but it may be required when dependencies contain declarations that are incompatible with the TypeScript engine\n\t * that API Extractor uses for its analysis.  Where possible, the underlying issue should be fixed rather than\n\t * relying on skipLibCheck.\n\t */\n\tskipLibCheck?: boolean;\n\n\t/**\n\t * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project.\n\t *\n\t * @remarks\n\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t * prepend a folder token such as `<projectFolder>`.\n\t *\n\t * Note: This setting will be ignored if `overrideTsconfig` is used.\n\t */\n\ttsconfigFilePath?: string;\n}\n\n/**\n * The allowed variations of API reports.\n *\n * @public\n */\nexport type ApiReportVariant = 'alpha' | 'beta' | 'complete' | 'public';\n\n/**\n * Configures how the API report files (*.api.md) will be generated.\n *\n * @remarks\n * This is part of the {@link IConfigFile} structure.\n * @public\n */\nexport interface IConfigApiReport {\n\t/**\n\t * Whether to generate an API report.\n\t */\n\tenabled: boolean;\n\n\t/**\n\t * Whether \"forgotten exports\" should be included in the API report file.\n\t *\n\t * @remarks\n\t * Forgotten exports are declarations flagged with `ae-forgotten-export` warnings. See\n\t * https://api-extractor.com/pages/messages/ae-forgotten-export/ to learn more.\n\t * @defaultValue `false`\n\t */\n\tincludeForgottenExports?: boolean;\n\n\t/**\n\t * The base filename for the API report files, to be combined with {@link IConfigApiReport.reportFolder} or\n\t * {@link IConfigApiReport.reportTempFolder} to produce the full file path.\n\t *\n\t * @remarks\n\t * The `reportFileName` should not include any path separators such as `\\` or `/`.  The `reportFileName` should\n\t * not include a file extension, since API Extractor will automatically append an appropriate file extension such\n\t * as `.api.md`.  If the {@link IConfigApiReport.reportVariants} setting is used, then the file extension includes\n\t * the variant name, for example `my-report.public.api.md` or `my-report.beta.api.md`. The `complete` variant always\n\t * uses the simple extension `my-report.api.md`.\n\t *\n\t * Previous versions of API Extractor required `reportFileName` to include the `.api.md` extension explicitly;\n\t * for backwards compatibility, that is still accepted but will be discarded before applying the above rules.\n\t * @defaultValue `<unscopedPackageName>`\n\t */\n\treportFileName?: string;\n\n\t/**\n\t * Specifies the folder where the API report file is written.  The file name portion is determined by\n\t * the `reportFileName` setting.\n\t *\n\t * @remarks\n\t * The API report file is normally tracked by Git.  Changes to it can be used to trigger a branch policy,\n\t * e.g. for an API review.\n\t *\n\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t * prepend a folder token such as `<projectFolder>`.\n\t */\n\treportFolder?: string;\n\n\t/**\n\t * Specifies the folder where the temporary report file is written.  The file name portion is determined by\n\t * the `reportFileName` setting.\n\t *\n\t * @remarks\n\t * After the temporary file is written to disk, it is compared with the file in the `reportFolder`.\n\t * If they are different, a production build will fail.\n\t *\n\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t * prepend a folder token such as `<projectFolder>`.\n\t */\n\treportTempFolder?: string;\n\n\t/**\n\t * The set of report variants to generate.\n\t *\n\t * @remarks\n\t * To support different approval requirements for different API levels, multiple \"variants\" of the API report can\n\t * be generated.  The `reportVariants` setting specifies a list of variants to be generated.  If omitted,\n\t * by default only the `complete` variant will be generated, which includes all `@internal`, `@alpha`, `@beta`,\n\t * and `@public` items.  Other possible variants are `alpha` (`@alpha` + `@beta` + `@public`),\n\t * `beta` (`@beta` + `@public`), and `public` (`@public only`).\n\t *\n\t * The resulting API report file names will be derived from the {@link IConfigApiReport.reportFileName}.\n\t * @defaultValue `[ \"complete\" ]`\n\t */\n\treportVariants?: ApiReportVariant[];\n\n\t/**\n\t * Specifies a list of {@link https://tsdoc.org/ | TSDoc} tags that should be reported in the API report file for\n\t * items whose documentation contains them.\n\t *\n\t * @remarks\n\t * Tag names must begin with `@`.\n\t *\n\t * This list may include standard TSDoc tags as well as custom ones.\n\t * For more information on defining custom TSDoc tags, see\n\t * {@link https://api-extractor.com/pages/configs/tsdoc_json/#defining-your-own-tsdoc-tags | here}.\n\t *\n\t * Note that an item's release tag will always reported; this behavior cannot be overridden.\n\t * @defaultValue `@sealed`, `@virtual`, `@override`, `@eventProperty`, and `@deprecated`\n\t * @example Omitting default tags\n\t * To omit the `@sealed` and `@virtual` tags from API reports, you would specify `tagsToReport` as follows:\n\t * ```json\n\t * \"tagsToReport\": {\n\t *  \"@sealed\": false,\n\t *  \"@virtual\": false\n\t * }\n\t * ```\n\t * @example Including additional tags\n\t * To include additional tags to the set included in API reports, you could specify `tagsToReport` like this:\n\t * ```json\n\t * \"tagsToReport\": {\n\t *  \"@customTag\": true\n\t * }\n\t * ```\n\t * This will result in `@customTag` being included in addition to the default tags.\n\t */\n\ttagsToReport?: Readonly<Record<`@${string}`, boolean>>;\n}\n\n/**\n * The allowed release tags that can be used to mark API items.\n *\n * @public\n */\nexport type ReleaseTagForTrim = '@alpha' | '@beta' | '@internal' | '@public';\n\n/**\n * Configures how the doc model file (*.api.json) will be generated.\n *\n * @remarks\n * This is part of the {@link IConfigFile} structure.\n * @public\n */\nexport interface IConfigDocModel {\n\t/**\n\t * The output path for the doc model file.  The file extension should be \".api.json\".\n\t *\n\t * @remarks\n\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t * prepend a folder token such as `<projectFolder>`.\n\t */\n\tapiJsonFilePath?: string;\n\n\t/**\n\t * Whether to generate a doc model file.\n\t */\n\tenabled: boolean;\n\n\t/**\n\t * Whether \"forgotten exports\" should be included in the doc model file.\n\t *\n\t * @remarks\n\t * Forgotten exports are declarations flagged with `ae-forgotten-export` warnings. See\n\t * https://api-extractor.com/pages/messages/ae-forgotten-export/ to learn more.\n\t * @defaultValue `false`\n\t */\n\tincludeForgottenExports?: boolean;\n\n\t/**\n\t * The base URL where the project's source code can be viewed on a website such as GitHub or\n\t * Azure DevOps. This URL path corresponds to the `<projectFolder>` path on disk.\n\t *\n\t * @remarks\n\t * This URL is concatenated with the file paths serialized to the doc model to produce URL file paths to individual API items.\n\t * For example, if the `projectFolderUrl` is \"https://github.com/microsoft/rushstack/tree/main/apps/api-extractor\" and an API\n\t * item's file path is \"api/ExtractorConfig.ts\", the full URL file path would be\n\t * \"https://github.com/microsoft/rushstack/tree/main/apps/api-extractor/api/ExtractorConfig.js\".\n\t *\n\t * Can be omitted if you don't need source code links in your API documentation reference.\n\t */\n\tprojectFolderUrl?: string;\n\n\t/**\n\t * Specifies a list of release tags that will be trimmed from the doc model.\n\t *\n\t * @defaultValue `[\"@internal\"]`\n\t */\n\treleaseTagsToTrim?: ReleaseTagForTrim[];\n}\n\n/**\n * Configures how the .d.ts rollup file will be generated.\n *\n * @remarks\n * This is part of the {@link IConfigFile} structure.\n * @public\n */\nexport interface IConfigDtsRollup {\n\t/**\n\t * Specifies the output path for a .d.ts rollup file to be generated with trimming for an \"alpha\" release.\n\t *\n\t * @remarks\n\t * This file will include only declarations that are marked as `@public`, `@beta`, or `@alpha`.\n\t *\n\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t * prepend a folder token such as `<projectFolder>`.\n\t */\n\talphaTrimmedFilePath?: string;\n\n\t/**\n\t * Specifies the output path for a .d.ts rollup file to be generated with trimming for a \"beta\" release.\n\t *\n\t * @remarks\n\t * This file will include only declarations that are marked as `@public` or `@beta`.\n\t *\n\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t * prepend a folder token such as `<projectFolder>`.\n\t */\n\tbetaTrimmedFilePath?: string;\n\n\t/**\n\t * Whether to generate the .d.ts rollup file.\n\t */\n\tenabled: boolean;\n\n\t/**\n\t * When a declaration is trimmed, by default it will be replaced by a code comment such as\n\t * \"Excluded from this release type: exampleMember\".  Set \"omitTrimmingComments\" to true to remove the\n\t * declaration completely.\n\t */\n\tomitTrimmingComments?: boolean;\n\n\t/**\n\t * Specifies the output path for a .d.ts rollup file to be generated with trimming for a \"public\" release.\n\t *\n\t * @remarks\n\t * This file will include only declarations that are marked as `@public`.\n\t *\n\t * If the path is an empty string, then this file will not be written.\n\t *\n\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t * prepend a folder token such as `<projectFolder>`.\n\t */\n\tpublicTrimmedFilePath?: string;\n\n\t/**\n\t * Specifies the output path for a .d.ts rollup file to be generated without any trimming.\n\t *\n\t * @remarks\n\t * This file will include all declarations that are exported by the main entry point.\n\t *\n\t * If the path is an empty string, then this file will not be written.\n\t *\n\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t * prepend a folder token such as `<projectFolder>`.\n\t */\n\tuntrimmedFilePath?: string;\n}\n\n/**\n * Configures how the tsdoc-metadata.json file will be generated.\n *\n * @remarks\n * This is part of the {@link IConfigFile} structure.\n * @public\n */\nexport interface IConfigTsdocMetadata {\n\t/**\n\t * Whether to generate the tsdoc-metadata.json file.\n\t */\n\tenabled: boolean;\n\n\t/**\n\t * Specifies where the TSDoc metadata file should be written.\n\t *\n\t * @remarks\n\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t * prepend a folder token such as `<projectFolder>`.\n\t *\n\t * The default value is `<lookup>`, which causes the path to be automatically inferred from the `tsdocMetadata`,\n\t * `typings` or `main` fields of the project's package.json.  If none of these fields are set, the lookup\n\t * falls back to `tsdoc-metadata.json` in the package folder.\n\t */\n\ttsdocMetadataFilePath?: string;\n}\n\n/**\n * Configures reporting for a given message identifier.\n *\n * @remarks\n * This is part of the {@link IConfigFile} structure.\n * @public\n */\nexport interface IConfigMessageReportingRule {\n\t/**\n\t * When `addToApiReportFile` is true:  If API Extractor is configured to write an API report file (.api.md),\n\t * then the message will be written inside that file; otherwise, the message is instead logged according to\n\t * the `logLevel` option.\n\t */\n\taddToApiReportFile?: boolean;\n\n\t/**\n\t * Specifies whether the message should be written to the tool's output log.\n\t *\n\t * @remarks\n\t * Note that the `addToApiReportFile` property may supersede this option.\n\t */\n\tlogLevel: ExtractorLogLevel;\n}\n\n/**\n * Specifies a table of reporting rules for different message identifiers, and also the default rule used for\n * identifiers that do not appear in the table.\n *\n * @remarks\n * This is part of the {@link IConfigFile} structure.\n * @public\n */\nexport interface IConfigMessageReportingTable {\n\t/**\n\t * The key is a message identifier for the associated type of message, or \"default\" to specify the default policy.\n\t * For example, the key might be `TS2551` (a compiler message), `tsdoc-link-tag-unescaped-text` (a TSDOc message),\n\t * or `ae-extra-release-tag` (a message related to the API Extractor analysis).\n\t */\n\t[messageId: string]: IConfigMessageReportingRule;\n}\n\n/**\n * Configures how API Extractor reports error and warning messages produced during analysis.\n *\n * @remarks\n * This is part of the {@link IConfigFile} structure.\n * @public\n */\nexport interface IExtractorMessagesConfig {\n\t/**\n\t * Configures handling of diagnostic messages generating the TypeScript compiler while analyzing the\n\t * input .d.ts files.\n\t */\n\tcompilerMessageReporting?: IConfigMessageReportingTable;\n\n\t/**\n\t * Configures handling of messages reported by API Extractor during its analysis.\n\t */\n\textractorMessageReporting?: IConfigMessageReportingTable;\n\n\t/**\n\t * Configures handling of messages reported by the TSDoc parser when analyzing code comments.\n\t */\n\ttsdocMessageReporting?: IConfigMessageReportingTable;\n}\n\n/**\n * Configuration options for the API Extractor tool.  These options can be constructed programmatically\n * or loaded from the api-extractor.json config file using the {@link ExtractorConfig} class.\n *\n * @public\n */\nexport interface IConfigFile {\n\t/**\n\t * support multiple entry points.\n\t */\n\tadditionalEntryPoints: IConfigEntryPoint[];\n\n\t/**\n\t * {@inheritDoc IConfigApiReport}\n\t */\n\tapiReport?: IConfigApiReport;\n\n\t/**\n\t * A list of NPM package names whose exports should be treated as part of this package.\n\t *\n\t * @remarks\n\t *\n\t * For example, suppose that Webpack is used to generate a distributed bundle for the project `library1`,\n\t * and another NPM package `library2` is embedded in this bundle.  Some types from `library2` may become part\n\t * of the exported API for `library1`, but by default API Extractor would generate a .d.ts rollup that explicitly\n\t * imports `library2`.  To avoid this, we can specify:\n\t *\n\t * ```js\n\t *   \"bundledPackages\": [ \"library2\" ],\n\t * ```\n\t *\n\t * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been\n\t * local files for `library1`.\n\t */\n\tbundledPackages?: string[];\n\n\t/**\n\t * {@inheritDoc IConfigCompiler}\n\t */\n\tcompiler?: IConfigCompiler;\n\n\t/**\n\t * {@inheritDoc IConfigDocModel}\n\t */\n\tdocModel?: IConfigDocModel;\n\n\t/**\n\t * {@inheritDoc IConfigDtsRollup}\n\t *\n\t * @beta\n\t */\n\tdtsRollup?: IConfigDtsRollup;\n\n\t/**\n\t * Specifies how API Extractor sorts members of an enum when generating the .api.json file.\n\t *\n\t * @remarks\n\t * By default, the output files will be sorted alphabetically, which is \"by-name\".\n\t * To keep the ordering in the source code, specify \"preserve\".\n\t * @defaultValue `by-name`\n\t */\n\tenumMemberOrder?: EnumMemberOrder;\n\n\t/**\n\t * Optionally specifies another JSON config file that this file extends from.  This provides a way for\n\t * standard settings to be shared across multiple projects.\n\t *\n\t * @remarks\n\t * If the path starts with `./` or `../`, the path is resolved relative to the folder of the file that contains\n\t * the `extends` field.  Otherwise, the first path segment is interpreted as an NPM package name, and will be\n\t * resolved using NodeJS `require()`.\n\t */\n\textends?: string;\n\n\t/**\n\t * Specifies the .d.ts file to be used as the starting point for analysis.  API Extractor\n\t * analyzes the symbols exported by this module.\n\t *\n\t * @remarks\n\t *\n\t * The file extension must be \".d.ts\" and not \".ts\".\n\t * The path is resolved relative to the \"projectFolder\" location.\n\t */\n\tmainEntryPointFilePath: string;\n\n\t/**\n\t * Specifies the import path of the entrypoint used as the starting point for analysis.\n\t */\n\tmainEntryPointName: string;\n\n\t/**\n\t * {@inheritDoc IExtractorMessagesConfig}\n\t */\n\tmessages?: IExtractorMessagesConfig;\n\n\t/**\n\t * Specifies what type of newlines API Extractor should use when writing output files.\n\t *\n\t * @remarks\n\t * By default, the output files will be written with Windows-style newlines.\n\t * To use POSIX-style newlines, specify \"lf\" instead.\n\t * To use the OS's default newline kind, specify \"os\".\n\t */\n\tnewlineKind?: 'crlf' | 'lf' | 'os';\n\n\t/**\n\t * Determines the `<projectFolder>` token that can be used with other config file settings.  The project folder\n\t * typically contains the tsconfig.json and package.json config files, but the path is user-defined.\n\t *\n\t * @remarks\n\t *\n\t * The path is resolved relative to the folder of the config file that contains the setting.\n\t *\n\t * The default value for `projectFolder` is the token `<lookup>`, which means the folder is determined using\n\t * the following heuristics:\n\t *\n\t * If the config/rig.json system is used (as defined by {@link https://www.npmjs.com/package/@rushstack/rig-package\n\t * | @rushstack/rig-package}), then the `<lookup>` value will be the package folder that referenced the rig.\n\t *\n\t * Otherwise, the `<lookup>` value is determined by traversing parent folders, starting from the folder containing\n\t * api-extractor.json, and stopping at the first folder that contains a tsconfig.json file.  If a tsconfig.json file\n\t * cannot be found in this way, then an error will be reported.\n\t */\n\tprojectFolder?: string;\n\n\t/**\n\t * Set to true when invoking API Extractor's test harness.\n\t *\n\t * @remarks\n\t * When `testMode` is true, the `toolVersion` field in the .api.json file is assigned an empty string\n\t * to prevent spurious diffs in output files tracked for tests.\n\t */\n\ttestMode?: boolean;\n\n\t/**\n\t * {@inheritDoc IConfigTsdocMetadata}\n\t *\n\t * @beta\n\t */\n\ttsdocMetadata?: IConfigTsdocMetadata;\n}\n"
  },
  {
    "path": "packages/api-extractor/src/cli/ApiExtractorCommandLine.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as os from 'node:os';\nimport process from 'node:process';\nimport { InternalError } from '@rushstack/node-core-library';\nimport { CommandLineParser, type CommandLineFlagParameter } from '@rushstack/ts-command-line';\nimport colors from 'colors';\nimport { InitAction } from './InitAction.js';\nimport { RunAction } from './RunAction.js';\n\nexport class ApiExtractorCommandLine extends CommandLineParser {\n\tprivate readonly _debugParameter: CommandLineFlagParameter;\n\n\tpublic constructor() {\n\t\tsuper({\n\t\t\ttoolFilename: 'api-extractor',\n\t\t\ttoolDescription:\n\t\t\t\t'API Extractor helps you build better TypeScript libraries.  It analyzes the main entry' +\n\t\t\t\t' point for your package, collects the inventory of exported declarations, and then generates three kinds' +\n\t\t\t\t' of output:  an API report file (.api.md) to facilitate reviews, a declaration rollup (.d.ts) to be' +\n\t\t\t\t' published with your NPM package, and a doc model file (.api.json) to be used with a documentation' +\n\t\t\t\t' tool such as api-documenter.  For details, please visit the web site.',\n\t\t});\n\t\tthis._populateActions();\n\n\t\tthis._debugParameter = this.defineFlagParameter({\n\t\t\tparameterLongName: '--debug',\n\t\t\tparameterShortName: '-d',\n\t\t\tdescription: 'Show the full call stack if an error occurs while executing the tool',\n\t\t});\n\t}\n\n\tprotected override async onExecuteAsync(): Promise<void> {\n\t\t// override\n\t\tif (this._debugParameter.value) {\n\t\t\tInternalError.breakInDebugger = true;\n\t\t}\n\n\t\tprocess.exitCode = 1;\n\t\ttry {\n\t\t\tawait super.onExecuteAsync();\n\t\t\tprocess.exitCode = 0;\n\t\t} catch (error: any) {\n\t\t\tif (this._debugParameter.value) {\n\t\t\t\tconsole.error(os.EOL + error.stack);\n\t\t\t} else {\n\t\t\t\tconsole.error(os.EOL + colors.red('ERROR: ' + error.message.trim()));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _populateActions(): void {\n\t\tthis.addAction(new InitAction(this));\n\t\tthis.addAction(new RunAction(this));\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/cli/InitAction.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as path from 'node:path';\nimport { FileSystem } from '@rushstack/node-core-library';\nimport { CommandLineAction } from '@rushstack/ts-command-line';\nimport colors from 'colors';\nimport { ExtractorConfig } from '../api/ExtractorConfig.js';\nimport type { ApiExtractorCommandLine } from './ApiExtractorCommandLine.js';\n\nexport class InitAction extends CommandLineAction {\n\tpublic constructor(_parser: ApiExtractorCommandLine) {\n\t\tsuper({\n\t\t\tactionName: 'init',\n\t\t\tsummary: `Create an ${ExtractorConfig.FILENAME} config file`,\n\t\t\tdocumentation:\n\t\t\t\t`Use this command when setting up API Extractor for a new project.  It writes an` +\n\t\t\t\t` ${ExtractorConfig.FILENAME} config file template with code comments that describe all the settings.` +\n\t\t\t\t` The file will be written in the current directory.`,\n\t\t});\n\t}\n\n\tprotected override async onExecuteAsync(): Promise<void> {\n\t\tconst inputFilePath: string = path.resolve(__dirname, './schemas/api-extractor-template.json');\n\t\tconst outputFilePath: string = path.resolve(ExtractorConfig.FILENAME);\n\n\t\tif (FileSystem.exists(outputFilePath)) {\n\t\t\tconsole.log(colors.red('The output file already exists:'));\n\t\t\tconsole.log('\\n  ' + outputFilePath + '\\n');\n\t\t\tthrow new Error('Unable to write output file');\n\t\t}\n\n\t\tconsole.log(colors.green('Writing file: ') + outputFilePath);\n\t\tFileSystem.copyFile({\n\t\t\tsourcePath: inputFilePath,\n\t\t\tdestinationPath: outputFilePath,\n\t\t});\n\n\t\tconsole.log(\n\t\t\t'\\nThe recommended location for this file is in the project\\'s \"config\" subfolder,\\n' +\n\t\t\t\t'or else in the top-level folder with package.json.',\n\t\t);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/cli/RunAction.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport process from 'node:process';\nimport { PackageJsonLookup, FileSystem, type IPackageJson, Path } from '@rushstack/node-core-library';\nimport {\n\tCommandLineAction,\n\ttype CommandLineStringParameter,\n\ttype CommandLineFlagParameter,\n} from '@rushstack/ts-command-line';\nimport colors from 'colors';\nimport { Extractor, type ExtractorResult } from '../api/Extractor.js';\nimport { ExtractorConfig, type IExtractorConfigPrepareOptions } from '../api/ExtractorConfig.js';\nimport type { ApiExtractorCommandLine } from './ApiExtractorCommandLine.js';\n\nexport class RunAction extends CommandLineAction {\n\tprivate readonly _configFileParameter: CommandLineStringParameter;\n\n\tprivate readonly _localParameter: CommandLineFlagParameter;\n\n\tprivate readonly _verboseParameter: CommandLineFlagParameter;\n\n\tprivate readonly _diagnosticsParameter: CommandLineFlagParameter;\n\n\tprivate readonly _typescriptCompilerFolder: CommandLineStringParameter;\n\n\tprivate readonly _minify: CommandLineFlagParameter;\n\n\tpublic constructor(_parser: ApiExtractorCommandLine) {\n\t\tsuper({\n\t\t\tactionName: 'run',\n\t\t\tsummary: 'Invoke API Extractor on a project',\n\t\t\tdocumentation: 'Invoke API Extractor on a project',\n\t\t});\n\n\t\tthis._configFileParameter = this.defineStringParameter({\n\t\t\tparameterLongName: '--config',\n\t\t\tparameterShortName: '-c',\n\t\t\targumentName: 'FILE',\n\t\t\tdescription: `Use the specified ${ExtractorConfig.FILENAME} file path, rather than guessing its location`,\n\t\t});\n\n\t\tthis._localParameter = this.defineFlagParameter({\n\t\t\tparameterLongName: '--local',\n\t\t\tparameterShortName: '-l',\n\t\t\tdescription:\n\t\t\t\t'Indicates that API Extractor is running as part of a local build,' +\n\t\t\t\t\" e.g. on a developer's machine. This disables certain validation that would\" +\n\t\t\t\t' normally be performed for a ship/production build. For example, the *.api.md' +\n\t\t\t\t' report file is automatically copied in a local build.',\n\t\t});\n\n\t\tthis._verboseParameter = this.defineFlagParameter({\n\t\t\tparameterLongName: '--verbose',\n\t\t\tparameterShortName: '-v',\n\t\t\tdescription: 'Show additional informational messages in the output.',\n\t\t});\n\n\t\tthis._minify = this.defineFlagParameter({\n\t\t\tparameterLongName: '--minify',\n\t\t\tparameterShortName: '-m',\n\t\t\tdescription: 'Minify the resulting doc model JSON, i.e. without any indentation or newlines.',\n\t\t});\n\n\t\tthis._diagnosticsParameter = this.defineFlagParameter({\n\t\t\tparameterLongName: '--diagnostics',\n\t\t\tdescription:\n\t\t\t\t'Show diagnostic messages used for troubleshooting problems with API Extractor.' +\n\t\t\t\t'  This flag also enables the \"--verbose\" flag.',\n\t\t});\n\n\t\tthis._typescriptCompilerFolder = this.defineStringParameter({\n\t\t\tparameterLongName: '--typescript-compiler-folder',\n\t\t\targumentName: 'PATH',\n\t\t\tdescription:\n\t\t\t\t'API Extractor uses its own TypeScript compiler engine to analyze your project.  If your project' +\n\t\t\t\t' is built with a significantly different TypeScript version, sometimes API Extractor may report compilation' +\n\t\t\t\t' errors due to differences in the system typings (e.g. lib.dom.d.ts).  You can use the' +\n\t\t\t\t' \"--typescriptCompilerFolder\" option to specify the folder path where you installed the TypeScript package,' +\n\t\t\t\t\" and API Extractor's compiler will use those system typings instead.\",\n\t\t});\n\t}\n\n\tprotected override async onExecuteAsync(): Promise<void> {\n\t\tconst lookup: PackageJsonLookup = new PackageJsonLookup();\n\t\tlet configFilename: string;\n\n\t\tlet typescriptCompilerFolder: string | undefined = this._typescriptCompilerFolder.value;\n\t\tif (typescriptCompilerFolder) {\n\t\t\ttypescriptCompilerFolder = path.normalize(typescriptCompilerFolder);\n\n\t\t\tif (FileSystem.exists(typescriptCompilerFolder)) {\n\t\t\t\ttypescriptCompilerFolder = lookup.tryGetPackageFolderFor(typescriptCompilerFolder);\n\t\t\t\tconst typescriptCompilerPackageJson: IPackageJson | undefined = typescriptCompilerFolder\n\t\t\t\t\t? lookup.tryLoadPackageJsonFor(typescriptCompilerFolder)\n\t\t\t\t\t: undefined;\n\t\t\t\tif (!typescriptCompilerPackageJson) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`The path specified in the ${this._typescriptCompilerFolder.longName} parameter is not a package.`,\n\t\t\t\t\t);\n\t\t\t\t} else if (typescriptCompilerPackageJson.name !== 'typescript') {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`The path specified in the ${this._typescriptCompilerFolder.longName} parameter is not a TypeScript` +\n\t\t\t\t\t\t\t' compiler package.',\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`The path specified in the ${this._typescriptCompilerFolder.longName} parameter does not exist.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tlet extractorConfig: ExtractorConfig;\n\n\t\tif (this._configFileParameter.value) {\n\t\t\tconfigFilename = path.normalize(this._configFileParameter.value);\n\t\t\tif (!FileSystem.exists(configFilename)) {\n\t\t\t\tthrow new Error('Config file not found: ' + this._configFileParameter.value);\n\t\t\t}\n\n\t\t\textractorConfig = ExtractorConfig.loadFileAndPrepare(configFilename);\n\t\t} else {\n\t\t\tconst prepareOptions: IExtractorConfigPrepareOptions | undefined = ExtractorConfig.tryLoadForFolder({\n\t\t\t\tstartingFolder: '.',\n\t\t\t});\n\n\t\t\tif (!prepareOptions?.configObjectFullPath) {\n\t\t\t\tthrow new Error(`Unable to find an ${ExtractorConfig.FILENAME} file`);\n\t\t\t}\n\n\t\t\tconst configObjectShortPath: string = Path.formatConcisely({\n\t\t\t\tpathToConvert: prepareOptions.configObjectFullPath,\n\t\t\t\tbaseFolder: process.cwd(),\n\t\t\t});\n\t\t\tconsole.log(`Using configuration from ${configObjectShortPath}`);\n\n\t\t\textractorConfig = ExtractorConfig.prepare(prepareOptions);\n\t\t}\n\n\t\tconst extractorResult: ExtractorResult = Extractor.invoke(extractorConfig, {\n\t\t\tlocalBuild: this._localParameter.value,\n\t\t\tdocModelMinify: this._minify.value,\n\t\t\tshowVerboseMessages: this._verboseParameter.value,\n\t\t\tshowDiagnostics: this._diagnosticsParameter.value,\n\t\t\ttypescriptCompilerFolder,\n\t\t});\n\n\t\tif (extractorResult.succeeded) {\n\t\t\tconsole.log(os.EOL + 'API Extractor completed successfully');\n\t\t} else {\n\t\t\tprocess.exitCode = 1;\n\n\t\t\tif (extractorResult.errorCount > 0) {\n\t\t\t\tconsole.log(os.EOL + colors.red('API Extractor completed with errors'));\n\t\t\t} else {\n\t\t\t\tconsole.log(os.EOL + colors.yellow('API Extractor completed with warnings'));\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/collector/ApiItemMetadata.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { ReleaseTag } from '@discordjs/api-extractor-model';\nimport type * as tsdoc from '@microsoft/tsdoc';\nimport { VisitorState } from './VisitorState.js';\n\n/**\n * Constructor parameters for `ApiItemMetadata`.\n */\nexport interface IApiItemMetadataOptions {\n\tdeclaredReleaseTag: ReleaseTag;\n\teffectiveReleaseTag: ReleaseTag;\n\tisEventProperty: boolean;\n\tisOverride: boolean;\n\tisPreapproved: boolean;\n\tisSealed: boolean;\n\tisVirtual: boolean;\n\treleaseTagSameAsParent: boolean;\n}\n\n/**\n * Stores the Collector's additional analysis for an `AstDeclaration`.  This object is assigned to\n * `AstDeclaration.apiItemMetadata` but consumers must always obtain it by calling `Collector.fetchApiItemMetadata()`.\n *\n * @remarks\n * Note that ancillary declarations share their `ApiItemMetadata` with the main declaration,\n * whereas a separate `DeclarationMetadata` object is created for each declaration.\n *\n * Consider this example:\n * ```ts\n * export declare class A {\n *   get b(): string;\n *   set b(value: string);\n * }\n * export declare namespace A { }\n * ```\n *\n * In this example, there are two \"symbols\": `A` and `b`\n *\n * There are four \"declarations\": `A` class, `A` namespace, `b` getter, `b` setter\n *\n * There are three \"API items\": `A` class, `A` namespace, `b` property.  The property getter is the main declaration\n * for `b`, and the setter is the \"ancillary\" declaration.\n */\nexport class ApiItemMetadata {\n\t/**\n\t * This is the release tag that was explicitly specified in the original doc comment, if any.\n\t */\n\tpublic readonly declaredReleaseTag: ReleaseTag;\n\n\t/**\n\t * The \"effective\" release tag is a normalized value that is based on `declaredReleaseTag`,\n\t * but may be inherited from a parent, or corrected if the declared value was somehow invalid.\n\t * When actually trimming .d.ts files or generating docs, API Extractor uses the \"effective\" value\n\t * instead of the \"declared\" value.\n\t */\n\tpublic readonly effectiveReleaseTag: ReleaseTag;\n\n\t// If true, then it would be redundant to show this release tag\n\tpublic readonly releaseTagSameAsParent: boolean;\n\n\t// NOTE: In the future, the Collector may infer or error-correct some of these states.\n\t// Generators should rely on these instead of tsdocComment.modifierTagSet.\n\tpublic readonly isEventProperty: boolean;\n\n\tpublic readonly isOverride: boolean;\n\n\tpublic readonly isSealed: boolean;\n\n\tpublic readonly isVirtual: boolean;\n\n\tpublic readonly isPreapproved: boolean;\n\n\t/**\n\t * This is the TSDoc comment for the declaration.  It may be modified (or constructed artificially) by\n\t * the DocCommentEnhancer.\n\t */\n\tpublic tsdocComment: tsdoc.DocComment | undefined;\n\n\t// Assigned by DocCommentEnhancer\n\tpublic undocumented: boolean = true;\n\n\tpublic docCommentEnhancerVisitorState: VisitorState = VisitorState.Unvisited;\n\n\tpublic constructor(options: IApiItemMetadataOptions) {\n\t\tthis.declaredReleaseTag = options.declaredReleaseTag;\n\t\tthis.effectiveReleaseTag = options.effectiveReleaseTag;\n\t\tthis.releaseTagSameAsParent = options.releaseTagSameAsParent;\n\t\tthis.isEventProperty = options.isEventProperty;\n\t\tthis.isOverride = options.isOverride;\n\t\tthis.isSealed = options.isSealed;\n\t\tthis.isVirtual = options.isVirtual;\n\t\tthis.isPreapproved = options.isPreapproved;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/collector/Collector.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { ReleaseTag } from '@discordjs/api-extractor-model';\nimport * as tsdoc from '@microsoft/tsdoc';\nimport { PackageJsonLookup, Sort, InternalError } from '@rushstack/node-core-library';\nimport ts from 'typescript';\nimport { PackageDocComment } from '../aedoc/PackageDocComment.js';\nimport type { AstDeclaration } from '../analyzer/AstDeclaration.js';\nimport type { AstEntity } from '../analyzer/AstEntity.js';\nimport { AstImport } from '../analyzer/AstImport.js';\nimport type { AstModule, IAstModuleExportInfo } from '../analyzer/AstModule.js';\nimport { AstNamespaceImport } from '../analyzer/AstNamespaceImport.js';\nimport { AstReferenceResolver } from '../analyzer/AstReferenceResolver.js';\nimport { AstSymbol } from '../analyzer/AstSymbol.js';\nimport { AstSymbolTable } from '../analyzer/AstSymbolTable.js';\nimport { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers.js';\nimport { TypeScriptInternals, type IGlobalVariableAnalyzer } from '../analyzer/TypeScriptInternals.js';\nimport { ExtractorConfig } from '../api/ExtractorConfig.js';\nimport { ExtractorMessageId } from '../api/ExtractorMessageId.js';\nimport type { IConfigEntryPoint } from '../api/IConfigFile';\nimport { ApiItemMetadata, type IApiItemMetadataOptions } from './ApiItemMetadata.js';\nimport { CollectorEntity } from './CollectorEntity.js';\nimport { type DeclarationMetadata, InternalDeclarationMetadata } from './DeclarationMetadata.js';\nimport type { MessageRouter } from './MessageRouter.js';\nimport type { SourceMapper } from './SourceMapper.js';\nimport { SymbolMetadata } from './SymbolMetadata.js';\nimport type { IWorkingPackageEntryPoint } from './WorkingPackage.js';\nimport { WorkingPackage } from './WorkingPackage.js';\n\n/**\n * Options for Collector constructor.\n */\nexport interface ICollectorOptions {\n\textractorConfig: ExtractorConfig;\n\n\tmessageRouter: MessageRouter;\n\n\t/**\n\t * Configuration for the TypeScript compiler.  The most important options to set are:\n\t *\n\t * - target: ts.ScriptTarget.ES5\n\t * - module: ts.ModuleKind.CommonJS\n\t * - moduleResolution: ts.ModuleResolutionKind.NodeJs\n\t * - rootDir: inputFolder\n\t */\n\tprogram: ts.Program;\n\n\tsourceMapper: SourceMapper;\n}\n\n/**\n * The `Collector` manages the overall data set that is used by `ApiModelGenerator`,\n * `DtsRollupGenerator`, and `ApiReportGenerator`.  Starting from the working package's entry point,\n * the `Collector` collects all exported symbols, determines how to import any symbols they reference,\n * assigns unique names, and sorts everything into a normalized alphabetical ordering.\n */\nexport class Collector {\n\tpublic readonly program: ts.Program;\n\n\tpublic readonly typeChecker: ts.TypeChecker;\n\n\tpublic readonly globalVariableAnalyzer: IGlobalVariableAnalyzer;\n\n\tpublic readonly astSymbolTable: AstSymbolTable;\n\n\tpublic readonly astReferenceResolver: AstReferenceResolver;\n\n\tpublic readonly packageJsonLookup: PackageJsonLookup;\n\n\tpublic readonly messageRouter: MessageRouter;\n\n\tpublic readonly workingPackage: WorkingPackage;\n\n\tpublic readonly extractorConfig: ExtractorConfig;\n\n\tpublic readonly sourceMapper: SourceMapper;\n\n\t/**\n\t * The `ExtractorConfig.bundledPackages` names in a set.\n\t */\n\tpublic readonly bundledPackageNames: ReadonlySet<string>;\n\n\tprivate readonly _program: ts.Program;\n\n\tprivate readonly _tsdocParser: tsdoc.TSDocParser;\n\n\tprivate _astEntryPoints: AstModule[] | undefined;\n\n\tprivate readonly _entitiesByAstEntity: Map<AstEntity, CollectorEntity> = new Map<AstEntity, CollectorEntity>();\n\n\tprivate readonly _entitiesByAstEntryPoint: Map<IWorkingPackageEntryPoint, CollectorEntity[]> = new Map<\n\t\tIWorkingPackageEntryPoint,\n\t\tCollectorEntity[]\n\t>();\n\n\tprivate readonly _entitiesBySymbol: Map<ts.Symbol, CollectorEntity> = new Map<ts.Symbol, CollectorEntity>();\n\n\tprivate readonly _starExportedExternalModulePaths: string[] = [];\n\n\tprivate readonly _dtsTypeReferenceDirectives: Set<string> = new Set<string>();\n\n\tprivate readonly _dtsLibReferenceDirectives: Set<string> = new Set<string>();\n\n\t// Used by getOverloadIndex()\n\tprivate readonly _cachedOverloadIndexesByDeclaration: Map<AstDeclaration, number>;\n\n\tpublic constructor(options: ICollectorOptions) {\n\t\tthis.packageJsonLookup = new PackageJsonLookup();\n\n\t\tthis._program = options.program;\n\t\tthis.extractorConfig = options.extractorConfig;\n\t\tthis.sourceMapper = options.sourceMapper;\n\n\t\tconst entryPoints: IConfigEntryPoint[] = [\n\t\t\tthis.extractorConfig.mainEntryPointFilePath,\n\t\t\t...this.extractorConfig.additionalEntryPoints,\n\t\t];\n\n\t\tconst workingPackageEntryPoints: IWorkingPackageEntryPoint[] = entryPoints.map((entryPoint) => {\n\t\t\tconst sourceFile: ts.SourceFile | undefined = options.program.getSourceFile(entryPoint.filePath);\n\n\t\t\tif (!sourceFile) {\n\t\t\t\tthrow new Error('Unable to load file: ' + entryPoint.filePath);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tmodulePath: entryPoint.modulePath,\n\t\t\t\tsourceFile,\n\t\t\t};\n\t\t});\n\n\t\tif (!this.extractorConfig.packageFolder || !this.extractorConfig.packageJson) {\n\t\t\tthrow new Error('Unable to find a package.json file for the project being analyzed');\n\t\t}\n\n\t\tthis.workingPackage = new WorkingPackage({\n\t\t\tpackageFolder: this.extractorConfig.packageFolder,\n\t\t\tpackageJson: this.extractorConfig.packageJson,\n\t\t\tentryPoints: workingPackageEntryPoints,\n\t\t});\n\n\t\tthis.messageRouter = options.messageRouter;\n\n\t\tthis.program = options.program;\n\t\tthis.typeChecker = options.program.getTypeChecker();\n\t\tthis.globalVariableAnalyzer = TypeScriptInternals.getGlobalVariableAnalyzer(this.program);\n\n\t\tthis._tsdocParser = new tsdoc.TSDocParser(this.extractorConfig.tsdocConfiguration);\n\n\t\tthis.bundledPackageNames = new Set<string>(this.extractorConfig.bundledPackages);\n\n\t\tthis.astSymbolTable = new AstSymbolTable(\n\t\t\tthis.program,\n\t\t\tthis.typeChecker,\n\t\t\tthis.packageJsonLookup,\n\t\t\tthis.bundledPackageNames,\n\t\t\tthis.messageRouter,\n\t\t);\n\t\tthis.astReferenceResolver = new AstReferenceResolver(this);\n\n\t\tthis._cachedOverloadIndexesByDeclaration = new Map<AstDeclaration, number>();\n\t}\n\n\t/**\n\t * Returns a list of names (e.g. \"example-library\") that should appear in a reference like this:\n\t *\n\t * ```\n\t * /// <reference types=\"example-library\" />\n\t * ```\n\t */\n\tpublic get dtsTypeReferenceDirectives(): ReadonlySet<string> {\n\t\treturn this._dtsTypeReferenceDirectives;\n\t}\n\n\t/**\n\t * A list of names (e.g. \"runtime-library\") that should appear in a reference like this:\n\t *\n\t * ```\n\t * /// <reference lib=\"runtime-library\" />\n\t * ```\n\t */\n\tpublic get dtsLibReferenceDirectives(): ReadonlySet<string> {\n\t\treturn this._dtsLibReferenceDirectives;\n\t}\n\n\tpublic get entities(): ReadonlyMap<IWorkingPackageEntryPoint, CollectorEntity[]> {\n\t\treturn this._entitiesByAstEntryPoint;\n\t}\n\n\t/**\n\t * A list of module specifiers (e.g. `\"@rushstack/node-core-library/lib/FileSystem\"`) that should be emitted\n\t * as star exports (e.g. `export * from \"@rushstack/node-core-library/lib/FileSystem\"`).\n\t */\n\tpublic get starExportedExternalModulePaths(): readonly string[] {\n\t\treturn this._starExportedExternalModulePaths;\n\t}\n\n\t/**\n\t * Perform the analysis.\n\t */\n\tpublic analyze(): void {\n\t\tif (this._astEntryPoints) {\n\t\t\tthrow new Error('DtsRollupGenerator.analyze() was already called');\n\t\t}\n\n\t\t// This runs a full type analysis, and then augments the Abstract Syntax Tree (i.e. declarations)\n\t\t// with semantic information (i.e. symbols).  The \"diagnostics\" are a subset of the everyday\n\t\t// compile errors that would result from a full compilation.\n\t\tfor (const diagnostic of this._program.getSemanticDiagnostics()) {\n\t\t\tthis.messageRouter.addCompilerDiagnostic(diagnostic);\n\t\t}\n\n\t\tconst sourceFiles: readonly ts.SourceFile[] = this.program.getSourceFiles();\n\n\t\tif (this.messageRouter.showDiagnostics) {\n\t\t\tthis.messageRouter.logDiagnosticHeader('Root filenames');\n\t\t\tfor (const fileName of this.program.getRootFileNames()) {\n\t\t\t\tthis.messageRouter.logDiagnostic(fileName);\n\t\t\t}\n\n\t\t\tthis.messageRouter.logDiagnosticFooter();\n\n\t\t\tthis.messageRouter.logDiagnosticHeader('Files analyzed by compiler');\n\t\t\tfor (const sourceFile of sourceFiles) {\n\t\t\t\tthis.messageRouter.logDiagnostic(sourceFile.fileName);\n\t\t\t}\n\n\t\t\tthis.messageRouter.logDiagnosticFooter();\n\t\t}\n\n\t\t// We can throw this error earlier in CompilerState.ts, but intentionally wait until after we've logged the\n\t\t// associated diagnostic message above to make debugging easier for developers.\n\t\t// Typically there will be many such files -- to avoid too much noise, only report the first one.\n\t\tconst badSourceFile: ts.SourceFile | undefined = sourceFiles.find(\n\t\t\t({ fileName }) => !ExtractorConfig.hasDtsFileExtension(fileName),\n\t\t);\n\t\tif (badSourceFile) {\n\t\t\tthis.messageRouter.addAnalyzerIssueForPosition(\n\t\t\t\tExtractorMessageId.WrongInputFileType,\n\t\t\t\t'Incorrect file type; API Extractor expects to analyze compiler outputs with the .d.ts file extension. ' +\n\t\t\t\t\t'Troubleshooting tips: https://api-extractor.com/link/dts-error',\n\t\t\t\tbadSourceFile,\n\t\t\t\t0,\n\t\t\t);\n\t\t}\n\n\t\t// Build entry points\n\t\tfor (const entryPoint of this.workingPackage.entryPoints) {\n\t\t\tconst { sourceFile: entryPointSourceFile } = entryPoint;\n\n\t\t\tconst astEntryPoint: AstModule = this.astSymbolTable.fetchAstModuleFromWorkingPackage(entryPointSourceFile);\n\n\t\t\tif (this._astEntryPoints) {\n\t\t\t\tthis._astEntryPoints.push(astEntryPoint);\n\t\t\t} else {\n\t\t\t\tthis._astEntryPoints = [astEntryPoint];\n\t\t\t}\n\n\t\t\tif (!this._entitiesByAstEntryPoint.has(entryPoint)) {\n\t\t\t\tthis._entitiesByAstEntryPoint.set(entryPoint, []);\n\t\t\t}\n\n\t\t\t// Process pacakgeDocComment only for the default entry point\n\t\t\tif (this.workingPackage.isDefaultEntryPoint(entryPoint)) {\n\t\t\t\tconst packageDocCommentTextRange: ts.TextRange | undefined = PackageDocComment.tryFindInSourceFile(\n\t\t\t\t\tentryPointSourceFile,\n\t\t\t\t\tthis,\n\t\t\t\t);\n\n\t\t\t\tif (packageDocCommentTextRange) {\n\t\t\t\t\tconst range: tsdoc.TextRange = tsdoc.TextRange.fromStringRange(\n\t\t\t\t\t\tentryPointSourceFile.text,\n\t\t\t\t\t\tpackageDocCommentTextRange.pos,\n\t\t\t\t\t\tpackageDocCommentTextRange.end,\n\t\t\t\t\t);\n\n\t\t\t\t\tthis.workingPackage.tsdocParserContext = this._tsdocParser.parseRange(range);\n\n\t\t\t\t\tthis.messageRouter.addTsdocMessages(this.workingPackage.tsdocParserContext, entryPointSourceFile);\n\n\t\t\t\t\tthis.workingPackage.tsdocComment = this.workingPackage.tsdocParserContext!.docComment;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst { exportedLocalEntities, starExportedExternalModules, visitedAstModules }: IAstModuleExportInfo =\n\t\t\t\tthis.astSymbolTable.fetchAstModuleExportInfo(astEntryPoint);\n\n\t\t\t// Create a CollectorEntity for each top-level export.\n\t\t\tconst processedAstEntities: AstEntity[] = [];\n\t\t\tfor (const [exportName, astEntity] of exportedLocalEntities) {\n\t\t\t\tthis._createCollectorEntity(astEntity, entryPoint, exportName);\n\t\t\t\tprocessedAstEntities.push(astEntity);\n\t\t\t}\n\n\t\t\t// Recursively create the remaining CollectorEntities after the top-level entities\n\t\t\t// have been processed.\n\t\t\tconst alreadySeenAstEntities: Set<AstEntity> = new Set<AstEntity>();\n\t\t\tfor (const astEntity of processedAstEntities) {\n\t\t\t\tthis._recursivelyCreateEntities(astEntity, entryPoint, alreadySeenAstEntities);\n\t\t\t\tif (astEntity instanceof AstSymbol) {\n\t\t\t\t\tthis.fetchSymbolMetadata(astEntity);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Ensure references are collected from any intermediate files that\n\t\t\t// only include exports\n\t\t\tconst nonExternalSourceFiles: Set<ts.SourceFile> = new Set();\n\t\t\tfor (const { sourceFile, isExternal } of visitedAstModules) {\n\t\t\t\tif (!nonExternalSourceFiles.has(sourceFile) && !isExternal) {\n\t\t\t\t\tnonExternalSourceFiles.add(sourceFile);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Here, we're collecting reference directives from all non-external source files\n\t\t\t// that were encountered while looking for exports, but only those references that\n\t\t\t// were explicitly written by the developer and marked with the `preserve=\"true\"`\n\t\t\t// attribute. In TS >= 5.5, only references that are explicitly authored and marked\n\t\t\t// with `preserve=\"true\"` are included in the output. See https://github.com/microsoft/TypeScript/pull/57681\n\t\t\t//\n\t\t\t// The `_collectReferenceDirectives` function pulls in all references in files that\n\t\t\t// contain definitions, but does not examine files that only reexport from other\n\t\t\t// files. Here, we're looking through files that were missed by `_collectReferenceDirectives`,\n\t\t\t// but only collecting references that were explicitly marked with `preserve=\"true\"`.\n\t\t\t// It is intuitive for developers to include references that they explicitly want part of\n\t\t\t// their public API in a file like the entrypoint, which is likely to only contain reexports,\n\t\t\t// and this picks those up.\n\t\t\tthis._collectReferenceDirectivesFromSourceFiles(nonExternalSourceFiles, true);\n\n\t\t\tthis._makeUniqueNames(entryPoint);\n\n\t\t\tfor (const starExportedExternalModule of starExportedExternalModules) {\n\t\t\t\tif (starExportedExternalModule.externalModulePath !== undefined) {\n\t\t\t\t\tthis._starExportedExternalModulePaths.push(starExportedExternalModule.externalModulePath);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const entities of this._entitiesByAstEntryPoint.values()) {\n\t\t\tSort.sortBy(entities, (x) => x.getSortKey());\n\t\t}\n\n\t\tSort.sortSet(this._dtsTypeReferenceDirectives);\n\t\tSort.sortSet(this._dtsLibReferenceDirectives);\n\t\t// eslint-disable-next-line @typescript-eslint/require-array-sort-compare\n\t\tthis._starExportedExternalModulePaths.sort();\n\t}\n\n\t/**\n\t * For a given ts.Identifier that is part of an AstSymbol that we analyzed, return the CollectorEntity that\n\t * it refers to.  Returns undefined if it doesn't refer to anything interesting.\n\t *\n\t * @remarks\n\t * Throws an Error if the ts.Identifier is not part of node tree that was analyzed.\n\t */\n\tpublic tryGetEntityForNode(identifier: ts.Identifier | ts.ImportTypeNode): CollectorEntity | undefined {\n\t\tconst astEntity: AstEntity | undefined = this.astSymbolTable.tryGetEntityForNode(identifier);\n\t\tif (astEntity) {\n\t\t\treturn this._entitiesByAstEntity.get(astEntity);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * For a given analyzed ts.Symbol, return the CollectorEntity that it refers to. Returns undefined if it\n\t * doesn't refer to anything interesting.\n\t */\n\tpublic tryGetEntityForSymbol(symbol: ts.Symbol): CollectorEntity | undefined {\n\t\treturn this._entitiesBySymbol.get(symbol);\n\t}\n\n\t/**\n\t * Returns the associated `CollectorEntity` for the given `astEntity`, if one was created during analysis.\n\t */\n\tpublic tryGetCollectorEntity(astEntity: AstEntity): CollectorEntity | undefined {\n\t\treturn this._entitiesByAstEntity.get(astEntity);\n\t}\n\n\tpublic fetchSymbolMetadata(astSymbol: AstSymbol): SymbolMetadata {\n\t\tif (astSymbol.symbolMetadata === undefined) {\n\t\t\tthis._fetchSymbolMetadata(astSymbol);\n\t\t}\n\n\t\treturn astSymbol.symbolMetadata as SymbolMetadata;\n\t}\n\n\tpublic fetchDeclarationMetadata(astDeclaration: AstDeclaration): DeclarationMetadata {\n\t\tif (astDeclaration.declarationMetadata === undefined) {\n\t\t\t// Fetching the SymbolMetadata always constructs the DeclarationMetadata\n\t\t\tthis._fetchSymbolMetadata(astDeclaration.astSymbol);\n\t\t}\n\n\t\treturn astDeclaration.declarationMetadata as DeclarationMetadata;\n\t}\n\n\tpublic fetchApiItemMetadata(astDeclaration: AstDeclaration): ApiItemMetadata {\n\t\tif (astDeclaration.apiItemMetadata === undefined) {\n\t\t\t// Fetching the SymbolMetadata always constructs the ApiItemMetadata\n\t\t\tthis._fetchSymbolMetadata(astDeclaration.astSymbol);\n\t\t}\n\n\t\treturn astDeclaration.apiItemMetadata as ApiItemMetadata;\n\t}\n\n\tpublic tryFetchMetadataForAstEntity(astEntity: AstEntity): SymbolMetadata | undefined {\n\t\tif (astEntity instanceof AstSymbol) {\n\t\t\treturn this.fetchSymbolMetadata(astEntity);\n\t\t}\n\n\t\tif (astEntity instanceof AstImport && astEntity.astSymbol) {\n\t\t\treturn this.fetchSymbolMetadata(astEntity.astSymbol);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tpublic isAncillaryDeclaration(astDeclaration: AstDeclaration): boolean {\n\t\tconst declarationMetadata: DeclarationMetadata = this.fetchDeclarationMetadata(astDeclaration);\n\t\treturn declarationMetadata.isAncillary;\n\t}\n\n\tpublic getNonAncillaryDeclarations(astSymbol: AstSymbol): readonly AstDeclaration[] {\n\t\tconst result: AstDeclaration[] = [];\n\t\tfor (const astDeclaration of astSymbol.astDeclarations) {\n\t\t\tconst declarationMetadata: DeclarationMetadata = this.fetchDeclarationMetadata(astDeclaration);\n\t\t\tif (!declarationMetadata.isAncillary) {\n\t\t\t\tresult.push(astDeclaration);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Removes the leading underscore, for example: \"_Example\" --\\> \"example*Example*_\"\n\t *\n\t * @remarks\n\t * This causes internal definitions to sort alphabetically case-insensitive, then case-sensitive, and\n\t * initially ignoring the underscore prefix, while still deterministically comparing it.\n\t * The star is used as a delimiter because it is not a legal  identifier character.\n\t */\n\tpublic static getSortKeyIgnoringUnderscore(identifier: string | undefined): string {\n\t\tif (!identifier) return '';\n\n\t\tlet parts: string[];\n\n\t\tif (identifier.startsWith('_')) {\n\t\t\tconst withoutUnderscore: string = identifier.slice(1);\n\t\t\tparts = [withoutUnderscore.toLowerCase(), '*', withoutUnderscore, '*', '_'];\n\t\t} else {\n\t\t\tparts = [identifier.toLowerCase(), '*', identifier];\n\t\t}\n\n\t\treturn parts.join('');\n\t}\n\n\t/**\n\t * For function-like signatures, this returns the TSDoc \"overload index\" which can be used to identify\n\t * a specific overload.\n\t */\n\tpublic getOverloadIndex(astDeclaration: AstDeclaration): number {\n\t\tconst allDeclarations: readonly AstDeclaration[] = astDeclaration.astSymbol.astDeclarations;\n\t\tif (allDeclarations.length === 1) {\n\t\t\treturn 1; // trivial case\n\t\t}\n\n\t\tlet overloadIndex: number | undefined = this._cachedOverloadIndexesByDeclaration.get(astDeclaration);\n\n\t\tif (overloadIndex === undefined) {\n\t\t\t// TSDoc index selectors are positive integers counting from 1\n\t\t\tlet nextIndex = 1;\n\t\t\tfor (const other of allDeclarations) {\n\t\t\t\t// Filter out other declarations that are not overloads.  For example, an overloaded function can also\n\t\t\t\t// be a namespace.\n\t\t\t\tif (other.declaration.kind === astDeclaration.declaration.kind) {\n\t\t\t\t\tthis._cachedOverloadIndexesByDeclaration.set(other, nextIndex);\n\t\t\t\t\t++nextIndex;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toverloadIndex = this._cachedOverloadIndexesByDeclaration.get(astDeclaration);\n\t\t}\n\n\t\tif (overloadIndex === undefined) {\n\t\t\t// This should never happen\n\t\t\tthrow new InternalError('Error calculating overload index for declaration');\n\t\t}\n\n\t\treturn overloadIndex;\n\t}\n\n\tprivate _createCollectorEntity(\n\t\tastEntity: AstEntity,\n\t\tentryPoint: IWorkingPackageEntryPoint,\n\t\texportName?: string,\n\t\tparent?: CollectorEntity,\n\t): void {\n\t\tlet entity: CollectorEntity | undefined = this._entitiesByAstEntity.get(astEntity);\n\n\t\tif (!entity) {\n\t\t\tentity = new CollectorEntity(astEntity);\n\n\t\t\tthis._entitiesByAstEntity.set(astEntity, entity);\n\t\t\tif (astEntity instanceof AstSymbol) {\n\t\t\t\tthis._entitiesBySymbol.set(astEntity.followedSymbol, entity);\n\t\t\t} else if (astEntity instanceof AstNamespaceImport) {\n\t\t\t\tthis._entitiesBySymbol.set(astEntity.symbol, entity);\n\t\t\t}\n\n\t\t\tthis._collectReferenceDirectives(astEntity);\n\t\t}\n\n\t\t// add collectorEntity to the corresponding entry point\n\t\tconst entitiesOfAstModule: CollectorEntity[] = this._entitiesByAstEntryPoint.get(entryPoint) || [];\n\t\tif (!entitiesOfAstModule.includes(entity)) {\n\t\t\tentitiesOfAstModule.push(entity);\n\t\t\tthis._entitiesByAstEntryPoint.set(entryPoint, entitiesOfAstModule);\n\t\t}\n\n\t\tif (exportName) {\n\t\t\tif (parent) {\n\t\t\t\tentity.addLocalExportName(exportName, parent);\n\t\t\t} else {\n\t\t\t\tentity.addExportName(exportName);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _recursivelyCreateEntities(\n\t\tastEntity: AstEntity,\n\t\tentryPoint: IWorkingPackageEntryPoint,\n\t\talreadySeenAstEntities: Set<AstEntity>,\n\t): void {\n\t\tif (alreadySeenAstEntities.has(astEntity)) return;\n\t\talreadySeenAstEntities.add(astEntity);\n\n\t\tif (astEntity instanceof AstSymbol) {\n\t\t\tastEntity.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => {\n\t\t\t\tfor (const referencedAstEntity of astDeclaration.referencedAstEntities) {\n\t\t\t\t\tif (referencedAstEntity instanceof AstSymbol) {\n\t\t\t\t\t\t// We only create collector entities for root-level symbols. For example, if a symbol is\n\t\t\t\t\t\t// nested inside a namespace, only the namespace gets a collector entity. Note that this\n\t\t\t\t\t\t// is not true for AstNamespaceImports below.\n\t\t\t\t\t\tif (referencedAstEntity.parentAstSymbol === undefined) {\n\t\t\t\t\t\t\tthis._createCollectorEntity(referencedAstEntity, entryPoint);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._createCollectorEntity(referencedAstEntity, entryPoint);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._recursivelyCreateEntities(referencedAstEntity, entryPoint, alreadySeenAstEntities);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tif (astEntity instanceof AstNamespaceImport) {\n\t\t\tconst astModuleExportInfo: IAstModuleExportInfo = astEntity.fetchAstModuleExportInfo(this);\n\t\t\tconst parentEntity: CollectorEntity | undefined = this._entitiesByAstEntity.get(astEntity);\n\t\t\tif (!parentEntity) {\n\t\t\t\t// This should never happen, as we've already created entities for all AstNamespaceImports.\n\t\t\t\tthrow new InternalError(\n\t\t\t\t\t`Failed to get CollectorEntity for AstNamespaceImport with namespace name \"${astEntity.namespaceName}\"`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tfor (const [localExportName, localAstEntity] of astModuleExportInfo.exportedLocalEntities) {\n\t\t\t\t// Create a CollectorEntity for each local export within an AstNamespaceImport entity.\n\t\t\t\tthis._createCollectorEntity(localAstEntity, entryPoint, localExportName, parentEntity);\n\t\t\t\tthis._recursivelyCreateEntities(localAstEntity, entryPoint, alreadySeenAstEntities);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Ensures a unique name for each item in the entry point typings file.\n\t */\n\tprivate _makeUniqueNames(entryPoint: IWorkingPackageEntryPoint): void {\n\t\t// The following examples illustrate the nameForEmit heuristics:\n\t\t//\n\t\t// Example 1:\n\t\t//   class X { } <--- nameForEmit should be \"A\" to simplify things and reduce possibility of conflicts\n\t\t//   export { X as A };\n\t\t//\n\t\t// Example 2:\n\t\t//   class X { } <--- nameForEmit should be \"X\" because choosing A or B would be nondeterministic\n\t\t//   export { X as A };\n\t\t//   export { X as B };\n\t\t//\n\t\t// Example 3:\n\t\t//   class X { } <--- nameForEmit should be \"X_1\" because Y has a stronger claim to the name\n\t\t//   export { X as A };\n\t\t//   export { X as B };\n\t\t//   class Y { } <--- nameForEmit should be \"X\"\n\t\t//   export { Y as X };\n\n\t\t// Set of names that should NOT be used when generating a unique nameForEmit\n\t\tconst usedNames: Set<string> = new Set<string>();\n\n\t\tconst entities: CollectorEntity[] = this._entitiesByAstEntryPoint.get(entryPoint) || [];\n\n\t\t// First collect the names of explicit package exports, and perform a sanity check.\n\t\tfor (const entity of entities) {\n\t\t\tfor (const exportName of entity.exportNames) {\n\t\t\t\tif (usedNames.has(exportName)) {\n\t\t\t\t\t// This should be impossible\n\t\t\t\t\tthrow new InternalError(`A package cannot have two exports with the name \"${exportName}\"`);\n\t\t\t\t}\n\n\t\t\t\tusedNames.add(exportName);\n\t\t\t}\n\t\t}\n\n\t\t// Ensure that each entity has a unique nameForEmit\n\t\tfor (const entity of entities) {\n\t\t\t// What name would we ideally want to emit it as?\n\t\t\tlet idealNameForEmit: string;\n\n\t\t\t// If this entity is exported exactly once, then we prefer the exported name\n\t\t\tif (entity.singleExportName !== undefined && entity.singleExportName !== ts.InternalSymbolName.Default) {\n\t\t\t\tidealNameForEmit = entity.singleExportName;\n\t\t\t} else {\n\t\t\t\t// otherwise use the local name\n\t\t\t\tidealNameForEmit = entity.astEntity.localName;\n\t\t\t}\n\n\t\t\tif (idealNameForEmit.includes('.')) {\n\t\t\t\t// For an ImportType with a namespace chain, only the top namespace is imported.\n\t\t\t\tidealNameForEmit = idealNameForEmit.split('.')[0]!;\n\t\t\t}\n\n\t\t\t// If the idealNameForEmit happens to be the same as one of the exports, then we're safe to use that...\n\t\t\tif (\n\t\t\t\tentity.exportNames.has(idealNameForEmit) && // ...except that if it conflicts with a global name, then the global name wins\n\t\t\t\t!this.globalVariableAnalyzer.hasGlobalName(idealNameForEmit) && // ...also avoid \"default\" which can interfere with \"export { default } from 'some-module;'\"\n\t\t\t\tidealNameForEmit !== 'default'\n\t\t\t) {\n\t\t\t\tentity.nameForEmit = idealNameForEmit;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Generate a unique name based on idealNameForEmit\n\t\t\tlet suffix = 1;\n\t\t\tlet nameForEmit: string = idealNameForEmit;\n\n\t\t\t// Choose a name that doesn't conflict with usedNames or a global name\n\t\t\twhile (\n\t\t\t\tnameForEmit === 'default' ||\n\t\t\t\tusedNames.has(nameForEmit) ||\n\t\t\t\tthis.globalVariableAnalyzer.hasGlobalName(nameForEmit)\n\t\t\t) {\n\t\t\t\tnameForEmit = `${idealNameForEmit}_${++suffix}`;\n\t\t\t}\n\n\t\t\tentity.nameForEmit = nameForEmit;\n\t\t\tusedNames.add(nameForEmit);\n\t\t}\n\t}\n\n\tprivate _fetchSymbolMetadata(astSymbol: AstSymbol): void {\n\t\tif (astSymbol.symbolMetadata) {\n\t\t\treturn;\n\t\t}\n\n\t\t// When we solve an astSymbol, then we always also solve all of its parents and all of its declarations.\n\t\t// The parent is solved first.\n\t\tif (astSymbol.parentAstSymbol && astSymbol.parentAstSymbol.symbolMetadata === undefined) {\n\t\t\tthis._fetchSymbolMetadata(astSymbol.parentAstSymbol);\n\t\t}\n\n\t\t// Construct the DeclarationMetadata objects, and detect any ancillary declarations\n\t\tthis._calculateDeclarationMetadataForDeclarations(astSymbol);\n\n\t\t// Calculate the ApiItemMetadata objects\n\t\tfor (const astDeclaration of astSymbol.astDeclarations) {\n\t\t\tthis._calculateApiItemMetadata(astDeclaration);\n\t\t}\n\n\t\t// The most public effectiveReleaseTag for all declarations\n\t\tlet maxEffectiveReleaseTag: ReleaseTag = ReleaseTag.None;\n\n\t\tfor (const astDeclaration of astSymbol.astDeclarations) {\n\t\t\t// We know we solved this above\n\t\t\tconst apiItemMetadata: ApiItemMetadata = astDeclaration.apiItemMetadata as ApiItemMetadata;\n\n\t\t\tconst effectiveReleaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\n\t\t\tif (effectiveReleaseTag > maxEffectiveReleaseTag) {\n\t\t\t\tmaxEffectiveReleaseTag = effectiveReleaseTag;\n\t\t\t}\n\t\t}\n\n\t\t// Update this last when we're sure no exceptions were thrown\n\t\tastSymbol.symbolMetadata = new SymbolMetadata({\n\t\t\tmaxEffectiveReleaseTag,\n\t\t});\n\t}\n\n\tprivate _calculateDeclarationMetadataForDeclarations(astSymbol: AstSymbol): void {\n\t\t// Initialize DeclarationMetadata for each declaration\n\t\tfor (const astDeclaration of astSymbol.astDeclarations) {\n\t\t\tif (astDeclaration.declarationMetadata) {\n\t\t\t\tthrow new InternalError('AstDeclaration.declarationMetadata is not expected to have been initialized yet');\n\t\t\t}\n\n\t\t\tconst metadata: InternalDeclarationMetadata = new InternalDeclarationMetadata();\n\t\t\tmetadata.tsdocParserContext = this._parseTsdocForAstDeclaration(astDeclaration);\n\n\t\t\tastDeclaration.declarationMetadata = metadata;\n\t\t}\n\n\t\t// Detect ancillary declarations\n\t\tfor (const astDeclaration of astSymbol.astDeclarations) {\n\t\t\t// For a getter/setter pair, make the setter ancillary to the getter\n\t\t\tif (astDeclaration.declaration.kind === ts.SyntaxKind.SetAccessor) {\n\t\t\t\tlet foundGetter = false;\n\t\t\t\tfor (const getterAstDeclaration of astDeclaration.astSymbol.astDeclarations) {\n\t\t\t\t\tif (getterAstDeclaration.declaration.kind === ts.SyntaxKind.GetAccessor) {\n\t\t\t\t\t\t// Associate it with the getter\n\t\t\t\t\t\tthis._addAncillaryDeclaration(getterAstDeclaration, astDeclaration);\n\n\t\t\t\t\t\tfoundGetter = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!foundGetter) {\n\t\t\t\t\tthis.messageRouter.addAnalyzerIssue(\n\t\t\t\t\t\tExtractorMessageId.MissingGetter,\n\t\t\t\t\t\t`The property \"${astDeclaration.astSymbol.localName}\" has a setter but no getter.`,\n\t\t\t\t\t\tastDeclaration,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _addAncillaryDeclaration(mainAstDeclaration: AstDeclaration, ancillaryAstDeclaration: AstDeclaration): void {\n\t\tconst mainMetadata: InternalDeclarationMetadata =\n\t\t\tmainAstDeclaration.declarationMetadata as InternalDeclarationMetadata;\n\t\tconst ancillaryMetadata: InternalDeclarationMetadata =\n\t\t\tancillaryAstDeclaration.declarationMetadata as InternalDeclarationMetadata;\n\n\t\tif (mainMetadata.ancillaryDeclarations.includes(ancillaryAstDeclaration)) {\n\t\t\treturn; // already added\n\t\t}\n\n\t\tif (mainAstDeclaration.astSymbol !== ancillaryAstDeclaration.astSymbol) {\n\t\t\tthrow new InternalError(\n\t\t\t\t'Invalid call to _addAncillaryDeclaration() because declarations do not belong to the same symbol',\n\t\t\t);\n\t\t}\n\n\t\tif (mainMetadata.isAncillary) {\n\t\t\tthrow new InternalError('Invalid call to _addAncillaryDeclaration() because the target is ancillary itself');\n\t\t}\n\n\t\tif (ancillaryMetadata.isAncillary) {\n\t\t\tthrow new InternalError(\n\t\t\t\t'Invalid call to _addAncillaryDeclaration() because source is already ancillary to another declaration',\n\t\t\t);\n\t\t}\n\n\t\tif (mainAstDeclaration.apiItemMetadata || ancillaryAstDeclaration.apiItemMetadata) {\n\t\t\tthrow new InternalError(\n\t\t\t\t'Invalid call to _addAncillaryDeclaration() because the API item metadata has already been constructed',\n\t\t\t);\n\t\t}\n\n\t\tancillaryMetadata.isAncillary = true;\n\t\tmainMetadata.ancillaryDeclarations.push(ancillaryAstDeclaration);\n\t}\n\n\tprivate _calculateApiItemMetadata(astDeclaration: AstDeclaration): void {\n\t\tconst declarationMetadata: InternalDeclarationMetadata =\n\t\t\tastDeclaration.declarationMetadata as InternalDeclarationMetadata;\n\t\tif (declarationMetadata.isAncillary) {\n\t\t\tif (astDeclaration.declaration.kind === ts.SyntaxKind.SetAccessor && declarationMetadata.tsdocParserContext) {\n\t\t\t\tthis.messageRouter.addAnalyzerIssue(\n\t\t\t\t\tExtractorMessageId.SetterWithDocs,\n\t\t\t\t\t`The doc comment for the property \"${astDeclaration.astSymbol.localName}\"` +\n\t\t\t\t\t\t` must appear on the getter, not the setter.`,\n\t\t\t\t\tastDeclaration,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// We never calculate ApiItemMetadata for an ancillary declaration; instead, it is assigned when\n\t\t\t// the main declaration is processed.\n\t\t\treturn;\n\t\t}\n\n\t\tconst options: IApiItemMetadataOptions = {\n\t\t\tdeclaredReleaseTag: ReleaseTag.None,\n\t\t\teffectiveReleaseTag: ReleaseTag.None,\n\t\t\tisEventProperty: false,\n\t\t\tisOverride: false,\n\t\t\tisSealed: false,\n\t\t\tisVirtual: false,\n\t\t\tisPreapproved: false,\n\t\t\treleaseTagSameAsParent: false,\n\t\t};\n\n\t\tconst parserContext: tsdoc.ParserContext | undefined = declarationMetadata.tsdocParserContext;\n\t\tif (parserContext) {\n\t\t\tconst modifierTagSet: tsdoc.StandardModifierTagSet = parserContext.docComment.modifierTagSet;\n\n\t\t\tlet declaredReleaseTag: ReleaseTag = ReleaseTag.None;\n\t\t\tlet extraReleaseTags = false;\n\n\t\t\tif (modifierTagSet.isPublic()) {\n\t\t\t\tdeclaredReleaseTag = ReleaseTag.Public;\n\t\t\t}\n\n\t\t\tif (modifierTagSet.isBeta()) {\n\t\t\t\tif (declaredReleaseTag === ReleaseTag.None) {\n\t\t\t\t\tdeclaredReleaseTag = ReleaseTag.Beta;\n\t\t\t\t} else {\n\t\t\t\t\textraReleaseTags = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (modifierTagSet.isAlpha()) {\n\t\t\t\tif (declaredReleaseTag === ReleaseTag.None) {\n\t\t\t\t\tdeclaredReleaseTag = ReleaseTag.Alpha;\n\t\t\t\t} else {\n\t\t\t\t\textraReleaseTags = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (modifierTagSet.isInternal()) {\n\t\t\t\tif (declaredReleaseTag === ReleaseTag.None) {\n\t\t\t\t\tdeclaredReleaseTag = ReleaseTag.Internal;\n\t\t\t\t} else {\n\t\t\t\t\textraReleaseTags = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (extraReleaseTags && !astDeclaration.astSymbol.isExternal) {\n\t\t\t\t// for now, don't report errors for external code\n\t\t\t\tthis.messageRouter.addAnalyzerIssue(\n\t\t\t\t\tExtractorMessageId.ExtraReleaseTag,\n\t\t\t\t\t'The doc comment should not contain more than one release tag',\n\t\t\t\t\tastDeclaration,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\toptions.declaredReleaseTag = declaredReleaseTag;\n\n\t\t\toptions.isEventProperty = modifierTagSet.isEventProperty();\n\t\t\toptions.isOverride = modifierTagSet.isOverride();\n\t\t\toptions.isSealed = modifierTagSet.isSealed();\n\t\t\toptions.isVirtual = modifierTagSet.isVirtual();\n\t\t\tconst preapprovedTag: tsdoc.TSDocTagDefinition | undefined =\n\t\t\t\tthis.extractorConfig.tsdocConfiguration.tryGetTagDefinition('@preapproved');\n\n\t\t\tif (preapprovedTag && modifierTagSet.hasTag(preapprovedTag)) {\n\t\t\t\t// This feature only makes sense for potentially big declarations.\n\t\t\t\tswitch (astDeclaration.declaration.kind) {\n\t\t\t\t\tcase ts.SyntaxKind.ClassDeclaration:\n\t\t\t\t\tcase ts.SyntaxKind.EnumDeclaration:\n\t\t\t\t\tcase ts.SyntaxKind.InterfaceDeclaration:\n\t\t\t\t\tcase ts.SyntaxKind.ModuleDeclaration:\n\t\t\t\t\t\tif (declaredReleaseTag === ReleaseTag.Internal) {\n\t\t\t\t\t\t\toptions.isPreapproved = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.messageRouter.addAnalyzerIssue(\n\t\t\t\t\t\t\t\tExtractorMessageId.PreapprovedBadReleaseTag,\n\t\t\t\t\t\t\t\t`The @preapproved tag cannot be applied to \"${astDeclaration.astSymbol.localName}\"` +\n\t\t\t\t\t\t\t\t\t` without an @internal release tag`,\n\t\t\t\t\t\t\t\tastDeclaration,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthis.messageRouter.addAnalyzerIssue(\n\t\t\t\t\t\t\tExtractorMessageId.PreapprovedUnsupportedType,\n\t\t\t\t\t\t\t`The @preapproved tag cannot be applied to \"${astDeclaration.astSymbol.localName}\"` +\n\t\t\t\t\t\t\t\t` because it is not a supported declaration type`,\n\t\t\t\t\t\t\tastDeclaration,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// This needs to be set regardless of whether or not a parserContext exists\n\t\tif (astDeclaration.parent) {\n\t\t\tconst parentApiItemMetadata: ApiItemMetadata = this.fetchApiItemMetadata(astDeclaration.parent);\n\t\t\toptions.effectiveReleaseTag =\n\t\t\t\toptions.declaredReleaseTag === ReleaseTag.None\n\t\t\t\t\t? parentApiItemMetadata.effectiveReleaseTag\n\t\t\t\t\t: options.declaredReleaseTag;\n\n\t\t\toptions.releaseTagSameAsParent = parentApiItemMetadata.effectiveReleaseTag === options.effectiveReleaseTag;\n\t\t} else {\n\t\t\toptions.effectiveReleaseTag = options.declaredReleaseTag;\n\t\t}\n\n\t\tif (options.effectiveReleaseTag === ReleaseTag.None) {\n\t\t\tif (!astDeclaration.astSymbol.isExternal) {\n\t\t\t\t// for now, don't report errors for external code\n\t\t\t\t// Don't report missing release tags for forgotten exports (unless we're including forgotten exports\n\t\t\t\t// in either the API report or doc model).\n\t\t\t\tconst astSymbol: AstSymbol = astDeclaration.astSymbol;\n\t\t\t\tconst entity: CollectorEntity | undefined = this._entitiesByAstEntity.get(astSymbol.rootAstSymbol);\n\t\t\t\tif (\n\t\t\t\t\tentity &&\n\t\t\t\t\t(entity.consumable ||\n\t\t\t\t\t\tthis.extractorConfig.apiReportIncludeForgottenExports ||\n\t\t\t\t\t\tthis.extractorConfig.docModelIncludeForgottenExports) && // We also don't report errors for the default export of an entry point, since its doc comment\n\t\t\t\t\t// isn't easy to obtain from the .d.ts file\n\t\t\t\t\tastSymbol.rootAstSymbol.localName !== '_default'\n\t\t\t\t) {\n\t\t\t\t\tthis.messageRouter.addAnalyzerIssue(\n\t\t\t\t\t\tExtractorMessageId.MissingReleaseTag,\n\t\t\t\t\t\t`\"${entity.astEntity.localName}\" is part of the package's API, but it is missing ` +\n\t\t\t\t\t\t\t`a release tag (@alpha, @beta, @public, or @internal)`,\n\t\t\t\t\t\tastSymbol,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toptions.effectiveReleaseTag = ReleaseTag.Public;\n\t\t}\n\n\t\tconst apiItemMetadata: ApiItemMetadata = new ApiItemMetadata(options);\n\t\tif (parserContext) {\n\t\t\tapiItemMetadata.tsdocComment = parserContext.docComment;\n\t\t}\n\n\t\tastDeclaration.apiItemMetadata = apiItemMetadata;\n\n\t\t// Lastly, share the result with any ancillary declarations\n\t\tfor (const ancillaryDeclaration of declarationMetadata.ancillaryDeclarations) {\n\t\t\tancillaryDeclaration.apiItemMetadata = apiItemMetadata;\n\t\t}\n\t}\n\n\tprivate _parseTsdocForAstDeclaration(astDeclaration: AstDeclaration): tsdoc.ParserContext | undefined {\n\t\tconst declaration: ts.Declaration = astDeclaration.declaration;\n\t\tlet nodeForComment: ts.Node = declaration;\n\n\t\tif (ts.isVariableDeclaration(declaration)) {\n\t\t\t// Variable declarations are special because they can be combined into a list.  For example:\n\t\t\t//\n\t\t\t// /** A */ export /** B */ const /** C */ x = 1, /** D **/ [ /** E */ y, z] = [3, 4];\n\t\t\t//\n\t\t\t// The compiler will only emit comments A and C in the .d.ts file, so in general there isn't a well-defined\n\t\t\t// way to document these parts.  API Extractor requires you to break them into separate exports like this:\n\t\t\t//\n\t\t\t// /** A */ export const x = 1;\n\t\t\t//\n\t\t\t// But _getReleaseTagForDeclaration() still receives a node corresponding to \"x\", so we need to walk upwards\n\t\t\t// and find the containing statement in order for getJSDocCommentRanges() to read the comment that we expect.\n\t\t\tconst statement: ts.VariableStatement | undefined = TypeScriptHelpers.findFirstParent(\n\t\t\t\tdeclaration,\n\t\t\t\tts.SyntaxKind.VariableStatement,\n\t\t\t) as ts.VariableStatement | undefined;\n\t\t\t// For a compound declaration, fall back to looking for C instead of A\n\t\t\tif (statement?.declarationList.declarations.length === 1) {\n\t\t\t\tnodeForComment = statement;\n\t\t\t}\n\t\t}\n\n\t\tconst sourceFileText: string = declaration.getSourceFile().text;\n\t\tconst ranges: ts.CommentRange[] = TypeScriptInternals.getJSDocCommentRanges(nodeForComment, sourceFileText) ?? [];\n\n\t\tif (ranges.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// We use the JSDoc comment block that is closest to the definition, i.e.\n\t\t// the last one preceding it\n\t\tconst range: ts.TextRange = ranges[ranges.length - 1]!;\n\n\t\tconst tsdocTextRange: tsdoc.TextRange = tsdoc.TextRange.fromStringRange(sourceFileText, range.pos, range.end);\n\n\t\tconst parserContext: tsdoc.ParserContext = this._tsdocParser.parseRange(tsdocTextRange);\n\n\t\tthis.messageRouter.addTsdocMessages(parserContext, declaration.getSourceFile(), astDeclaration);\n\n\t\t// We delete the @privateRemarks block as early as possible, to ensure that it never leaks through\n\t\t// into one of the output files.\n\t\tparserContext.docComment.privateRemarks = undefined;\n\n\t\treturn parserContext;\n\t}\n\n\tprivate _collectReferenceDirectives(astEntity: AstEntity): void {\n\t\t// Here, we're collecting reference directives from source files that contain extracted\n\t\t// definitions (i.e. - files that contain `export class ...`, `export interface ...`, ...).\n\t\t// These references may or may not include the `preserve=\"true\" attribute. In TS < 5.5,\n\t\t// references that end up in .D.TS files may or may not be explicity written by the developer.\n\t\t// In TS >= 5.5, only references that are explicitly authored and are marked with\n\t\t// `preserve=\"true\"` are included in the output. See https://github.com/microsoft/TypeScript/pull/57681\n\t\t//\n\t\t// The calls to `_collectReferenceDirectivesFromSourceFiles` in this function are\n\t\t// preserving existing behavior, which is to include all reference directives\n\t\t// regardless of whether they are explicitly authored or not, but only in files that\n\t\t// contain definitions.\n\n\t\tif (astEntity instanceof AstSymbol) {\n\t\t\tconst sourceFiles: ts.SourceFile[] = astEntity.astDeclarations.map((astDeclaration) =>\n\t\t\t\tastDeclaration.declaration.getSourceFile(),\n\t\t\t);\n\t\t\tthis._collectReferenceDirectivesFromSourceFiles(sourceFiles, false);\n\t\t\treturn;\n\t\t}\n\n\t\tif (astEntity instanceof AstNamespaceImport) {\n\t\t\tconst sourceFiles: ts.SourceFile[] = [astEntity.astModule.sourceFile];\n\t\t\tthis._collectReferenceDirectivesFromSourceFiles(sourceFiles, false);\n\t\t}\n\t}\n\n\tprivate _collectReferenceDirectivesFromSourceFiles(\n\t\tsourceFiles: Iterable<ts.SourceFile>,\n\t\tonlyIncludeExplicitlyPreserved: boolean,\n\t): void {\n\t\tconst seenFilenames: Set<string> = new Set<string>();\n\n\t\tfor (const sourceFile of sourceFiles) {\n\t\t\tif (sourceFile?.fileName) {\n\t\t\t\tconst { fileName, typeReferenceDirectives, libReferenceDirectives, text: sourceFileText } = sourceFile;\n\t\t\t\tif (!seenFilenames.has(fileName)) {\n\t\t\t\t\tseenFilenames.add(fileName);\n\n\t\t\t\t\tfor (const typeReferenceDirective of typeReferenceDirectives) {\n\t\t\t\t\t\tconst name: string | undefined = this._getReferenceDirectiveFromSourceFile(\n\t\t\t\t\t\t\tsourceFileText,\n\t\t\t\t\t\t\ttypeReferenceDirective,\n\t\t\t\t\t\t\tonlyIncludeExplicitlyPreserved,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (name) {\n\t\t\t\t\t\t\tthis._dtsTypeReferenceDirectives.add(name);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const libReferenceDirective of libReferenceDirectives) {\n\t\t\t\t\t\tconst reference: string | undefined = this._getReferenceDirectiveFromSourceFile(\n\t\t\t\t\t\t\tsourceFileText,\n\t\t\t\t\t\t\tlibReferenceDirective,\n\t\t\t\t\t\t\tonlyIncludeExplicitlyPreserved,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (reference) {\n\t\t\t\t\t\t\tthis._dtsLibReferenceDirectives.add(reference);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _getReferenceDirectiveFromSourceFile(\n\t\tsourceFileText: string,\n\t\t{ pos, end, preserve }: ts.FileReference,\n\t\tonlyIncludeExplicitlyPreserved: boolean,\n\t): string | undefined {\n\t\tconst reference: string = sourceFileText.slice(pos, end);\n\t\tif (preserve || !onlyIncludeExplicitlyPreserved) {\n\t\t\treturn reference;\n\t\t}\n\n\t\treturn undefined;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/collector/CollectorEntity.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { Sort } from '@rushstack/node-core-library';\nimport * as ts from 'typescript';\nimport type { AstEntity } from '../analyzer/AstEntity.js';\nimport { AstSymbol } from '../analyzer/AstSymbol.js';\nimport { Collector } from './Collector.js';\n\n/**\n * This is a data structure used by the Collector to track an AstEntity that may be emitted in the *.d.ts file.\n *\n * @remarks\n * The additional contextual state beyond AstSymbol is:\n * - Whether it's an export of this entry point or not\n * - The nameForEmit, which may get renamed by DtsRollupGenerator._makeUniqueNames()\n * - The export name (or names, if the same symbol is exported multiple times)\n */\nexport class CollectorEntity {\n\t/**\n\t * The AstEntity that this entry represents.\n\t */\n\tpublic readonly astEntity: AstEntity;\n\n\tprivate _exportNames: Set<string> = new Set();\n\n\tprivate _exportNamesSorted: boolean = false;\n\n\tprivate _singleExportName: string | undefined = undefined;\n\n\tprivate _localExportNamesByParent: Map<CollectorEntity, Set<string>> = new Map();\n\n\tprivate _nameForEmit: string | undefined = undefined;\n\n\tprivate _sortKey: string | undefined = undefined;\n\n\tpublic constructor(astEntity: AstEntity) {\n\t\tthis.astEntity = astEntity;\n\t}\n\n\t/**\n\t * The declaration name that will be emitted in the .d.ts rollup, .api.md, and .api.json files. Generated by\n\t * `Collector._makeUniqueNames`. Be aware that the declaration may be renamed to avoid conflicts with (1)\n\t * global names (e.g. `Promise`) and (2) if local, other local names across different files.\n\t */\n\tpublic get nameForEmit(): string | undefined {\n\t\treturn this._nameForEmit;\n\t}\n\n\tpublic set nameForEmit(value: string | undefined) {\n\t\tthis._nameForEmit = value;\n\t\tthis._sortKey = undefined; // invalidate the cached value\n\t}\n\n\t/**\n\t * The list of export names if this symbol is exported from the entry point.\n\t *\n\t * @remarks\n\t * Note that a given symbol may be exported more than once:\n\t * ```\n\t * class X { }\n\t * export { X }\n\t * export { X as Y }\n\t * ```\n\t */\n\tpublic get exportNames(): ReadonlySet<string> {\n\t\tif (!this._exportNamesSorted) {\n\t\t\tSort.sortSet(this._exportNames);\n\t\t\tthis._exportNamesSorted = true;\n\t\t}\n\n\t\treturn this._exportNames;\n\t}\n\n\t/**\n\t * If exportNames contains only one string, then singleExportName is that string.\n\t * In all other cases, it is undefined.\n\t */\n\tpublic get singleExportName(): string | undefined {\n\t\treturn this._singleExportName;\n\t}\n\n\t/**\n\t * This is true if exportNames contains only one string, and the declaration can be exported using the inline syntax\n\t * such as \"export class X \\{ \\}\" instead of \"export \\{ X \\}\".\n\t */\n\tpublic get shouldInlineExport(): boolean {\n\t\t// We don't inline an AstImport\n\t\treturn (\n\t\t\tthis.astEntity instanceof AstSymbol && // We don't inline a symbol with more than one exported name\n\t\t\tthis._singleExportName !== undefined &&\n\t\t\tthis._singleExportName !== ts.InternalSymbolName.Default && // We can't inline a symbol whose emitted name is different from the export name\n\t\t\t(this._nameForEmit === undefined || this._nameForEmit === this._singleExportName)\n\t\t);\n\t}\n\n\t/**\n\t * Indicates that this entity is exported from the package entry point. Compare to `CollectorEntity.exported`.\n\t */\n\tpublic get exportedFromEntryPoint(): boolean {\n\t\treturn this.exportNames.size > 0;\n\t}\n\n\t/**\n\t * Indicates that this entity is exported from its parent module (i.e. either the package entry point or\n\t * a local namespace). Compare to `CollectorEntity.consumable`.\n\t *\n\t * @remarks\n\t * In the example below:\n\t *\n\t * ```ts\n\t * declare function add(): void;\n\t * declare namespace calculator {\n\t *  export {\n\t *    add\n\t *  }\n\t * }\n\t * ```\n\t *\n\t * Namespace `calculator` is neither exported nor consumable, function `add` is exported (from `calculator`)\n\t * but not consumable.\n\t */\n\tpublic get exported(): boolean {\n\t\t// Exported from top-level?\n\t\tif (this.exportedFromEntryPoint) return true;\n\n\t\t// Exported from parent?\n\t\tfor (const localExportNames of this._localExportNamesByParent.values()) {\n\t\t\tif (localExportNames.size > 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Indicates that it is possible for a consumer of the API to \"consume\" this entity, either by importing\n\t * it directly or via a namespace. If an entity is not consumable, then API Extractor will report an\n\t * `ae-forgotten-export` warning. Compare to `CollectorEntity.exported`.\n\t *\n\t * @remarks\n\t * An API item is consumable if:\n\t *\n\t * 1. It is exported from the top-level entry point OR\n\t * 2. It is exported from a consumable parent entity.\n\t *\n\t * For an example of #2, consider how `AstNamespaceImport` entities are processed. A generated rollup.d.ts\n\t * might look like this:\n\t *\n\t * ```ts\n\t * declare function add(): void;\n\t * declare namespace calculator {\n\t *   export {\n\t *     add\n\t *   }\n\t * }\n\t * export { calculator }\n\t * ```\n\t *\n\t * In this example, `add` is exported via the consumable `calculator` namespace.\n\t */\n\tpublic get consumable(): boolean {\n\t\t// Exported from top-level?\n\t\tif (this.exportedFromEntryPoint) return true;\n\n\t\t// Exported from consumable parent?\n\t\tfor (const [parent, localExportNames] of this._localExportNamesByParent) {\n\t\t\tif (localExportNames.size > 0 && parent.consumable) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Return the first consumable parent that exports this entity. If there is none, returns\n\t * `undefined`.\n\t */\n\tpublic getFirstExportingConsumableParent(): CollectorEntity | undefined {\n\t\tfor (const [parent, localExportNames] of this._localExportNamesByParent) {\n\t\t\tif (parent.consumable && localExportNames.size > 0) {\n\t\t\t\treturn parent;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Adds a new export name to the entity.\n\t */\n\tpublic addExportName(exportName: string): void {\n\t\tif (!this._exportNames.has(exportName)) {\n\t\t\tthis._exportNamesSorted = false;\n\t\t\tthis._exportNames.add(exportName);\n\n\t\t\tif (this._exportNames.size === 1) {\n\t\t\t\tthis._singleExportName = exportName;\n\t\t\t} else {\n\t\t\t\tthis._singleExportName = undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Adds a new local export name to the entity.\n\t *\n\t * @remarks\n\t * In the example below:\n\t *\n\t * ```ts\n\t * declare function add(): void;\n\t * declare namespace calculator {\n\t *  export {\n\t *    add\n\t *  }\n\t * }\n\t * ```\n\t *\n\t * `add` is the local export name for the `CollectorEntity` for `add`.\n\t */\n\tpublic addLocalExportName(localExportName: string, parent: CollectorEntity): void {\n\t\tconst localExportNames: Set<string> = this._localExportNamesByParent.get(parent) ?? new Set();\n\t\tlocalExportNames.add(localExportName);\n\n\t\tthis._localExportNamesByParent.set(parent, localExportNames);\n\t}\n\n\t/**\n\t * A sorting key used by DtsRollupGenerator._makeUniqueNames()\n\t */\n\tpublic getSortKey(): string {\n\t\tif (!this._sortKey) {\n\t\t\tthis._sortKey = Collector.getSortKeyIgnoringUnderscore(this.nameForEmit ?? this.astEntity.localName);\n\t\t}\n\n\t\treturn this._sortKey;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/collector/DeclarationMetadata.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type * as tsdoc from '@microsoft/tsdoc';\nimport type { AstDeclaration } from '../analyzer/AstDeclaration.js';\n\n/**\n * Stores the Collector's additional analysis for a specific `AstDeclaration` signature.  This object is assigned to\n * `AstDeclaration.declarationMetadata` but consumers must always obtain it by calling\n * `Collector.fetchDeclarationMetadata()`.\n *\n * Note that ancillary declarations share their `ApiItemMetadata` with the main declaration,\n * whereas a separate `DeclarationMetadata` object is created for each declaration.\n */\nexport abstract class DeclarationMetadata {\n\t/**\n\t * The ParserContext from when the TSDoc comment was parsed from the source code.\n\t * If the source code did not contain a doc comment, then this will be undefined.\n\t *\n\t * Note that if an ancillary declaration has a doc comment, it is tracked here, whereas\n\t * `ApiItemMetadata.tsdocComment` corresponds to documentation for the main declaration.\n\t */\n\tpublic abstract readonly tsdocParserContext: tsdoc.ParserContext | undefined;\n\n\t/**\n\t * If true, then this declaration is treated as part of another declaration.\n\t */\n\tpublic abstract readonly isAncillary: boolean;\n\n\t/**\n\t * A list of other declarations that are treated as being part of this declaration.  For example, a property\n\t * getter/setter pair will be treated as a single API item, with the setter being treated as ancillary to the getter.\n\t *\n\t * If the `ancillaryDeclarations` array is non-empty, then `isAncillary` will be false for this declaration,\n\t * and `isAncillary` will be true for all the array items.\n\t */\n\tpublic abstract readonly ancillaryDeclarations: readonly AstDeclaration[];\n}\n\n/**\n * Used internally by the `Collector` to build up `DeclarationMetadata`.\n */\nexport class InternalDeclarationMetadata extends DeclarationMetadata {\n\tpublic tsdocParserContext: tsdoc.ParserContext | undefined = undefined;\n\n\tpublic isAncillary: boolean = false;\n\n\tpublic ancillaryDeclarations: AstDeclaration[] = [];\n}\n"
  },
  {
    "path": "packages/api-extractor/src/collector/MessageRouter.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type * as tsdoc from '@microsoft/tsdoc';\nimport { Sort, InternalError } from '@rushstack/node-core-library';\nimport colors from 'colors';\nimport * as ts from 'typescript';\nimport { AstDeclaration } from '../analyzer/AstDeclaration.js';\nimport type { AstSymbol } from '../analyzer/AstSymbol.js';\nimport { ConsoleMessageId } from '../api/ConsoleMessageId.js';\nimport { ExtractorLogLevel } from '../api/ExtractorLogLevel.js';\nimport {\n\tExtractorMessage,\n\tExtractorMessageCategory,\n\ttype IExtractorMessageOptions,\n\ttype IExtractorMessageProperties,\n} from '../api/ExtractorMessage.js';\nimport { type ExtractorMessageId, allExtractorMessageIds } from '../api/ExtractorMessageId.js';\nimport type { IExtractorMessagesConfig, IConfigMessageReportingRule } from '../api/IConfigFile.js';\nimport type { ISourceLocation, SourceMapper } from './SourceMapper.js';\n\ninterface IReportingRule {\n\taddToApiReportFile: boolean;\n\tlogLevel: ExtractorLogLevel;\n}\n\nexport interface IMessageRouterOptions {\n\tmessageCallback: ((message: ExtractorMessage) => void) | undefined;\n\tmessagesConfig: IExtractorMessagesConfig;\n\tshowDiagnostics: boolean;\n\tshowVerboseMessages: boolean;\n\tsourceMapper: SourceMapper;\n\ttsdocConfiguration: tsdoc.TSDocConfiguration;\n\tworkingPackageFolder: string | undefined;\n}\n\nexport interface IBuildJsonDumpObjectOptions {\n\t/**\n\t * {@link MessageRouter.buildJsonDumpObject} will omit any objects keys with these names.\n\t */\n\tkeyNamesToOmit?: string[];\n}\n\nexport class MessageRouter {\n\tpublic static readonly DIAGNOSTICS_LINE: string = '============================================================';\n\n\tprivate readonly _workingPackageFolder: string | undefined;\n\n\tprivate readonly _messageCallback: ((message: ExtractorMessage) => void) | undefined;\n\n\t// All messages\n\tprivate readonly _messages: ExtractorMessage[];\n\n\t// For each AstDeclaration, the messages associated with it.  This is used when addToApiReportFile=true\n\tprivate readonly _associatedMessagesForAstDeclaration: Map<AstDeclaration, ExtractorMessage[]>;\n\n\tprivate readonly _sourceMapper: SourceMapper;\n\n\tprivate readonly _tsdocConfiguration: tsdoc.TSDocConfiguration;\n\n\t// Normalized representation of the routing rules from api-extractor.json\n\tprivate _reportingRuleByMessageId: Map<string, IReportingRule> = new Map<string, IReportingRule>();\n\n\tprivate _compilerDefaultRule: IReportingRule = {\n\t\tlogLevel: ExtractorLogLevel.None,\n\t\taddToApiReportFile: false,\n\t};\n\n\tprivate _extractorDefaultRule: IReportingRule = {\n\t\tlogLevel: ExtractorLogLevel.None,\n\t\taddToApiReportFile: false,\n\t};\n\n\tprivate _tsdocDefaultRule: IReportingRule = { logLevel: ExtractorLogLevel.None, addToApiReportFile: false };\n\n\tpublic errorCount: number = 0;\n\n\tpublic warningCount: number = 0;\n\n\t/**\n\t * See {@link IExtractorInvokeOptions.showVerboseMessages}\n\t */\n\tpublic readonly showVerboseMessages: boolean;\n\n\t/**\n\t * See {@link IExtractorInvokeOptions.showDiagnostics}\n\t */\n\tpublic readonly showDiagnostics: boolean;\n\n\tpublic constructor(options: IMessageRouterOptions) {\n\t\tthis._workingPackageFolder = options.workingPackageFolder;\n\t\tthis._messageCallback = options.messageCallback;\n\n\t\tthis._messages = [];\n\t\tthis._associatedMessagesForAstDeclaration = new Map<AstDeclaration, ExtractorMessage[]>();\n\t\tthis._sourceMapper = options.sourceMapper;\n\t\tthis._tsdocConfiguration = options.tsdocConfiguration;\n\n\t\t// showDiagnostics implies showVerboseMessages\n\t\tthis.showVerboseMessages = options.showVerboseMessages || options.showDiagnostics;\n\t\tthis.showDiagnostics = options.showDiagnostics;\n\n\t\tthis._applyMessagesConfig(options.messagesConfig);\n\t}\n\n\t/**\n\t * Read the api-extractor.json configuration and build up the tables of routing rules.\n\t */\n\tprivate _applyMessagesConfig(messagesConfig: IExtractorMessagesConfig): void {\n\t\tif (messagesConfig.compilerMessageReporting) {\n\t\t\tfor (const messageId of Object.getOwnPropertyNames(messagesConfig.compilerMessageReporting)) {\n\t\t\t\tconst reportingRule: IReportingRule = MessageRouter._getNormalizedRule(\n\t\t\t\t\tmessagesConfig.compilerMessageReporting[messageId]!,\n\t\t\t\t);\n\n\t\t\t\tif (messageId === 'default') {\n\t\t\t\t\tthis._compilerDefaultRule = reportingRule;\n\t\t\t\t} else if (/^TS\\d+$/.test(messageId)) {\n\t\t\t\t\tthis._reportingRuleByMessageId.set(messageId, reportingRule);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Error in API Extractor config: The messages.compilerMessageReporting table contains` +\n\t\t\t\t\t\t\t` an invalid entry \"${messageId}\". The identifier format is \"TS\" followed by an integer.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (messagesConfig.extractorMessageReporting) {\n\t\t\tfor (const messageId of Object.getOwnPropertyNames(messagesConfig.extractorMessageReporting)) {\n\t\t\t\tconst reportingRule: IReportingRule = MessageRouter._getNormalizedRule(\n\t\t\t\t\tmessagesConfig.extractorMessageReporting[messageId]!,\n\t\t\t\t);\n\n\t\t\t\tif (messageId === 'default') {\n\t\t\t\t\tthis._extractorDefaultRule = reportingRule;\n\t\t\t\t} else if (!messageId.startsWith('ae-')) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Error in API Extractor config: The messages.extractorMessageReporting table contains` +\n\t\t\t\t\t\t\t` an invalid entry \"${messageId}\".  The name should begin with the \"ae-\" prefix.`,\n\t\t\t\t\t);\n\t\t\t\t} else if (allExtractorMessageIds.has(messageId)) {\n\t\t\t\t\tthis._reportingRuleByMessageId.set(messageId, reportingRule);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Error in API Extractor config: The messages.extractorMessageReporting table contains` +\n\t\t\t\t\t\t\t` an unrecognized identifier \"${messageId}\".  Is it spelled correctly?`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (messagesConfig.tsdocMessageReporting) {\n\t\t\tfor (const messageId of Object.getOwnPropertyNames(messagesConfig.tsdocMessageReporting)) {\n\t\t\t\tconst reportingRule: IReportingRule = MessageRouter._getNormalizedRule(\n\t\t\t\t\tmessagesConfig.tsdocMessageReporting[messageId]!,\n\t\t\t\t);\n\n\t\t\t\tif (messageId === 'default') {\n\t\t\t\t\tthis._tsdocDefaultRule = reportingRule;\n\t\t\t\t} else if (!messageId.startsWith('tsdoc-')) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Error in API Extractor config: The messages.tsdocMessageReporting table contains` +\n\t\t\t\t\t\t\t` an invalid entry \"${messageId}\".  The name should begin with the \"tsdoc-\" prefix.`,\n\t\t\t\t\t);\n\t\t\t\t} else if (this._tsdocConfiguration.isKnownMessageId(messageId)) {\n\t\t\t\t\tthis._reportingRuleByMessageId.set(messageId, reportingRule);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Error in API Extractor config: The messages.tsdocMessageReporting table contains` +\n\t\t\t\t\t\t\t` an unrecognized identifier \"${messageId}\".  Is it spelled correctly?`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static _getNormalizedRule(rule: IConfigMessageReportingRule): IReportingRule {\n\t\treturn {\n\t\t\tlogLevel: rule.logLevel || 'none',\n\t\t\taddToApiReportFile: rule.addToApiReportFile ?? false,\n\t\t};\n\t}\n\n\tpublic get messages(): readonly ExtractorMessage[] {\n\t\treturn this._messages;\n\t}\n\n\t/**\n\t * Add a diagnostic message reported by the TypeScript compiler\n\t */\n\tpublic addCompilerDiagnostic(diagnostic: ts.Diagnostic): void {\n\t\tswitch (diagnostic.category) {\n\t\t\tcase ts.DiagnosticCategory.Suggestion:\n\t\t\tcase ts.DiagnosticCategory.Message:\n\t\t\t\treturn; // ignore noise\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\n\t\tconst messageText: string = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\\n');\n\t\tconst options: IExtractorMessageOptions = {\n\t\t\tcategory: ExtractorMessageCategory.Compiler,\n\t\t\tmessageId: `TS${diagnostic.code}`,\n\t\t\ttext: messageText,\n\t\t};\n\n\t\tif (diagnostic.file) {\n\t\t\t// NOTE: Since compiler errors pertain to issues specific to the .d.ts files,\n\t\t\t// we do not apply source mappings for them.\n\t\t\tconst sourceFile: ts.SourceFile = diagnostic.file;\n\t\t\tconst sourceLocation: ISourceLocation = this._sourceMapper.getSourceLocation({\n\t\t\t\tsourceFile,\n\t\t\t\tpos: diagnostic.start ?? 0,\n\t\t\t\tuseDtsLocation: true,\n\t\t\t});\n\t\t\toptions.sourceFilePath = sourceLocation.sourceFilePath;\n\t\t\toptions.sourceFileLine = sourceLocation.sourceFileLine;\n\t\t\toptions.sourceFileColumn = sourceLocation.sourceFileColumn;\n\t\t}\n\n\t\tthis._messages.push(new ExtractorMessage(options));\n\t}\n\n\t/**\n\t * Add a message from the API Extractor analysis\n\t */\n\tpublic addAnalyzerIssue(\n\t\tmessageId: ExtractorMessageId,\n\t\tmessageText: string,\n\t\tastDeclarationOrSymbol: AstDeclaration | AstSymbol,\n\t\tproperties?: IExtractorMessageProperties,\n\t): void {\n\t\tlet astDeclaration: AstDeclaration;\n\t\tif (astDeclarationOrSymbol instanceof AstDeclaration) {\n\t\t\tastDeclaration = astDeclarationOrSymbol;\n\t\t} else {\n\t\t\tastDeclaration = astDeclarationOrSymbol.astDeclarations[0]!;\n\t\t}\n\n\t\tconst extractorMessage: ExtractorMessage = this.addAnalyzerIssueForPosition(\n\t\t\tmessageId,\n\t\t\tmessageText,\n\t\t\tastDeclaration.declaration.getSourceFile(),\n\t\t\tastDeclaration.declaration.getStart(),\n\t\t\tproperties,\n\t\t);\n\n\t\tthis._associateMessageWithAstDeclaration(extractorMessage, astDeclaration);\n\t}\n\n\t/**\n\t * Add all messages produced from an invocation of the TSDoc parser, assuming they refer to\n\t * code in the specified source file.\n\t */\n\tpublic addTsdocMessages(\n\t\tparserContext: tsdoc.ParserContext,\n\t\tsourceFile: ts.SourceFile,\n\t\tastDeclaration?: AstDeclaration,\n\t): void {\n\t\tfor (const message of parserContext.log.messages) {\n\t\t\tconst options: IExtractorMessageOptions = {\n\t\t\t\tcategory: ExtractorMessageCategory.TSDoc,\n\t\t\t\tmessageId: message.messageId,\n\t\t\t\ttext: message.unformattedText,\n\t\t\t};\n\n\t\t\tconst sourceLocation: ISourceLocation = this._sourceMapper.getSourceLocation({\n\t\t\t\tsourceFile,\n\t\t\t\tpos: message.textRange.pos,\n\t\t\t});\n\t\t\toptions.sourceFilePath = sourceLocation.sourceFilePath;\n\t\t\toptions.sourceFileLine = sourceLocation.sourceFileLine;\n\t\t\toptions.sourceFileColumn = sourceLocation.sourceFileColumn;\n\n\t\t\tconst extractorMessage: ExtractorMessage = new ExtractorMessage(options);\n\n\t\t\tif (astDeclaration) {\n\t\t\t\tthis._associateMessageWithAstDeclaration(extractorMessage, astDeclaration);\n\t\t\t}\n\n\t\t\tthis._messages.push(extractorMessage);\n\t\t}\n\t}\n\n\t/**\n\t * Recursively collects the primitive members (numbers, strings, arrays, etc) into an object that\n\t * is JSON serializable.  This is used by the \"--diagnostics\" feature to dump the state of configuration objects.\n\t *\n\t * @returns a JSON serializable object (possibly including `null` values)\n\t *          or `undefined` if the input cannot be represented as JSON\n\t */\n\n\tpublic static buildJsonDumpObject(input: any, options?: IBuildJsonDumpObjectOptions): any | undefined {\n\t\tconst ioptions = options ?? {};\n\n\t\tconst keyNamesToOmit: Set<string> = new Set(ioptions.keyNamesToOmit);\n\n\t\treturn MessageRouter._buildJsonDumpObject(input, keyNamesToOmit);\n\t}\n\n\tprivate static _buildJsonDumpObject(input: any, keyNamesToOmit: Set<string>): any | undefined {\n\t\tif (input === null || input === undefined) {\n\t\t\treturn null; // JSON uses null instead of undefined\n\t\t}\n\n\t\tswitch (typeof input) {\n\t\t\tcase 'boolean':\n\t\t\tcase 'number':\n\t\t\tcase 'string':\n\t\t\t\treturn input;\n\t\t\tcase 'object':\n\t\t\t\tif (Array.isArray(input)) {\n\t\t\t\t\tconst outputArray: any[] = [];\n\t\t\t\t\tfor (const element of input) {\n\t\t\t\t\t\tconst serializedElement: any = MessageRouter._buildJsonDumpObject(element, keyNamesToOmit);\n\t\t\t\t\t\tif (serializedElement !== undefined) {\n\t\t\t\t\t\t\toutputArray.push(serializedElement);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn outputArray;\n\t\t\t\t}\n\n\t\t\t\t// eslint-disable-next-line no-case-declarations\n\t\t\t\tconst outputObject: object = {};\n\t\t\t\tfor (const key of Object.getOwnPropertyNames(input)) {\n\t\t\t\t\tif (keyNamesToOmit.has(key)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst value: any = input[key];\n\n\t\t\t\t\tconst serializedValue: any = MessageRouter._buildJsonDumpObject(value, keyNamesToOmit);\n\n\t\t\t\t\tif (serializedValue !== undefined) {\n\t\t\t\t\t\t(outputObject as any)[key] = serializedValue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn outputObject;\n\t\t\tdefault:\n\t\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Record this message in  _associatedMessagesForAstDeclaration\n\t */\n\tprivate _associateMessageWithAstDeclaration(\n\t\textractorMessage: ExtractorMessage,\n\t\tastDeclaration: AstDeclaration,\n\t): void {\n\t\tlet associatedMessages: ExtractorMessage[] | undefined =\n\t\t\tthis._associatedMessagesForAstDeclaration.get(astDeclaration);\n\n\t\tif (!associatedMessages) {\n\t\t\tassociatedMessages = [];\n\t\t\tthis._associatedMessagesForAstDeclaration.set(astDeclaration, associatedMessages);\n\t\t}\n\n\t\tassociatedMessages.push(extractorMessage);\n\t}\n\n\t/**\n\t * Add a message for a location in an arbitrary source file.\n\t */\n\tpublic addAnalyzerIssueForPosition(\n\t\tmessageId: ExtractorMessageId,\n\t\tmessageText: string,\n\t\tsourceFile: ts.SourceFile,\n\t\tpos: number,\n\t\tproperties?: IExtractorMessageProperties,\n\t): ExtractorMessage {\n\t\tconst options: IExtractorMessageOptions = {\n\t\t\tcategory: ExtractorMessageCategory.Extractor,\n\t\t\tmessageId,\n\t\t\ttext: messageText,\n\t\t\tproperties,\n\t\t};\n\n\t\tconst sourceLocation: ISourceLocation = this._sourceMapper.getSourceLocation({\n\t\t\tsourceFile,\n\t\t\tpos,\n\t\t});\n\t\toptions.sourceFilePath = sourceLocation.sourceFilePath;\n\t\toptions.sourceFileLine = sourceLocation.sourceFileLine;\n\t\toptions.sourceFileColumn = sourceLocation.sourceFileColumn;\n\n\t\tconst extractorMessage: ExtractorMessage = new ExtractorMessage(options);\n\n\t\tthis._messages.push(extractorMessage);\n\t\treturn extractorMessage;\n\t}\n\n\t/**\n\t * This is used when writing the API report file.  It looks up any messages that were configured to get emitted\n\t * in the API report file and returns them.  It also records that they were emitted, which suppresses them from\n\t * being shown on the console.\n\t */\n\tpublic fetchAssociatedMessagesForReviewFile(astDeclaration: AstDeclaration): ExtractorMessage[] {\n\t\tconst messagesForApiReportFile: ExtractorMessage[] = [];\n\n\t\tconst associatedMessages: ExtractorMessage[] = this._associatedMessagesForAstDeclaration.get(astDeclaration) ?? [];\n\t\tfor (const associatedMessage of associatedMessages) {\n\t\t\t// Make sure we didn't already report this message for some reason\n\t\t\tif (!associatedMessage.handled) {\n\t\t\t\t// Is this message type configured to go in the API report file?\n\t\t\t\tconst reportingRule: IReportingRule = this._getRuleForMessage(associatedMessage);\n\t\t\t\tif (reportingRule.addToApiReportFile) {\n\t\t\t\t\t// Include it in the result, and record that it went to the API report file\n\t\t\t\t\tmessagesForApiReportFile.push(associatedMessage);\n\t\t\t\t\tassociatedMessage.handled = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis._sortMessagesForOutput(messagesForApiReportFile);\n\t\treturn messagesForApiReportFile;\n\t}\n\n\t/**\n\t * This returns all remaining messages that were flagged with `addToApiReportFile`, but which were not\n\t * retreieved using `fetchAssociatedMessagesForReviewFile()`.\n\t */\n\tpublic fetchUnassociatedMessagesForReviewFile(): ExtractorMessage[] {\n\t\tconst messagesForApiReportFile: ExtractorMessage[] = [];\n\n\t\tfor (const unassociatedMessage of this.messages) {\n\t\t\t// Make sure we didn't already report this message for some reason\n\t\t\tif (!unassociatedMessage.handled) {\n\t\t\t\t// Is this message type configured to go in the API report file?\n\t\t\t\tconst reportingRule: IReportingRule = this._getRuleForMessage(unassociatedMessage);\n\t\t\t\tif (reportingRule.addToApiReportFile) {\n\t\t\t\t\t// Include it in the result, and record that it went to the API report file\n\t\t\t\t\tmessagesForApiReportFile.push(unassociatedMessage);\n\t\t\t\t\tunassociatedMessage.handled = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis._sortMessagesForOutput(messagesForApiReportFile);\n\t\treturn messagesForApiReportFile;\n\t}\n\n\t/**\n\t * This returns the list of remaining messages that were not already processed by\n\t * `fetchAssociatedMessagesForReviewFile()` or `fetchUnassociatedMessagesForReviewFile()`.\n\t * These messages will be shown on the console.\n\t */\n\tpublic handleRemainingNonConsoleMessages(): void {\n\t\tconst messagesForLogger: ExtractorMessage[] = [];\n\n\t\tfor (const message of this.messages) {\n\t\t\t// Make sure we didn't already report this message\n\t\t\tif (!message.handled) {\n\t\t\t\tmessagesForLogger.push(message);\n\t\t\t}\n\t\t}\n\n\t\tthis._sortMessagesForOutput(messagesForLogger);\n\n\t\tfor (const message of messagesForLogger) {\n\t\t\tthis._handleMessage(message);\n\t\t}\n\t}\n\n\tpublic logError(messageId: ConsoleMessageId, message: string, properties?: IExtractorMessageProperties): void {\n\t\tthis._handleMessage(\n\t\t\tnew ExtractorMessage({\n\t\t\t\tcategory: ExtractorMessageCategory.Console,\n\t\t\t\tmessageId,\n\t\t\t\ttext: message,\n\t\t\t\tproperties,\n\t\t\t\tlogLevel: ExtractorLogLevel.Error,\n\t\t\t}),\n\t\t);\n\t}\n\n\tpublic logWarning(messageId: ConsoleMessageId, message: string, properties?: IExtractorMessageProperties): void {\n\t\tthis._handleMessage(\n\t\t\tnew ExtractorMessage({\n\t\t\t\tcategory: ExtractorMessageCategory.Console,\n\t\t\t\tmessageId,\n\t\t\t\ttext: message,\n\t\t\t\tproperties,\n\t\t\t\tlogLevel: ExtractorLogLevel.Warning,\n\t\t\t}),\n\t\t);\n\t}\n\n\tpublic logInfo(messageId: ConsoleMessageId, message: string, properties?: IExtractorMessageProperties): void {\n\t\tthis._handleMessage(\n\t\t\tnew ExtractorMessage({\n\t\t\t\tcategory: ExtractorMessageCategory.Console,\n\t\t\t\tmessageId,\n\t\t\t\ttext: message,\n\t\t\t\tproperties,\n\t\t\t\tlogLevel: ExtractorLogLevel.Info,\n\t\t\t}),\n\t\t);\n\t}\n\n\tpublic logVerbose(messageId: ConsoleMessageId, message: string, properties?: IExtractorMessageProperties): void {\n\t\tthis._handleMessage(\n\t\t\tnew ExtractorMessage({\n\t\t\t\tcategory: ExtractorMessageCategory.Console,\n\t\t\t\tmessageId,\n\t\t\t\ttext: message,\n\t\t\t\tproperties,\n\t\t\t\tlogLevel: ExtractorLogLevel.Verbose,\n\t\t\t}),\n\t\t);\n\t}\n\n\tpublic logDiagnosticHeader(title: string): void {\n\t\tthis.logDiagnostic(MessageRouter.DIAGNOSTICS_LINE);\n\t\tthis.logDiagnostic(`DIAGNOSTIC: ` + title);\n\t\tthis.logDiagnostic(MessageRouter.DIAGNOSTICS_LINE);\n\t}\n\n\tpublic logDiagnosticFooter(): void {\n\t\tthis.logDiagnostic(MessageRouter.DIAGNOSTICS_LINE + '\\n');\n\t}\n\n\tpublic logDiagnostic(message: string): void {\n\t\tif (this.showDiagnostics) {\n\t\t\tthis.logVerbose(ConsoleMessageId.Diagnostics, message);\n\t\t}\n\t}\n\n\t/**\n\t * Give the calling application a chance to handle the `ExtractorMessage`, and if not, display it on the console.\n\t */\n\tprivate _handleMessage(message: ExtractorMessage): void {\n\t\t// Don't tally messages that were already \"handled\" by writing them into the API report\n\t\tif (message.handled) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Assign the ExtractorMessage.logLevel; the message callback may adjust it below\n\t\tif (message.category === ExtractorMessageCategory.Console) {\n\t\t\t// Console messages have their category log level assigned via logInfo(), logVerbose(), etc.\n\t\t} else {\n\t\t\tconst reportingRule: IReportingRule = this._getRuleForMessage(message);\n\t\t\tmessage.logLevel = reportingRule.logLevel;\n\t\t}\n\n\t\t// If there is a callback, allow it to modify and/or handle the message\n\t\tif (this._messageCallback) {\n\t\t\tthis._messageCallback(message);\n\t\t}\n\n\t\t// Update the statistics\n\t\tswitch (message.logLevel) {\n\t\t\tcase ExtractorLogLevel.Error:\n\t\t\t\t++this.errorCount;\n\t\t\t\tbreak;\n\t\t\tcase ExtractorLogLevel.Warning:\n\t\t\t\t++this.warningCount;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (message.handled) {\n\t\t\treturn;\n\t\t}\n\n\t\t// The messageCallback did not handle the message, so perform default handling\n\t\tmessage.handled = true;\n\n\t\tif (message.logLevel === ExtractorLogLevel.None) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet messageText: string;\n\t\tif (message.category === ExtractorMessageCategory.Console) {\n\t\t\tmessageText = message.text;\n\t\t} else {\n\t\t\tmessageText = message.formatMessageWithLocation(this._workingPackageFolder);\n\t\t}\n\n\t\tswitch (message.logLevel) {\n\t\t\tcase ExtractorLogLevel.Error:\n\t\t\t\tconsole.error(colors.red('Error: ' + messageText));\n\t\t\t\tbreak;\n\t\t\tcase ExtractorLogLevel.Warning:\n\t\t\t\tconsole.warn(colors.yellow('Warning: ' + messageText));\n\t\t\t\tbreak;\n\t\t\tcase ExtractorLogLevel.Info:\n\t\t\t\tconsole.log(messageText);\n\t\t\t\tbreak;\n\t\t\tcase ExtractorLogLevel.Verbose:\n\t\t\t\tif (this.showVerboseMessages) {\n\t\t\t\t\tconsole.log(colors.cyan(messageText));\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Invalid logLevel value: ${JSON.stringify(message.logLevel)}`);\n\t\t}\n\t}\n\n\t/**\n\t * For a given message, determine the IReportingRule based on the rule tables.\n\t */\n\tprivate _getRuleForMessage(message: ExtractorMessage): IReportingRule {\n\t\tconst reportingRule: IReportingRule | undefined = this._reportingRuleByMessageId.get(message.messageId);\n\t\tif (reportingRule) {\n\t\t\treturn reportingRule;\n\t\t}\n\n\t\tswitch (message.category) {\n\t\t\tcase ExtractorMessageCategory.Compiler:\n\t\t\t\treturn this._compilerDefaultRule;\n\t\t\tcase ExtractorMessageCategory.Extractor:\n\t\t\t\treturn this._extractorDefaultRule;\n\t\t\tcase ExtractorMessageCategory.TSDoc:\n\t\t\t\treturn this._tsdocDefaultRule;\n\t\t\tcase ExtractorMessageCategory.Console:\n\t\t\t\tthrow new InternalError('ExtractorMessageCategory.Console is not supported with IReportingRule');\n\t\t}\n\t}\n\n\t/**\n\t * Sorts an array of messages according to a reasonable ordering\n\t */\n\tprivate _sortMessagesForOutput(messages: ExtractorMessage[]): void {\n\t\tmessages.sort((a, b) => {\n\t\t\tlet diff: number;\n\t\t\t// First sort by file name\n\t\t\tdiff = Sort.compareByValue(a.sourceFilePath, b.sourceFilePath);\n\t\t\tif (diff !== 0) {\n\t\t\t\treturn diff;\n\t\t\t}\n\n\t\t\t// Then sort by line number\n\t\t\tdiff = Sort.compareByValue(a.sourceFileLine, b.sourceFileLine);\n\t\t\tif (diff !== 0) {\n\t\t\t\treturn diff;\n\t\t\t}\n\n\t\t\t// Then sort by messageId\n\t\t\treturn Sort.compareByValue(a.messageId, b.messageId);\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/collector/SourceMapper.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as path from 'node:path';\nimport { FileSystem, InternalError, JsonFile, NewlineKind } from '@rushstack/node-core-library';\nimport { SourceMapConsumer, type RawSourceMap, type MappingItem, type Position } from 'source-map';\nimport type ts from 'typescript';\n\ninterface ISourceMap {\n\t// SourceMapConsumer.originalPositionFor() is useless because the mapping contains numerous gaps,\n\t// and the API provides no way to find the nearest match.  So instead we extract all the mapping items\n\t// and search them using SourceMapper._findNearestMappingItem().\n\tmappingItems: MappingItem[];\n\n\tsourceMapConsumer: SourceMapConsumer;\n}\n\ninterface IOriginalFileInfo {\n\t// Whether the .ts file exists\n\tfileExists: boolean;\n\n\t// This is used to check whether the guessed position is out of bounds.\n\t// Since column/line numbers are 1-based, the 0th item in this array is unused.\n\tmaxColumnForLine: number[];\n}\n\nexport interface ISourceLocation {\n\t/**\n\t * The column number in the source file. The first column number is 1.\n\t */\n\tsourceFileColumn: number;\n\n\t/**\n\t * The line number in the source file. The first line number is 1.\n\t */\n\tsourceFileLine: number;\n\n\t/**\n\t * The absolute path to the source file.\n\t */\n\tsourceFilePath: string;\n}\n\nexport interface IGetSourceLocationOptions {\n\t/**\n\t * The position within the source file to get the source location from.\n\t */\n\tpos: number;\n\n\t/**\n\t * The source file to get the source location from.\n\t */\n\tsourceFile: ts.SourceFile;\n\n\t/**\n\t * If `false` or not provided, then we attempt to follow source maps in order to resolve the\n\t * location to the original `.ts` file. If resolution isn't possible for some reason, we fall\n\t * back to the `.d.ts` location.\n\t *\n\t * If `true`, then we don't bother following source maps, and the location refers to the `.d.ts`\n\t * location.\n\t */\n\tuseDtsLocation?: boolean;\n}\n\nexport class SourceMapper {\n\t// Map from .d.ts file path --> ISourceMap if a source map was found, or null if not found\n\tprivate _sourceMapByFilePath: Map<string, ISourceMap | null> = new Map<string, ISourceMap | null>();\n\n\t// Cache the FileSystem.exists() result for mapped .ts files\n\tprivate _originalFileInfoByPath: Map<string, IOriginalFileInfo> = new Map<string, IOriginalFileInfo>();\n\n\t/**\n\t * Given a `.d.ts` source file and a specific position within the file, return the corresponding\n\t * `ISourceLocation`.\n\t */\n\tpublic getSourceLocation(options: IGetSourceLocationOptions): ISourceLocation {\n\t\tconst lineAndCharacter: ts.LineAndCharacter = options.sourceFile.getLineAndCharacterOfPosition(options.pos);\n\t\tconst sourceLocation: ISourceLocation = {\n\t\t\tsourceFilePath: options.sourceFile.fileName,\n\t\t\tsourceFileLine: lineAndCharacter.line + 1,\n\t\t\tsourceFileColumn: lineAndCharacter.character + 1,\n\t\t};\n\n\t\tif (options.useDtsLocation) {\n\t\t\treturn sourceLocation;\n\t\t}\n\n\t\tconst mappedSourceLocation: ISourceLocation | undefined = this._getMappedSourceLocation(sourceLocation);\n\t\treturn mappedSourceLocation ?? sourceLocation;\n\t}\n\n\tprivate _getMappedSourceLocation(sourceLocation: ISourceLocation): ISourceLocation | undefined {\n\t\tconst { sourceFilePath, sourceFileLine, sourceFileColumn } = sourceLocation;\n\n\t\tif (!FileSystem.exists(sourceFilePath)) {\n\t\t\t// Sanity check\n\t\t\tthrow new InternalError('The referenced path was not found: ' + sourceFilePath);\n\t\t}\n\n\t\tconst sourceMap: ISourceMap | null = this._getSourceMap(sourceFilePath);\n\t\tif (!sourceMap) return;\n\n\t\tconst nearestMappingItem: MappingItem | undefined = SourceMapper._findNearestMappingItem(sourceMap.mappingItems, {\n\t\t\tline: sourceFileLine,\n\t\t\tcolumn: sourceFileColumn,\n\t\t});\n\n\t\tif (!nearestMappingItem) return;\n\n\t\tconst mappedFilePath: string = path.resolve(path.dirname(sourceFilePath), nearestMappingItem.source);\n\n\t\t// Does the mapped filename exist?  Use a cache to remember the answer.\n\t\tlet originalFileInfo: IOriginalFileInfo | undefined = this._originalFileInfoByPath.get(mappedFilePath);\n\t\tif (originalFileInfo === undefined) {\n\t\t\toriginalFileInfo = {\n\t\t\t\tfileExists: FileSystem.exists(mappedFilePath),\n\t\t\t\tmaxColumnForLine: [],\n\t\t\t};\n\n\t\t\tif (originalFileInfo.fileExists) {\n\t\t\t\t// Read the file and measure the length of each line\n\t\t\t\toriginalFileInfo.maxColumnForLine = FileSystem.readFile(mappedFilePath, {\n\t\t\t\t\tconvertLineEndings: NewlineKind.Lf,\n\t\t\t\t})\n\t\t\t\t\t.split('\\n')\n\t\t\t\t\t.map((x) => x.length + 1); // +1 since columns are 1-based\n\t\t\t\toriginalFileInfo.maxColumnForLine.unshift(0); // Extra item since lines are 1-based\n\t\t\t}\n\n\t\t\tthis._originalFileInfoByPath.set(mappedFilePath, originalFileInfo);\n\t\t}\n\n\t\t// Don't translate coordinates to a file that doesn't exist\n\t\tif (!originalFileInfo.fileExists) return;\n\n\t\t// The nearestMappingItem anchor may be above/left of the real position, due to gaps in the mapping.  Calculate\n\t\t// the delta and apply it to the original position.\n\t\tconst guessedPosition: Position = {\n\t\t\tline: nearestMappingItem.originalLine + sourceFileLine - nearestMappingItem.generatedLine,\n\t\t\tcolumn: nearestMappingItem.originalColumn + sourceFileColumn - nearestMappingItem.generatedColumn,\n\t\t};\n\n\t\t// Verify that the result is not out of bounds, in cause our heuristic failed\n\t\tif (\n\t\t\tguessedPosition.line >= 1 &&\n\t\t\tguessedPosition.line < originalFileInfo.maxColumnForLine.length &&\n\t\t\tguessedPosition.column >= 1 &&\n\t\t\tguessedPosition.column <= originalFileInfo.maxColumnForLine[guessedPosition.line]!\n\t\t) {\n\t\t\treturn {\n\t\t\t\tsourceFilePath: mappedFilePath,\n\t\t\t\tsourceFileLine: guessedPosition.line,\n\t\t\t\tsourceFileColumn: guessedPosition.column,\n\t\t\t};\n\t\t} else {\n\t\t\t// The guessed position was out of bounds, so use the nearestMappingItem position instead.\n\t\t\treturn {\n\t\t\t\tsourceFilePath: mappedFilePath,\n\t\t\t\tsourceFileLine: nearestMappingItem.originalLine,\n\t\t\t\tsourceFileColumn: nearestMappingItem.originalColumn,\n\t\t\t};\n\t\t}\n\t}\n\n\tprivate _getSourceMap(sourceFilePath: string): ISourceMap | null {\n\t\tlet sourceMap: ISourceMap | null | undefined = this._sourceMapByFilePath.get(sourceFilePath);\n\n\t\tif (sourceMap === undefined) {\n\t\t\t// Normalize the path and redo the lookup\n\t\t\tconst normalizedPath: string = FileSystem.getRealPath(sourceFilePath);\n\n\t\t\tsourceMap = this._sourceMapByFilePath.get(normalizedPath);\n\t\t\tif (sourceMap === undefined) {\n\t\t\t\t// Given \"folder/file.d.ts\", check for a corresponding \"folder/file.d.ts.map\"\n\t\t\t\tconst sourceMapPath: string = normalizedPath + '.map';\n\t\t\t\tif (FileSystem.exists(sourceMapPath)) {\n\t\t\t\t\t// Load up the source map\n\t\t\t\t\tconst rawSourceMap: RawSourceMap = JsonFile.load(sourceMapPath) as RawSourceMap;\n\n\t\t\t\t\tconst sourceMapConsumer: SourceMapConsumer = new SourceMapConsumer(rawSourceMap);\n\t\t\t\t\tconst mappingItems: MappingItem[] = [];\n\n\t\t\t\t\t// Extract the list of mapping items\n\t\t\t\t\tsourceMapConsumer.eachMapping(\n\t\t\t\t\t\t(mappingItem: MappingItem) => {\n\t\t\t\t\t\t\tmappingItems.push({\n\t\t\t\t\t\t\t\t...mappingItem,\n\t\t\t\t\t\t\t\t// The \"source-map\" package inexplicably uses 1-based line numbers but 0-based column numbers.\n\t\t\t\t\t\t\t\t// Fix that up proactively so we don't have to deal with it later.\n\t\t\t\t\t\t\t\tgeneratedColumn: mappingItem.generatedColumn + 1,\n\t\t\t\t\t\t\t\toriginalColumn: mappingItem.originalColumn + 1,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\tSourceMapConsumer.GENERATED_ORDER,\n\t\t\t\t\t);\n\n\t\t\t\t\tsourceMap = { sourceMapConsumer, mappingItems };\n\t\t\t\t} else {\n\t\t\t\t\t// No source map for this filename\n\t\t\t\t\tsourceMap = null;\n\t\t\t\t}\n\n\t\t\t\tthis._sourceMapByFilePath.set(normalizedPath, sourceMap);\n\t\t\t\tif (sourceFilePath !== normalizedPath) {\n\t\t\t\t\t// Add both keys to the map\n\t\t\t\t\tthis._sourceMapByFilePath.set(sourceFilePath, sourceMap);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Copy the result from the normalized to the non-normalized key\n\t\t\t\tthis._sourceMapByFilePath.set(sourceFilePath, sourceMap);\n\t\t\t}\n\t\t}\n\n\t\treturn sourceMap;\n\t}\n\n\t// The `mappingItems` array is sorted by generatedLine/generatedColumn (GENERATED_ORDER).\n\t// The _findNearestMappingItem() lookup is a simple binary search that returns the previous item\n\t// if there is no exact match.\n\tprivate static _findNearestMappingItem(mappingItems: MappingItem[], position: Position): MappingItem | undefined {\n\t\tif (mappingItems.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tlet startIndex = 0;\n\t\tlet endIndex: number = mappingItems.length - 1;\n\n\t\twhile (startIndex <= endIndex) {\n\t\t\tconst middleIndex: number = startIndex + Math.floor((endIndex - startIndex) / 2);\n\n\t\t\tconst diff: number = SourceMapper._compareMappingItem(mappingItems[middleIndex]!, position);\n\n\t\t\tif (diff < 0) {\n\t\t\t\tstartIndex = middleIndex + 1;\n\t\t\t} else if (diff > 0) {\n\t\t\t\tendIndex = middleIndex - 1;\n\t\t\t} else {\n\t\t\t\t// Exact match\n\t\t\t\treturn mappingItems[middleIndex];\n\t\t\t}\n\t\t}\n\n\t\t// If we didn't find an exact match, then endIndex < startIndex.\n\t\t// Take endIndex because it's the smaller value.\n\t\treturn mappingItems[endIndex];\n\t}\n\n\tprivate static _compareMappingItem(mappingItem: MappingItem, position: Position): number {\n\t\tconst diff: number = mappingItem.generatedLine - position.line;\n\t\tif (diff !== 0) {\n\t\t\treturn diff;\n\t\t}\n\n\t\treturn mappingItem.generatedColumn - position.column;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/collector/SymbolMetadata.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { ReleaseTag } from '@discordjs/api-extractor-model';\n\n/**\n * Constructor parameters for `SymbolMetadata`.\n */\nexport interface ISymbolMetadataOptions {\n\tmaxEffectiveReleaseTag: ReleaseTag;\n}\n\n/**\n * Stores the Collector's additional analysis for an `AstSymbol`.  This object is assigned to `AstSymbol.metadata`\n * but consumers must always obtain it by calling `Collector.fetchSymbolMetadata()`.\n */\nexport class SymbolMetadata {\n\t// For all declarations associated with this symbol, this is the\n\t// `ApiItemMetadata.effectiveReleaseTag` value that is most public.\n\tpublic readonly maxEffectiveReleaseTag: ReleaseTag;\n\n\tpublic constructor(options: ISymbolMetadataOptions) {\n\t\tthis.maxEffectiveReleaseTag = options.maxEffectiveReleaseTag;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/collector/VisitorState.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * Keeps track of a directed graph traversal that needs to detect cycles.\n */\nexport enum VisitorState {\n\t/**\n\t * We have not visited the node yet.\n\t */\n\tUnvisited = 0,\n\n\t/**\n\t * We have visited the node, but have not finished traversing its references yet.\n\t * If we reach a node that is already in the `Visiting` state, this means we have\n\t * encountered a cyclic reference.\n\t */\n\tVisiting = 1,\n\n\t/**\n\t * We are finished vising the node and all its references.\n\t */\n\tVisited = 2,\n}\n"
  },
  {
    "path": "packages/api-extractor/src/collector/WorkingPackage.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type * as tsdoc from '@microsoft/tsdoc';\nimport type { INodePackageJson } from '@rushstack/node-core-library';\nimport type * as ts from 'typescript';\n\n/**\n * Constructor options for WorkingPackage\n */\nexport interface IWorkingPackageOptions {\n\tentryPoints: IWorkingPackageEntryPoint[];\n\tpackageFolder: string;\n\tpackageJson: INodePackageJson;\n}\n\nexport interface IWorkingPackageEntryPoint {\n\tmodulePath: string;\n\tsourceFile: ts.SourceFile;\n}\n\n/**\n * Information about the working package for a particular invocation of API Extractor.\n *\n * @remarks\n * API Extractor tries to model the world as a collection of NPM packages, such that each\n * .d.ts file belongs to at most one package.  When API Extractor is invoked on a project,\n * we refer to that project as being the \"working package\".  There is exactly one\n * \"working package\" for the duration of this analysis.  Any files that do not belong to\n * the working package are referred to as \"external\":  external declarations belonging to\n * external packages.\n *\n * If API Extractor is invoked on a standalone .d.ts file, the \"working package\" may not\n * have an actual package.json file on disk, but we still refer to it in concept.\n */\nexport class WorkingPackage {\n\t/**\n\t * Returns the folder for the package.json file of the working package.\n\t *\n\t * @remarks\n\t * If the entry point is `C:\\Folder\\project\\src\\index.ts` and the nearest package.json\n\t * is `C:\\Folder\\project\\package.json`, then the packageFolder is `C:\\Folder\\project`\n\t */\n\tpublic readonly packageFolder: string;\n\n\t/**\n\t * The parsed package.json file for the working package.\n\t */\n\tpublic readonly packageJson: INodePackageJson;\n\n\t/**\n\t * The entry point being processed during this invocation of API Extractor.\n\t *\n\t * @remarks\n\t * The working package may have multiple entry points; however, today API Extractor\n\t * only processes a single entry point during an invocation.  This will be improved\n\t * in the future.\n\t */\n\tpublic readonly entryPoints: IWorkingPackageEntryPoint[];\n\n\t/**\n\t * The `@packageDocumentation` comment, if any, for the working package.\n\t */\n\tpublic tsdocComment: tsdoc.DocComment | undefined;\n\n\t/**\n\t * Additional parser information for `WorkingPackage.tsdocComment`.\n\t */\n\tpublic tsdocParserContext: tsdoc.ParserContext | undefined;\n\n\tpublic constructor(options: IWorkingPackageOptions) {\n\t\tthis.packageFolder = options.packageFolder;\n\t\tthis.packageJson = options.packageJson;\n\t\tthis.entryPoints = options.entryPoints;\n\t}\n\n\t/**\n\t * Returns the full name of the working package.\n\t */\n\tpublic get name(): string {\n\t\treturn this.packageJson.name;\n\t}\n\n\tpublic isDefaultEntryPoint(entryPoint: IWorkingPackageEntryPoint): boolean {\n\t\treturn entryPoint.modulePath === '';\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/enhancers/DocCommentEnhancer.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { ReleaseTag } from '@discordjs/api-extractor-model';\nimport * as tsdoc from '@microsoft/tsdoc';\nimport * as ts from 'typescript';\nimport type { AstDeclaration } from '../analyzer/AstDeclaration.js';\nimport { ResolverFailure } from '../analyzer/AstReferenceResolver.js';\nimport { AstSymbol } from '../analyzer/AstSymbol.js';\nimport { ExtractorMessageId } from '../api/ExtractorMessageId.js';\nimport type { ApiItemMetadata } from '../collector/ApiItemMetadata.js';\nimport type { Collector } from '../collector/Collector.js';\nimport { VisitorState } from '../collector/VisitorState.js';\nimport type { IWorkingPackageEntryPoint } from '../collector/WorkingPackage.js';\n\nexport class DocCommentEnhancer {\n\tprivate readonly _collector: Collector;\n\n\tpublic constructor(collector: Collector) {\n\t\tthis._collector = collector;\n\t}\n\n\tpublic static analyze(collector: Collector): void {\n\t\tconst docCommentEnhancer: DocCommentEnhancer = new DocCommentEnhancer(collector);\n\t\tdocCommentEnhancer.analyze();\n\t}\n\n\tpublic analyze(): void {\n\t\tfor (const [entryPoint, entities] of this._collector.entities) {\n\t\t\tfor (const entity of entities) {\n\t\t\t\tif (\n\t\t\t\t\tentity.astEntity instanceof AstSymbol &&\n\t\t\t\t\t(entity.consumable ||\n\t\t\t\t\t\tthis._collector.extractorConfig.apiReportIncludeForgottenExports ||\n\t\t\t\t\t\tthis._collector.extractorConfig.docModelIncludeForgottenExports)\n\t\t\t\t) {\n\t\t\t\t\tentity.astEntity.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => {\n\t\t\t\t\t\tthis._analyzeApiItem(astDeclaration, entryPoint);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _analyzeApiItem(astDeclaration: AstDeclaration, entryPoint: IWorkingPackageEntryPoint): void {\n\t\tconst metadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\tif (metadata.docCommentEnhancerVisitorState === VisitorState.Visited) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (metadata.docCommentEnhancerVisitorState === VisitorState.Visiting) {\n\t\t\tthis._collector.messageRouter.addAnalyzerIssue(\n\t\t\t\tExtractorMessageId.CyclicInheritDoc,\n\t\t\t\t`The @inheritDoc tag for \"${astDeclaration.astSymbol.localName}\" refers to its own declaration`,\n\t\t\t\tastDeclaration,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tmetadata.docCommentEnhancerVisitorState = VisitorState.Visiting;\n\n\t\tif (metadata.tsdocComment?.inheritDocTag) {\n\t\t\tthis._applyInheritDoc(astDeclaration, metadata.tsdocComment, metadata.tsdocComment.inheritDocTag, entryPoint);\n\t\t}\n\n\t\tthis._analyzeNeedsDocumentation(astDeclaration, metadata);\n\n\t\tthis._checkForBrokenLinks(astDeclaration, metadata, entryPoint);\n\n\t\tmetadata.docCommentEnhancerVisitorState = VisitorState.Visited;\n\t}\n\n\tprivate _analyzeNeedsDocumentation(astDeclaration: AstDeclaration, metadata: ApiItemMetadata): void {\n\t\tif (astDeclaration.declaration.kind === ts.SyntaxKind.Constructor) {\n\t\t\t// Constructors always do pretty much the same thing, so it's annoying to require people to write\n\t\t\t// descriptions for them.  Instead, if the constructor lacks a TSDoc summary, then API Extractor\n\t\t\t// will auto-generate one.\n\t\t\tmetadata.undocumented = false;\n\n\t\t\t// The class that contains this constructor\n\t\t\tconst classDeclaration: AstDeclaration = astDeclaration.parent!;\n\n\t\t\tconst configuration: tsdoc.TSDocConfiguration = this._collector.extractorConfig.tsdocConfiguration;\n\n\t\t\tif (!metadata.tsdocComment) {\n\t\t\t\tmetadata.tsdocComment = new tsdoc.DocComment({ configuration });\n\t\t\t}\n\n\t\t\tif (!tsdoc.PlainTextEmitter.hasAnyTextContent(metadata.tsdocComment.summarySection)) {\n\t\t\t\tmetadata.tsdocComment.summarySection.appendNodesInParagraph([\n\t\t\t\t\tnew tsdoc.DocPlainText({ configuration, text: 'Constructs a new instance of the ' }),\n\t\t\t\t\tnew tsdoc.DocCodeSpan({\n\t\t\t\t\t\tconfiguration,\n\t\t\t\t\t\tcode: classDeclaration.astSymbol.localName,\n\t\t\t\t\t}),\n\t\t\t\t\tnew tsdoc.DocPlainText({ configuration, text: ' class' }),\n\t\t\t\t]);\n\t\t\t}\n\n\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\tif (apiItemMetadata.effectiveReleaseTag === ReleaseTag.Internal) {\n\t\t\t\t// If the constructor is marked as internal, then add a boilerplate notice for the containing class\n\t\t\t\tconst classMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(classDeclaration);\n\n\t\t\t\tif (!classMetadata.tsdocComment) {\n\t\t\t\t\tclassMetadata.tsdocComment = new tsdoc.DocComment({ configuration });\n\t\t\t\t}\n\n\t\t\t\tif (classMetadata.tsdocComment.remarksBlock === undefined) {\n\t\t\t\t\tclassMetadata.tsdocComment.remarksBlock = new tsdoc.DocBlock({\n\t\t\t\t\t\tconfiguration,\n\t\t\t\t\t\tblockTag: new tsdoc.DocBlockTag({\n\t\t\t\t\t\t\tconfiguration,\n\t\t\t\t\t\t\ttagName: tsdoc.StandardTags.remarks.tagName,\n\t\t\t\t\t\t}),\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tclassMetadata.tsdocComment.remarksBlock.content.appendNode(\n\t\t\t\t\tnew tsdoc.DocParagraph({ configuration }, [\n\t\t\t\t\t\tnew tsdoc.DocPlainText({\n\t\t\t\t\t\t\tconfiguration,\n\t\t\t\t\t\t\ttext:\n\t\t\t\t\t\t\t\t`The constructor for this class is marked as internal. Third-party code should not` +\n\t\t\t\t\t\t\t\t` call the constructor directly or create subclasses that extend the `,\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tnew tsdoc.DocCodeSpan({\n\t\t\t\t\t\t\tconfiguration,\n\t\t\t\t\t\t\tcode: classDeclaration.astSymbol.localName,\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tnew tsdoc.DocPlainText({ configuration, text: ' class.' }),\n\t\t\t\t\t]),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (metadata.tsdocComment) {\n\t\t\t// Require the summary to contain at least 10 non-spacing characters\n\t\t\tmetadata.undocumented = !tsdoc.PlainTextEmitter.hasAnyTextContent(metadata.tsdocComment.summarySection, 10);\n\t\t} else {\n\t\t\tmetadata.undocumented = true;\n\t\t}\n\t}\n\n\tprivate _checkForBrokenLinks(\n\t\tastDeclaration: AstDeclaration,\n\t\tmetadata: ApiItemMetadata,\n\t\tentryPoint: IWorkingPackageEntryPoint,\n\t): void {\n\t\tif (!metadata.tsdocComment) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._checkForBrokenLinksRecursive(astDeclaration, metadata.tsdocComment, entryPoint);\n\t}\n\n\tprivate _checkForBrokenLinksRecursive(\n\t\tastDeclaration: AstDeclaration,\n\t\tnode: tsdoc.DocNode,\n\t\tentryPoint: IWorkingPackageEntryPoint,\n\t): void {\n\t\tif (\n\t\t\tnode instanceof tsdoc.DocLinkTag &&\n\t\t\tnode.codeDestination && // Is it referring to the working package?  If not, we don't do any link validation, because\n\t\t\t// AstReferenceResolver doesn't support it yet (but ModelReferenceResolver does of course).\n\t\t\t// Tracked by:  https://github.com/microsoft/rushstack/issues/1195\n\t\t\t(node.codeDestination.packageName === undefined ||\n\t\t\t\tnode.codeDestination.packageName === this._collector.workingPackage.name)\n\t\t) {\n\t\t\tconst referencedAstDeclaration: AstDeclaration | ResolverFailure = this._collector.astReferenceResolver.resolve(\n\t\t\t\tnode.codeDestination,\n\t\t\t\tentryPoint,\n\t\t\t);\n\n\t\t\tif (referencedAstDeclaration instanceof ResolverFailure) {\n\t\t\t\tthis._collector.messageRouter.addAnalyzerIssue(\n\t\t\t\t\tExtractorMessageId.UnresolvedLink,\n\t\t\t\t\t'The @link reference could not be resolved: ' + referencedAstDeclaration.reason,\n\t\t\t\t\tastDeclaration,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tfor (const childNode of node.getChildNodes()) {\n\t\t\tthis._checkForBrokenLinksRecursive(astDeclaration, childNode, entryPoint);\n\t\t}\n\t}\n\n\t/**\n\t * Follow an `{@inheritDoc ___}` reference and copy the content that we find in the referenced comment.\n\t */\n\tprivate _applyInheritDoc(\n\t\tastDeclaration: AstDeclaration,\n\t\tdocComment: tsdoc.DocComment,\n\t\tinheritDocTag: tsdoc.DocInheritDocTag,\n\t\tentryPoint: IWorkingPackageEntryPoint,\n\t): void {\n\t\tif (!inheritDocTag.declarationReference) {\n\t\t\tthis._collector.messageRouter.addAnalyzerIssue(\n\t\t\t\tExtractorMessageId.UnresolvedInheritDocBase,\n\t\t\t\t'The @inheritDoc tag needs a TSDoc declaration reference; signature matching is not supported yet',\n\t\t\t\tastDeclaration,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Is it referring to the working package?\n\t\tif (\n\t\t\t!(\n\t\t\t\tinheritDocTag.declarationReference.packageName === undefined ||\n\t\t\t\tinheritDocTag.declarationReference.packageName === this._collector.workingPackage.name\n\t\t\t)\n\t\t) {\n\t\t\t// It's referencing an external package, so skip this inheritDoc tag, since AstReferenceResolver doesn't\n\t\t\t// support it yet.  As a workaround, this tag will get handled later by api-documenter.\n\t\t\t// Tracked by:  https://github.com/microsoft/rushstack/issues/1195\n\t\t\treturn;\n\t\t}\n\n\t\tconst referencedAstDeclaration: AstDeclaration | ResolverFailure = this._collector.astReferenceResolver.resolve(\n\t\t\tinheritDocTag.declarationReference,\n\t\t\tentryPoint,\n\t\t);\n\n\t\tif (referencedAstDeclaration instanceof ResolverFailure) {\n\t\t\tthis._collector.messageRouter.addAnalyzerIssue(\n\t\t\t\tExtractorMessageId.UnresolvedInheritDocReference,\n\t\t\t\t'The @inheritDoc reference could not be resolved: ' + referencedAstDeclaration.reason,\n\t\t\t\tastDeclaration,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tthis._analyzeApiItem(referencedAstDeclaration, entryPoint);\n\n\t\tconst referencedMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(referencedAstDeclaration);\n\n\t\tif (referencedMetadata.tsdocComment) {\n\t\t\tthis._copyInheritedDocs(docComment, referencedMetadata.tsdocComment);\n\t\t}\n\t}\n\n\t/**\n\t * Copy the content from `sourceDocComment` to `targetDocComment`.\n\t */\n\tprivate _copyInheritedDocs(targetDocComment: tsdoc.DocComment, sourceDocComment: tsdoc.DocComment): void {\n\t\ttargetDocComment.summarySection = sourceDocComment.summarySection;\n\t\ttargetDocComment.remarksBlock = sourceDocComment.remarksBlock;\n\n\t\ttargetDocComment.params.clear();\n\t\tfor (const param of sourceDocComment.params) {\n\t\t\ttargetDocComment.params.add(param);\n\t\t}\n\n\t\tfor (const typeParam of sourceDocComment.typeParams) {\n\t\t\ttargetDocComment.typeParams.add(typeParam);\n\t\t}\n\n\t\ttargetDocComment.returnsBlock = sourceDocComment.returnsBlock;\n\n\t\ttargetDocComment.inheritDocTag = undefined;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/enhancers/ValidationEnhancer.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as path from 'node:path';\nimport { ReleaseTag, releaseTagCompare, releaseTagGetTagName } from '@discordjs/api-extractor-model';\nimport * as ts from 'typescript';\nimport type { AstDeclaration } from '../analyzer/AstDeclaration.js';\nimport type { AstEntity } from '../analyzer/AstEntity.js';\nimport type { IAstModuleExportInfo } from '../analyzer/AstModule.js';\nimport { AstNamespaceImport } from '../analyzer/AstNamespaceImport.js';\nimport { AstSymbol } from '../analyzer/AstSymbol.js';\nimport { ExtractorMessageId } from '../api/ExtractorMessageId.js';\nimport type { ApiItemMetadata } from '../collector/ApiItemMetadata.js';\nimport type { Collector } from '../collector/Collector.js';\nimport type { CollectorEntity } from '../collector/CollectorEntity.js';\nimport type { SymbolMetadata } from '../collector/SymbolMetadata.js';\nimport type { IWorkingPackageEntryPoint } from '../collector/WorkingPackage.js';\n\nexport class ValidationEnhancer {\n\tpublic static analyze(collector: Collector): void {\n\t\tconst alreadyWarnedEntities: Set<AstEntity> = new Set<AstEntity>();\n\n\t\tfor (const [entryPoint, entities] of collector.entities) {\n\t\t\tfor (const entity of entities) {\n\t\t\t\tif (\n\t\t\t\t\t!(\n\t\t\t\t\t\tentity.consumable ||\n\t\t\t\t\t\tcollector.extractorConfig.apiReportIncludeForgottenExports ||\n\t\t\t\t\t\tcollector.extractorConfig.docModelIncludeForgottenExports\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (entity.astEntity instanceof AstSymbol) {\n\t\t\t\t\t// A regular exported AstSymbol\n\n\t\t\t\t\tconst astSymbol: AstSymbol = entity.astEntity;\n\n\t\t\t\t\tastSymbol.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => {\n\t\t\t\t\t\tValidationEnhancer._checkReferences(collector, astDeclaration, alreadyWarnedEntities, entryPoint);\n\t\t\t\t\t});\n\n\t\t\t\t\tconst symbolMetadata: SymbolMetadata = collector.fetchSymbolMetadata(astSymbol);\n\t\t\t\t\tValidationEnhancer._checkForInternalUnderscore(collector, entity, astSymbol, symbolMetadata);\n\t\t\t\t\tValidationEnhancer._checkForInconsistentReleaseTags(collector, astSymbol, symbolMetadata);\n\t\t\t\t} else if (entity.astEntity instanceof AstNamespaceImport) {\n\t\t\t\t\t// A namespace created using \"import * as ___ from ___\"\n\t\t\t\t\tconst astNamespaceImport: AstNamespaceImport = entity.astEntity;\n\n\t\t\t\t\tconst astModuleExportInfo: IAstModuleExportInfo = astNamespaceImport.fetchAstModuleExportInfo(collector);\n\n\t\t\t\t\tfor (const namespaceMemberAstEntity of astModuleExportInfo.exportedLocalEntities.values()) {\n\t\t\t\t\t\tif (namespaceMemberAstEntity instanceof AstSymbol) {\n\t\t\t\t\t\t\tconst astSymbol: AstSymbol = namespaceMemberAstEntity;\n\n\t\t\t\t\t\t\tastSymbol.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => {\n\t\t\t\t\t\t\t\tValidationEnhancer._checkReferences(collector, astDeclaration, alreadyWarnedEntities, entryPoint);\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tconst symbolMetadata: SymbolMetadata = collector.fetchSymbolMetadata(astSymbol);\n\n\t\t\t\t\t\t\t// (Don't apply ValidationEnhancer._checkForInternalUnderscore() for AstNamespaceImport members)\n\n\t\t\t\t\t\t\tValidationEnhancer._checkForInconsistentReleaseTags(collector, astSymbol, symbolMetadata);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static _checkForInternalUnderscore(\n\t\tcollector: Collector,\n\t\tcollectorEntity: CollectorEntity,\n\t\tastSymbol: AstSymbol,\n\t\tsymbolMetadata: SymbolMetadata,\n\t): void {\n\t\tlet needsUnderscore = false;\n\n\t\tif (symbolMetadata.maxEffectiveReleaseTag === ReleaseTag.Internal) {\n\t\t\tif (astSymbol.parentAstSymbol) {\n\t\t\t\t// If it's marked as @internal and the parent isn't obviously already @internal, then it needs an underscore.\n\t\t\t\t//\n\t\t\t\t// For example, we WOULD need an underscore for a merged declaration like this:\n\t\t\t\t//\n\t\t\t\t//   /** @internal */\n\t\t\t\t//   export namespace X {\n\t\t\t\t//     export interface _Y { }\n\t\t\t\t//   }\n\t\t\t\t//\n\t\t\t\t//   /** @public */\n\t\t\t\t//   export class X {\n\t\t\t\t//     /** @internal */\n\t\t\t\t//     public static _Y(): void { }   // <==== different from parent\n\t\t\t\t//   }\n\t\t\t\tconst parentSymbolMetadata: SymbolMetadata = collector.fetchSymbolMetadata(astSymbol);\n\t\t\t\tif (parentSymbolMetadata.maxEffectiveReleaseTag > ReleaseTag.Internal) {\n\t\t\t\t\tneedsUnderscore = true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// If it's marked as @internal and has no parent, then it needs an underscore.\n\t\t\t\t// We use maxEffectiveReleaseTag because a merged declaration would NOT need an underscore in a case like this:\n\t\t\t\t//\n\t\t\t\t//   /** @public */\n\t\t\t\t//   export enum X { }\n\t\t\t\t//\n\t\t\t\t//   /** @internal */\n\t\t\t\t//   export namespace X { }\n\t\t\t\t//\n\t\t\t\t// (The above normally reports an error \"ae-different-release-tags\", but that may be suppressed.)\n\t\t\t\tneedsUnderscore = true;\n\t\t\t}\n\t\t}\n\n\t\tif (needsUnderscore) {\n\t\t\tfor (const exportName of collectorEntity.exportNames) {\n\t\t\t\tif (!exportName.startsWith('_')) {\n\t\t\t\t\tcollector.messageRouter.addAnalyzerIssue(\n\t\t\t\t\t\tExtractorMessageId.InternalMissingUnderscore,\n\t\t\t\t\t\t`The name \"${exportName}\" should be prefixed with an underscore` +\n\t\t\t\t\t\t\t` because the declaration is marked as @internal`,\n\t\t\t\t\t\tastSymbol,\n\t\t\t\t\t\t{ exportName },\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static _checkForInconsistentReleaseTags(\n\t\tcollector: Collector,\n\t\tastSymbol: AstSymbol,\n\t\tsymbolMetadata: SymbolMetadata,\n\t): void {\n\t\tif (astSymbol.isExternal) {\n\t\t\t// For now, don't report errors for external code.  If the developer cares about it, they should run\n\t\t\t// API Extractor separately on the external project\n\t\t\treturn;\n\t\t}\n\n\t\t// Normally we will expect all release tags to be the same.  Arbitrarily we choose the maxEffectiveReleaseTag\n\t\t// as the thing they should all match.\n\t\tconst expectedEffectiveReleaseTag: ReleaseTag = symbolMetadata.maxEffectiveReleaseTag;\n\n\t\t// This is set to true if we find a declaration whose release tag is different from expectedEffectiveReleaseTag\n\t\tlet mixedReleaseTags = false;\n\n\t\t// This is set to false if we find a declaration that is not a function/method overload\n\t\tlet onlyFunctionOverloads = true;\n\n\t\t// This is set to true if we find a declaration that is @internal\n\t\tlet anyInternalReleaseTags = false;\n\n\t\tfor (const astDeclaration of astSymbol.astDeclarations) {\n\t\t\tconst apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration);\n\t\t\tconst effectiveReleaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\n\t\t\tswitch (astDeclaration.declaration.kind) {\n\t\t\t\tcase ts.SyntaxKind.FunctionDeclaration:\n\t\t\t\tcase ts.SyntaxKind.MethodDeclaration:\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tonlyFunctionOverloads = false;\n\t\t\t}\n\n\t\t\tif (effectiveReleaseTag !== expectedEffectiveReleaseTag) {\n\t\t\t\tmixedReleaseTags = true;\n\t\t\t}\n\n\t\t\tif (effectiveReleaseTag === ReleaseTag.Internal) {\n\t\t\t\tanyInternalReleaseTags = true;\n\t\t\t}\n\t\t}\n\n\t\tif (mixedReleaseTags) {\n\t\t\tif (!onlyFunctionOverloads) {\n\t\t\t\tcollector.messageRouter.addAnalyzerIssue(\n\t\t\t\t\tExtractorMessageId.DifferentReleaseTags,\n\t\t\t\t\t'This symbol has another declaration with a different release tag',\n\t\t\t\t\tastSymbol,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (anyInternalReleaseTags) {\n\t\t\t\tcollector.messageRouter.addAnalyzerIssue(\n\t\t\t\t\tExtractorMessageId.InternalMixedReleaseTag,\n\t\t\t\t\t`Mixed release tags are not allowed for \"${astSymbol.localName}\" because one of its declarations` +\n\t\t\t\t\t\t` is marked as @internal`,\n\t\t\t\t\tastSymbol,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static _checkReferences(\n\t\tcollector: Collector,\n\t\tastDeclaration: AstDeclaration,\n\t\talreadyWarnedEntities: Set<AstEntity>,\n\t\tentryPoint: IWorkingPackageEntryPoint,\n\t): void {\n\t\tconst apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration);\n\t\tconst declarationReleaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\n\t\tfor (const referencedEntity of astDeclaration.referencedAstEntities) {\n\t\t\tlet collectorEntity: CollectorEntity | undefined;\n\t\t\tlet referencedReleaseTag: ReleaseTag;\n\t\t\tlet localName: string;\n\n\t\t\tif (referencedEntity instanceof AstSymbol) {\n\t\t\t\t// If this is e.g. a member of a namespace, then we need to be checking the top-level scope to see\n\t\t\t\t// whether it's exported.\n\t\t\t\t//\n\t\t\t\t// Technically we should also check each of the nested scopes along the way.\n\t\t\t\tconst rootSymbol: AstSymbol = referencedEntity.rootAstSymbol;\n\n\t\t\t\tif (rootSymbol.isExternal) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tcollectorEntity = collector.tryGetCollectorEntity(rootSymbol);\n\t\t\t\tlocalName = collectorEntity?.nameForEmit ?? rootSymbol.localName;\n\n\t\t\t\tconst referencedMetadata: SymbolMetadata = collector.fetchSymbolMetadata(referencedEntity);\n\t\t\t\treferencedReleaseTag = referencedMetadata.maxEffectiveReleaseTag;\n\t\t\t} else if (referencedEntity instanceof AstNamespaceImport) {\n\t\t\t\tcollectorEntity = collector.tryGetCollectorEntity(referencedEntity);\n\n\t\t\t\treferencedReleaseTag = ReleaseTag.Public;\n\n\t\t\t\tlocalName = collectorEntity?.nameForEmit ?? referencedEntity.localName;\n\t\t\t} else {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (collectorEntity?.consumable) {\n\t\t\t\tif (releaseTagCompare(declarationReleaseTag, referencedReleaseTag) > 0) {\n\t\t\t\t\tcollector.messageRouter.addAnalyzerIssue(\n\t\t\t\t\t\tExtractorMessageId.IncompatibleReleaseTags,\n\t\t\t\t\t\t`The symbol \"${astDeclaration.astSymbol.localName}\"` +\n\t\t\t\t\t\t\t` is marked as ${releaseTagGetTagName(declarationReleaseTag)},` +\n\t\t\t\t\t\t\t` but its signature references \"${localName}\"` +\n\t\t\t\t\t\t\t` which is marked as ${releaseTagGetTagName(referencedReleaseTag)}`,\n\t\t\t\t\t\tastDeclaration,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst entryPointFilename: string = path.basename(entryPoint!.sourceFile.fileName);\n\n\t\t\t\tif (!alreadyWarnedEntities.has(referencedEntity)) {\n\t\t\t\t\talreadyWarnedEntities.add(referencedEntity);\n\n\t\t\t\t\tif (referencedEntity instanceof AstSymbol && ValidationEnhancer._isEcmaScriptSymbol(referencedEntity)) {\n\t\t\t\t\t\t// The main usage scenario for ECMAScript symbols is to attach private data to a JavaScript object,\n\t\t\t\t\t\t// so as a special case, we do NOT report them as forgotten exports.\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcollector.messageRouter.addAnalyzerIssue(\n\t\t\t\t\t\t\tExtractorMessageId.ForgottenExport,\n\t\t\t\t\t\t\t`The symbol \"${localName}\" needs to be exported by the entry point ${entryPointFilename}`,\n\t\t\t\t\t\t\tastDeclaration,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Detect an AstSymbol that refers to an ECMAScript symbol declaration such as:\n\t//\n\t// const mySymbol: unique symbol = Symbol('mySymbol');\n\tprivate static _isEcmaScriptSymbol(astSymbol: AstSymbol): boolean {\n\t\tif (astSymbol.astDeclarations.length !== 1) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// We are matching a form like this:\n\t\t//\n\t\t// - VariableDeclaration:\n\t\t//   - Identifier:  pre=[mySymbol]\n\t\t//   - ColonToken:  pre=[:] sep=[ ]\n\t\t//   - TypeOperator:\n\t\t//     - UniqueKeyword:  pre=[unique] sep=[ ]\n\t\t//     - SymbolKeyword:  pre=[symbol]\n\t\tconst astDeclaration: AstDeclaration = astSymbol.astDeclarations[0]!;\n\t\tif (ts.isVariableDeclaration(astDeclaration.declaration)) {\n\t\t\tconst variableTypeNode: ts.TypeNode | undefined = astDeclaration.declaration.type;\n\t\t\tif (variableTypeNode) {\n\t\t\t\tfor (const token of variableTypeNode.getChildren()) {\n\t\t\t\t\tif (token.kind === ts.SyntaxKind.SymbolKeyword) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/generators/ApiModelGenerator.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { existsSync } from 'node:fs';\nimport * as path from 'node:path';\nimport type {\n\tIApiMethodOptions,\n\tApiItemContainerMixin,\n\tIApiParameterOptions,\n\tIExcerptTokenRange,\n\tIExcerptTokenRangeWithTypeParameters,\n\tIExcerptToken,\n\tIApiTypeParameterOptions,\n\tIApiPropertyOptions,\n} from '@discordjs/api-extractor-model';\nimport {\n\tApiItemKind,\n\tApiModel,\n\tApiClass,\n\tApiPackage,\n\tApiEntryPoint,\n\tApiEvent,\n\tApiMethod,\n\tApiNamespace,\n\tApiInterface,\n\tApiPropertySignature,\n\tReleaseTag,\n\tApiProperty,\n\tApiMethodSignature,\n\tApiEnum,\n\tApiEnumMember,\n\tApiConstructor,\n\tApiConstructSignature,\n\tApiFunction,\n\tApiIndexSignature,\n\tApiVariable,\n\tApiTypeAlias,\n\tApiCallSignature,\n\tEnumMemberOrder,\n\tExcerptTokenKind,\n\tNavigation,\n} from '@discordjs/api-extractor-model';\nimport type * as tsdoc from '@microsoft/tsdoc';\nimport { DeclarationReference, type Meaning } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { JsonFile, Path } from '@rushstack/node-core-library';\nimport * as ts from 'typescript';\nimport type { AstDeclaration } from '../analyzer/AstDeclaration.js';\nimport type { AstEntity } from '../analyzer/AstEntity.js';\nimport { AstImport } from '../analyzer/AstImport.js';\nimport type { AstModule } from '../analyzer/AstModule.js';\nimport { AstNamespaceImport } from '../analyzer/AstNamespaceImport.js';\nimport { AstSymbol } from '../analyzer/AstSymbol.js';\nimport { TypeScriptInternals } from '../analyzer/TypeScriptInternals.js';\nimport type { ExtractorConfig } from '../api/ExtractorConfig';\nimport type { ApiItemMetadata } from '../collector/ApiItemMetadata.js';\nimport type { Collector } from '../collector/Collector.js';\nimport type { DeclarationMetadata } from '../collector/DeclarationMetadata.js';\nimport type { ISourceLocation } from '../collector/SourceMapper.js';\nimport type { IWorkingPackageEntryPoint } from '../collector/WorkingPackage.js';\nimport { DeclarationReferenceGenerator } from './DeclarationReferenceGenerator.js';\nimport { ExcerptBuilder, type IExcerptBuilderNodeToCapture } from './ExcerptBuilder.js';\n\ntype DocgenAccess = 'private' | 'protected' | 'public';\ntype DocgenScope = 'global' | 'instance' | 'static';\ntype DocgenDeprecated = boolean | string;\n\ninterface DocgenMetaJson {\n\tfile: string;\n\tline: number;\n\tpath: string;\n}\n\ninterface DocgenTypeJson {\n\tnames?: string[] | undefined;\n}\n\ninterface DocgenVarJson {\n\tdescription?: string;\n\tnullable?: boolean;\n\ttypes?: string[][][];\n}\ntype DocgenVarTypeJson = DocgenVarJson | string[][][];\ninterface DocgenExceptionJson {\n\tdescription?: string;\n\tnullable?: boolean;\n\ttype: DocgenTypeJson;\n}\n\ninterface DocgenExternalJson {\n\tdescription: string;\n\tmeta: DocgenMetaJson;\n\tname: string;\n\tsee?: string[];\n}\n\ninterface DocgenTypedefJson {\n\taccess?: DocgenAccess;\n\tdeprecated?: DocgenDeprecated;\n\tdescription: string;\n\tmeta: DocgenMetaJson;\n\tname: string;\n\tparams?: DocgenParamJson[];\n\tprops?: DocgenParamJson[];\n\treturns?: DocgenVarTypeJson[];\n\tsee?: string[];\n\ttype: DocgenVarTypeJson;\n}\n\ninterface DocgenEventJson {\n\tdeprecated?: DocgenDeprecated;\n\tdescription: string;\n\tmeta: DocgenMetaJson;\n\tname: string;\n\tparams?: DocgenParamJson[];\n\tsee?: string[];\n}\n\ninterface DocgenParamJson {\n\tdefault?: boolean | number | string;\n\tdescription: string;\n\tname: string;\n\tnullable?: boolean;\n\toptional?: boolean;\n\ttype: DocgenVarTypeJson;\n\tvariable?: string;\n}\n\ninterface DocgenConstructorJson {\n\taccess?: DocgenAccess;\n\tdescription: string;\n\tname: string;\n\tparams?: DocgenParamJson[];\n\tsee?: string[];\n}\n\ninterface DocgenMethodJson {\n\tabstract: boolean;\n\taccess?: DocgenAccess;\n\tasync?: boolean;\n\tdeprecated?: DocgenDeprecated;\n\tdescription: string;\n\temits?: string[];\n\texamples?: string[];\n\tgenerator?: boolean;\n\timplements?: string[];\n\tinherited?: boolean;\n\tinherits?: string;\n\tmeta: DocgenMetaJson;\n\tname: string;\n\tparams?: DocgenParamJson[];\n\treturns?: DocgenVarTypeJson[];\n\tscope: DocgenScope;\n\tsee?: string[];\n\tthrows?: DocgenExceptionJson[];\n}\n\ninterface DocgenPropertyJson {\n\tabstract?: boolean;\n\taccess?: DocgenAccess;\n\tdefault?: boolean | number | string;\n\tdeprecated?: DocgenDeprecated;\n\tdescription: string;\n\tmeta: DocgenMetaJson;\n\tname: string;\n\tnullable?: boolean;\n\tprops?: DocgenPropertyJson[];\n\treadonly?: boolean;\n\tscope: DocgenScope;\n\tsee?: string[];\n\ttype: DocgenVarTypeJson;\n}\ninterface DocgenClassJson {\n\tabstract?: boolean;\n\taccess?: DocgenAccess;\n\tconstruct: DocgenConstructorJson;\n\tdeprecated?: DocgenDeprecated | string;\n\tdescription: string;\n\tevents?: DocgenEventJson[];\n\textends?: DocgenVarTypeJson;\n\timplements?: DocgenVarTypeJson;\n\tmeta: DocgenMetaJson;\n\tmethods?: DocgenMethodJson[];\n\tname: string;\n\tprops?: DocgenPropertyJson[];\n\tsee?: string[];\n}\ntype DocgenInterfaceJson = DocgenClassJson;\ntype DocgenContainerJson =\n\t| DocgenClassJson\n\t| DocgenConstructorJson\n\t| DocgenInterfaceJson\n\t| DocgenJson\n\t| DocgenMethodJson\n\t| DocgenTypedefJson;\n\nexport interface DocgenJson {\n\tclasses: DocgenClassJson[];\n\texternals: DocgenExternalJson[];\n\tfunctions: DocgenMethodJson[];\n\tinterfaces: DocgenInterfaceJson[];\n\tmeta: {\n\t\tdate: number;\n\t\tformat: number;\n\t\tgenerator: string;\n\t};\n\ttypedefs: DocgenTypedefJson[];\n}\ninterface IProcessAstEntityContext {\n\tentryPoint: IWorkingPackageEntryPoint;\n\tisExported: boolean;\n\tname: string;\n\tparentApiItem: ApiItemContainerMixin;\n\tparentDocgenJson?: DocgenContainerJson | undefined;\n}\n\n/**\n * @beta\n */\nexport interface IApiModelGenerationOptions {\n\t/**\n\t * The release tags to trim.\n\t */\n\treleaseTagsToTrim: Set<ReleaseTag>;\n}\n\nconst linkRegEx =\n\t/{@link\\s(?:(?<class>\\w+)(?:[#.](?<event>event:)?(?<prop>[\\w()]+))?|(?<url>https?:\\/\\/[^\\s}]*))(?<name>\\s[^}]*)?}/g;\n\nconst moduleNameRegEx = /^(?<package>(?:@[\\w.-]+\\/)?[\\w.-]+)(?<path>(?:\\/[\\w.-]+)+)?$/i;\n\nfunction filePathFromJson(meta: DocgenMetaJson): string {\n\treturn `${meta.path.slice('packages/discord.js/'.length)}/${meta.file}`;\n}\n\nfunction fixPrimitiveTypes(type: string, symbol: string | undefined) {\n\tswitch (type) {\n\t\tcase '*':\n\t\t\treturn 'any';\n\t\tcase 'Object':\n\t\t\treturn symbol === '<' ? 'Record' : 'object';\n\t\tdefault:\n\t\t\treturn type;\n\t}\n}\n\nexport class ApiModelGenerator {\n\tprivate readonly _collector: Collector;\n\n\tprivate readonly _apiModel: ApiModel;\n\n\tprivate readonly _tsDocParser: tsdoc.TSDocParser;\n\n\tprivate readonly _referenceGenerator: DeclarationReferenceGenerator;\n\n\tprivate readonly _releaseTagsToTrim: Set<ReleaseTag> | undefined;\n\n\tpublic readonly docModelEnabled: boolean;\n\n\tprivate readonly _jsDocJson: DocgenJson | undefined;\n\n\tpublic constructor(collector: Collector, extractorConfig: ExtractorConfig) {\n\t\tthis._collector = collector;\n\t\tthis._apiModel = new ApiModel();\n\t\tthis._referenceGenerator = new DeclarationReferenceGenerator(collector);\n\n\t\tconst apiModelGenerationOptions: IApiModelGenerationOptions | undefined = extractorConfig.docModelGenerationOptions;\n\t\tif (apiModelGenerationOptions) {\n\t\t\tthis._releaseTagsToTrim = apiModelGenerationOptions.releaseTagsToTrim;\n\t\t\tthis.docModelEnabled = true;\n\t\t} else {\n\t\t\tthis.docModelEnabled = false;\n\t\t}\n\n\t\t// @ts-expect-error we reuse the private tsdocParser from collector here\n\t\tthis._tsDocParser = collector._tsdocParser;\n\t}\n\n\tpublic get apiModel(): ApiModel {\n\t\treturn this._apiModel;\n\t}\n\n\tpublic buildApiPackage(): ApiPackage {\n\t\tconst packageDocComment: tsdoc.DocComment | undefined = this._collector.workingPackage.tsdocComment;\n\n\t\tconst jsDocFilepath = `${this._collector.extractorConfig.apiJsonFilePath.slice(0, -8)}json`;\n\t\tif (existsSync(jsDocFilepath)) {\n\t\t\t// @ts-expect-error assign value only when starting to build a new ApiPackage\n\t\t\tthis._jsDocJson = JsonFile.load(jsDocFilepath);\n\t\t}\n\n\t\tconst apiPackage: ApiPackage = new ApiPackage({\n\t\t\tname: this._collector.workingPackage.name,\n\t\t\tdocComment: packageDocComment,\n\t\t\ttsdocConfiguration: this._collector.extractorConfig.tsdocConfiguration,\n\t\t\tprojectFolderUrl: this._collector.extractorConfig.projectFolderUrl,\n\t\t\tpreserveMemberOrder: true,\n\t\t});\n\t\tthis._apiModel.addMember(apiPackage);\n\n\t\tfor (const [entryPoint, entities] of this._collector.entities.entries()) {\n\t\t\tconst apiEntryPoint: ApiEntryPoint = new ApiEntryPoint({ name: entryPoint.modulePath });\n\t\t\tapiPackage.addMember(apiEntryPoint);\n\n\t\t\tfor (const entity of entities) {\n\t\t\t\t// Only process entities that are exported from the entry point. Entities that are exported from\n\t\t\t\t// `AstNamespaceImport` entities will be processed by `_processAstNamespaceImport`. However, if\n\t\t\t\t// we are including forgotten exports, then process everything.\n\t\t\t\tif (entity.exportedFromEntryPoint || this._collector.extractorConfig.docModelIncludeForgottenExports) {\n\t\t\t\t\tthis._processAstEntity(entity.astEntity, {\n\t\t\t\t\t\tentryPoint,\n\t\t\t\t\t\tname: entity.nameForEmit!,\n\t\t\t\t\t\tisExported: entity.exportedFromEntryPoint,\n\t\t\t\t\t\tparentApiItem: apiEntryPoint,\n\t\t\t\t\t\tparentDocgenJson: this._jsDocJson,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn apiPackage;\n\t}\n\n\tprivate _processAstEntity(astEntity: AstEntity, context: IProcessAstEntityContext): void {\n\t\tif (astEntity instanceof AstSymbol) {\n\t\t\t// Skip ancillary declarations; we will process them with the main declaration\n\t\t\tfor (const astDeclaration of this._collector.getNonAncillaryDeclarations(astEntity)) {\n\t\t\t\tthis._processDeclaration(astDeclaration, context);\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (astEntity instanceof AstNamespaceImport) {\n\t\t\t// Note that a single API item can belong to two different AstNamespaceImport namespaces.  For example:\n\t\t\t//\n\t\t\t//   // file.ts defines \"thing()\"\n\t\t\t//   import * as example1 from \"./file\";\n\t\t\t//   import * as example2 from \"./file\";\n\t\t\t//\n\t\t\t//   // ...so here we end up with example1.thing() and example2.thing()\n\t\t\t//   export { example1, example2 }\n\t\t\t//\n\t\t\t// The current logic does not try to associate \"thing()\" with a specific parent.  Instead\n\t\t\t// the API documentation will show duplicated entries for example1.thing() and example2.thing().\n\t\t\t//\n\t\t\t// This could be improved in the future, but it requires a stable mechanism for choosing an associated parent.\n\t\t\t// For thoughts about this:  https://github.com/microsoft/rushstack/issues/1308\n\t\t\tthis._processAstNamespaceImport(astEntity, context);\n\t\t}\n\n\t\t// TO DO: Figure out how to represent reexported AstImport objects.  Basically we need to introduce a new\n\t\t// ApiItem subclass for \"export alias\", similar to a type alias, but representing declarations of the\n\t\t// form \"export { X } from 'external-package'\".  We can also use this to solve GitHub issue #950.\n\t}\n\n\tprivate _processAstNamespaceImport(astNamespaceImport: AstNamespaceImport, context: IProcessAstEntityContext): void {\n\t\tconst astModule: AstModule = astNamespaceImport.astModule;\n\t\tconst { entryPoint, name, isExported, parentApiItem } = context;\n\t\tconst containerKey: string = ApiNamespace.getContainerKey(name);\n\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(astNamespaceImport.declaration);\n\n\t\tlet apiNamespace: ApiNamespace | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiNamespace;\n\n\t\tif (apiNamespace === undefined) {\n\t\t\tapiNamespace = new ApiNamespace({\n\t\t\t\tname,\n\t\t\t\tdocComment: undefined,\n\t\t\t\treleaseTag: ReleaseTag.None,\n\t\t\t\texcerptTokens: [],\n\t\t\t\tisExported,\n\t\t\t\tfileUrlPath: sourceLocation.sourceFilePath,\n\t\t\t\tfileLine: sourceLocation.sourceFileLine,\n\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t});\n\t\t\tparentApiItem.addMember(apiNamespace);\n\t\t}\n\n\t\t// eslint-disable-next-line unicorn/no-array-for-each\n\t\tastModule.astModuleExportInfo!.exportedLocalEntities.forEach((exportedEntity: AstEntity, exportedName: string) => {\n\t\t\tthis._processAstEntity(exportedEntity, {\n\t\t\t\tentryPoint,\n\t\t\t\tname: exportedName,\n\t\t\t\tisExported: true,\n\t\t\t\tparentApiItem: apiNamespace!,\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _processDeclaration(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {\n\t\tif ((astDeclaration.modifierFlags & ts.ModifierFlags.Private) !== 0) {\n\t\t\treturn; // trim out private declarations\n\t\t}\n\n\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\tif (this._releaseTagsToTrim?.has(releaseTag)) {\n\t\t\treturn;\n\t\t}\n\n\t\tswitch (astDeclaration.declaration.kind) {\n\t\t\tcase ts.SyntaxKind.CallSignature:\n\t\t\t\tthis._processApiCallSignature(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.Constructor:\n\t\t\t\tthis._processApiConstructor(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.ConstructSignature:\n\t\t\t\tthis._processApiConstructSignature(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.ClassDeclaration:\n\t\t\t\tthis._processApiClass(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.EnumDeclaration:\n\t\t\t\tthis._processApiEnum(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.EnumMember:\n\t\t\t\tthis._processApiEnumMember(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.FunctionDeclaration:\n\t\t\t\tthis._processApiFunction(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.GetAccessor:\n\t\t\t\tthis._processApiProperty(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.SetAccessor:\n\t\t\t\tthis._processApiProperty(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.IndexSignature:\n\t\t\t\tthis._processApiIndexSignature(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.InterfaceDeclaration:\n\t\t\t\tthis._processApiInterface(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.MethodDeclaration:\n\t\t\t\tthis._processApiMethod(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.MethodSignature:\n\t\t\t\tthis._processApiMethodSignature(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.ModuleDeclaration:\n\t\t\t\tthis._processApiNamespace(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.PropertyDeclaration:\n\t\t\t\tthis._processApiProperty(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.PropertySignature:\n\t\t\t\tthis._processApiPropertySignature(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.TypeAliasDeclaration:\n\t\t\t\tthis._processApiTypeAlias(astDeclaration, context);\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.VariableDeclaration: {\n\t\t\t\t// check for arrow functions in variable declaration\n\t\t\t\tconst functionDeclaration: ts.FunctionDeclaration | undefined =\n\t\t\t\t\tthis._tryFindFunctionDeclaration(astDeclaration);\n\t\t\t\tif (functionDeclaration) {\n\t\t\t\t\tthis._processApiFunction(astDeclaration, context, functionDeclaration);\n\t\t\t\t} else {\n\t\t\t\t\tthis._processApiVariable(astDeclaration, context);\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t// ignore unknown types\n\t\t}\n\t}\n\n\tprivate _tryFindFunctionDeclaration(astDeclaration: AstDeclaration): ts.FunctionDeclaration | undefined {\n\t\tconst children: readonly ts.Node[] = astDeclaration.declaration.getChildren(\n\t\t\tastDeclaration.declaration.getSourceFile(),\n\t\t);\n\t\treturn children.find(ts.isFunctionTypeNode) as ts.FunctionDeclaration | undefined;\n\t}\n\n\tprivate _processChildDeclarations(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {\n\t\tfor (const childDeclaration of astDeclaration.children) {\n\t\t\tthis._processDeclaration(childDeclaration, {\n\t\t\t\t...context,\n\t\t\t\tname: childDeclaration.astSymbol.localName,\n\t\t\t});\n\t\t}\n\n\t\tfor (const method of (context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | undefined)?.methods ??\n\t\t\t[]) {\n\t\t\tswitch (context.parentApiItem.kind) {\n\t\t\t\tcase ApiItemKind.Class:\n\t\t\t\t\tthis._processApiMethod(null, { ...context, name: method.name });\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase ApiItemKind.Interface:\n\t\t\t\t\tthis._processApiMethodSignature(null, { ...context, name: method.name });\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t`Found docgen method not in TS typings for ApiItem of kind ${ApiItemKind[context.parentApiItem.kind]}`,\n\t\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tfor (const property of (context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | undefined)?.props ??\n\t\t\t[]) {\n\t\t\tswitch (context.parentApiItem.kind) {\n\t\t\t\tcase ApiItemKind.Class:\n\t\t\t\t\tthis._processApiProperty(null, { ...context, name: property.name });\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase ApiItemKind.Interface:\n\t\t\t\t\tthis._processApiPropertySignature(null, { ...context, name: property.name });\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tconsole.log(\n\t\t\t\t\t\t`Found docgen property not in TS typings for ApiItem of kind ${ApiItemKind[context.parentApiItem.kind]}`,\n\t\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _processApiCallSignature(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {\n\t\tconst { entryPoint, parentApiItem } = context;\n\t\tconst overloadIndex: number = this._collector.getOverloadIndex(astDeclaration);\n\t\tconst containerKey: string = ApiCallSignature.getContainerKey(overloadIndex);\n\n\t\tlet apiCallSignature: ApiCallSignature | undefined = parentApiItem.tryGetMemberByKey(\n\t\t\tcontainerKey,\n\t\t) as ApiCallSignature;\n\n\t\tif (apiCallSignature === undefined) {\n\t\t\tconst callSignature: ts.CallSignatureDeclaration = astDeclaration.declaration as ts.CallSignatureDeclaration;\n\n\t\t\tconst nodesToCapture: IExcerptBuilderNodeToCapture[] = [];\n\n\t\t\tconst returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\tnodesToCapture.push({ node: callSignature.type, tokenRange: returnTypeTokenRange });\n\n\t\t\tconst typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(\n\t\t\t\tnodesToCapture,\n\t\t\t\tcallSignature.typeParameters,\n\t\t\t);\n\n\t\t\tconst parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, callSignature.parameters);\n\n\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint);\n\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\tconst docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment;\n\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(callSignature);\n\n\t\t\tapiCallSignature = new ApiCallSignature({\n\t\t\t\tdocComment,\n\t\t\t\treleaseTag,\n\t\t\t\ttypeParameters,\n\t\t\t\tparameters,\n\t\t\t\toverloadIndex,\n\t\t\t\texcerptTokens,\n\t\t\t\treturnTypeTokenRange,\n\t\t\t\tfileUrlPath: sourceLocation.sourceFilePath,\n\t\t\t\tfileLine: sourceLocation.sourceFileLine,\n\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t});\n\n\t\t\tparentApiItem.addMember(apiCallSignature);\n\t\t}\n\t}\n\n\tprivate _processApiConstructor(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {\n\t\tconst { entryPoint, parentApiItem } = context;\n\t\tconst overloadIndex: number = this._collector.getOverloadIndex(astDeclaration);\n\t\tconst containerKey: string = ApiConstructor.getContainerKey(overloadIndex);\n\n\t\tlet apiConstructor: ApiConstructor | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiConstructor;\n\n\t\tif (apiConstructor === undefined) {\n\t\t\tconst constructorDeclaration: ts.ConstructorDeclaration = astDeclaration.declaration as ts.ConstructorDeclaration;\n\n\t\t\tconst nodesToCapture: IExcerptBuilderNodeToCapture[] = [];\n\t\t\tconst parent = context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | undefined;\n\n\t\t\tconst parameters: IApiParameterOptions[] = this._captureParameters(\n\t\t\t\tnodesToCapture,\n\t\t\t\tconstructorDeclaration.parameters,\n\t\t\t);\n\n\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint);\n\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\tconst docComment: tsdoc.DocComment | undefined = parent?.construct\n\t\t\t\t? this._tsDocParser.parseString(\n\t\t\t\t\t\t`/*+\\n * ${this._fixLinkTags(parent.construct.description) ?? ''}\\n${\n\t\t\t\t\t\t\tparent.construct.params\n\t\t\t\t\t\t\t\t?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\\n`)\n\t\t\t\t\t\t\t\t.join('') ?? ''\n\t\t\t\t\t\t} */`,\n\t\t\t\t\t).docComment\n\t\t\t\t: apiItemMetadata.tsdocComment;\n\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\tconst isProtected: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Protected) !== 0;\n\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(constructorDeclaration);\n\n\t\t\tapiConstructor = new ApiConstructor({\n\t\t\t\tdocComment,\n\t\t\t\treleaseTag,\n\t\t\t\tisProtected,\n\t\t\t\tparameters,\n\t\t\t\toverloadIndex,\n\t\t\t\texcerptTokens,\n\t\t\t\tfileUrlPath: parent ? filePathFromJson(parent.meta) : sourceLocation.sourceFilePath,\n\t\t\t\tfileLine: parent?.meta.line ?? sourceLocation.sourceFileLine,\n\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t});\n\n\t\t\tparentApiItem.addMember(apiConstructor);\n\t\t}\n\t}\n\n\tprivate _processApiClass(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {\n\t\tconst { entryPoint, name, isExported, parentApiItem } = context;\n\t\tconst containerKey: string = ApiClass.getContainerKey(name);\n\n\t\tlet apiClass: ApiClass | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiClass;\n\t\tconst parent = context.parentDocgenJson as DocgenJson | undefined;\n\t\tconst jsDoc = parent?.classes.find((_class) => _class.name === name);\n\n\t\tif (apiClass === undefined) {\n\t\t\tconst classDeclaration: ts.ClassDeclaration = astDeclaration.declaration as ts.ClassDeclaration;\n\n\t\t\tconst nodesToCapture: IExcerptBuilderNodeToCapture[] = [];\n\n\t\t\tconst typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(\n\t\t\t\tnodesToCapture,\n\t\t\t\tclassDeclaration.typeParameters,\n\t\t\t);\n\n\t\t\tlet extendsTokenRange: IExcerptTokenRangeWithTypeParameters | undefined;\n\t\t\tconst implementsTokenRanges: IExcerptTokenRangeWithTypeParameters[] = [];\n\n\t\t\tfor (const heritageClause of classDeclaration.heritageClauses ?? []) {\n\t\t\t\tif (heritageClause.token === ts.SyntaxKind.ExtendsKeyword) {\n\t\t\t\t\textendsTokenRange = ExcerptBuilder.createEmptyTokenRangeWithTypeParameters();\n\t\t\t\t\tif (heritageClause.types.length > 0) {\n\t\t\t\t\t\textendsTokenRange.typeParameters.push(\n\t\t\t\t\t\t\t...(heritageClause.types[0]?.typeArguments?.map((typeArgument) => {\n\t\t\t\t\t\t\t\tconst typeArgumentTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\t\t\t\t\t\tnodesToCapture.push({ node: typeArgument, tokenRange: typeArgumentTokenRange });\n\n\t\t\t\t\t\t\t\treturn typeArgumentTokenRange;\n\t\t\t\t\t\t\t}) ?? []),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tnodesToCapture.push({ node: heritageClause.types[0], tokenRange: extendsTokenRange });\n\t\t\t\t\t}\n\t\t\t\t} else if (heritageClause.token === ts.SyntaxKind.ImplementsKeyword) {\n\t\t\t\t\tfor (const heritageType of heritageClause.types) {\n\t\t\t\t\t\tconst implementsTokenRange: IExcerptTokenRangeWithTypeParameters =\n\t\t\t\t\t\t\tExcerptBuilder.createEmptyTokenRangeWithTypeParameters();\n\t\t\t\t\t\timplementsTokenRange.typeParameters.push(\n\t\t\t\t\t\t\t...(heritageType.typeArguments?.map((typeArgument) => {\n\t\t\t\t\t\t\t\tconst typeArgumentTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\t\t\t\t\t\tif (ts.isTypeReferenceNode(typeArgument)) {\n\t\t\t\t\t\t\t\t\tnodesToCapture.push({ node: typeArgument, tokenRange: typeArgumentTokenRange });\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn typeArgumentTokenRange;\n\t\t\t\t\t\t\t}) ?? []),\n\t\t\t\t\t\t);\n\t\t\t\t\t\timplementsTokenRanges.push(implementsTokenRange);\n\t\t\t\t\t\tnodesToCapture.push({ node: heritageType, tokenRange: implementsTokenRange });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint);\n\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\tconst docComment: tsdoc.DocComment | undefined = jsDoc\n\t\t\t\t? this._tsDocParser.parseString(\n\t\t\t\t\t\t`/**\\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\\n${\n\t\t\t\t\t\t\tjsDoc.see?.map((see) => ` * @see ${see}\\n`).join('') ?? ''\n\t\t\t\t\t\t}${\n\t\t\t\t\t\t\tjsDoc.deprecated\n\t\t\t\t\t\t\t\t? ` * @deprecated ${\n\t\t\t\t\t\t\t\t\t\ttypeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated\n\t\t\t\t\t\t\t\t\t}\\n`\n\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t} */`,\n\t\t\t\t\t).docComment\n\t\t\t\t: apiItemMetadata.tsdocComment;\n\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\tconst isAbstract: boolean = (ts.getCombinedModifierFlags(classDeclaration) & ts.ModifierFlags.Abstract) !== 0;\n\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(classDeclaration);\n\n\t\t\tapiClass = new ApiClass({\n\t\t\t\tname,\n\t\t\t\tisAbstract,\n\t\t\t\tdocComment,\n\t\t\t\treleaseTag,\n\t\t\t\texcerptTokens,\n\t\t\t\ttypeParameters,\n\t\t\t\textendsTokenRange,\n\t\t\t\timplementsTokenRanges,\n\t\t\t\tisExported,\n\t\t\t\tfileUrlPath: jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,\n\t\t\t\tfileLine: jsDoc?.meta.line ?? sourceLocation.sourceFileLine,\n\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t});\n\n\t\t\tparentApiItem.addMember(apiClass);\n\t\t}\n\n\t\tthis._processChildDeclarations(astDeclaration, {\n\t\t\t...context,\n\t\t\tparentApiItem: apiClass,\n\t\t\tparentDocgenJson: jsDoc,\n\t\t});\n\n\t\tfor (const event of jsDoc?.events ?? []) {\n\t\t\tthis._processApiEvent({ ...context, name: event.name, parentApiItem: apiClass, parentDocgenJson: jsDoc });\n\t\t}\n\t}\n\n\tprivate _processApiConstructSignature(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {\n\t\tconst { entryPoint, parentApiItem } = context;\n\t\tconst overloadIndex: number = this._collector.getOverloadIndex(astDeclaration);\n\t\tconst containerKey: string = ApiConstructSignature.getContainerKey(overloadIndex);\n\n\t\tlet apiConstructSignature: ApiConstructSignature | undefined = parentApiItem.tryGetMemberByKey(\n\t\t\tcontainerKey,\n\t\t) as ApiConstructSignature;\n\n\t\tif (apiConstructSignature === undefined) {\n\t\t\tconst constructSignature: ts.ConstructSignatureDeclaration =\n\t\t\t\tastDeclaration.declaration as ts.ConstructSignatureDeclaration;\n\n\t\t\tconst nodesToCapture: IExcerptBuilderNodeToCapture[] = [];\n\t\t\tconst parent = context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | undefined;\n\n\t\t\tconst returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\tnodesToCapture.push({ node: constructSignature.type, tokenRange: returnTypeTokenRange });\n\n\t\t\tconst typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(\n\t\t\t\tnodesToCapture,\n\t\t\t\tconstructSignature.typeParameters,\n\t\t\t);\n\n\t\t\tconst parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, constructSignature.parameters);\n\n\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint);\n\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\tconst docComment: tsdoc.DocComment | undefined = parent?.construct\n\t\t\t\t? this._tsDocParser.parseString(\n\t\t\t\t\t\t`/*+\\n * ${this._fixLinkTags(parent.construct.description) ?? ''}\\n${\n\t\t\t\t\t\t\tparent.construct.params\n\t\t\t\t\t\t\t\t?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\\n`)\n\t\t\t\t\t\t\t\t.join('') ?? ''\n\t\t\t\t\t\t} */`,\n\t\t\t\t\t).docComment\n\t\t\t\t: apiItemMetadata.tsdocComment;\n\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(constructSignature);\n\n\t\t\tapiConstructSignature = new ApiConstructSignature({\n\t\t\t\tdocComment,\n\t\t\t\treleaseTag,\n\t\t\t\ttypeParameters,\n\t\t\t\tparameters,\n\t\t\t\toverloadIndex,\n\t\t\t\texcerptTokens,\n\t\t\t\treturnTypeTokenRange,\n\t\t\t\tfileUrlPath: parent ? filePathFromJson(parent.meta) : sourceLocation.sourceFilePath,\n\t\t\t\tfileLine: parent?.meta.line ?? sourceLocation.sourceFileLine,\n\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t});\n\n\t\t\tparentApiItem.addMember(apiConstructSignature);\n\t\t}\n\t}\n\n\tprivate _processApiEnum(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {\n\t\tconst { entryPoint, name, isExported, parentApiItem } = context;\n\t\tconst containerKey: string = ApiEnum.getContainerKey(name);\n\n\t\tlet apiEnum: ApiEnum | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiEnum;\n\n\t\tif (apiEnum === undefined) {\n\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, [], entryPoint);\n\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\tconst docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment;\n\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\tconst preserveMemberOrder: boolean = this._collector.extractorConfig.enumMemberOrder === EnumMemberOrder.Preserve;\n\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(astDeclaration.declaration);\n\n\t\t\tapiEnum = new ApiEnum({\n\t\t\t\tname,\n\t\t\t\tdocComment,\n\t\t\t\treleaseTag,\n\t\t\t\texcerptTokens,\n\t\t\t\tpreserveMemberOrder,\n\t\t\t\tisExported,\n\t\t\t\tfileUrlPath: sourceLocation.sourceFilePath,\n\t\t\t\tfileLine: sourceLocation.sourceFileLine,\n\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t});\n\t\t\tparentApiItem.addMember(apiEnum);\n\t\t}\n\n\t\tthis._processChildDeclarations(astDeclaration, {\n\t\t\t...context,\n\t\t\tparentApiItem: apiEnum,\n\t\t});\n\t}\n\n\tprivate _processApiEnumMember(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {\n\t\tconst { entryPoint, name, parentApiItem } = context;\n\t\tconst containerKey: string = ApiEnumMember.getContainerKey(name);\n\n\t\tlet apiEnumMember: ApiEnumMember | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiEnumMember;\n\n\t\tif (apiEnumMember === undefined) {\n\t\t\tconst enumMember: ts.EnumMember = astDeclaration.declaration as ts.EnumMember;\n\n\t\t\tconst nodesToCapture: IExcerptBuilderNodeToCapture[] = [];\n\n\t\t\tlet initializerTokenRange: IExcerptTokenRange | undefined;\n\t\t\tif (enumMember.initializer) {\n\t\t\t\tinitializerTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\t\tnodesToCapture.push({ node: enumMember.initializer, tokenRange: initializerTokenRange });\n\t\t\t}\n\n\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint);\n\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\tconst docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment;\n\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(enumMember);\n\n\t\t\tapiEnumMember = new ApiEnumMember({\n\t\t\t\tname,\n\t\t\t\tdocComment,\n\t\t\t\treleaseTag,\n\t\t\t\texcerptTokens,\n\t\t\t\tinitializerTokenRange,\n\t\t\t\tfileUrlPath: sourceLocation.sourceFilePath,\n\t\t\t\tfileLine: sourceLocation.sourceFileLine,\n\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t});\n\n\t\t\tparentApiItem.addMember(apiEnumMember);\n\t\t}\n\t}\n\n\tprivate _processApiFunction(\n\t\tastDeclaration: AstDeclaration,\n\t\tcontext: IProcessAstEntityContext,\n\t\taltFunctionDeclaration?: ts.FunctionDeclaration,\n\t): void {\n\t\tconst { entryPoint, name, isExported, parentApiItem } = context;\n\n\t\tconst overloadIndex: number = this._collector.getOverloadIndex(astDeclaration);\n\t\tconst containerKey: string = ApiFunction.getContainerKey(name, overloadIndex);\n\n\t\tlet apiFunction: ApiFunction | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiFunction;\n\t\tconst parent = context.parentDocgenJson as DocgenJson | undefined;\n\t\tconst jsDoc = parent?.functions.find((fun) => fun.name === name);\n\n\t\tif (apiFunction === undefined) {\n\t\t\tconst functionDeclaration: ts.FunctionDeclaration =\n\t\t\t\taltFunctionDeclaration ?? (astDeclaration.declaration as ts.FunctionDeclaration);\n\n\t\t\tconst nodesToCapture: IExcerptBuilderNodeToCapture[] = [];\n\n\t\t\tconst returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\tnodesToCapture.push({ node: functionDeclaration.type, tokenRange: returnTypeTokenRange });\n\n\t\t\tconst typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(\n\t\t\t\tnodesToCapture,\n\t\t\t\tfunctionDeclaration.typeParameters,\n\t\t\t);\n\n\t\t\tconst parameters: IApiParameterOptions[] = this._captureParameters(\n\t\t\t\tnodesToCapture,\n\t\t\t\tfunctionDeclaration.parameters,\n\t\t\t\tjsDoc?.params,\n\t\t\t);\n\n\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint);\n\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\tconst docComment: tsdoc.DocComment | undefined = jsDoc\n\t\t\t\t? this._tsDocParser.parseString(\n\t\t\t\t\t\t`/**\\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\\n${\n\t\t\t\t\t\t\tjsDoc.params\n\t\t\t\t\t\t\t\t?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\\n`)\n\t\t\t\t\t\t\t\t.join('') ?? ''\n\t\t\t\t\t\t}${\n\t\t\t\t\t\t\tjsDoc.returns?.length && !Array.isArray(jsDoc.returns[0])\n\t\t\t\t\t\t\t\t? ` * @returns ${this._fixLinkTags(jsDoc.returns[0]!.description) ?? ''}`\n\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t}${\n\t\t\t\t\t\t\tjsDoc.deprecated\n\t\t\t\t\t\t\t\t? ` * @deprecated ${\n\t\t\t\t\t\t\t\t\t\ttypeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated\n\t\t\t\t\t\t\t\t\t}\\n`\n\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t} */`,\n\t\t\t\t\t).docComment\n\t\t\t\t: apiItemMetadata.tsdocComment;\n\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(functionDeclaration);\n\n\t\t\tapiFunction = new ApiFunction({\n\t\t\t\tname,\n\t\t\t\tdocComment,\n\t\t\t\treleaseTag,\n\t\t\t\ttypeParameters,\n\t\t\t\tparameters,\n\t\t\t\toverloadIndex,\n\t\t\t\texcerptTokens,\n\t\t\t\treturnTypeTokenRange,\n\t\t\t\tisExported,\n\t\t\t\tfileUrlPath: jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,\n\t\t\t\tfileLine: jsDoc?.meta.line ?? sourceLocation.sourceFileLine,\n\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t});\n\n\t\t\tparentApiItem.addMember(apiFunction);\n\t\t}\n\t}\n\n\tprivate _processApiIndexSignature(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {\n\t\tconst { entryPoint, parentApiItem } = context;\n\t\tconst overloadIndex: number = this._collector.getOverloadIndex(astDeclaration);\n\t\tconst containerKey: string = ApiIndexSignature.getContainerKey(overloadIndex);\n\n\t\tlet apiIndexSignature: ApiIndexSignature | undefined = parentApiItem.tryGetMemberByKey(\n\t\t\tcontainerKey,\n\t\t) as ApiIndexSignature;\n\n\t\tif (apiIndexSignature === undefined) {\n\t\t\tconst indexSignature: ts.IndexSignatureDeclaration = astDeclaration.declaration as ts.IndexSignatureDeclaration;\n\n\t\t\tconst nodesToCapture: IExcerptBuilderNodeToCapture[] = [];\n\n\t\t\tconst returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\tnodesToCapture.push({ node: indexSignature.type, tokenRange: returnTypeTokenRange });\n\n\t\t\tconst parameters: IApiParameterOptions[] = this._captureParameters(nodesToCapture, indexSignature.parameters);\n\n\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint);\n\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\tconst docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment;\n\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\tconst isReadonly: boolean = this._isReadonly(astDeclaration);\n\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(indexSignature);\n\n\t\t\tapiIndexSignature = new ApiIndexSignature({\n\t\t\t\tdocComment,\n\t\t\t\treleaseTag,\n\t\t\t\tparameters,\n\t\t\t\toverloadIndex,\n\t\t\t\texcerptTokens,\n\t\t\t\treturnTypeTokenRange,\n\t\t\t\tisReadonly,\n\t\t\t\tfileUrlPath: sourceLocation.sourceFilePath,\n\t\t\t\tfileLine: sourceLocation.sourceFileLine,\n\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t});\n\n\t\t\tparentApiItem.addMember(apiIndexSignature);\n\t\t}\n\t}\n\n\tprivate _processApiInterface(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {\n\t\tconst { entryPoint, name, isExported, parentApiItem } = context;\n\t\tconst containerKey: string = ApiInterface.getContainerKey(name);\n\n\t\tlet apiInterface: ApiInterface | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiInterface;\n\t\tconst parent = context.parentDocgenJson as DocgenJson | undefined;\n\t\tconst jsDoc =\n\t\t\tparent?.interfaces.find((int) => int.name === name) ?? parent?.typedefs.find((int) => int.name === name);\n\n\t\tif (apiInterface === undefined) {\n\t\t\tconst interfaceDeclaration: ts.InterfaceDeclaration = astDeclaration.declaration as ts.InterfaceDeclaration;\n\n\t\t\tconst nodesToCapture: IExcerptBuilderNodeToCapture[] = [];\n\n\t\t\tconst typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(\n\t\t\t\tnodesToCapture,\n\t\t\t\tinterfaceDeclaration.typeParameters,\n\t\t\t);\n\n\t\t\tconst extendsTokenRanges: IExcerptTokenRangeWithTypeParameters[] = [];\n\n\t\t\tfor (const heritageClause of interfaceDeclaration.heritageClauses ?? []) {\n\t\t\t\tif (heritageClause.token === ts.SyntaxKind.ExtendsKeyword) {\n\t\t\t\t\tfor (const heritageType of heritageClause.types) {\n\t\t\t\t\t\tconst extendsTokenRange: IExcerptTokenRangeWithTypeParameters =\n\t\t\t\t\t\t\tExcerptBuilder.createEmptyTokenRangeWithTypeParameters();\n\t\t\t\t\t\textendsTokenRange.typeParameters.push(\n\t\t\t\t\t\t\t...(heritageType.typeArguments?.map((typeArgument) => {\n\t\t\t\t\t\t\t\tconst typeArgumentTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\t\t\t\t\t\tif (ts.isTypeReferenceNode(typeArgument)) {\n\t\t\t\t\t\t\t\t\tnodesToCapture.push({ node: typeArgument, tokenRange: typeArgumentTokenRange });\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn typeArgumentTokenRange;\n\t\t\t\t\t\t\t}) ?? []),\n\t\t\t\t\t\t);\n\t\t\t\t\t\textendsTokenRanges.push(extendsTokenRange);\n\t\t\t\t\t\tnodesToCapture.push({ node: heritageType, tokenRange: extendsTokenRange });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint);\n\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\tconst docComment: tsdoc.DocComment | undefined = jsDoc\n\t\t\t\t? this._tsDocParser.parseString(\n\t\t\t\t\t\t`/**\\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\\n${\n\t\t\t\t\t\t\tjsDoc.see?.map((see) => ` * @see ${see}\\n`).join('') ?? ''\n\t\t\t\t\t\t}${\n\t\t\t\t\t\t\tjsDoc.deprecated\n\t\t\t\t\t\t\t\t? ` * @deprecated ${\n\t\t\t\t\t\t\t\t\t\ttypeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated\n\t\t\t\t\t\t\t\t\t}\\n`\n\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t} */`,\n\t\t\t\t\t).docComment\n\t\t\t\t: apiItemMetadata.tsdocComment;\n\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(interfaceDeclaration);\n\n\t\t\tapiInterface = new ApiInterface({\n\t\t\t\tname,\n\t\t\t\tdocComment,\n\t\t\t\treleaseTag,\n\t\t\t\texcerptTokens,\n\t\t\t\ttypeParameters,\n\t\t\t\textendsTokenRanges,\n\t\t\t\tisExported,\n\t\t\t\tfileUrlPath: jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,\n\t\t\t\tfileLine: jsDoc?.meta.line ?? sourceLocation.sourceFileLine,\n\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t});\n\n\t\t\tparentApiItem.addMember(apiInterface);\n\t\t}\n\n\t\tthis._processChildDeclarations(astDeclaration, {\n\t\t\t...context,\n\t\t\tparentApiItem: apiInterface,\n\t\t\tparentDocgenJson: jsDoc,\n\t\t});\n\t}\n\n\tprivate _processApiMethod(astDeclaration: AstDeclaration | null, context: IProcessAstEntityContext): void {\n\t\tconst { entryPoint, name, parentApiItem } = context;\n\t\tconst parent = context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | undefined;\n\t\tconst jsDoc = parent?.methods?.find((method) => method.name === name);\n\t\tconst isStatic: boolean = astDeclaration\n\t\t\t? (astDeclaration.modifierFlags & ts.ModifierFlags.Static) !== 0\n\t\t\t: jsDoc?.scope === 'static';\n\t\tconst overloadIndex: number = astDeclaration ? this._collector.getOverloadIndex(astDeclaration) : 1;\n\t\tconst containerKey: string = ApiMethod.getContainerKey(name, isStatic, overloadIndex);\n\n\t\tlet apiMethod: ApiMethod | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiMethod;\n\n\t\tif (apiMethod === undefined) {\n\t\t\tif (astDeclaration) {\n\t\t\t\tconst methodDeclaration: ts.MethodDeclaration = astDeclaration.declaration as ts.MethodDeclaration;\n\n\t\t\t\tconst nodesToCapture: IExcerptBuilderNodeToCapture[] = [];\n\n\t\t\t\tconst returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\t\tnodesToCapture.push({ node: methodDeclaration.type, tokenRange: returnTypeTokenRange });\n\n\t\t\t\tconst typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(\n\t\t\t\t\tnodesToCapture,\n\t\t\t\t\tmethodDeclaration.typeParameters,\n\t\t\t\t);\n\n\t\t\t\tconst parameters: IApiParameterOptions[] = this._captureParameters(\n\t\t\t\t\tnodesToCapture,\n\t\t\t\t\tmethodDeclaration.parameters,\n\t\t\t\t\tjsDoc?.params,\n\t\t\t\t);\n\n\t\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint);\n\t\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\t\tconst docComment: tsdoc.DocComment | undefined = jsDoc\n\t\t\t\t\t? this._tsDocParser.parseString(\n\t\t\t\t\t\t\t`/**\\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\\n${\n\t\t\t\t\t\t\t\tjsDoc.params\n\t\t\t\t\t\t\t\t\t?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\\n`)\n\t\t\t\t\t\t\t\t\t.join('') ?? ''\n\t\t\t\t\t\t\t}${\n\t\t\t\t\t\t\t\tjsDoc.returns?.length && !Array.isArray(jsDoc.returns[0])\n\t\t\t\t\t\t\t\t\t? ` * @returns ${this._fixLinkTags(jsDoc.returns[0]!.description) ?? ''}\\n`\n\t\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t\t}${\n\t\t\t\t\t\t\t\tjsDoc.examples?.map((example) => ` * @example\\n * \\`\\`\\`js\\n * ${example}\\n * \\`\\`\\`\\n`).join('') ?? ''\n\t\t\t\t\t\t\t}${\n\t\t\t\t\t\t\t\tjsDoc.deprecated\n\t\t\t\t\t\t\t\t\t? ` * @deprecated ${\n\t\t\t\t\t\t\t\t\t\t\ttypeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated\n\t\t\t\t\t\t\t\t\t\t}\\n`\n\t\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t\t} */`,\n\t\t\t\t\t\t).docComment\n\t\t\t\t\t: apiItemMetadata.tsdocComment;\n\t\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\t\tif (releaseTag === ReleaseTag.Internal || releaseTag === ReleaseTag.Alpha) {\n\t\t\t\t\treturn; // trim out items marked as \"@internal\" or \"@alpha\"\n\t\t\t\t}\n\n\t\t\t\tconst isOptional: boolean = (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0;\n\t\t\t\tconst isProtected: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Protected) !== 0;\n\t\t\t\tconst isAbstract: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Abstract) !== 0;\n\t\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(methodDeclaration);\n\n\t\t\t\tapiMethod = new ApiMethod({\n\t\t\t\t\tname,\n\t\t\t\t\tisAbstract,\n\t\t\t\t\tdocComment,\n\t\t\t\t\treleaseTag,\n\t\t\t\t\tisProtected,\n\t\t\t\t\tisStatic,\n\t\t\t\t\tisOptional,\n\t\t\t\t\ttypeParameters,\n\t\t\t\t\tparameters,\n\t\t\t\t\toverloadIndex,\n\t\t\t\t\texcerptTokens,\n\t\t\t\t\treturnTypeTokenRange,\n\t\t\t\t\tfileUrlPath: jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,\n\t\t\t\t\tfileLine: jsDoc?.meta.line ?? sourceLocation.sourceFileLine,\n\t\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t\t});\n\t\t\t} else if (jsDoc) {\n\t\t\t\tif (jsDoc.inherited) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst methodOptions = this._mapMethod(jsDoc, parentApiItem.getAssociatedPackage()!.name);\n\t\t\t\tif (methodOptions.releaseTag === ReleaseTag.Internal || methodOptions.releaseTag === ReleaseTag.Alpha) {\n\t\t\t\t\treturn; // trim out items marked as \"@internal\" or \"@alpha\"\n\t\t\t\t}\n\n\t\t\t\tapiMethod = new ApiMethod(methodOptions);\n\t\t\t}\n\n\t\t\tparentApiItem.addMember(apiMethod);\n\t\t}\n\t}\n\n\tprivate _processApiMethodSignature(astDeclaration: AstDeclaration | null, context: IProcessAstEntityContext): void {\n\t\tconst { entryPoint, name, parentApiItem } = context;\n\t\tconst overloadIndex: number = astDeclaration ? this._collector.getOverloadIndex(astDeclaration) : 1;\n\t\tconst containerKey: string = ApiMethodSignature.getContainerKey(name, overloadIndex);\n\n\t\tlet apiMethodSignature: ApiMethodSignature | undefined = parentApiItem.tryGetMemberByKey(\n\t\t\tcontainerKey,\n\t\t) as ApiMethodSignature;\n\t\tconst parent = context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | undefined;\n\t\tconst jsDoc = parent?.methods?.find((method) => method.name === name);\n\n\t\tif (apiMethodSignature === undefined) {\n\t\t\tif (astDeclaration) {\n\t\t\t\tconst methodSignature: ts.MethodSignature = astDeclaration.declaration as ts.MethodSignature;\n\n\t\t\t\tconst nodesToCapture: IExcerptBuilderNodeToCapture[] = [];\n\n\t\t\t\tconst returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\t\tnodesToCapture.push({ node: methodSignature.type, tokenRange: returnTypeTokenRange });\n\n\t\t\t\tconst typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(\n\t\t\t\t\tnodesToCapture,\n\t\t\t\t\tmethodSignature.typeParameters,\n\t\t\t\t);\n\n\t\t\t\tconst parameters: IApiParameterOptions[] = this._captureParameters(\n\t\t\t\t\tnodesToCapture,\n\t\t\t\t\tmethodSignature.parameters,\n\t\t\t\t\tjsDoc?.params,\n\t\t\t\t);\n\n\t\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint);\n\t\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\t\tconst docComment: tsdoc.DocComment | undefined = jsDoc\n\t\t\t\t\t? this._tsDocParser.parseString(\n\t\t\t\t\t\t\t`/**\\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\\n${\n\t\t\t\t\t\t\t\tjsDoc.params\n\t\t\t\t\t\t\t\t\t?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\\n`)\n\t\t\t\t\t\t\t\t\t.join('') ?? ''\n\t\t\t\t\t\t\t}${\n\t\t\t\t\t\t\t\tjsDoc.returns?.length && !Array.isArray(jsDoc.returns[0])\n\t\t\t\t\t\t\t\t\t? ` * @returns ${this._fixLinkTags(jsDoc.returns[0]!.description) ?? ''}\\n`\n\t\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t\t}${\n\t\t\t\t\t\t\t\tjsDoc.deprecated\n\t\t\t\t\t\t\t\t\t? ` * @deprecated ${\n\t\t\t\t\t\t\t\t\t\t\ttypeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated\n\t\t\t\t\t\t\t\t\t\t}\\n`\n\t\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t\t} */`,\n\t\t\t\t\t\t).docComment\n\t\t\t\t\t: apiItemMetadata.tsdocComment;\n\t\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\t\tconst isOptional: boolean = (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0;\n\t\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(methodSignature);\n\n\t\t\t\tapiMethodSignature = new ApiMethodSignature({\n\t\t\t\t\tname,\n\t\t\t\t\tdocComment,\n\t\t\t\t\treleaseTag,\n\t\t\t\t\tisOptional,\n\t\t\t\t\ttypeParameters,\n\t\t\t\t\tparameters,\n\t\t\t\t\toverloadIndex,\n\t\t\t\t\texcerptTokens,\n\t\t\t\t\treturnTypeTokenRange,\n\t\t\t\t\tfileUrlPath: jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,\n\t\t\t\t\tfileLine: jsDoc?.meta.line ?? sourceLocation.sourceFileLine,\n\t\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t\t});\n\t\t\t} else if (jsDoc) {\n\t\t\t\tapiMethodSignature = new ApiMethodSignature(this._mapMethod(jsDoc, parentApiItem.getAssociatedPackage()!.name));\n\t\t\t}\n\n\t\t\tparentApiItem.addMember(apiMethodSignature);\n\t\t}\n\t}\n\n\tprivate _processApiNamespace(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {\n\t\tconst { entryPoint, name, isExported, parentApiItem } = context;\n\t\tconst containerKey: string = ApiNamespace.getContainerKey(name);\n\n\t\tlet apiNamespace: ApiNamespace | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiNamespace;\n\n\t\tif (apiNamespace === undefined) {\n\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, [], entryPoint);\n\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\tconst docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment;\n\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(astDeclaration.declaration);\n\n\t\t\tapiNamespace = new ApiNamespace({\n\t\t\t\tname,\n\t\t\t\tdocComment,\n\t\t\t\treleaseTag,\n\t\t\t\texcerptTokens,\n\t\t\t\tisExported,\n\t\t\t\tfileUrlPath: sourceLocation.sourceFilePath,\n\t\t\t\tfileLine: sourceLocation.sourceFileLine,\n\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t});\n\t\t\tparentApiItem.addMember(apiNamespace);\n\t\t}\n\n\t\tthis._processChildDeclarations(astDeclaration, {\n\t\t\t...context,\n\t\t\tparentApiItem: apiNamespace,\n\t\t});\n\t}\n\n\tprivate _processApiProperty(astDeclaration: AstDeclaration | null, context: IProcessAstEntityContext): void {\n\t\tconst { entryPoint, name, parentApiItem } = context;\n\t\tconst parent = context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | DocgenTypedefJson | undefined;\n\t\tconst jsDoc = parent?.props?.find((prop) => prop.name === name);\n\t\tconst isStatic: boolean = astDeclaration\n\t\t\t? (astDeclaration.modifierFlags & ts.ModifierFlags.Static) !== 0\n\t\t\t: parentApiItem.kind === ApiItemKind.Class || parentApiItem.kind === ApiItemKind.Interface\n\t\t\t\t? (jsDoc as DocgenPropertyJson).scope === 'static'\n\t\t\t\t: false;\n\t\tconst containerKey: string = ApiProperty.getContainerKey(name, isStatic);\n\n\t\tlet apiProperty: ApiProperty | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiProperty;\n\n\t\tif (\n\t\t\tapiProperty === undefined &&\n\t\t\t(astDeclaration ||\n\t\t\t\t!this._isInherited(parent as DocgenClassJson | DocgenInterfaceJson, jsDoc!, parentApiItem.kind))\n\t\t) {\n\t\t\tif (astDeclaration) {\n\t\t\t\tconst declaration: ts.Declaration = astDeclaration.declaration;\n\t\t\t\tconst nodesToCapture: IExcerptBuilderNodeToCapture[] = [];\n\n\t\t\t\tconst propertyTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\t\tlet propertyTypeNode: ts.TypeNode | undefined;\n\n\t\t\t\tif (ts.isPropertyDeclaration(declaration) || ts.isGetAccessorDeclaration(declaration)) {\n\t\t\t\t\tpropertyTypeNode = declaration.type;\n\t\t\t\t}\n\n\t\t\t\tif (ts.isSetAccessorDeclaration(declaration)) {\n\t\t\t\t\t// Note that TypeScript always reports an error if a setter does not have exactly one parameter.\n\t\t\t\t\tpropertyTypeNode = declaration.parameters[0]!.type;\n\t\t\t\t}\n\n\t\t\t\tnodesToCapture.push({ node: propertyTypeNode, tokenRange: propertyTypeTokenRange });\n\n\t\t\t\tlet initializerTokenRange: IExcerptTokenRange | undefined;\n\t\t\t\tif (ts.isPropertyDeclaration(declaration) && declaration.initializer) {\n\t\t\t\t\tinitializerTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\t\t\tnodesToCapture.push({ node: declaration.initializer, tokenRange: initializerTokenRange });\n\t\t\t\t}\n\n\t\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint);\n\t\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\t\tconst docComment: tsdoc.DocComment | undefined = jsDoc\n\t\t\t\t\t? this._tsDocParser.parseString(\n\t\t\t\t\t\t\t`/**\\n * ${this._fixLinkTags(jsDoc.description) ?? ''}${jsDoc.default === undefined ? '' : ` (default: ${this._escapeSpecialChars(jsDoc.default)})`}\\n${\n\t\t\t\t\t\t\t\t'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\\n`).join('') : ''\n\t\t\t\t\t\t\t}${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\\n' : ''}${\n\t\t\t\t\t\t\t\t'deprecated' in jsDoc && jsDoc.deprecated\n\t\t\t\t\t\t\t\t\t? ` * @deprecated ${\n\t\t\t\t\t\t\t\t\t\t\ttypeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated\n\t\t\t\t\t\t\t\t\t\t}\\n`\n\t\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t\t} */`,\n\t\t\t\t\t\t).docComment\n\t\t\t\t\t: apiItemMetadata.tsdocComment;\n\t\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\t\tconst isOptional: boolean = (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0;\n\t\t\t\tconst isProtected: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Protected) !== 0;\n\t\t\t\tconst isAbstract: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Abstract) !== 0;\n\t\t\t\tconst isReadonly: boolean = this._isReadonly(astDeclaration);\n\t\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(declaration);\n\n\t\t\t\tapiProperty = new ApiProperty({\n\t\t\t\t\tname,\n\t\t\t\t\tdocComment,\n\t\t\t\t\treleaseTag,\n\t\t\t\t\tisAbstract,\n\t\t\t\t\tisProtected,\n\t\t\t\t\tisStatic,\n\t\t\t\t\tisOptional,\n\t\t\t\t\tisReadonly,\n\t\t\t\t\texcerptTokens,\n\t\t\t\t\tpropertyTypeTokenRange,\n\t\t\t\t\tinitializerTokenRange,\n\t\t\t\t\tfileUrlPath: jsDoc && 'meta' in jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,\n\t\t\t\t\tfileLine: jsDoc && 'meta' in jsDoc ? jsDoc.meta.line : sourceLocation.sourceFileLine,\n\t\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t\t});\n\t\t\t} else if (parentApiItem.kind === ApiItemKind.Class || parentApiItem.kind === ApiItemKind.Interface) {\n\t\t\t\tconst propertyOptions = this._mapProp(jsDoc as DocgenPropertyJson, parentApiItem.getAssociatedPackage()!.name);\n\t\t\t\tif (propertyOptions.releaseTag === ReleaseTag.Internal || propertyOptions.releaseTag === ReleaseTag.Alpha) {\n\t\t\t\t\treturn; // trim out items marked as \"@internal\" or \"@alpha\"\n\t\t\t\t}\n\n\t\t\t\tapiProperty = new ApiProperty(propertyOptions);\n\t\t\t} else {\n\t\t\t\tconsole.log(`We got a property in ApiItem of kind ${ApiItemKind[parentApiItem.kind]}`);\n\t\t\t}\n\n\t\t\tparentApiItem.addMember(apiProperty);\n\t\t} else {\n\t\t\t// If the property was already declared before (via a merged interface declaration),\n\t\t\t// we assume its signature is identical, because the language requires that.\n\t\t}\n\t}\n\n\tprivate _processApiPropertySignature(astDeclaration: AstDeclaration | null, context: IProcessAstEntityContext): void {\n\t\tconst { entryPoint, name, parentApiItem } = context;\n\t\tconst containerKey: string = ApiPropertySignature.getContainerKey(name);\n\n\t\tlet apiPropertySignature: ApiPropertySignature | undefined = parentApiItem.tryGetMemberByKey(\n\t\t\tcontainerKey,\n\t\t) as ApiPropertySignature;\n\t\tconst parent = context.parentDocgenJson as DocgenInterfaceJson | DocgenPropertyJson | DocgenTypedefJson | undefined;\n\t\tconst jsDoc = parent?.props?.find((prop) => prop.name === name);\n\n\t\tif (\n\t\t\tapiPropertySignature === undefined &&\n\t\t\t(astDeclaration || !this._isInherited(parent as DocgenInterfaceJson, jsDoc!, parentApiItem.kind))\n\t\t) {\n\t\t\tif (astDeclaration) {\n\t\t\t\tconst propertySignature: ts.PropertySignature = astDeclaration.declaration as ts.PropertySignature;\n\n\t\t\t\tconst nodesToCapture: IExcerptBuilderNodeToCapture[] = [];\n\n\t\t\t\tconst propertyTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\t\tnodesToCapture.push({ node: propertySignature.type, tokenRange: propertyTypeTokenRange });\n\n\t\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint);\n\t\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\t\tconst docComment: tsdoc.DocComment | undefined = jsDoc\n\t\t\t\t\t? this._tsDocParser.parseString(\n\t\t\t\t\t\t\t`/**\\n * ${this._fixLinkTags(jsDoc.description) ?? ''}${jsDoc.default === undefined ? '' : `\\n * @defaultValue ${this._escapeSpecialChars(jsDoc.default)}`}\\n${\n\t\t\t\t\t\t\t\t'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\\n`).join('') : ''\n\t\t\t\t\t\t\t}${'readonly' in jsDoc && jsDoc.readonly ? ' * @readonly\\n' : ''}${\n\t\t\t\t\t\t\t\t'deprecated' in jsDoc && jsDoc.deprecated\n\t\t\t\t\t\t\t\t\t? ` * @deprecated ${\n\t\t\t\t\t\t\t\t\t\t\ttypeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated\n\t\t\t\t\t\t\t\t\t\t}\\n`\n\t\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t\t} */`,\n\t\t\t\t\t\t).docComment\n\t\t\t\t\t: apiItemMetadata.tsdocComment;\n\t\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\t\tconst isOptional: boolean = (astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0;\n\t\t\t\tconst isReadonly: boolean = this._isReadonly(astDeclaration);\n\t\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(propertySignature);\n\n\t\t\t\tapiPropertySignature = new ApiPropertySignature({\n\t\t\t\t\tname,\n\t\t\t\t\tdocComment,\n\t\t\t\t\treleaseTag,\n\t\t\t\t\tisOptional,\n\t\t\t\t\texcerptTokens,\n\t\t\t\t\tpropertyTypeTokenRange,\n\t\t\t\t\tisReadonly,\n\t\t\t\t\tfileUrlPath: jsDoc && 'meta' in jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,\n\t\t\t\t\tfileLine: jsDoc && 'meta' in jsDoc ? jsDoc.meta.line : sourceLocation.sourceFileLine,\n\t\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t\t});\n\t\t\t} else if (parentApiItem.kind === ApiItemKind.Class || parentApiItem.kind === ApiItemKind.Interface) {\n\t\t\t\tapiPropertySignature = new ApiPropertySignature(\n\t\t\t\t\tthis._mapProp(jsDoc as DocgenPropertyJson, parentApiItem.getAssociatedPackage()!.name),\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tconsole.log(`We got a property in ApiItem of kind ${ApiItemKind[parentApiItem.kind]}`);\n\t\t\t}\n\n\t\t\tparentApiItem.addMember(apiPropertySignature);\n\t\t} else {\n\t\t\t// If the property was already declared before (via a merged interface declaration),\n\t\t\t// we assume its signature is identical, because the language requires that.\n\t\t}\n\t}\n\n\tprivate _processApiTypeAlias(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {\n\t\tconst { entryPoint, name, isExported, parentApiItem } = context;\n\n\t\tconst containerKey: string = ApiTypeAlias.getContainerKey(name);\n\n\t\tlet apiTypeAlias: ApiTypeAlias | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiTypeAlias;\n\t\tconst parent = context.parentDocgenJson as DocgenJson | undefined;\n\t\tconst jsDoc =\n\t\t\tparent?.typedefs.find((type) => type.name === name) ??\n\t\t\tparent?.functions.find((func) => func.name === name) ??\n\t\t\tparent?.interfaces.find((clas) => clas.name === name);\n\n\t\tif (apiTypeAlias === undefined) {\n\t\t\tconst typeAliasDeclaration: ts.TypeAliasDeclaration = astDeclaration.declaration as ts.TypeAliasDeclaration;\n\n\t\t\tconst nodesToCapture: IExcerptBuilderNodeToCapture[] = [];\n\n\t\t\tconst typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters(\n\t\t\t\tnodesToCapture,\n\t\t\t\ttypeAliasDeclaration.typeParameters,\n\t\t\t);\n\n\t\t\tconst typeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\tnodesToCapture.push({ node: typeAliasDeclaration.type, tokenRange: typeTokenRange });\n\n\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint);\n\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\tconst docComment: tsdoc.DocComment | undefined = jsDoc\n\t\t\t\t? this._tsDocParser.parseString(\n\t\t\t\t\t\t`/**\\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\\n${\n\t\t\t\t\t\t\t'params' in jsDoc\n\t\t\t\t\t\t\t\t? jsDoc.params\n\t\t\t\t\t\t\t\t\t\t.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\\n`)\n\t\t\t\t\t\t\t\t\t\t.join('')\n\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t}${\n\t\t\t\t\t\t\t'returns' in jsDoc\n\t\t\t\t\t\t\t\t? jsDoc.returns\n\t\t\t\t\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t\t\t\t\t(ret) => ` * @returns ${Array.isArray(ret) ? '' : (this._fixLinkTags(ret.description) ?? '')}\\n`,\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t.join('')\n\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t} */`,\n\t\t\t\t\t).docComment\n\t\t\t\t: apiItemMetadata.tsdocComment;\n\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(typeAliasDeclaration);\n\n\t\t\tapiTypeAlias = new ApiTypeAlias({\n\t\t\t\tname,\n\t\t\t\tdocComment,\n\t\t\t\ttypeParameters,\n\t\t\t\treleaseTag,\n\t\t\t\texcerptTokens,\n\t\t\t\ttypeTokenRange,\n\t\t\t\tisExported,\n\t\t\t\tfileUrlPath: jsDoc ? filePathFromJson(jsDoc.meta) : sourceLocation.sourceFilePath,\n\t\t\t\tfileLine: jsDoc?.meta.line ?? sourceLocation.sourceFileLine,\n\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t});\n\n\t\t\tparentApiItem.addMember(apiTypeAlias);\n\t\t}\n\t}\n\n\tprivate _processApiVariable(astDeclaration: AstDeclaration, context: IProcessAstEntityContext): void {\n\t\tconst { entryPoint, name, isExported, parentApiItem } = context;\n\n\t\tconst containerKey: string = ApiVariable.getContainerKey(name);\n\n\t\tlet apiVariable: ApiVariable | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiVariable;\n\n\t\tif (apiVariable === undefined) {\n\t\t\tconst variableDeclaration: ts.VariableDeclaration = astDeclaration.declaration as ts.VariableDeclaration;\n\n\t\t\tconst nodesToCapture: IExcerptBuilderNodeToCapture[] = [];\n\n\t\t\tconst variableTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\tnodesToCapture.push({ node: variableDeclaration.type, tokenRange: variableTypeTokenRange });\n\n\t\t\tlet initializerTokenRange: IExcerptTokenRange | undefined;\n\t\t\tif (variableDeclaration.initializer) {\n\t\t\t\tinitializerTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\t\tnodesToCapture.push({ node: variableDeclaration.initializer, tokenRange: initializerTokenRange });\n\t\t\t}\n\n\t\t\tconst excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture, entryPoint);\n\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\tconst docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment;\n\t\t\tconst releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;\n\t\t\tconst isReadonly: boolean = this._isReadonly(astDeclaration);\n\t\t\tconst sourceLocation: ISourceLocation = this._getSourceLocation(variableDeclaration);\n\n\t\t\tapiVariable = new ApiVariable({\n\t\t\t\tname,\n\t\t\t\tdocComment,\n\t\t\t\treleaseTag,\n\t\t\t\texcerptTokens,\n\t\t\t\tvariableTypeTokenRange,\n\t\t\t\tinitializerTokenRange,\n\t\t\t\tisReadonly,\n\t\t\t\tisExported,\n\t\t\t\tfileUrlPath: sourceLocation.sourceFilePath,\n\t\t\t\tfileLine: sourceLocation.sourceFileLine,\n\t\t\t\tfileColumn: sourceLocation.sourceFileColumn,\n\t\t\t});\n\n\t\t\tparentApiItem.addMember(apiVariable);\n\t\t}\n\t}\n\n\t// events aren't part of typescript, we only get them from docgen JSON here\n\tprivate _processApiEvent(context: IProcessAstEntityContext): void {\n\t\tconst { name, parentApiItem } = context;\n\t\tconst containerKey: string = ApiProperty.getContainerKey(name, false);\n\n\t\tlet apiEvent: ApiEvent | undefined = parentApiItem.tryGetMemberByKey(containerKey) as ApiEvent;\n\t\tconst parent = context.parentDocgenJson as DocgenClassJson | DocgenInterfaceJson | undefined;\n\t\tconst jsDoc = parent?.events?.find((prop) => prop.name === name);\n\n\t\tif (apiEvent === undefined && jsDoc) {\n\t\t\tconst excerptTokens: IExcerptToken[] = [\n\t\t\t\t{\n\t\t\t\t\tkind: ExcerptTokenKind.Content,\n\t\t\t\t\ttext: `public on(eventName: '${name}', listener: (${\n\t\t\t\t\t\tjsDoc.params?.length\n\t\t\t\t\t\t\t? `${jsDoc.params[0]?.name}${jsDoc.params[0]?.optional ? '?' : ''}: `\n\t\t\t\t\t\t\t: ') => void): this;'\n\t\t\t\t\t}`,\n\t\t\t\t},\n\t\t\t];\n\t\t\tconst parameters: IApiParameterOptions[] = [];\n\t\t\tfor (let index = 0; index < (jsDoc.params?.length ?? 0) - 1; index++) {\n\t\t\t\tconst parameter = jsDoc.params![index]!;\n\t\t\t\tconst newTokens = this._mapVarType(parameter.type, parameter.nullable);\n\t\t\t\tparameters.push({\n\t\t\t\t\tparameterName: parameter.name,\n\t\t\t\t\tparameterTypeTokenRange: {\n\t\t\t\t\t\tstartIndex: excerptTokens.length,\n\t\t\t\t\t\tendIndex: excerptTokens.length + newTokens.length,\n\t\t\t\t\t},\n\t\t\t\t\tisOptional: Boolean(parameter.optional),\n\t\t\t\t\tisRest: parameter.name.startsWith('...'),\n\t\t\t\t\tdefaultValue: parameter.default?.toString(),\n\t\t\t\t});\n\t\t\t\texcerptTokens.push(...newTokens);\n\t\t\t\texcerptTokens.push({\n\t\t\t\t\tkind: ExcerptTokenKind.Content,\n\t\t\t\t\ttext: `, ${jsDoc.params![index + 1]?.name}${jsDoc.params![index + 1]!.optional ? '?' : ''}: `,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (jsDoc.params?.length) {\n\t\t\t\tconst parameter = jsDoc.params![jsDoc.params.length - 1]!;\n\t\t\t\tconst newTokens = this._mapVarType(parameter.type, parameter.nullable);\n\t\t\t\tparameters.push({\n\t\t\t\t\tparameterName: parameter.name,\n\t\t\t\t\tparameterTypeTokenRange: {\n\t\t\t\t\t\tstartIndex: excerptTokens.length,\n\t\t\t\t\t\tendIndex: excerptTokens.length + newTokens.length,\n\t\t\t\t\t},\n\t\t\t\t\tisOptional: Boolean(parameter.optional),\n\t\t\t\t\tisRest: parameter.name.startsWith('...'),\n\t\t\t\t\tdefaultValue: parameter.default?.toString(),\n\t\t\t\t});\n\t\t\t\texcerptTokens.push(...newTokens);\n\t\t\t\texcerptTokens.push({\n\t\t\t\t\tkind: ExcerptTokenKind.Content,\n\t\t\t\t\ttext: `) => void): this;`,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst docComment: tsdoc.DocComment | undefined = this._tsDocParser.parseString(\n\t\t\t\t`/**\\n * ${this._fixLinkTags(jsDoc.description) ?? ''}\\n${\n\t\t\t\t\tjsDoc.params\n\t\t\t\t\t\t?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\\n`)\n\t\t\t\t\t\t.join('') ?? ''\n\t\t\t\t}${'see' in jsDoc ? jsDoc.see.map((see) => ` * @see ${see}\\n`).join('') : ''}${\n\t\t\t\t\t'deprecated' in jsDoc && jsDoc.deprecated\n\t\t\t\t\t\t? ` * @deprecated ${\n\t\t\t\t\t\t\t\ttypeof jsDoc.deprecated === 'string' ? this._fixLinkTags(jsDoc.deprecated) : jsDoc.deprecated\n\t\t\t\t\t\t\t}\\n`\n\t\t\t\t\t\t: ''\n\t\t\t\t} */`,\n\t\t\t).docComment;\n\t\t\tconst releaseTag: ReleaseTag = ReleaseTag.Public;\n\n\t\t\tapiEvent = new ApiEvent({\n\t\t\t\tname,\n\t\t\t\tdocComment,\n\t\t\t\treleaseTag,\n\t\t\t\texcerptTokens,\n\t\t\t\toverloadIndex: 0,\n\t\t\t\tparameters,\n\t\t\t\tfileUrlPath: filePathFromJson(jsDoc.meta),\n\t\t\t\tfileLine: jsDoc.meta.line,\n\t\t\t\tfileColumn: 0,\n\t\t\t});\n\t\t\tparentApiItem.addMember(apiEvent);\n\t\t} else {\n\t\t\t// If the event was already declared before (via a merged interface declaration),\n\t\t\t// we assume its signature is identical, because the language requires that.\n\t\t}\n\t}\n\n\t/**\n\t * @param astDeclaration - The declaration\n\t * @param nodesToCapture - A list of child nodes whose token ranges we want to capture\n\t */\n\tprivate _buildExcerptTokens(\n\t\tastDeclaration: AstDeclaration,\n\t\tnodesToCapture: IExcerptBuilderNodeToCapture[],\n\t\tentryPoint: IWorkingPackageEntryPoint,\n\t): IExcerptToken[] {\n\t\tconst excerptTokens: IExcerptToken[] = [];\n\n\t\t// Build the main declaration\n\t\tExcerptBuilder.addDeclaration(excerptTokens, astDeclaration, nodesToCapture, this._referenceGenerator, entryPoint);\n\n\t\tconst declarationMetadata: DeclarationMetadata = this._collector.fetchDeclarationMetadata(astDeclaration);\n\n\t\t// Add any ancillary declarations\n\t\tfor (const ancillaryDeclaration of declarationMetadata.ancillaryDeclarations) {\n\t\t\tExcerptBuilder.addBlankLine(excerptTokens);\n\t\t\tExcerptBuilder.addDeclaration(\n\t\t\t\texcerptTokens,\n\t\t\t\tancillaryDeclaration,\n\t\t\t\tnodesToCapture,\n\t\t\t\tthis._referenceGenerator,\n\t\t\t\tentryPoint,\n\t\t\t);\n\t\t}\n\n\t\treturn excerptTokens;\n\t}\n\n\tprivate _captureTypeParameters(\n\t\tnodesToCapture: IExcerptBuilderNodeToCapture[],\n\t\ttypeParameterNodes: ts.NodeArray<ts.TypeParameterDeclaration> | undefined,\n\t): IApiTypeParameterOptions[] {\n\t\tconst typeParameters: IApiTypeParameterOptions[] = [];\n\t\tif (typeParameterNodes) {\n\t\t\tfor (const typeParameter of typeParameterNodes) {\n\t\t\t\tconst constraintTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\t\tnodesToCapture.push({ node: typeParameter.constraint, tokenRange: constraintTokenRange });\n\n\t\t\t\tconst defaultTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\t\tnodesToCapture.push({ node: typeParameter.default, tokenRange: defaultTypeTokenRange });\n\n\t\t\t\ttypeParameters.push({\n\t\t\t\t\ttypeParameterName: typeParameter.name.getText().trim(),\n\t\t\t\t\tconstraintTokenRange,\n\t\t\t\t\tdefaultTypeTokenRange,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn typeParameters;\n\t}\n\n\tprivate _captureParameters(\n\t\tnodesToCapture: IExcerptBuilderNodeToCapture[],\n\t\tparameterNodes: ts.NodeArray<ts.ParameterDeclaration>,\n\t\tjsDoc?: DocgenParamJson[],\n\t): IApiParameterOptions[] {\n\t\tconst parameters: IApiParameterOptions[] = [];\n\t\tfor (const parameter of parameterNodes) {\n\t\t\tconst parameterTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange();\n\t\t\tnodesToCapture.push({ node: parameter.type, tokenRange: parameterTypeTokenRange });\n\t\t\tparameters.push({\n\t\t\t\tparameterName: parameter.name.getText().trim(),\n\t\t\t\tparameterTypeTokenRange,\n\t\t\t\tisOptional: this._collector.typeChecker.isOptionalParameter(parameter),\n\t\t\t\tisRest: Boolean(parameter.dotDotDotToken),\n\t\t\t\tdefaultValue:\n\t\t\t\t\tparameter.initializer?.getText() ??\n\t\t\t\t\tjsDoc?.find((param) => param.name === parameter.name.getText().trim())?.default?.toString(),\n\t\t\t});\n\t\t}\n\n\t\treturn parameters;\n\t}\n\n\tprivate _isInherited(\n\t\tcontainer: DocgenClassJson | DocgenInterfaceJson,\n\t\tjsDoc: DocgenParamJson | DocgenPropertyJson,\n\t\tcontainerKind: ApiItemKind,\n\t): boolean {\n\t\tswitch (containerKind) {\n\t\t\tcase ApiItemKind.Class: {\n\t\t\t\tconst token = (container as DocgenClassJson).extends;\n\t\t\t\tconst parentName = Array.isArray(token) ? token[0]?.[0]?.[0] : token?.types?.[0]?.[0]?.[0];\n\t\t\t\tconst parentJson = this._jsDocJson?.classes.find((clas) => clas.name === parentName);\n\t\t\t\tif (parentJson) {\n\t\t\t\t\tif (parentJson.props?.find((prop) => prop.name === jsDoc.name)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn this._isInherited(parentJson, jsDoc, containerKind);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase ApiItemKind.Interface: {\n\t\t\t\tconst token = (container as DocgenInterfaceJson).extends;\n\t\t\t\tconst parentNames = Array.isArray(token) ? token.map((parent) => parent[0]?.[0]) : undefined;\n\t\t\t\tconst parentJsons = parentNames?.map((name) =>\n\t\t\t\t\tthis._jsDocJson?.interfaces.find((inter) => inter.name === name),\n\t\t\t\t);\n\t\t\t\tif (parentJsons?.length) {\n\t\t\t\t\tfor (const parentJson of parentJsons) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tparentJson?.props?.find((prop) => prop.name === jsDoc.name) ||\n\t\t\t\t\t\t\tthis._isInherited(parentJson as DocgenInterfaceJson, jsDoc, containerKind)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tconsole.log(`Unexpected parent of type ${containerKind} (${container.name}) of ${jsDoc?.name} `);\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tprivate _isReadonly(astDeclaration: AstDeclaration): boolean {\n\t\tswitch (astDeclaration.declaration.kind) {\n\t\t\tcase ts.SyntaxKind.GetAccessor:\n\t\t\tcase ts.SyntaxKind.IndexSignature:\n\t\t\tcase ts.SyntaxKind.PropertyDeclaration:\n\t\t\tcase ts.SyntaxKind.PropertySignature:\n\t\t\tcase ts.SyntaxKind.SetAccessor:\n\t\t\tcase ts.SyntaxKind.VariableDeclaration: {\n\t\t\t\tconst apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);\n\t\t\t\tconst docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment;\n\t\t\t\tconst declarationMetadata: DeclarationMetadata = this._collector.fetchDeclarationMetadata(astDeclaration);\n\n\t\t\t\tconst hasReadonlyModifier: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Readonly) !== 0;\n\t\t\t\tconst hasReadonlyDocTag = Boolean(docComment?.modifierTagSet?.hasTagName('@readonly'));\n\t\t\t\tconst isGetterWithNoSetter: boolean =\n\t\t\t\t\tts.isGetAccessorDeclaration(astDeclaration.declaration) &&\n\t\t\t\t\tdeclarationMetadata.ancillaryDeclarations.length === 0;\n\t\t\t\tconst isVarConst: boolean =\n\t\t\t\t\tts.isVariableDeclaration(astDeclaration.declaration) &&\n\t\t\t\t\tTypeScriptInternals.isVarConst(astDeclaration.declaration);\n\n\t\t\t\treturn hasReadonlyModifier || hasReadonlyDocTag || isGetterWithNoSetter || isVarConst;\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\t// Readonly-ness does not make sense for any other declaration kind.\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _getSourceLocation(declaration: ts.Declaration): ISourceLocation {\n\t\tconst sourceFile: ts.SourceFile = declaration.getSourceFile();\n\t\tconst sourceLocation: ISourceLocation = this._collector.sourceMapper.getSourceLocation({\n\t\t\tsourceFile,\n\t\t\tpos: declaration.getStart(sourceFile, false),\n\t\t});\n\n\t\tsourceLocation.sourceFilePath = Path.convertToSlashes(\n\t\t\tpath.relative(this._collector.extractorConfig.projectFolder, sourceLocation.sourceFilePath),\n\t\t);\n\t\treturn sourceLocation;\n\t}\n\n\tprivate _escapeSpecialChars(input: boolean | number | string) {\n\t\tif (typeof input !== 'string') {\n\t\t\treturn input;\n\t\t}\n\n\t\treturn input.replaceAll(/(?<char>[@{}])/g, '\\\\$<char>');\n\t}\n\n\tprivate _fixLinkTags(input?: string): string | undefined {\n\t\treturn input\n\t\t\t?.replaceAll(linkRegEx, (_match, _p1, _p2, _p3, _p4, _p5, _offset, _string, groups) => {\n\t\t\t\tlet target = groups.class ?? groups.url;\n\t\t\t\tconst external = this._jsDocJson?.externals.find((external) => groups.class && external.name === groups.class);\n\t\t\t\tconst match = /discord-api-types-(?<type>[^#]*?)(?:#|\\/(?<kind>[^#/]*)\\/)(?<name>[^/}]*)}$/.exec(\n\t\t\t\t\texternal?.see?.[0] ?? '',\n\t\t\t\t);\n\t\t\t\tif (match) {\n\t\t\t\t\ttarget = `discord-api-types#(${match.groups!.name}:${\n\t\t\t\t\t\t/^v\\d+$/.test(match.groups!.type!) ? match.groups!.kind : 'type'\n\t\t\t\t\t})`;\n\t\t\t\t}\n\n\t\t\t\treturn `{@link ${target}${groups.prop ? `.${groups.prop}` : ''}${groups.name ? ` |${groups.name}` : ''}}`;\n\t\t\t})\n\t\t\t.replaceAll('* ', '\\n * * ');\n\t}\n\n\tprivate _mapVarType(typey: DocgenVarTypeJson, nullable?: boolean): IExcerptToken[] {\n\t\tconst mapper = Array.isArray(typey) ? typey : (typey.types ?? []);\n\t\tconst lookup: { [K in ts.SyntaxKind]?: string } = {\n\t\t\t[ts.SyntaxKind.ClassDeclaration]: 'class',\n\t\t\t[ts.SyntaxKind.EnumDeclaration]: 'enum',\n\t\t\t[ts.SyntaxKind.InterfaceDeclaration]: 'interface',\n\t\t\t[ts.SyntaxKind.TypeAliasDeclaration]: 'type',\n\t\t};\n\t\treturn mapper\n\t\t\t.flatMap((typ, index) => {\n\t\t\t\tconst result = typ.reduce<IExcerptToken[]>((arr, [type, symbol]) => {\n\t\t\t\t\tconst astEntity =\n\t\t\t\t\t\t[...this._collector.entities.values()].reduce<AstSymbol | undefined>(\n\t\t\t\t\t\t\t(found, entities) =>\n\t\t\t\t\t\t\t\tfound ??\n\t\t\t\t\t\t\t\t(entities.find((entity) => entity.nameForEmit === type && 'astDeclarations' in entity.astEntity)\n\t\t\t\t\t\t\t\t\t?.astEntity as AstSymbol | undefined),\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t) ??\n\t\t\t\t\t\t[...this._collector.entities.values()].reduce<AstImport | undefined>(\n\t\t\t\t\t\t\t(found, entities) =>\n\t\t\t\t\t\t\t\tfound ??\n\t\t\t\t\t\t\t\t(entities.find((entity) => entity.nameForEmit === type && 'astSymbol' in entity.astEntity)\n\t\t\t\t\t\t\t\t\t?.astEntity as AstImport | undefined),\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t);\n\t\t\t\t\tconst astSymbol = astEntity instanceof AstImport ? astEntity.astSymbol : astEntity;\n\t\t\t\t\tconst match = astEntity instanceof AstImport ? moduleNameRegEx.exec(astEntity.modulePath) : null;\n\t\t\t\t\tconst pkg = match?.groups!.package ?? this._apiModel.packages[0]!.name;\n\t\t\t\t\treturn [\n\t\t\t\t\t\t...arr,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tkind: type?.includes(\"'\") ? ExcerptTokenKind.Content : ExcerptTokenKind.Reference,\n\t\t\t\t\t\t\ttext: fixPrimitiveTypes(type ?? 'unknown', symbol),\n\t\t\t\t\t\t\tcanonicalReference:\n\t\t\t\t\t\t\t\ttype?.includes(\"'\") || !astEntity\n\t\t\t\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t\t\t\t: DeclarationReference.package(pkg)\n\t\t\t\t\t\t\t\t\t\t\t.addNavigationStep(\n\t\t\t\t\t\t\t\t\t\t\t\tNavigation.Members as any,\n\t\t\t\t\t\t\t\t\t\t\t\tDeclarationReference.parseComponent(type ?? 'unknown'),\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t.withMeaning(\n\t\t\t\t\t\t\t\t\t\t\t\t(lookup[\n\t\t\t\t\t\t\t\t\t\t\t\t\tastSymbol?.astDeclarations.at(-1)?.declaration.kind ?? ts.SyntaxKind.ClassDeclaration\n\t\t\t\t\t\t\t\t\t\t\t\t] ?? 'class') as Meaning,\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t.toString(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{ kind: ExcerptTokenKind.Content, text: symbol ?? '' },\n\t\t\t\t\t];\n\t\t\t\t}, []);\n\t\t\t\treturn index === 0\n\t\t\t\t\t? mapper.length === 1 && (nullable || ('nullable' in typey && typey.nullable))\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t...result,\n\t\t\t\t\t\t\t\t{ kind: ExcerptTokenKind.Content, text: ' | ' },\n\t\t\t\t\t\t\t\t{ kind: ExcerptTokenKind.Reference, text: 'null' },\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: result\n\t\t\t\t\t: index === mapper.length - 1 && (nullable || ('nullable' in typey && typey.nullable))\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{ kind: ExcerptTokenKind.Content, text: ' | ' },\n\t\t\t\t\t\t\t\t...result,\n\t\t\t\t\t\t\t\t{ kind: ExcerptTokenKind.Content, text: ' | ' },\n\t\t\t\t\t\t\t\t{ kind: ExcerptTokenKind.Reference, text: 'null' },\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: [{ kind: ExcerptTokenKind.Content, text: ' | ' }, ...result];\n\t\t\t})\n\t\t\t.filter((excerpt) => excerpt.text.length);\n\t}\n\n\tprivate _mapProp(prop: DocgenPropertyJson, _package: string): IApiPropertyOptions {\n\t\tconst mappedVarType = this._mapVarType(prop.type);\n\t\treturn {\n\t\t\tname: prop.name,\n\t\t\tisAbstract: Boolean(prop.abstract),\n\t\t\tisProtected: prop.access === 'protected',\n\t\t\tisStatic: prop.scope === 'static',\n\t\t\tisOptional: Boolean(prop.nullable),\n\t\t\tisReadonly: Boolean(prop.readonly),\n\t\t\tdocComment: this._tsDocParser.parseString(\n\t\t\t\t`/**\\n * ${this._fixLinkTags(prop.description) ?? ''}\\n${prop.default ? ` * @defaultValue ${this._escapeSpecialChars(prop.default)}\\n` : ''}${\n\t\t\t\t\tprop.see?.map((see) => ` * @see ${see}\\n`).join('') ?? ''\n\t\t\t\t}${prop.readonly ? ' * @readonly\\n' : ''} */`,\n\t\t\t).docComment,\n\t\t\texcerptTokens: [\n\t\t\t\t{\n\t\t\t\t\tkind: ExcerptTokenKind.Content,\n\t\t\t\t\ttext: `${prop.access ? `${prop.access} ` : ''}${prop.scope === 'static' ? 'static ' : ''}${\n\t\t\t\t\t\tprop.readonly ? 'readonly ' : ''\n\t\t\t\t\t}${prop.name} :`,\n\t\t\t\t},\n\t\t\t\t...mappedVarType,\n\t\t\t\t{ kind: ExcerptTokenKind.Content, text: `${prop.default ? ` = ${prop.default}` : ''};` },\n\t\t\t],\n\t\t\tpropertyTypeTokenRange: { startIndex: 1, endIndex: 1 + mappedVarType.length },\n\t\t\treleaseTag: prop.access === 'private' ? ReleaseTag.Internal : ReleaseTag.Public,\n\t\t\tfileLine: prop.meta?.line ?? 0,\n\t\t\tfileUrlPath: prop.meta ? `${prop.meta.path.slice(`packages/${_package}/`.length)}/${prop.meta.file}` : '',\n\t\t};\n\t}\n\n\tprivate _mapParam(\n\t\tparam: DocgenParamJson,\n\t\tindex: number,\n\t\t_package: string,\n\t\tparamTokens: number[],\n\t): IApiParameterOptions {\n\t\treturn {\n\t\t\tparameterName: param.name.startsWith('...') ? param.name.slice(3) : param.name,\n\t\t\tisOptional: Boolean(param.optional),\n\t\t\tisRest: param.name.startsWith('...'),\n\t\t\tparameterTypeTokenRange: {\n\t\t\t\tstartIndex: 1 + index + paramTokens.slice(0, index).reduce((akk, num) => akk + num, 0),\n\t\t\t\tendIndex: 1 + index + paramTokens.slice(0, index + 1).reduce((akk, num) => akk + num, 0),\n\t\t\t},\n\t\t\tdefaultValue: param.default?.toString(),\n\t\t};\n\t}\n\n\tprivate _mapMethod(method: DocgenMethodJson, _package: string): IApiMethodOptions {\n\t\tconst excerptTokens: IExcerptToken[] = [];\n\t\texcerptTokens.push({\n\t\t\tkind: ExcerptTokenKind.Content,\n\t\t\ttext: `${\n\t\t\t\tmethod.scope === 'global'\n\t\t\t\t\t? `export function ${method.name}(`\n\t\t\t\t\t: `${method.access ? `${method.access} ` : ''}${method.scope === 'static' ? 'static ' : ''}${method.name}(`\n\t\t\t}${\n\t\t\t\tmethod.params?.length\n\t\t\t\t\t? `${method.params[0]!.name}${method.params[0]!.nullable || method.params[0]!.optional ? '?' : ''}: `\n\t\t\t\t\t: '): '\n\t\t\t}`,\n\t\t});\n\t\tconst paramTokens: number[] = [];\n\t\tfor (let index = 0; index < (method.params?.length ?? 0) - 1; index++) {\n\t\t\tconst newTokens = this._mapVarType(method.params![index]!.type);\n\t\t\tparamTokens.push(newTokens.length);\n\t\t\texcerptTokens.push(...newTokens);\n\t\t\texcerptTokens.push({\n\t\t\t\tkind: ExcerptTokenKind.Content,\n\t\t\t\ttext: `${method.params![index]!.default ? ` = ${method.params![index]!.default}` : ''}, ${method.params![index + 1]!.name}${\n\t\t\t\t\tmethod.params![index + 1]!.nullable || method.params![index + 1]!.optional ? '?' : ''\n\t\t\t\t}: `,\n\t\t\t});\n\t\t}\n\n\t\tif (method.params?.length) {\n\t\t\tconst newTokens = this._mapVarType(method.params[method.params.length - 1]!.type);\n\t\t\tparamTokens.push(newTokens.length);\n\t\t\texcerptTokens.push(...newTokens);\n\t\t\texcerptTokens.push({\n\t\t\t\tkind: ExcerptTokenKind.Content,\n\t\t\t\ttext: `${method.params![method.params.length - 1]!.default ? ` = ${method.params![method.params.length - 1]!.default}` : ''}): `,\n\t\t\t});\n\t\t}\n\n\t\tconst returnTokens = this._mapVarType(method.returns?.[0] ?? []);\n\t\texcerptTokens.push(...returnTokens);\n\n\t\texcerptTokens.push({ kind: ExcerptTokenKind.Content, text: ';' });\n\n\t\treturn {\n\t\t\tname: method.name,\n\t\t\tisAbstract: Boolean(method.abstract),\n\t\t\tisOptional: false,\n\t\t\tisProtected: method.access === 'protected',\n\t\t\tisStatic: method.scope === 'static',\n\t\t\toverloadIndex: 1,\n\t\t\tparameters: method.params?.map((param, index) => this._mapParam(param, index, _package, paramTokens)) ?? [],\n\t\t\treleaseTag: method.access === 'private' ? ReleaseTag.Internal : ReleaseTag.Public,\n\t\t\treturnTypeTokenRange: method.returns?.length\n\t\t\t\t? { startIndex: excerptTokens.length - 1 - returnTokens.length, endIndex: excerptTokens.length - 1 }\n\t\t\t\t: { startIndex: 0, endIndex: 0 },\n\t\t\ttypeParameters: [],\n\t\t\tdocComment: this._tsDocParser.parseString(\n\t\t\t\t`/**\\n * ${this._fixLinkTags(method.description) ?? ''}\\n${\n\t\t\t\t\tmethod.params\n\t\t\t\t\t\t?.map((param) => ` * @param ${param.name} - ${this._fixLinkTags(param.description) ?? ''}\\n`)\n\t\t\t\t\t\t.join('') ?? ''\n\t\t\t\t}${\n\t\t\t\t\tmethod.returns?.length && !Array.isArray(method.returns[0]) && method.returns[0]!.description\n\t\t\t\t\t\t? ` * @returns ${this._fixLinkTags(method.returns[0]!.description) ?? ''}`\n\t\t\t\t\t\t: ''\n\t\t\t\t}${method.examples?.map((example) => ` * @example\\n * \\`\\`\\`js\\n * ${example}\\n * \\`\\`\\`\\n`).join('') ?? ''}${\n\t\t\t\t\tmethod.deprecated\n\t\t\t\t\t\t? ` * @deprecated ${typeof method.deprecated === 'boolean' ? 'yes' : method.deprecated}\\n`\n\t\t\t\t\t\t: ''\n\t\t\t\t} */`,\n\t\t\t).docComment,\n\t\t\texcerptTokens,\n\t\t\tfileLine: method.meta.line,\n\t\t\tfileUrlPath: `${method.meta.path.slice(`packages/${_package}/`.length)}/${method.meta.file}`,\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/generators/ApiReportGenerator.ts",
    "content": "/* eslint-disable no-case-declarations */\n/* eslint-disable @typescript-eslint/require-array-sort-compare */\n// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { ReleaseTag, releaseTagGetTagName } from '@discordjs/api-extractor-model';\nimport { Text, InternalError } from '@rushstack/node-core-library';\nimport * as ts from 'typescript';\nimport { AstDeclaration } from '../analyzer/AstDeclaration.js';\nimport type { AstEntity } from '../analyzer/AstEntity.js';\nimport { AstImport } from '../analyzer/AstImport.js';\nimport type { IAstModuleExportInfo } from '../analyzer/AstModule.js';\nimport { AstNamespaceImport } from '../analyzer/AstNamespaceImport.js';\nimport { AstSymbol } from '../analyzer/AstSymbol.js';\nimport { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter.js';\nimport { Span } from '../analyzer/Span.js';\nimport { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers.js';\nimport type { ExtractorMessage } from '../api/ExtractorMessage.js';\nimport { ExtractorMessageId } from '../api/ExtractorMessageId.js';\nimport type { ApiReportVariant } from '../api/IConfigFile';\nimport type { ApiItemMetadata } from '../collector/ApiItemMetadata.js';\nimport { Collector } from '../collector/Collector.js';\nimport type { CollectorEntity } from '../collector/CollectorEntity.js';\nimport type { SymbolMetadata } from '../collector/SymbolMetadata';\nimport { DtsEmitHelpers } from './DtsEmitHelpers.js';\nimport { IndentedWriter } from './IndentedWriter.js';\n\nfunction capitalizeFirstLetter(input: string): string {\n\treturn input === '' ? '' : `${input[0]!.toLocaleUpperCase()}${input.slice(1)}`;\n}\n\nexport class ApiReportGenerator {\n\tprivate static _trimSpacesRegExp: RegExp = / +$/gm;\n\n\t/**\n\t * Compares the contents of two API files that were created using ApiFileGenerator,\n\t * and returns true if they are equivalent.  Note that these files are not normally edited\n\t * by a human; the \"equivalence\" comparison here is intended to ignore spurious changes that\n\t * might be introduced by a tool, e.g. Git newline normalization or an editor that strips\n\t * whitespace when saving.\n\t */\n\tpublic static areEquivalentApiFileContents(actualFileContent: string, expectedFileContent: string): boolean {\n\t\t// NOTE: \"\\s\" also matches \"\\r\" and \"\\n\"\n\t\tconst normalizedActual: string = actualFileContent.replaceAll(/\\s+/g, ' ');\n\t\tconst normalizedExpected: string = expectedFileContent.replaceAll(/\\s+/g, ' ');\n\t\treturn normalizedActual === normalizedExpected;\n\t}\n\n\t/**\n\t * Generates and returns the API report contents as a string.\n\t *\n\t * @param collector - The collector that has the entities.\n\t * @param reportVariant - The release level with which the report is associated.\n\t * Can also be viewed as the minimal release level of items that should be included in the report.\n\t */\n\tpublic static generateReviewFileContent(collector: Collector, reportVariant: ApiReportVariant): Map<string, string> {\n\t\t// mapping from entrypoint name to its file content\n\t\tconst fileContentMap: Map<string, string> = new Map<string, string>();\n\n\t\tfor (const [entryPoint, entryPointEntities] of collector.entities) {\n\t\t\tconst writer: IndentedWriter = new IndentedWriter();\n\t\t\twriter.trimLeadingSpaces = true;\n\n\t\t\t// For backwards compatibility, don't emit \"complete\" in report text for untrimmed reports.\n\t\t\tconst releaseLevelPrefix: string = reportVariant === 'complete' ? '' : `${capitalizeFirstLetter(reportVariant)} `;\n\t\t\twriter.writeLine(\n\t\t\t\t[\n\t\t\t\t\t`## ${releaseLevelPrefix}API Report File for \"${collector.workingPackage.name}${entryPoint.modulePath ? '/' : ''}${\n\t\t\t\t\t\tentryPoint.modulePath\n\t\t\t\t\t}\"`,\n\t\t\t\t\t``,\n\t\t\t\t\t`> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).`,\n\t\t\t\t\t``,\n\t\t\t\t].join('\\n'),\n\t\t\t);\n\n\t\t\t// Write the opening delimiter for the Markdown code fence\n\t\t\twriter.writeLine('```ts\\n');\n\n\t\t\t// Emit the triple slash directives\n\t\t\tfor (const typeDirectiveReference of Array.from(collector.dtsTypeReferenceDirectives).sort()) {\n\t\t\t\t// https://github.com/microsoft/TypeScript/blob/611ebc7aadd7a44a4c0447698bfda9222a78cb66/src/compiler/declarationEmitter.ts#L162\n\t\t\t\twriter.writeLine(`/// <reference types=\"${typeDirectiveReference}\" />`);\n\t\t\t}\n\n\t\t\tfor (const libDirectiveReference of Array.from(collector.dtsLibReferenceDirectives).sort()) {\n\t\t\t\twriter.writeLine(`/// <reference lib=\"${libDirectiveReference}\" />`);\n\t\t\t}\n\n\t\t\twriter.ensureSkippedLine();\n\n\t\t\t// Emit the imports\n\t\t\tfor (const entity of entryPointEntities) {\n\t\t\t\tif (entity.astEntity instanceof AstImport) {\n\t\t\t\t\tDtsEmitHelpers.emitImport(writer, entity, entity.astEntity);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\twriter.ensureSkippedLine();\n\n\t\t\t// Emit the regular declarations\n\t\t\tfor (const entity of entryPointEntities) {\n\t\t\t\tconst astEntity: AstEntity = entity.astEntity;\n\t\t\t\tconst symbolMetadata: SymbolMetadata | undefined = collector.tryFetchMetadataForAstEntity(astEntity);\n\t\t\t\tconst maxEffectiveReleaseTag: ReleaseTag = symbolMetadata?.maxEffectiveReleaseTag ?? ReleaseTag.None;\n\n\t\t\t\tif (!this._shouldIncludeReleaseTag(maxEffectiveReleaseTag, reportVariant)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (entity.consumable || collector.extractorConfig.apiReportIncludeForgottenExports) {\n\t\t\t\t\t// First, collect the list of export names for this symbol.  When reporting messages with\n\t\t\t\t\t// ExtractorMessage.properties.exportName, this will enable us to emit the warning comments alongside\n\t\t\t\t\t// the associated export statement.\n\t\t\t\t\tinterface IExportToEmit {\n\t\t\t\t\t\treadonly associatedMessages: ExtractorMessage[];\n\t\t\t\t\t\treadonly exportName: string;\n\t\t\t\t\t}\n\t\t\t\t\tconst exportsToEmit: Map<string, IExportToEmit> = new Map<string, IExportToEmit>();\n\n\t\t\t\t\tfor (const exportName of entity.exportNames) {\n\t\t\t\t\t\tif (!entity.shouldInlineExport) {\n\t\t\t\t\t\t\texportsToEmit.set(exportName, { exportName, associatedMessages: [] });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (astEntity instanceof AstSymbol) {\n\t\t\t\t\t\t// Emit all the declarations for this entity\n\t\t\t\t\t\tfor (const astDeclaration of astEntity.astDeclarations || []) {\n\t\t\t\t\t\t\t// Get the messages associated with this declaration\n\t\t\t\t\t\t\tconst fetchedMessages: ExtractorMessage[] =\n\t\t\t\t\t\t\t\tcollector.messageRouter.fetchAssociatedMessagesForReviewFile(astDeclaration);\n\n\t\t\t\t\t\t\t// Peel off the messages associated with an export statement and store them\n\t\t\t\t\t\t\t// in IExportToEmit.associatedMessages (to be processed later).  The remaining messages will\n\t\t\t\t\t\t\t// added to messagesToReport, to be emitted next to the declaration instead of the export statement.\n\t\t\t\t\t\t\tconst messagesToReport: ExtractorMessage[] = [];\n\t\t\t\t\t\t\tfor (const message of fetchedMessages) {\n\t\t\t\t\t\t\t\tif (message.properties.exportName) {\n\t\t\t\t\t\t\t\t\tconst exportToEmit: IExportToEmit | undefined = exportsToEmit.get(message.properties.exportName);\n\t\t\t\t\t\t\t\t\tif (exportToEmit) {\n\t\t\t\t\t\t\t\t\t\texportToEmit.associatedMessages.push(message);\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tmessagesToReport.push(message);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (this._shouldIncludeDeclaration(collector, astDeclaration, reportVariant)) {\n\t\t\t\t\t\t\t\twriter.ensureSkippedLine();\n\t\t\t\t\t\t\t\twriter.write(ApiReportGenerator._getAedocSynopsis(collector, astDeclaration, messagesToReport));\n\n\t\t\t\t\t\t\t\tconst span: Span = new Span(astDeclaration.declaration);\n\n\t\t\t\t\t\t\t\tconst apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration);\n\t\t\t\t\t\t\t\tif (apiItemMetadata.isPreapproved) {\n\t\t\t\t\t\t\t\t\tApiReportGenerator._modifySpanForPreapproved(span);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tApiReportGenerator._modifySpan(collector, span, entity, astDeclaration, false, reportVariant);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tspan.writeModifiedText(writer);\n\t\t\t\t\t\t\t\twriter.ensureNewLine();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (astEntity instanceof AstNamespaceImport) {\n\t\t\t\t\t\tconst astModuleExportInfo: IAstModuleExportInfo = astEntity.fetchAstModuleExportInfo(collector);\n\n\t\t\t\t\t\tif (entity.nameForEmit === undefined) {\n\t\t\t\t\t\t\t// This should never happen\n\t\t\t\t\t\t\tthrow new InternalError('referencedEntry.nameForEmit is undefined');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (astModuleExportInfo.starExportedExternalModules.size > 0) {\n\t\t\t\t\t\t\t// We could support this, but we would need to find a way to safely represent it.\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`The ${entity.nameForEmit} namespace import includes a star export, which is not supported:\\n` +\n\t\t\t\t\t\t\t\t\tSourceFileLocationFormatter.formatDeclaration(astEntity.declaration),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Emit a synthetic declaration for the namespace.  It will look like this:\n\t\t\t\t\t\t//\n\t\t\t\t\t\t//    declare namespace example {\n\t\t\t\t\t\t//      export {\n\t\t\t\t\t\t//        f1,\n\t\t\t\t\t\t//        f2\n\t\t\t\t\t\t//      }\n\t\t\t\t\t\t//    }\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// Note that we do not try to relocate f1()/f2() to be inside the namespace because other type\n\t\t\t\t\t\t// signatures may reference them directly (without using the namespace qualifier).\n\n\t\t\t\t\t\twriter.ensureSkippedLine();\n\t\t\t\t\t\twriter.writeLine(`declare namespace ${entity.nameForEmit} {`);\n\n\t\t\t\t\t\t// all local exports of local imported module are just references to top-level declarations\n\t\t\t\t\t\twriter.increaseIndent();\n\t\t\t\t\t\twriter.writeLine('export {');\n\t\t\t\t\t\twriter.increaseIndent();\n\n\t\t\t\t\t\tconst exportClauses: string[] = [];\n\t\t\t\t\t\tfor (const [exportedName, exportedEntity] of astModuleExportInfo.exportedLocalEntities) {\n\t\t\t\t\t\t\tconst collectorEntity: CollectorEntity | undefined = collector.tryGetCollectorEntity(exportedEntity);\n\t\t\t\t\t\t\tif (collectorEntity === undefined) {\n\t\t\t\t\t\t\t\t// This should never happen\n\t\t\t\t\t\t\t\t// top-level exports of local imported module should be added as collector entities before\n\t\t\t\t\t\t\t\tthrow new InternalError(\n\t\t\t\t\t\t\t\t\t`Cannot find collector entity for ${entity.nameForEmit}.${exportedEntity.localName}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (collectorEntity.nameForEmit === exportedName) {\n\t\t\t\t\t\t\t\texportClauses.push(collectorEntity.nameForEmit);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\texportClauses.push(`${collectorEntity.nameForEmit} as ${exportedName}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\twriter.writeLine(exportClauses.join(',\\n'));\n\n\t\t\t\t\t\twriter.decreaseIndent();\n\t\t\t\t\t\twriter.writeLine('}'); // end of \"export { ... }\"\n\t\t\t\t\t\twriter.decreaseIndent();\n\t\t\t\t\t\twriter.writeLine('}'); // end of \"declare namespace { ... }\"\n\t\t\t\t\t}\n\n\t\t\t\t\t// Now emit the export statements for this entity.\n\t\t\t\t\tfor (const exportToEmit of exportsToEmit.values()) {\n\t\t\t\t\t\t// Write any associated messages\n\t\t\t\t\t\tif (exportToEmit.associatedMessages.length > 0) {\n\t\t\t\t\t\t\twriter.ensureSkippedLine();\n\t\t\t\t\t\t\tfor (const message of exportToEmit.associatedMessages) {\n\t\t\t\t\t\t\t\tApiReportGenerator._writeLineAsComments(writer, 'Warning: ' + message.formatMessageWithoutLocation());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tDtsEmitHelpers.emitNamedExport(writer, exportToEmit.exportName, entity);\n\t\t\t\t\t}\n\n\t\t\t\t\twriter.ensureSkippedLine();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tDtsEmitHelpers.emitStarExports(writer, collector);\n\n\t\t\t// Write the unassociated warnings at the bottom of the file\n\t\t\tconst unassociatedMessages: ExtractorMessage[] = collector.messageRouter.fetchUnassociatedMessagesForReviewFile();\n\t\t\tif (unassociatedMessages.length > 0) {\n\t\t\t\twriter.ensureSkippedLine();\n\t\t\t\tApiReportGenerator._writeLineAsComments(writer, 'Warnings were encountered during analysis:');\n\t\t\t\tApiReportGenerator._writeLineAsComments(writer, '');\n\t\t\t\tfor (const unassociatedMessage of unassociatedMessages) {\n\t\t\t\t\tApiReportGenerator._writeLineAsComments(\n\t\t\t\t\t\twriter,\n\t\t\t\t\t\tunassociatedMessage.formatMessageWithLocation(collector.workingPackage.packageFolder),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (collector.workingPackage.tsdocComment === undefined) {\n\t\t\t\twriter.ensureSkippedLine();\n\t\t\t\tApiReportGenerator._writeLineAsComments(writer, '(No @packageDocumentation comment for this package)');\n\t\t\t}\n\n\t\t\t// Write the closing delimiter for the Markdown code fence\n\t\t\twriter.ensureSkippedLine();\n\t\t\twriter.writeLine('```');\n\n\t\t\t// Remove any trailing spaces\n\t\t\tfileContentMap.set(entryPoint.modulePath, writer.toString().replace(ApiReportGenerator._trimSpacesRegExp, ''));\n\t\t}\n\n\t\treturn fileContentMap;\n\t}\n\n\t/**\n\t * Before writing out a declaration, _modifySpan() applies various fixups to make it nice.\n\t */\n\tprivate static _modifySpan(\n\t\tcollector: Collector,\n\t\tspan: Span,\n\t\tentity: CollectorEntity,\n\t\tastDeclaration: AstDeclaration,\n\t\tinsideTypeLiteral: boolean,\n\t\treportVariant: ApiReportVariant,\n\t): void {\n\t\t// Should we process this declaration at all?\n\n\t\tif (!ApiReportGenerator._shouldIncludeDeclaration(collector, astDeclaration, reportVariant)) {\n\t\t\tspan.modification.skipAll();\n\t\t\treturn;\n\t\t}\n\n\t\tconst previousSpan: Span | undefined = span.previousSibling;\n\n\t\tlet recurseChildren = true;\n\t\tlet sortChildren = false;\n\n\t\tswitch (span.kind) {\n\t\t\tcase ts.SyntaxKind.JSDocComment:\n\t\t\t\tspan.modification.skipAll();\n\t\t\t\t// For now, we don't transform JSDoc comment nodes at all\n\t\t\t\trecurseChildren = false;\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.ExportKeyword:\n\t\t\tcase ts.SyntaxKind.DefaultKeyword:\n\t\t\tcase ts.SyntaxKind.DeclareKeyword:\n\t\t\t\t// Delete any explicit \"export\" or \"declare\" keywords -- we will re-add them below\n\t\t\t\tspan.modification.skipAll();\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.InterfaceKeyword:\n\t\t\tcase ts.SyntaxKind.ClassKeyword:\n\t\t\tcase ts.SyntaxKind.EnumKeyword:\n\t\t\tcase ts.SyntaxKind.NamespaceKeyword:\n\t\t\tcase ts.SyntaxKind.ModuleKeyword:\n\t\t\tcase ts.SyntaxKind.TypeKeyword:\n\t\t\tcase ts.SyntaxKind.FunctionKeyword:\n\t\t\t\t// Replace the stuff we possibly deleted above\n\t\t\t\tlet replacedModifiers = '';\n\n\t\t\t\tif (entity.shouldInlineExport) {\n\t\t\t\t\treplacedModifiers = 'export ' + replacedModifiers;\n\t\t\t\t}\n\n\t\t\t\tif (previousSpan?.kind === ts.SyntaxKind.SyntaxList) {\n\t\t\t\t\t// If there is a previous span of type SyntaxList, then apply it before any other modifiers\n\t\t\t\t\t// (e.g. \"abstract\") that appear there.\n\t\t\t\t\tpreviousSpan.modification.prefix = replacedModifiers + previousSpan.modification.prefix;\n\t\t\t\t} else {\n\t\t\t\t\t// Otherwise just stick it in front of this span\n\t\t\t\t\tspan.modification.prefix = replacedModifiers + span.modification.prefix;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.SyntaxList:\n\t\t\t\tif (\n\t\t\t\t\tspan.parent &&\n\t\t\t\t\t(AstDeclaration.isSupportedSyntaxKind(span.parent.kind) || span.parent.kind === ts.SyntaxKind.ModuleBlock)\n\t\t\t\t) {\n\t\t\t\t\t// If the immediate parent is an API declaration, and the immediate children are API declarations,\n\t\t\t\t\t// then sort the children alphabetically\n\t\t\t\t\t// Namespaces are special because their chain goes ModuleDeclaration -> ModuleBlock -> SyntaxList\n\t\t\t\t\tsortChildren = true;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.VariableDeclaration:\n\t\t\t\tif (!span.parent) {\n\t\t\t\t\t// The VariableDeclaration node is part of a VariableDeclarationList, however\n\t\t\t\t\t// the Entry.followedSymbol points to the VariableDeclaration part because\n\t\t\t\t\t// multiple definitions might share the same VariableDeclarationList.\n\t\t\t\t\t//\n\t\t\t\t\t// Since we are emitting a separate declaration for each one, we need to look upwards\n\t\t\t\t\t// in the ts.Node tree and write a copy of the enclosing VariableDeclarationList\n\t\t\t\t\t// content (e.g. \"var\" from \"var x=1, y=2\").\n\t\t\t\t\tconst list: ts.VariableDeclarationList | undefined = TypeScriptHelpers.matchAncestor(span.node, [\n\t\t\t\t\t\tts.SyntaxKind.VariableDeclarationList,\n\t\t\t\t\t\tts.SyntaxKind.VariableDeclaration,\n\t\t\t\t\t]);\n\t\t\t\t\tif (!list) {\n\t\t\t\t\t\t// This should not happen unless the compiler API changes somehow\n\t\t\t\t\t\tthrow new InternalError('Unsupported variable declaration');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst listPrefix: string = list.getSourceFile().text.slice(list.getStart(), list.declarations[0]!.getStart());\n\t\t\t\t\tspan.modification.prefix = listPrefix + span.modification.prefix;\n\t\t\t\t\tspan.modification.suffix = ';';\n\n\t\t\t\t\tif (entity.shouldInlineExport) {\n\t\t\t\t\t\tspan.modification.prefix = 'export ' + span.modification.prefix;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.Identifier:\n\t\t\t\tconst referencedEntity: CollectorEntity | undefined = collector.tryGetEntityForNode(span.node as ts.Identifier);\n\n\t\t\t\tif (referencedEntity) {\n\t\t\t\t\tif (!referencedEntity.nameForEmit) {\n\t\t\t\t\t\t// This should never happen\n\t\t\t\t\t\tthrow new InternalError('referencedEntry.nameForEmit is undefined');\n\t\t\t\t\t}\n\n\t\t\t\t\tspan.modification.prefix = referencedEntity.nameForEmit;\n\t\t\t\t\t// For debugging:\n\t\t\t\t\t// span.modification.prefix += '/*R=FIX*/';\n\t\t\t\t} else {\n\t\t\t\t\t// For debugging:\n\t\t\t\t\t// span.modification.prefix += '/*R=KEEP*/';\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.TypeLiteral:\n\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\tinsideTypeLiteral = true;\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.ImportType:\n\t\t\t\tDtsEmitHelpers.modifyImportTypeSpan(collector, span, astDeclaration, (childSpan, childAstDeclaration) => {\n\t\t\t\t\tApiReportGenerator._modifySpan(\n\t\t\t\t\t\tcollector,\n\t\t\t\t\t\tchildSpan,\n\t\t\t\t\t\tentity,\n\t\t\t\t\t\tchildAstDeclaration,\n\t\t\t\t\t\tinsideTypeLiteral,\n\t\t\t\t\t\treportVariant,\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (recurseChildren) {\n\t\t\tfor (const child of span.children) {\n\t\t\t\tlet childAstDeclaration: AstDeclaration = astDeclaration;\n\n\t\t\t\tif (AstDeclaration.isSupportedSyntaxKind(child.kind)) {\n\t\t\t\t\tchildAstDeclaration = collector.astSymbolTable.getChildAstDeclarationByNode(child.node, astDeclaration);\n\n\t\t\t\t\tif (sortChildren) {\n\t\t\t\t\t\tspan.modification.sortChildren = true;\n\t\t\t\t\t\tchild.modification.sortKey = Collector.getSortKeyIgnoringUnderscore(\n\t\t\t\t\t\t\tchildAstDeclaration.astSymbol.localName,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!insideTypeLiteral) {\n\t\t\t\t\t\tconst messagesToReport: ExtractorMessage[] =\n\t\t\t\t\t\t\tcollector.messageRouter.fetchAssociatedMessagesForReviewFile(childAstDeclaration);\n\t\t\t\t\t\tconst aedocSynopsis: string = ApiReportGenerator._getAedocSynopsis(\n\t\t\t\t\t\t\tcollector,\n\t\t\t\t\t\t\tchildAstDeclaration,\n\t\t\t\t\t\t\tmessagesToReport,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tchild.modification.prefix = aedocSynopsis + child.modification.prefix;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tApiReportGenerator._modifySpan(collector, child, entity, childAstDeclaration, insideTypeLiteral, reportVariant);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static _shouldIncludeDeclaration(\n\t\tcollector: Collector,\n\t\tastDeclaration: AstDeclaration,\n\t\treportVariant: ApiReportVariant,\n\t): boolean {\n\t\t// Private declarations are not included in the API report\n\t\tif ((astDeclaration.modifierFlags & ts.ModifierFlags.Private) !== 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration);\n\n\t\treturn this._shouldIncludeReleaseTag(apiItemMetadata.effectiveReleaseTag, reportVariant);\n\t}\n\n\tprivate static _shouldIncludeReleaseTag(releaseTag: ReleaseTag, reportVariant: ApiReportVariant): boolean {\n\t\tswitch (reportVariant) {\n\t\t\tcase 'complete':\n\t\t\t\treturn true;\n\t\t\tcase 'alpha':\n\t\t\t\treturn (\n\t\t\t\t\treleaseTag === ReleaseTag.Alpha ||\n\t\t\t\t\treleaseTag === ReleaseTag.Beta ||\n\t\t\t\t\treleaseTag === ReleaseTag.Public ||\n\t\t\t\t\t// NOTE: No specified release tag is implicitly treated as `@public`.\n\t\t\t\t\treleaseTag === ReleaseTag.None\n\t\t\t\t);\n\t\t\tcase 'beta':\n\t\t\t\treturn (\n\t\t\t\t\treleaseTag === ReleaseTag.Beta ||\n\t\t\t\t\treleaseTag === ReleaseTag.Public ||\n\t\t\t\t\t// NOTE: No specified release tag is implicitly treated as `@public`.\n\t\t\t\t\treleaseTag === ReleaseTag.None\n\t\t\t\t);\n\t\t\tcase 'public':\n\t\t\t\treturn (\n\t\t\t\t\treleaseTag === ReleaseTag.Public ||\n\t\t\t\t\t// NOTE: No specified release tag is implicitly treated as `@public`.\n\t\t\t\t\treleaseTag === ReleaseTag.None\n\t\t\t\t);\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unrecognized release level: ${reportVariant}`);\n\t\t}\n\t}\n\n\t/**\n\t * For declarations marked as `@preapproved`, this is used instead of _modifySpan().\n\t */\n\tprivate static _modifySpanForPreapproved(span: Span): void {\n\t\t// Match something like this:\n\t\t//\n\t\t//   ClassDeclaration:\n\t\t//     SyntaxList:\n\t\t//       ExportKeyword:  pre=[export] sep=[ ]\n\t\t//       DeclareKeyword:  pre=[declare] sep=[ ]\n\t\t//     ClassKeyword:  pre=[class] sep=[ ]\n\t\t//     Identifier:  pre=[_PreapprovedClass] sep=[ ]\n\t\t//     FirstPunctuation:  pre=[{] sep=[\\n\\n    ]\n\t\t//     SyntaxList:\n\t\t//       ...\n\t\t//     CloseBraceToken:  pre=[}]\n\t\t//\n\t\t// or this:\n\t\t//   ModuleDeclaration:\n\t\t//     SyntaxList:\n\t\t//       ExportKeyword:  pre=[export] sep=[ ]\n\t\t//       DeclareKeyword:  pre=[declare] sep=[ ]\n\t\t//     NamespaceKeyword:  pre=[namespace] sep=[ ]\n\t\t//     Identifier:  pre=[_PreapprovedNamespace] sep=[ ]\n\t\t//     ModuleBlock:\n\t\t//       FirstPunctuation:  pre=[{] sep=[\\n\\n    ]\n\t\t//       SyntaxList:\n\t\t//         ...\n\t\t//       CloseBraceToken:  pre=[}]\n\t\t//\n\t\t// And reduce it to something like this:\n\t\t//\n\t\t//   // @internal (undocumented)\n\t\t//   class _PreapprovedClass { /* (preapproved) */ }\n\t\t//\n\n\t\tlet skipRest = false;\n\t\tfor (const child of span.children) {\n\t\t\tif (skipRest || child.kind === ts.SyntaxKind.SyntaxList || child.kind === ts.SyntaxKind.JSDocComment) {\n\t\t\t\tchild.modification.skipAll();\n\t\t\t}\n\n\t\t\tif (child.kind === ts.SyntaxKind.Identifier) {\n\t\t\t\tskipRest = true;\n\t\t\t\tchild.modification.omitSeparatorAfter = true;\n\t\t\t\tchild.modification.suffix = ' { /* (preapproved) */ }';\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Writes a synopsis of the AEDoc comments, which indicates the release tag,\n\t * whether the item has been documented, and any warnings that were detected\n\t * by the analysis.\n\t */\n\tprivate static _getAedocSynopsis(\n\t\tcollector: Collector,\n\t\tastDeclaration: AstDeclaration,\n\t\tmessagesToReport: ExtractorMessage[],\n\t): string {\n\t\tconst writer: IndentedWriter = new IndentedWriter();\n\n\t\tfor (const message of messagesToReport) {\n\t\t\tApiReportGenerator._writeLineAsComments(writer, 'Warning: ' + message.formatMessageWithoutLocation());\n\t\t}\n\n\t\tif (!collector.isAncillaryDeclaration(astDeclaration)) {\n\t\t\tconst footerParts: string[] = [];\n\t\t\tconst apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration);\n\n\t\t\t// 1. Release tag (if present)\n\t\t\tif (!apiItemMetadata.releaseTagSameAsParent && apiItemMetadata.effectiveReleaseTag !== ReleaseTag.None) {\n\t\t\t\tfooterParts.push(releaseTagGetTagName(apiItemMetadata.effectiveReleaseTag));\n\t\t\t}\n\n\t\t\t// 2. Enumerate configured tags, reporting standard system tags first and then other configured tags.\n\t\t\t// Note that the ordering we handle the standard tags is important for backwards compatibility.\n\t\t\t// Also note that we had special mechanisms for checking whether or not an item is documented with these tags,\n\t\t\t// so they are checked specially.\n\t\t\tconst {\n\t\t\t\t'@sealed': reportSealedTag,\n\t\t\t\t'@virtual': reportVirtualTag,\n\t\t\t\t'@override': reportOverrideTag,\n\t\t\t\t'@eventProperty': reportEventPropertyTag,\n\t\t\t\t'@deprecated': reportDeprecatedTag,\n\t\t\t\t...otherTagsToReport\n\t\t\t} = collector.extractorConfig.tagsToReport;\n\n\t\t\t// 2.a Check for standard tags and report those that are both configured and present in the metadata.\n\t\t\tif (reportSealedTag && apiItemMetadata.isSealed) {\n\t\t\t\tfooterParts.push('@sealed');\n\t\t\t}\n\n\t\t\tif (reportVirtualTag && apiItemMetadata.isVirtual) {\n\t\t\t\tfooterParts.push('@virtual');\n\t\t\t}\n\n\t\t\tif (reportOverrideTag && apiItemMetadata.isOverride) {\n\t\t\t\tfooterParts.push('@override');\n\t\t\t}\n\n\t\t\tif (reportEventPropertyTag && apiItemMetadata.isEventProperty) {\n\t\t\t\tfooterParts.push('@eventProperty');\n\t\t\t}\n\n\t\t\tif (reportDeprecatedTag && apiItemMetadata.tsdocComment?.deprecatedBlock) {\n\t\t\t\tfooterParts.push('@deprecated');\n\t\t\t}\n\n\t\t\t// 2.b Check for other configured tags and report those that are present in the tsdoc metadata.\n\t\t\tfor (const [tag, reportTag] of Object.entries(otherTagsToReport)) {\n\t\t\t\t// If the tag was not handled specially, check if it is present in the metadata.\n\t\t\t\tif (\n\t\t\t\t\treportTag &&\n\t\t\t\t\t(apiItemMetadata.tsdocComment?.customBlocks.some((block) => block.blockTag.tagName === tag) ||\n\t\t\t\t\t\tapiItemMetadata.tsdocComment?.modifierTagSet.hasTagName(tag))\n\t\t\t\t) {\n\t\t\t\t\tfooterParts.push(tag);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 3. If the item is undocumented, append notice at the end of the list\n\t\t\tif (apiItemMetadata.undocumented) {\n\t\t\t\tfooterParts.push('(undocumented)');\n\n\t\t\t\tcollector.messageRouter.addAnalyzerIssue(\n\t\t\t\t\tExtractorMessageId.Undocumented,\n\t\t\t\t\t`Missing documentation for \"${astDeclaration.astSymbol.localName}\".`,\n\t\t\t\t\tastDeclaration,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (footerParts.length > 0) {\n\t\t\t\tif (messagesToReport.length > 0) {\n\t\t\t\t\tApiReportGenerator._writeLineAsComments(writer, ''); // skip a line after the warnings\n\t\t\t\t}\n\n\t\t\t\tApiReportGenerator._writeLineAsComments(writer, footerParts.join(' '));\n\t\t\t}\n\t\t}\n\n\t\treturn writer.toString();\n\t}\n\n\tprivate static _writeLineAsComments(writer: IndentedWriter, line: string): void {\n\t\tconst lines: string[] = Text.convertToLf(line).split('\\n');\n\t\tfor (const realLine of lines) {\n\t\t\twriter.write('// ');\n\t\t\twriter.write(realLine);\n\t\t\twriter.writeLine();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/generators/DeclarationReferenceGenerator.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { dirname } from 'node:path';\nimport { Navigation, Meaning } from '@discordjs/api-extractor-model';\nimport {\n\tDeclarationReference,\n\tModuleSource,\n\tGlobalSource,\n} from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { type INodePackageJson, InternalError } from '@rushstack/node-core-library';\nimport * as ts from 'typescript';\nimport { AstNamespaceImport } from '../analyzer/AstNamespaceImport.js';\nimport { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers.js';\nimport { TypeScriptInternals } from '../analyzer/TypeScriptInternals.js';\nimport type { Collector } from '../collector/Collector.js';\nimport type { CollectorEntity } from '../collector/CollectorEntity.js';\nimport type { IWorkingPackageEntryPoint } from '../collector/WorkingPackage.js';\n\nexport class DeclarationReferenceGenerator {\n\tpublic static readonly unknownReference: string = '?';\n\n\tprivate readonly _collector: Collector;\n\n\tpublic constructor(collector: Collector) {\n\t\tthis._collector = collector;\n\t}\n\n\t/**\n\t * Gets the UID for a TypeScript Identifier that references a type.\n\t */\n\tpublic getDeclarationReferenceForIdentifier(\n\t\tnode: ts.Identifier,\n\t\tentryPoint: IWorkingPackageEntryPoint,\n\t): DeclarationReference | undefined {\n\t\tconst symbol: ts.Symbol | undefined = this._collector.typeChecker.getSymbolAtLocation(node);\n\t\tif (symbol !== undefined) {\n\t\t\tconst isExpression: boolean = DeclarationReferenceGenerator._isInExpressionContext(node);\n\t\t\treturn (\n\t\t\t\tthis.getDeclarationReferenceForSymbol(\n\t\t\t\t\tsymbol,\n\t\t\t\t\tisExpression ? ts.SymbolFlags.Value : ts.SymbolFlags.Type,\n\t\t\t\t\tentryPoint,\n\t\t\t\t) ??\n\t\t\t\tthis.getDeclarationReferenceForSymbol(\n\t\t\t\t\tsymbol,\n\t\t\t\t\tisExpression ? ts.SymbolFlags.Type : ts.SymbolFlags.Value,\n\t\t\t\t\tentryPoint,\n\t\t\t\t) ??\n\t\t\t\tthis.getDeclarationReferenceForSymbol(symbol, ts.SymbolFlags.Namespace, entryPoint)\n\t\t\t);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Gets the DeclarationReference for a TypeScript Symbol for a given meaning.\n\t */\n\tpublic getDeclarationReferenceForSymbol(\n\t\tsymbol: ts.Symbol,\n\t\tmeaning: ts.SymbolFlags,\n\t\tentryPoint: IWorkingPackageEntryPoint,\n\t): DeclarationReference | undefined {\n\t\treturn this._symbolToDeclarationReference(symbol, meaning, /* includeModuleSymbols*/ false, entryPoint);\n\t}\n\n\tprivate static _isInExpressionContext(node: ts.Node): boolean {\n\t\tswitch (node.parent.kind) {\n\t\t\tcase ts.SyntaxKind.TypeQuery:\n\t\t\tcase ts.SyntaxKind.ComputedPropertyName:\n\t\t\t\treturn true;\n\t\t\tcase ts.SyntaxKind.QualifiedName:\n\t\t\t\treturn DeclarationReferenceGenerator._isInExpressionContext(node.parent);\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate static _isExternalModuleSymbol(symbol: ts.Symbol): boolean {\n\t\treturn (\n\t\t\tBoolean(symbol.flags & ts.SymbolFlags.ValueModule) &&\n\t\t\tsymbol.valueDeclaration !== undefined &&\n\t\t\tts.isSourceFile(symbol.valueDeclaration)\n\t\t);\n\t}\n\n\tprivate static _isSameSymbol(left: ts.Symbol | undefined, right: ts.Symbol): boolean {\n\t\treturn (\n\t\t\tleft === right ||\n\t\t\tBoolean(left?.valueDeclaration && right.valueDeclaration && left.valueDeclaration === right.valueDeclaration)\n\t\t);\n\t}\n\n\tprivate _getNavigationToSymbol(symbol: ts.Symbol): Navigation {\n\t\tconst declaration: ts.Declaration | undefined = TypeScriptHelpers.tryGetADeclaration(symbol);\n\t\tconst sourceFile: ts.SourceFile | undefined = declaration?.getSourceFile();\n\t\tconst parent: ts.Symbol | undefined = TypeScriptInternals.getSymbolParent(symbol);\n\n\t\t// If it's global or from an external library, then use either Members or Exports. It's not possible for\n\t\t// global symbols or external library symbols to be Locals.\n\t\tconst isGlobal: boolean = Boolean(sourceFile) && !ts.isExternalModule(sourceFile!);\n\t\tconst isFromExternalLibrary: boolean =\n\t\t\tBoolean(sourceFile) && this._collector.program.isSourceFileFromExternalLibrary(sourceFile!);\n\t\tif (isGlobal || isFromExternalLibrary) {\n\t\t\tif (\n\t\t\t\tparent?.members &&\n\t\t\t\tDeclarationReferenceGenerator._isSameSymbol(parent.members.get(symbol.escapedName), symbol)\n\t\t\t) {\n\t\t\t\treturn Navigation.Members;\n\t\t\t}\n\n\t\t\treturn Navigation.Exports;\n\t\t}\n\n\t\t// Otherwise, this symbol is from the current package. If we've found an associated consumable\n\t\t// `CollectorEntity`, then use Exports. We use `consumable` here instead of `exported` because\n\t\t// if the symbol is exported from a non-consumable `AstNamespaceImport`, we don't want to use\n\t\t// Exports. We should use Locals instead.\n\t\tconst entity: CollectorEntity | undefined = this._collector.tryGetEntityForSymbol(symbol);\n\t\tif (entity?.consumable) {\n\t\t\treturn Navigation.Exports;\n\t\t}\n\n\t\t// If its parent symbol is not a source file, then use either Exports or Members. If the parent symbol\n\t\t// is a source file, but it wasn't exported from the package entry point (in the check above), then the\n\t\t// symbol is a local, so fall through below.\n\t\tif (parent && !DeclarationReferenceGenerator._isExternalModuleSymbol(parent)) {\n\t\t\tif (\n\t\t\t\tparent.members &&\n\t\t\t\tDeclarationReferenceGenerator._isSameSymbol(parent.members.get(symbol.escapedName), symbol)\n\t\t\t) {\n\t\t\t\treturn Navigation.Members;\n\t\t\t}\n\n\t\t\treturn Navigation.Exports;\n\t\t}\n\n\t\t// Otherwise, we have a local symbol, so use a Locals navigation. These are either:\n\t\t//\n\t\t// 1. Symbols that are exported from a file module but not the package entry point.\n\t\t// 2. Symbols that are not exported from their parent module.\n\t\treturn Navigation.Locals;\n\t}\n\n\tprivate static _getMeaningOfSymbol(symbol: ts.Symbol, meaning: ts.SymbolFlags): Meaning | undefined {\n\t\tif (symbol.flags & meaning & ts.SymbolFlags.Class) {\n\t\t\treturn Meaning.Class;\n\t\t}\n\n\t\tif (symbol.flags & meaning & ts.SymbolFlags.Enum) {\n\t\t\treturn Meaning.Enum;\n\t\t}\n\n\t\tif (symbol.flags & meaning & ts.SymbolFlags.Interface) {\n\t\t\treturn Meaning.Interface;\n\t\t}\n\n\t\tif (symbol.flags & meaning & ts.SymbolFlags.TypeAlias) {\n\t\t\treturn Meaning.TypeAlias;\n\t\t}\n\n\t\tif (symbol.flags & meaning & ts.SymbolFlags.Function) {\n\t\t\treturn Meaning.Function;\n\t\t}\n\n\t\tif (symbol.flags & meaning & ts.SymbolFlags.Variable) {\n\t\t\treturn Meaning.Variable;\n\t\t}\n\n\t\tif (symbol.flags & meaning & ts.SymbolFlags.Module) {\n\t\t\treturn Meaning.Namespace;\n\t\t}\n\n\t\tif (symbol.flags & meaning & ts.SymbolFlags.ClassMember) {\n\t\t\treturn Meaning.Member;\n\t\t}\n\n\t\tif (symbol.flags & meaning & ts.SymbolFlags.Constructor) {\n\t\t\treturn Meaning.Constructor;\n\t\t}\n\n\t\tif (symbol.flags & meaning & ts.SymbolFlags.EnumMember) {\n\t\t\treturn Meaning.Member;\n\t\t}\n\n\t\tif (symbol.flags & meaning & ts.SymbolFlags.Signature) {\n\t\t\tif (symbol.escapedName === ts.InternalSymbolName.Call) {\n\t\t\t\treturn Meaning.CallSignature;\n\t\t\t}\n\n\t\t\tif (symbol.escapedName === ts.InternalSymbolName.New) {\n\t\t\t\treturn Meaning.ConstructSignature;\n\t\t\t}\n\n\t\t\tif (symbol.escapedName === ts.InternalSymbolName.Index) {\n\t\t\t\treturn Meaning.IndexSignature;\n\t\t\t}\n\t\t}\n\n\t\tif (symbol.flags & meaning & ts.SymbolFlags.TypeParameter) {\n\t\t\t// This should have already been handled in `getDeclarationReferenceOfSymbol`.\n\t\t\tthrow new InternalError('Not supported.');\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate _symbolToDeclarationReference(\n\t\tsymbol: ts.Symbol,\n\t\tmeaning: ts.SymbolFlags,\n\t\tincludeModuleSymbols: boolean,\n\t\tentryPoint: IWorkingPackageEntryPoint,\n\t): DeclarationReference | undefined {\n\t\tconst declaration: ts.Node | undefined = TypeScriptHelpers.tryGetADeclaration(symbol);\n\t\tconst sourceFile: ts.SourceFile | undefined = declaration?.getSourceFile();\n\n\t\tlet followedSymbol: ts.Symbol = symbol;\n\t\tif (followedSymbol.flags & ts.SymbolFlags.ExportValue) {\n\t\t\tfollowedSymbol = this._collector.typeChecker.getExportSymbolOfSymbol(followedSymbol);\n\t\t}\n\n\t\tif (followedSymbol.flags & ts.SymbolFlags.Alias) {\n\t\t\tfollowedSymbol = this._collector.typeChecker.getAliasedSymbol(followedSymbol);\n\n\t\t\t// Without this logic, we end up following the symbol `ns` in `import * as ns from './file'` to\n\t\t\t// the actual file `file.ts`. We don't want to do this, so revert to the original symbol.\n\t\t\tif (followedSymbol.flags & ts.SymbolFlags.ValueModule) {\n\t\t\t\tfollowedSymbol = symbol;\n\t\t\t}\n\t\t}\n\n\t\tif (DeclarationReferenceGenerator._isExternalModuleSymbol(followedSymbol)) {\n\t\t\tif (!includeModuleSymbols) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\treturn new DeclarationReference(this._sourceFileToModuleSource(sourceFile, entryPoint));\n\t\t}\n\n\t\t// Do not generate a declaration reference for a type parameter.\n\t\tif (followedSymbol.flags & ts.SymbolFlags.TypeParameter) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tlet parentRef: DeclarationReference | undefined = this._getParentReference(followedSymbol, entryPoint);\n\t\tif (!parentRef) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tlet localName: string = followedSymbol.name;\n\t\tconst entity: CollectorEntity | undefined = this._collector.tryGetEntityForSymbol(followedSymbol);\n\t\tif (entity?.nameForEmit) {\n\t\t\tlocalName = entity.nameForEmit;\n\t\t}\n\n\t\tif (followedSymbol.escapedName === ts.InternalSymbolName.Constructor) {\n\t\t\tlocalName = 'constructor';\n\t\t} else {\n\t\t\tconst wellKnownName: string | undefined = TypeScriptHelpers.tryDecodeWellKnownSymbolName(\n\t\t\t\tfollowedSymbol.escapedName,\n\t\t\t);\n\t\t\tif (wellKnownName) {\n\t\t\t\t// TypeScript binds well-known ECMAScript symbols like 'Symbol.iterator' as '__@iterator'.\n\t\t\t\t// This converts a string like '__@iterator' into the property name '[Symbol.iterator]'.\n\t\t\t\tlocalName = wellKnownName;\n\t\t\t} else if (TypeScriptHelpers.isUniqueSymbolName(followedSymbol.escapedName)) {\n\t\t\t\tfor (const decl of followedSymbol.declarations ?? []) {\n\t\t\t\t\tconst declName: ts.DeclarationName | undefined = ts.getNameOfDeclaration(decl);\n\t\t\t\t\tif (declName && ts.isComputedPropertyName(declName)) {\n\t\t\t\t\t\tconst lateName: string | undefined = TypeScriptHelpers.tryGetLateBoundName(declName);\n\t\t\t\t\t\tif (lateName !== undefined) {\n\t\t\t\t\t\t\tlocalName = lateName;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst navigation: Navigation = this._getNavigationToSymbol(followedSymbol);\n\n\t\t// If the symbol is a global, ensure the source is global.\n\t\tif (sourceFile && !ts.isExternalModule(sourceFile) && parentRef.source !== GlobalSource.instance) {\n\t\t\tparentRef = new DeclarationReference(GlobalSource.instance);\n\t\t}\n\n\t\treturn parentRef\n\t\t\t.addNavigationStep(navigation as any, localName)\n\t\t\t.withMeaning(DeclarationReferenceGenerator._getMeaningOfSymbol(followedSymbol, meaning) as any);\n\t}\n\n\tprivate _getParentReference(\n\t\tsymbol: ts.Symbol,\n\t\tentryPoint: IWorkingPackageEntryPoint,\n\t): DeclarationReference | undefined {\n\t\tconst declaration: ts.Node | undefined = TypeScriptHelpers.tryGetADeclaration(symbol);\n\t\tconst sourceFile: ts.SourceFile | undefined = declaration?.getSourceFile();\n\n\t\t// Note that it's possible for a symbol to be exported from an entry point as well as one or more\n\t\t// namespaces. In that case, it's not clear what to choose as its parent. Today's logic is neither\n\t\t// perfect nor particularly stable to API items being renamed and shuffled around.\n\t\tconst entity: CollectorEntity | undefined = this._collector.tryGetEntityForSymbol(symbol);\n\t\tif (entity) {\n\t\t\tif (entity.exportedFromEntryPoint) {\n\t\t\t\treturn new DeclarationReference(this._sourceFileToModuleSource(sourceFile, entryPoint));\n\t\t\t}\n\n\t\t\tconst firstExportingConsumableParent: CollectorEntity | undefined = entity.getFirstExportingConsumableParent();\n\t\t\tif (firstExportingConsumableParent && firstExportingConsumableParent.astEntity instanceof AstNamespaceImport) {\n\t\t\t\tconst parentSymbol: ts.Symbol | undefined = TypeScriptInternals.tryGetSymbolForDeclaration(\n\t\t\t\t\tfirstExportingConsumableParent.astEntity.declaration,\n\t\t\t\t\tthis._collector.typeChecker,\n\t\t\t\t);\n\t\t\t\tif (parentSymbol) {\n\t\t\t\t\treturn this._symbolToDeclarationReference(\n\t\t\t\t\t\tparentSymbol,\n\t\t\t\t\t\tparentSymbol.flags,\n\t\t\t\t\t\t/* includeModuleSymbols*/ true,\n\t\t\t\t\t\tentryPoint,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Next, try to find a parent symbol via the symbol tree.\n\t\tconst parentSymbol: ts.Symbol | undefined = TypeScriptInternals.getSymbolParent(symbol);\n\t\tif (parentSymbol) {\n\t\t\treturn this._symbolToDeclarationReference(\n\t\t\t\tparentSymbol,\n\t\t\t\tparentSymbol.flags,\n\t\t\t\t/* includeModuleSymbols*/ true,\n\t\t\t\tentryPoint,\n\t\t\t);\n\t\t}\n\n\t\t// If that doesn't work, try to find a parent symbol via the node tree. As far as we can tell,\n\t\t// this logic is only needed for local symbols within namespaces. For example:\n\t\t//\n\t\t// ```\n\t\t// export namespace n {\n\t\t//   type SomeType = number;\n\t\t//   export function someFunction(): SomeType { return 5; }\n\t\t// }\n\t\t// ```\n\t\t//\n\t\t// In the example above, `SomeType` doesn't have a parent symbol per the TS internal API above,\n\t\t// but its reference still needs to be qualified with the parent reference for `n`.\n\t\tconst grandParent: ts.Node | undefined = declaration?.parent?.parent;\n\t\tif (grandParent && ts.isModuleDeclaration(grandParent)) {\n\t\t\tconst grandParentSymbol: ts.Symbol | undefined = TypeScriptInternals.tryGetSymbolForDeclaration(\n\t\t\t\tgrandParent,\n\t\t\t\tthis._collector.typeChecker,\n\t\t\t);\n\t\t\tif (grandParentSymbol) {\n\t\t\t\treturn this._symbolToDeclarationReference(\n\t\t\t\t\tgrandParentSymbol,\n\t\t\t\t\tgrandParentSymbol.flags,\n\t\t\t\t\t/* includeModuleSymbols*/ true,\n\t\t\t\t\tentryPoint,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// At this point, we have a local symbol in a module.\n\t\tif (sourceFile && ts.isExternalModule(sourceFile)) {\n\t\t\treturn new DeclarationReference(this._sourceFileToModuleSource(sourceFile, entryPoint));\n\t\t} else {\n\t\t\treturn new DeclarationReference(GlobalSource.instance);\n\t\t}\n\t}\n\n\tprivate _getEntryPointName(sourceFile: ts.SourceFile, entry: IWorkingPackageEntryPoint): string {\n\t\tif (this._collector.program.isSourceFileFromExternalLibrary(sourceFile)) {\n\t\t\tconst packageJson: INodePackageJson | undefined = this._collector.packageJsonLookup.tryLoadNodePackageJsonFor(\n\t\t\t\tsourceFile.fileName,\n\t\t\t);\n\n\t\t\tif (packageJson?.name) {\n\t\t\t\tif (packageJson?.exports && !Array.isArray(packageJson.exports) && typeof packageJson.exports !== 'string') {\n\t\t\t\t\tconst entryPoint = Object.keys(packageJson.exports).find((path) =>\n\t\t\t\t\t\tdirname(sourceFile.fileName).endsWith(path.slice(1)),\n\t\t\t\t\t);\n\n\t\t\t\t\tif (entryPoint && packageJson.exports[entryPoint]) {\n\t\t\t\t\t\treturn `${packageJson.name}${entryPoint.slice(1)}`;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn packageJson.name;\n\t\t\t}\n\n\t\t\treturn DeclarationReferenceGenerator.unknownReference;\n\t\t}\n\n\t\tconst modulePath = entry.modulePath;\n\n\t\treturn `${this._collector.workingPackage.name}${modulePath ? `/${modulePath}` : ''}`;\n\t}\n\n\tprivate _sourceFileToModuleSource(\n\t\tsourceFile: ts.SourceFile | undefined,\n\t\tentryPoint: IWorkingPackageEntryPoint,\n\t): GlobalSource | ModuleSource {\n\t\tif (sourceFile && ts.isExternalModule(sourceFile)) {\n\t\t\tconst packageName: string = this._getEntryPointName(sourceFile, entryPoint);\n\n\t\t\tif (this._collector.bundledPackageNames.has(packageName)) {\n\t\t\t\t// The api-extractor.json config file has a \"bundledPackages\" setting, which causes imports from\n\t\t\t\t// certain NPM packages to be treated as part of the working project.  In this case, we need to\n\t\t\t\t// substitute the working package name.\n\t\t\t\treturn new ModuleSource(this._collector.workingPackage.name); // TODO: make it work with multiple entrypoints\n\t\t\t} else {\n\t\t\t\treturn new ModuleSource(packageName);\n\t\t\t}\n\t\t}\n\n\t\treturn GlobalSource.instance;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/generators/DtsEmitHelpers.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError } from '@rushstack/node-core-library';\nimport * as ts from 'typescript';\nimport { AstDeclaration } from '../analyzer/AstDeclaration.js';\nimport { AstImport, AstImportKind } from '../analyzer/AstImport.js';\nimport { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter.js';\nimport type { Span } from '../analyzer/Span.js';\nimport type { Collector } from '../collector/Collector.js';\nimport type { CollectorEntity } from '../collector/CollectorEntity.js';\nimport type { IndentedWriter } from './IndentedWriter.js';\n\n/**\n * Some common code shared between DtsRollupGenerator and ApiReportGenerator.\n */\nexport class DtsEmitHelpers {\n\tpublic static emitImport(writer: IndentedWriter, collectorEntity: CollectorEntity, astImport: AstImport): void {\n\t\tconst importPrefix: string = astImport.isTypeOnlyEverywhere ? 'import type' : 'import';\n\n\t\tswitch (astImport.importKind) {\n\t\t\tcase AstImportKind.DefaultImport:\n\t\t\t\tif (collectorEntity.nameForEmit === astImport.exportName) {\n\t\t\t\t\twriter.write(`${importPrefix} ${astImport.exportName}`);\n\t\t\t\t} else {\n\t\t\t\t\twriter.write(`${importPrefix} { default as ${collectorEntity.nameForEmit} }`);\n\t\t\t\t}\n\n\t\t\t\twriter.writeLine(` from '${astImport.modulePath}';`);\n\t\t\t\tbreak;\n\t\t\tcase AstImportKind.NamedImport:\n\t\t\t\tif (collectorEntity.nameForEmit === astImport.exportName) {\n\t\t\t\t\twriter.write(`${importPrefix} { ${astImport.exportName} }`);\n\t\t\t\t} else {\n\t\t\t\t\twriter.write(`${importPrefix} { ${astImport.exportName} as ${collectorEntity.nameForEmit} }`);\n\t\t\t\t}\n\n\t\t\t\twriter.writeLine(` from '${astImport.modulePath}';`);\n\t\t\t\tbreak;\n\t\t\tcase AstImportKind.StarImport:\n\t\t\t\twriter.writeLine(`${importPrefix} * as ${collectorEntity.nameForEmit} from '${astImport.modulePath}';`);\n\t\t\t\tbreak;\n\t\t\tcase AstImportKind.EqualsImport:\n\t\t\t\twriter.writeLine(`${importPrefix} ${collectorEntity.nameForEmit} = require('${astImport.modulePath}');`);\n\t\t\t\tbreak;\n\t\t\tcase AstImportKind.ImportType:\n\t\t\t\tif (astImport.exportName) {\n\t\t\t\t\tconst topExportName: string = astImport.exportName.split('.')[0]!;\n\t\t\t\t\tif (collectorEntity.nameForEmit === topExportName) {\n\t\t\t\t\t\twriter.write(`${importPrefix} { ${topExportName} }`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\twriter.write(`${importPrefix} { ${topExportName} as ${collectorEntity.nameForEmit} }`);\n\t\t\t\t\t}\n\n\t\t\t\t\twriter.writeLine(` from '${astImport.modulePath}';`);\n\t\t\t\t} else {\n\t\t\t\t\twriter.writeLine(`${importPrefix} * as ${collectorEntity.nameForEmit} from '${astImport.modulePath}';`);\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new InternalError('Unimplemented AstImportKind');\n\t\t}\n\t}\n\n\tpublic static emitNamedExport(writer: IndentedWriter, exportName: string, collectorEntity: CollectorEntity): void {\n\t\tif (exportName === ts.InternalSymbolName.Default) {\n\t\t\twriter.writeLine(`export default ${collectorEntity.nameForEmit};`);\n\t\t} else if (collectorEntity.nameForEmit === exportName) {\n\t\t\twriter.writeLine(`export { ${exportName} }`);\n\t\t} else {\n\t\t\twriter.writeLine(`export { ${collectorEntity.nameForEmit} as ${exportName} }`);\n\t\t}\n\t}\n\n\tpublic static emitStarExports(writer: IndentedWriter, collector: Collector): void {\n\t\tif (collector.starExportedExternalModulePaths.length > 0) {\n\t\t\twriter.writeLine();\n\t\t\tfor (const starExportedExternalModulePath of collector.starExportedExternalModulePaths) {\n\t\t\t\twriter.writeLine(`export * from \"${starExportedExternalModulePath}\";`);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static modifyImportTypeSpan(\n\t\tcollector: Collector,\n\t\tspan: Span,\n\t\tastDeclaration: AstDeclaration,\n\t\tmodifyNestedSpan: (childSpan: Span, childAstDeclaration: AstDeclaration) => void,\n\t): void {\n\t\tconst node: ts.ImportTypeNode = span.node as ts.ImportTypeNode;\n\t\tconst referencedEntity: CollectorEntity | undefined = collector.tryGetEntityForNode(node);\n\n\t\tif (referencedEntity) {\n\t\t\tif (!referencedEntity.nameForEmit) {\n\t\t\t\t// This should never happen\n\n\t\t\t\tthrow new InternalError('referencedEntry.nameForEmit is undefined');\n\t\t\t}\n\n\t\t\tlet typeArgumentsText = '';\n\n\t\t\tif (node.typeArguments && node.typeArguments.length > 0) {\n\t\t\t\t// Type arguments have to be processed and written to the document\n\t\t\t\tconst lessThanTokenPos: number = span.children.findIndex(\n\t\t\t\t\t(childSpan) => childSpan.node.kind === ts.SyntaxKind.LessThanToken,\n\t\t\t\t);\n\t\t\t\tconst greaterThanTokenPos: number = span.children.findIndex(\n\t\t\t\t\t(childSpan) => childSpan.node.kind === ts.SyntaxKind.GreaterThanToken,\n\t\t\t\t);\n\n\t\t\t\tif (lessThanTokenPos < 0 || greaterThanTokenPos <= lessThanTokenPos) {\n\t\t\t\t\tthrow new InternalError(\n\t\t\t\t\t\t`Invalid type arguments: ${node.getText()}\\n` + SourceFileLocationFormatter.formatDeclaration(node),\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst typeArgumentsSpans: Span[] = span.children.slice(lessThanTokenPos + 1, greaterThanTokenPos);\n\n\t\t\t\t// Apply modifications to Span elements of typeArguments\n\t\t\t\tfor (const childSpan of typeArgumentsSpans) {\n\t\t\t\t\tconst childAstDeclaration: AstDeclaration = AstDeclaration.isSupportedSyntaxKind(childSpan.kind)\n\t\t\t\t\t\t? collector.astSymbolTable.getChildAstDeclarationByNode(childSpan.node, astDeclaration)\n\t\t\t\t\t\t: astDeclaration;\n\n\t\t\t\t\tmodifyNestedSpan(childSpan, childAstDeclaration);\n\t\t\t\t}\n\n\t\t\t\tconst typeArgumentsStrings: string[] = typeArgumentsSpans.map((childSpan) => childSpan.getModifiedText());\n\t\t\t\ttypeArgumentsText = `<${typeArgumentsStrings.join(', ')}>`;\n\t\t\t}\n\n\t\t\tconst separatorAfter: string = /(?<separator>\\s*)$/.exec(span.getText())?.groups?.separator ?? '';\n\n\t\t\tif (\n\t\t\t\treferencedEntity.astEntity instanceof AstImport &&\n\t\t\t\treferencedEntity.astEntity.importKind === AstImportKind.ImportType &&\n\t\t\t\treferencedEntity.astEntity.exportName\n\t\t\t) {\n\t\t\t\t// For an ImportType with a namespace chain, only the top namespace is imported.\n\t\t\t\t// Must add the original nested qualifiers to the rolled up import.\n\t\t\t\tconst qualifiersText: string = node.qualifier?.getText() ?? '';\n\t\t\t\tconst nestedQualifiersStart: number = qualifiersText.indexOf('.');\n\t\t\t\t// Including the leading \".\"\n\t\t\t\tconst nestedQualifiersText: string =\n\t\t\t\t\tnestedQualifiersStart >= 0 ? qualifiersText.slice(Math.max(0, nestedQualifiersStart)) : '';\n\n\t\t\t\tconst replacement = `${referencedEntity.nameForEmit}${nestedQualifiersText}${typeArgumentsText}${separatorAfter}`;\n\n\t\t\t\tspan.modification.skipAll();\n\t\t\t\tspan.modification.prefix = replacement;\n\t\t\t} else {\n\t\t\t\t// Replace with internal symbol or AstImport\n\t\t\t\tspan.modification.skipAll();\n\t\t\t\tspan.modification.prefix = `${referencedEntity.nameForEmit}${typeArgumentsText}${separatorAfter}`;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/generators/DtsRollupGenerator.ts",
    "content": "/* eslint-disable no-case-declarations */\n// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { ReleaseTag } from '@discordjs/api-extractor-model';\nimport { FileSystem, type NewlineKind, InternalError } from '@rushstack/node-core-library';\nimport * as ts from 'typescript';\nimport { AstDeclaration } from '../analyzer/AstDeclaration.js';\nimport type { AstEntity } from '../analyzer/AstEntity.js';\nimport { AstImport } from '../analyzer/AstImport.js';\nimport type { IAstModuleExportInfo } from '../analyzer/AstModule.js';\nimport { AstNamespaceImport } from '../analyzer/AstNamespaceImport.js';\nimport { AstSymbol } from '../analyzer/AstSymbol.js';\nimport { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter.js';\nimport { IndentDocCommentScope, Span, type SpanModification } from '../analyzer/Span.js';\nimport { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers.js';\nimport type { ApiItemMetadata } from '../collector/ApiItemMetadata.js';\nimport type { Collector } from '../collector/Collector.js';\nimport type { CollectorEntity } from '../collector/CollectorEntity.js';\nimport type { DeclarationMetadata } from '../collector/DeclarationMetadata.js';\nimport type { SymbolMetadata } from '../collector/SymbolMetadata.js';\nimport { DtsEmitHelpers } from './DtsEmitHelpers.js';\nimport { IndentedWriter } from './IndentedWriter.js';\n\n/**\n * Used with DtsRollupGenerator.writeTypingsFile()\n */\nexport enum DtsRollupKind {\n\t/**\n\t * Generate a *.d.ts file for an internal release, or for the trimming=false mode.\n\t * This output file will contain all definitions that are reachable from the entry point.\n\t */\n\tInternalRelease,\n\n\t/**\n\t * Generate a *.d.ts file for a preview release.\n\t * This output file will contain all definitions that are reachable from the entry point,\n\t * except definitions marked as \\@internal.\n\t */\n\tAlphaRelease,\n\n\t/**\n\t * Generate a *.d.ts file for a preview release.\n\t * This output file will contain all definitions that are reachable from the entry point,\n\t * except definitions marked as \\@alpha or \\@internal.\n\t */\n\tBetaRelease,\n\n\t/**\n\t * Generate a *.d.ts file for a public release.\n\t * This output file will contain all definitions that are reachable from the entry point,\n\t * except definitions marked as \\@beta, \\@alpha, or \\@internal.\n\t */\n\tPublicRelease,\n}\n\nexport class DtsRollupGenerator {\n\t/**\n\t * Generates the typings file and writes it to disk.\n\t *\n\t * @param collector - The Collector\n\t * @param dtsFilename    - The *.d.ts output filename\n\t */\n\tpublic static writeTypingsFile(\n\t\tcollector: Collector,\n\t\tdtsFilename: string,\n\t\tdtsKind: DtsRollupKind,\n\t\tnewlineKind: NewlineKind,\n\t): void {\n\t\tconst writer: IndentedWriter = new IndentedWriter();\n\t\twriter.trimLeadingSpaces = true;\n\n\t\tDtsRollupGenerator._generateTypingsFileContent(collector, writer, dtsKind);\n\n\t\tFileSystem.writeFile(dtsFilename, writer.toString(), {\n\t\t\tconvertLineEndings: newlineKind,\n\t\t\tensureFolderExists: true,\n\t\t});\n\t}\n\n\tprivate static _generateTypingsFileContent(\n\t\tcollector: Collector,\n\t\twriter: IndentedWriter,\n\t\tdtsKind: DtsRollupKind,\n\t): void {\n\t\t// Emit the @packageDocumentation comment at the top of the file\n\t\tif (collector.workingPackage.tsdocParserContext) {\n\t\t\twriter.trimLeadingSpaces = false;\n\t\t\twriter.writeLine(collector.workingPackage.tsdocParserContext.sourceRange.toString());\n\t\t\twriter.trimLeadingSpaces = true;\n\t\t\twriter.ensureSkippedLine();\n\t\t}\n\n\t\t// Emit the triple slash directives\n\t\tfor (const typeDirectiveReference of collector.dtsTypeReferenceDirectives) {\n\t\t\t// https://github.com/microsoft/TypeScript/blob/611ebc7aadd7a44a4c0447698bfda9222a78cb66/src/compiler/declarationEmitter.ts#L162\n\t\t\twriter.writeLine(`/// <reference types=\"${typeDirectiveReference}\" />`);\n\t\t}\n\n\t\tfor (const libDirectiveReference of collector.dtsLibReferenceDirectives) {\n\t\t\twriter.writeLine(`/// <reference lib=\"${libDirectiveReference}\" />`);\n\t\t}\n\n\t\twriter.ensureSkippedLine();\n\n\t\t// dtsRollup doesn't support multiple entry points. We throw error if dtsRollup is enabled while more than one entry points are specified.\n\t\t// So at this point, we can safely assume there is only one entry point in collector.entities\n\t\t// Emit the imports\n\t\tfor (const entity of [...collector.entities.values()][0]!) {\n\t\t\tif (entity.astEntity instanceof AstImport) {\n\t\t\t\tconst astImport: AstImport = entity.astEntity;\n\n\t\t\t\t// For example, if the imported API comes from an external package that supports AEDoc,\n\t\t\t\t// and it was marked as `@internal`, then don't emit it.\n\t\t\t\tconst symbolMetadata: SymbolMetadata | undefined = collector.tryFetchMetadataForAstEntity(astImport);\n\t\t\t\tconst maxEffectiveReleaseTag: ReleaseTag = symbolMetadata\n\t\t\t\t\t? symbolMetadata.maxEffectiveReleaseTag\n\t\t\t\t\t: ReleaseTag.None;\n\n\t\t\t\tif (this._shouldIncludeReleaseTag(maxEffectiveReleaseTag, dtsKind)) {\n\t\t\t\t\tDtsEmitHelpers.emitImport(writer, entity, astImport);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\twriter.ensureSkippedLine();\n\n\t\t// Emit the regular declarations\n\t\tfor (const entity of [...collector.entities.values()][0]!) {\n\t\t\tconst astEntity: AstEntity = entity.astEntity;\n\t\t\tconst symbolMetadata: SymbolMetadata | undefined = collector.tryFetchMetadataForAstEntity(astEntity);\n\t\t\tconst maxEffectiveReleaseTag: ReleaseTag = symbolMetadata\n\t\t\t\t? symbolMetadata.maxEffectiveReleaseTag\n\t\t\t\t: ReleaseTag.None;\n\n\t\t\tif (!this._shouldIncludeReleaseTag(maxEffectiveReleaseTag, dtsKind)) {\n\t\t\t\tif (!collector.extractorConfig.omitTrimmingComments) {\n\t\t\t\t\twriter.ensureSkippedLine();\n\t\t\t\t\twriter.writeLine(`/* Excluded from this release type: ${entity.nameForEmit} */`);\n\t\t\t\t}\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (astEntity instanceof AstSymbol) {\n\t\t\t\t// Emit all the declarations for this entry\n\t\t\t\tfor (const astDeclaration of astEntity.astDeclarations || []) {\n\t\t\t\t\tconst apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration);\n\n\t\t\t\t\tif (this._shouldIncludeReleaseTag(apiItemMetadata.effectiveReleaseTag, dtsKind)) {\n\t\t\t\t\t\tconst span: Span = new Span(astDeclaration.declaration);\n\t\t\t\t\t\tDtsRollupGenerator._modifySpan(collector, span, entity, astDeclaration, dtsKind);\n\t\t\t\t\t\twriter.ensureSkippedLine();\n\t\t\t\t\t\tspan.writeModifiedText(writer);\n\t\t\t\t\t\twriter.ensureNewLine();\n\t\t\t\t\t} else if (!collector.extractorConfig.omitTrimmingComments) {\n\t\t\t\t\t\twriter.ensureSkippedLine();\n\t\t\t\t\t\twriter.writeLine(`/* Excluded declaration from this release type: ${entity.nameForEmit} */`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (astEntity instanceof AstNamespaceImport) {\n\t\t\t\tconst astModuleExportInfo: IAstModuleExportInfo = astEntity.fetchAstModuleExportInfo(collector);\n\n\t\t\t\tif (entity.nameForEmit === undefined) {\n\t\t\t\t\t// This should never happen\n\t\t\t\t\tthrow new InternalError('referencedEntry.nameForEmit is undefined');\n\t\t\t\t}\n\n\t\t\t\tif (astModuleExportInfo.starExportedExternalModules.size > 0) {\n\t\t\t\t\t// We could support this, but we would need to find a way to safely represent it.\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`The ${entity.nameForEmit} namespace import includes a start export, which is not supported:\\n` +\n\t\t\t\t\t\t\tSourceFileLocationFormatter.formatDeclaration(astEntity.declaration),\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Emit a synthetic declaration for the namespace.  It will look like this:\n\t\t\t\t//\n\t\t\t\t//    declare namespace example {\n\t\t\t\t//      export {\n\t\t\t\t//        f1,\n\t\t\t\t//        f2\n\t\t\t\t//      }\n\t\t\t\t//    }\n\t\t\t\t//\n\t\t\t\t// Note that we do not try to relocate f1()/f2() to be inside the namespace because other type\n\t\t\t\t// signatures may reference them directly (without using the namespace qualifier).\n\n\t\t\t\twriter.ensureSkippedLine();\n\t\t\t\tif (entity.shouldInlineExport) {\n\t\t\t\t\twriter.write('export ');\n\t\t\t\t}\n\n\t\t\t\twriter.writeLine(`declare namespace ${entity.nameForEmit} {`);\n\n\t\t\t\t// all local exports of local imported module are just references to top-level declarations\n\t\t\t\twriter.increaseIndent();\n\t\t\t\twriter.writeLine('export {');\n\t\t\t\twriter.increaseIndent();\n\n\t\t\t\tconst exportClauses: string[] = [];\n\t\t\t\tfor (const [exportedName, exportedEntity] of astModuleExportInfo.exportedLocalEntities) {\n\t\t\t\t\tconst collectorEntity: CollectorEntity | undefined = collector.tryGetCollectorEntity(exportedEntity);\n\t\t\t\t\tif (collectorEntity === undefined) {\n\t\t\t\t\t\t// This should never happen\n\t\t\t\t\t\t// top-level exports of local imported module should be added as collector entities before\n\t\t\t\t\t\tthrow new InternalError(\n\t\t\t\t\t\t\t`Cannot find collector entity for ${entity.nameForEmit}.${exportedEntity.localName}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (collectorEntity.nameForEmit === exportedName) {\n\t\t\t\t\t\texportClauses.push(collectorEntity.nameForEmit);\n\t\t\t\t\t} else {\n\t\t\t\t\t\texportClauses.push(`${collectorEntity.nameForEmit} as ${exportedName}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\twriter.writeLine(exportClauses.join(',\\n'));\n\n\t\t\t\twriter.decreaseIndent();\n\t\t\t\twriter.writeLine('}'); // end of \"export { ... }\"\n\t\t\t\twriter.decreaseIndent();\n\t\t\t\twriter.writeLine('}'); // end of \"declare namespace { ... }\"\n\t\t\t}\n\n\t\t\tif (!entity.shouldInlineExport) {\n\t\t\t\tfor (const exportName of entity.exportNames) {\n\t\t\t\t\tDtsEmitHelpers.emitNamedExport(writer, exportName, entity);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\twriter.ensureSkippedLine();\n\t\t}\n\n\t\tDtsEmitHelpers.emitStarExports(writer, collector);\n\n\t\t// Emit \"export { }\" which is a special directive that prevents consumers from importing declarations\n\t\t// that don't have an explicit \"export\" modifier.\n\t\twriter.ensureSkippedLine();\n\t\twriter.writeLine('export { }');\n\t}\n\n\t/**\n\t * Before writing out a declaration, _modifySpan() applies various fixups to make it nice.\n\t */\n\tprivate static _modifySpan(\n\t\tcollector: Collector,\n\t\tspan: Span,\n\t\tentity: CollectorEntity,\n\t\tastDeclaration: AstDeclaration,\n\t\tdtsKind: DtsRollupKind,\n\t): void {\n\t\tconst previousSpan: Span | undefined = span.previousSibling;\n\n\t\tlet recurseChildren = true;\n\t\tswitch (span.kind) {\n\t\t\tcase ts.SyntaxKind.JSDocComment:\n\t\t\t\t// If the @packageDocumentation comment seems to be attached to one of the regular API items,\n\t\t\t\t// omit it.  It gets explictly emitted at the top of the file.\n\t\t\t\tif (/[\\s*]@packagedocumentation[\\s*]/gi.test(span.node.getText())) {\n\t\t\t\t\tspan.modification.skipAll();\n\t\t\t\t}\n\n\t\t\t\t// For now, we don't transform JSDoc comment nodes at all\n\t\t\t\trecurseChildren = false;\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.ExportKeyword:\n\t\t\tcase ts.SyntaxKind.DefaultKeyword:\n\t\t\tcase ts.SyntaxKind.DeclareKeyword:\n\t\t\t\t// Delete any explicit \"export\" or \"declare\" keywords -- we will re-add them below\n\t\t\t\tspan.modification.skipAll();\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.InterfaceKeyword:\n\t\t\tcase ts.SyntaxKind.ClassKeyword:\n\t\t\tcase ts.SyntaxKind.EnumKeyword:\n\t\t\tcase ts.SyntaxKind.NamespaceKeyword:\n\t\t\tcase ts.SyntaxKind.ModuleKeyword:\n\t\t\tcase ts.SyntaxKind.TypeKeyword:\n\t\t\tcase ts.SyntaxKind.FunctionKeyword:\n\t\t\t\t// Replace the stuff we possibly deleted above\n\t\t\t\tlet replacedModifiers = '';\n\n\t\t\t\t// Add a declare statement for root declarations (but not for nested declarations)\n\t\t\t\tif (!astDeclaration.parent) {\n\t\t\t\t\treplacedModifiers += 'declare ';\n\t\t\t\t}\n\n\t\t\t\tif (entity.shouldInlineExport) {\n\t\t\t\t\treplacedModifiers = 'export ' + replacedModifiers;\n\t\t\t\t}\n\n\t\t\t\tif (previousSpan?.kind === ts.SyntaxKind.SyntaxList) {\n\t\t\t\t\t// If there is a previous span of type SyntaxList, then apply it before any other modifiers\n\t\t\t\t\t// (e.g. \"abstract\") that appear there.\n\t\t\t\t\tpreviousSpan.modification.prefix = replacedModifiers + previousSpan.modification.prefix;\n\t\t\t\t} else {\n\t\t\t\t\t// Otherwise just stick it in front of this span\n\t\t\t\t\tspan.modification.prefix = replacedModifiers + span.modification.prefix;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.VariableDeclaration:\n\t\t\t\t// Is this a top-level variable declaration?\n\t\t\t\t// (The logic below does not apply to variable declarations that are part of an explicit \"namespace\" block,\n\t\t\t\t// since the compiler prefers not to emit \"declare\" or \"export\" keywords for those declarations.)\n\t\t\t\tif (!span.parent) {\n\t\t\t\t\t// The VariableDeclaration node is part of a VariableDeclarationList, however\n\t\t\t\t\t// the Entry.followedSymbol points to the VariableDeclaration part because\n\t\t\t\t\t// multiple definitions might share the same VariableDeclarationList.\n\t\t\t\t\t//\n\t\t\t\t\t// Since we are emitting a separate declaration for each one, we need to look upwards\n\t\t\t\t\t// in the ts.Node tree and write a copy of the enclosing VariableDeclarationList\n\t\t\t\t\t// content (e.g. \"var\" from \"var x=1, y=2\").\n\t\t\t\t\tconst list: ts.VariableDeclarationList | undefined = TypeScriptHelpers.matchAncestor(span.node, [\n\t\t\t\t\t\tts.SyntaxKind.VariableDeclarationList,\n\t\t\t\t\t\tts.SyntaxKind.VariableDeclaration,\n\t\t\t\t\t]);\n\t\t\t\t\tif (!list) {\n\t\t\t\t\t\t// This should not happen unless the compiler API changes somehow\n\t\t\t\t\t\tthrow new InternalError('Unsupported variable declaration');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst listPrefix: string = list.getSourceFile().text.slice(list.getStart(), list.declarations[0]!.getStart());\n\t\t\t\t\tspan.modification.prefix = 'declare ' + listPrefix + span.modification.prefix;\n\t\t\t\t\tspan.modification.suffix = ';';\n\n\t\t\t\t\tif (entity.shouldInlineExport) {\n\t\t\t\t\t\tspan.modification.prefix = 'export ' + span.modification.prefix;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst declarationMetadata: DeclarationMetadata = collector.fetchDeclarationMetadata(astDeclaration);\n\t\t\t\t\tif (declarationMetadata.tsdocParserContext) {\n\t\t\t\t\t\t// Typically the comment for a variable declaration is attached to the outer variable statement\n\t\t\t\t\t\t// (which may possibly contain multiple variable declarations), so it's not part of the Span.\n\t\t\t\t\t\t// Instead we need to manually inject it.\n\t\t\t\t\t\tlet originalComment: string = declarationMetadata.tsdocParserContext.sourceRange.toString();\n\t\t\t\t\t\tif (!/\\r?\\n\\s*$/.test(originalComment)) {\n\t\t\t\t\t\t\toriginalComment += '\\n';\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tspan.modification.indentDocComment = IndentDocCommentScope.PrefixOnly;\n\t\t\t\t\t\tspan.modification.prefix = originalComment + span.modification.prefix;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.Identifier:\n\t\t\t\t{\n\t\t\t\t\tconst referencedEntity: CollectorEntity | undefined = collector.tryGetEntityForNode(\n\t\t\t\t\t\tspan.node as ts.Identifier,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (referencedEntity) {\n\t\t\t\t\t\tif (!referencedEntity.nameForEmit) {\n\t\t\t\t\t\t\t// This should never happen\n\t\t\t\t\t\t\tthrow new InternalError('referencedEntry.nameForEmit is undefined');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tspan.modification.prefix = referencedEntity.nameForEmit;\n\t\t\t\t\t\t// For debugging:\n\t\t\t\t\t\t// span.modification.prefix += '/*R=FIX*/';\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// For debugging:\n\t\t\t\t\t\t// span.modification.prefix += '/*R=KEEP*/';\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase ts.SyntaxKind.ImportType:\n\t\t\t\tDtsEmitHelpers.modifyImportTypeSpan(collector, span, astDeclaration, (childSpan, childAstDeclaration) => {\n\t\t\t\t\tDtsRollupGenerator._modifySpan(collector, childSpan, entity, childAstDeclaration, dtsKind);\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (recurseChildren) {\n\t\t\tfor (const child of span.children) {\n\t\t\t\tlet childAstDeclaration: AstDeclaration = astDeclaration;\n\n\t\t\t\t// Should we trim this node?\n\t\t\t\tlet trimmed = false;\n\t\t\t\tif (AstDeclaration.isSupportedSyntaxKind(child.kind)) {\n\t\t\t\t\tchildAstDeclaration = collector.astSymbolTable.getChildAstDeclarationByNode(child.node, astDeclaration);\n\t\t\t\t\tconst releaseTag: ReleaseTag = collector.fetchApiItemMetadata(childAstDeclaration).effectiveReleaseTag;\n\n\t\t\t\t\tif (!this._shouldIncludeReleaseTag(releaseTag, dtsKind)) {\n\t\t\t\t\t\tlet nodeToTrim: Span = child;\n\n\t\t\t\t\t\t// If we are trimming a variable statement, then we need to trim the outer VariableDeclarationList\n\t\t\t\t\t\t// as well.\n\t\t\t\t\t\tif (child.kind === ts.SyntaxKind.VariableDeclaration) {\n\t\t\t\t\t\t\tconst variableStatement: Span | undefined = child.findFirstParent(ts.SyntaxKind.VariableStatement);\n\t\t\t\t\t\t\tif (variableStatement !== undefined) {\n\t\t\t\t\t\t\t\tnodeToTrim = variableStatement;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst modification: SpanModification = nodeToTrim.modification;\n\n\t\t\t\t\t\t// Yes, trim it and stop here\n\t\t\t\t\t\tconst name: string = childAstDeclaration.astSymbol.localName;\n\t\t\t\t\t\tmodification.omitChildren = true;\n\n\t\t\t\t\t\tif (collector.extractorConfig.omitTrimmingComments) {\n\t\t\t\t\t\t\tmodification.prefix = '';\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmodification.prefix = `/* Excluded from this release type: ${name} */`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tmodification.suffix = '';\n\n\t\t\t\t\t\tif (nodeToTrim.children.length > 0) {\n\t\t\t\t\t\t\t// If there are grandchildren, then keep the last grandchild's separator,\n\t\t\t\t\t\t\t// since it often has useful whitespace\n\t\t\t\t\t\t\tmodification.suffix = nodeToTrim.children[nodeToTrim.children.length - 1]!.separator;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// If the thing we are trimming is followed by a comma, then trim the comma also.\n\t\t\t\t\t\t// An example would be an enum member.\n\t\t\t\t\t\tif (nodeToTrim.nextSibling?.kind === ts.SyntaxKind.CommaToken) {\n\t\t\t\t\t\t\t// Keep its separator since it often has useful whitespace\n\t\t\t\t\t\t\tmodification.suffix += nodeToTrim.nextSibling.separator;\n\t\t\t\t\t\t\tnodeToTrim.nextSibling.modification.skipAll();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttrimmed = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!trimmed) {\n\t\t\t\t\tDtsRollupGenerator._modifySpan(collector, child, entity, childAstDeclaration, dtsKind);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static _shouldIncludeReleaseTag(releaseTag: ReleaseTag, dtsKind: DtsRollupKind): boolean {\n\t\tswitch (dtsKind) {\n\t\t\tcase DtsRollupKind.InternalRelease:\n\t\t\t\treturn true;\n\t\t\tcase DtsRollupKind.AlphaRelease:\n\t\t\t\treturn (\n\t\t\t\t\treleaseTag === ReleaseTag.Alpha ||\n\t\t\t\t\treleaseTag === ReleaseTag.Beta ||\n\t\t\t\t\treleaseTag === ReleaseTag.Public ||\n\t\t\t\t\t// NOTE: If the release tag is \"None\", then we don't have enough information to trim it\n\t\t\t\t\treleaseTag === ReleaseTag.None\n\t\t\t\t);\n\t\t\tcase DtsRollupKind.BetaRelease:\n\t\t\t\treturn (\n\t\t\t\t\treleaseTag === ReleaseTag.Beta ||\n\t\t\t\t\treleaseTag === ReleaseTag.Public ||\n\t\t\t\t\t// NOTE: If the release tag is \"None\", then we don't have enough information to trim it\n\t\t\t\t\treleaseTag === ReleaseTag.None\n\t\t\t\t);\n\t\t\tcase DtsRollupKind.PublicRelease:\n\t\t\t\treturn releaseTag === ReleaseTag.Public || releaseTag === ReleaseTag.None;\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`${DtsRollupKind[dtsKind]} is not implemented`);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/generators/ExcerptBuilder.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport {\n\tExcerptTokenKind,\n\ttype IExcerptToken,\n\ttype IExcerptTokenRange,\n\ttype IExcerptTokenRangeWithTypeParameters,\n} from '@discordjs/api-extractor-model';\nimport type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference';\nimport * as ts from 'typescript';\nimport type { AstDeclaration } from '../analyzer/AstDeclaration.js';\nimport { Span } from '../analyzer/Span.js';\nimport type { IWorkingPackageEntryPoint } from '../collector/WorkingPackage.js';\nimport type { DeclarationReferenceGenerator } from './DeclarationReferenceGenerator.js';\n\n/**\n * Used to provide ExcerptBuilder with a list of nodes whose token range we want to capture.\n */\nexport interface IExcerptBuilderNodeToCapture {\n\t/**\n\t * The node to capture\n\t */\n\tnode: ts.Node | undefined;\n\t/**\n\t * The token range whose startIndex/endIndex will be overwritten with the indexes for the\n\t * tokens corresponding to IExcerptBuilderNodeToCapture.node\n\t */\n\ttokenRange: IExcerptTokenRange;\n}\n\n/**\n * Internal state for ExcerptBuilder\n */\ninterface IBuildSpanState {\n\tentryPoint: IWorkingPackageEntryPoint;\n\n\t/**\n\t * Tracks whether the last appended token was a separator. If so, and we're in the middle of\n\t * capturing a token range, then omit the separator from the range.\n\t */\n\tlastAppendedTokenIsSeparator: boolean;\n\n\treferenceGenerator: DeclarationReferenceGenerator;\n\n\t/**\n\t * The AST node that we will traverse to extract tokens\n\t */\n\tstartingNode: ts.Node;\n\n\t/**\n\t * Normally, the excerpt will include all child nodes for `startingNode`; whereas if `childKindToStopBefore`\n\t * is specified, then the node traversal will stop before (i.e. excluding) the first immediate child\n\t * of `startingNode` with the specified syntax kind.\n\t *\n\t * @remarks\n\t * For example, suppose the signature is `interface X: Y { z: string }`.  The token `{` has syntax kind\n\t * `ts.SyntaxKind.FirstPunctuation`, so we can specify that to truncate the excerpt to `interface X: Y`.\n\t */\n\tstopBeforeChildKind: ts.SyntaxKind | undefined;\n\n\ttokenRangesByNode: Map<ts.Node, IExcerptTokenRange>;\n}\n\nexport class ExcerptBuilder {\n\t/**\n\t * Appends a blank line to the `excerptTokens` list.\n\t *\n\t * @param excerptTokens - The target token list to append to\n\t */\n\tpublic static addBlankLine(excerptTokens: IExcerptToken[]): void {\n\t\tlet newlines = '\\n\\n';\n\t\t// If the existing text already ended with a newline, then only append one newline\n\t\tif (excerptTokens.length > 0) {\n\t\t\tconst previousText: string = excerptTokens[excerptTokens.length - 1]!.text;\n\t\t\tif (previousText.endsWith('\\n')) {\n\t\t\t\tnewlines = '\\n';\n\t\t\t}\n\t\t}\n\n\t\texcerptTokens.push({ kind: ExcerptTokenKind.Content, text: newlines });\n\t}\n\n\t/**\n\t * Appends the signature for the specified `AstDeclaration` to the `excerptTokens` list.\n\t *\n\t * @param excerptTokens - The target token list to append to\n\t * @param astDeclaration - The declaration\n\t * @param nodesToCapture - A list of child nodes whose token ranges we want to capture\n\t */\n\tpublic static addDeclaration(\n\t\texcerptTokens: IExcerptToken[],\n\t\tastDeclaration: AstDeclaration,\n\t\tnodesToCapture: IExcerptBuilderNodeToCapture[],\n\t\treferenceGenerator: DeclarationReferenceGenerator,\n\t\tentryPoint: IWorkingPackageEntryPoint,\n\t): void {\n\t\tlet stopBeforeChildKind: ts.SyntaxKind | undefined;\n\n\t\tswitch (astDeclaration.declaration.kind) {\n\t\t\tcase ts.SyntaxKind.ClassDeclaration:\n\t\t\tcase ts.SyntaxKind.EnumDeclaration:\n\t\t\tcase ts.SyntaxKind.InterfaceDeclaration:\n\t\t\t\t// FirstPunctuation = \"{\"\n\t\t\t\tstopBeforeChildKind = ts.SyntaxKind.FirstPunctuation;\n\t\t\t\tbreak;\n\t\t\tcase ts.SyntaxKind.ModuleDeclaration:\n\t\t\t\t// ModuleBlock = the \"{ ... }\" block\n\t\t\t\tstopBeforeChildKind = ts.SyntaxKind.ModuleBlock;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\n\t\tconst span: Span = new Span(astDeclaration.declaration);\n\n\t\tconst tokenRangesByNode: Map<ts.Node, IExcerptTokenRange> = new Map<ts.Node, IExcerptTokenRange>();\n\t\tfor (const excerpt of nodesToCapture || []) {\n\t\t\tif (excerpt.node) {\n\t\t\t\ttokenRangesByNode.set(excerpt.node, excerpt.tokenRange);\n\t\t\t}\n\t\t}\n\n\t\tExcerptBuilder._buildSpan(excerptTokens, span, {\n\t\t\tentryPoint,\n\t\t\treferenceGenerator,\n\t\t\tstartingNode: span.node,\n\t\t\tstopBeforeChildKind,\n\t\t\ttokenRangesByNode,\n\t\t\tlastAppendedTokenIsSeparator: false,\n\t\t});\n\t\tExcerptBuilder._condenseTokens(excerptTokens, [...tokenRangesByNode.values()]);\n\t}\n\n\tpublic static createEmptyTokenRange(): IExcerptTokenRange {\n\t\treturn { startIndex: 0, endIndex: 0 };\n\t}\n\n\tpublic static createEmptyTokenRangeWithTypeParameters(): IExcerptTokenRangeWithTypeParameters {\n\t\treturn { startIndex: 0, endIndex: 0, typeParameters: [] };\n\t}\n\n\tprivate static _isPrimitiveKeyword(node: ts.Node): boolean {\n\t\tswitch (node.kind) {\n\t\t\tcase ts.SyntaxKind.AnyKeyword:\n\t\t\tcase ts.SyntaxKind.BigIntKeyword:\n\t\t\tcase ts.SyntaxKind.BooleanKeyword:\n\t\t\tcase ts.SyntaxKind.NeverKeyword:\n\t\t\tcase ts.SyntaxKind.NumberKeyword:\n\t\t\tcase ts.SyntaxKind.ObjectKeyword:\n\t\t\tcase ts.SyntaxKind.StringKeyword:\n\t\t\tcase ts.SyntaxKind.SymbolKeyword:\n\t\t\tcase ts.SyntaxKind.UnknownKeyword:\n\t\t\tcase ts.SyntaxKind.VoidKeyword:\n\t\t\tcase ts.SyntaxKind.TypeOfKeyword:\n\t\t\tcase ts.SyntaxKind.UndefinedKeyword:\n\t\t\tcase ts.SyntaxKind.NullKeyword:\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate static _isRedundantBarAfterColon(span: Span) {\n\t\treturn (\n\t\t\tspan.kind === ts.SyntaxKind.BarToken &&\n\t\t\tspan.previousSibling === undefined &&\n\t\t\t(span.parent?.parent?.previousSibling?.kind === ts.SyntaxKind.LessThanToken ||\n\t\t\t\tspan.parent?.parent?.previousSibling?.kind === ts.SyntaxKind.ColonToken)\n\t\t);\n\t}\n\n\tprivate static _buildSpan(excerptTokens: IExcerptToken[], span: Span, state: IBuildSpanState): boolean {\n\t\tif (span.kind === ts.SyntaxKind.JSDocComment) {\n\t\t\t// Discard any comments\n\t\t\treturn true;\n\t\t}\n\n\t\t// Can this node start a excerpt?\n\t\tconst capturedTokenRange: IExcerptTokenRange | undefined = state.tokenRangesByNode.get(span.node);\n\t\tlet excerptStartIndex = 0;\n\n\t\tif (capturedTokenRange) {\n\t\t\t// We will assign capturedTokenRange.startIndex to be the index of the next token to be appended\n\t\t\texcerptStartIndex = excerptTokens.length;\n\t\t}\n\n\t\tif (span.prefix) {\n\t\t\tlet canonicalReference: DeclarationReference | undefined;\n\n\t\t\tif (ts.isIdentifier(span.node)) {\n\t\t\t\tconst name: ts.Identifier = span.node;\n\t\t\t\tcanonicalReference = state.referenceGenerator.getDeclarationReferenceForIdentifier(name, state.entryPoint);\n\t\t\t}\n\n\t\t\tif (canonicalReference) {\n\t\t\t\tExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Reference, span.prefix, canonicalReference);\n\t\t\t} else if (\n\t\t\t\tExcerptBuilder._isPrimitiveKeyword(span.node) ||\n\t\t\t\t(ts.isIdentifier(span.node) &&\n\t\t\t\t\t((ts.isTypeReferenceNode(span.node.parent) && span.node.parent.typeName === span.node) ||\n\t\t\t\t\t\t(ts.isTypeParameterDeclaration(span.node.parent) && span.node.parent.name === span.node)))\n\t\t\t) {\n\t\t\t\tExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Reference, span.prefix);\n\t\t\t} else if (!ExcerptBuilder._isRedundantBarAfterColon(span)) {\n\t\t\t\tExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, span.prefix);\n\t\t\t}\n\n\t\t\tstate.lastAppendedTokenIsSeparator = false;\n\t\t}\n\n\t\tfor (const child of span.children) {\n\t\t\tif (span.node === state.startingNode && state.stopBeforeChildKind && child.kind === state.stopBeforeChildKind) {\n\t\t\t\t// We reached a child whose kind is stopBeforeChildKind, so stop traversing\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (!this._buildSpan(excerptTokens, child, state)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tif (span.suffix) {\n\t\t\tExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, span.suffix);\n\t\t\tstate.lastAppendedTokenIsSeparator = false;\n\t\t}\n\n\t\tif (span.separator) {\n\t\t\tExcerptBuilder._appendToken(\n\t\t\t\texcerptTokens,\n\t\t\t\tExcerptTokenKind.Content,\n\t\t\t\tspan.separator.replaceAll('\\n', '').replaceAll(/\\s{2}/g, ' '),\n\t\t\t);\n\t\t\tstate.lastAppendedTokenIsSeparator = true;\n\t\t}\n\n\t\t// Are we building a excerpt?  If so, set its range\n\t\tif (capturedTokenRange) {\n\t\t\tcapturedTokenRange.startIndex = excerptStartIndex;\n\n\t\t\t// We will assign capturedTokenRange.startIndex to be the index after the last token\n\t\t\t// that was appended so far. However, if the last appended token was a separator, omit\n\t\t\t// it from the range.\n\t\t\tlet excerptEndIndex: number = excerptTokens.length;\n\t\t\tif (state.lastAppendedTokenIsSeparator) {\n\t\t\t\texcerptEndIndex--;\n\t\t\t}\n\n\t\t\tcapturedTokenRange.endIndex = excerptEndIndex;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate static _appendToken(\n\t\texcerptTokens: IExcerptToken[],\n\t\texcerptTokenKind: ExcerptTokenKind,\n\t\ttext: string,\n\t\tcanonicalReference?: DeclarationReference,\n\t): void {\n\t\tif (text.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst excerptToken: IExcerptToken = { kind: excerptTokenKind, text };\n\t\tif (canonicalReference !== undefined) {\n\t\t\texcerptToken.canonicalReference = canonicalReference.toString();\n\t\t}\n\n\t\texcerptTokens.push(excerptToken);\n\t}\n\n\t/**\n\t * Condenses the provided excerpt tokens by merging tokens where possible. Updates the provided token ranges to\n\t * remain accurate after token merging.\n\t *\n\t * @remarks\n\t * For example, suppose we have excerpt tokens [\"A\", \"B\", \"C\"] and a token range [0, 2]. If the excerpt tokens\n\t * are condensed to [\"AB\", \"C\"], then the token range would be updated to [0, 1]. Note that merges are only\n\t * performed if they are compatible with the provided token ranges. In the example above, if our token range was\n\t * originally [0, 1], we would not be able to merge tokens \"A\" and \"B\".\n\t */\n\tprivate static _condenseTokens(excerptTokens: IExcerptToken[], tokenRanges: IExcerptTokenRange[]): void {\n\t\t// This set is used to quickly lookup a start or end index.\n\t\tconst startOrEndIndices: Set<number> = new Set();\n\t\tfor (const tokenRange of tokenRanges) {\n\t\t\tstartOrEndIndices.add(tokenRange.startIndex);\n\t\t\tstartOrEndIndices.add(tokenRange.endIndex);\n\t\t}\n\n\t\tfor (let currentIndex = 1; currentIndex < excerptTokens.length; ++currentIndex) {\n\t\t\twhile (currentIndex < excerptTokens.length) {\n\t\t\t\tconst prevPrevToken: IExcerptToken | undefined = excerptTokens[currentIndex - 2]; // May be undefined\n\t\t\t\tconst prevToken: IExcerptToken = excerptTokens[currentIndex - 1]!;\n\t\t\t\tconst currentToken: IExcerptToken = excerptTokens[currentIndex]!;\n\n\t\t\t\t// The number of excerpt tokens that are merged in this iteration. We need this to determine\n\t\t\t\t// how to update the start and end indices of our token ranges.\n\t\t\t\tlet mergeCount: number;\n\n\t\t\t\t// There are two types of merges that can occur. We only perform these merges if they are\n\t\t\t\t// compatible with all of our token ranges.\n\t\t\t\tif (\n\t\t\t\t\tprevPrevToken?.kind === ExcerptTokenKind.Reference &&\n\t\t\t\t\tprevToken.kind === ExcerptTokenKind.Content &&\n\t\t\t\t\tprevToken.text.trim() === '.' &&\n\t\t\t\t\tcurrentToken.kind === ExcerptTokenKind.Reference &&\n\t\t\t\t\t!startOrEndIndices.has(currentIndex) &&\n\t\t\t\t\t!startOrEndIndices.has(currentIndex - 1)\n\t\t\t\t) {\n\t\t\t\t\t// If the current token is a reference token, the previous token is a \".\", and the previous-\n\t\t\t\t\t// previous token is a reference token, then merge all three tokens into a reference token.\n\t\t\t\t\t//\n\t\t\t\t\t// For example: Given [\"MyNamespace\" (R), \".\", \"MyClass\" (R)], tokens \".\" and \"MyClass\" might\n\t\t\t\t\t// be merged into \"MyNamespace\". The condensed token would be [\"MyNamespace.MyClass\" (R)].\n\t\t\t\t\tprevPrevToken.text += prevToken.text + currentToken.text;\n\t\t\t\t\tprevPrevToken.canonicalReference = currentToken.canonicalReference;\n\t\t\t\t\tmergeCount = 2;\n\t\t\t\t\tcurrentIndex--;\n\t\t\t\t} else if (\n\t\t\t\t\t// If the current and previous tokens are both content tokens, then merge the tokens into a\n\t\t\t\t\t// single content token. For example: Given [\"export \", \"declare class\"], these tokens\n\t\t\t\t\t// might be merged into \"export declare class\".\n\t\t\t\t\tprevToken.kind === ExcerptTokenKind.Content &&\n\t\t\t\t\tprevToken.kind === currentToken.kind &&\n\t\t\t\t\t!startOrEndIndices.has(currentIndex)\n\t\t\t\t) {\n\t\t\t\t\tprevToken.text += currentToken.text;\n\t\t\t\t\t// Remove BarTokens from excerpts if they immediately follow a LessThanToken, e.g. `Promise< | Something>`\n\t\t\t\t\t// would become `Promise<Something>`\n\t\t\t\t\tif (/<(?:\\s*\\||\\s+)/.test(prevToken.text)) {\n\t\t\t\t\t\tprevToken.text = prevToken.text.replaceAll(/<\\s*\\|?\\s*/g, '<');\n\t\t\t\t\t}\n\n\t\t\t\t\tif (/\\s+>/.test(prevToken.text)) {\n\t\t\t\t\t\tprevToken.text = prevToken.text.replaceAll(/\\s*>/g, '>');\n\t\t\t\t\t}\n\n\t\t\t\t\tmergeCount = 1;\n\t\t\t\t} else {\n\t\t\t\t\t// Otherwise, no merging can occur here. Continue to the next index.\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// Remove the now redundant excerpt token(s), as they were merged into a previous token.\n\t\t\t\texcerptTokens.splice(currentIndex, mergeCount);\n\n\t\t\t\t// Update the start and end indices for all token ranges based upon how many excerpt\n\t\t\t\t// tokens were merged and in what positions.\n\t\t\t\tfor (const tokenRange of tokenRanges) {\n\t\t\t\t\tif (tokenRange.startIndex > currentIndex) {\n\t\t\t\t\t\ttokenRange.startIndex -= mergeCount;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (tokenRange.endIndex > currentIndex) {\n\t\t\t\t\t\ttokenRange.endIndex -= mergeCount;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Clear and repopulate our set with the updated indices.\n\t\t\t\tstartOrEndIndices.clear();\n\t\t\t\tfor (const tokenRange of tokenRanges) {\n\t\t\t\t\tstartOrEndIndices.add(tokenRange.startIndex);\n\t\t\t\t\tstartOrEndIndices.add(tokenRange.endIndex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} /*\n\n\tprivate static _isDeclarationName(name: ts.Identifier): boolean {\n\t\treturn ExcerptBuilder._isDeclaration(name.parent) && name.parent.name === name;\n\t}\n\n\tprivate static _isDeclaration(node: ts.Node): node is ts.NamedDeclaration {\n\t\tswitch (node.kind) {\n\t\t\tcase ts.SyntaxKind.FunctionDeclaration:\n\t\t\tcase ts.SyntaxKind.FunctionExpression:\n\t\t\tcase ts.SyntaxKind.VariableDeclaration:\n\t\t\tcase ts.SyntaxKind.Parameter:\n\t\t\tcase ts.SyntaxKind.EnumDeclaration:\n\t\t\tcase ts.SyntaxKind.ClassDeclaration:\n\t\t\tcase ts.SyntaxKind.ClassExpression:\n\t\t\tcase ts.SyntaxKind.ModuleDeclaration:\n\t\t\tcase ts.SyntaxKind.MethodDeclaration:\n\t\t\tcase ts.SyntaxKind.MethodSignature:\n\t\t\tcase ts.SyntaxKind.PropertyDeclaration:\n\t\t\tcase ts.SyntaxKind.PropertySignature:\n\t\t\tcase ts.SyntaxKind.GetAccessor:\n\t\t\tcase ts.SyntaxKind.SetAccessor:\n\t\t\tcase ts.SyntaxKind.InterfaceDeclaration:\n\t\t\tcase ts.SyntaxKind.TypeAliasDeclaration:\n\t\t\tcase ts.SyntaxKind.TypeParameter:\n\t\t\tcase ts.SyntaxKind.EnumMember:\n\t\t\tcase ts.SyntaxKind.BindingElement:\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t} // */\n}\n"
  },
  {
    "path": "packages/api-extractor/src/generators/IndentedWriter.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { StringBuilder, type IStringBuilder } from '@rushstack/node-core-library';\n\n/**\n * A utility for writing indented text.\n *\n * @remarks\n *\n * Note that the indentation is inserted at the last possible opportunity.\n * For example, this code...\n *\n * ```ts\n *   writer.write('begin\\n');\n *   writer.increaseIndent();\n *   writer.write('one\\ntwo\\n');\n *   writer.decreaseIndent();\n *   writer.increaseIndent();\n *   writer.decreaseIndent();\n *   writer.write('end');\n * ```\n *\n * ...would produce this output:\n *\n * ```\n *   begin\n *     one\n *     two\n *   end\n * ```\n */\nexport class IndentedWriter {\n\t/**\n\t * The text characters used to create one level of indentation.\n\t * Two spaces by default.\n\t */\n\tpublic defaultIndentPrefix: string = '    ';\n\n\t/**\n\t * Whether to indent blank lines\n\t */\n\tpublic indentBlankLines: boolean = false;\n\n\t/**\n\t * Trims leading spaces from the input text before applying the indent.\n\t *\n\t * @remarks\n\t * Consider the following example:\n\t *\n\t * ```ts\n\t * indentedWriter.increaseIndent('    '); // four spaces\n\t * indentedWriter.write('  a\\n  b  c\\n');\n\t * indentedWriter.decreaseIndent();\n\t * ```\n\t *\n\t * Normally the output would be indented by 6 spaces: 4 from `increaseIndent()`, plus the 2 spaces\n\t * from `write()`:\n\t * ```\n\t *       a\n\t *       b  c\n\t * ```\n\t *\n\t * Setting `trimLeadingSpaces=true` will trim the leading spaces, so that the lines are indented\n\t * by 4 spaces only:\n\t * ```\n\t *     a\n\t *     b  c\n\t * ```\n\t */\n\tpublic trimLeadingSpaces: boolean = false;\n\n\tprivate readonly _builder: IStringBuilder;\n\n\tprivate _latestChunk: string | undefined;\n\n\tprivate _previousChunk: string | undefined;\n\n\tprivate _atStartOfLine: boolean;\n\n\tprivate readonly _indentStack: string[];\n\n\tprivate _indentText: string;\n\n\tprivate _previousLineIsBlank: boolean;\n\n\tprivate _currentLineIsBlank: boolean;\n\n\tpublic constructor(builder?: IStringBuilder) {\n\t\tthis._builder = builder ?? new StringBuilder();\n\t\tthis._latestChunk = undefined;\n\t\tthis._previousChunk = undefined;\n\t\tthis._atStartOfLine = true;\n\t\tthis._previousLineIsBlank = true;\n\t\tthis._currentLineIsBlank = true;\n\n\t\tthis._indentStack = [];\n\t\tthis._indentText = '';\n\t}\n\n\t/**\n\t * Retrieves the output that was built so far.\n\t */\n\tpublic getText(): string {\n\t\treturn this._builder.toString();\n\t}\n\n\tpublic toString(): string {\n\t\treturn this.getText();\n\t}\n\n\t/**\n\t * Increases the indentation.  Normally the indentation is two spaces,\n\t * however an arbitrary prefix can optional be specified.  (For example,\n\t * the prefix could be \"// \" to indent and comment simultaneously.)\n\t * Each call to IndentedWriter.increaseIndent() must be followed by a\n\t * corresponding call to IndentedWriter.decreaseIndent().\n\t */\n\tpublic increaseIndent(indentPrefix?: string): void {\n\t\tthis._indentStack.push(indentPrefix ?? this.defaultIndentPrefix);\n\t\tthis._updateIndentText();\n\t}\n\n\t/**\n\t * Decreases the indentation, reverting the effect of the corresponding call\n\t * to IndentedWriter.increaseIndent().\n\t */\n\tpublic decreaseIndent(): void {\n\t\tthis._indentStack.pop();\n\t\tthis._updateIndentText();\n\t}\n\n\t/**\n\t * A shorthand for ensuring that increaseIndent()/decreaseIndent() occur\n\t * in pairs.\n\t */\n\tpublic indentScope(scope: () => void, indentPrefix?: string): void {\n\t\tthis.increaseIndent(indentPrefix);\n\t\tscope();\n\t\tthis.decreaseIndent();\n\t}\n\n\t/**\n\t * Adds a newline if the file pointer is not already at the start of the line (or start of the stream).\n\t */\n\tpublic ensureNewLine(): void {\n\t\tconst lastCharacter: string = this.peekLastCharacter();\n\t\tif (lastCharacter !== '\\n' && lastCharacter !== '') {\n\t\t\tthis._writeNewLine();\n\t\t}\n\t}\n\n\t/**\n\t * Adds up to two newlines to ensure that there is a blank line above the current position.\n\t * The start of the stream is considered to be a blank line, so `ensureSkippedLine()` has no effect\n\t * unless some text has been written.\n\t */\n\tpublic ensureSkippedLine(): void {\n\t\tthis.ensureNewLine();\n\t\tif (!this._previousLineIsBlank) {\n\t\t\tthis._writeNewLine();\n\t\t}\n\t}\n\n\t/**\n\t * Returns the last character that was written, or an empty string if no characters have been written yet.\n\t */\n\tpublic peekLastCharacter(): string {\n\t\tif (this._latestChunk !== undefined) {\n\t\t\treturn this._latestChunk.slice(-1, -1 + 1);\n\t\t}\n\n\t\treturn '';\n\t}\n\n\t/**\n\t * Returns the second to last character that was written, or an empty string if less than one characters\n\t * have been written yet.\n\t */\n\tpublic peekSecondLastCharacter(): string {\n\t\tif (this._latestChunk !== undefined) {\n\t\t\tif (this._latestChunk.length > 1) {\n\t\t\t\treturn this._latestChunk.slice(-2, -2 + 1);\n\t\t\t}\n\n\t\t\tif (this._previousChunk !== undefined) {\n\t\t\t\treturn this._previousChunk.slice(-1, -1 + 1);\n\t\t\t}\n\t\t}\n\n\t\treturn '';\n\t}\n\n\t/**\n\t * Writes some text to the internal string buffer, applying indentation according\n\t * to the current indentation level.  If the string contains multiple newlines,\n\t * each line will be indented separately.\n\t */\n\tpublic write(message: string): void {\n\t\tif (message.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are no newline characters, then append the string verbatim\n\t\tif (!/[\\n\\r]/.test(message)) {\n\t\t\tthis._writeLinePart(message);\n\t\t\treturn;\n\t\t}\n\n\t\t// Otherwise split the lines and write each one individually\n\t\tlet first = true;\n\t\tfor (const linePart of message.split('\\n')) {\n\t\t\tif (first) {\n\t\t\t\tfirst = false;\n\t\t\t} else {\n\t\t\t\tthis._writeNewLine();\n\t\t\t}\n\n\t\t\tif (linePart) {\n\t\t\t\tthis._writeLinePart(linePart.replaceAll('\\r', ''));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * A shorthand for writing an optional message, followed by a newline.\n\t * Indentation is applied following the semantics of IndentedWriter.write().\n\t */\n\tpublic writeLine(message: string = ''): void {\n\t\tif (message.length > 0) {\n\t\t\tthis.write(message);\n\t\t}\n\n\t\tthis._writeNewLine();\n\t}\n\n\t/**\n\t * Writes a string that does not contain any newline characters.\n\t */\n\tprivate _writeLinePart(message: string): void {\n\t\tlet trimmedMessage: string = message;\n\n\t\tif (this.trimLeadingSpaces && this._atStartOfLine) {\n\t\t\ttrimmedMessage = message.replace(/^ +/, '');\n\t\t}\n\n\t\tif (trimmedMessage.length > 0) {\n\t\t\tif (this._atStartOfLine && this._indentText.length > 0) {\n\t\t\t\tthis._write(this._indentText);\n\t\t\t}\n\n\t\t\tthis._write(trimmedMessage);\n\t\t\tif (this._currentLineIsBlank && /\\S/.test(trimmedMessage)) {\n\t\t\t\tthis._currentLineIsBlank = false;\n\t\t\t}\n\n\t\t\tthis._atStartOfLine = false;\n\t\t}\n\t}\n\n\tprivate _writeNewLine(): void {\n\t\tif (this.indentBlankLines && this._atStartOfLine && this._indentText.length > 0) {\n\t\t\tthis._write(this._indentText);\n\t\t}\n\n\t\tthis._previousLineIsBlank = this._currentLineIsBlank;\n\t\tthis._write('\\n');\n\t\tthis._currentLineIsBlank = true;\n\t\tthis._atStartOfLine = true;\n\t}\n\n\tprivate _write(str: string): void {\n\t\tthis._previousChunk = this._latestChunk;\n\t\tthis._latestChunk = str;\n\t\tthis._builder.append(str);\n\t}\n\n\tprivate _updateIndentText(): void {\n\t\tthis._indentText = this._indentStack.join('');\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/index.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * API Extractor helps with validation, documentation, and reviewing of the exported API for a TypeScript library.\n * The `@discordjs/api-extractor` package provides the command-line tool.  It also exposes a developer API that you\n * can use to invoke API Extractor programmatically.\n *\n * @packageDocumentation\n */\n\nexport { ConsoleMessageId } from './api/ConsoleMessageId.js';\n\nexport { CompilerState, type ICompilerStateCreateOptions } from './api/CompilerState.js';\n\nexport { Extractor, type IExtractorInvokeOptions, ExtractorResult } from './api/Extractor.js';\n\nexport {\n\ttype IExtractorConfigPrepareOptions,\n\ttype IExtractorConfigLoadForFolderOptions,\n\tExtractorConfig,\n} from './api/ExtractorConfig.js';\n\nexport { ExtractorLogLevel } from './api/ExtractorLogLevel.js';\n\nexport {\n\tExtractorMessage,\n\ttype IExtractorMessageProperties,\n\tExtractorMessageCategory,\n} from './api/ExtractorMessage.js';\n\nexport { ExtractorMessageId } from './api/ExtractorMessageId.js';\n\nexport type {\n\tIConfigCompiler,\n\tIConfigApiReport,\n\tIConfigDocModel,\n\tIConfigDtsRollup,\n\tIConfigTsdocMetadata,\n\tIConfigMessageReportingRule,\n\tIConfigMessageReportingTable,\n\tIExtractorMessagesConfig,\n\tIConfigFile,\n} from './api/IConfigFile.js';\n"
  },
  {
    "path": "packages/api-extractor/src/schemas/api-extractor-defaults.json",
    "content": "{\n\t\"projectFolder\": \"<lookup>\",\n\n\t// (\"mainEntryPointFilePath\" is required)\n\n\t\"mainEntryPointName\": \"\",\n\n\t\"bundledPackages\": [],\n\n\t\"newlineKind\": \"crlf\",\n\n\t\"enumMemberOrder\": \"by-name\",\n\n\t\"compiler\": {\n\t\t\"tsconfigFilePath\": \"<projectFolder>/tsconfig.json\",\n\t\t\"skipLibCheck\": false\n\t},\n\n\t\"apiReport\": {\n\t\t// (\"enabled\" is required)\n\t\t\"reportFileName\": \"<unscopedPackageName>.api.md\",\n\t\t\"reportFolder\": \"<projectFolder>/etc/\",\n\t\t\"reportTempFolder\": \"<projectFolder>/temp/\",\n\t\t\"includeForgottenExports\": false\n\t},\n\n\t\"docModel\": {\n\t\t// (\"enabled\" is required)\n\t\t\"apiJsonFilePath\": \"<projectFolder>/temp/<unscopedPackageName>.api.json\",\n\t\t\"includeForgottenExports\": false\n\t},\n\n\t\"dtsRollup\": {\n\t\t// (\"enabled\" is required)\n\n\t\t\"untrimmedFilePath\": \"<projectFolder>/dist/<unscopedPackageName>.d.ts\",\n\t\t\"alphaTrimmedFilePath\": \"\",\n\t\t\"betaTrimmedFilePath\": \"\",\n\t\t\"publicTrimmedFilePath\": \"\",\n\t\t\"omitTrimmingComments\": false\n\t},\n\n\t\"tsdocMetadata\": {\n\t\t\"enabled\": true,\n\t\t\"tsdocMetadataFilePath\": \"<lookup>\"\n\t},\n\n\t\"messages\": {\n\t\t\"compilerMessageReporting\": {\n\t\t\t\"default\": {\n\t\t\t\t\"logLevel\": \"warning\"\n\t\t\t}\n\t\t},\n\t\t\"extractorMessageReporting\": {\n\t\t\t\"default\": {\n\t\t\t\t\"logLevel\": \"warning\"\n\t\t\t},\n\t\t\t\"ae-forgotten-export\": {\n\t\t\t\t\"logLevel\": \"warning\",\n\t\t\t\t\"addToApiReportFile\": true\n\t\t\t},\n\t\t\t\"ae-incompatible-release-tags\": {\n\t\t\t\t\"logLevel\": \"warning\",\n\t\t\t\t\"addToApiReportFile\": true\n\t\t\t},\n\t\t\t\"ae-internal-missing-underscore\": {\n\t\t\t\t\"logLevel\": \"warning\",\n\t\t\t\t\"addToApiReportFile\": true\n\t\t\t},\n\t\t\t\"ae-internal-mixed-release-tag\": {\n\t\t\t\t\"logLevel\": \"warning\",\n\t\t\t\t\"addToApiReportFile\": true\n\t\t\t},\n\t\t\t\"ae-undocumented\": {\n\t\t\t\t\"logLevel\": \"none\"\n\t\t\t},\n\t\t\t\"ae-unresolved-inheritdoc-reference\": {\n\t\t\t\t\"logLevel\": \"warning\",\n\t\t\t\t\"addToApiReportFile\": true\n\t\t\t},\n\t\t\t\"ae-unresolved-inheritdoc-base\": {\n\t\t\t\t\"logLevel\": \"warning\",\n\t\t\t\t\"addToApiReportFile\": true\n\t\t\t},\n\t\t\t\"ae-wrong-input-file-type\": {\n\t\t\t\t\"logLevel\": \"error\"\n\t\t\t}\n\t\t},\n\t\t\"tsdocMessageReporting\": {\n\t\t\t\"default\": {\n\t\t\t\t\"logLevel\": \"warning\"\n\t\t\t}\n\t\t}\n\t},\n\n\t\"testMode\": false\n}\n"
  },
  {
    "path": "packages/api-extractor/src/schemas/api-extractor-template.json",
    "content": "/**\n * Config file for API Extractor.  For more info, please visit: https://api-extractor.com\n */\n{\n\t\"$schema\": \"https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json\",\n\n\t/**\n\t * Optionally specifies another JSON config file that this file extends from.  This provides a way for\n\t * standard settings to be shared across multiple projects.\n\t *\n\t * If the path starts with \"./\" or \"../\", the path is resolved relative to the folder of the file that contains\n\t * the \"extends\" field.  Otherwise, the first path segment is interpreted as an NPM package name, and will be\n\t * resolved using NodeJS require().\n\t *\n\t * SUPPORTED TOKENS: none\n\t * DEFAULT VALUE: \"\"\n\t */\n\t// \"extends\": \"./shared/api-extractor-base.json\"\n\t// \"extends\": \"my-package/include/api-extractor-base.json\"\n\n\t/**\n\t * Determines the \"<projectFolder>\" token that can be used with other config file settings.  The project folder\n\t * typically contains the tsconfig.json and package.json config files, but the path is user-defined.\n\t *\n\t * The path is resolved relative to the folder of the config file that contains the setting.\n\t *\n\t * The default value for \"projectFolder\" is the token \"<lookup>\", which means the folder is determined by traversing\n\t * parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder\n\t * that contains a tsconfig.json file.  If a tsconfig.json file cannot be found in this way, then an error\n\t * will be reported.\n\t *\n\t * SUPPORTED TOKENS: <lookup>\n\t * DEFAULT VALUE: \"<lookup>\"\n\t */\n\t// \"projectFolder\": \"..\",\n\n\t/**\n\t * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis.  API Extractor\n\t * analyzes the symbols exported by this module.\n\t *\n\t * The file extension must be \".d.ts\" and not \".ts\".\n\t *\n\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t * prepend a folder token such as \"<projectFolder>\".\n\t *\n\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t */\n\t\"mainEntryPointFilePath\": \"<projectFolder>/lib/index.d.ts\",\n\n\t/**\n\t * Specifies the import path of the entrypoint used as the starting point for analysis.\n\t */\n\t// \"mainEntryPointName\": \"\",\n\n\t/**\n\t * A list of NPM package names whose exports should be treated as part of this package.\n\t *\n\t * For example, suppose that Webpack is used to generate a distributed bundle for the project \"library1\",\n\t * and another NPM package \"library2\" is embedded in this bundle.  Some types from library2 may become part\n\t * of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly\n\t * imports library2.  To avoid this, we can specify:\n\t *\n\t *   \"bundledPackages\": [ \"library2\" ],\n\t *\n\t * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been\n\t * local files for library1.\n\t */\n\t\"bundledPackages\": [],\n\n\t/**\n\t * Specifies what type of newlines API Extractor should use when writing output files.  By default, the output files\n\t * will be written with Windows-style newlines.  To use POSIX-style newlines, specify \"lf\" instead.\n\t * To use the OS's default newline kind, specify \"os\".\n\t *\n\t * DEFAULT VALUE: \"crlf\"\n\t */\n\t// \"newlineKind\": \"crlf\",\n\n\t/**\n\t * Set to true when invoking API Extractor's test harness. When `testMode` is true, the `toolVersion` field in the\n\t * .api.json file is assigned an empty string to prevent spurious diffs in output files tracked for tests.\n\t *\n\t * DEFAULT VALUE: \"false\"\n\t */\n\t// \"testMode\": false,\n\n\t/**\n\t * Specifies how API Extractor sorts members of an enum when generating the .api.json file. By default, the output\n\t * files will be sorted alphabetically, which is \"by-name\". To keep the ordering in the source code, specify\n\t * \"preserve\".\n\t *\n\t * DEFAULT VALUE: \"by-name\"\n\t */\n\t// \"enumMemberOrder\": \"by-name\",\n\n\t/**\n\t * Determines how the TypeScript compiler engine will be invoked by API Extractor.\n\t */\n\t\"compiler\": {\n\t\t/**\n\t\t * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project.\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * Note: This setting will be ignored if \"overrideTsconfig\" is used.\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"<projectFolder>/tsconfig.json\"\n\t\t */\n\t\t// \"tsconfigFilePath\": \"<projectFolder>/tsconfig.json\",\n\t\t/**\n\t\t * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk.\n\t\t * The object must conform to the TypeScript tsconfig schema:\n\t\t *\n\t\t * http://json.schemastore.org/tsconfig\n\t\t *\n\t\t * If omitted, then the tsconfig.json file will be read from the \"projectFolder\".\n\t\t *\n\t\t * DEFAULT VALUE: no overrideTsconfig section\n\t\t */\n\t\t// \"overrideTsconfig\": {\n\t\t//   . . .\n\t\t// }\n\t\t/**\n\t\t * This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended\n\t\t * and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when\n\t\t * dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses\n\t\t * for its analysis.  Where possible, the underlying issue should be fixed rather than relying on skipLibCheck.\n\t\t *\n\t\t * DEFAULT VALUE: false\n\t\t */\n\t\t// \"skipLibCheck\": true,\n\t},\n\n\t/**\n\t * Configures how the API report file (*.api.md) will be generated.\n\t */\n\t\"apiReport\": {\n\t\t/**\n\t\t * (REQUIRED) Whether to generate an API report.\n\t\t */\n\t\t\"enabled\": true\n\n\t\t/**\n\t\t * The base filename for the API report files, to be combined with \"reportFolder\" or \"reportTempFolder\"\n\t\t * to produce the full file path.  The \"reportFileName\" should not include any path separators such as\n\t\t * \"\\\" or \"/\".  The \"reportFileName\" should not include a file extension, since API Extractor will automatically\n\t\t * append an appropriate file extension such as \".api.md\".  If the \"reportVariants\" setting is used, then the\n\t\t * file extension includes the variant name, for example \"my-report.public.api.md\" or \"my-report.beta.api.md\".\n\t\t * The \"complete\" variant always uses the simple extension \"my-report.api.md\".\n\t\t *\n\t\t * Previous versions of API Extractor required \"reportFileName\" to include the \".api.md\" extension explicitly;\n\t\t * for backwards compatibility, that is still accepted but will be discarded before applying the above rules.\n\t\t *\n\t\t * SUPPORTED TOKENS: <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"<unscopedPackageName>\"\n\t\t */\n\t\t// \"reportFileName\": \"<unscopedPackageName>\",\n\n\t\t/**\n\t\t * To support different approval requirements for different API levels, multiple \"variants\" of the API report can\n\t\t * be generated.  The \"reportVariants\" setting specifies a list of variants to be generated.  If omitted,\n\t\t * by default only the \"complete\" variant will be generated, which includes all @internal, @alpha, @beta,\n\t\t * and @public items.  Other possible variants are \"alpha\" (@alpha + @beta + @public), \"beta\" (@beta + @public),\n\t\t * and \"public\" (@public only).\n\t\t *\n\t\t * DEFAULT VALUE: [ \"complete\" ]\n\t\t */\n\t\t// \"reportVariants\": [\"public\", \"beta\"],\n\n\t\t/**\n\t\t * Specifies the folder where the API report file is written.  The file name portion is determined by\n\t\t * the \"reportFileName\" setting.\n\t\t *\n\t\t * The API report file is normally tracked by Git.  Changes to it can be used to trigger a branch policy,\n\t\t * e.g. for an API review.\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"<projectFolder>/etc/\"\n\t\t */\n\t\t// \"reportFolder\": \"<projectFolder>/etc/\",\n\n\t\t/**\n\t\t * Specifies the folder where the temporary report file is written.  The file name portion is determined by\n\t\t * the \"reportFileName\" setting.\n\t\t *\n\t\t * After the temporary file is written to disk, it is compared with the file in the \"reportFolder\".\n\t\t * If they are different, a production build will fail.\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"<projectFolder>/temp/\"\n\t\t */\n\t\t// \"reportTempFolder\": \"<projectFolder>/temp/\",\n\n\t\t/**\n\t\t * Whether \"forgotten exports\" should be included in the API report file. Forgotten exports are declarations\n\t\t * flagged with `ae-forgotten-export` warnings. See https://api-extractor.com/pages/messages/ae-forgotten-export/ to\n\t\t * learn more.\n\t\t *\n\t\t * DEFAULT VALUE: \"false\"\n\t\t */\n\t\t// \"includeForgottenExports\": false\n\t},\n\n\t/**\n\t * Configures how the doc model file (*.api.json) will be generated.\n\t */\n\t\"docModel\": {\n\t\t/**\n\t\t * (REQUIRED) Whether to generate a doc model file.\n\t\t */\n\t\t\"enabled\": true\n\n\t\t/**\n\t\t * The output path for the doc model file.  The file extension should be \".api.json\".\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"<projectFolder>/temp/<unscopedPackageName>.api.json\"\n\t\t */\n\t\t// \"apiJsonFilePath\": \"<projectFolder>/temp/<unscopedPackageName>.api.json\",\n\n\t\t/**\n\t\t * Whether \"forgotten exports\" should be included in the doc model file. Forgotten exports are declarations\n\t\t * flagged with `ae-forgotten-export` warnings. See https://api-extractor.com/pages/messages/ae-forgotten-export/ to\n\t\t * learn more.\n\t\t *\n\t\t * DEFAULT VALUE: \"false\"\n\t\t */\n\t\t// \"includeForgottenExports\": false,\n\n\t\t/**\n\t\t * The base URL where the project's source code can be viewed on a website such as GitHub or\n\t\t * Azure DevOps. This URL path corresponds to the `<projectFolder>` path on disk.\n\t\t *\n\t\t * This URL is concatenated with the file paths serialized to the doc model to produce URL file paths to individual API items.\n\t\t * For example, if the `projectFolderUrl` is \"https://github.com/microsoft/rushstack/tree/main/apps/api-extractor\" and an API\n\t\t * item's file path is \"api/ExtractorConfig.ts\", the full URL file path would be\n\t\t * \"https://github.com/microsoft/rushstack/tree/main/apps/api-extractor/api/ExtractorConfig.js\".\n\t\t *\n\t\t * This setting can be omitted if you don't need source code links in your API documentation reference.\n\t\t *\n\t\t * SUPPORTED TOKENS: none\n\t\t * DEFAULT VALUE: \"\"\n\t\t */\n\t\t// \"projectFolderUrl\": \"http://github.com/path/to/your/projectFolder\"\n\t},\n\n\t/**\n\t * Configures how the .d.ts rollup file will be generated.\n\t */\n\t\"dtsRollup\": {\n\t\t/**\n\t\t * (REQUIRED) Whether to generate the .d.ts rollup file.\n\t\t */\n\t\t\"enabled\": true\n\n\t\t/**\n\t\t * Specifies the output path for a .d.ts rollup file to be generated without any trimming.\n\t\t * This file will include all declarations that are exported by the main entry point.\n\t\t *\n\t\t * If the path is an empty string, then this file will not be written.\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"<projectFolder>/dist/<unscopedPackageName>.d.ts\"\n\t\t */\n\t\t// \"untrimmedFilePath\": \"<projectFolder>/dist/<unscopedPackageName>.d.ts\",\n\n\t\t/**\n\t\t * Specifies the output path for a .d.ts rollup file to be generated with trimming for an \"alpha\" release.\n\t\t * This file will include only declarations that are marked as \"@public\", \"@beta\", or \"@alpha\".\n\t\t *\n\t\t * If the path is an empty string, then this file will not be written.\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"\"\n\t\t */\n\t\t// \"alphaTrimmedFilePath\": \"<projectFolder>/dist/<unscopedPackageName>-alpha.d.ts\",\n\n\t\t/**\n\t\t * Specifies the output path for a .d.ts rollup file to be generated with trimming for a \"beta\" release.\n\t\t * This file will include only declarations that are marked as \"@public\" or \"@beta\".\n\t\t *\n\t\t * If the path is an empty string, then this file will not be written.\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"\"\n\t\t */\n\t\t// \"betaTrimmedFilePath\": \"<projectFolder>/dist/<unscopedPackageName>-beta.d.ts\",\n\n\t\t/**\n\t\t * Specifies the output path for a .d.ts rollup file to be generated with trimming for a \"public\" release.\n\t\t * This file will include only declarations that are marked as \"@public\".\n\t\t *\n\t\t * If the path is an empty string, then this file will not be written.\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"\"\n\t\t */\n\t\t// \"publicTrimmedFilePath\": \"<projectFolder>/dist/<unscopedPackageName>-public.d.ts\",\n\n\t\t/**\n\t\t * When a declaration is trimmed, by default it will be replaced by a code comment such as\n\t\t * \"Excluded from this release type: exampleMember\".  Set \"omitTrimmingComments\" to true to remove the\n\t\t * declaration completely.\n\t\t *\n\t\t * DEFAULT VALUE: false\n\t\t */\n\t\t// \"omitTrimmingComments\": true\n\t},\n\n\t/**\n\t * Configures how the tsdoc-metadata.json file will be generated.\n\t */\n\t\"tsdocMetadata\": {\n\t\t/**\n\t\t * Whether to generate the tsdoc-metadata.json file.\n\t\t *\n\t\t * DEFAULT VALUE: true\n\t\t */\n\t\t// \"enabled\": true,\n\t\t/**\n\t\t * Specifies where the TSDoc metadata file should be written.\n\t\t *\n\t\t * The path is resolved relative to the folder of the config file that contains the setting; to change this,\n\t\t * prepend a folder token such as \"<projectFolder>\".\n\t\t *\n\t\t * The default value is \"<lookup>\", which causes the path to be automatically inferred from the \"tsdocMetadata\",\n\t\t * \"typings\" or \"main\" fields of the project's package.json.  If none of these fields are set, the lookup\n\t\t * falls back to \"tsdoc-metadata.json\" in the package folder.\n\t\t *\n\t\t * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>\n\t\t * DEFAULT VALUE: \"<lookup>\"\n\t\t */\n\t\t// \"tsdocMetadataFilePath\": \"<projectFolder>/dist/tsdoc-metadata.json\"\n\t},\n\n\t/**\n\t * Configures how API Extractor reports error and warning messages produced during analysis.\n\t *\n\t * There are three sources of messages:  compiler messages, API Extractor messages, and TSDoc messages.\n\t */\n\t\"messages\": {\n\t\t/**\n\t\t * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing\n\t\t * the input .d.ts files.\n\t\t *\n\t\t * TypeScript message identifiers start with \"TS\" followed by an integer.  For example: \"TS2551\"\n\t\t *\n\t\t * DEFAULT VALUE:  A single \"default\" entry with logLevel=warning.\n\t\t */\n\t\t\"compilerMessageReporting\": {\n\t\t\t/**\n\t\t\t * Configures the default routing for messages that don't match an explicit rule in this table.\n\t\t\t */\n\t\t\t\"default\": {\n\t\t\t\t/**\n\t\t\t\t * Specifies whether the message should be written to the the tool's output log.  Note that\n\t\t\t\t * the \"addToApiReportFile\" property may supersede this option.\n\t\t\t\t *\n\t\t\t\t * Possible values: \"error\", \"warning\", \"none\"\n\t\t\t\t *\n\t\t\t\t * Errors cause the build to fail and return a nonzero exit code.  Warnings cause a production build fail\n\t\t\t\t * and return a nonzero exit code.  For a non-production build (e.g. when \"api-extractor run\" includes\n\t\t\t\t * the \"--local\" option), the warning is displayed but the build will not fail.\n\t\t\t\t *\n\t\t\t\t * DEFAULT VALUE: \"warning\"\n\t\t\t\t */\n\t\t\t\t\"logLevel\": \"warning\"\n\n\t\t\t\t/**\n\t\t\t\t * When addToApiReportFile is true:  If API Extractor is configured to write an API report file (.api.md),\n\t\t\t\t * then the message will be written inside that file; otherwise, the message is instead logged according to\n\t\t\t\t * the \"logLevel\" option.\n\t\t\t\t *\n\t\t\t\t * DEFAULT VALUE: false\n\t\t\t\t */\n\t\t\t\t// \"addToApiReportFile\": false\n\t\t\t}\n\n\t\t\t// \"TS2551\": {\n\t\t\t//   \"logLevel\": \"warning\",\n\t\t\t//   \"addToApiReportFile\": true\n\t\t\t// },\n\t\t\t//\n\t\t\t// . . .\n\t\t},\n\n\t\t/**\n\t\t * Configures handling of messages reported by API Extractor during its analysis.\n\t\t *\n\t\t * API Extractor message identifiers start with \"ae-\".  For example: \"ae-extra-release-tag\"\n\t\t *\n\t\t * DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings\n\t\t */\n\t\t\"extractorMessageReporting\": {\n\t\t\t\"default\": {\n\t\t\t\t\"logLevel\": \"warning\"\n\t\t\t\t// \"addToApiReportFile\": false\n\t\t\t}\n\n\t\t\t// \"ae-extra-release-tag\": {\n\t\t\t//   \"logLevel\": \"warning\",\n\t\t\t//   \"addToApiReportFile\": true\n\t\t\t// },\n\t\t\t//\n\t\t\t// . . .\n\t\t},\n\n\t\t/**\n\t\t * Configures handling of messages reported by the TSDoc parser when analyzing code comments.\n\t\t *\n\t\t * TSDoc message identifiers start with \"tsdoc-\".  For example: \"tsdoc-link-tag-unescaped-text\"\n\t\t *\n\t\t * DEFAULT VALUE:  A single \"default\" entry with logLevel=warning.\n\t\t */\n\t\t\"tsdocMessageReporting\": {\n\t\t\t\"default\": {\n\t\t\t\t\"logLevel\": \"warning\"\n\t\t\t\t// \"addToApiReportFile\": false\n\t\t\t}\n\n\t\t\t// \"tsdoc-link-tag-unescaped-text\": {\n\t\t\t//   \"logLevel\": \"warning\",\n\t\t\t//   \"addToApiReportFile\": true\n\t\t\t// },\n\t\t\t//\n\t\t\t// . . .\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/schemas/api-extractor.schema.json",
    "content": "{\n\t\"title\": \"API Extractor Configuration\",\n\t\"description\": \"Describes how the API Extractor tool will process a project.\",\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"$schema\": {\n\t\t\t\"description\": \"Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.\",\n\t\t\t\"type\": \"string\"\n\t\t},\n\n\t\t\"extends\": {\n\t\t\t\"description\": \"Optionally specifies another JSON config file that this file extends from.  This provides a way for standard settings to be shared across multiple projects.\",\n\t\t\t\"type\": \"string\"\n\t\t},\n\n\t\t\"projectFolder\": {\n\t\t\t\"description\": \"Determines the \\\"<projectFolder>\\\" token that can be used with other config file settings.  The project folder typically contains the tsconfig.json and package.json config files, but the path is user-defined.  The path is resolved relative to the folder of the config file that contains the setting.  The default value for \\\"projectFolder\\\" is the token \\\"<lookup>\\\", which means the folder is determined using the following heuristics:\\n\\nIf the config/rig.json system is used (as defined by @rushstack/rig-package), then the \\\"<lookup>\\\" value will be the package folder that referenced the rig.\\n\\nOtherwise, the \\\"<lookup>\\\" value is determined by traversing parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder that contains a tsconfig.json file.  If a tsconfig.json file cannot be found in this way, then an error will be reported.\",\n\t\t\t\"type\": \"string\"\n\t\t},\n\n\t\t\"mainEntryPointFilePath\": {\n\t\t\t\"description\": \"Specifies the .d.ts file to be used as the starting point for analysis.  API Extractor analyzes the symbols exported by this module. The file extension must be \\\".d.ts\\\" and not \\\".ts\\\". The path is resolved relative to the folder of the config file that contains the setting; to change this, prepend a folder token such as \\\"<projectFolder>\\\".\",\n\t\t\t\"type\": \"string\"\n\t\t},\n\n\t\t\"mainEntryPointName\": {\n\t\t\t\"description\": \"Specifies the import path of the entrypoint used as the starting point for analysis.\",\n\t\t\t\"type\": \"string\"\n\t\t},\n\n\t\t\"additionalEntryPoints\": {\n\t\t\t\"description\": \"Specifies the .d.ts files to be used as the starting points for analysis.\",\n\t\t\t\"type\": \"array\",\n\t\t\t\"items\": {\n\t\t\t\t\"type\": \"object\"\n\t\t\t}\n\t\t},\n\n\t\t\"bundledPackages\": {\n\t\t\t\"description\": \"A list of NPM package names whose exports should be treated as part of this package.\",\n\t\t\t\"type\": \"array\",\n\t\t\t\"items\": {\n\t\t\t\t\"type\": \"string\"\n\t\t\t}\n\t\t},\n\n\t\t\"enumMemberOrder\": {\n\t\t\t\"description\": \"Specifies how API Extractor sorts the members of an enum when generating the .api.json doc model. \\n 'by-name': sort the items according to the enum member name \\n 'preserve': keep the original order that items appear in the source code\",\n\t\t\t\"type\": \"string\",\n\t\t\t\"enum\": [\"by-name\", \"preserve\"],\n\t\t\t\"default\": \"by-name\"\n\t\t},\n\n\t\t\"compiler\": {\n\t\t\t\"description\": \"Determines how the TypeScript compiler engine will be invoked by API Extractor.\",\n\t\t\t\"type\": \"object\",\n\t\t\t\"properties\": {\n\t\t\t\t\"tsconfigFilePath\": {\n\t\t\t\t\t\"description\": \"Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project.  The path is resolved relative to the folder of the config file that contains the setting; to change this, prepend a folder token such as \\\"<projectFolder>\\\".  Note: This setting will be ignored if \\\"overrideTsconfig\\\" is used.\",\n\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t},\n\t\t\t\t\"overrideTsconfig\": {\n\t\t\t\t\t\"description\": \"Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk. The object must conform to the TypeScript tsconfig schema: http://json.schemastore.org/tsconfig  If omitted, then the tsconfig.json file will be read from the \\\"projectFolder\\\".\",\n\t\t\t\t\t\"type\": \"object\"\n\t\t\t\t},\n\t\t\t\t\"skipLibCheck\": {\n\t\t\t\t\t\"description\": \"This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses for its analysis.  Where possible, the underlying issue should be fixed rather than relying on skipLibCheck.\",\n\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"additionalProperties\": false\n\t\t},\n\n\t\t\"apiReport\": {\n\t\t\t\"description\": \"Configures how the API report file (*.api.md) will be generated.\",\n\t\t\t\"type\": \"object\",\n\t\t\t\"properties\": {\n\t\t\t\t\"enabled\": {\n\t\t\t\t\t\"description\": \"Whether to generate an API report.\",\n\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t},\n\n\t\t\t\t\"reportFileName\": {\n\t\t\t\t\t\"description\": \"The base filename for the API report files, to be combined with \\\"reportFolder\\\" or \\\"reportTempFolder\\\" to produce the full file path.  The \\\"reportFileName\\\" should not include any path separators such as \\\"\\\\\\\" or \\\"/\\\".  The \\\"reportFileName\\\" should not include a file extension, since API Extractor will automatically append an appropriate file extension such as \\\".api.md\\\".  If the \\\"reportVariants\\\" setting is used, then the file extension includes the variant name, for example \\\"my-report.public.api.md\\\" or \\\"my-report.beta.api.md\\\".  The \\\"complete\\\" variant always uses the simple extension \\\"my-report.api.md\\\".\\n\\nPrevious versions of API Extractor required \\\"reportFileName\\\" to include the \\\".api.md\\\" extension explicitly; for backwards compatibility, that is still accepted but will be discarded before applying the above rules.\",\n\t\t\t\t\t\"type\": [\"string\"]\n\t\t\t\t},\n\n\t\t\t\t\"reportVariants\": {\n\t\t\t\t\t\"description\": \"To support different approval requirements for different API levels, multiple \\\"variants\\\" of the API report can be generated.  The \\\"reportVariants\\\" setting specifies a list of variants to be generated.  If omitted, by default only the \\\"complete\\\" variant will be generated, which includes all @internal, @alpha, @beta, and @public items.  Other possible variants are \\\"alpha\\\" (@alpha + @beta + @public), \\\"beta\\\" (@beta + @public), and \\\"public\\\" (@public only).\",\n\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"enum\": [\"public\", \"beta\", \"alpha\", \"complete\"]\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t\"reportFolder\": {\n\t\t\t\t\t\"description\": \"Specifies the folder where the API report file is written.  The file name portion is determined by the \\\"reportFileName\\\" setting. The API report file is normally tracked by Git.  Changes to it can be used to trigger a branch policy, e.g. for an API review. The path is resolved relative to the folder of the config file that contains the setting; to change this,  prepend a folder token such as \\\"<projectFolder>\\\".\",\n\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t},\n\n\t\t\t\t\"reportTempFolder\": {\n\t\t\t\t\t\"description\": \"Specifies the folder where the temporary report file is written.  The file name portion is determined by the \\\"reportFileName\\\" setting. After the temporary file is written to disk, it is compared with the file in the \\\"reportFolder\\\". If they are different, a production build will fail. The path is resolved relative to the folder of the config file that contains the setting; to change this, prepend a folder token such as \\\"<projectFolder>\\\".\",\n\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t},\n\n\t\t\t\t\"includeForgottenExports\": {\n\t\t\t\t\t\"description\": \"Whether \\\"forgotten exports\\\" should be included in the API report file. Forgotten exports are declarations flagged with `ae-forgotten-export` warnings. See https://api-extractor.com/pages/messages/ae-forgotten-export/ to learn more.\",\n\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t},\n\n\t\t\t\t\"tagsToReport\": {\n\t\t\t\t\t\"description\": \"Specifies a list of TSDoc tags that should be reported in the API report file for items whose documentation contains them.  This can be used to include standard TSDoc tags or custom ones.  Specified tag names must begin with \\\"@\\\".  By default, the following tags are reported: [@sealed, @virtual, @override, @eventProperty, @deprecated].  Tags will appear in the order they are specified in this list.  Note that an item's release tag will always reported; this behavior cannot be overridden.\",\n\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\"patternProperties\": {\n\t\t\t\t\t\t\"^@[^\\\\s]*$\": {\n\t\t\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"additionalProperties\": false\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"required\": [\"enabled\"],\n\t\t\t\"additionalProperties\": false\n\t\t},\n\n\t\t\"docModel\": {\n\t\t\t\"description\": \"Configures how the doc model file (*.api.json) will be generated.\",\n\t\t\t\"type\": \"object\",\n\t\t\t\"properties\": {\n\t\t\t\t\"enabled\": {\n\t\t\t\t\t\"description\": \"Whether to generate doc model file.\",\n\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t},\n\t\t\t\t\"apiJsonFilePath\": {\n\t\t\t\t\t\"description\": \"The output path for the doc model file.  The file extension should be \\\".api.json\\\". The path is resolved relative to the folder of the config file that contains the setting; to change this, prepend a folder token such as \\\"<projectFolder>\\\".\",\n\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t},\n\t\t\t\t\"includeForgottenExports\": {\n\t\t\t\t\t\"description\": \"Whether \\\"forgotten exports\\\" should be included in the doc model file. Forgotten exports are declarations flagged with `ae-forgotten-export` warnings. See https://api-extractor.com/pages/messages/ae-forgotten-export/ to learn more.\",\n\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t},\n\t\t\t\t\"projectFolderUrl\": {\n\t\t\t\t\t\"description\": \"The base URL where the project's source code can be viewed on a website such as GitHub or Azure DevOps. This URL path corresponds to the `<projectFolder>` path on disk. This URL is concatenated with the file paths serialized to the doc model to produce URL file paths to individual API items. For example, if the `projectFolderUrl` is \\\"https://github.com/microsoft/rushstack/tree/main/apps/api-extractor\\\" and an API item's file path is \\\"api/ExtractorConfig.ts\\\", the full URL file path would be \\\"https://github.com/microsoft/rushstack/tree/main/apps/api-extractor/api/ExtractorConfig.js\\\". Can be omitted if you don't need source code links in your API documentation reference.\",\n\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t},\n\t\t\t\t\"releaseTagsToTrim\": {\n\t\t\t\t\t\"description\": \"Specifies a list of release tags that will be trimmed from the doc model. The default value is `[\\\"@internal\\\"]`.\",\n\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\"enum\": [\"@internal\", \"@alpha\", \"@beta\", \"@public\"]\n\t\t\t\t\t},\n\t\t\t\t\t\"uniqueItems\": true\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"required\": [\"enabled\"],\n\t\t\t\"additionalProperties\": false\n\t\t},\n\n\t\t\"dtsRollup\": {\n\t\t\t\"description\": \"Configures how the .d.ts rollup file will be generated.\",\n\t\t\t\"type\": \"object\",\n\t\t\t\"properties\": {\n\t\t\t\t\"enabled\": {\n\t\t\t\t\t\"description\": \"Whether to generate the .d.ts rollup file.\",\n\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t},\n\t\t\t\t\"untrimmedFilePath\": {\n\t\t\t\t\t\"description\": \"Specifies the output path for a .d.ts rollup file to be generated without any trimming. This file will include all declarations that are exported by the main entry point. If the path is an empty string, then this file will not be written. The path is resolved relative to the folder of the config file that contains the setting; to change this, prepend a folder token such as \\\"<projectFolder>\\\".\",\n\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t},\n\t\t\t\t\"alphaTrimmedFilePath\": {\n\t\t\t\t\t\"description\": \"Specifies the output path for a .d.ts rollup file to be generated with trimming for an \\\"alpha\\\" release. This file will include only declarations that are marked as \\\"@public\\\", \\\"@beta\\\", or \\\"@alpha\\\". The path is resolved relative to the folder of the config file that contains the setting; to change this, prepend a folder token such as \\\"<projectFolder>\\\".\",\n\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t},\n\t\t\t\t\"betaTrimmedFilePath\": {\n\t\t\t\t\t\"description\": \"Specifies the output path for a .d.ts rollup file to be generated with trimming for a \\\"beta\\\" release. This file will include only declarations that are marked as \\\"@public\\\" or \\\"@beta\\\". The path is resolved relative to the folder of the config file that contains the setting; to change this, prepend a folder token such as \\\"<projectFolder>\\\".\",\n\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t},\n\t\t\t\t\"publicTrimmedFilePath\": {\n\t\t\t\t\t\"description\": \"Specifies the output path for a .d.ts rollup file to be generated with trimming for a \\\"public\\\" release. This file will include only declarations that are marked as \\\"@public\\\". If the path is an empty string, then this file will not be written. The path is resolved relative to the folder of the config file that contains the setting; to change this, prepend a folder token such as \\\"<projectFolder>\\\".\",\n\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t},\n\t\t\t\t\"omitTrimmingComments\": {\n\t\t\t\t\t\"description\": \"When a declaration is trimmed, by default it will be replaced by a code comment such as \\\"Excluded from this release type: exampleMember\\\".  Set \\\"omitTrimmingComments\\\" to true to remove the declaration completely.\",\n\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"required\": [\"enabled\"],\n\t\t\t\"additionalProperties\": false\n\t\t},\n\n\t\t\"tsdocMetadata\": {\n\t\t\t\"description\": \"Configures how the tsdoc-metadata.json file will be generated.\",\n\t\t\t\"type\": \"object\",\n\t\t\t\"properties\": {\n\t\t\t\t\"enabled\": {\n\t\t\t\t\t\"description\": \"Whether to generate the tsdoc-metadata.json file.\",\n\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t},\n\t\t\t\t\"tsdocMetadataFilePath\": {\n\t\t\t\t\t\"description\": \"Specifies where the TSDoc metadata file should be written. The path is resolved relative to the folder of the config file that contains the setting; to change this, prepend a folder token such as \\\"<projectFolder>\\\". The default value is \\\"<lookup>\\\", which causes the path to be automatically inferred from the \\\"tsdocMetadata\\\", \\\"typings\\\" or \\\"main\\\" fields of the project's package.json.  If none of these fields are set, the lookup falls back to \\\"tsdoc-metadata.json\\\" in the package folder.\",\n\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"additionalProperties\": false\n\t\t},\n\n\t\t\"newlineKind\": {\n\t\t\t\"description\": \"Specifies what type of newlines API Extractor should use when writing output files.  By default, the output files will be written with Windows-style newlines.  To use POSIX-style newlines, specify \\\"lf\\\" instead. To use the OS's default newline kind, specify \\\"os\\\".\",\n\t\t\t\"type\": \"string\",\n\t\t\t\"enum\": [\"crlf\", \"lf\", \"os\"],\n\t\t\t\"default\": \"crlf\"\n\t\t},\n\n\t\t\"messages\": {\n\t\t\t\"description\": \"Configures how API Extractor reports error and warning messages produced during analysis.\",\n\t\t\t\"type\": \"object\",\n\t\t\t\"properties\": {\n\t\t\t\t\"compilerMessageReporting\": {\n\t\t\t\t\t\"description\": \"Configures handling of diagnostic messages generating the TypeScript compiler while analyzing the input .d.ts files.\",\n\t\t\t\t\t\"$ref\": \"#/definitions/extractorMessageReportingTable\"\n\t\t\t\t},\n\t\t\t\t\"extractorMessageReporting\": {\n\t\t\t\t\t\"description\": \"Configures handling of messages reported by API Extractor during its analysis.\",\n\t\t\t\t\t\"$ref\": \"#/definitions/extractorMessageReportingTable\"\n\t\t\t\t},\n\t\t\t\t\"tsdocMessageReporting\": {\n\t\t\t\t\t\"description\": \"Configures handling of messages reported by the TSDoc parser when analyzing code comments.\",\n\t\t\t\t\t\"$ref\": \"#/definitions/extractorMessageReportingTable\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"additionalProperties\": false\n\t\t},\n\n\t\t\"testMode\": {\n\t\t\t\"description\": \"Set to true invoking API Extractor's test harness. When \\\"testMode\\\" is true, the \\\"toolVersion\\\" field in the .api.json file is assigned an empty string to prevent spurious diffs in output files tracked for tests.\",\n\t\t\t\"type\": \"boolean\"\n\t\t}\n\t},\n\t\"required\": [\"mainEntryPointFilePath\"],\n\t\"additionalProperties\": false,\n\n\t\"definitions\": {\n\t\t\"extractorMessageReportingTable\": {\n\t\t\t\"type\": \"object\",\n\t\t\t\"description\": \"Specifies a table of reporting rules for different message identifiers, and also the default rule used for identifiers that do not appear in the table. The key is a message identifier for the associated type of message, or \\\"default\\\" to specify the default policy. For example, the key might be \\\"TS2551\\\" (a compiler message), \\\"tsdoc-link-tag-unescaped-text\\\" (a TSDOc message), or \\\"ae-extra-release-tag\\\" (a message related to the API Extractor analysis).\",\n\t\t\t\"patternProperties\": {\n\t\t\t\t\".+\": {\n\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\"description\": \"Configures reporting for a given message identifier.\",\n\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\"logLevel\": {\n\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\"description\": \"Specifies whether the message should be written to the the tool's output log. Note that the \\\"addToApiReportFile\\\" property may supersede this option.\",\n\t\t\t\t\t\t\t\"enum\": [\"error\", \"warning\", \"none\"]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"addToApiReportFile\": {\n\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\"description\": \"If API Extractor is configured to write an API review file (.api.md), then the message will be written inside that file.  If the API review file is NOT being written, then the message is instead logged according to the \\\"logLevel\\\" option.\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"additionalProperties\": false,\n\t\t\t\t\t\"required\": [\"logLevel\"]\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"additionalProperties\": false\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor/src/start.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as os from 'node:os';\nimport process from 'node:process';\nimport colors from 'colors';\nimport { Extractor } from './api/Extractor.js';\nimport { ApiExtractorCommandLine } from './cli/ApiExtractorCommandLine.js';\n\nconsole.log(\n\tos.EOL + colors.bold(`api-extractor ${Extractor.version} ` + colors.cyan(' - https://api-extractor.com/') + os.EOL),\n);\n\nconst parser: ApiExtractorCommandLine = new ApiExtractorCommandLine();\n\n// eslint-disable-next-line promise/prefer-await-to-callbacks\nparser.executeAsync().catch((error) => {\n\tconsole.error(colors.red(`An unexpected error occurred:`), error);\n\tprocess.exit(1);\n});\n"
  },
  {
    "path": "packages/api-extractor/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/api-extractor/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\"node\"],\n\t\t\"isolatedModules\": false,\n\t\t\"outDir\": \"./dist\",\n\t\t\"esModuleInterop\": true\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/api-extractor/tsup.config.ts",
    "content": "import { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tentry: ['src/**/*.ts'],\n\tminify: 'terser',\n\tcjsInterop: true,\n\tnoExternal: ['@microsoft/tsdoc*'],\n});\n"
  },
  {
    "path": "packages/api-extractor-model/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/api-extractor-model/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/api-extractor-model/.npmignore",
    "content": "# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO.\n\n# Ignore all files by default, to avoid accidentally publishing unintended files.\n*\n\n# Use negative patterns to bring back the specific things we want to publish.\n!/bin/**\n!/lib/**\n!/lib-*/**\n!/dist/**\n!ThirdPartyNotice.txt\n\n# Ignore certain patterns that should not get published.\n/dist/*.stats.*\n/lib/**/test/\n/lib-*/**/test/\n*.test.js\n\n# NOTE: These don't need to be specified, because NPM includes them automatically.\n#\n# package.json\n# README (and its variants)\n# CHANGELOG (and its variants)\n# LICENSE / LICENCE\n\n#--------------------------------------------\n# DO NOT MODIFY THE TEMPLATE ABOVE THIS LINE\n#--------------------------------------------\n\n# (Add your project-specific overrides here)"
  },
  {
    "path": "packages/api-extractor-model/.prettierignore",
    "content": ".turbo\ncoverage\ndist\nCHANGELOG.md\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/api-extractor-model/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/api-extractor-model/CHANGELOG.json",
    "content": "{\n\t\"name\": \"@microsoft/api-extractor-model\",\n\t\"entries\": [\n\t\t{\n\t\t\t\"version\": \"7.28.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.28.2\",\n\t\t\t\"date\": \"Thu, 28 Sep 2023 20:53:16 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.61.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.28.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.28.1\",\n\t\t\t\"date\": \"Tue, 26 Sep 2023 09:30:33 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update type-only imports to include the type modifier.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.60.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.28.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.28.0\",\n\t\t\t\"date\": \"Fri, 15 Sep 2023 00:36:58 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update @types/node from 14 to 18\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.60.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.3.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.27.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.27.6\",\n\t\t\t\"date\": \"Tue, 08 Aug 2023 07:10:40 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.3.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.27.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.27.5\",\n\t\t\t\"date\": \"Wed, 19 Jul 2023 00:20:32 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.6`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.27.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.27.4\",\n\t\t\t\"date\": \"Thu, 06 Jul 2023 00:16:20 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.5`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.27.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.27.3\",\n\t\t\t\"date\": \"Thu, 15 Jun 2023 00:21:01 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.3.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.27.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.27.2\",\n\t\t\t\"date\": \"Wed, 07 Jun 2023 22:45:16 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.3.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.27.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.27.1\",\n\t\t\t\"date\": \"Mon, 29 May 2023 15:21:15 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.27.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.27.0\",\n\t\t\t\"date\": \"Mon, 22 May 2023 06:34:32 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade the TypeScript dependency to ~5.0.4\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.3.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.26.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.26.9\",\n\t\t\t\"date\": \"Fri, 12 May 2023 00:23:05 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.59.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.26.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.26.8\",\n\t\t\t\"date\": \"Thu, 04 May 2023 00:20:28 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix a mistake in the documentation for ApiParameterListMixin.overloadIndex\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.26.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.26.7\",\n\t\t\t\"date\": \"Mon, 01 May 2023 15:23:20 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.58.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.26.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.26.6\",\n\t\t\t\"date\": \"Sat, 29 Apr 2023 00:23:03 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.57.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.26.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.26.5\",\n\t\t\t\"date\": \"Thu, 27 Apr 2023 17:18:43 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.56.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.26.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.26.4\",\n\t\t\t\"date\": \"Fri, 10 Feb 2023 01:18:51 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.55.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.2.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.26.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.26.3\",\n\t\t\t\"date\": \"Sun, 05 Feb 2023 03:02:02 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.55.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.26.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.26.2\",\n\t\t\t\"date\": \"Wed, 01 Feb 2023 02:16:34 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.55.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.26.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.26.1\",\n\t\t\t\"date\": \"Mon, 30 Jan 2023 16:22:30 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.54.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.26.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.26.0\",\n\t\t\t\"date\": \"Wed, 25 Jan 2023 07:26:55 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add new .api.json field `isAbstract` to track `abstract` modifier in ApiClass, ApiMethod, and ApiProperty via ApiAbstractMixin (GitHub #3661)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.25.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.25.3\",\n\t\t\t\"date\": \"Fri, 09 Dec 2022 16:18:28 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.53.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.25.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.25.2\",\n\t\t\t\"date\": \"Wed, 26 Oct 2022 00:16:16 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update the @microsoft/tsdoc dependency version to 0.14.2.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.25.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.25.1\",\n\t\t\t\"date\": \"Thu, 13 Oct 2022 00:20:15 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.53.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.25.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.25.0\",\n\t\t\t\"date\": \"Tue, 11 Oct 2022 23:49:12 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add a new fileUrlPath property to relevant API items and serialize this to the .api.json. Additionally, add a SourceFile helper class for constructing file URLs from these paths and the projectFolderUrl.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.24.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.24.4\",\n\t\t\t\"date\": \"Mon, 10 Oct 2022 15:23:44 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.53.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.1.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.24.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.24.3\",\n\t\t\t\"date\": \"Thu, 29 Sep 2022 07:13:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.53.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.1.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.24.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.24.2\",\n\t\t\t\"date\": \"Wed, 21 Sep 2022 20:21:10 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.52.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.24.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.24.1\",\n\t\t\t\"date\": \"Thu, 15 Sep 2022 00:18:52 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.51.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.0.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.24.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.24.0\",\n\t\t\t\"date\": \"Fri, 02 Sep 2022 17:48:42 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add new ApiExportedMixin mixin class for determining whether an API item is exported or not\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.23.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.23.3\",\n\t\t\t\"date\": \"Wed, 24 Aug 2022 03:01:22 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.51.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.23.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.23.2\",\n\t\t\t\"date\": \"Wed, 24 Aug 2022 00:14:38 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Remove use of LegacyAdapters.sortStable\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.51.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.23.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.23.1\",\n\t\t\t\"date\": \"Fri, 19 Aug 2022 00:17:19 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.50.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.23.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.23.0\",\n\t\t\t\"date\": \"Wed, 03 Aug 2022 18:40:35 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade TypeScript dependency to 4.7\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.50.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `3.0.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.22.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.22.2\",\n\t\t\t\"date\": \"Mon, 01 Aug 2022 02:45:32 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.50.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.22.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.22.1\",\n\t\t\t\"date\": \"Thu, 21 Jul 2022 23:30:27 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve IFindApiItemMessage and fix two small bugs with ApiItemContainerMixin.findMembersWithInheritance()\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.22.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.22.0\",\n\t\t\t\"date\": \"Thu, 21 Jul 2022 00:16:14 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add a new ApiItemContainerMixin.findMembersWithInheritance() method for finding an item's inherited members\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.21.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.21.0\",\n\t\t\t\"date\": \"Thu, 30 Jun 2022 04:48:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update model to reflect that index signatures can also be readonly\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.20.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.20.3\",\n\t\t\t\"date\": \"Tue, 28 Jun 2022 22:47:13 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.49.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.20.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.20.2\",\n\t\t\t\"date\": \"Tue, 28 Jun 2022 00:23:32 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.48.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.6.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.20.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.20.1\",\n\t\t\t\"date\": \"Mon, 27 Jun 2022 18:43:09 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.47.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.20.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.20.0\",\n\t\t\t\"date\": \"Sat, 25 Jun 2022 21:00:40 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add a new initializerTokenRange field to ApiProperty and ApiVariable items.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.19.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.19.1\",\n\t\t\t\"date\": \"Sat, 25 Jun 2022 01:54:29 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.46.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.19.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.19.0\",\n\t\t\t\"date\": \"Fri, 24 Jun 2022 07:16:47 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Added new configuration for ItemContainerMixin member ordering\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.18.2\",\n\t\t\t\"date\": \"Fri, 17 Jun 2022 09:17:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.7`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.18.1\",\n\t\t\t\"date\": \"Fri, 17 Jun 2022 00:16:18 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.6.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.18.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.18.0\",\n\t\t\t\"date\": \"Tue, 07 Jun 2022 09:37:04 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add an \\\"isReadonly\\\" field to ApiProperty, ApiPropertySignature, and ApiVariable\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add an \\\"isProtected\\\" field to ApiConstructor, ApiMethod, and ApiProperty\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.17.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.17.3\",\n\t\t\t\"date\": \"Tue, 10 May 2022 01:20:43 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.5`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.17.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.17.2\",\n\t\t\t\"date\": \"Sat, 23 Apr 2022 02:13:07 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.6.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.17.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.17.1\",\n\t\t\t\"date\": \"Fri, 15 Apr 2022 00:12:36 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.5.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.17.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.17.0\",\n\t\t\t\"date\": \"Wed, 13 Apr 2022 15:12:40 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add a new isOptional property to TypeParameters deserialized from the .api.json file with api-extractor-model.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.16.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.16.2\",\n\t\t\t\"date\": \"Tue, 12 Apr 2022 02:58:32 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update TSDoc dependencies.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.16.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.16.1\",\n\t\t\t\"date\": \"Sat, 09 Apr 2022 02:24:26 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Rename the \\\"master\\\" branch to \\\"main\\\".\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update a path in the README.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.5.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.16.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.16.0\",\n\t\t\t\"date\": \"Thu, 31 Mar 2022 02:06:05 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updated api-extractor-model to store whether a parameter is optional.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.15.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.15.4\",\n\t\t\t\"date\": \"Tue, 15 Mar 2022 19:15:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.5.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.15.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.15.3\",\n\t\t\t\"date\": \"Wed, 05 Jan 2022 16:07:47 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.45.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.15.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.15.2\",\n\t\t\t\"date\": \"Mon, 27 Dec 2021 16:10:40 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.44.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.5.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.15.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.15.1\",\n\t\t\t\"date\": \"Thu, 09 Dec 2021 20:34:41 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.44.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.15.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.15.0\",\n\t\t\t\"date\": \"Thu, 09 Dec 2021 00:21:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Replace const enums with conventional enums to allow for compatibility with JavaScript consumers.\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.14.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.14.0\",\n\t\t\t\"date\": \"Wed, 08 Dec 2021 16:14:05 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update to TypeScript 4.5\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.18\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.18\",\n\t\t\t\"date\": \"Mon, 06 Dec 2021 16:08:33 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.44.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.5.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.17\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.17\",\n\t\t\t\"date\": \"Fri, 03 Dec 2021 03:05:22 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.44.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.16\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.16\",\n\t\t\t\"date\": \"Sat, 06 Nov 2021 00:09:13 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.43.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.15\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.15\",\n\t\t\t\"date\": \"Fri, 05 Nov 2021 15:09:18 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.43.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.4.5`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.14\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.14\",\n\t\t\t\"date\": \"Wed, 27 Oct 2021 00:08:15 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update the package.json repository field to include the directory property.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.43.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.4.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.13\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.13\",\n\t\t\t\"date\": \"Wed, 13 Oct 2021 15:09:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.42.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.4.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.12\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.12\",\n\t\t\t\"date\": \"Fri, 08 Oct 2021 08:08:34 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.42.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.11\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.11\",\n\t\t\t\"date\": \"Thu, 07 Oct 2021 07:13:35 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.42.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.4.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.10\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.10\",\n\t\t\t\"date\": \"Tue, 05 Oct 2021 15:08:38 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.42.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.9\",\n\t\t\t\"date\": \"Fri, 24 Sep 2021 00:09:29 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.41.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.8\",\n\t\t\t\"date\": \"Thu, 23 Sep 2021 00:10:40 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade the `@types/node` dependency to version to version 12.\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.40.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.4.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.7\",\n\t\t\t\"date\": \"Tue, 14 Sep 2021 01:17:04 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.40.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.6\",\n\t\t\t\"date\": \"Mon, 13 Sep 2021 15:07:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.40.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.5\",\n\t\t\t\"date\": \"Wed, 11 Aug 2021 00:07:21 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.40.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.4\",\n\t\t\t\"date\": \"Mon, 12 Jul 2021 23:08:26 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.39.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.4.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.3\",\n\t\t\t\"date\": \"Fri, 04 Jun 2021 19:59:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.39.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.2\",\n\t\t\t\"date\": \"Wed, 19 May 2021 00:11:39 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.38.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.1\",\n\t\t\t\"date\": \"Mon, 03 May 2021 15:10:29 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.37.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.13.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.13.0\",\n\t\t\t\"date\": \"Tue, 20 Apr 2021 04:59:51 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"The .api.json file format now stores the TSDoc configuration used for parsing doc comments\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.12.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.12.5\",\n\t\t\t\"date\": \"Mon, 12 Apr 2021 15:10:28 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.36.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.3.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.12.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.12.4\",\n\t\t\t\"date\": \"Thu, 08 Apr 2021 06:05:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix minor typo in README.md\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.12.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.12.3\",\n\t\t\t\"date\": \"Tue, 06 Apr 2021 15:14:22 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.36.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.3.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.12.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.12.2\",\n\t\t\t\"date\": \"Fri, 05 Feb 2021 16:10:42 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.36.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.12.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.12.1\",\n\t\t\t\"date\": \"Thu, 10 Dec 2020 23:25:49 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Enable support for @decorator\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.35.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.3.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.12.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.12.0\",\n\t\t\t\"date\": \"Wed, 18 Nov 2020 08:19:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Introduce an ApiOptionalMixin base class for representing optional properties and methods\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.11.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.11.0\",\n\t\t\t\"date\": \"Wed, 18 Nov 2020 06:21:57 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update .api.json file format to store a new field \\\"isOptional\\\" for documenting optional properties\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.10\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.10.10\",\n\t\t\t\"date\": \"Wed, 11 Nov 2020 01:08:59 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.35.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.3.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.10.9\",\n\t\t\t\"date\": \"Tue, 10 Nov 2020 23:13:12 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.35.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.10.8\",\n\t\t\t\"date\": \"Fri, 30 Oct 2020 06:38:39 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.3.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.10.7\",\n\t\t\t\"date\": \"Fri, 30 Oct 2020 00:10:14 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.2.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.10.6\",\n\t\t\t\"date\": \"Thu, 29 Oct 2020 06:14:19 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix .d.ts error when the library is imported by a project using TypeScript 4.0\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.10.5\",\n\t\t\t\"date\": \"Wed, 28 Oct 2020 01:18:03 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.2.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.10.4\",\n\t\t\t\"date\": \"Tue, 27 Oct 2020 15:10:14 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.10.3\",\n\t\t\t\"date\": \"Tue, 06 Oct 2020 00:24:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.2.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.10.2\",\n\t\t\t\"date\": \"Mon, 05 Oct 2020 22:36:57 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.2.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.10.1\",\n\t\t\t\"date\": \"Wed, 30 Sep 2020 18:39:17 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update to build with @rushstack/heft-node-rig\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.1.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.10.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.10.0\",\n\t\t\t\"date\": \"Wed, 30 Sep 2020 06:53:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update README.md\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade compiler; the API now requires TypeScript 3.9 or newer\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.34.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.1.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.9.7\",\n\t\t\t\"date\": \"Tue, 22 Sep 2020 05:45:57 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.33.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.1.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.9.6\",\n\t\t\t\"date\": \"Tue, 22 Sep 2020 01:45:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.33.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.1.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.9.5\",\n\t\t\t\"date\": \"Tue, 22 Sep 2020 00:08:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.33.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `2.0.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.9.4\",\n\t\t\t\"date\": \"Sat, 19 Sep 2020 04:37:27 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.33.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.4.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.9.3\",\n\t\t\t\"date\": \"Sat, 19 Sep 2020 03:33:07 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.33.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.4.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.9.2\",\n\t\t\t\"date\": \"Fri, 18 Sep 2020 22:57:24 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.33.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.4.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.9.1\",\n\t\t\t\"date\": \"Fri, 18 Sep 2020 21:49:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.33.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.9.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.9.0\",\n\t\t\t\"date\": \"Sun, 13 Sep 2020 01:53:20 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add support for system selectors in declaration references\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.22\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.22\",\n\t\t\t\"date\": \"Fri, 11 Sep 2020 02:13:35 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.32.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.21\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.21\",\n\t\t\t\"date\": \"Mon, 07 Sep 2020 07:37:37 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.31.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.20\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.20\",\n\t\t\t\"date\": \"Sat, 05 Sep 2020 18:56:34 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix \\\"Converting circular structure to JSON\\\" error (GitHub #2152)\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.19\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.19\",\n\t\t\t\"date\": \"Thu, 27 Aug 2020 11:27:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.30.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.3.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.18\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.18\",\n\t\t\t\"date\": \"Mon, 24 Aug 2020 07:35:20 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.29.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.2.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.17\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.17\",\n\t\t\t\"date\": \"Sat, 22 Aug 2020 05:55:43 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.29.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.2.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.16\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.16\",\n\t\t\t\"date\": \"Tue, 18 Aug 2020 23:59:42 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.28.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.15\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.15\",\n\t\t\t\"date\": \"Mon, 17 Aug 2020 04:53:23 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.27.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.1.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.14\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.14\",\n\t\t\t\"date\": \"Wed, 12 Aug 2020 00:10:05 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updated project to build with Heft\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.26.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" to `1.0.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.13\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.13\",\n\t\t\t\"date\": \"Wed, 05 Aug 2020 18:27:33 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" to `3.26.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.12\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.12\",\n\t\t\t\"date\": \"Fri, 03 Jul 2020 15:09:04 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.24.4` to `3.25.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.11\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.11\",\n\t\t\t\"date\": \"Thu, 25 Jun 2020 06:43:35 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.24.3` to `3.24.4`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `1.0.1` to `1.0.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.10\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.10\",\n\t\t\t\"date\": \"Wed, 24 Jun 2020 09:50:48 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.24.2` to `3.24.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `1.0.0` to `1.0.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.9\",\n\t\t\t\"date\": \"Wed, 24 Jun 2020 09:04:28 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.24.1` to `3.24.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.8` to `1.0.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.8\",\n\t\t\t\"date\": \"Wed, 10 Jun 2020 20:48:30 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.24.0` to `3.24.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.7\",\n\t\t\t\"date\": \"Sat, 30 May 2020 02:59:54 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.23.1` to `3.24.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.6\",\n\t\t\t\"date\": \"Thu, 28 May 2020 05:59:02 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.23.0` to `3.23.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.5\",\n\t\t\t\"date\": \"Wed, 27 May 2020 05:15:11 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.22.1` to `3.23.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.7` to `0.5.8`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.4\",\n\t\t\t\"date\": \"Tue, 26 May 2020 23:00:25 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.22.0` to `3.22.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.3\",\n\t\t\t\"date\": \"Fri, 22 May 2020 15:08:43 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.21.0` to `3.22.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.2\",\n\t\t\t\"date\": \"Thu, 21 May 2020 23:09:44 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.20.0` to `3.21.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.1\",\n\t\t\t\"date\": \"Thu, 21 May 2020 15:42:00 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.19.7` to `3.20.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.8.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.8.0\",\n\t\t\t\"date\": \"Wed, 06 May 2020 08:23:45 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Enable canonicalReference to ApiItem lookup\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.11\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.7.11\",\n\t\t\t\"date\": \"Wed, 08 Apr 2020 04:07:33 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.19.6` to `3.19.7`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.6` to `0.5.7`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.10\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.7.10\",\n\t\t\t\"date\": \"Sat, 28 Mar 2020 00:37:16 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade to TSdoc 0.12.19\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.19.5` to `3.19.6`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.5` to `0.5.6`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.9\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.7.9\",\n\t\t\t\"date\": \"Wed, 18 Mar 2020 15:07:47 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade cyclic dependencies\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.19.4` to `3.19.5`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.4` to `0.5.5`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.8\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.7.8\",\n\t\t\t\"date\": \"Tue, 17 Mar 2020 23:55:58 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack`\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/node-core-library\\\" from `3.19.3` to `3.19.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.7\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.7.7\",\n\t\t\t\"date\": \"Tue, 28 Jan 2020 02:23:44 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.19.2` to `3.19.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.7.6\",\n\t\t\t\"date\": \"Thu, 23 Jan 2020 01:07:56 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.19.1` to `3.19.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.7.5\",\n\t\t\t\"date\": \"Tue, 21 Jan 2020 21:56:14 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.19.0` to `3.19.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.3` to `0.5.4`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.7.4\",\n\t\t\t\"date\": \"Sun, 19 Jan 2020 02:26:52 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade Node typings to Node 10\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.18.3` to `3.19.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.2` to `0.5.3`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.7.3\",\n\t\t\t\"date\": \"Fri, 17 Jan 2020 01:08:23 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.18.2` to `3.18.3`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.1` to `0.5.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.7.2\",\n\t\t\t\"date\": \"Thu, 09 Jan 2020 06:44:13 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.18.1` to `3.18.2`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.5.0` to `0.5.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.7.1\",\n\t\t\t\"date\": \"Wed, 08 Jan 2020 00:11:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.18.0` to `3.18.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.4.2` to `0.5.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.7.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.7.0\",\n\t\t\t\"date\": \"Tue, 03 Dec 2019 03:17:43 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve declaration reference syntax to allow linking to overloaded functions/methods\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.6.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.6.0\",\n\t\t\t\"date\": \"Sun, 24 Nov 2019 00:54:04 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Added support for `@throws`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.5.6\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.5.6\",\n\t\t\t\"date\": \"Fri, 15 Nov 2019 04:50:50 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.17.1` to `3.18.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.5.5\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.5.5\",\n\t\t\t\"date\": \"Mon, 11 Nov 2019 16:07:56 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.17.0` to `3.17.1`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.4.1` to `0.4.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.5.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.5.4\",\n\t\t\t\"date\": \"Tue, 05 Nov 2019 06:49:28 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where API reports sometimes were ordered differently depending on the version of NodeJS (GitHub #1552)\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.16.0` to `3.17.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.5.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.5.3\",\n\t\t\t\"date\": \"Tue, 05 Nov 2019 01:08:39 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Clarified an error message\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.5.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.5.2\",\n\t\t\t\"date\": \"Tue, 22 Oct 2019 06:24:44 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Refactor some code as part of migration from TSLint to ESLint\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.15.1` to `3.16.0`\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@rushstack/eslint-config\\\" from `0.4.0` to `0.4.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.5.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.5.1\",\n\t\t\t\"date\": \"Sun, 29 Sep 2019 23:56:29 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update repository URL\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.15.0` to `3.15.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.5.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.5.0\",\n\t\t\t\"date\": \"Wed, 25 Sep 2019 15:15:31 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add ApiItem.getMergedSiblings() API\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.4.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.4.2\",\n\t\t\t\"date\": \"Mon, 23 Sep 2019 15:14:55 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Remove unnecessary dependency on @types/node\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.14.2` to `3.15.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.4.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.4.1\",\n\t\t\t\"date\": \"Tue, 10 Sep 2019 22:32:23 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update documentation\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.14.1` to `3.14.2`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.4.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.4.0\",\n\t\t\t\"date\": \"Tue, 10 Sep 2019 20:38:33 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add 'canonicalReference' to ExcerptToken\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.4\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.3.4\",\n\t\t\t\"date\": \"Wed, 04 Sep 2019 18:28:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.14.0` to `3.14.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.3.3\",\n\t\t\t\"date\": \"Wed, 04 Sep 2019 15:15:37 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Update TSDoc dependency to 0.12.14\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.3.2\",\n\t\t\t\"date\": \"Thu, 08 Aug 2019 15:14:17 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.13.0` to `3.14.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.3.1\",\n\t\t\t\"date\": \"Thu, 08 Aug 2019 00:49:05 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"(Experimental) Add ApiExtractor.canonicalReference which is a beta implementation of the revised TSDoc declaration reference notation\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.3.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.3.0\",\n\t\t\t\"date\": \"Mon, 22 Jul 2019 19:13:10 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Rename `ApiItem.canonicalReference` to `.containerKey`; rename `ApiItemContainerMixin.tryGetMember()` to `.tryGetMemberByKey()`; rename `Api___.getCanonicalReference()` to `.getContainerKey()`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.2.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.2.0\",\n\t\t\t\"date\": \"Tue, 11 Jun 2019 00:48:06 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve the .api.json deserializer to validate the schema version and support backwards compatibility\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add API support for type parameters and type alias types\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.1.3\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.1.3\",\n\t\t\t\"date\": \"Wed, 05 Jun 2019 19:12:34 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where TSDoc index selectors (ApiParameterListMixin.overloadIndex) started from 0, whereas TSDoc requires a nonzero number\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.1.2\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.1.2\",\n\t\t\t\"date\": \"Tue, 04 Jun 2019 05:51:53 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Fix an issue where ApiConstructor inherited from ApiStaticMixin, but TypeScript constructors cannot be static\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.1.1\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.1.1\",\n\t\t\t\"date\": \"Mon, 27 May 2019 04:13:44 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Make the strings returned by ApiItem.displayName less verbose\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Improve formatting of the strings returned by ApiItem.getScopedNameWithinPackage()\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.1.0\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.1.0\",\n\t\t\t\"date\": \"Tue, 16 Apr 2019 11:01:37 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"minor\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Initial stable release of API Extractor 7\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.28\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.0.28\",\n\t\t\t\"date\": \"Wed, 20 Mar 2019 19:14:49 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.12.1` to `3.13.0`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.27\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.0.27\",\n\t\t\t\"date\": \"Mon, 18 Mar 2019 04:28:43 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Add helper functions for ReleaseTag\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Export IApiItemConstructor to eliminate the ae-forgotten-export warning\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"dependency\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Updating dependency \\\"@microsoft/node-core-library\\\" from `3.12.0` to `3.12.1`\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.26\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.0.26\",\n\t\t\t\"date\": \"Wed, 13 Mar 2019 19:13:14 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Refactor code to move the IndentedWriter API from api-extractor-model to api-documenter\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.25\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.0.25\",\n\t\t\t\"date\": \"Wed, 13 Mar 2019 01:14:05 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Upgrade TSDoc\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"version\": \"7.0.24\",\n\t\t\t\"tag\": \"@microsoft/api-extractor-model_v7.0.24\",\n\t\t\t\"date\": \"Mon, 11 Mar 2019 16:13:36 GMT\",\n\t\t\t\"comments\": {\n\t\t\t\t\"patch\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"comment\": \"Initial setup of new package @microsoft/api-extractor-model\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "packages/api-extractor-model/CHANGELOG.md",
    "content": "# Change Log - @microsoft/api-extractor-model\n\nThis log was last generated on Thu, 28 Sep 2023 20:53:16 GMT and should not be manually modified.\n\n## 7.28.2\nThu, 28 Sep 2023 20:53:16 GMT\n\n_Version update only_\n\n## 7.28.1\nTue, 26 Sep 2023 09:30:33 GMT\n\n### Patches\n\n- Update type-only imports to include the type modifier.\n\n## 7.28.0\nFri, 15 Sep 2023 00:36:58 GMT\n\n### Minor changes\n\n- Update @types/node from 14 to 18\n\n## 7.27.6\nTue, 08 Aug 2023 07:10:40 GMT\n\n_Version update only_\n\n## 7.27.5\nWed, 19 Jul 2023 00:20:32 GMT\n\n_Version update only_\n\n## 7.27.4\nThu, 06 Jul 2023 00:16:20 GMT\n\n_Version update only_\n\n## 7.27.3\nThu, 15 Jun 2023 00:21:01 GMT\n\n_Version update only_\n\n## 7.27.2\nWed, 07 Jun 2023 22:45:16 GMT\n\n_Version update only_\n\n## 7.27.1\nMon, 29 May 2023 15:21:15 GMT\n\n_Version update only_\n\n## 7.27.0\nMon, 22 May 2023 06:34:32 GMT\n\n### Minor changes\n\n- Upgrade the TypeScript dependency to ~5.0.4\n\n## 7.26.9\nFri, 12 May 2023 00:23:05 GMT\n\n_Version update only_\n\n## 7.26.8\nThu, 04 May 2023 00:20:28 GMT\n\n### Patches\n\n- Fix a mistake in the documentation for ApiParameterListMixin.overloadIndex\n\n## 7.26.7\nMon, 01 May 2023 15:23:20 GMT\n\n_Version update only_\n\n## 7.26.6\nSat, 29 Apr 2023 00:23:03 GMT\n\n_Version update only_\n\n## 7.26.5\nThu, 27 Apr 2023 17:18:43 GMT\n\n_Version update only_\n\n## 7.26.4\nFri, 10 Feb 2023 01:18:51 GMT\n\n_Version update only_\n\n## 7.26.3\nSun, 05 Feb 2023 03:02:02 GMT\n\n_Version update only_\n\n## 7.26.2\nWed, 01 Feb 2023 02:16:34 GMT\n\n_Version update only_\n\n## 7.26.1\nMon, 30 Jan 2023 16:22:30 GMT\n\n_Version update only_\n\n## 7.26.0\nWed, 25 Jan 2023 07:26:55 GMT\n\n### Minor changes\n\n- Add new .api.json field `isAbstract` to track `abstract` modifier in ApiClass, ApiMethod, and ApiProperty via ApiAbstractMixin (GitHub #3661)\n\n## 7.25.3\nFri, 09 Dec 2022 16:18:28 GMT\n\n_Version update only_\n\n## 7.25.2\nWed, 26 Oct 2022 00:16:16 GMT\n\n### Patches\n\n- Update the @microsoft/tsdoc dependency version to 0.14.2.\n\n## 7.25.1\nThu, 13 Oct 2022 00:20:15 GMT\n\n_Version update only_\n\n## 7.25.0\nTue, 11 Oct 2022 23:49:12 GMT\n\n### Minor changes\n\n- Add a new fileUrlPath property to relevant API items and serialize this to the .api.json. Additionally, add a SourceFile helper class for constructing file URLs from these paths and the projectFolderUrl.\n\n## 7.24.4\nMon, 10 Oct 2022 15:23:44 GMT\n\n_Version update only_\n\n## 7.24.3\nThu, 29 Sep 2022 07:13:06 GMT\n\n_Version update only_\n\n## 7.24.2\nWed, 21 Sep 2022 20:21:10 GMT\n\n_Version update only_\n\n## 7.24.1\nThu, 15 Sep 2022 00:18:52 GMT\n\n_Version update only_\n\n## 7.24.0\nFri, 02 Sep 2022 17:48:42 GMT\n\n### Minor changes\n\n- Add new ApiExportedMixin mixin class for determining whether an API item is exported or not\n\n## 7.23.3\nWed, 24 Aug 2022 03:01:22 GMT\n\n_Version update only_\n\n## 7.23.2\nWed, 24 Aug 2022 00:14:38 GMT\n\n### Patches\n\n- Remove use of LegacyAdapters.sortStable\n\n## 7.23.1\nFri, 19 Aug 2022 00:17:19 GMT\n\n_Version update only_\n\n## 7.23.0\nWed, 03 Aug 2022 18:40:35 GMT\n\n### Minor changes\n\n- Upgrade TypeScript dependency to 4.7\n\n## 7.22.2\nMon, 01 Aug 2022 02:45:32 GMT\n\n_Version update only_\n\n## 7.22.1\nThu, 21 Jul 2022 23:30:27 GMT\n\n### Patches\n\n- Improve IFindApiItemMessage and fix two small bugs with ApiItemContainerMixin.findMembersWithInheritance()\n\n## 7.22.0\nThu, 21 Jul 2022 00:16:14 GMT\n\n### Minor changes\n\n- Add a new ApiItemContainerMixin.findMembersWithInheritance() method for finding an item's inherited members\n\n## 7.21.0\nThu, 30 Jun 2022 04:48:53 GMT\n\n### Minor changes\n\n- Update model to reflect that index signatures can also be readonly\n\n## 7.20.3\nTue, 28 Jun 2022 22:47:13 GMT\n\n_Version update only_\n\n## 7.20.2\nTue, 28 Jun 2022 00:23:32 GMT\n\n_Version update only_\n\n## 7.20.1\nMon, 27 Jun 2022 18:43:09 GMT\n\n_Version update only_\n\n## 7.20.0\nSat, 25 Jun 2022 21:00:40 GMT\n\n### Minor changes\n\n- Add a new initializerTokenRange field to ApiProperty and ApiVariable items.\n\n## 7.19.1\nSat, 25 Jun 2022 01:54:29 GMT\n\n_Version update only_\n\n## 7.19.0\nFri, 24 Jun 2022 07:16:47 GMT\n\n### Minor changes\n\n- Added new configuration for ItemContainerMixin member ordering\n\n## 7.18.2\nFri, 17 Jun 2022 09:17:54 GMT\n\n_Version update only_\n\n## 7.18.1\nFri, 17 Jun 2022 00:16:18 GMT\n\n_Version update only_\n\n## 7.18.0\nTue, 07 Jun 2022 09:37:04 GMT\n\n### Minor changes\n\n- Add an \"isReadonly\" field to ApiProperty, ApiPropertySignature, and ApiVariable\n- Add an \"isProtected\" field to ApiConstructor, ApiMethod, and ApiProperty\n\n## 7.17.3\nTue, 10 May 2022 01:20:43 GMT\n\n_Version update only_\n\n## 7.17.2\nSat, 23 Apr 2022 02:13:07 GMT\n\n_Version update only_\n\n## 7.17.1\nFri, 15 Apr 2022 00:12:36 GMT\n\n_Version update only_\n\n## 7.17.0\nWed, 13 Apr 2022 15:12:40 GMT\n\n### Minor changes\n\n- Add a new isOptional property to TypeParameters deserialized from the .api.json file with api-extractor-model.\n\n## 7.16.2\nTue, 12 Apr 2022 02:58:32 GMT\n\n### Patches\n\n- Update TSDoc dependencies.\n\n## 7.16.1\nSat, 09 Apr 2022 02:24:26 GMT\n\n### Patches\n\n- Rename the \"master\" branch to \"main\".\n- Update a path in the README.\n\n## 7.16.0\nThu, 31 Mar 2022 02:06:05 GMT\n\n### Minor changes\n\n- Updated api-extractor-model to store whether a parameter is optional.\n\n## 7.15.4\nTue, 15 Mar 2022 19:15:53 GMT\n\n_Version update only_\n\n## 7.15.3\nWed, 05 Jan 2022 16:07:47 GMT\n\n_Version update only_\n\n## 7.15.2\nMon, 27 Dec 2021 16:10:40 GMT\n\n_Version update only_\n\n## 7.15.1\nThu, 09 Dec 2021 20:34:41 GMT\n\n_Version update only_\n\n## 7.15.0\nThu, 09 Dec 2021 00:21:54 GMT\n\n### Minor changes\n\n- Replace const enums with conventional enums to allow for compatibility with JavaScript consumers.\n\n## 7.14.0\nWed, 08 Dec 2021 16:14:05 GMT\n\n### Minor changes\n\n- Update to TypeScript 4.5\n\n## 7.13.18\nMon, 06 Dec 2021 16:08:33 GMT\n\n_Version update only_\n\n## 7.13.17\nFri, 03 Dec 2021 03:05:22 GMT\n\n_Version update only_\n\n## 7.13.16\nSat, 06 Nov 2021 00:09:13 GMT\n\n_Version update only_\n\n## 7.13.15\nFri, 05 Nov 2021 15:09:18 GMT\n\n_Version update only_\n\n## 7.13.14\nWed, 27 Oct 2021 00:08:15 GMT\n\n### Patches\n\n- Update the package.json repository field to include the directory property.\n\n## 7.13.13\nWed, 13 Oct 2021 15:09:54 GMT\n\n_Version update only_\n\n## 7.13.12\nFri, 08 Oct 2021 08:08:34 GMT\n\n_Version update only_\n\n## 7.13.11\nThu, 07 Oct 2021 07:13:35 GMT\n\n_Version update only_\n\n## 7.13.10\nTue, 05 Oct 2021 15:08:38 GMT\n\n_Version update only_\n\n## 7.13.9\nFri, 24 Sep 2021 00:09:29 GMT\n\n_Version update only_\n\n## 7.13.8\nThu, 23 Sep 2021 00:10:40 GMT\n\n### Patches\n\n- Upgrade the `@types/node` dependency to version to version 12.\n\n## 7.13.7\nTue, 14 Sep 2021 01:17:04 GMT\n\n_Version update only_\n\n## 7.13.6\nMon, 13 Sep 2021 15:07:06 GMT\n\n_Version update only_\n\n## 7.13.5\nWed, 11 Aug 2021 00:07:21 GMT\n\n_Version update only_\n\n## 7.13.4\nMon, 12 Jul 2021 23:08:26 GMT\n\n_Version update only_\n\n## 7.13.3\nFri, 04 Jun 2021 19:59:53 GMT\n\n_Version update only_\n\n## 7.13.2\nWed, 19 May 2021 00:11:39 GMT\n\n_Version update only_\n\n## 7.13.1\nMon, 03 May 2021 15:10:29 GMT\n\n_Version update only_\n\n## 7.13.0\nTue, 20 Apr 2021 04:59:51 GMT\n\n### Minor changes\n\n- The .api.json file format now stores the TSDoc configuration used for parsing doc comments\n\n## 7.12.5\nMon, 12 Apr 2021 15:10:28 GMT\n\n_Version update only_\n\n## 7.12.4\nThu, 08 Apr 2021 06:05:31 GMT\n\n### Patches\n\n- Fix minor typo in README.md\n\n## 7.12.3\nTue, 06 Apr 2021 15:14:22 GMT\n\n_Version update only_\n\n## 7.12.2\nFri, 05 Feb 2021 16:10:42 GMT\n\n_Version update only_\n\n## 7.12.1\nThu, 10 Dec 2020 23:25:49 GMT\n\n### Patches\n\n- Enable support for @decorator\n\n## 7.12.0\nWed, 18 Nov 2020 08:19:54 GMT\n\n### Minor changes\n\n- Introduce an ApiOptionalMixin base class for representing optional properties and methods\n\n## 7.11.0\nWed, 18 Nov 2020 06:21:57 GMT\n\n### Minor changes\n\n- Update .api.json file format to store a new field \"isOptional\" for documenting optional properties\n\n## 7.10.10\nWed, 11 Nov 2020 01:08:59 GMT\n\n_Version update only_\n\n## 7.10.9\nTue, 10 Nov 2020 23:13:12 GMT\n\n_Version update only_\n\n## 7.10.8\nFri, 30 Oct 2020 06:38:39 GMT\n\n_Version update only_\n\n## 7.10.7\nFri, 30 Oct 2020 00:10:14 GMT\n\n_Version update only_\n\n## 7.10.6\nThu, 29 Oct 2020 06:14:19 GMT\n\n### Patches\n\n- Fix .d.ts error when the library is imported by a project using TypeScript 4.0\n\n## 7.10.5\nWed, 28 Oct 2020 01:18:03 GMT\n\n_Version update only_\n\n## 7.10.4\nTue, 27 Oct 2020 15:10:14 GMT\n\n_Version update only_\n\n## 7.10.3\nTue, 06 Oct 2020 00:24:06 GMT\n\n_Version update only_\n\n## 7.10.2\nMon, 05 Oct 2020 22:36:57 GMT\n\n_Version update only_\n\n## 7.10.1\nWed, 30 Sep 2020 18:39:17 GMT\n\n### Patches\n\n- Update to build with @rushstack/heft-node-rig\n\n## 7.10.0\nWed, 30 Sep 2020 06:53:53 GMT\n\n### Minor changes\n\n- Upgrade compiler; the API now requires TypeScript 3.9 or newer\n\n### Patches\n\n- Update README.md\n\n## 7.9.7\nTue, 22 Sep 2020 05:45:57 GMT\n\n_Version update only_\n\n## 7.9.6\nTue, 22 Sep 2020 01:45:31 GMT\n\n_Version update only_\n\n## 7.9.5\nTue, 22 Sep 2020 00:08:53 GMT\n\n_Version update only_\n\n## 7.9.4\nSat, 19 Sep 2020 04:37:27 GMT\n\n_Version update only_\n\n## 7.9.3\nSat, 19 Sep 2020 03:33:07 GMT\n\n_Version update only_\n\n## 7.9.2\nFri, 18 Sep 2020 22:57:24 GMT\n\n_Version update only_\n\n## 7.9.1\nFri, 18 Sep 2020 21:49:54 GMT\n\n_Version update only_\n\n## 7.9.0\nSun, 13 Sep 2020 01:53:20 GMT\n\n### Minor changes\n\n- Add support for system selectors in declaration references\n\n## 7.8.22\nFri, 11 Sep 2020 02:13:35 GMT\n\n_Version update only_\n\n## 7.8.21\nMon, 07 Sep 2020 07:37:37 GMT\n\n_Version update only_\n\n## 7.8.20\nSat, 05 Sep 2020 18:56:34 GMT\n\n### Patches\n\n- Fix \"Converting circular structure to JSON\" error (GitHub #2152)\n\n## 7.8.19\nThu, 27 Aug 2020 11:27:06 GMT\n\n_Version update only_\n\n## 7.8.18\nMon, 24 Aug 2020 07:35:20 GMT\n\n_Version update only_\n\n## 7.8.17\nSat, 22 Aug 2020 05:55:43 GMT\n\n_Version update only_\n\n## 7.8.16\nTue, 18 Aug 2020 23:59:42 GMT\n\n_Version update only_\n\n## 7.8.15\nMon, 17 Aug 2020 04:53:23 GMT\n\n_Version update only_\n\n## 7.8.14\nWed, 12 Aug 2020 00:10:05 GMT\n\n### Patches\n\n- Updated project to build with Heft\n\n## 7.8.13\nWed, 05 Aug 2020 18:27:33 GMT\n\n_Version update only_\n\n## 7.8.12\nFri, 03 Jul 2020 15:09:04 GMT\n\n_Version update only_\n\n## 7.8.11\nThu, 25 Jun 2020 06:43:35 GMT\n\n_Version update only_\n\n## 7.8.10\nWed, 24 Jun 2020 09:50:48 GMT\n\n_Version update only_\n\n## 7.8.9\nWed, 24 Jun 2020 09:04:28 GMT\n\n_Version update only_\n\n## 7.8.8\nWed, 10 Jun 2020 20:48:30 GMT\n\n_Version update only_\n\n## 7.8.7\nSat, 30 May 2020 02:59:54 GMT\n\n_Version update only_\n\n## 7.8.6\nThu, 28 May 2020 05:59:02 GMT\n\n_Version update only_\n\n## 7.8.5\nWed, 27 May 2020 05:15:11 GMT\n\n_Version update only_\n\n## 7.8.4\nTue, 26 May 2020 23:00:25 GMT\n\n_Version update only_\n\n## 7.8.3\nFri, 22 May 2020 15:08:43 GMT\n\n_Version update only_\n\n## 7.8.2\nThu, 21 May 2020 23:09:44 GMT\n\n_Version update only_\n\n## 7.8.1\nThu, 21 May 2020 15:42:00 GMT\n\n_Version update only_\n\n## 7.8.0\nWed, 06 May 2020 08:23:45 GMT\n\n### Minor changes\n\n- Enable canonicalReference to ApiItem lookup\n\n## 7.7.11\nWed, 08 Apr 2020 04:07:33 GMT\n\n_Version update only_\n\n## 7.7.10\nSat, 28 Mar 2020 00:37:16 GMT\n\n### Patches\n\n- Upgrade to TSdoc 0.12.19\n\n## 7.7.9\nWed, 18 Mar 2020 15:07:47 GMT\n\n### Patches\n\n- Upgrade cyclic dependencies\n\n## 7.7.8\nTue, 17 Mar 2020 23:55:58 GMT\n\n### Patches\n\n- Replace dependencies whose NPM scope was renamed from `@microsoft` to `@rushstack`\n\n## 7.7.7\nTue, 28 Jan 2020 02:23:44 GMT\n\n_Version update only_\n\n## 7.7.6\nThu, 23 Jan 2020 01:07:56 GMT\n\n_Version update only_\n\n## 7.7.5\nTue, 21 Jan 2020 21:56:14 GMT\n\n_Version update only_\n\n## 7.7.4\nSun, 19 Jan 2020 02:26:52 GMT\n\n### Patches\n\n- Upgrade Node typings to Node 10\n\n## 7.7.3\nFri, 17 Jan 2020 01:08:23 GMT\n\n_Version update only_\n\n## 7.7.2\nThu, 09 Jan 2020 06:44:13 GMT\n\n_Version update only_\n\n## 7.7.1\nWed, 08 Jan 2020 00:11:31 GMT\n\n_Version update only_\n\n## 7.7.0\nTue, 03 Dec 2019 03:17:43 GMT\n\n### Minor changes\n\n- Improve declaration reference syntax to allow linking to overloaded functions/methods\n\n## 7.6.0\nSun, 24 Nov 2019 00:54:04 GMT\n\n### Minor changes\n\n- Added support for `@throws`\n\n## 7.5.6\nFri, 15 Nov 2019 04:50:50 GMT\n\n_Version update only_\n\n## 7.5.5\nMon, 11 Nov 2019 16:07:56 GMT\n\n_Version update only_\n\n## 7.5.4\nTue, 05 Nov 2019 06:49:28 GMT\n\n### Patches\n\n- Fix an issue where API reports sometimes were ordered differently depending on the version of NodeJS (GitHub #1552)\n\n## 7.5.3\nTue, 05 Nov 2019 01:08:39 GMT\n\n### Patches\n\n- Clarified an error message\n\n## 7.5.2\nTue, 22 Oct 2019 06:24:44 GMT\n\n### Patches\n\n- Refactor some code as part of migration from TSLint to ESLint\n\n## 7.5.1\nSun, 29 Sep 2019 23:56:29 GMT\n\n### Patches\n\n- Update repository URL\n\n## 7.5.0\nWed, 25 Sep 2019 15:15:31 GMT\n\n### Minor changes\n\n- Add ApiItem.getMergedSiblings() API\n\n## 7.4.2\nMon, 23 Sep 2019 15:14:55 GMT\n\n### Patches\n\n- Remove unnecessary dependency on @types/node\n\n## 7.4.1\nTue, 10 Sep 2019 22:32:23 GMT\n\n### Patches\n\n- Update documentation\n\n## 7.4.0\nTue, 10 Sep 2019 20:38:33 GMT\n\n### Minor changes\n\n- Add 'canonicalReference' to ExcerptToken\n\n## 7.3.4\nWed, 04 Sep 2019 18:28:06 GMT\n\n_Version update only_\n\n## 7.3.3\nWed, 04 Sep 2019 15:15:37 GMT\n\n### Patches\n\n- Update TSDoc dependency to 0.12.14\n\n## 7.3.2\nThu, 08 Aug 2019 15:14:17 GMT\n\n_Version update only_\n\n## 7.3.1\nThu, 08 Aug 2019 00:49:05 GMT\n\n### Patches\n\n- (Experimental) Add ApiExtractor.canonicalReference which is a beta implementation of the revised TSDoc declaration reference notation\n\n## 7.3.0\nMon, 22 Jul 2019 19:13:10 GMT\n\n### Minor changes\n\n- Rename `ApiItem.canonicalReference` to `.containerKey`; rename `ApiItemContainerMixin.tryGetMember()` to `.tryGetMemberByKey()`; rename `Api___.getCanonicalReference()` to `.getContainerKey()`\n\n## 7.2.0\nTue, 11 Jun 2019 00:48:06 GMT\n\n### Minor changes\n\n- Add API support for type parameters and type alias types\n\n### Patches\n\n- Improve the .api.json deserializer to validate the schema version and support backwards compatibility\n\n## 7.1.3\nWed, 05 Jun 2019 19:12:34 GMT\n\n### Patches\n\n- Fix an issue where TSDoc index selectors (ApiParameterListMixin.overloadIndex) started from 0, whereas TSDoc requires a nonzero number\n\n## 7.1.2\nTue, 04 Jun 2019 05:51:53 GMT\n\n### Patches\n\n- Fix an issue where ApiConstructor inherited from ApiStaticMixin, but TypeScript constructors cannot be static\n\n## 7.1.1\nMon, 27 May 2019 04:13:44 GMT\n\n### Patches\n\n- Make the strings returned by ApiItem.displayName less verbose\n- Improve formatting of the strings returned by ApiItem.getScopedNameWithinPackage()\n\n## 7.1.0\nTue, 16 Apr 2019 11:01:37 GMT\n\n### Minor changes\n\n- Initial stable release of API Extractor 7\n\n## 7.0.28\nWed, 20 Mar 2019 19:14:49 GMT\n\n_Version update only_\n\n## 7.0.27\nMon, 18 Mar 2019 04:28:43 GMT\n\n### Patches\n\n- Add helper functions for ReleaseTag\n- Export IApiItemConstructor to eliminate the ae-forgotten-export warning\n\n## 7.0.26\nWed, 13 Mar 2019 19:13:14 GMT\n\n### Patches\n\n- Refactor code to move the IndentedWriter API from api-extractor-model to api-documenter\n\n## 7.0.25\nWed, 13 Mar 2019 01:14:05 GMT\n\n### Patches\n\n- Upgrade TSDoc\n\n## 7.0.24\nMon, 11 Mar 2019 16:13:36 GMT\n\n### Patches\n\n- Initial setup of new package @microsoft/api-extractor-model\n\n"
  },
  {
    "path": "packages/api-extractor-model/LICENSE",
    "content": "@microsoft/api-extractor\n\nCopyright (c) Microsoft Corporation. All rights reserved.\n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "packages/api-extractor-model/README.md",
    "content": "# @discordjs/api-extractor-model\n\nUse this library to read and write \\*.api.json files as defined by the [API Extractor](https://api-extractor.com/) tool.\nThese files are used to generate a documentation website for your TypeScript package. The files store the\nAPI signatures and doc comments that were extracted from your package.\n\nAPI documentation for this package: https://rushstack.io/pages/api/api-extractor-model/\n\n## Example Usage\n\nThe following code sample shows how to load `example.api.json`, which would be generated by API Extractor\nwhen it analyzes a hypothetical NPM package called `example`:\n\n```ts\nimport { ApiModel, ApiPackage } from '@discordjs/api-extractor-model';\n\nconst apiModel: ApiModel = new ApiModel();\nconst apiPackage: ApiPackage = apiModel.loadPackage('example.api.json');\n\nfor (const member of apiPackage.members) {\n\tconsole.log(member.displayName);\n}\n```\n\nThe `ApiModel` is acts as a container for various packages that are loaded and operated on as a group.\nFor example, a documentation tool may need to resolve `@link` references across different packages.\nIn this case we would load the various packages into the `ApiModel`, and then use\nthe `ApiModel.resolveDeclarationReference()` to resolve the `@link` targets.\n\nThe data structure forms a tree of various classes that start with the `Api` prefix. The nesting hierarchy\nmight look like this:\n\n```\n- ApiModel\n  - ApiPackage\n    - ApiEntryPoint\n      - ApiClass\n        - ApiMethod\n        - ApiProperty\n      - ApiEnum\n        - ApiEnumMember\n      - ApiInterface\n        - ApiMethodSignature\n        - ApiPropertySignature\n      - ApiNamespace\n        - (ApiClass, ApiEnum, ApiInterface, ...)\n```\n\nYou can use the `ApiItem.members` property to traverse this tree.\n\nNote that the non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use\nTypeScript \"mixin\" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various\nfeatures that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class\nto extend more than one base class). The \"mixin\" is a TypeScript merged declaration with three components:\nthe function that generates a subclass, an interface that describes the members of the subclass, and\na namespace containing static members of the class.\n\n> For a complete project that uses these APIs to generate an API reference web site,\n> see the [@microsoft/api-documenter](https://www.npmjs.com/package/@microsoft/api-documenter) source code.\n\n## Links\n\n- [CHANGELOG.md](https://github.com/discordjs/discord.js/blob/main/packages/api-extractor-model/CHANGELOG.md) - Find\n  out what's new in the latest version\n- [API Reference](https://rushstack.io/pages/api/api-extractor-model/)\n\nAPI Extractor is part of the [Rush Stack](https://rushstack.io/) family of projects.\n"
  },
  {
    "path": "packages/api-extractor-model/config/api-extractor.json",
    "content": "{\n\t\"$schema\": \"https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json\",\n\n\t\"mainEntryPointFilePath\": \"<projectFolder>/lib/index.d.ts\",\n\n\t\"apiReport\": {\n\t\t\"enabled\": true,\n\t\t\"reportFolder\": \"../../../common/reviews/api\"\n\t},\n\n\t\"docModel\": {\n\t\t\"enabled\": true,\n\t\t\"apiJsonFilePath\": \"../../../common/temp/api/<unscopedPackageName>.api.json\"\n\t},\n\n\t\"dtsRollup\": {\n\t\t\"enabled\": true,\n\t\t\"untrimmedFilePath\": \"<projectFolder>/dist/rollup.d.ts\"\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/package.json",
    "content": "{\n\t\"name\": \"@discordjs/api-extractor-model\",\n\t\"version\": \"7.30.6\",\n\t\"description\": \"A helper library for loading and saving the .api.json files created by API Extractor\",\n\t\"private\": true,\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/api-extractor-model\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"license\": \"MIT\",\n\t\"main\": \"./dist/index.js\",\n\t\"types\": \"./dist/index.d.ts\",\n\t\"scripts\": {\n\t\t\"build\": \"tsc --noEmit && tsup\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"dependencies\": {\n\t\t\"@microsoft/tsdoc\": \"~0.15.1\",\n\t\t\"@microsoft/tsdoc-config\": \"~0.17.1\",\n\t\t\"@rushstack/node-core-library\": \"5.13.1\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@types/node\": \"^24.10.13\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"terser\": \"^5.46.0\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\"\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/aedoc/AedocDefinitions.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { TSDocConfiguration, TSDocTagDefinition, TSDocTagSyntaxKind, StandardTags } from '@microsoft/tsdoc';\n\n/**\n * @internal\n * @deprecated - tsdoc configuration is now constructed from tsdoc.json files associated with each package.\n */\nexport class AedocDefinitions {\n\tpublic static readonly betaDocumentation: TSDocTagDefinition = new TSDocTagDefinition({\n\t\ttagName: '@betaDocumentation',\n\t\tsyntaxKind: TSDocTagSyntaxKind.ModifierTag,\n\t});\n\n\tpublic static readonly internalRemarks: TSDocTagDefinition = new TSDocTagDefinition({\n\t\ttagName: '@internalRemarks',\n\t\tsyntaxKind: TSDocTagSyntaxKind.BlockTag,\n\t});\n\n\tpublic static readonly preapprovedTag: TSDocTagDefinition = new TSDocTagDefinition({\n\t\ttagName: '@preapproved',\n\t\tsyntaxKind: TSDocTagSyntaxKind.ModifierTag,\n\t});\n\n\tpublic static get tsdocConfiguration(): TSDocConfiguration {\n\t\tif (!AedocDefinitions._tsdocConfiguration) {\n\t\t\tconst configuration: TSDocConfiguration = new TSDocConfiguration();\n\t\t\tconfiguration.addTagDefinitions(\n\t\t\t\t[AedocDefinitions.betaDocumentation, AedocDefinitions.internalRemarks, AedocDefinitions.preapprovedTag],\n\t\t\t\ttrue,\n\t\t\t);\n\n\t\t\tconfiguration.setSupportForTags(\n\t\t\t\t[\n\t\t\t\t\tStandardTags.alpha,\n\t\t\t\t\tStandardTags.beta,\n\t\t\t\t\tStandardTags.decorator,\n\t\t\t\t\tStandardTags.defaultValue,\n\t\t\t\t\tStandardTags.deprecated,\n\t\t\t\t\tStandardTags.eventProperty,\n\t\t\t\t\tStandardTags.example,\n\t\t\t\t\tStandardTags.inheritDoc,\n\t\t\t\t\tStandardTags.internal,\n\t\t\t\t\tStandardTags.link,\n\t\t\t\t\tStandardTags.override,\n\t\t\t\t\tStandardTags.packageDocumentation,\n\t\t\t\t\tStandardTags.param,\n\t\t\t\t\tStandardTags.privateRemarks,\n\t\t\t\t\tStandardTags.public,\n\t\t\t\t\tStandardTags.readonly,\n\t\t\t\t\tStandardTags.remarks,\n\t\t\t\t\tStandardTags.returns,\n\t\t\t\t\tStandardTags.sealed,\n\t\t\t\t\tStandardTags.throws,\n\t\t\t\t\tStandardTags.virtual,\n\t\t\t\t],\n\t\t\t\ttrue,\n\t\t\t);\n\n\t\t\tAedocDefinitions._tsdocConfiguration = configuration;\n\t\t}\n\n\t\treturn AedocDefinitions._tsdocConfiguration;\n\t}\n\n\tprivate static _tsdocConfiguration: TSDocConfiguration | undefined;\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/aedoc/ReleaseTag.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * A \"release tag\" is a custom TSDoc tag that is applied to an API to communicate the level of support\n * provided for third-party developers.\n *\n * @remarks\n *\n * The four release tags are: `@internal`, `@alpha`, `@beta`, and `@public`. They are applied to API items such\n * as classes, member functions, enums, etc.  The release tag applies recursively to members of a container\n * (e.g. class or interface). For example, if a class is marked as `@beta`, then all of its members automatically\n * have this status; you DON'T need add the `@beta` tag to each member function. However, you could add\n * `@internal` to a member function to give it a different release status.\n * @public\n */\nexport enum ReleaseTag {\n\t/**\n\t * No release tag was specified in the AEDoc summary.\n\t */\n\tNone = 0,\n\t/**\n\t * Indicates that an API item is meant only for usage by other NPM packages from the same\n\t * maintainer. Third parties should never use \"internal\" APIs. (To emphasize this, their\n\t * names are prefixed by underscores.)\n\t */\n\tInternal = 1,\n\t/**\n\t * Indicates that an API item is eventually intended to be public, but currently is in an\n\t * early stage of development. Third parties should not use \"alpha\" APIs.\n\t */\n\tAlpha = 2,\n\t/**\n\t * Indicates that an API item has been released in an experimental state. Third parties are\n\t * encouraged to try it and provide feedback. However, a \"beta\" API should NOT be used\n\t * in production.\n\t */\n\tBeta = 3,\n\t/**\n\t * Indicates that an API item has been officially released. It is part of the supported\n\t * contract (e.g. SemVer) for a package.\n\t */\n\tPublic = 4,\n}\n\n/**\n * Helper functions for working with the `ReleaseTag` enum.\n *\n * @public\n */\n\n// export namespace ReleaseTag {\n/**\n * Returns the TSDoc tag name for a `ReleaseTag` value.\n *\n * @remarks\n * For example, `getTagName(ReleaseTag.Internal)` would return the string `@internal`.\n */\nexport function getTagName(releaseTag: ReleaseTag): string {\n\tswitch (releaseTag) {\n\t\tcase ReleaseTag.None:\n\t\t\treturn '(none)';\n\t\tcase ReleaseTag.Internal:\n\t\t\treturn '@internal';\n\t\tcase ReleaseTag.Alpha:\n\t\t\treturn '@alpha';\n\t\tcase ReleaseTag.Beta:\n\t\t\treturn '@beta';\n\t\tcase ReleaseTag.Public:\n\t\t\treturn '@public';\n\t\tdefault:\n\t\t\tthrow new Error('Unsupported release tag');\n\t}\n}\n\n/**\n * Compares two `ReleaseTag` values. Their values must not be `ReleaseTag.None`.\n *\n * @returns 0 if `a` and `b` are equal, a positive number if `a` is more public than `b`,\n * and a negative number if `a` is less public than `b`.\n * @remarks\n * For example, `compareReleaseTag(ReleaseTag.Beta, ReleaseTag.Alpha)` will return a positive\n * number because beta is more public than alpha.\n */\nexport function compare(a: ReleaseTag, b: ReleaseTag): number {\n\treturn a - b;\n}\n// }\n"
  },
  {
    "path": "packages/api-extractor-model/src/index.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * Use this library to read and write *.api.json files as defined by the\n * {@link https://api-extractor.com/ | API Extractor}  tool.  These files are used to generate a documentation\n * website for your TypeScript package.  The files store the API signatures and doc comments that were extracted\n * from your package.\n *\n * @packageDocumentation\n */\n\nexport { AedocDefinitions } from './aedoc/AedocDefinitions.js';\nexport { ReleaseTag, compare as releaseTagCompare, getTagName as releaseTagGetTagName } from './aedoc/ReleaseTag.js';\n\n// items\nexport { type IApiDeclaredItemOptions, ApiDeclaredItem } from './items/ApiDeclaredItem.js';\nexport { type IApiDocumentedItemOptions, ApiDocumentedItem } from './items/ApiDocumentedItem.js';\nexport { ApiItemKind, type IApiItemOptions, ApiItem, type IApiItemConstructor } from './items/ApiItem.js';\nexport { type IApiPropertyItemOptions, ApiPropertyItem } from './items/ApiPropertyItem.js';\n\n// mixins\nexport {\n\ttype IApiParameterListMixinOptions,\n\ttype IApiParameterOptions,\n\tApiParameterListMixin,\n} from './mixins/ApiParameterListMixin.js';\nexport {\n\ttype IApiTypeParameterOptions,\n\ttype IApiTypeParameterListMixinOptions,\n\tApiTypeParameterListMixin,\n} from './mixins/ApiTypeParameterListMixin.js';\nexport { type IApiAbstractMixinOptions, ApiAbstractMixin } from './mixins/ApiAbstractMixin.js';\nexport { type IApiItemContainerMixinOptions, ApiItemContainerMixin } from './mixins/ApiItemContainerMixin.js';\nexport { type IApiProtectedMixinOptions, ApiProtectedMixin } from './mixins/ApiProtectedMixin.js';\nexport { type IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from './mixins/ApiReleaseTagMixin.js';\nexport { type IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from './mixins/ApiReturnTypeMixin.js';\nexport { type IApiStaticMixinOptions, ApiStaticMixin } from './mixins/ApiStaticMixin.js';\nexport { type IApiNameMixinOptions, ApiNameMixin } from './mixins/ApiNameMixin.js';\nexport { type IApiOptionalMixinOptions, ApiOptionalMixin } from './mixins/ApiOptionalMixin.js';\nexport { type IApiReadonlyMixinOptions, ApiReadonlyMixin } from './mixins/ApiReadonlyMixin.js';\nexport { type IApiInitializerMixinOptions, ApiInitializerMixin } from './mixins/ApiInitializerMixin.js';\nexport { type IApiExportedMixinOptions, ApiExportedMixin } from './mixins/ApiExportedMixin.js';\nexport {\n\ttype IFindApiItemsResult,\n\ttype IFindApiItemsMessage,\n\tFindApiItemsMessageId,\n} from './mixins/IFindApiItemsResult.js';\n\nexport {\n\tExcerptTokenKind,\n\ttype IExcerptTokenRange,\n\ttype IExcerptToken,\n\tExcerptToken,\n\tExcerpt,\n} from './mixins/Excerpt.js';\nexport type { Constructor, PropertiesOf } from './mixins/Mixin.js';\n\n// model\nexport { type IApiCallSignatureOptions, ApiCallSignature } from './model/ApiCallSignature.js';\nexport { type IApiClassOptions, ApiClass, type IExcerptTokenRangeWithTypeParameters } from './model/ApiClass.js';\nexport { type IApiConstructorOptions, ApiConstructor } from './model/ApiConstructor.js';\nexport { type IApiConstructSignatureOptions, ApiConstructSignature } from './model/ApiConstructSignature.js';\nexport { type IApiEntryPointOptions, ApiEntryPoint } from './model/ApiEntryPoint.js';\nexport { type IApiEnumOptions, ApiEnum } from './model/ApiEnum.js';\nexport { type IApiEnumMemberOptions, ApiEnumMember, EnumMemberOrder } from './model/ApiEnumMember.js';\nexport { type IApiEventOptions, ApiEvent } from './model/ApiEvent.js';\nexport { type IApiFunctionOptions, ApiFunction } from './model/ApiFunction.js';\nexport { type IApiIndexSignatureOptions, ApiIndexSignature } from './model/ApiIndexSignature.js';\nexport { type IApiInterfaceOptions, ApiInterface } from './model/ApiInterface.js';\nexport { type IApiMethodOptions, ApiMethod } from './model/ApiMethod.js';\nexport { type IApiMethodSignatureOptions, ApiMethodSignature } from './model/ApiMethodSignature.js';\nexport { ApiModel } from './model/ApiModel.js';\nexport { type IApiNamespaceOptions, ApiNamespace } from './model/ApiNamespace.js';\nexport { type IApiPackageOptions, ApiPackage, type IApiPackageSaveOptions } from './model/ApiPackage.js';\nexport { type IParameterOptions, Parameter } from './model/Parameter.js';\nexport { type IApiPropertyOptions, ApiProperty } from './model/ApiProperty.js';\nexport { type IApiPropertySignatureOptions, ApiPropertySignature } from './model/ApiPropertySignature.js';\nexport { type IApiTypeAliasOptions, ApiTypeAlias } from './model/ApiTypeAlias.js';\nexport { type ITypeParameterOptions, TypeParameter } from './model/TypeParameter.js';\nexport { type IApiVariableOptions, ApiVariable } from './model/ApiVariable.js';\nexport type { IResolveDeclarationReferenceResult } from './model/ModelReferenceResolver.js';\nexport { HeritageType } from './model/HeritageType.js';\nexport { type ISourceLocationOptions, SourceLocation } from './model/SourceLocation.js';\nexport { Navigation, Meaning } from './items/ApiItem.js';\n"
  },
  {
    "path": "packages/api-extractor-model/src/items/ApiDeclaredItem.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { Excerpt, ExcerptToken, type IExcerptTokenRange, type IExcerptToken } from '../mixins/Excerpt.js';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\nimport { SourceLocation } from '../model/SourceLocation.js';\nimport { ApiDocumentedItem, type IApiDocumentedItemJson, type IApiDocumentedItemOptions } from './ApiDocumentedItem.js';\nimport type { ApiItem } from './ApiItem.js';\n\n/**\n * Constructor options for {@link ApiDeclaredItem}.\n *\n * @public\n */\nexport interface IApiDeclaredItemOptions extends IApiDocumentedItemOptions {\n\texcerptTokens: IExcerptToken[];\n\tfileColumn?: number | undefined;\n\tfileLine?: number | undefined;\n\tfileUrlPath?: string | undefined;\n}\n\nexport interface IApiDeclaredItemJson extends IApiDocumentedItemJson {\n\texcerptTokens: IExcerptToken[];\n\tfileColumn?: number;\n\tfileLine?: number;\n\tfileUrlPath?: string | undefined;\n}\n\n/**\n * The base class for API items that have an associated source code excerpt containing a TypeScript declaration.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * Most `ApiItem` subclasses have declarations and thus extend `ApiDeclaredItem`.  Counterexamples include\n * `ApiModel` and `ApiPackage`, which do not have any corresponding TypeScript source code.\n * @public\n */\n\nexport class ApiDeclaredItem extends ApiDocumentedItem {\n\tprivate readonly _excerptTokens: ExcerptToken[];\n\n\tprivate readonly _excerpt: Excerpt;\n\n\tprivate readonly _fileUrlPath?: string | undefined;\n\n\tprivate readonly _fileLine?: number | undefined;\n\n\tprivate readonly _fileColumn?: number | undefined;\n\n\tprivate _sourceLocation?: SourceLocation;\n\n\tpublic constructor(options: IApiDeclaredItemOptions) {\n\t\tsuper(options);\n\n\t\tthis._excerptTokens = options.excerptTokens.map((token) => {\n\t\t\tconst canonicalReference: DeclarationReference | undefined =\n\t\t\t\ttoken.canonicalReference === undefined ? undefined : DeclarationReference.parse(token.canonicalReference);\n\t\t\treturn new ExcerptToken(token.kind, token.text, canonicalReference);\n\t\t});\n\t\tthis._excerpt = new Excerpt(this.excerptTokens, { startIndex: 0, endIndex: this.excerptTokens.length });\n\t\tthis._fileUrlPath = options.fileUrlPath;\n\t\tthis._fileLine = options.fileLine;\n\t\tthis._fileColumn = options.fileColumn;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic static override onDeserializeInto(\n\t\toptions: Partial<IApiDeclaredItemOptions>,\n\t\tcontext: DeserializerContext,\n\t\tjsonObject: IApiDeclaredItemJson,\n\t): void {\n\t\tsuper.onDeserializeInto(options, context, jsonObject);\n\n\t\toptions.excerptTokens = jsonObject.excerptTokens;\n\t\toptions.fileUrlPath = jsonObject.fileUrlPath;\n\t\toptions.fileLine = jsonObject.fileLine;\n\t\toptions.fileColumn = jsonObject.fileColumn;\n\t}\n\n\t/**\n\t * The source code excerpt where the API item is declared.\n\t */\n\tpublic get excerpt(): Excerpt {\n\t\treturn this._excerpt;\n\t}\n\n\t/**\n\t * The individual source code tokens that comprise the main excerpt.\n\t */\n\tpublic get excerptTokens(): readonly ExcerptToken[] {\n\t\treturn this._excerptTokens;\n\t}\n\n\t/**\n\t * The file URL path relative to the `projectFolder` and `projectFolderURL` fields\n\t * as defined in the `api-extractor.json` config. Is `undefined` if the path is\n\t * the same as the parent API item's.\n\t */\n\tpublic get fileUrlPath(): string | undefined {\n\t\treturn this._fileUrlPath;\n\t}\n\n\t/**\n\t * The line in the `fileUrlPath` where the API item is declared.\n\t */\n\tpublic get fileLine(): number | undefined {\n\t\treturn this._fileLine;\n\t}\n\n\t/**\n\t * The column in the `fileUrlPath` where the API item is declared.\n\t */\n\tpublic get fileColumn(): number | undefined {\n\t\treturn this._fileColumn;\n\t}\n\n\t/**\n\t * Returns the source location where the API item is declared.\n\t */\n\tpublic get sourceLocation(): SourceLocation {\n\t\tif (!this._sourceLocation) {\n\t\t\tthis._sourceLocation = this._buildSourceLocation();\n\t\t}\n\n\t\treturn this._sourceLocation;\n\t}\n\n\t/**\n\t * If the API item has certain important modifier tags such as `@sealed`, `@virtual`, or `@override`,\n\t * this prepends them as a doc comment above the excerpt.\n\t */\n\tpublic getExcerptWithModifiers(): string {\n\t\tconst excerpt: string = this.excerpt.text;\n\t\tconst modifierTags: string[] = [];\n\n\t\tif (excerpt.length > 0 && this instanceof ApiDocumentedItem) {\n\t\t\tif (this.tsdocComment) {\n\t\t\t\tif (this.tsdocComment.modifierTagSet.isSealed()) {\n\t\t\t\t\tmodifierTags.push('@sealed');\n\t\t\t\t}\n\n\t\t\t\tif (this.tsdocComment.modifierTagSet.isVirtual()) {\n\t\t\t\t\tmodifierTags.push('@virtual');\n\t\t\t\t}\n\n\t\t\t\tif (this.tsdocComment.modifierTagSet.isOverride()) {\n\t\t\t\t\tmodifierTags.push('@override');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (modifierTags.length > 0) {\n\t\t\t\treturn '/** ' + modifierTags.join(' ') + ' */\\n' + excerpt;\n\t\t\t}\n\t\t}\n\n\t\treturn excerpt;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override serializeInto(jsonObject: Partial<IApiDeclaredItemJson>): void {\n\t\tsuper.serializeInto(jsonObject);\n\t\tjsonObject.excerptTokens = this.excerptTokens.map((x) => {\n\t\t\tconst excerptToken: IExcerptToken = { kind: x.kind, text: x.text };\n\t\t\tif (x.canonicalReference !== undefined) {\n\t\t\t\texcerptToken.canonicalReference = x.canonicalReference.toString();\n\t\t\t}\n\n\t\t\treturn excerptToken;\n\t\t});\n\n\t\t// Only serialize this API item's file URL path if it exists and it's different from its parent's\n\t\t// (a little optimization to keep the doc model succinct).\n\t\tif (\n\t\t\tthis.fileUrlPath &&\n\t\t\t(!(this.parent instanceof ApiDeclaredItem) || this.fileUrlPath !== this.parent.fileUrlPath)\n\t\t) {\n\t\t\tjsonObject.fileUrlPath = this.fileUrlPath;\n\t\t}\n\n\t\tif (this.fileLine) {\n\t\t\tjsonObject.fileLine = this.fileLine;\n\t\t}\n\n\t\tif (this.fileColumn) {\n\t\t\tjsonObject.fileColumn = this.fileColumn;\n\t\t}\n\t}\n\n\t/**\n\t * Constructs a new {@link Excerpt} corresponding to the provided token range.\n\t */\n\tpublic buildExcerpt(tokenRange: IExcerptTokenRange): Excerpt {\n\t\treturn new Excerpt(this.excerptTokens, tokenRange);\n\t}\n\n\t/**\n\t * Builds the cached object used by the `sourceLocation` property.\n\t */\n\tprivate _buildSourceLocation(): SourceLocation {\n\t\tconst projectFolderUrl: string | undefined = this.getAssociatedPackage()?.projectFolderUrl;\n\n\t\tlet fileUrlPath: string | undefined;\n\t\tfor (let current: ApiItem | undefined = this; current !== undefined; current = current.parent) {\n\t\t\tif (current instanceof ApiDeclaredItem && current.fileUrlPath) {\n\t\t\t\tfileUrlPath = current.fileUrlPath;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn new SourceLocation({\n\t\t\tprojectFolderUrl,\n\t\t\tfileUrlPath,\n\t\t\tsourceFileColumn: this.fileColumn,\n\t\t\tsourceFileLine: this.fileLine,\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/items/ApiDocumentedItem.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as tsdoc from '@microsoft/tsdoc';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\nimport { ApiItem, type IApiItemOptions, type IApiItemJson } from './ApiItem.js';\n\n/**\n * Constructor options for {@link ApiDocumentedItem}.\n *\n * @public\n */\nexport interface IApiDocumentedItemOptions extends IApiItemOptions {\n\tdocComment: tsdoc.DocComment | undefined;\n}\n\nexport interface IApiDocumentedItemJson extends IApiItemJson {\n\tdocComment: string;\n}\n\n/**\n * An abstract base class for API declarations that can have an associated TSDoc comment.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n * @public\n */\nexport class ApiDocumentedItem extends ApiItem {\n\tprivate readonly _tsdocComment: tsdoc.DocComment | undefined;\n\n\tpublic constructor(options: IApiDocumentedItemOptions) {\n\t\tsuper(options);\n\t\tthis._tsdocComment = options.docComment;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic static override onDeserializeInto(\n\t\toptions: Partial<IApiDocumentedItemOptions>,\n\t\tcontext: DeserializerContext,\n\t\tjsonObject: IApiItemJson,\n\t): void {\n\t\tsuper.onDeserializeInto(options, context, jsonObject);\n\n\t\tconst documentedJson: IApiDocumentedItemJson = jsonObject as IApiDocumentedItemJson;\n\n\t\tif (documentedJson.docComment) {\n\t\t\tconst tsdocParser: tsdoc.TSDocParser = new tsdoc.TSDocParser(context.tsdocConfiguration);\n\n\t\t\t// NOTE: For now, we ignore TSDoc errors found in a serialized .api.json file.\n\t\t\t// Normally these errors would have already been reported by API Extractor during analysis.\n\t\t\t// However, they could also arise if the JSON file was edited manually, or if the file was saved\n\t\t\t// using a different release of the software that used an incompatible syntax.\n\t\t\tconst parserContext: tsdoc.ParserContext = tsdocParser.parseString(documentedJson.docComment);\n\n\t\t\toptions.docComment = parserContext.docComment;\n\t\t}\n\t}\n\n\tpublic get tsdocComment(): tsdoc.DocComment | undefined {\n\t\treturn this._tsdocComment;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override serializeInto(jsonObject: Partial<IApiDocumentedItemJson>): void {\n\t\tsuper.serializeInto(jsonObject);\n\t\tif (this.tsdocComment === undefined) {\n\t\t\tjsonObject.docComment = '';\n\t\t} else {\n\t\t\tjsonObject.docComment = this.tsdocComment.emitAsTsdoc();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/items/ApiItem.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { InternalError } from '@rushstack/node-core-library';\nimport { ApiItemContainerMixin } from '../mixins/ApiItemContainerMixin.js';\nimport { ApiParameterListMixin } from '../mixins/ApiParameterListMixin.js';\nimport type { Constructor, PropertiesOf } from '../mixins/Mixin.js';\nimport type { ApiEntryPoint } from '../model/ApiEntryPoint.js';\nimport type { ApiModel } from '../model/ApiModel.js';\nimport type { ApiPackage } from '../model/ApiPackage.js';\nimport type { DocgenJson } from '../model/Deserializer';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\n\n/**\n * The type returned by the {@link ApiItem.kind} property, which can be used to easily distinguish subclasses of\n * {@link ApiItem}.\n *\n * @public\n */\nexport enum ApiItemKind {\n\tCallSignature = 'CallSignature',\n\tClass = 'Class',\n\tConstructSignature = 'ConstructSignature',\n\tConstructor = 'Constructor',\n\tEntryPoint = 'EntryPoint',\n\tEnum = 'Enum',\n\tEnumMember = 'EnumMember',\n\tEvent = 'Event',\n\tFunction = 'Function',\n\tIndexSignature = 'IndexSignature',\n\tInterface = 'Interface',\n\tMethod = 'Method',\n\tMethodSignature = 'MethodSignature',\n\tModel = 'Model',\n\tNamespace = 'Namespace',\n\tNone = 'None',\n\tPackage = 'Package',\n\tProperty = 'Property',\n\tPropertySignature = 'PropertySignature',\n\tTypeAlias = 'TypeAlias',\n\tVariable = 'Variable',\n}\n/**\n * Indicates the symbol table from which to resolve the next symbol component.\n *\n * @beta\n */\nexport enum Navigation {\n\tExports = '.',\n\tLocals = '~',\n\tMembers = '#',\n}\n/**\n * @beta\n */\nexport enum Meaning {\n\tCallSignature = 'call',\n\tClass = 'class',\n\tComplexType = 'complex',\n\tConstructSignature = 'new',\n\tConstructor = 'constructor',\n\tEnum = 'enum',\n\tEvent = 'event',\n\tFunction = 'function',\n\tIndexSignature = 'index',\n\tInterface = 'interface',\n\tMember = 'member',\n\tNamespace = 'namespace',\n\tTypeAlias = 'type',\n\tVariable = 'var',\n}\n\n/**\n * Constructor options for {@link ApiItem}.\n *\n * @public\n */\nexport interface IApiItemOptions {}\n\nexport interface IApiItemJson {\n\tcanonicalReference: string;\n\tkind: ApiItemKind;\n}\n\n// PRIVATE - Allows ApiItemContainerMixin to assign the parent.\n//\nexport const apiItem_onParentChanged: unique symbol = Symbol('ApiItem._onAddToContainer');\n\n/**\n * The abstract base class for all members of an `ApiModel` object.\n *\n * @remarks\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n * @public\n */\nexport class ApiItem {\n\tprivate _canonicalReference: DeclarationReference | undefined;\n\n\tprivate _parent: ApiItem | undefined;\n\n\t// eslint-disable-next-line @typescript-eslint/no-useless-constructor\n\tpublic constructor(_options: IApiItemOptions) {\n\t\t// (\"options\" is not used here, but part of the inheritance pattern)\n\t}\n\n\tpublic static deserialize(jsonObject: IApiItemJson, context: DeserializerContext): ApiItem {\n\t\t// The Deserializer class is coupled with a ton of other classes, so  we delay loading it\n\t\t// to avoid ES5 circular imports.\n\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-imports, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n\t\tconst deserializerModule: typeof import('../model/Deserializer') = require('../model/Deserializer');\n\t\treturn deserializerModule.Deserializer.deserialize(context, jsonObject);\n\t}\n\n\tpublic static deserializeDocgen(jsonObject: DocgenJson, _package: string): ApiItem {\n\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-imports, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n\t\tconst deserializerModule: typeof import('../model/Deserializer') = require('../model/Deserializer');\n\t\treturn deserializerModule.Deserializer.deserializeDocgen(jsonObject, _package);\n\t}\n\n\t/**\n\t * @virtual\n\t */\n\tpublic static onDeserializeInto(\n\t\t_options: Partial<IApiItemOptions>,\n\t\t_context: DeserializerContext,\n\t\t_jsonObject: IApiItemJson,\n\t): void {\n\t\t// (implemented by subclasses)\n\t}\n\n\t/**\n\t * @virtual\n\t */\n\tpublic serializeInto(jsonObject: Partial<IApiItemJson>): void {\n\t\tjsonObject.kind = this.kind;\n\t\tjsonObject.canonicalReference = this.canonicalReference.toString();\n\t}\n\n\t/**\n\t * Identifies the subclass of the `ApiItem` base class.\n\t *\n\t * @virtual\n\t */\n\tpublic get kind(): ApiItemKind {\n\t\tthrow new Error('ApiItem.kind was not implemented by the child class');\n\t}\n\n\t/**\n\t * Warning: This API is used internally by API extractor but is not yet ready for general usage.\n\t *\n\t * @remarks\n\t *\n\t * Returns a `DeclarationReference` object using the experimental new declaration reference notation.\n\t * @beta\n\t */\n\tpublic get canonicalReference(): DeclarationReference {\n\t\tif (!this._canonicalReference) {\n\t\t\ttry {\n\t\t\t\tthis._canonicalReference = this.buildCanonicalReference();\n\t\t\t} catch (error) {\n\t\t\t\tconst name: string = this.getScopedNameWithinPackage() || this.displayName;\n\t\t\t\tthrow new InternalError(`Error building canonical reference for ${name}:\\n` + (error as Error).message);\n\t\t\t}\n\t\t}\n\n\t\treturn this._canonicalReference;\n\t}\n\n\t/**\n\t * Returns a string key that can be used to efficiently retrieve an `ApiItem` from an `ApiItemContainerMixin`.\n\t * The key is unique within the container.  Its format is undocumented and may change at any time.\n\t *\n\t * @remarks\n\t * Use the `getContainerKey()` static member to construct the key.  Each subclass has a different implementation\n\t * of this function, according to the aspects that are important for identifying it.\n\t * @virtual\n\t */\n\tpublic get containerKey(): string {\n\t\tthrow new InternalError('ApiItem.containerKey was not implemented by the child class');\n\t}\n\n\t/**\n\t * Returns a name for this object that can be used in diagnostic messages, for example.\n\t *\n\t * @remarks\n\t * For an object that inherits ApiNameMixin, this will return the declared name (e.g. the name of a TypeScript\n\t * function).  Otherwise, it will return a string such as \"(call signature)\" or \"(model)\".\n\t * @virtual\n\t */\n\tpublic get displayName(): string {\n\t\tswitch (this.kind) {\n\t\t\tcase ApiItemKind.CallSignature:\n\t\t\t\treturn '(call)';\n\t\t\tcase ApiItemKind.Constructor:\n\t\t\t\treturn '(constructor)';\n\t\t\tcase ApiItemKind.ConstructSignature:\n\t\t\t\treturn '(new)';\n\t\t\tcase ApiItemKind.IndexSignature:\n\t\t\t\treturn '(indexer)';\n\t\t\tcase ApiItemKind.Model:\n\t\t\t\treturn '(model)';\n\t\t\tdefault:\n\t\t\t\treturn '(???)'; // All other types should inherit ApiNameMixin which will override this property\n\t\t}\n\t}\n\n\t/**\n\t * If this item was added to a ApiItemContainerMixin item, then this returns the container item.\n\t * If this is an Parameter that was added to a method or function, then this returns the function item.\n\t * Otherwise, it returns undefined.\n\t *\n\t * @virtual\n\t */\n\tpublic get parent(): ApiItem | undefined {\n\t\treturn this._parent;\n\t}\n\n\t/**\n\t * This property supports a visitor pattern for walking the tree.\n\t * For items with ApiItemContainerMixin, it returns the contained items, sorted alphabetically.\n\t * Otherwise it returns an empty array.\n\t *\n\t * @virtual\n\t */\n\tpublic get members(): readonly ApiItem[] {\n\t\treturn [];\n\t}\n\n\t/**\n\t * If this item has a name (i.e. extends `ApiNameMixin`), then return all items that have the same parent\n\t * and the same name.  Otherwise, return all items that have the same parent and the same `ApiItemKind`.\n\t *\n\t * @remarks\n\t * Examples: For a function, this would return all overloads for the function.  For a constructor, this would\n\t * return all overloads for the constructor.  For a merged declaration (e.g. a `namespace` and `enum` with the\n\t * same name), this would return both declarations.  If this item does not have a parent, or if it is the only\n\t * item of its name/kind, then the result is an array containing only this item.\n\t */\n\tpublic getMergedSiblings(): readonly ApiItem[] {\n\t\tconst parent: ApiItem | undefined = this._parent;\n\t\tif (parent && ApiItemContainerMixin.isBaseClassOf(parent)) {\n\t\t\treturn parent._getMergedSiblingsForMember(this);\n\t\t}\n\n\t\treturn [];\n\t}\n\n\t/**\n\t * Returns the chain of ancestors, starting from the root of the tree, and ending with the this item.\n\t */\n\tpublic getHierarchy(): readonly ApiItem[] {\n\t\tconst hierarchy: ApiItem[] = [];\n\t\tfor (let current: ApiItem | undefined = this; current !== undefined; current = current.parent) {\n\t\t\thierarchy.push(current);\n\t\t}\n\n\t\thierarchy.reverse();\n\t\treturn hierarchy;\n\t}\n\n\t/**\n\t * This returns a scoped name such as `\"Namespace1.Namespace2.MyClass.myMember()\"`.  It does not include the\n\t * package name or entry point.\n\t *\n\t * @remarks\n\t * If called on an ApiEntrypoint, ApiPackage, or ApiModel item, the result is an empty string.\n\t */\n\tpublic getScopedNameWithinPackage(): string {\n\t\tconst reversedParts: string[] = [];\n\n\t\tfor (let current: ApiItem | undefined = this; current !== undefined; current = current.parent) {\n\t\t\tif (\n\t\t\t\tcurrent.kind === ApiItemKind.Model ||\n\t\t\t\tcurrent.kind === ApiItemKind.Package ||\n\t\t\t\tcurrent.kind === ApiItemKind.EntryPoint\n\t\t\t) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (reversedParts.length === 0) {\n\t\t\t\tswitch (current.kind) {\n\t\t\t\t\tcase ApiItemKind.CallSignature:\n\t\t\t\t\tcase ApiItemKind.ConstructSignature:\n\t\t\t\t\tcase ApiItemKind.Constructor:\n\t\t\t\t\tcase ApiItemKind.IndexSignature:\n\t\t\t\t\t\t// These functional forms don't have a proper name, so we don't append the \"()\" suffix\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif (ApiParameterListMixin.isBaseClassOf(current)) {\n\t\t\t\t\t\t\treversedParts.push('()');\n\t\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treversedParts.push('.');\n\t\t\t}\n\n\t\t\treversedParts.push(current.displayName);\n\t\t}\n\n\t\treturn reversedParts.reverse().join('');\n\t}\n\n\t/**\n\t * If this item is an ApiEntryPoint or has an ApiEntryPoint as one of its parents, then that object is returned.\n\t * Otherwise undefined is returned.\n\t */\n\tpublic getAssociatedEntryPoint(): ApiEntryPoint | undefined {\n\t\tfor (let current: ApiItem | undefined = this; current !== undefined; current = current.parent) {\n\t\t\tif (current.kind === ApiItemKind.EntryPoint) {\n\t\t\t\treturn current as ApiEntryPoint;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * If this item is an ApiPackage or has an ApiPackage as one of its parents, then that object is returned.\n\t * Otherwise undefined is returned.\n\t */\n\tpublic getAssociatedPackage(): ApiPackage | undefined {\n\t\tfor (let current: ApiItem | undefined = this; current !== undefined; current = current.parent) {\n\t\t\tif (current.kind === ApiItemKind.Package) {\n\t\t\t\treturn current as ApiPackage;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * If this item is an ApiModel or has an ApiModel as one of its parents, then that object is returned.\n\t * Otherwise undefined is returned.\n\t */\n\tpublic getAssociatedModel(): ApiModel | undefined {\n\t\tfor (let current: ApiItem | undefined = this; current !== undefined; current = current.parent) {\n\t\t\tif (current.kind === ApiItemKind.Model) {\n\t\t\t\treturn current as ApiModel;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * A text string whose value determines the sort order that is automatically applied by the\n\t * {@link (ApiItemContainerMixin:interface)} class.\n\t *\n\t * @remarks\n\t * The value of this string is undocumented and may change at any time.\n\t * If {@link (ApiItemContainerMixin:interface).preserveMemberOrder} is enabled for the `ApiItem`'s parent,\n\t * then no sorting is performed, and this key is not used.\n\t * @virtual\n\t */\n\tpublic getSortKey(): string {\n\t\treturn this.containerKey;\n\t}\n\n\t/**\n\t * PRIVATE\n\t *\n\t * @privateRemarks\n\t * Allows ApiItemContainerMixin to assign the parent when the item is added to a container.\n\t * @internal\n\t */\n\tpublic [apiItem_onParentChanged](parent: ApiItem | undefined): void {\n\t\tthis._parent = parent;\n\t\tthis._canonicalReference = undefined;\n\t}\n\n\t/**\n\t * Builds the cached object used by the `canonicalReference` property.\n\t *\n\t * @virtual\n\t */\n\tprotected buildCanonicalReference(): DeclarationReference {\n\t\tthrow new InternalError('ApiItem.canonicalReference was not implemented by the child class');\n\t}\n}\n\n/**\n * This abstraction is used by the mixin pattern.\n * It describes a class type that inherits from {@link ApiItem}.\n *\n * @public\n */\nexport interface IApiItemConstructor extends Constructor<ApiItem>, PropertiesOf<typeof ApiItem> {}\n"
  },
  {
    "path": "packages/api-extractor-model/src/items/ApiPropertyItem.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin.js';\nimport { ApiOptionalMixin, type IApiOptionalMixinOptions } from '../mixins/ApiOptionalMixin.js';\nimport { ApiReadonlyMixin, type IApiReadonlyMixinOptions } from '../mixins/ApiReadonlyMixin.js';\nimport { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin.js';\nimport type { Excerpt, IExcerptTokenRange } from '../mixins/Excerpt.js';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\nimport { type IApiDeclaredItemOptions, ApiDeclaredItem, type IApiDeclaredItemJson } from './ApiDeclaredItem.js';\n\n/**\n * Constructor options for {@link ApiPropertyItem}.\n *\n * @public\n */\nexport interface IApiPropertyItemOptions\n\textends\n\t\tIApiNameMixinOptions,\n\t\tIApiReleaseTagMixinOptions,\n\t\tIApiOptionalMixinOptions,\n\t\tIApiReadonlyMixinOptions,\n\t\tIApiDeclaredItemOptions {\n\tpropertyTypeTokenRange: IExcerptTokenRange;\n}\n\nexport interface IApiPropertyItemJson extends IApiDeclaredItemJson {\n\tpropertyTypeTokenRange: IExcerptTokenRange;\n}\n\n/**\n * The abstract base class for {@link ApiProperty} and {@link ApiPropertySignature}.\n *\n * @public\n */\nexport class ApiPropertyItem extends ApiNameMixin(\n\tApiReleaseTagMixin(ApiOptionalMixin(ApiReadonlyMixin(ApiDeclaredItem))),\n) {\n\t/**\n\t * An {@link Excerpt} that describes the type of the property.\n\t */\n\tpublic readonly propertyTypeExcerpt: Excerpt;\n\n\tpublic constructor(options: IApiPropertyItemOptions) {\n\t\tsuper(options);\n\n\t\tthis.propertyTypeExcerpt = this.buildExcerpt(options.propertyTypeTokenRange);\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic static override onDeserializeInto(\n\t\toptions: Partial<IApiPropertyItemOptions>,\n\t\tcontext: DeserializerContext,\n\t\tjsonObject: IApiPropertyItemJson,\n\t): void {\n\t\tsuper.onDeserializeInto(options, context, jsonObject);\n\n\t\toptions.propertyTypeTokenRange = jsonObject.propertyTypeTokenRange;\n\t}\n\n\t/**\n\t * Returns true if this property should be documented as an event.\n\t *\n\t * @remarks\n\t * The `@eventProperty` TSDoc modifier can be added to readonly properties to indicate that they return an\n\t * event object that event handlers can be attached to.  The event-handling API is implementation-defined, but\n\t * typically the return type would be a class with members such as `addHandler()` and `removeHandler()`.\n\t * The documentation should display such properties under an \"Events\" heading instead of the\n\t * usual \"Properties\" heading.\n\t */\n\tpublic get isEventProperty(): boolean {\n\t\tif (this.tsdocComment) {\n\t\t\treturn this.tsdocComment.modifierTagSet.isEventProperty();\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override serializeInto(jsonObject: Partial<IApiPropertyItemJson>): void {\n\t\tsuper.serializeInto(jsonObject);\n\n\t\tjsonObject.propertyTypeTokenRange = this.propertyTypeExcerpt.tokenRange;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/ApiAbstractMixin.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem.js';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\n\n/**\n * Constructor options for {@link (ApiAbstractMixin:interface)}.\n *\n * @public\n */\nexport interface IApiAbstractMixinOptions extends IApiItemOptions {\n\tisAbstract: boolean;\n}\n\nexport interface IApiAbstractMixinJson extends IApiItemJson {\n\tisAbstract: boolean;\n}\n\nconst _isAbstract: unique symbol = Symbol('ApiAbstractMixin._isAbstract');\n\n/**\n * The mixin base class for API items that have an abstract modifier.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.  The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use\n * TypeScript \"mixin\" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various\n * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class\n * to extend more than one base class).  The \"mixin\" is a TypeScript merged declaration with three components:\n * the function that generates a subclass, an interface that describes the members of the subclass, and\n * a namespace containing static members of the class.\n * @public\n */\n\nexport interface ApiAbstractMixin extends ApiItem {\n\t/**\n\t * Indicates that the API item's value has an 'abstract' modifier.\n\t */\n\treadonly isAbstract: boolean;\n\n\tserializeInto(jsonObject: Partial<IApiItemJson>): void;\n}\n\n/**\n * Mixin function for {@link (ApiAbstractMixin:interface)}.\n *\n * @param baseClass - The base class to be extended\n * @returns A child class that extends baseClass, adding the {@link (ApiAbstractMixin:interface)}\n * functionality.\n * @public\n */\nexport function ApiAbstractMixin<TBaseClass extends IApiItemConstructor>(\n\tbaseClass: TBaseClass,\n): TBaseClass & (new (...args: any[]) => ApiAbstractMixin) {\n\tclass MixedClass extends baseClass implements ApiAbstractMixin {\n\t\tpublic [_isAbstract]: boolean;\n\n\t\tpublic constructor(...args: any[]) {\n\t\t\tsuper(...args);\n\n\t\t\tconst options: IApiAbstractMixinOptions = args[0];\n\t\t\tthis[_isAbstract] = options.isAbstract;\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic static override onDeserializeInto(\n\t\t\toptions: Partial<IApiAbstractMixinOptions>,\n\t\t\tcontext: DeserializerContext,\n\t\t\tjsonObject: IApiAbstractMixinJson,\n\t\t): void {\n\t\t\tbaseClass.onDeserializeInto(options, context, jsonObject);\n\n\t\t\toptions.isAbstract = jsonObject.isAbstract || false;\n\t\t}\n\n\t\tpublic get isAbstract(): boolean {\n\t\t\treturn this[_isAbstract];\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic override serializeInto(jsonObject: Partial<IApiAbstractMixinJson>): void {\n\t\t\tsuper.serializeInto(jsonObject);\n\n\t\t\tjsonObject.isAbstract = this.isAbstract;\n\t\t}\n\t}\n\n\treturn MixedClass;\n}\n\n/**\n * Static members for {@link (ApiAbstractMixin:interface)}.\n *\n * @public\n */\nexport namespace ApiAbstractMixin {\n\t/**\n\t * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiAbstractMixin` mixin.\n\t *\n\t * @remarks\n\t *\n\t * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of\n\t * the mixin function produces a different subclass.  (This could be mitigated by `Symbol.hasInstance`, however\n\t * the TypeScript type system cannot invoke a runtime test.)\n\t */\n\texport function isBaseClassOf(apiItem: ApiItem): apiItem is ApiAbstractMixin {\n\t\treturn apiItem.hasOwnProperty(_isAbstract);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/ApiExportedMixin.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem.js';\nimport { Navigation } from '../items/ApiItem.js';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\n\n/**\n * Constructor options for {@link (IApiExportedMixinOptions:interface)}.\n *\n * @public\n */\nexport interface IApiExportedMixinOptions extends IApiItemOptions {\n\tisExported: boolean;\n}\n\nexport interface IApiExportedMixinJson extends IApiItemJson {\n\tisExported: boolean;\n}\n\nconst _isExported: unique symbol = Symbol('ApiExportedMixin._isExported');\n\n/**\n * The mixin base class for API items that can be exported.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.  The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use\n * TypeScript \"mixin\" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various\n * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class\n * to extend more than one base class).  The \"mixin\" is a TypeScript merged declaration with three components:\n * the function that generates a subclass, an interface that describes the members of the subclass, and\n * a namespace containing static members of the class.\n * @public\n */\n\nexport interface ApiExportedMixin extends ApiItem {\n\t/**\n\t * Whether the declaration is exported from its parent item container (i.e. either an `ApiEntryPoint` or an\n\t * `ApiNamespace`).\n\t *\n\t * @remarks\n\t * Suppose `index.ts` is your entry point:\n\t *\n\t * ```ts\n\t * // index.ts\n\t *\n\t * export class A {}\n\t * class B {}\n\t *\n\t * namespace n {\n\t *   export class C {}\n\t *   class D {}\n\t * }\n\t *\n\t * // file.ts\n\t * export class E {}\n\t * ```\n\t *\n\t * Classes `A` and `C` are both exported, while classes `B`, `D`, and `E` are not. `E` is exported from its\n\t * local file, but not from its parent item container (i.e. the entry point).\n\t */\n\treadonly isExported: boolean;\n\n\t/**\n\t * @override\n\t */\n\tserializeInto(jsonObject: Partial<IApiItemJson>): void;\n}\n\n/**\n * Mixin function for {@link (ApiExportedMixin:interface)}.\n *\n * @param baseClass - The base class to be extended\n * @returns A child class that extends baseClass, adding the {@link (ApiExportedMixin:interface)} functionality.\n * @public\n */\nexport function ApiExportedMixin<TBaseClass extends IApiItemConstructor>(\n\tbaseClass: TBaseClass,\n): TBaseClass & (new (...args: any[]) => ApiExportedMixin) {\n\tclass MixedClass extends baseClass implements ApiExportedMixin {\n\t\tpublic [_isExported]: boolean;\n\n\t\tpublic constructor(...args: any[]) {\n\t\t\tsuper(...args);\n\n\t\t\tconst options: IApiExportedMixinOptions = args[0];\n\t\t\tthis[_isExported] = options.isExported;\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic static override onDeserializeInto(\n\t\t\toptions: Partial<IApiExportedMixinOptions>,\n\t\t\tcontext: DeserializerContext,\n\t\t\tjsonObject: IApiExportedMixinJson,\n\t\t): void {\n\t\t\tbaseClass.onDeserializeInto(options, context, jsonObject);\n\n\t\t\tconst declarationReference: DeclarationReference = DeclarationReference.parse(jsonObject.canonicalReference);\n\t\t\toptions.isExported = declarationReference.navigation === (Navigation.Exports as any); // ambient const enums suck...\n\t\t}\n\n\t\tpublic get isExported(): boolean {\n\t\t\treturn this[_isExported];\n\t\t}\n\n\t\t/**\n\t\t * The `isExported` property is intentionally not serialized because the information is already present\n\t\t * in the item's `canonicalReference`.\n\t\t *\n\t\t * @override\n\t\t */\n\t\tpublic override serializeInto(jsonObject: Partial<IApiExportedMixinJson>): void {\n\t\t\tsuper.serializeInto(jsonObject);\n\t\t}\n\t}\n\n\treturn MixedClass;\n}\n\n/**\n * Static members for {@link (ApiExportedMixin:interface)}.\n *\n * @public\n */\nexport namespace ApiExportedMixin {\n\t/**\n\t * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiExportedMixin` mixin.\n\t *\n\t * @remarks\n\t *\n\t * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of\n\t * the mixin function produces a different subclass.  (This could be mitigated by `Symbol.hasInstance`, however\n\t * the TypeScript type system cannot invoke a runtime test.)\n\t */\n\texport function isBaseClassOf(apiItem: ApiItem): apiItem is ApiExportedMixin {\n\t\treturn apiItem.hasOwnProperty(_isExported);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/ApiInitializerMixin.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError } from '@rushstack/node-core-library';\nimport { ApiDeclaredItem } from '../items/ApiDeclaredItem.js';\nimport type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem.js';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\nimport type { IExcerptTokenRange, Excerpt } from './Excerpt.js';\n\n/**\n * Constructor options for {@link (IApiInitializerMixinOptions:interface)}.\n *\n * @public\n */\nexport interface IApiInitializerMixinOptions extends IApiItemOptions {\n\tinitializerTokenRange?: IExcerptTokenRange | undefined;\n}\n\nexport interface IApiInitializerMixinJson extends IApiItemJson {\n\tinitializerTokenRange?: IExcerptTokenRange;\n}\n\nconst _initializerExcerpt: unique symbol = Symbol('ApiInitializerMixin._initializerExcerpt');\n\n/**\n * The mixin base class for API items that can have an initializer.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.  The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use\n * TypeScript \"mixin\" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various\n * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class\n * to extend more than one base class).  The \"mixin\" is a TypeScript merged declaration with three components:\n * the function that generates a subclass, an interface that describes the members of the subclass, and\n * a namespace containing static members of the class.\n * @public\n */\n\nexport interface ApiInitializerMixin extends ApiItem {\n\t/**\n\t * An {@link Excerpt} that describes the item's initializer.\n\t */\n\treadonly initializerExcerpt?: Excerpt | undefined;\n\n\t/**\n\t * @override\n\t */\n\tserializeInto(jsonObject: Partial<IApiInitializerMixinJson>): void;\n}\n\n/**\n * Mixin function for {@link (ApiInitializerMixin:interface)}.\n *\n * @param baseClass - The base class to be extended\n * @returns A child class that extends baseClass, adding the {@link (ApiInitializerMixin:interface)} functionality.\n * @public\n */\nexport function ApiInitializerMixin<TBaseClass extends IApiItemConstructor>(\n\tbaseClass: TBaseClass,\n): TBaseClass & (new (...args: any[]) => ApiInitializerMixin) {\n\tclass MixedClass extends baseClass implements ApiInitializerMixin {\n\t\tpublic [_initializerExcerpt]?: Excerpt;\n\n\t\tpublic constructor(...args: any[]) {\n\t\t\tsuper(...args);\n\n\t\t\tconst options: IApiInitializerMixinOptions = args[0];\n\n\t\t\tif (this instanceof ApiDeclaredItem) {\n\t\t\t\tif (options.initializerTokenRange) {\n\t\t\t\t\tthis[_initializerExcerpt] = this.buildExcerpt(options.initializerTokenRange);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthrow new InternalError('ApiInitializerMixin expects a base class that inherits from ApiDeclaredItem');\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic static override onDeserializeInto(\n\t\t\toptions: Partial<IApiInitializerMixinOptions>,\n\t\t\tcontext: DeserializerContext,\n\t\t\tjsonObject: IApiInitializerMixinJson,\n\t\t): void {\n\t\t\tbaseClass.onDeserializeInto(options, context, jsonObject);\n\n\t\t\toptions.initializerTokenRange = jsonObject.initializerTokenRange;\n\t\t}\n\n\t\tpublic get initializerExcerpt(): Excerpt | undefined {\n\t\t\treturn this[_initializerExcerpt];\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic override serializeInto(jsonObject: Partial<IApiInitializerMixinJson>): void {\n\t\t\tsuper.serializeInto(jsonObject);\n\n\t\t\t// Note that JSON does not support the \"undefined\" value, so we simply omit the field entirely if it is undefined\n\t\t\tif (this.initializerExcerpt) {\n\t\t\t\tjsonObject.initializerTokenRange = this.initializerExcerpt.tokenRange;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn MixedClass;\n}\n\n/**\n * Static members for {@link (ApiInitializerMixin:interface)}.\n *\n * @public\n */\nexport namespace ApiInitializerMixin {\n\t/**\n\t * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiInitializerMixin` mixin.\n\t *\n\t * @remarks\n\t *\n\t * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of\n\t * the mixin function produces a different subclass.  (This could be mitigated by `Symbol.hasInstance`, however\n\t * the TypeScript type system cannot invoke a runtime test.)\n\t */\n\texport function isBaseClassOf(apiItem: ApiItem): apiItem is ApiInitializerMixin {\n\t\treturn apiItem.hasOwnProperty(_initializerExcerpt);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/ApiItemContainerMixin.ts",
    "content": "/* eslint-disable @typescript-eslint/no-loop-func */\n// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport {\n\ttype DocNode,\n\ttype DocPlainText,\n\tDocDeclarationReference,\n\tDocNodeKind,\n\tTSDocConfiguration,\n\tDocMemberReference,\n\tDocMemberIdentifier,\n} from '@microsoft/tsdoc';\nimport type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { InternalError } from '@rushstack/node-core-library';\nimport type { IExcerptToken, IExcerptTokenRange } from '../index.js';\nimport { ApiDeclaredItem } from '../index.js';\nimport type { IApiDeclaredItemJson } from '../items/ApiDeclaredItem.js';\nimport {\n\tApiItem,\n\tapiItem_onParentChanged,\n\ttype IApiItemJson,\n\ttype IApiItemOptions,\n\ttype IApiItemConstructor,\n\tApiItemKind,\n} from '../items/ApiItem.js';\nimport type { ApiClass } from '../model/ApiClass.js';\nimport type { ApiInterface } from '../model/ApiInterface.js';\nimport type { ApiModel } from '../model/ApiModel.js';\nimport { ApiJsonSchemaVersion, type DeserializerContext } from '../model/DeserializerContext.js';\nimport type { HeritageType } from '../model/HeritageType.js';\nimport type { IResolveDeclarationReferenceResult } from '../model/ModelReferenceResolver.js';\nimport { ApiNameMixin } from './ApiNameMixin.js';\nimport type { ExcerptToken } from './Excerpt.js';\nimport { ExcerptTokenKind } from './Excerpt.js';\nimport { type IFindApiItemsResult, type IFindApiItemsMessage, FindApiItemsMessageId } from './IFindApiItemsResult.js';\n\n/**\n * Constructor options for {@link (ApiItemContainerMixin:interface)}.\n *\n * @public\n */\nexport interface IApiItemContainerMixinOptions extends IApiItemOptions {\n\tmembers?: ApiItem[] | undefined;\n\tpreserveMemberOrder?: boolean | undefined;\n}\n\nexport interface IApiItemContainerJson extends IApiItemJson {\n\tmembers: IApiItemJson[];\n\tpreserveMemberOrder?: boolean;\n}\n\ninterface Mixin {\n\tdeclarationReference: DocDeclarationReference;\n\ttypeParameters: IExcerptTokenRange[];\n}\n\ninterface ExcerptTokenRangeInDeclaredItem {\n\titem: ApiDeclaredItem;\n\trange: IExcerptTokenRange;\n}\ninterface IMappedTypeParameters {\n\titem: ApiItem;\n\tmappedTypeParameters: Map<string, ExcerptTokenRangeInDeclaredItem>;\n}\n\nconst _members: unique symbol = Symbol('ApiItemContainerMixin._members');\nconst _membersSorted: unique symbol = Symbol('ApiItemContainerMixin._membersSorted');\nconst _membersByContainerKey: unique symbol = Symbol('ApiItemContainerMixin._membersByContainerKey');\nconst _membersByName: unique symbol = Symbol('ApiItemContainerMixin._membersByName');\nconst _membersByKind: unique symbol = Symbol('ApiItemContainerMixin._membersByKind');\nconst _preserveMemberOrder: unique symbol = Symbol('ApiItemContainerMixin._preserveMemberOrder');\n\n/**\n * The mixin base class for API items that act as containers for other child items.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.  The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use\n * TypeScript \"mixin\" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various\n * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class\n * to extend more than one base class).  The \"mixin\" is a TypeScript merged declaration with three components:\n * the function that generates a subclass, an interface that describes the members of the subclass, and\n * a namespace containing static members of the class.\n *\n * Examples of `ApiItemContainerMixin` child classes include `ApiModel`, `ApiPackage`, `ApiEntryPoint`,\n * and `ApiEnum`.  But note that `Parameter` is not considered a \"member\" of an `ApiMethod`; this relationship\n * is modeled using {@link (ApiParameterListMixin:interface).parameters} instead\n * of {@link ApiItem.members}.\n * @public\n */\n\nexport interface ApiItemContainerMixin extends ApiItem {\n\t/**\n\t * For a given member of this container, return its `ApiItem.getMergedSiblings()` list.\n\t *\n\t * @internal\n\t */\n\t_getMergedSiblingsForMember(memberApiItem: ApiItem): readonly ApiItem[];\n\n\t/**\n\t * Adds a new member to the container.\n\t *\n\t * @remarks\n\t * An ApiItem cannot be added to more than one container.\n\t */\n\taddMember(member: ApiItem): void;\n\n\t/**\n\t * Returns a list of members with the specified name.\n\t */\n\tfindMembersByName(name: string): readonly ApiItem[];\n\n\t/**\n\t * Finds all of the ApiItem's immediate and inherited members by walking up the inheritance tree.\n\t *\n\t * @remarks\n\t *\n\t * Given the following class heritage:\n\t *\n\t * ```\n\t * export class A {\n\t *   public a: number|boolean;\n\t * }\n\t *\n\t * export class B extends A {\n\t *   public a: number;\n\t *   public b: string;\n\t * }\n\t *\n\t * export class C extends B {\n\t *   public c: boolean;\n\t * }\n\t * ```\n\t *\n\t * Calling `findMembersWithInheritance` on `C` will return `B.a`, `B.b`, and `C.c`. Calling the\n\t * method on `B` will return `B.a` and `B.b`. And calling the method on `A` will return just\n\t * `A.a`.\n\t *\n\t * The inherited members returned by this method may be incomplete. If so, there will be a flag\n\t * on the result object indicating this as well as messages explaining the errors in more detail.\n\t * Some scenarios include:\n\t *\n\t * - Interface extending from a type alias.\n\t *\n\t * - Class extending from a variable.\n\t *\n\t * - Extending from a declaration not present in the model (e.g. external package).\n\t *\n\t * - Extending from an unexported declaration (e.g. ae-forgotten-export). Common in mixin\n\t *   patterns.\n\t *\n\t * - Unexpected runtime errors...\n\t *\n\t * Lastly, be aware that the types of inherited members are returned with respect to their\n\t * defining class as opposed to with respect to the inheriting class. For example, consider\n\t * the following:\n\t *\n\t * ```\n\t * export class A<T> {\n\t *   public a: T;\n\t * }\n\t *\n\t * export class B extends A<number> {}\n\t * ```\n\t *\n\t * When called on `B`, this method will return `B.a` with type `T` as opposed to type\n\t * `number`, although the latter is more accurate.\n\t */\n\tfindMembersWithInheritance(): IFindApiItemsResult;\n\n\t/**\n\t * Disables automatic sorting of {@link ApiItem.members}.\n\t *\n\t * @remarks\n\t * By default `ApiItemContainerMixin` will automatically sort its members according to their\n\t * {@link ApiItem.getSortKey} string, which provides a standardized mostly alphabetical ordering\n\t * that is appropriate for most API items.  When loading older .api.json files the automatic sorting\n\t * is reapplied and may update the ordering.\n\t *\n\t * Set `preserveMemberOrder` to true to disable automatic sorting for this container; instead, the\n\t * members will retain whatever ordering appeared in the {@link IApiItemContainerMixinOptions.members} array.\n\t * The `preserveMemberOrder` option is saved in the .api.json file.\n\t */\n\treadonly preserveMemberOrder: boolean;\n\n\t/**\n\t * @override\n\t */\n\tserializeInto(jsonObject: Partial<IApiItemJson>): void;\n\n\t/**\n\t * Attempts to retrieve a member using its containerKey, or returns `undefined` if no matching member was found.\n\t *\n\t * @remarks\n\t * Use the `getContainerKey()` static member to construct the key.  Each subclass has a different implementation\n\t * of this function, according to the aspects that are important for identifying it.\n\t *\n\t * See {@link ApiItem.containerKey} for more information.\n\t */\n\ttryGetMemberByKey(containerKey: string): ApiItem | undefined;\n}\n\n/**\n * Mixin function for {@link ApiDeclaredItem}.\n *\n * @param baseClass - The base class to be extended\n * @returns A child class that extends baseClass, adding the {@link (ApiItemContainerMixin:interface)} functionality.\n * @public\n */\nexport function ApiItemContainerMixin<TBaseClass extends IApiItemConstructor>(\n\tbaseClass: TBaseClass,\n): TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) {\n\tclass MixedClass extends baseClass implements ApiItemContainerMixin {\n\t\tpublic readonly [_members]: ApiItem[];\n\n\t\tpublic [_membersSorted]: boolean;\n\n\t\tpublic [_membersByContainerKey]: Map<string, ApiItem>;\n\n\t\tpublic [_preserveMemberOrder]: boolean;\n\n\t\t// For members of this container that extend ApiNameMixin, this stores the list of members with a given name.\n\t\t// Examples include merged declarations, overloaded functions, etc.\n\t\tpublic [_membersByName]: Map<string, ApiItem[]> | undefined;\n\n\t\t// For members of this container that do NOT extend ApiNameMixin, this stores the list of members\n\t\t// that share a common ApiItemKind.  Examples include overloaded constructors or index signatures.\n\t\tpublic [_membersByKind]: Map<string, ApiItem[]> | undefined; // key is ApiItemKind\n\n\t\tpublic constructor(...args: any[]) {\n\t\t\tsuper(...args);\n\t\t\tconst options: IApiItemContainerMixinOptions = args[0] as IApiItemContainerMixinOptions;\n\n\t\t\tthis[_members] = [];\n\t\t\tthis[_membersSorted] = false;\n\t\t\tthis[_membersByContainerKey] = new Map<string, ApiItem>();\n\t\t\tthis[_preserveMemberOrder] = options.preserveMemberOrder ?? false;\n\n\t\t\tif (options.members) {\n\t\t\t\tfor (const member of options.members) {\n\t\t\t\t\tthis.addMember(member);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic static override onDeserializeInto(\n\t\t\toptions: Partial<IApiItemContainerMixinOptions>,\n\t\t\tcontext: DeserializerContext,\n\t\t\tjsonObject: IApiItemContainerJson,\n\t\t): void {\n\t\t\tbaseClass.onDeserializeInto(options, context, jsonObject);\n\t\t\toptions.preserveMemberOrder = jsonObject.preserveMemberOrder;\n\t\t\toptions.members = [];\n\t\t\tfor (const memberObject of jsonObject.members) {\n\t\t\t\toptions.members.push(ApiItem.deserialize(memberObject, context));\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic override get members(): readonly ApiItem[] {\n\t\t\tif (!this[_membersSorted] && !this[_preserveMemberOrder]) {\n\t\t\t\tthis[_members].sort((x, y) => x.getSortKey().localeCompare(y.getSortKey()));\n\t\t\t\tthis[_membersSorted] = true;\n\t\t\t}\n\n\t\t\treturn this[_members];\n\t\t}\n\n\t\tpublic get preserveMemberOrder(): boolean {\n\t\t\treturn this[_preserveMemberOrder];\n\t\t}\n\n\t\tpublic addMember(member: ApiItem): void {\n\t\t\tif (this[_membersByContainerKey].has(member.containerKey)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Another member has already been added with the same name (${member.displayName})` +\n\t\t\t\t\t\t` and containerKey (${member.containerKey})`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst existingParent: ApiItem | undefined = member.parent;\n\t\t\tif (existingParent !== undefined) {\n\t\t\t\tthrow new Error(`This item has already been added to another container: \"${existingParent.displayName}\"`);\n\t\t\t}\n\n\t\t\tthis[_members].push(member);\n\t\t\tthis[_membersByName] = undefined; // invalidate the lookup\n\t\t\tthis[_membersByKind] = undefined; // invalidate the lookup\n\t\t\tthis[_membersSorted] = false;\n\t\t\tthis[_membersByContainerKey].set(member.containerKey, member);\n\n\t\t\tmember[apiItem_onParentChanged](this);\n\t\t}\n\n\t\tpublic tryGetMemberByKey(containerKey: string): ApiItem | undefined {\n\t\t\treturn this[_membersByContainerKey].get(containerKey);\n\t\t}\n\n\t\tpublic findMembersByName(name: string): readonly ApiItem[] {\n\t\t\tthis._ensureMemberMaps();\n\t\t\treturn this[_membersByName]!.get(name) ?? [];\n\t\t}\n\n\t\tpublic findMembersWithInheritance(): IFindApiItemsResult {\n\t\t\tconst messages: IFindApiItemsMessage[] = [];\n\t\t\tlet maybeIncompleteResult = false;\n\n\t\t\t// For API items that don't support inheritance, this method just returns the item's\n\t\t\t// immediate members.\n\t\t\tswitch (this.kind) {\n\t\t\t\tcase ApiItemKind.Class:\n\t\t\t\tcase ApiItemKind.Interface:\n\t\t\t\t\tbreak;\n\t\t\t\tdefault: {\n\t\t\t\t\treturn {\n\t\t\t\t\t\titems: this.members.concat(),\n\t\t\t\t\t\tmessages,\n\t\t\t\t\t\tmaybeIncompleteResult,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// The Deserializer class is coupled with a ton of other classes, so  we delay loading it\n\t\t\t// to avoid ES5 circular imports.\n\t\t\t// *eslint-disable-next-line @typescript-eslint/consistent-type-imports, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n\t\t\t// const deserializerModule: typeof import('../model/Deserializer') = require('../model/Deserializer');\n\n\t\t\tconst membersByName: Map<string, ApiItem[]> = new Map();\n\t\t\tconst membersByKind: Map<ApiItemKind, ApiItem[]> = new Map();\n\n\t\t\tconst toVisit: IMappedTypeParameters[] = [];\n\t\t\tlet next: IMappedTypeParameters | undefined = { item: this, mappedTypeParameters: new Map() };\n\n\t\t\twhile (next?.item) {\n\t\t\t\tconst membersToAdd: ApiItem[] = []; //*\n\t\t\t\tconst typeParams = next.mappedTypeParameters;\n\t\t\t\tconst context: DeserializerContext = {\n\t\t\t\t\tapiJsonFilename: '',\n\t\t\t\t\ttoolPackage: '',\n\t\t\t\t\ttoolVersion: '',\n\t\t\t\t\tversionToDeserialize: ApiJsonSchemaVersion.LATEST,\n\t\t\t\t\ttsdocConfiguration: new TSDocConfiguration(),\n\t\t\t\t}; // */\n\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-imports, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n\t\t\t\tconst deserializerModule: typeof import('../model/Deserializer') = require('../model/Deserializer');\n\n\t\t\t\t// For each member, check to see if we've already seen a member with the same name\n\t\t\t\t// previously in the inheritance tree. If so, we know we won't inherit it, and thus\n\t\t\t\t// do not add it to our `membersToAdd` array.\n\t\t\t\tfor (let member of next.item.members) {\n\t\t\t\t\t// We add the to-be-added members to an intermediate array instead of immediately\n\t\t\t\t\t// to the maps themselves to support method overloads with the same name.\n\n\t\t\t\t\t// This was supposed to replace type parameters with their assigned values in inheritance, but doesn't work yet\n\t\t\t\t\t//*\n\t\t\t\t\tif (member instanceof ApiDeclaredItem && member.excerptTokens.some((token) => typeParams.has(token.text))) {\n\t\t\t\t\t\tconst jsonObject: Partial<IApiItemJson> = {};\n\t\t\t\t\t\tmember.serializeInto(jsonObject);\n\t\t\t\t\t\tconst excerptTokens = (jsonObject as IApiDeclaredItemJson).excerptTokens.map((token) => {\n\t\t\t\t\t\t\tlet x: ExcerptToken | undefined;\n\t\t\t\t\t\t\tif (typeParams.has(token.text) && next?.item instanceof ApiDeclaredItem) {\n\t\t\t\t\t\t\t\tconst originalValue = typeParams.get(token.text)!;\n\t\t\t\t\t\t\t\tx = originalValue.item.excerptTokens[originalValue.range.startIndex];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst excerptToken: IExcerptToken = x ? { kind: x.kind, text: x.text } : token;\n\t\t\t\t\t\t\tif (x?.canonicalReference !== undefined) {\n\t\t\t\t\t\t\t\texcerptToken.canonicalReference = x.canonicalReference.toString();\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn excerptToken;\n\t\t\t\t\t\t});\n\t\t\t\t\t\tmember = deserializerModule.Deserializer.deserialize(context, {\n\t\t\t\t\t\t\t...jsonObject,\n\t\t\t\t\t\t\texcerptTokens,\n\t\t\t\t\t\t} as IApiDeclaredItemJson);\n\t\t\t\t\t\tmember[apiItem_onParentChanged](next.item);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (ApiNameMixin.isBaseClassOf(member)) {\n\t\t\t\t\t\tif (!membersByName.has(member.name)) {\n\t\t\t\t\t\t\tmembersToAdd.push(member);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!membersByKind.has(member.kind)) {\n\t\t\t\t\t\tmembersToAdd.push(member);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (const member of membersToAdd) {\n\t\t\t\t\tif (ApiNameMixin.isBaseClassOf(member)) {\n\t\t\t\t\t\tconst members: ApiItem[] = membersByName.get(member.name) ?? [];\n\t\t\t\t\t\tmembers.push(member);\n\t\t\t\t\t\tmembersByName.set(member.name, members);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst members: ApiItem[] = membersByKind.get(member.kind) ?? [];\n\t\t\t\t\t\tmembers.push(member);\n\t\t\t\t\t\tmembersByKind.set(member.kind, members);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst findPlainTextNode = (node: DocNode): DocPlainText | undefined => {\n\t\t\t\t\tswitch (node.kind) {\n\t\t\t\t\t\tcase DocNodeKind.PlainText:\n\t\t\t\t\t\t\treturn node as DocPlainText;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tfor (const child of node.getChildNodes()) {\n\t\t\t\t\t\t\t\tconst result = findPlainTextNode(child);\n\t\t\t\t\t\t\t\tif (result) return result;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn undefined;\n\t\t\t\t};\n\n\t\t\t\t// Interfaces can extend multiple interfaces, so iterate through all of them.\n\t\t\t\t// Also Classes can have multiple mixins\n\t\t\t\tconst extendedItems: IMappedTypeParameters[] = [];\n\t\t\t\tlet extendsTypes: readonly (HeritageType | Mixin)[] | undefined;\n\n\t\t\t\tswitch (next.item.kind) {\n\t\t\t\t\tcase ApiItemKind.Class: {\n\t\t\t\t\t\tconst apiClass: ApiClass = next.item as ApiClass;\n\t\t\t\t\t\tconst configuration = apiClass.tsdocComment?.configuration ?? new TSDocConfiguration();\n\t\t\t\t\t\tconst mixins =\n\t\t\t\t\t\t\tapiClass.tsdocComment?.customBlocks\n\t\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t\t(block) => block.blockTag.tagName === '@mixes', // &&\n\t\t\t\t\t\t\t\t\t// block.getChildNodes().some((node) => node.kind === DocNodeKind.PlainText),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t.map(findPlainTextNode)\n\t\t\t\t\t\t\t\t.filter((block) => block !== undefined)\n\t\t\t\t\t\t\t\t.map((block) => ({\n\t\t\t\t\t\t\t\t\tdeclarationReference: new DocDeclarationReference({\n\t\t\t\t\t\t\t\t\t\tconfiguration,\n\t\t\t\t\t\t\t\t\t\tmemberReferences: block.text.split('.').map(\n\t\t\t\t\t\t\t\t\t\t\t(part, index) =>\n\t\t\t\t\t\t\t\t\t\t\t\tnew DocMemberReference({\n\t\t\t\t\t\t\t\t\t\t\t\t\tconfiguration,\n\t\t\t\t\t\t\t\t\t\t\t\t\thasDot: index > 0,\n\t\t\t\t\t\t\t\t\t\t\t\t\tmemberIdentifier: new DocMemberIdentifier({ configuration, identifier: part }),\n\t\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\ttypeParameters: [] as IExcerptTokenRange[],\n\t\t\t\t\t\t\t\t})) ?? [];\n\t\t\t\t\t\textendsTypes = apiClass.extendsType ? [apiClass.extendsType, ...mixins] : [...mixins];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase ApiItemKind.Interface: {\n\t\t\t\t\t\tconst apiInterface: ApiInterface = next.item as ApiInterface;\n\t\t\t\t\t\textendsTypes = apiInterface.extendsTypes;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (extendsTypes === undefined) {\n\t\t\t\t\tmessages.push({\n\t\t\t\t\t\tmessageId: FindApiItemsMessageId.UnsupportedKind,\n\t\t\t\t\t\ttext: `Unable to analyze references of API item ${next.item.displayName} because it is of unsupported kind ${next.item.kind}`,\n\t\t\t\t\t});\n\t\t\t\t\tmaybeIncompleteResult = true;\n\t\t\t\t\tnext = toVisit.shift();\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tfor (const extendsType of extendsTypes) {\n\t\t\t\t\tlet canonicalReference: DeclarationReference | DocDeclarationReference;\n\t\t\t\t\tif ('excerpt' in extendsType) {\n\t\t\t\t\t\t// We want to find the reference token associated with the actual inherited declaration.\n\t\t\t\t\t\t// In every case we support, this is the first reference token. For example:\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// ```\n\t\t\t\t\t\t// export class A extends B {}\n\t\t\t\t\t\t//                        ^\n\t\t\t\t\t\t// export class A extends B<C> {}\n\t\t\t\t\t\t//                        ^\n\t\t\t\t\t\t// export class A extends B.C {}\n\t\t\t\t\t\t//                        ^^^\n\t\t\t\t\t\t// ```\n\t\t\t\t\t\tconst firstReferenceToken: ExcerptToken | undefined = extendsType.excerpt.spannedTokens.find(\n\t\t\t\t\t\t\t(token: ExcerptToken) => token.kind === ExcerptTokenKind.Reference && token.canonicalReference,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tif (!firstReferenceToken) {\n\t\t\t\t\t\t\tmessages.push({\n\t\t\t\t\t\t\t\tmessageId: FindApiItemsMessageId.ExtendsClauseMissingReference,\n\t\t\t\t\t\t\t\ttext: `Unable to analyze extends clause ${extendsType.excerpt.text} of API item ${next.item.displayName} because no canonical reference was found`,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tmaybeIncompleteResult = true;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcanonicalReference = firstReferenceToken.canonicalReference!;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// extendsType is a Mixin\n\t\t\t\t\t\tcanonicalReference = extendsType.declarationReference;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst apiModel: ApiModel | undefined = this.getAssociatedModel();\n\t\t\t\t\tif (!apiModel) {\n\t\t\t\t\t\tmessages.push({\n\t\t\t\t\t\t\tmessageId: FindApiItemsMessageId.NoAssociatedApiModel,\n\t\t\t\t\t\t\ttext: `Unable to analyze references of API item ${next.item.displayName} because it is not associated with an ApiModel`,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tmaybeIncompleteResult = true;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst apiItemResult: IResolveDeclarationReferenceResult = apiModel.resolveDeclarationReference(\n\t\t\t\t\t\tcanonicalReference,\n\t\t\t\t\t\tthis,\n\t\t\t\t\t);\n\n\t\t\t\t\tconst apiItem: ApiItem | undefined = apiItemResult.resolvedApiItem;\n\t\t\t\t\tif (!apiItem) {\n\t\t\t\t\t\tmessages.push({\n\t\t\t\t\t\t\tmessageId: FindApiItemsMessageId.DeclarationResolutionFailed,\n\t\t\t\t\t\t\ttext: `Unable to resolve declaration reference within API item ${next.item.displayName}: ${apiItemResult.errorMessage}`,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tmaybeIncompleteResult = true;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst mappedTypeParameters: Map<string, ExcerptTokenRangeInDeclaredItem> = new Map();\n\t\t\t\t\tif (\n\t\t\t\t\t\t(apiItem.kind === ApiItemKind.Class || apiItem.kind === ApiItemKind.Interface) &&\n\t\t\t\t\t\tnext.item.kind === ApiItemKind.Class\n\t\t\t\t\t) {\n\t\t\t\t\t\tfor (const [index, key] of (apiItem as ApiClass | ApiInterface).typeParameters.entries() ?? []) {\n\t\t\t\t\t\t\tconst typeParameter = extendsType.typeParameters?.[index];\n\t\t\t\t\t\t\tif (typeParameter)\n\t\t\t\t\t\t\t\tmappedTypeParameters.set(key.name, { item: next.item as ApiDeclaredItem, range: typeParameter });\n\t\t\t\t\t\t\telse if (key.defaultTypeExcerpt)\n\t\t\t\t\t\t\t\tmappedTypeParameters.set(key.name, {\n\t\t\t\t\t\t\t\t\titem: apiItem as ApiDeclaredItem,\n\t\t\t\t\t\t\t\t\trange: key.defaultTypeExcerpt.tokenRange,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\textendedItems.push({ item: apiItem, mappedTypeParameters });\n\t\t\t\t}\n\n\t\t\t\t// For classes, this array will only have one item. For interfaces, there may be multiple items. Sort the array\n\t\t\t\t// into alphabetical order before adding to our list of API items to visit. This ensures that in the case\n\t\t\t\t// of multiple interface inheritance, a member inherited from multiple interfaces is attributed to the interface\n\t\t\t\t// earlier in alphabetical order (as opposed to source order).\n\t\t\t\t//\n\t\t\t\t// For example, in the code block below, `Bar.x` is reported as the inherited item, not `Foo.x`.\n\t\t\t\t//\n\t\t\t\t// ```\n\t\t\t\t// interface Foo {\n\t\t\t\t//   public x: string;\n\t\t\t\t// }\n\t\t\t\t//\n\t\t\t\t// interface Bar {\n\t\t\t\t//   public x: string;\n\t\t\t\t// }\n\t\t\t\t//\n\t\t\t\t// interface FooBar extends Foo, Bar {}\n\t\t\t\t// ```\n\t\t\t\textendedItems.sort((x: IMappedTypeParameters, y: IMappedTypeParameters) =>\n\t\t\t\t\tx.item.getSortKey().localeCompare(y.item.getSortKey()),\n\t\t\t\t);\n\n\t\t\t\ttoVisit.push(...extendedItems);\n\t\t\t\tnext = toVisit.shift();\n\t\t\t}\n\n\t\t\tconst items: ApiItem[] = [];\n\t\t\tfor (const members of membersByName.values()) {\n\t\t\t\titems.push(...members);\n\t\t\t}\n\n\t\t\tfor (const members of membersByKind.values()) {\n\t\t\t\titems.push(...members);\n\t\t\t}\n\n\t\t\titems.sort((x: ApiItem, y: ApiItem) => x.getSortKey().localeCompare(y.getSortKey()));\n\n\t\t\treturn {\n\t\t\t\titems,\n\t\t\t\tmessages,\n\t\t\t\tmaybeIncompleteResult,\n\t\t\t};\n\t\t}\n\n\t\t/**\n\t\t * @internal\n\t\t */\n\t\tpublic _getMergedSiblingsForMember(memberApiItem: ApiItem): readonly ApiItem[] {\n\t\t\tthis._ensureMemberMaps();\n\t\t\tlet result: ApiItem[] | undefined;\n\t\t\tif (ApiNameMixin.isBaseClassOf(memberApiItem)) {\n\t\t\t\tresult = this[_membersByName]!.get(memberApiItem.name);\n\t\t\t} else {\n\t\t\t\tresult = this[_membersByKind]!.get(memberApiItem.kind);\n\t\t\t}\n\n\t\t\tif (!result) {\n\t\t\t\tthrow new InternalError('Item was not found in the _membersByName/_membersByKind lookup');\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\t/**\n\t\t * @internal\n\t\t */\n\t\tpublic _ensureMemberMaps(): void {\n\t\t\t// Build the _membersByName and _membersByKind tables if they don't already exist\n\t\t\tif (this[_membersByName] === undefined) {\n\t\t\t\tconst membersByName: Map<string, ApiItem[]> = new Map<string, ApiItem[]>();\n\t\t\t\tconst membersByKind: Map<string, ApiItem[]> = new Map<string, ApiItem[]>();\n\n\t\t\t\tfor (const member of this[_members]) {\n\t\t\t\t\tlet map: Map<ApiItemKind, ApiItem[]> | Map<string, ApiItem[]>;\n\t\t\t\t\tlet key: ApiItemKind | string;\n\n\t\t\t\t\tif (ApiNameMixin.isBaseClassOf(member)) {\n\t\t\t\t\t\tmap = membersByName;\n\t\t\t\t\t\tkey = member.name;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmap = membersByKind;\n\t\t\t\t\t\tkey = member.kind;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet list: ApiItem[] | undefined = map.get(key);\n\t\t\t\t\tif (list === undefined) {\n\t\t\t\t\t\tlist = [];\n\t\t\t\t\t\tmap.set(key, list);\n\t\t\t\t\t}\n\n\t\t\t\t\tlist.push(member);\n\t\t\t\t}\n\n\t\t\t\tthis[_membersByName] = membersByName;\n\t\t\t\tthis[_membersByKind] = membersByKind;\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic override serializeInto(jsonObject: Partial<IApiItemContainerJson>): void {\n\t\t\tsuper.serializeInto(jsonObject);\n\n\t\t\tconst memberObjects: IApiItemJson[] = [];\n\n\t\t\tfor (const member of this.members) {\n\t\t\t\tconst memberJsonObject: Partial<IApiItemJson> = {};\n\t\t\t\tmember.serializeInto(memberJsonObject);\n\t\t\t\tmemberObjects.push(memberJsonObject as IApiItemJson);\n\t\t\t}\n\n\t\t\tjsonObject.preserveMemberOrder = this.preserveMemberOrder;\n\t\t\tjsonObject.members = memberObjects;\n\t\t}\n\t}\n\n\treturn MixedClass;\n}\n\n/**\n * Static members for {@link (ApiItemContainerMixin:interface)}.\n *\n * @public\n */\n\nexport namespace ApiItemContainerMixin {\n\t/**\n\t * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiItemContainerMixin` mixin.\n\t *\n\t * @remarks\n\t *\n\t * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of\n\t * the mixin function produces a different subclass.  (This could be mitigated by `Symbol.hasInstance`, however\n\t * the TypeScript type system cannot invoke a runtime test.)\n\t */\n\texport function isBaseClassOf(apiItem: ApiItem): apiItem is ApiItemContainerMixin {\n\t\treturn apiItem.hasOwnProperty(_members);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/ApiNameMixin.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem.js';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\n\n/**\n * Constructor options for {@link (IApiNameMixinOptions:interface)}.\n *\n * @public\n */\nexport interface IApiNameMixinOptions extends IApiItemOptions {\n\tname: string;\n}\n\nexport interface IApiNameMixinJson extends IApiItemJson {\n\tname: string;\n}\n\nconst _name: unique symbol = Symbol('ApiNameMixin._name');\n\n/**\n * The mixin base class for API items that have a name.  For example, a class has a name, but a class constructor\n * does not.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.  The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use\n * TypeScript \"mixin\" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various\n * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class\n * to extend more than one base class).  The \"mixin\" is a TypeScript merged declaration with three components:\n * the function that generates a subclass, an interface that describes the members of the subclass, and\n * a namespace containing static members of the class.\n * @public\n */\n\nexport interface ApiNameMixin extends ApiItem {\n\t/**\n\t * The exported name of this API item.\n\t *\n\t * @remarks\n\t * Note that due tue type aliasing, the exported name may be different from the locally declared name.\n\t */\n\treadonly name: string;\n\n\t/**\n\t * @override\n\t */\n\tserializeInto(jsonObject: Partial<IApiItemJson>): void;\n}\n\n/**\n * Mixin function for {@link (ApiNameMixin:interface)}.\n *\n * @param baseClass - The base class to be extended\n * @returns A child class that extends baseClass, adding the {@link (ApiNameMixin:interface)} functionality.\n * @public\n */\nexport function ApiNameMixin<TBaseClass extends IApiItemConstructor>(\n\tbaseClass: TBaseClass,\n): TBaseClass & (new (...args: any[]) => ApiNameMixin) {\n\tclass MixedClass extends baseClass implements ApiNameMixin {\n\t\tpublic readonly [_name]: string;\n\n\t\tpublic constructor(...args: any[]) {\n\t\t\tsuper(...args);\n\n\t\t\tconst options: IApiNameMixinOptions = args[0];\n\t\t\tthis[_name] = options.name;\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic static override onDeserializeInto(\n\t\t\toptions: Partial<IApiNameMixinOptions>,\n\t\t\tcontext: DeserializerContext,\n\t\t\tjsonObject: IApiNameMixinJson,\n\t\t): void {\n\t\t\tbaseClass.onDeserializeInto(options, context, jsonObject);\n\n\t\t\toptions.name = jsonObject.name;\n\t\t}\n\n\t\tpublic get name(): string {\n\t\t\treturn this[_name];\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic override get displayName(): string {\n\t\t\treturn this[_name];\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic override serializeInto(jsonObject: Partial<IApiNameMixinJson>): void {\n\t\t\tsuper.serializeInto(jsonObject);\n\n\t\t\tjsonObject.name = this.name;\n\t\t}\n\t}\n\n\treturn MixedClass;\n}\n\n/**\n * Static members for {@link (ApiNameMixin:interface)}.\n *\n * @public\n */\nexport namespace ApiNameMixin {\n\t/**\n\t * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiNameMixin` mixin.\n\t *\n\t * @remarks\n\t *\n\t * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of\n\t * the mixin function produces a different subclass.  (This could be mitigated by `Symbol.hasInstance`, however\n\t * the TypeScript type system cannot invoke a runtime test.)\n\t */\n\texport function isBaseClassOf(apiItem: ApiItem): apiItem is ApiNameMixin {\n\t\treturn apiItem.hasOwnProperty(_name);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/ApiOptionalMixin.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem.js';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\n\n/**\n * Constructor options for {@link (IApiOptionalMixinOptions:interface)}.\n *\n * @public\n */\nexport interface IApiOptionalMixinOptions extends IApiItemOptions {\n\tisOptional: boolean;\n}\n\nexport interface IApiOptionalMixinJson extends IApiItemJson {\n\tisOptional: boolean;\n}\n\nconst _isOptional: unique symbol = Symbol('ApiOptionalMixin._isOptional');\n\n/**\n * The mixin base class for API items that can be marked as optional by appending a `?` to them.\n * For example, a property of an interface can be optional.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.  The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use\n * TypeScript \"mixin\" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various\n * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class\n * to extend more than one base class).  The \"mixin\" is a TypeScript merged declaration with three components:\n * the function that generates a subclass, an interface that describes the members of the subclass, and\n * a namespace containing static members of the class.\n * @public\n */\n\nexport interface ApiOptionalMixin extends ApiItem {\n\t/**\n\t * True if this is an optional property.\n\t *\n\t * @remarks\n\t * For example:\n\t * ```ts\n\t * interface X {\n\t *   y: string;   // not optional\n\t *   z?: string;  // optional\n\t * }\n\t * ```\n\t */\n\treadonly isOptional: boolean;\n\n\t/**\n\t * @override\n\t */\n\tserializeInto(jsonObject: Partial<IApiItemJson>): void;\n}\n\n/**\n * Mixin function for {@link (ApiOptionalMixin:interface)}.\n *\n * @param baseClass - The base class to be extended\n * @returns A child class that extends baseClass, adding the {@link (ApiOptionalMixin:interface)} functionality.\n * @public\n */\nexport function ApiOptionalMixin<TBaseClass extends IApiItemConstructor>(\n\tbaseClass: TBaseClass,\n): TBaseClass & (new (...args: any[]) => ApiOptionalMixin) {\n\tclass MixedClass extends baseClass implements ApiOptionalMixin {\n\t\tpublic [_isOptional]: boolean;\n\n\t\tpublic constructor(...args: any[]) {\n\t\t\tsuper(...args);\n\n\t\t\tconst options: IApiOptionalMixinOptions = args[0];\n\t\t\tthis[_isOptional] = Boolean(options.isOptional);\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic static override onDeserializeInto(\n\t\t\toptions: Partial<IApiOptionalMixinOptions>,\n\t\t\tcontext: DeserializerContext,\n\t\t\tjsonObject: IApiOptionalMixinJson,\n\t\t): void {\n\t\t\tbaseClass.onDeserializeInto(options, context, jsonObject);\n\n\t\t\toptions.isOptional = Boolean(jsonObject.isOptional);\n\t\t}\n\n\t\tpublic get isOptional(): boolean {\n\t\t\treturn this[_isOptional];\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic override serializeInto(jsonObject: Partial<IApiOptionalMixinJson>): void {\n\t\t\tsuper.serializeInto(jsonObject);\n\n\t\t\tjsonObject.isOptional = this.isOptional;\n\t\t}\n\t}\n\n\treturn MixedClass;\n}\n\n/**\n * Optional members for {@link (ApiOptionalMixin:interface)}.\n *\n * @public\n */\nexport namespace ApiOptionalMixin {\n\t/**\n\t * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiOptionalMixin` mixin.\n\t *\n\t * @remarks\n\t *\n\t * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of\n\t * the mixin function produces a different subclass.  (This could be mitigated by `Symbol.hasInstance`, however\n\t * the TypeScript type system cannot invoke a runtime test.)\n\t */\n\texport function isBaseClassOf(apiItem: ApiItem): apiItem is ApiOptionalMixin {\n\t\treturn apiItem.hasOwnProperty(_isOptional);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/ApiParameterListMixin.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError } from '@rushstack/node-core-library';\nimport { ApiDeclaredItem } from '../items/ApiDeclaredItem.js';\nimport type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem.js';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\nimport { Parameter } from '../model/Parameter.js';\nimport type { IExcerptTokenRange } from './Excerpt.js';\n\n/**\n * Represents parameter information that is part of {@link IApiParameterListMixinOptions}\n *\n * @public\n */\nexport interface IApiParameterOptions {\n\tdefaultValue: string | undefined;\n\tisOptional: boolean;\n\tisRest: boolean;\n\tparameterName: string;\n\tparameterTypeTokenRange: IExcerptTokenRange;\n}\n\n/**\n * Constructor options for {@link (ApiParameterListMixin:interface)}.\n *\n * @public\n */\nexport interface IApiParameterListMixinOptions extends IApiItemOptions {\n\toverloadIndex: number;\n\tparameters: IApiParameterOptions[];\n}\n\nexport interface IApiParameterListJson extends IApiItemJson {\n\toverloadIndex: number;\n\tparameters: IApiParameterOptions[];\n}\n\nconst _overloadIndex: unique symbol = Symbol('ApiParameterListMixin._overloadIndex');\nconst _parameters: unique symbol = Symbol('ApiParameterListMixin._parameters');\n\n/**\n * The mixin base class for API items that can have function parameters (but not necessarily a return value).\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.  The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use\n * TypeScript \"mixin\" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various\n * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class\n * to extend more than one base class).  The \"mixin\" is a TypeScript merged declaration with three components:\n * the function that generates a subclass, an interface that describes the members of the subclass, and\n * a namespace containing static members of the class.\n * @public\n */\n\nexport interface ApiParameterListMixin extends ApiItem {\n\t/**\n\t * When a function has multiple overloaded declarations, this one-based integer index can be used to uniquely\n\t * identify them.\n\t *\n\t * @remarks\n\t *\n\t * Consider this overloaded declaration:\n\t *\n\t * ```ts\n\t * export namespace Versioning {\n\t *   // TSDoc: Versioning.(addVersions:1)\n\t *   export function addVersions(x: number, y: number): number;\n\t *\n\t *   // TSDoc: Versioning.(addVersions:2)\n\t *   export function addVersions(x: string, y: string): string;\n\t *\n\t *   // (implementation)\n\t *   export function addVersions(x: number|string, y: number|string): number|string {\n\t *     // . . .\n\t *   }\n\t * }\n\t * ```\n\t *\n\t * In the above example, there are two overloaded declarations.  The overload using numbers will have\n\t * `overloadIndex = 1`.  The overload using strings will have `overloadIndex = 2`.  The third declaration that\n\t * accepts all possible inputs is considered part of the implementation, and is not processed by API Extractor.\n\t */\n\treadonly overloadIndex: number;\n\n\t/**\n\t * The function parameters.\n\t */\n\treadonly parameters: readonly Parameter[];\n\n\tserializeInto(jsonObject: Partial<IApiItemJson>): void;\n}\n\n/**\n * Mixin function for {@link (ApiParameterListMixin:interface)}.\n *\n * @param baseClass - The base class to be extended\n * @returns A child class that extends baseClass, adding the {@link (ApiParameterListMixin:interface)} functionality.\n * @public\n */\nexport function ApiParameterListMixin<TBaseClass extends IApiItemConstructor>(\n\tbaseClass: TBaseClass,\n): TBaseClass & (new (...args: any[]) => ApiParameterListMixin) {\n\tclass MixedClass extends baseClass implements ApiParameterListMixin {\n\t\tpublic readonly [_overloadIndex]: number;\n\n\t\tpublic readonly [_parameters]: Parameter[];\n\n\t\tpublic constructor(...args: any[]) {\n\t\t\tsuper(...args);\n\n\t\t\tconst options: IApiParameterListMixinOptions = args[0];\n\t\t\tthis[_overloadIndex] = options.overloadIndex;\n\n\t\t\tthis[_parameters] = [];\n\n\t\t\tif (this instanceof ApiDeclaredItem) {\n\t\t\t\tif (options.parameters) {\n\t\t\t\t\tfor (const parameterOptions of options.parameters) {\n\t\t\t\t\t\tconst parameter: Parameter = new Parameter({\n\t\t\t\t\t\t\tname: parameterOptions.parameterName,\n\t\t\t\t\t\t\tparameterTypeExcerpt: this.buildExcerpt(parameterOptions.parameterTypeTokenRange),\n\t\t\t\t\t\t\t// Prior to ApiJsonSchemaVersion.V_1005 this input will be undefined\n\t\t\t\t\t\t\tisOptional: Boolean(parameterOptions.isOptional),\n\t\t\t\t\t\t\tisRest: Boolean(parameterOptions.isRest),\n\t\t\t\t\t\t\tparent: this,\n\t\t\t\t\t\t\tdefaultValue: parameterOptions.defaultValue,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tthis[_parameters].push(parameter);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthrow new InternalError('ApiReturnTypeMixin expects a base class that inherits from ApiDeclaredItem');\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic static override onDeserializeInto(\n\t\t\toptions: Partial<IApiParameterListMixinOptions>,\n\t\t\tcontext: DeserializerContext,\n\t\t\tjsonObject: IApiParameterListJson,\n\t\t): void {\n\t\t\tbaseClass.onDeserializeInto(options, context, jsonObject);\n\n\t\t\toptions.overloadIndex = jsonObject.overloadIndex;\n\t\t\toptions.parameters = jsonObject.parameters || [];\n\t\t}\n\n\t\tpublic get overloadIndex(): number {\n\t\t\treturn this[_overloadIndex];\n\t\t}\n\n\t\tpublic get parameters(): readonly Parameter[] {\n\t\t\treturn this[_parameters];\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic override serializeInto(jsonObject: Partial<IApiParameterListJson>): void {\n\t\t\tsuper.serializeInto(jsonObject);\n\n\t\t\tjsonObject.overloadIndex = this.overloadIndex;\n\n\t\t\tconst parameterObjects: IApiParameterOptions[] = [];\n\t\t\tfor (const parameter of this.parameters) {\n\t\t\t\tparameterObjects.push({\n\t\t\t\t\tparameterName: parameter.name,\n\t\t\t\t\tparameterTypeTokenRange: parameter.parameterTypeExcerpt.tokenRange,\n\t\t\t\t\tisOptional: parameter.isOptional,\n\t\t\t\t\tisRest: parameter.isRest,\n\t\t\t\t\tdefaultValue: parameter.defaultValue,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tjsonObject.parameters = parameterObjects;\n\t\t}\n\t}\n\n\treturn MixedClass;\n}\n\n/**\n * Static members for {@link (ApiParameterListMixin:interface)}.\n *\n * @public\n */\nexport namespace ApiParameterListMixin {\n\t/**\n\t * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiParameterListMixin` mixin.\n\t *\n\t * @remarks\n\t *\n\t * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of\n\t * the mixin function produces a different subclass.  (This could be mitigated by `Symbol.hasInstance`, however\n\t * the TypeScript type system cannot invoke a runtime test.)\n\t */\n\texport function isBaseClassOf(apiItem: ApiItem): apiItem is ApiParameterListMixin {\n\t\treturn apiItem.hasOwnProperty(_parameters);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/ApiProtectedMixin.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem.js';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\n\n/**\n * Constructor options for {@link (IApiProtectedMixinOptions:interface)}.\n *\n * @public\n */\nexport interface IApiProtectedMixinOptions extends IApiItemOptions {\n\tisProtected: boolean;\n}\n\nexport interface IApiProtectedMixinJson extends IApiItemJson {\n\tisProtected: boolean;\n}\n\nconst _isProtected: unique symbol = Symbol('ApiProtectedMixin._isProtected');\n\n/**\n * The mixin base class for API items that can have the TypeScript `protected` keyword applied to them.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.  The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use\n * TypeScript \"mixin\" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various\n * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class\n * to extend more than one base class).  The \"mixin\" is a TypeScript merged declaration with three components:\n * the function that generates a subclass, an interface that describes the members of the subclass, and\n * a namespace containing static members of the class.\n * @public\n */\n\nexport interface ApiProtectedMixin extends ApiItem {\n\t/**\n\t * Whether the declaration has the TypeScript `protected` keyword.\n\t */\n\treadonly isProtected: boolean;\n\n\t/**\n\t * @override\n\t */\n\tserializeInto(jsonObject: Partial<IApiItemJson>): void;\n}\n\n/**\n * Mixin function for {@link (ApiProtectedMixin:interface)}.\n *\n * @param baseClass - The base class to be extended\n * @returns A child class that extends baseClass, adding the {@link (ApiProtectedMixin:interface)} functionality.\n * @public\n */\nexport function ApiProtectedMixin<TBaseClass extends IApiItemConstructor>(\n\tbaseClass: TBaseClass,\n): TBaseClass & (new (...args: any[]) => ApiProtectedMixin) {\n\tclass MixedClass extends baseClass implements ApiProtectedMixin {\n\t\tpublic [_isProtected]: boolean;\n\n\t\tpublic constructor(...args: any[]) {\n\t\t\tsuper(...args);\n\n\t\t\tconst options: IApiProtectedMixinOptions = args[0];\n\t\t\tthis[_isProtected] = options.isProtected;\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic static override onDeserializeInto(\n\t\t\toptions: Partial<IApiProtectedMixinOptions>,\n\t\t\tcontext: DeserializerContext,\n\t\t\tjsonObject: IApiProtectedMixinJson,\n\t\t): void {\n\t\t\tbaseClass.onDeserializeInto(options, context, jsonObject);\n\n\t\t\toptions.isProtected = jsonObject.isProtected;\n\t\t}\n\n\t\tpublic get isProtected(): boolean {\n\t\t\treturn this[_isProtected];\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic override serializeInto(jsonObject: Partial<IApiProtectedMixinJson>): void {\n\t\t\tsuper.serializeInto(jsonObject);\n\n\t\t\tjsonObject.isProtected = this.isProtected;\n\t\t}\n\t}\n\n\treturn MixedClass;\n}\n\n/**\n * Static members for {@link (ApiProtectedMixin:interface)}.\n *\n * @public\n */\nexport namespace ApiProtectedMixin {\n\t/**\n\t * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiProtectedMixin` mixin.\n\t *\n\t * @remarks\n\t *\n\t * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of\n\t * the mixin function produces a different subclass.  (This could be mitigated by `Symbol.hasInstance`, however\n\t * the TypeScript type system cannot invoke a runtime test.)\n\t */\n\texport function isBaseClassOf(apiItem: ApiItem): apiItem is ApiProtectedMixin {\n\t\treturn apiItem.hasOwnProperty(_isProtected);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/ApiReadonlyMixin.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem.js';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\n\n/**\n * Constructor options for {@link (ApiReadonlyMixin:interface)}.\n *\n * @public\n */\nexport interface IApiReadonlyMixinOptions extends IApiItemOptions {\n\tisReadonly: boolean;\n}\n\nexport interface IApiReadonlyMixinJson extends IApiItemJson {\n\tisReadonly: boolean;\n}\n\nconst _isReadonly: unique symbol = Symbol('ApiReadonlyMixin._isReadonly');\n\n/**\n * The mixin base class for API items that cannot be modified after instantiation.\n * Examples such as the readonly modifier and only having a getter but no setter.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.  The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use\n * TypeScript \"mixin\" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various\n * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class\n * to extend more than one base class).  The \"mixin\" is a TypeScript merged declaration with three components:\n * the function that generates a subclass, an interface that describes the members of the subclass, and\n * a namespace containing static members of the class.\n * @public\n */\n\nexport interface ApiReadonlyMixin extends ApiItem {\n\t/**\n\t * Indicates that the API item's value cannot be assigned by an external consumer.\n\t *\n\t * @remarks\n\t * Examples of API items that would be considered \"read only\" by API Extractor:\n\t *\n\t * - A class or interface's property that has the `readonly` modifier.\n\t *\n\t * - A variable that has the `const` modifier.\n\t *\n\t * - A property or variable whose TSDoc comment includes the `@readonly` tag.\n\t *\n\t * - A property declaration with a getter but no setter.\n\t *\n\t * Note that if the `readonly` keyword appears in a type annotation, this does not\n\t * guarantee that that the API item will be considered readonly. For example:\n\t *\n\t * ```ts\n\t * declare class C {\n\t *   // isReadonly=false in this case, because C.x is assignable\n\t *   public x: readonly string[];\n\t * }\n\t * ```\n\t */\n\treadonly isReadonly: boolean;\n\n\tserializeInto(jsonObject: Partial<IApiItemJson>): void;\n}\n\n/**\n * Mixin function for {@link (ApiReadonlyMixin:interface)}.\n *\n * @param baseClass - The base class to be extended\n * @returns A child class that extends baseClass, adding the {@link (ApiReadonlyMixin:interface)}\n * functionality.\n * @public\n */\nexport function ApiReadonlyMixin<TBaseClass extends IApiItemConstructor>(\n\tbaseClass: TBaseClass,\n): TBaseClass & (new (...args: any[]) => ApiReadonlyMixin) {\n\tclass MixedClass extends baseClass implements ApiReadonlyMixin {\n\t\tpublic [_isReadonly]: boolean;\n\n\t\tpublic constructor(...args: any[]) {\n\t\t\tsuper(...args);\n\n\t\t\tconst options: IApiReadonlyMixinOptions = args[0];\n\t\t\tthis[_isReadonly] = options.isReadonly;\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic static override onDeserializeInto(\n\t\t\toptions: Partial<IApiReadonlyMixinOptions>,\n\t\t\tcontext: DeserializerContext,\n\t\t\tjsonObject: IApiReadonlyMixinJson,\n\t\t): void {\n\t\t\tbaseClass.onDeserializeInto(options, context, jsonObject);\n\n\t\t\toptions.isReadonly = jsonObject.isReadonly || false;\n\t\t}\n\n\t\tpublic get isReadonly(): boolean {\n\t\t\treturn this[_isReadonly];\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic override serializeInto(jsonObject: Partial<IApiReadonlyMixinJson>): void {\n\t\t\tsuper.serializeInto(jsonObject);\n\n\t\t\tjsonObject.isReadonly = this.isReadonly;\n\t\t}\n\t}\n\n\treturn MixedClass;\n}\n\n/**\n * Static members for {@link (ApiReadonlyMixin:interface)}.\n *\n * @public\n */\nexport namespace ApiReadonlyMixin {\n\t/**\n\t * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiReadonlyMixin` mixin.\n\t *\n\t * @remarks\n\t *\n\t * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of\n\t * the mixin function produces a different subclass.  (This could be mitigated by `Symbol.hasInstance`, however\n\t * the TypeScript type system cannot invoke a runtime test.)\n\t */\n\texport function isBaseClassOf(apiItem: ApiItem): apiItem is ApiReadonlyMixin {\n\t\treturn apiItem.hasOwnProperty(_isReadonly);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/ApiReleaseTagMixin.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { Enum } from '@rushstack/node-core-library';\nimport { ReleaseTag } from '../aedoc/ReleaseTag.js';\nimport type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem.js';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\n\n/**\n * Constructor options for {@link (ApiReleaseTagMixin:interface)}.\n *\n * @public\n */\nexport interface IApiReleaseTagMixinOptions extends IApiItemOptions {\n\treleaseTag: ReleaseTag;\n}\n\nexport interface IApiReleaseTagMixinJson extends IApiItemJson {\n\treleaseTag: string;\n}\n\nconst _releaseTag: unique symbol = Symbol('ApiReleaseTagMixin._releaseTag');\n\n/**\n * The mixin base class for API items that can be attributed with a TSDoc tag such as `@internal`,\n * `@alpha`, `@beta`, or `@public`.  These \"release tags\" indicate the support level for an API.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.  The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use\n * TypeScript \"mixin\" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various\n * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class\n * to extend more than one base class).  The \"mixin\" is a TypeScript merged declaration with three components:\n * the function that generates a subclass, an interface that describes the members of the subclass, and\n * a namespace containing static members of the class.\n * @public\n */\n\nexport interface ApiReleaseTagMixin extends ApiItem {\n\t/**\n\t * The effective release tag for this declaration.  If it is not explicitly specified, the value may be\n\t * inherited from a containing declaration.\n\t *\n\t * @remarks\n\t * For example, an `ApiEnumMember` may inherit its release tag from the containing `ApiEnum`.\n\t */\n\treadonly releaseTag: ReleaseTag;\n\n\t/**\n\t * @override\n\t */\n\tserializeInto(jsonObject: Partial<IApiItemJson>): void;\n}\n\n/**\n * Mixin function for {@link (ApiReleaseTagMixin:interface)}.\n *\n * @param baseClass - The base class to be extended\n * @returns A child class that extends baseClass, adding the {@link (ApiReleaseTagMixin:interface)} functionality.\n * @public\n */\nexport function ApiReleaseTagMixin<TBaseClass extends IApiItemConstructor>(\n\tbaseClass: TBaseClass,\n): TBaseClass & (new (...args: any[]) => ApiReleaseTagMixin) {\n\tclass MixedClass extends baseClass implements ApiReleaseTagMixin {\n\t\tpublic [_releaseTag]: ReleaseTag;\n\n\t\tpublic constructor(...args: any[]) {\n\t\t\tsuper(...args);\n\n\t\t\tconst options: IApiReleaseTagMixinOptions = args[0];\n\t\t\tthis[_releaseTag] = options.releaseTag;\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic static override onDeserializeInto(\n\t\t\toptions: Partial<IApiReleaseTagMixinOptions>,\n\t\t\tcontext: DeserializerContext,\n\t\t\tjsonObject: IApiReleaseTagMixinJson,\n\t\t): void {\n\t\t\tbaseClass.onDeserializeInto(options, context, jsonObject);\n\n\t\t\tconst deserializedReleaseTag: ReleaseTag | undefined = Enum.tryGetValueByKey<ReleaseTag>(\n\t\t\t\tReleaseTag as any,\n\t\t\t\tjsonObject.releaseTag,\n\t\t\t);\n\t\t\tif (deserializedReleaseTag === undefined) {\n\t\t\t\tthrow new Error(`Failed to deserialize release tag ${JSON.stringify(jsonObject.releaseTag)}`);\n\t\t\t}\n\n\t\t\toptions.releaseTag = deserializedReleaseTag;\n\t\t}\n\n\t\tpublic get releaseTag(): ReleaseTag {\n\t\t\treturn this[_releaseTag];\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic override serializeInto(jsonObject: Partial<IApiReleaseTagMixinJson>): void {\n\t\t\tsuper.serializeInto(jsonObject);\n\n\t\t\tjsonObject.releaseTag = ReleaseTag[this.releaseTag];\n\t\t}\n\t}\n\n\treturn MixedClass;\n}\n\n/**\n * Static members for {@link (ApiReleaseTagMixin:interface)}.\n *\n * @public\n */\nexport namespace ApiReleaseTagMixin {\n\t/**\n\t * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiReleaseTagMixin` mixin.\n\t *\n\t * @remarks\n\t *\n\t * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of\n\t * the mixin function produces a different subclass.  (This could be mitigated by `Symbol.hasInstance`, however\n\t * the TypeScript type system cannot invoke a runtime test.)\n\t */\n\texport function isBaseClassOf(apiItem: ApiItem): apiItem is ApiReleaseTagMixin {\n\t\treturn apiItem.hasOwnProperty(_releaseTag);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/ApiReturnTypeMixin.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError } from '@rushstack/node-core-library';\nimport { ApiDeclaredItem } from '../items/ApiDeclaredItem.js';\nimport type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem.js';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\nimport type { IExcerptTokenRange, Excerpt } from './Excerpt.js';\n\n/**\n * Constructor options for {@link (ApiReturnTypeMixin:interface)}.\n *\n * @public\n */\nexport interface IApiReturnTypeMixinOptions extends IApiItemOptions {\n\treturnTypeTokenRange: IExcerptTokenRange;\n}\n\nexport interface IApiReturnTypeMixinJson extends IApiItemJson {\n\treturnTypeTokenRange: IExcerptTokenRange;\n}\n\nconst _returnTypeExcerpt: unique symbol = Symbol('ApiReturnTypeMixin._returnTypeExcerpt');\n\n/**\n * The mixin base class for API items that are functions that return a value.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.  The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use\n * TypeScript \"mixin\" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various\n * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class\n * to extend more than one base class).  The \"mixin\" is a TypeScript merged declaration with three components:\n * the function that generates a subclass, an interface that describes the members of the subclass, and\n * a namespace containing static members of the class.\n * @public\n */\n\nexport interface ApiReturnTypeMixin extends ApiItem {\n\t/**\n\t * An {@link Excerpt} that describes the type of the function's return value.\n\t */\n\treadonly returnTypeExcerpt: Excerpt;\n\n\t/**\n\t * @override\n\t */\n\tserializeInto(jsonObject: Partial<IApiReturnTypeMixinJson>): void;\n}\n\n/**\n * Mixin function for {@link (ApiReturnTypeMixin:interface)}.\n *\n * @param baseClass - The base class to be extended\n * @returns A child class that extends baseClass, adding the {@link (ApiReturnTypeMixin:interface)} functionality.\n * @public\n */\nexport function ApiReturnTypeMixin<TBaseClass extends IApiItemConstructor>(\n\tbaseClass: TBaseClass,\n): TBaseClass & (new (...args: any[]) => ApiReturnTypeMixin) {\n\tclass MixedClass extends baseClass implements ApiReturnTypeMixin {\n\t\tpublic [_returnTypeExcerpt]: Excerpt;\n\n\t\tpublic constructor(...args: any[]) {\n\t\t\tsuper(...args);\n\n\t\t\tconst options: IApiReturnTypeMixinOptions = args[0];\n\n\t\t\tif (this instanceof ApiDeclaredItem) {\n\t\t\t\tthis[_returnTypeExcerpt] = this.buildExcerpt(options.returnTypeTokenRange);\n\t\t\t} else {\n\t\t\t\tthrow new InternalError('ApiReturnTypeMixin expects a base class that inherits from ApiDeclaredItem');\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic static override onDeserializeInto(\n\t\t\toptions: Partial<IApiReturnTypeMixinOptions>,\n\t\t\tcontext: DeserializerContext,\n\t\t\tjsonObject: IApiReturnTypeMixinJson,\n\t\t): void {\n\t\t\tbaseClass.onDeserializeInto(options, context, jsonObject);\n\n\t\t\toptions.returnTypeTokenRange = jsonObject.returnTypeTokenRange;\n\t\t}\n\n\t\tpublic get returnTypeExcerpt(): Excerpt {\n\t\t\treturn this[_returnTypeExcerpt];\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic override serializeInto(jsonObject: Partial<IApiReturnTypeMixinJson>): void {\n\t\t\tsuper.serializeInto(jsonObject);\n\n\t\t\tjsonObject.returnTypeTokenRange = this.returnTypeExcerpt.tokenRange;\n\t\t}\n\t}\n\n\treturn MixedClass;\n}\n\n/**\n * Static members for {@link (ApiReturnTypeMixin:interface)}.\n *\n * @public\n */\nexport namespace ApiReturnTypeMixin {\n\t/**\n\t * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiReturnTypeMixin` mixin.\n\t *\n\t * @remarks\n\t *\n\t * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of\n\t * the mixin function produces a different subclass.  (This could be mitigated by `Symbol.hasInstance`, however\n\t * the TypeScript type system cannot invoke a runtime test.)\n\t */\n\texport function isBaseClassOf(apiItem: ApiItem): apiItem is ApiReturnTypeMixin {\n\t\treturn apiItem.hasOwnProperty(_returnTypeExcerpt);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/ApiStaticMixin.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem.js';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\n\n/**\n * Constructor options for {@link (IApiStaticMixinOptions:interface)}.\n *\n * @public\n */\nexport interface IApiStaticMixinOptions extends IApiItemOptions {\n\tisStatic: boolean;\n}\n\nexport interface IApiStaticMixinJson extends IApiItemJson {\n\tisStatic: boolean;\n}\n\nconst _isStatic: unique symbol = Symbol('ApiStaticMixin._isStatic');\n\n/**\n * The mixin base class for API items that can have the TypeScript `static` keyword applied to them.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.  The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use\n * TypeScript \"mixin\" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various\n * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class\n * to extend more than one base class).  The \"mixin\" is a TypeScript merged declaration with three components:\n * the function that generates a subclass, an interface that describes the members of the subclass, and\n * a namespace containing static members of the class.\n * @public\n */\n\nexport interface ApiStaticMixin extends ApiItem {\n\t/**\n\t * Whether the declaration has the TypeScript `static` keyword.\n\t */\n\treadonly isStatic: boolean;\n\n\t/**\n\t * @override\n\t */\n\tserializeInto(jsonObject: Partial<IApiItemJson>): void;\n}\n\n/**\n * Mixin function for {@link (ApiStaticMixin:interface)}.\n *\n * @param baseClass - The base class to be extended\n * @returns A child class that extends baseClass, adding the {@link (ApiStaticMixin:interface)} functionality.\n * @public\n */\nexport function ApiStaticMixin<TBaseClass extends IApiItemConstructor>(\n\tbaseClass: TBaseClass,\n): TBaseClass & (new (...args: any[]) => ApiStaticMixin) {\n\tclass MixedClass extends baseClass implements ApiStaticMixin {\n\t\tpublic [_isStatic]: boolean;\n\n\t\tpublic constructor(...args: any[]) {\n\t\t\tsuper(...args);\n\n\t\t\tconst options: IApiStaticMixinOptions = args[0];\n\t\t\tthis[_isStatic] = options.isStatic;\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic static override onDeserializeInto(\n\t\t\toptions: Partial<IApiStaticMixinOptions>,\n\t\t\tcontext: DeserializerContext,\n\t\t\tjsonObject: IApiStaticMixinJson,\n\t\t): void {\n\t\t\tbaseClass.onDeserializeInto(options, context, jsonObject);\n\n\t\t\toptions.isStatic = jsonObject.isStatic;\n\t\t}\n\n\t\tpublic get isStatic(): boolean {\n\t\t\treturn this[_isStatic];\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic override serializeInto(jsonObject: Partial<IApiStaticMixinJson>): void {\n\t\t\tsuper.serializeInto(jsonObject);\n\n\t\t\tjsonObject.isStatic = this.isStatic;\n\t\t}\n\t}\n\n\treturn MixedClass;\n}\n\n/**\n * Static members for {@link (ApiStaticMixin:interface)}.\n *\n * @public\n */\nexport namespace ApiStaticMixin {\n\t/**\n\t * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiStaticMixin` mixin.\n\t *\n\t * @remarks\n\t *\n\t * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of\n\t * the mixin function produces a different subclass.  (This could be mitigated by `Symbol.hasInstance`, however\n\t * the TypeScript type system cannot invoke a runtime test.)\n\t */\n\texport function isBaseClassOf(apiItem: ApiItem): apiItem is ApiStaticMixin {\n\t\treturn apiItem.hasOwnProperty(_isStatic);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/ApiTypeParameterListMixin.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError } from '@rushstack/node-core-library';\nimport { ApiDeclaredItem } from '../items/ApiDeclaredItem.js';\nimport type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem.js';\nimport type { DeserializerContext } from '../model/DeserializerContext.js';\nimport { TypeParameter } from '../model/TypeParameter.js';\nimport type { Excerpt, IExcerptTokenRange } from './Excerpt.js';\n\n/**\n * Represents parameter information that is part of {@link IApiTypeParameterListMixinOptions}\n *\n * @public\n */\nexport interface IApiTypeParameterOptions {\n\tconstraintTokenRange: IExcerptTokenRange;\n\tdefaultTypeTokenRange: IExcerptTokenRange;\n\ttypeParameterName: string;\n}\n\n/**\n * Constructor options for {@link (ApiTypeParameterListMixin:interface)}.\n *\n * @public\n */\nexport interface IApiTypeParameterListMixinOptions extends IApiItemOptions {\n\ttypeParameters: IApiTypeParameterOptions[];\n}\n\nexport interface IApiTypeParameterListMixinJson extends IApiItemJson {\n\ttypeParameters: IApiTypeParameterOptions[];\n}\n\nconst _typeParameters: unique symbol = Symbol('ApiTypeParameterListMixin._typeParameters');\n\n/**\n * The mixin base class for API items that can have type parameters.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.  The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use\n * TypeScript \"mixin\" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various\n * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class\n * to extend more than one base class).  The \"mixin\" is a TypeScript merged declaration with three components:\n * the function that generates a subclass, an interface that describes the members of the subclass, and\n * a namespace containing static members of the class.\n * @public\n */\n\nexport interface ApiTypeParameterListMixin extends ApiItem {\n\tserializeInto(jsonObject: Partial<IApiItemJson>): void;\n\n\t/**\n\t * The type parameters.\n\t */\n\treadonly typeParameters: readonly TypeParameter[];\n}\n\n/**\n * Mixin function for {@link (ApiTypeParameterListMixin:interface)}.\n *\n * @param baseClass - The base class to be extended\n * @returns A child class that extends baseClass, adding the {@link (ApiTypeParameterListMixin:interface)}\n * functionality.\n * @public\n */\nexport function ApiTypeParameterListMixin<TBaseClass extends IApiItemConstructor>(\n\tbaseClass: TBaseClass,\n): TBaseClass & (new (...args: any[]) => ApiTypeParameterListMixin) {\n\tclass MixedClass extends baseClass implements ApiTypeParameterListMixin {\n\t\tpublic readonly [_typeParameters]: TypeParameter[];\n\n\t\tpublic constructor(...args: any[]) {\n\t\t\tsuper(...args);\n\n\t\t\tconst options: IApiTypeParameterListMixinOptions = args[0];\n\n\t\t\tthis[_typeParameters] = [];\n\n\t\t\tif (this instanceof ApiDeclaredItem) {\n\t\t\t\tif (options.typeParameters) {\n\t\t\t\t\tfor (const typeParameterOptions of options.typeParameters) {\n\t\t\t\t\t\tconst defaultTypeExcerpt: Excerpt = this.buildExcerpt(typeParameterOptions.defaultTypeTokenRange);\n\t\t\t\t\t\tconst typeParameter: TypeParameter = new TypeParameter({\n\t\t\t\t\t\t\tname: typeParameterOptions.typeParameterName,\n\t\t\t\t\t\t\tconstraintExcerpt: this.buildExcerpt(typeParameterOptions.constraintTokenRange),\n\t\t\t\t\t\t\tdefaultTypeExcerpt,\n\t\t\t\t\t\t\tisOptional: !defaultTypeExcerpt.isEmpty,\n\t\t\t\t\t\t\tparent: this,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tthis[_typeParameters].push(typeParameter);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthrow new InternalError('ApiTypeParameterListMixin expects a base class that inherits from ApiDeclaredItem');\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic static override onDeserializeInto(\n\t\t\toptions: Partial<IApiTypeParameterListMixinOptions>,\n\t\t\tcontext: DeserializerContext,\n\t\t\tjsonObject: IApiTypeParameterListMixinJson,\n\t\t): void {\n\t\t\tbaseClass.onDeserializeInto(options, context, jsonObject);\n\n\t\t\toptions.typeParameters = jsonObject.typeParameters || [];\n\t\t}\n\n\t\tpublic get typeParameters(): readonly TypeParameter[] {\n\t\t\treturn this[_typeParameters];\n\t\t}\n\n\t\t/**\n\t\t * @override\n\t\t */\n\t\tpublic override serializeInto(jsonObject: Partial<IApiTypeParameterListMixinJson>): void {\n\t\t\tsuper.serializeInto(jsonObject);\n\n\t\t\tconst typeParameterObjects: IApiTypeParameterOptions[] = [];\n\t\t\tfor (const typeParameter of this.typeParameters) {\n\t\t\t\ttypeParameterObjects.push({\n\t\t\t\t\ttypeParameterName: typeParameter.name,\n\t\t\t\t\tconstraintTokenRange: typeParameter.constraintExcerpt.tokenRange,\n\t\t\t\t\tdefaultTypeTokenRange: typeParameter.defaultTypeExcerpt.tokenRange,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (typeParameterObjects.length > 0) {\n\t\t\t\tjsonObject.typeParameters = typeParameterObjects;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn MixedClass;\n}\n\n/**\n * Static members for {@link (ApiTypeParameterListMixin:interface)}.\n *\n * @public\n */\nexport namespace ApiTypeParameterListMixin {\n\t/**\n\t * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiParameterListMixin` mixin.\n\t *\n\t * @remarks\n\t *\n\t * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of\n\t * the mixin function produces a different subclass.  (This could be mitigated by `Symbol.hasInstance`, however\n\t * the TypeScript type system cannot invoke a runtime test.)\n\t */\n\texport function isBaseClassOf(apiItem: ApiItem): apiItem is ApiTypeParameterListMixin {\n\t\treturn apiItem.hasOwnProperty(_typeParameters);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/Excerpt.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference';\nimport { Text } from '@rushstack/node-core-library';\n\n/**\n * @public\n */\nexport enum ExcerptTokenKind {\n\t/**\n\t * Generic text without any special properties\n\t */\n\tContent = 'Content',\n\n\t/**\n\t * A reference to an API declaration\n\t */\n\tReference = 'Reference',\n}\n\n/**\n * Used by {@link Excerpt} to indicate a range of indexes within an array of `ExcerptToken` objects.\n *\n * @public\n */\nexport interface IExcerptTokenRange {\n\t/**\n\t * The index of the last member of the span, plus one.\n\t *\n\t * @remarks\n\t *\n\t * If `startIndex` and `endIndex` are the same number, then the span is empty.\n\t */\n\tendIndex: number;\n\n\t/**\n\t * The starting index of the span.\n\t */\n\tstartIndex: number;\n}\n\n/**\n * @public\n */\nexport interface IExcerptToken {\n\tcanonicalReference?: string | undefined;\n\treadonly kind: ExcerptTokenKind;\n\ttext: string;\n}\n\n/**\n * Represents a fragment of text belonging to an {@link Excerpt} object.\n *\n * @public\n */\nexport class ExcerptToken {\n\tprivate readonly _kind: ExcerptTokenKind;\n\n\tprivate readonly _text: string;\n\n\tprivate readonly _canonicalReference: DeclarationReference | undefined;\n\n\tpublic constructor(kind: ExcerptTokenKind, text: string, canonicalReference?: DeclarationReference) {\n\t\tthis._kind = kind;\n\n\t\t// Standardize the newlines across operating systems. Even though this may deviate from the actual\n\t\t// input source file that was parsed, it's useful because the newline gets serialized inside\n\t\t// a string literal in .api.json, which cannot be automatically normalized by Git.\n\t\tthis._text = Text.convertToLf(text);\n\t\tthis._canonicalReference = canonicalReference;\n\t}\n\n\t/**\n\t * Indicates the kind of token.\n\t */\n\tpublic get kind(): ExcerptTokenKind {\n\t\treturn this._kind;\n\t}\n\n\t/**\n\t * The text fragment.\n\t */\n\tpublic get text(): string {\n\t\treturn this._text;\n\t}\n\n\t/**\n\t * The hyperlink target for a token whose type is `ExcerptTokenKind.Reference`.  For other token types,\n\t * this property will be `undefined`.\n\t */\n\tpublic get canonicalReference(): DeclarationReference | undefined {\n\t\treturn this._canonicalReference;\n\t}\n}\n\n/**\n * The `Excerpt` class is used by {@link ApiDeclaredItem} to represent a TypeScript code fragment that may be\n * annotated with hyperlinks to declared types (and in the future, source code locations).\n *\n * @remarks\n * API Extractor's .api.json file format stores excerpts compactly as a start/end indexes into an array of tokens.\n * Every `ApiDeclaredItem` has a \"main excerpt\" corresponding to the full list of tokens.  The declaration may\n * also have have \"captured\" excerpts that correspond to subranges of tokens.\n *\n * For example, if the main excerpt is:\n *\n * ```\n * function parse(s: string): Vector | undefined;\n * ```\n *\n * ...then this entire signature is the \"main excerpt\", whereas the function's return type `Vector | undefined` is a\n * captured excerpt.  The `Vector` token might be a hyperlink to that API item.\n *\n * An excerpt may be empty (i.e. a token range containing zero tokens).  For example, if a function's return value\n * is not explicitly declared, then the returnTypeExcerpt will be empty.  By contrast, a class constructor cannot\n * have a return value, so ApiConstructor has no returnTypeExcerpt property at all.\n * @public\n */\nexport class Excerpt {\n\t/**\n\t * The complete list of tokens for the source code fragment that this excerpt is based upon.\n\t * If this object is the main excerpt, then it will span all of the tokens; otherwise, it will correspond to\n\t * a range within the array.\n\t */\n\tpublic readonly tokens: readonly ExcerptToken[];\n\n\t/**\n\t * Specifies the excerpt's range within the `tokens` array.\n\t */\n\tpublic readonly tokenRange: Readonly<IExcerptTokenRange>;\n\n\t/**\n\t * The tokens spanned by this excerpt.  It is the range of the `tokens` array as specified by the `tokenRange`\n\t * property.\n\t */\n\tpublic readonly spannedTokens: readonly ExcerptToken[];\n\n\tprivate _text: string | undefined;\n\n\tpublic constructor(tokens: readonly ExcerptToken[], tokenRange: IExcerptTokenRange) {\n\t\tthis.tokens = tokens;\n\t\tthis.tokenRange = tokenRange;\n\n\t\tif (\n\t\t\tthis.tokenRange.startIndex < 0 ||\n\t\t\tthis.tokenRange.endIndex > this.tokens.length ||\n\t\t\tthis.tokenRange.startIndex > this.tokenRange.endIndex\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid token range. length:${this.tokens.length}, start:${this.tokenRange.startIndex}, end:${\n\t\t\t\t\tthis.tokenRange.endIndex\n\t\t\t\t}, ${this.tokens.map((token) => token.text)}`,\n\t\t\t);\n\t\t}\n\n\t\tthis.spannedTokens = this.tokens.slice(this.tokenRange.startIndex, this.tokenRange.endIndex);\n\t}\n\n\t/**\n\t * The excerpted text, formed by concatenating the text of the `spannedTokens` strings.\n\t */\n\tpublic get text(): string {\n\t\tif (this._text === undefined) {\n\t\t\tthis._text = this.spannedTokens.map((x) => x.text).join('');\n\t\t}\n\n\t\treturn this._text;\n\t}\n\n\t/**\n\t * Returns true if the excerpt is an empty range.\n\t */\n\tpublic get isEmpty(): boolean {\n\t\treturn this.tokenRange.startIndex === this.tokenRange.endIndex;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/IFindApiItemsResult.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { ApiItem } from '../items/ApiItem.js';\n\n/**\n * Generic result object for finding API items used by different kinds of find operations.\n *\n * @public\n */\nexport interface IFindApiItemsResult {\n\t/**\n\t * The API items that were found. Not guaranteed to be complete, see `maybeIncompleteResult`.\n\t */\n\titems: ApiItem[];\n\n\t/**\n\t * Indicates whether the result is potentially incomplete due to errors during the find operation.\n\t * If true, the `messages` explain the errors in more detail.\n\t */\n\tmaybeIncompleteResult: boolean;\n\n\t/**\n\t * Diagnostic messages regarding the find operation.\n\t */\n\tmessages: IFindApiItemsMessage[];\n}\n\n/**\n * This object is used for messages returned as part of `IFindApiItemsResult`.\n *\n * @public\n */\nexport interface IFindApiItemsMessage {\n\t/**\n\t * Unique identifier for the message.\n\t *\n\t * @beta\n\t */\n\tmessageId: FindApiItemsMessageId;\n\n\t/**\n\t * Text description of the message.\n\t */\n\ttext: string;\n}\n\n/**\n * Unique identifiers for messages returned as part of `IFindApiItemsResult`.\n *\n * @public\n */\nexport enum FindApiItemsMessageId {\n\t/**\n\t * \"Unable to resolve declaration reference within API item ___: ___\"\n\t */\n\tDeclarationResolutionFailed = 'declaration-resolution-failed',\n\n\t/**\n\t * \"Unable to analyze extends clause ___ of API item ___ because no canonical reference was found.\"\n\t */\n\tExtendsClauseMissingReference = 'extends-clause-missing-reference',\n\n\t/**\n\t * \"Unable to analyze references of API item ___ because it is not associated with an ApiModel\"\n\t */\n\tNoAssociatedApiModel = 'no-associated-api-model',\n\n\t/**\n\t * \"Unable to analyze references of API item ___ because it is of unsupported kind ___\"\n\t */\n\tUnsupportedKind = 'unsupported-kind',\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/mixins/Mixin.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * This abstraction is used by the mixin pattern.\n * It describes a class constructor.\n *\n * @public\n */\nexport type Constructor<T = {}> = new (...args: any[]) => T;\n\n/**\n * This abstraction is used by the mixin pattern.\n * It describes the \"static side\" of a class.\n *\n * @public\n */\nexport type PropertiesOf<T> = { [K in keyof T]: T[K] };\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiCallSignature.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { type IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport { type IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin.js';\nimport { type IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin.js';\nimport { type IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from '../mixins/ApiReturnTypeMixin.js';\nimport {\n\ttype IApiTypeParameterListMixinOptions,\n\tApiTypeParameterListMixin,\n} from '../mixins/ApiTypeParameterListMixin.js';\n\n/**\n * Constructor options for {@link ApiCallSignature}.\n *\n * @public\n */\nexport interface IApiCallSignatureOptions\n\textends\n\t\tIApiTypeParameterListMixinOptions,\n\t\tIApiParameterListMixinOptions,\n\t\tIApiReleaseTagMixinOptions,\n\t\tIApiReturnTypeMixinOptions,\n\t\tIApiDeclaredItemOptions {}\n\n/**\n * Represents a TypeScript function call signature.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiCallSignature` represents a TypeScript declaration such as `(x: number, y: number): number`\n * in this example:\n *\n * ```ts\n * export interface IChooser {\n *   // A call signature:\n *   (x: number, y: number): number;\n *\n *   // Another overload for this call signature:\n *   (x: string, y: string): string;\n * }\n *\n * function chooseFirst<T>(x: T, y: T): T {\n *   return x;\n * }\n *\n * let chooser: IChooser = chooseFirst;\n * ```\n * @public\n */\nexport class ApiCallSignature extends ApiTypeParameterListMixin(\n\tApiParameterListMixin(ApiReleaseTagMixin(ApiReturnTypeMixin(ApiDeclaredItem))),\n) {\n\tpublic constructor(options: IApiCallSignatureOptions) {\n\t\tsuper(options);\n\t}\n\n\tpublic static getContainerKey(overloadIndex: number): string {\n\t\treturn `|${ApiItemKind.CallSignature}|${overloadIndex}`;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.CallSignature;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiCallSignature.getContainerKey(this.overloadIndex);\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst parent: DeclarationReference = this.parent\n\t\t\t? this.parent.canonicalReference\n\t\t\t: // .withMeaning() requires some kind of component\n\t\t\t\tDeclarationReference.empty().addNavigationStep(Navigation.Members as any, '(parent)');\n\t\treturn parent.withMeaning(Meaning.CallSignature as any).withOverloadIndex(this.overloadIndex);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiClass.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { ApiDeclaredItem, type IApiDeclaredItemOptions, type IApiDeclaredItemJson } from '../items/ApiDeclaredItem.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport {\n\tApiAbstractMixin,\n\ttype IApiAbstractMixinJson,\n\ttype IApiAbstractMixinOptions,\n} from '../mixins/ApiAbstractMixin.js';\nimport {\n\ttype IApiExportedMixinJson,\n\ttype IApiExportedMixinOptions,\n\tApiExportedMixin,\n} from '../mixins/ApiExportedMixin.js';\nimport { ApiItemContainerMixin, type IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin.js';\nimport { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin.js';\nimport { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin.js';\nimport {\n\tApiTypeParameterListMixin,\n\ttype IApiTypeParameterListMixinOptions,\n\ttype IApiTypeParameterListMixinJson,\n} from '../mixins/ApiTypeParameterListMixin.js';\nimport type { IExcerptTokenRange } from '../mixins/Excerpt.js';\nimport type { DeserializerContext } from './DeserializerContext.js';\nimport { HeritageType } from './HeritageType.js';\n\n/**\n * Constructor options for {@link ApiClass}.\n *\n * @public\n */\nexport interface IApiClassOptions\n\textends\n\t\tIApiItemContainerMixinOptions,\n\t\tIApiNameMixinOptions,\n\t\tIApiAbstractMixinOptions,\n\t\tIApiReleaseTagMixinOptions,\n\t\tIApiDeclaredItemOptions,\n\t\tIApiTypeParameterListMixinOptions,\n\t\tIApiExportedMixinOptions {\n\textendsTokenRange: IExcerptTokenRangeWithTypeParameters | undefined;\n\timplementsTokenRanges: IExcerptTokenRangeWithTypeParameters[];\n}\n\nexport interface IExcerptTokenRangeWithTypeParameters extends IExcerptTokenRange {\n\ttypeParameters: IExcerptTokenRange[];\n}\n\nexport interface IApiClassJson\n\textends IApiDeclaredItemJson, IApiAbstractMixinJson, IApiTypeParameterListMixinJson, IApiExportedMixinJson {\n\textendsTokenRange?: IExcerptTokenRangeWithTypeParameters | undefined;\n\timplementsTokenRanges: IExcerptTokenRangeWithTypeParameters[];\n}\n\n/**\n * Represents a TypeScript class declaration.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiClass` represents a TypeScript declaration such as this:\n *\n * ```ts\n * export class X { }\n * ```\n * @public\n */\nexport class ApiClass extends ApiItemContainerMixin(\n\tApiNameMixin(ApiAbstractMixin(ApiTypeParameterListMixin(ApiReleaseTagMixin(ApiExportedMixin(ApiDeclaredItem))))),\n) {\n\t/**\n\t * The base class that this class inherits from (using the `extends` keyword), or undefined if there is no base class.\n\t */\n\tpublic readonly extendsType: HeritageType | undefined;\n\n\tprivate readonly _implementsTypes: HeritageType[] = [];\n\n\tpublic constructor(options: IApiClassOptions) {\n\t\tsuper(options);\n\n\t\tif (options.extendsTokenRange) {\n\t\t\tthis.extendsType = new HeritageType(\n\t\t\t\tthis.buildExcerpt(options.extendsTokenRange),\n\t\t\t\toptions.extendsTokenRange.typeParameters,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.extendsType = undefined;\n\t\t}\n\n\t\tfor (const implementsTokenRange of options.implementsTokenRanges) {\n\t\t\tthis._implementsTypes.push(\n\t\t\t\tnew HeritageType(this.buildExcerpt(implementsTokenRange), implementsTokenRange.typeParameters),\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic static getContainerKey(name: string): string {\n\t\treturn `${name}|${ApiItemKind.Class}`;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic static override onDeserializeInto(\n\t\toptions: Partial<IApiClassOptions>,\n\t\tcontext: DeserializerContext,\n\t\tjsonObject: IApiClassJson,\n\t): void {\n\t\tsuper.onDeserializeInto(options, context, jsonObject);\n\n\t\toptions.extendsTokenRange = jsonObject.extendsTokenRange;\n\t\toptions.implementsTokenRanges = jsonObject.implementsTokenRanges;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.Class;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiClass.getContainerKey(this.name);\n\t}\n\n\t/**\n\t * The list of interfaces that this class implements using the `implements` keyword.\n\t */\n\tpublic get implementsTypes(): readonly HeritageType[] {\n\t\treturn this._implementsTypes;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override serializeInto(jsonObject: Partial<IApiClassJson>): void {\n\t\tsuper.serializeInto(jsonObject);\n\n\t\t// Note that JSON does not support the \"undefined\" value, so we simply omit the field entirely if it is undefined\n\t\tif (this.extendsType) {\n\t\t\tjsonObject.extendsTokenRange = {\n\t\t\t\t...this.extendsType.excerpt.tokenRange,\n\t\t\t\ttypeParameters: this.extendsType.typeParameters ?? [],\n\t\t\t};\n\t\t}\n\n\t\tjsonObject.implementsTokenRanges = this.implementsTypes.map((x) => ({\n\t\t\t...x.excerpt.tokenRange,\n\t\t\ttypeParameters: x.typeParameters ?? [],\n\t\t}));\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst nameComponent: Component = DeclarationReference.parseComponent(this.name);\n\t\tconst navigation: Navigation = this.isExported ? Navigation.Exports : Navigation.Locals;\n\t\treturn (this.parent ? this.parent.canonicalReference : DeclarationReference.empty())\n\t\t\t.addNavigationStep(navigation as any, nameComponent)\n\t\t\t.withMeaning(Meaning.Class as any);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiConstructSignature.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { type IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport { type IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin.js';\nimport { type IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin.js';\nimport { type IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from '../mixins/ApiReturnTypeMixin.js';\nimport {\n\tApiTypeParameterListMixin,\n\ttype IApiTypeParameterListMixinOptions,\n} from '../mixins/ApiTypeParameterListMixin.js';\n\n/**\n * Constructor options for {@link ApiConstructor}.\n *\n * @public\n */\nexport interface IApiConstructSignatureOptions\n\textends\n\t\tIApiTypeParameterListMixinOptions,\n\t\tIApiParameterListMixinOptions,\n\t\tIApiReleaseTagMixinOptions,\n\t\tIApiReturnTypeMixinOptions,\n\t\tIApiDeclaredItemOptions {}\n\n/**\n * Represents a TypeScript construct signature that belongs to an `ApiInterface`.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiConstructSignature` represents a construct signature using the `new` keyword such as in this example:\n *\n * ```ts\n * export interface IVector {\n *   x: number;\n *   y: number;\n * }\n *\n * export interface IVectorConstructor {\n *   // A construct signature:\n *   new(x: number, y: number): IVector;\n * }\n *\n * export function createVector(vectorConstructor: IVectorConstructor,\n *   x: number, y: number): IVector {\n *   return new vectorConstructor(x, y);\n * }\n *\n * class Vector implements IVector {\n *   public x: number;\n *   public y: number;\n *   public constructor(x: number, y: number) {\n *     this.x = x;\n *     this.y = y;\n *   }\n * }\n *\n * let vector: Vector = createVector(Vector, 1, 2);\n * ```\n *\n * Compare with {@link ApiConstructor}, which describes the class constructor itself.\n * @public\n */\nexport class ApiConstructSignature extends ApiTypeParameterListMixin(\n\tApiParameterListMixin(ApiReleaseTagMixin(ApiReturnTypeMixin(ApiDeclaredItem))),\n) {\n\tpublic constructor(options: IApiConstructSignatureOptions) {\n\t\tsuper(options);\n\t}\n\n\tpublic static getContainerKey(overloadIndex: number): string {\n\t\treturn `|${ApiItemKind.ConstructSignature}|${overloadIndex}`;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.ConstructSignature;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiConstructSignature.getContainerKey(this.overloadIndex);\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst parent: DeclarationReference = this.parent\n\t\t\t? this.parent.canonicalReference\n\t\t\t: // .withMeaning() requires some kind of component\n\t\t\t\tDeclarationReference.empty().addNavigationStep(Navigation.Members as any, '(parent)');\n\t\treturn parent.withMeaning(Meaning.ConstructSignature as any).withOverloadIndex(this.overloadIndex);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiConstructor.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { type IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport { type IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin.js';\nimport { ApiProtectedMixin, type IApiProtectedMixinOptions } from '../mixins/ApiProtectedMixin.js';\nimport { type IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin.js';\n\n/**\n * Constructor options for {@link ApiConstructor}.\n *\n * @public\n */\nexport interface IApiConstructorOptions\n\textends\n\t\tIApiParameterListMixinOptions,\n\t\tIApiProtectedMixinOptions,\n\t\tIApiReleaseTagMixinOptions,\n\t\tIApiDeclaredItemOptions {}\n\n/**\n * Represents a TypeScript class constructor declaration that belongs to an `ApiClass`.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiConstructor` represents a declaration using the `constructor` keyword such as in this example:\n *\n * ```ts\n * export class Vector {\n *   public x: number;\n *   public y: number;\n *\n *   // A class constructor:\n *   public constructor(x: number, y: number) {\n *     this.x = x;\n *     this.y = y;\n *   }\n * }\n * ```\n *\n * Compare with {@link ApiConstructSignature}, which describes the construct signature for a class constructor.\n * @public\n */\nexport class ApiConstructor extends ApiParameterListMixin(ApiProtectedMixin(ApiReleaseTagMixin(ApiDeclaredItem))) {\n\tpublic constructor(options: IApiConstructorOptions) {\n\t\tsuper(options);\n\t}\n\n\tpublic static getContainerKey(overloadIndex: number): string {\n\t\treturn `|${ApiItemKind.Constructor}|${overloadIndex}`;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.Constructor;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiConstructor.getContainerKey(this.overloadIndex);\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst parent: DeclarationReference = this.parent\n\t\t\t? this.parent.canonicalReference\n\t\t\t: // .withMeaning() requires some kind of component\n\t\t\t\tDeclarationReference.empty().addNavigationStep(Navigation.Members as any, '(parent)');\n\t\treturn parent.withMeaning(Meaning.Constructor as any).withOverloadIndex(this.overloadIndex);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiEntryPoint.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { ApiItem, ApiItemKind } from '../items/ApiItem.js';\nimport { ApiItemContainerMixin, type IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin.js';\nimport { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin.js';\nimport { ApiPackage } from './ApiPackage.js';\n\n/**\n * Constructor options for {@link ApiEntryPoint}.\n *\n * @public\n */\nexport interface IApiEntryPointOptions extends IApiItemContainerMixinOptions, IApiNameMixinOptions {}\n\n/**\n * Represents an entry point for an NPM package.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiEntryPoint` represents an entry point to an NPM package.\n *\n * For example, suppose the package.json file looks like this:\n *\n * ```json\n * {\n *   \"name\": \"example-library\",\n *   \"version\": \"1.0.0\",\n *   \"main\": \"./lib/index.js\",\n *   \"typings\": \"./lib/index.d.ts\"\n * }\n * ```\n *\n * In this example, the main `ApiEntryPoint` would represent the TypeScript module for `./lib/index.js`.\n * @public\n */\nexport class ApiEntryPoint extends ApiItemContainerMixin(ApiNameMixin(ApiItem)) {\n\tpublic constructor(options: IApiEntryPointOptions) {\n\t\tsuper(options);\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.EntryPoint;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\t// No prefix needed, because ApiEntryPoint is the only possible member of an ApiPackage\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * The module path for this entry point, relative to the parent `ApiPackage`.  In the current implementation,\n\t * this is used to distinguish different entry points,\n\t * for example: `controls/Button` in `import { Button } from \"example-package/controls/Button\";`.\n\t *\n\t * The `ApiEntryPoint.name` property stores the same value as `ApiEntryPoint.importPath`.\n\t */\n\tpublic get importPath(): string {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tif (this.parent instanceof ApiPackage) {\n\t\t\treturn DeclarationReference.package(this.parent.name, this.importPath);\n\t\t}\n\n\t\treturn DeclarationReference.empty();\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiEnum.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { ApiDeclaredItem, type IApiDeclaredItemOptions } from '../items/ApiDeclaredItem.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport { type IApiExportedMixinOptions, ApiExportedMixin } from '../mixins/ApiExportedMixin.js';\nimport { ApiItemContainerMixin, type IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin.js';\nimport { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin.js';\nimport { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin.js';\nimport type { ApiEnumMember } from './ApiEnumMember.js';\n\n/**\n * Constructor options for {@link ApiEnum}.\n *\n * @public\n */\nexport interface IApiEnumOptions\n\textends\n\t\tIApiItemContainerMixinOptions,\n\t\tIApiNameMixinOptions,\n\t\tIApiReleaseTagMixinOptions,\n\t\tIApiDeclaredItemOptions,\n\t\tIApiExportedMixinOptions {}\n\n/**\n * Represents a TypeScript enum declaration.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiEnum` represents an enum declaration such as `FontSizes` in the example below:\n *\n * ```ts\n * export enum FontSizes {\n *   Small = 100,\n *   Medium = 200,\n *   Large = 300\n * }\n * ```\n * @public\n */\nexport class ApiEnum extends ApiItemContainerMixin(\n\tApiNameMixin(ApiReleaseTagMixin(ApiExportedMixin(ApiDeclaredItem))),\n) {\n\tpublic constructor(options: IApiEnumOptions) {\n\t\tsuper(options);\n\t}\n\n\tpublic static getContainerKey(name: string): string {\n\t\treturn `${name}|${ApiItemKind.Enum}`;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.Enum;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get members(): readonly ApiEnumMember[] {\n\t\treturn super.members as readonly ApiEnumMember[];\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiEnum.getContainerKey(this.name);\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override addMember(member: ApiEnumMember): void {\n\t\tif (member.kind !== ApiItemKind.EnumMember) {\n\t\t\tthrow new Error('Only ApiEnumMember objects can be added to an ApiEnum');\n\t\t}\n\n\t\tsuper.addMember(member);\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst nameComponent: Component = DeclarationReference.parseComponent(this.name);\n\t\tconst navigation: Navigation = this.isExported ? Navigation.Exports : Navigation.Locals;\n\t\treturn (this.parent ? this.parent.canonicalReference : DeclarationReference.empty())\n\t\t\t.addNavigationStep(navigation as any, nameComponent)\n\t\t\t.withMeaning(Meaning.Enum as any);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiEnumMember.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { ApiDeclaredItem, type IApiDeclaredItemOptions } from '../items/ApiDeclaredItem.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport { ApiInitializerMixin, type IApiInitializerMixinOptions } from '../mixins/ApiInitializerMixin.js';\nimport { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin.js';\nimport { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin.js';\n\n/**\n * Constructor options for {@link ApiEnumMember}.\n *\n * @public\n */\nexport interface IApiEnumMemberOptions\n\textends IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions, IApiInitializerMixinOptions {}\n\n/**\n * Options for customizing the sort order of {@link ApiEnum} members.\n *\n * @privateRemarks\n * This enum is currently only used by the `@microsoft/api-extractor` package; it is declared here\n * because we anticipate that if more options are added in the future, their sorting will be implemented\n * by the `@microsoft/api-extractor-model` package.\n *\n * See https://github.com/microsoft/rushstack/issues/918 for details.\n * @public\n */\nexport enum EnumMemberOrder {\n\t/**\n\t * `ApiEnumMember` items are sorted according to their {@link ApiItem.getSortKey}.  The order is\n\t * basically alphabetical by identifier name, but otherwise unspecified to allow for cosmetic improvements.\n\t *\n\t * This is the default behavior.\n\t */\n\tByName = 'by-name',\n\n\t/**\n\t * `ApiEnumMember` items preserve the original order of the declarations in the source file.\n\t * (This disables the automatic sorting that is normally applied based on {@link ApiItem.getSortKey}.)\n\t */\n\tPreserve = 'preserve',\n}\n\n/**\n * Represents a member of a TypeScript enum declaration.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiEnumMember` represents an enum member such as `Small = 100` in the example below:\n *\n * ```ts\n * export enum FontSizes {\n *   Small = 100,\n *   Medium = 200,\n *   Large = 300\n * }\n * ```\n * @public\n */\nexport class ApiEnumMember extends ApiNameMixin(ApiReleaseTagMixin(ApiInitializerMixin(ApiDeclaredItem))) {\n\tpublic constructor(options: IApiEnumMemberOptions) {\n\t\tsuper(options);\n\t}\n\n\tpublic static getContainerKey(name: string): string {\n\t\t// No prefix needed, because ApiEnumMember is the only possible member of an ApiEnum\n\t\treturn name;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.EnumMember;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiEnumMember.getContainerKey(this.name);\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst nameComponent: Component = DeclarationReference.parseComponent(this.name);\n\t\treturn (this.parent ? this.parent.canonicalReference : DeclarationReference.empty())\n\t\t\t.addNavigationStep(Navigation.Exports as any, nameComponent)\n\t\t\t.withMeaning(Meaning.Member as any);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiEvent.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { type IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin.js';\nimport { type IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin.js';\nimport { type IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin.js';\n\n/**\n * Constructor options for {@link ApiEvent}.\n *\n * @public\n */\nexport interface IApiEventOptions\n\textends IApiNameMixinOptions, IApiParameterListMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions {}\n\n/**\n * Represents a TypeScript event declaration that belongs to an `ApiClass`.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiEvent` represents a emittable event such as the `ready` event in this example:\n *\n * ```ts\n * export class Cliet extends EventEmitter {\n *   on(event: 'ready', ...args: [Client]): this { }\n * }\n * ```\n * @public\n */\nexport class ApiEvent extends ApiNameMixin(ApiParameterListMixin(ApiReleaseTagMixin(ApiDeclaredItem))) {\n\tpublic constructor(options: IApiEventOptions) {\n\t\tsuper(options);\n\t}\n\n\tpublic static getContainerKey(name: string, overloadIndex: number): string {\n\t\treturn `${name}|${ApiItemKind.Event}|${overloadIndex}`;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.Event;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiEvent.getContainerKey(this.name, this.overloadIndex);\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst nameComponent: Component = DeclarationReference.parseComponent(this.name);\n\t\treturn (this.parent ? this.parent.canonicalReference : DeclarationReference.empty())\n\t\t\t.addNavigationStep(Navigation.Members as any, nameComponent)\n\t\t\t.withMeaning(Meaning.Member as any)\n\t\t\t.withOverloadIndex(this.overloadIndex);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiFunction.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { type IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport { type IApiExportedMixinOptions, ApiExportedMixin } from '../mixins/ApiExportedMixin.js';\nimport { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin.js';\nimport { type IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin.js';\nimport { type IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin.js';\nimport { type IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from '../mixins/ApiReturnTypeMixin.js';\nimport {\n\ttype IApiTypeParameterListMixinOptions,\n\tApiTypeParameterListMixin,\n} from '../mixins/ApiTypeParameterListMixin.js';\n\n/**\n * Constructor options for {@link ApiFunction}.\n *\n * @public\n */\nexport interface IApiFunctionOptions\n\textends\n\t\tIApiNameMixinOptions,\n\t\tIApiTypeParameterListMixinOptions,\n\t\tIApiParameterListMixinOptions,\n\t\tIApiReleaseTagMixinOptions,\n\t\tIApiReturnTypeMixinOptions,\n\t\tIApiDeclaredItemOptions,\n\t\tIApiExportedMixinOptions {}\n\n/**\n * Represents a TypeScript function declaration.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiFunction` represents a TypeScript declaration such as this example:\n *\n * ```ts\n * export function getAverage(x: number, y: number): number {\n *   return (x + y) / 2.0;\n * }\n * ```\n *\n * Functions are exported by an entry point module or by a namespace.  Compare with {@link ApiMethod}, which\n * represents a function that is a member of a class.\n * @public\n */\nexport class ApiFunction extends ApiNameMixin(\n\tApiTypeParameterListMixin(\n\t\tApiParameterListMixin(ApiReleaseTagMixin(ApiReturnTypeMixin(ApiExportedMixin(ApiDeclaredItem)))),\n\t),\n) {\n\tpublic constructor(options: IApiFunctionOptions) {\n\t\tsuper(options);\n\t}\n\n\tpublic static getContainerKey(name: string, overloadIndex: number): string {\n\t\treturn `${name}|${ApiItemKind.Function}|${overloadIndex}`;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.Function;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiFunction.getContainerKey(this.name, this.overloadIndex);\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst nameComponent: Component = DeclarationReference.parseComponent(this.name);\n\t\tconst navigation: Navigation = this.isExported ? Navigation.Exports : Navigation.Locals;\n\t\treturn (this.parent ? this.parent.canonicalReference : DeclarationReference.empty())\n\t\t\t.addNavigationStep(navigation as any, nameComponent)\n\t\t\t.withMeaning(Meaning.Function as any)\n\t\t\t.withOverloadIndex(this.overloadIndex);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiIndexSignature.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { type IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport { type IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin.js';\nimport { type IApiReadonlyMixinOptions, ApiReadonlyMixin } from '../mixins/ApiReadonlyMixin.js';\nimport { type IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin.js';\nimport { type IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from '../mixins/ApiReturnTypeMixin.js';\n\n/**\n * Constructor options for {@link ApiIndexSignature}.\n *\n * @public\n */\nexport interface IApiIndexSignatureOptions\n\textends\n\t\tIApiParameterListMixinOptions,\n\t\tIApiReleaseTagMixinOptions,\n\t\tIApiReturnTypeMixinOptions,\n\t\tIApiReadonlyMixinOptions,\n\t\tIApiDeclaredItemOptions {}\n\n/**\n * Represents a TypeScript index signature.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiIndexSignature` represents a TypeScript declaration such as `[x: number]: number` in this example:\n *\n * ```ts\n * export interface INumberTable {\n *   // An index signature\n *   [value: number]: number;\n *\n *   // An overloaded index signature\n *   [name: string]: number;\n * }\n * ```\n * @public\n */\nexport class ApiIndexSignature extends ApiParameterListMixin(\n\tApiReleaseTagMixin(ApiReturnTypeMixin(ApiReadonlyMixin(ApiDeclaredItem))),\n) {\n\tpublic constructor(options: IApiIndexSignatureOptions) {\n\t\tsuper(options);\n\t}\n\n\tpublic static getContainerKey(overloadIndex: number): string {\n\t\treturn `|${ApiItemKind.IndexSignature}|${overloadIndex}`;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.IndexSignature;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiIndexSignature.getContainerKey(this.overloadIndex);\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst parent: DeclarationReference = this.parent\n\t\t\t? this.parent.canonicalReference\n\t\t\t: // .withMeaning() requires some kind of component\n\t\t\t\tDeclarationReference.empty().addNavigationStep(Navigation.Members as any, '(parent)');\n\t\treturn parent.withMeaning(Meaning.IndexSignature as any).withOverloadIndex(this.overloadIndex);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiInterface.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { ApiDeclaredItem, type IApiDeclaredItemOptions, type IApiDeclaredItemJson } from '../items/ApiDeclaredItem.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport {\n\ttype IApiExportedMixinJson,\n\ttype IApiExportedMixinOptions,\n\tApiExportedMixin,\n} from '../mixins/ApiExportedMixin.js';\nimport {\n\tApiItemContainerMixin,\n\ttype IApiItemContainerMixinOptions,\n\ttype IApiItemContainerJson,\n} from '../mixins/ApiItemContainerMixin.js';\nimport { type IApiNameMixinOptions, ApiNameMixin, type IApiNameMixinJson } from '../mixins/ApiNameMixin.js';\nimport {\n\ttype IApiReleaseTagMixinOptions,\n\tApiReleaseTagMixin,\n\ttype IApiReleaseTagMixinJson,\n} from '../mixins/ApiReleaseTagMixin.js';\nimport {\n\ttype IApiTypeParameterListMixinOptions,\n\ttype IApiTypeParameterListMixinJson,\n\tApiTypeParameterListMixin,\n} from '../mixins/ApiTypeParameterListMixin.js';\nimport type { IExcerptTokenRangeWithTypeParameters } from './ApiClass.js';\nimport type { DeserializerContext } from './DeserializerContext.js';\nimport { HeritageType } from './HeritageType.js';\n\n/**\n * Constructor options for {@link ApiInterface}.\n *\n * @public\n */\nexport interface IApiInterfaceOptions\n\textends\n\t\tIApiItemContainerMixinOptions,\n\t\tIApiNameMixinOptions,\n\t\tIApiTypeParameterListMixinOptions,\n\t\tIApiReleaseTagMixinOptions,\n\t\tIApiDeclaredItemOptions,\n\t\tIApiExportedMixinOptions {\n\textendsTokenRanges: IExcerptTokenRangeWithTypeParameters[];\n}\n\nexport interface IApiInterfaceJson\n\textends\n\t\tIApiItemContainerJson,\n\t\tIApiNameMixinJson,\n\t\tIApiTypeParameterListMixinJson,\n\t\tIApiReleaseTagMixinJson,\n\t\tIApiDeclaredItemJson,\n\t\tIApiExportedMixinJson {\n\textendsTokenRanges: IExcerptTokenRangeWithTypeParameters[];\n}\n\n/**\n * Represents a TypeScript class declaration.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiInterface` represents a TypeScript declaration such as this:\n *\n * ```ts\n * export interface X extends Y {\n * }\n * ```\n * @public\n */\nexport class ApiInterface extends ApiItemContainerMixin(\n\tApiNameMixin(ApiTypeParameterListMixin(ApiReleaseTagMixin(ApiExportedMixin(ApiDeclaredItem)))),\n) {\n\tprivate readonly _extendsTypes: HeritageType[] = [];\n\n\tpublic constructor(options: IApiInterfaceOptions) {\n\t\tsuper(options);\n\n\t\tfor (const extendsTokenRange of options.extendsTokenRanges) {\n\t\t\tthis._extendsTypes.push(new HeritageType(this.buildExcerpt(extendsTokenRange), extendsTokenRange.typeParameters));\n\t\t}\n\t}\n\n\tpublic static getContainerKey(name: string): string {\n\t\treturn `${name}|${ApiItemKind.Interface}`;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic static override onDeserializeInto(\n\t\toptions: Partial<IApiInterfaceOptions>,\n\t\tcontext: DeserializerContext,\n\t\tjsonObject: IApiInterfaceJson,\n\t): void {\n\t\tsuper.onDeserializeInto(options, context, jsonObject);\n\n\t\toptions.extendsTokenRanges = jsonObject.extendsTokenRanges;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.Interface;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiInterface.getContainerKey(this.name);\n\t}\n\n\t/**\n\t * The list of base interfaces that this interface inherits from using the `extends` keyword.\n\t */\n\tpublic get extendsTypes(): readonly HeritageType[] {\n\t\treturn this._extendsTypes;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override serializeInto(jsonObject: Partial<IApiInterfaceJson>): void {\n\t\tsuper.serializeInto(jsonObject);\n\n\t\tjsonObject.extendsTokenRanges = this.extendsTypes.map((x) => ({\n\t\t\t...x.excerpt.tokenRange,\n\t\t\ttypeParameters: x.typeParameters ?? [],\n\t\t}));\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst nameComponent: Component = DeclarationReference.parseComponent(this.name);\n\t\tconst navigation: Navigation = this.isExported ? Navigation.Exports : Navigation.Locals;\n\t\treturn (this.parent ? this.parent.canonicalReference : DeclarationReference.empty())\n\t\t\t.addNavigationStep(navigation as any, nameComponent)\n\t\t\t.withMeaning(Meaning.Interface as any);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiMethod.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { type IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport { type IApiAbstractMixinOptions, ApiAbstractMixin } from '../mixins/ApiAbstractMixin.js';\nimport { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin.js';\nimport { ApiOptionalMixin, type IApiOptionalMixinOptions } from '../mixins/ApiOptionalMixin.js';\nimport { type IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin.js';\nimport { ApiProtectedMixin, type IApiProtectedMixinOptions } from '../mixins/ApiProtectedMixin.js';\nimport { type IApiReleaseTagMixinOptions, ApiReleaseTagMixin } from '../mixins/ApiReleaseTagMixin.js';\nimport { ApiReturnTypeMixin, type IApiReturnTypeMixinOptions } from '../mixins/ApiReturnTypeMixin.js';\nimport { ApiStaticMixin, type IApiStaticMixinOptions } from '../mixins/ApiStaticMixin.js';\nimport {\n\tApiTypeParameterListMixin,\n\ttype IApiTypeParameterListMixinOptions,\n} from '../mixins/ApiTypeParameterListMixin.js';\n\n/**\n * Constructor options for {@link ApiMethod}.\n *\n * @public\n */\nexport interface IApiMethodOptions\n\textends\n\t\tIApiNameMixinOptions,\n\t\tIApiAbstractMixinOptions,\n\t\tIApiOptionalMixinOptions,\n\t\tIApiParameterListMixinOptions,\n\t\tIApiProtectedMixinOptions,\n\t\tIApiReleaseTagMixinOptions,\n\t\tIApiReturnTypeMixinOptions,\n\t\tIApiStaticMixinOptions,\n\t\tIApiTypeParameterListMixinOptions,\n\t\tIApiDeclaredItemOptions {}\n\n/**\n * Represents a TypeScript member function declaration that belongs to an `ApiClass`.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiMethod` represents a TypeScript declaration such as the `render` member function in this example:\n *\n * ```ts\n * export class Widget {\n *   public render(): void { }\n * }\n * ```\n *\n * Compare with {@link ApiMethodSignature}, which represents a method belonging to an interface.\n * For example, a class method can be `static` but an interface method cannot.\n * @public\n */\nexport class ApiMethod extends ApiNameMixin(\n\tApiAbstractMixin(\n\t\tApiOptionalMixin(\n\t\t\tApiParameterListMixin(\n\t\t\t\tApiProtectedMixin(\n\t\t\t\t\tApiReleaseTagMixin(ApiReturnTypeMixin(ApiStaticMixin(ApiTypeParameterListMixin(ApiDeclaredItem)))),\n\t\t\t\t),\n\t\t\t),\n\t\t),\n\t),\n) {\n\tpublic constructor(options: IApiMethodOptions) {\n\t\tsuper(options);\n\t}\n\n\tpublic static getContainerKey(name: string, isStatic: boolean, overloadIndex: number): string {\n\t\tif (isStatic) {\n\t\t\treturn `${name}|${ApiItemKind.Method}|static|${overloadIndex}`;\n\t\t} else {\n\t\t\treturn `${name}|${ApiItemKind.Method}|instance|${overloadIndex}`;\n\t\t}\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.Method;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiMethod.getContainerKey(this.name, this.isStatic, this.overloadIndex);\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst nameComponent: Component = DeclarationReference.parseComponent(this.name);\n\t\treturn (this.parent ? this.parent.canonicalReference : DeclarationReference.empty())\n\t\t\t.addNavigationStep((this.isStatic ? Navigation.Exports : Navigation.Members) as any, nameComponent)\n\t\t\t.withMeaning(Meaning.Member as any)\n\t\t\t.withOverloadIndex(this.overloadIndex);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiMethodSignature.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { ApiDeclaredItem, type IApiDeclaredItemOptions } from '../items/ApiDeclaredItem.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin.js';\nimport { ApiOptionalMixin, type IApiOptionalMixinOptions } from '../mixins/ApiOptionalMixin.js';\nimport { ApiParameterListMixin, type IApiParameterListMixinOptions } from '../mixins/ApiParameterListMixin.js';\nimport { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin.js';\nimport { type IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from '../mixins/ApiReturnTypeMixin.js';\nimport {\n\ttype IApiTypeParameterListMixinOptions,\n\tApiTypeParameterListMixin,\n} from '../mixins/ApiTypeParameterListMixin.js';\n\n/**\n * @public\n */\nexport interface IApiMethodSignatureOptions\n\textends\n\t\tIApiNameMixinOptions,\n\t\tIApiTypeParameterListMixinOptions,\n\t\tIApiParameterListMixinOptions,\n\t\tIApiReleaseTagMixinOptions,\n\t\tIApiReturnTypeMixinOptions,\n\t\tIApiOptionalMixinOptions,\n\t\tIApiDeclaredItemOptions {}\n\n/**\n * Represents a TypeScript member function declaration that belongs to an `ApiInterface`.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiMethodSignature` represents a TypeScript declaration such as the `render` member function in this example:\n *\n * ```ts\n * export interface IWidget {\n *   render(): void;\n * }\n * ```\n *\n * Compare with {@link ApiMethod}, which represents a method belonging to a class.\n * For example, a class method can be `static` but an interface method cannot.\n * @public\n */\nexport class ApiMethodSignature extends ApiNameMixin(\n\tApiTypeParameterListMixin(\n\t\tApiParameterListMixin(ApiReleaseTagMixin(ApiReturnTypeMixin(ApiOptionalMixin(ApiDeclaredItem)))),\n\t),\n) {\n\tpublic constructor(options: IApiMethodSignatureOptions) {\n\t\tsuper(options);\n\t}\n\n\tpublic static getContainerKey(name: string, overloadIndex: number): string {\n\t\treturn `${name}|${ApiItemKind.MethodSignature}|${overloadIndex}`;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.MethodSignature;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiMethodSignature.getContainerKey(this.name, this.overloadIndex);\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst nameComponent: Component = DeclarationReference.parseComponent(this.name);\n\t\treturn (this.parent ? this.parent.canonicalReference : DeclarationReference.empty())\n\t\t\t.addNavigationStep(Navigation.Members as any, nameComponent)\n\t\t\t.withMeaning(Meaning.Member as any)\n\t\t\t.withOverloadIndex(this.overloadIndex);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiModel.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DocDeclarationReference } from '@microsoft/tsdoc';\nimport { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { PackageName } from '@rushstack/node-core-library';\nimport { ApiItem, ApiItemKind } from '../items/ApiItem.js';\nimport { ApiItemContainerMixin } from '../mixins/ApiItemContainerMixin.js';\nimport { ApiPackage } from './ApiPackage.js';\nimport { ModelReferenceResolver, type IResolveDeclarationReferenceResult } from './ModelReferenceResolver.js';\n\n/**\n * A serializable representation of a collection of API declarations.\n *\n * @remarks\n *\n * An `ApiModel` represents a collection of API declarations that can be serialized to disk.  It captures all the\n * important information needed to generate documentation, without any reliance on the TypeScript compiler engine.\n *\n * An `ApiModel` acts as the root of a tree of objects that all inherit from the `ApiItem` base class.\n * The tree children are determined by the {@link (ApiItemContainerMixin:interface)} mixin base class.  The model\n * contains packages.  Packages have an entry point (today, only one).  And the entry point can contain various types\n * of API declarations.  The container relationships might look like this:\n *\n * ```\n * Things that can contain other things:\n *\n * - ApiModel\n *   - ApiPackage\n *     - ApiEntryPoint\n *       - ApiClass\n *         - ApiMethod\n *         - ApiProperty\n *       - ApiEnum\n *         - ApiEnumMember\n *       - ApiInterface\n *         - ApiMethodSignature\n *         - ApiPropertySignature\n *       - ApiNamespace\n *         - (ApiClass, ApiEnum, ApiInterace, ...)\n *\n * ```\n *\n * Normally, API Extractor writes an .api.json file to disk for each project that it builds.  Then, a tool like\n * API Documenter can load the various `ApiPackage` objects into a single `ApiModel` and process them as a group.\n * This is useful because compilation generally occurs separately (e.g. because projects may reside in different\n * Git repos, or because they build with different TypeScript compiler configurations that may be incompatible),\n * whereas API Documenter cannot detect broken hyperlinks without seeing the entire documentation set.\n * @public\n */\nexport class ApiModel extends ApiItemContainerMixin(ApiItem) {\n\tprivate readonly _resolver: ModelReferenceResolver;\n\n\tprivate _packagesByName: Map<string, ApiPackage> | undefined = undefined;\n\n\tprivate _apiItemsByCanonicalReference: Map<string, ApiItem> | undefined = undefined;\n\n\tpublic constructor() {\n\t\tsuper({});\n\n\t\tthis._resolver = new ModelReferenceResolver(this);\n\t}\n\n\tpublic loadPackage(apiJsonFilename: string): ApiPackage {\n\t\tconst apiPackage: ApiPackage = ApiPackage.loadFromJsonFile(apiJsonFilename);\n\t\tthis.addMember(apiPackage);\n\t\treturn apiPackage;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.Model;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn '';\n\t}\n\n\tpublic get packages(): readonly ApiPackage[] {\n\t\treturn this.members as readonly ApiPackage[];\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override addMember(member: ApiPackage): void {\n\t\tif (member.kind !== ApiItemKind.Package) {\n\t\t\tthrow new Error('Only items of type ApiPackage may be added to an ApiModel');\n\t\t}\n\n\t\tsuper.addMember(member);\n\t\tthis._packagesByName = undefined; // invalidate the cache\n\t\tthis._apiItemsByCanonicalReference = undefined; // invalidate the cache\n\t}\n\n\t/**\n\t * Efficiently finds a package by the NPM package name.\n\t *\n\t * @remarks\n\t *\n\t * If the NPM scope is omitted in the package name, it will still be found provided that it is an unambiguous match.\n\t * For example, it's often convenient to write `{@link node-core-library#JsonFile}` instead of\n\t * `{@link @rushstack/node-core-library#JsonFile}`.\n\t */\n\tpublic tryGetPackageByName(packageName: string): ApiPackage | undefined {\n\t\t// Build the lookup on demand\n\t\tif (this._packagesByName === undefined) {\n\t\t\tthis._packagesByName = new Map<string, ApiPackage>();\n\n\t\t\tconst unscopedMap: Map<string, ApiPackage | undefined> = new Map<string, ApiPackage | undefined>();\n\n\t\t\tfor (const apiPackage of this.packages) {\n\t\t\t\tif (this._packagesByName.get(apiPackage.name)) {\n\t\t\t\t\t// This should not happen\n\t\t\t\t\tthrow new Error(`The model contains multiple packages with the name ${apiPackage.name}`);\n\t\t\t\t}\n\n\t\t\t\tthis._packagesByName.set(apiPackage.name, apiPackage);\n\n\t\t\t\tconst unscopedName: string = PackageName.parse(apiPackage.name).unscopedName;\n\n\t\t\t\tif (unscopedMap.has(unscopedName)) {\n\t\t\t\t\t// If another package has the same unscoped name, then we won't register it\n\t\t\t\t\tunscopedMap.set(unscopedName, undefined);\n\t\t\t\t} else {\n\t\t\t\t\tunscopedMap.set(unscopedName, apiPackage);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const [unscopedName, apiPackage] of unscopedMap) {\n\t\t\t\tif (apiPackage && !this._packagesByName.has(unscopedName)) {\n\t\t\t\t\t// If the unscoped name is unambiguous, then we can also use it as a lookup\n\t\t\t\t\tthis._packagesByName.set(unscopedName, apiPackage);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this._packagesByName.get(packageName);\n\t}\n\n\tpublic resolveDeclarationReference(\n\t\tdeclarationReference: DeclarationReference | DocDeclarationReference,\n\t\tcontextApiItem: ApiItem | undefined,\n\t): IResolveDeclarationReferenceResult {\n\t\tif (declarationReference instanceof DocDeclarationReference) {\n\t\t\treturn this._resolver.resolve(declarationReference, contextApiItem);\n\t\t} else if (declarationReference instanceof DeclarationReference) {\n\t\t\t// use this._apiItemsByCanonicalReference to look up ApiItem\n\n\t\t\t// Build the lookup on demand\n\t\t\tif (!this._apiItemsByCanonicalReference) {\n\t\t\t\tthis._apiItemsByCanonicalReference = new Map<string, ApiItem>();\n\n\t\t\t\tfor (const apiPackage of this.packages) {\n\t\t\t\t\tthis._initApiItemsRecursive(apiPackage, this._apiItemsByCanonicalReference);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst result: IResolveDeclarationReferenceResult = {\n\t\t\t\tresolvedApiItem: undefined,\n\t\t\t\terrorMessage: undefined,\n\t\t\t};\n\n\t\t\tconst apiItem: ApiItem | undefined = this._apiItemsByCanonicalReference.get(declarationReference.toString());\n\n\t\t\tif (apiItem) {\n\t\t\t\tresult.resolvedApiItem = apiItem;\n\t\t\t} else {\n\t\t\t\tresult.errorMessage = `${declarationReference.toString()} can not be located`;\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} else {\n\t\t\t// NOTE: The \"instanceof DeclarationReference\" test assumes a specific version of the @microsoft/tsdoc package.\n\t\t\tthrow new TypeError(\n\t\t\t\t'The \"declarationReference\" parameter must be an instance of' +\n\t\t\t\t\t' DocDeclarationReference or DeclarationReference',\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate _initApiItemsRecursive(apiItem: ApiItem, apiItemsByCanonicalReference: Map<string, ApiItem>): void {\n\t\tif (apiItem.canonicalReference && !apiItem.canonicalReference.isEmpty) {\n\t\t\tapiItemsByCanonicalReference.set(apiItem.canonicalReference.toString(), apiItem);\n\t\t}\n\n\t\t// Recurse container members\n\t\tif (ApiItemContainerMixin.isBaseClassOf(apiItem)) {\n\t\t\tfor (const apiMember of apiItem.members) {\n\t\t\t\tthis._initApiItemsRecursive(apiMember, apiItemsByCanonicalReference);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\treturn DeclarationReference.empty();\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiNamespace.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { type IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport { type IApiExportedMixinOptions, ApiExportedMixin } from '../mixins/ApiExportedMixin.js';\nimport { ApiItemContainerMixin, type IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin.js';\nimport { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin.js';\nimport { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin.js';\n\n/**\n * Constructor options for {@link ApiClass}.\n *\n * @public\n */\nexport interface IApiNamespaceOptions\n\textends\n\t\tIApiItemContainerMixinOptions,\n\t\tIApiNameMixinOptions,\n\t\tIApiReleaseTagMixinOptions,\n\t\tIApiDeclaredItemOptions,\n\t\tIApiExportedMixinOptions {}\n\n/**\n * Represents a TypeScript namespace declaration.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiNamespace` represents a TypeScript declaration such `X` or `Y` in this example:\n *\n * ```ts\n * export namespace X {\n *   export namespace Y {\n *     export interface IWidget {\n *       render(): void;\n *     }\n *   }\n * }\n * ```\n * @public\n */\nexport class ApiNamespace extends ApiItemContainerMixin(\n\tApiNameMixin(ApiReleaseTagMixin(ApiExportedMixin(ApiDeclaredItem))),\n) {\n\tpublic constructor(options: IApiNamespaceOptions) {\n\t\tsuper(options);\n\t}\n\n\tpublic static getContainerKey(name: string): string {\n\t\treturn `${name}|${ApiItemKind.Namespace}`;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.Namespace;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiNamespace.getContainerKey(this.name);\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst nameComponent: Component = DeclarationReference.parseComponent(this.name);\n\t\tconst navigation: Navigation = this.isExported ? Navigation.Exports : Navigation.Locals;\n\t\treturn (this.parent ? this.parent.canonicalReference : DeclarationReference.empty())\n\t\t\t.addNavigationStep(navigation as any, nameComponent)\n\t\t\t.withMeaning(Meaning.Namespace as any);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiPackage.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { Buffer } from 'node:buffer';\nimport path from 'node:path';\nimport util from 'node:util';\nimport { TSDocConfiguration } from '@microsoft/tsdoc';\nimport { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { TSDocConfigFile } from '@microsoft/tsdoc-config';\nimport {\n\tJsonFile,\n\ttype IJsonFileSaveOptions,\n\tPackageJsonLookup,\n\ttype IPackageJson,\n\ttype JsonObject,\n\tFileSystem,\n} from '@rushstack/node-core-library';\nimport { ApiDocumentedItem, type IApiDocumentedItemOptions } from '../items/ApiDocumentedItem.js';\nimport { ApiItem, ApiItemKind, type IApiItemJson } from '../items/ApiItem.js';\nimport { ApiItemContainerMixin, type IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin.js';\nimport { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin.js';\nimport type { ApiEntryPoint } from './ApiEntryPoint.js';\nimport { DeserializerContext, ApiJsonSchemaVersion } from './DeserializerContext.js';\n\n/**\n * Constructor options for {@link ApiPackage}.\n *\n * @public\n */\nexport interface IApiPackageOptions\n\textends IApiItemContainerMixinOptions, IApiNameMixinOptions, IApiDocumentedItemOptions {\n\tdependencies?: Record<string, string> | undefined;\n\tprojectFolderUrl?: string | undefined;\n\ttsdocConfiguration: TSDocConfiguration;\n}\n\nconst MinifyJSONMapping = {\n\tcanonicalReference: 'c',\n\tconstraintTokenRange: 'ctr',\n\tdependencies: 'dp',\n\tdefaultTypeTokenRange: 'dtr',\n\tdefaultValue: 'dv',\n\tdocComment: 'd',\n\tendIndex: 'en',\n\texcerptTokens: 'ex',\n\textendsTokenRange: 'etr',\n\textendsTokenRanges: 'etrs',\n\tfileColumn: 'co',\n\tfileLine: 'l',\n\tfileUrlPath: 'pat',\n\timplementsTokenRanges: 'itrs',\n\tinitializerTokenRange: 'itr',\n\tisAbstract: 'ab',\n\tisOptional: 'op',\n\tisProtected: 'pr',\n\tisReadonly: 'ro',\n\tisRest: 'rs',\n\tisStatic: 'sta',\n\tkind: 'k',\n\tmembers: 'ms',\n\tmetadata: 'meta',\n\tname: 'n',\n\toldestForwardsCompatibleVersion: 'ov',\n\toverloadIndex: 'oi',\n\tparameterName: 'pn',\n\tparameterTypeTokenRange: 'ptr',\n\tparameters: 'ps',\n\tpreserveMemberOrder: 'pmo',\n\tprojectFolderUrl: 'pdir',\n\tpropertyTypeTokenRange: 'prtr',\n\treleaseTag: 'r',\n\treturnTypeTokenRange: 'rtr',\n\tschemaVersion: 'v',\n\tstartIndex: 'st',\n\ttext: 't',\n\ttoolPackage: 'tpk',\n\ttoolVersion: 'tv',\n\ttsdocConfig: 'ts',\n\ttypeParameterName: 'tp',\n\ttypeParameters: 'tps',\n\ttypeTokenRange: 'ttr',\n\tvariableTypeTokenRange: 'vtr',\n};\n\nexport interface IApiPackageMetadataJson {\n\t/**\n\t * To support forwards compatibility, the `oldestForwardsCompatibleVersion` field tracks the oldest schema version\n\t * whose corresponding deserializer could safely load this file.\n\t *\n\t * @remarks\n\t * Normally api-extractor-model should refuse to load a schema version that is newer than the latest version\n\t * that its deserializer understands.  However, sometimes a schema change may merely introduce some new fields\n\t * without modifying or removing any existing fields.  In this case, an older api-extractor-model library can\n\t * safely deserialize the newer version (by ignoring the extra fields that it doesn't recognize).  The newer\n\t * serializer can use this field to communicate that.\n\t *\n\t * If present, the `oldestForwardsCompatibleVersion` must be less than or equal to\n\t * `IApiPackageMetadataJson.schemaVersion`.\n\t */\n\toldestForwardsCompatibleVersion?: ApiJsonSchemaVersion;\n\n\t/**\n\t * The schema version for the .api.json file format.  Used for determining whether the file format is\n\t * supported, and for backwards compatibility.\n\t */\n\tschemaVersion: ApiJsonSchemaVersion;\n\n\t/**\n\t * The NPM package name for the tool that wrote the *.api.json file.\n\t * For informational purposes only.\n\t */\n\ttoolPackage: string;\n\n\t/**\n\t * The NPM package version for the tool that wrote the *.api.json file.\n\t * For informational purposes only.\n\t */\n\ttoolVersion: string;\n\n\t/**\n\t * The TSDoc configuration that was used when analyzing the API for this package.\n\t *\n\t * @remarks\n\t *\n\t * The structure of this objet is defined by the `@microsoft/tsdoc-config` library.\n\t * Normally this configuration is loaded from the project's tsdoc.json file.  It is stored\n\t * in the .api.json file so that doc comments can be parsed accurately when loading the file.\n\t */\n\ttsdocConfig?: JsonObject;\n}\n\nexport interface IApiPackageJson extends IApiItemJson {\n\t/**\n\t * Names of packages in the same monorepo this one uses mapped to the version of said package.\n\t */\n\tdependencies?: Record<string, string>;\n\n\t/**\n\t * A file header that stores metadata about the tool that wrote the *.api.json file.\n\t */\n\tmetadata: IApiPackageMetadataJson;\n\n\t/**\n\t * The base URL where the project's source code can be viewed on a website such as GitHub or\n\t * Azure DevOps. This URL path corresponds to the `<projectFolder>` path on disk. Provided via the\n\t * `api-extractor.json` config.\n\t */\n\tprojectFolderUrl?: string;\n}\n\n/**\n * Options for {@link ApiPackage.saveToJsonFile}.\n *\n * @public\n */\nexport interface IApiPackageSaveOptions extends IJsonFileSaveOptions {\n\t/**\n\t * Set to true to not have indentation or newlines in resulting JSON.\n\t */\n\tminify?: boolean;\n\n\t/**\n\t * Set to true only when invoking API Extractor's test harness.\n\t *\n\t * @remarks\n\t * When `testMode` is true, the `toolVersion` field in the .api.json file is assigned an empty string\n\t * to prevent spurious diffs in output files tracked for tests.\n\t */\n\ttestMode?: boolean;\n\n\t/**\n\t * Optionally specifies a value for the \"toolPackage\" field in the output .api.json data file;\n\t * otherwise, the value will be \"api-extractor-model\".\n\t */\n\ttoolPackage?: string;\n\n\t/**\n\t * Optionally specifies a value for the \"toolVersion\" field in the output .api.json data file;\n\t * otherwise, the value will be the current version of the api-extractor-model package.\n\t */\n\ttoolVersion?: string;\n}\n\n/**\n * Represents an NPM package containing API declarations.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n * @public\n */\nexport class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumentedItem)) {\n\tprivate readonly _tsdocConfiguration: TSDocConfiguration;\n\n\tprivate readonly _projectFolderUrl?: string | undefined;\n\n\tprivate readonly _dependencies?: Record<string, string> | undefined;\n\n\tpublic constructor(options: IApiPackageOptions) {\n\t\tsuper(options);\n\n\t\tthis._tsdocConfiguration = options.tsdocConfiguration;\n\t\tthis._projectFolderUrl = options.projectFolderUrl;\n\n\t\tif (options.dependencies) {\n\t\t\tthis._dependencies = options.dependencies;\n\t\t} else {\n\t\t\tconst packageJson = PackageJsonLookup.instance.tryLoadPackageJsonFor('.');\n\t\t\tif (packageJson?.dependencies) {\n\t\t\t\tthis._dependencies = {};\n\t\t\t\tfor (const [pack, semVer] of Object.entries(packageJson.dependencies)) {\n\t\t\t\t\tconst pathToPackage = path.join('..', pack.includes('/') ? pack.slice(pack.lastIndexOf('/')) : pack);\n\t\t\t\t\tif (semVer === 'workspace:^') {\n\t\t\t\t\t\tthis._dependencies[pack] =\n\t\t\t\t\t\t\tPackageJsonLookup.instance.tryLoadPackageJsonFor(pathToPackage)?.version ?? 'unknown';\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// if (FileSystem.exists(pathToPackage))\n\t\t\t\t\t\tthis._dependencies[pack] = semVer.replace(/^[\\^~]/, '');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic static override onDeserializeInto(\n\t\toptions: Partial<IApiPackageOptions>,\n\t\tcontext: DeserializerContext,\n\t\tjsonObject: IApiPackageJson,\n\t): void {\n\t\tsuper.onDeserializeInto(options, context, jsonObject);\n\n\t\toptions.projectFolderUrl = jsonObject.projectFolderUrl;\n\t\toptions.dependencies = jsonObject.dependencies;\n\t}\n\n\tpublic static loadFromJsonFile(apiJsonFilename: string): ApiPackage {\n\t\treturn this.loadFromJson(JsonFile.load(apiJsonFilename), apiJsonFilename);\n\t}\n\n\tpublic static loadFromJson(rawJson: any, apiJsonFilename: string = ''): ApiPackage {\n\t\tconst jsonObject =\n\t\t\tMinifyJSONMapping.metadata in rawJson ? this._mapFromMinified(rawJson) : (rawJson as IApiPackageJson);\n\t\tif (!jsonObject?.metadata) throw new Error(util.inspect(rawJson, { depth: 2 }));\n\t\tif (!jsonObject?.metadata || typeof jsonObject.metadata.schemaVersion !== 'number') {\n\t\t\tthrow new Error(\n\t\t\t\t`Error loading ${apiJsonFilename}:` +\n\t\t\t\t\t`\\nThe file format is not recognized; the \"metadata.schemaVersion\" field is missing or invalid`,\n\t\t\t);\n\t\t}\n\n\t\tconst schemaVersion: number = jsonObject.metadata.schemaVersion;\n\n\t\tif (schemaVersion < ApiJsonSchemaVersion.OLDEST_SUPPORTED) {\n\t\t\tthrow new Error(\n\t\t\t\t`Error loading ${apiJsonFilename}:` +\n\t\t\t\t\t`\\nThe file format is version ${schemaVersion},` +\n\t\t\t\t\t` whereas ${ApiJsonSchemaVersion.OLDEST_SUPPORTED} is the oldest version supported by this tool`,\n\t\t\t);\n\t\t}\n\n\t\tlet oldestForwardsCompatibleVersion: number = schemaVersion;\n\t\tif (jsonObject.metadata.oldestForwardsCompatibleVersion) {\n\t\t\t// Sanity check\n\t\t\tif (jsonObject.metadata.oldestForwardsCompatibleVersion > schemaVersion) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Error loading ${apiJsonFilename}:` +\n\t\t\t\t\t\t`\\nInvalid file format; \"oldestForwardsCompatibleVersion\" cannot be newer than \"schemaVersion\"`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\toldestForwardsCompatibleVersion = jsonObject.metadata.oldestForwardsCompatibleVersion;\n\t\t}\n\n\t\tlet versionToDeserialize: number = schemaVersion;\n\t\tif (versionToDeserialize > ApiJsonSchemaVersion.LATEST) {\n\t\t\t// If the file format is too new, can we treat it as some earlier compatible version\n\t\t\t// as indicated by oldestForwardsCompatibleVersion?\n\t\t\tversionToDeserialize = Math.max(oldestForwardsCompatibleVersion, ApiJsonSchemaVersion.LATEST);\n\n\t\t\tif (versionToDeserialize > ApiJsonSchemaVersion.LATEST) {\n\t\t\t\t// Nope, still too new\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Error loading ${apiJsonFilename}:` +\n\t\t\t\t\t\t`\\nThe file format version ${schemaVersion} was written by a newer release of` +\n\t\t\t\t\t\t` the api-extractor-model library; you may need to upgrade your software`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst tsdocConfiguration: TSDocConfiguration = new TSDocConfiguration();\n\n\t\tif (\n\t\t\tversionToDeserialize >= ApiJsonSchemaVersion.V_1004 &&\n\t\t\t'tsdocConfig' in jsonObject.metadata &&\n\t\t\t'$schema' in jsonObject.metadata.tsdocConfig\n\t\t) {\n\t\t\tconst tsdocConfigFile: TSDocConfigFile = TSDocConfigFile.loadFromObject(jsonObject.metadata.tsdocConfig);\n\t\t\tif (tsdocConfigFile.hasErrors) {\n\t\t\t\tthrow new Error(`Error loading ${apiJsonFilename}:\\n` + tsdocConfigFile.getErrorSummary());\n\t\t\t}\n\n\t\t\ttsdocConfigFile.configureParser(tsdocConfiguration);\n\t\t}\n\n\t\tconst context: DeserializerContext = new DeserializerContext({\n\t\t\tapiJsonFilename,\n\t\t\ttoolPackage: jsonObject.metadata.toolPackage,\n\t\t\ttoolVersion: jsonObject.metadata.toolVersion,\n\t\t\tversionToDeserialize,\n\t\t\ttsdocConfiguration,\n\t\t});\n\n\t\treturn ApiItem.deserialize(jsonObject, context) as ApiPackage;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.Package;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\t// No prefix needed, because ApiPackage is the only possible member of an ApiModel\n\t\treturn this.name;\n\t}\n\n\tpublic get entryPoints(): readonly ApiEntryPoint[] {\n\t\treturn this.members as readonly ApiEntryPoint[];\n\t}\n\n\tpublic get dependencies(): Record<string, string> | undefined {\n\t\treturn this._dependencies;\n\t}\n\n\t/**\n\t * The TSDoc configuration that was used when analyzing the API for this package.\n\t *\n\t * @remarks\n\t *\n\t * Normally this configuration is loaded from the project's tsdoc.json file.  It is stored\n\t * in the .api.json file so that doc comments can be parsed accurately when loading the file.\n\t */\n\tpublic get tsdocConfiguration(): TSDocConfiguration {\n\t\treturn this._tsdocConfiguration;\n\t}\n\n\tpublic get projectFolderUrl(): string | undefined {\n\t\treturn this._projectFolderUrl;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override addMember(member: ApiEntryPoint): void {\n\t\tif (member.kind !== ApiItemKind.EntryPoint) {\n\t\t\tthrow new Error('Only items of type ApiEntryPoint may be added to an ApiPackage');\n\t\t}\n\n\t\tsuper.addMember(member);\n\t}\n\n\tpublic findEntryPointsByPath(importPath: string): readonly ApiEntryPoint[] {\n\t\treturn this.findMembersByName(importPath) as readonly ApiEntryPoint[];\n\t}\n\n\tpublic saveToJsonFile(apiJsonFilename: string, options?: IApiPackageSaveOptions): void {\n\t\tconst ioptions = options ?? {};\n\n\t\tconst packageJson: IPackageJson = PackageJsonLookup.loadOwnPackageJson(__dirname);\n\n\t\tconst tsdocConfigFile: TSDocConfigFile = TSDocConfigFile.loadFromParser(this.tsdocConfiguration);\n\t\tconst tsdocConfig: JsonObject = tsdocConfigFile.saveToObject();\n\n\t\tconst jsonObject: IApiPackageJson = {\n\t\t\tmetadata: {\n\t\t\t\ttoolPackage: ioptions.toolPackage ?? packageJson.name,\n\t\t\t\t// In test mode, we don't write the real version, since that would cause spurious diffs whenever\n\t\t\t\t// the version is bumped.  Instead we write a placeholder string.\n\t\t\t\ttoolVersion: ioptions.testMode ? '[test mode]' : (ioptions.toolVersion ?? packageJson.version),\n\t\t\t\tschemaVersion: ApiJsonSchemaVersion.LATEST,\n\t\t\t\toldestForwardsCompatibleVersion: ApiJsonSchemaVersion.OLDEST_FORWARDS_COMPATIBLE,\n\t\t\t\ttsdocConfig,\n\t\t\t},\n\t\t} as IApiPackageJson;\n\n\t\tif (this.projectFolderUrl) {\n\t\t\tjsonObject.projectFolderUrl = this.projectFolderUrl;\n\t\t}\n\n\t\tif (this._dependencies) {\n\t\t\tjsonObject.dependencies = this._dependencies;\n\t\t}\n\n\t\tthis.serializeInto(jsonObject);\n\t\tif (ioptions.minify) {\n\t\t\tFileSystem.writeFile(apiJsonFilename, Buffer.from(JSON.stringify(this._mapToMinified(jsonObject)), 'utf8'), {\n\t\t\t\tensureFolderExists: ioptions.ensureFolderExists ?? true,\n\t\t\t});\n\t\t} else {\n\t\t\tJsonFile.save(jsonObject, apiJsonFilename, ioptions);\n\t\t}\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\treturn DeclarationReference.package(this.name);\n\t}\n\n\tprivate _mapToMinified(jsonObject: IApiPackageJson) {\n\t\tconst mapper = (item: any): any => {\n\t\t\tif (Array.isArray(item)) return item.map(mapper);\n\t\t\telse {\n\t\t\t\tconst result: any = {};\n\t\t\t\tfor (const key of Object.keys(item)) {\n\t\t\t\t\tif (key === 'dependencies') {\n\t\t\t\t\t\tresult[MinifyJSONMapping.dependencies] = item.dependencies;\n\t\t\t\t\t} else if (key === 'tsdocConfig') {\n\t\t\t\t\t\tresult[MinifyJSONMapping.tsdocConfig] = item.tsdocConfig;\n\t\t\t\t\t} else\n\t\t\t\t\t\tresult[MinifyJSONMapping[key as keyof typeof MinifyJSONMapping]] =\n\t\t\t\t\t\t\ttypeof item[key] === 'object' ? mapper(item[key]) : item[key];\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\t\t};\n\n\t\treturn mapper(jsonObject);\n\t}\n\n\tprivate static _mapFromMinified(jsonObject: any): IApiPackageJson {\n\t\tconst mapper = (item: any): any => {\n\t\t\tif (Array.isArray(item)) return item.map(mapper);\n\t\t\telse {\n\t\t\t\tconst result: any = {};\n\t\t\t\tfor (const key of Object.keys(item)) {\n\t\t\t\t\tif (key === MinifyJSONMapping.dependencies) {\n\t\t\t\t\t\tresult.dependencies = item[MinifyJSONMapping.dependencies];\n\t\t\t\t\t} else if (key === MinifyJSONMapping.tsdocConfig) {\n\t\t\t\t\t\tresult.tsdocConfig = item[MinifyJSONMapping.tsdocConfig];\n\t\t\t\t\t} else\n\t\t\t\t\t\tresult[\n\t\t\t\t\t\t\tObject.keys(MinifyJSONMapping).find(\n\t\t\t\t\t\t\t\t(look) => MinifyJSONMapping[look as keyof typeof MinifyJSONMapping] === key,\n\t\t\t\t\t\t\t)!\n\t\t\t\t\t\t] = typeof item[key] === 'object' ? mapper(item[key]) : item[key];\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\t\t};\n\n\t\treturn mapper(jsonObject) as IApiPackageJson;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiProperty.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport { ApiPropertyItem, type IApiPropertyItemOptions } from '../items/ApiPropertyItem.js';\nimport { ApiAbstractMixin, type IApiAbstractMixinOptions } from '../mixins/ApiAbstractMixin.js';\nimport { ApiInitializerMixin, type IApiInitializerMixinOptions } from '../mixins/ApiInitializerMixin.js';\nimport { ApiProtectedMixin, type IApiProtectedMixinOptions } from '../mixins/ApiProtectedMixin.js';\nimport { ApiStaticMixin, type IApiStaticMixinOptions } from '../mixins/ApiStaticMixin.js';\n\n/**\n * Constructor options for {@link ApiProperty}.\n *\n * @public\n */\nexport interface IApiPropertyOptions\n\textends\n\t\tIApiPropertyItemOptions,\n\t\tIApiAbstractMixinOptions,\n\t\tIApiProtectedMixinOptions,\n\t\tIApiStaticMixinOptions,\n\t\tIApiInitializerMixinOptions {}\n\n/**\n * Represents a TypeScript property declaration that belongs to an `ApiClass`.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiProperty` represents a TypeScript declaration such as the `width` and `height` members in this example:\n *\n * ```ts\n * export class Widget {\n *   public width: number = 100;\n *\n *   public get height(): number {\n *     if (this.isSquashed()) {\n *       return 0;\n *     } else {\n *       return this.clientArea.height;\n *     }\n *   }\n * }\n * ```\n *\n * Note that member variables are also considered to be properties.\n *\n * If the property has both a getter function and setter function, they will be represented by a single `ApiProperty`\n * and must have a single documentation comment.\n *\n * Compare with {@link ApiPropertySignature}, which represents a property belonging to an interface.\n * For example, a class property can be `static` but an interface property cannot.\n * @public\n */\nexport class ApiProperty extends ApiAbstractMixin(\n\tApiProtectedMixin(ApiStaticMixin(ApiInitializerMixin(ApiPropertyItem))),\n) {\n\tpublic constructor(options: IApiPropertyOptions) {\n\t\tsuper(options);\n\t}\n\n\tpublic static getContainerKey(name: string, isStatic: boolean): string {\n\t\tif (isStatic) {\n\t\t\treturn `${name}|${ApiItemKind.Property}|static`;\n\t\t} else {\n\t\t\treturn `${name}|${ApiItemKind.Property}|instance`;\n\t\t}\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.Property;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiProperty.getContainerKey(this.name, this.isStatic);\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst nameComponent: Component = DeclarationReference.parseComponent(this.name);\n\t\treturn (this.parent ? this.parent.canonicalReference : DeclarationReference.empty())\n\t\t\t.addNavigationStep((this.isStatic ? Navigation.Exports : Navigation.Members) as any, nameComponent)\n\t\t\t.withMeaning(Meaning.Member as any);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiPropertySignature.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport { ApiPropertyItem, type IApiPropertyItemOptions } from '../items/ApiPropertyItem.js';\n\n/**\n * Constructor options for {@link ApiPropertySignature}.\n *\n * @public\n */\nexport interface IApiPropertySignatureOptions extends IApiPropertyItemOptions {}\n\n/**\n * Represents a TypeScript property declaration that belongs to an `ApiInterface`.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiPropertySignature` represents a TypeScript declaration such as the `width` and `height` members in this example:\n *\n * ```ts\n * export interface IWidget {\n *   readonly width: number;\n *   height: number;\n * }\n * ```\n *\n * Compare with {@link ApiProperty}, which represents a property belonging to a class.\n * For example, a class property can be `static` but an interface property cannot.\n * @public\n */\nexport class ApiPropertySignature extends ApiPropertyItem {\n\tpublic constructor(options: IApiPropertySignatureOptions) {\n\t\tsuper(options);\n\t}\n\n\tpublic static getContainerKey(name: string): string {\n\t\treturn `${name}|${ApiItemKind.PropertySignature}`;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.PropertySignature;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiPropertySignature.getContainerKey(this.name);\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst nameComponent: Component = DeclarationReference.parseComponent(this.name);\n\t\treturn (this.parent ? this.parent.canonicalReference : DeclarationReference.empty())\n\t\t\t.addNavigationStep(Navigation.Members as any, nameComponent)\n\t\t\t.withMeaning(Meaning.Member as any);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiTypeAlias.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { ApiDeclaredItem, type IApiDeclaredItemOptions, type IApiDeclaredItemJson } from '../items/ApiDeclaredItem.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport {\n\ttype IApiExportedMixinJson,\n\ttype IApiExportedMixinOptions,\n\tApiExportedMixin,\n} from '../mixins/ApiExportedMixin.js';\nimport { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin.js';\nimport { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin.js';\nimport {\n\tApiTypeParameterListMixin,\n\ttype IApiTypeParameterListMixinOptions,\n\ttype IApiTypeParameterListMixinJson,\n} from '../mixins/ApiTypeParameterListMixin.js';\nimport type { Excerpt, IExcerptTokenRange } from '../mixins/Excerpt.js';\nimport type { DeserializerContext } from './DeserializerContext.js';\n\n/**\n * Constructor options for {@link ApiTypeAlias}.\n *\n * @public\n */\nexport interface IApiTypeAliasOptions\n\textends\n\t\tIApiNameMixinOptions,\n\t\tIApiReleaseTagMixinOptions,\n\t\tIApiDeclaredItemOptions,\n\t\tIApiTypeParameterListMixinOptions,\n\t\tIApiExportedMixinOptions {\n\ttypeTokenRange: IExcerptTokenRange;\n}\n\nexport interface IApiTypeAliasJson extends IApiDeclaredItemJson, IApiTypeParameterListMixinJson, IApiExportedMixinJson {\n\ttypeTokenRange: IExcerptTokenRange;\n}\n\n/**\n * Represents a TypeScript type alias declaration.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiTypeAlias` represents a definition such as one of these examples:\n *\n * ```ts\n * // A union type:\n * export type Shape = Square | Triangle | Circle;\n *\n * // A generic type alias:\n * export type BoxedValue<T> = { value: T };\n *\n * export type BoxedArray<T> = { array: T[] };\n *\n * // A conditional type alias:\n * export type Boxed<T> = T extends any[] ? BoxedArray<T[number]> : BoxedValue<T>;\n *\n * ```\n * @public\n */\nexport class ApiTypeAlias extends ApiTypeParameterListMixin(\n\tApiNameMixin(ApiReleaseTagMixin(ApiExportedMixin(ApiDeclaredItem))),\n) {\n\t/**\n\t * An {@link Excerpt} that describes the type of the alias.\n\t *\n\t * @remarks\n\t * In the example below, the `typeExcerpt` would correspond to the subexpression\n\t * `T extends any[] ? BoxedArray<T[number]> : BoxedValue<T>;`:\n\t *\n\t * ```ts\n\t * export type Boxed<T> = T extends any[] ? BoxedArray<T[number]> : BoxedValue<T>;\n\t * ```\n\t */\n\tpublic readonly typeExcerpt: Excerpt;\n\n\tpublic constructor(options: IApiTypeAliasOptions) {\n\t\tsuper(options);\n\n\t\tthis.typeExcerpt = this.buildExcerpt(options.typeTokenRange);\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic static override onDeserializeInto(\n\t\toptions: Partial<IApiTypeAliasOptions>,\n\t\tcontext: DeserializerContext,\n\t\tjsonObject: IApiTypeAliasJson,\n\t): void {\n\t\tsuper.onDeserializeInto(options, context, jsonObject);\n\n\t\toptions.typeTokenRange = jsonObject.typeTokenRange;\n\t}\n\n\tpublic static getContainerKey(name: string): string {\n\t\treturn `${name}|${ApiItemKind.TypeAlias}`;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.TypeAlias;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiTypeAlias.getContainerKey(this.name);\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override serializeInto(jsonObject: Partial<IApiTypeAliasJson>): void {\n\t\tsuper.serializeInto(jsonObject);\n\n\t\tjsonObject.typeTokenRange = this.typeExcerpt.tokenRange;\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst nameComponent: Component = DeclarationReference.parseComponent(this.name);\n\t\tconst navigation: Navigation = this.isExported ? Navigation.Exports : Navigation.Locals;\n\t\treturn (this.parent ? this.parent.canonicalReference : DeclarationReference.empty())\n\t\t\t.addNavigationStep(navigation as any, nameComponent)\n\t\t\t.withMeaning(Meaning.TypeAlias as any);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ApiVariable.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { DeclarationReference, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { ApiDeclaredItem, type IApiDeclaredItemOptions, type IApiDeclaredItemJson } from '../items/ApiDeclaredItem.js';\nimport { ApiItemKind, Navigation, Meaning } from '../items/ApiItem.js';\nimport {\n\ttype IApiExportedMixinJson,\n\ttype IApiExportedMixinOptions,\n\tApiExportedMixin,\n} from '../mixins/ApiExportedMixin.js';\nimport { ApiInitializerMixin, type IApiInitializerMixinOptions } from '../mixins/ApiInitializerMixin.js';\nimport { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin.js';\nimport { ApiReadonlyMixin, type IApiReadonlyMixinOptions } from '../mixins/ApiReadonlyMixin.js';\nimport { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin.js';\nimport type { IExcerptTokenRange, Excerpt } from '../mixins/Excerpt.js';\nimport type { DeserializerContext } from './DeserializerContext.js';\n\n/**\n * Constructor options for {@link ApiVariable}.\n *\n * @public\n */\nexport interface IApiVariableOptions\n\textends\n\t\tIApiNameMixinOptions,\n\t\tIApiReleaseTagMixinOptions,\n\t\tIApiReadonlyMixinOptions,\n\t\tIApiDeclaredItemOptions,\n\t\tIApiInitializerMixinOptions,\n\t\tIApiExportedMixinOptions {\n\tvariableTypeTokenRange: IExcerptTokenRange;\n}\n\nexport interface IApiVariableJson extends IApiDeclaredItemJson, IApiExportedMixinJson {\n\tvariableTypeTokenRange: IExcerptTokenRange;\n}\n\n/**\n * Represents a TypeScript variable declaration.\n *\n * @remarks\n *\n * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of\n * API declarations.\n *\n * `ApiVariable` represents an exported `const` or `let` object such as these examples:\n *\n * ```ts\n * // A variable declaration\n * export let verboseLogging: boolean;\n *\n * // A constant variable declaration with an initializer\n * export const canvas: IWidget = createCanvas();\n * ```\n * @public\n */\nexport class ApiVariable extends ApiNameMixin(\n\tApiReleaseTagMixin(ApiReadonlyMixin(ApiInitializerMixin(ApiExportedMixin(ApiDeclaredItem)))),\n) {\n\t/**\n\t * An {@link Excerpt} that describes the type of the variable.\n\t */\n\tpublic readonly variableTypeExcerpt: Excerpt;\n\n\tpublic constructor(options: IApiVariableOptions) {\n\t\tsuper(options);\n\n\t\tthis.variableTypeExcerpt = this.buildExcerpt(options.variableTypeTokenRange);\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic static override onDeserializeInto(\n\t\toptions: Partial<IApiVariableOptions>,\n\t\tcontext: DeserializerContext,\n\t\tjsonObject: IApiVariableJson,\n\t): void {\n\t\tsuper.onDeserializeInto(options, context, jsonObject);\n\n\t\toptions.variableTypeTokenRange = jsonObject.variableTypeTokenRange;\n\t}\n\n\tpublic static getContainerKey(name: string): string {\n\t\treturn `${name}|${ApiItemKind.Variable}`;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get kind(): ApiItemKind {\n\t\treturn ApiItemKind.Variable;\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override get containerKey(): string {\n\t\treturn ApiVariable.getContainerKey(this.name);\n\t}\n\n\t/**\n\t * @override\n\t */\n\tpublic override serializeInto(jsonObject: Partial<IApiVariableJson>): void {\n\t\tsuper.serializeInto(jsonObject);\n\n\t\tjsonObject.variableTypeTokenRange = this.variableTypeExcerpt.tokenRange;\n\t}\n\n\t/**\n\t * @beta @override\n\t */\n\tpublic override buildCanonicalReference(): DeclarationReference {\n\t\tconst nameComponent: Component = DeclarationReference.parseComponent(this.name);\n\t\tconst navigation: Navigation = this.isExported ? Navigation.Exports : Navigation.Locals;\n\t\treturn (this.parent ? this.parent.canonicalReference : DeclarationReference.empty())\n\t\t\t.addNavigationStep(navigation as any, nameComponent)\n\t\t\t.withMeaning(Meaning.Variable as any);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/Deserializer.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { TSDocConfiguration } from '@microsoft/tsdoc';\nimport type { IExcerptToken } from '../index.js';\nimport { ExcerptTokenKind } from '../index.js';\nimport type { IApiDeclaredItemJson } from '../items/ApiDeclaredItem.js';\nimport type { IApiDocumentedItemJson } from '../items/ApiDocumentedItem.js';\nimport { type IApiItemJson, type IApiItemOptions, type ApiItem, ApiItemKind } from '../items/ApiItem.js';\nimport type { IApiPropertyItemJson } from '../items/ApiPropertyItem.js';\nimport type { IApiAbstractMixinJson } from '../mixins/ApiAbstractMixin.js';\nimport type { IApiItemContainerJson } from '../mixins/ApiItemContainerMixin.js';\nimport type { IApiNameMixinJson } from '../mixins/ApiNameMixin.js';\nimport type { IApiOptionalMixinJson } from '../mixins/ApiOptionalMixin.js';\nimport type { IApiParameterListJson, IApiParameterOptions } from '../mixins/ApiParameterListMixin.js';\nimport type { IApiProtectedMixinJson } from '../mixins/ApiProtectedMixin.js';\nimport type { IApiReadonlyMixinJson } from '../mixins/ApiReadonlyMixin.js';\nimport type { IApiReleaseTagMixinJson } from '../mixins/ApiReleaseTagMixin.js';\nimport type { IApiReturnTypeMixinJson } from '../mixins/ApiReturnTypeMixin.js';\nimport type { IApiStaticMixinJson } from '../mixins/ApiStaticMixin.js';\nimport type { IApiTypeParameterListMixinJson } from '../mixins/ApiTypeParameterListMixin.js';\nimport { ApiCallSignature, type IApiCallSignatureOptions } from './ApiCallSignature.js';\nimport { ApiClass, type IApiClassOptions, type IApiClassJson } from './ApiClass.js';\nimport { ApiConstructSignature, type IApiConstructSignatureOptions } from './ApiConstructSignature.js';\nimport { ApiConstructor, type IApiConstructorOptions } from './ApiConstructor.js';\nimport { ApiEntryPoint, type IApiEntryPointOptions } from './ApiEntryPoint.js';\nimport { ApiEnum, type IApiEnumOptions } from './ApiEnum.js';\nimport { ApiEnumMember, type IApiEnumMemberOptions } from './ApiEnumMember.js';\nimport type { IApiEventOptions } from './ApiEvent.js';\nimport { ApiEvent } from './ApiEvent.js';\nimport { ApiFunction, type IApiFunctionOptions } from './ApiFunction.js';\nimport { ApiIndexSignature, type IApiIndexSignatureOptions } from './ApiIndexSignature.js';\nimport { ApiInterface, type IApiInterfaceOptions, type IApiInterfaceJson } from './ApiInterface.js';\nimport { ApiMethod, type IApiMethodOptions } from './ApiMethod.js';\nimport { ApiMethodSignature, type IApiMethodSignatureOptions } from './ApiMethodSignature.js';\nimport { ApiModel } from './ApiModel.js';\nimport { ApiNamespace, type IApiNamespaceOptions } from './ApiNamespace.js';\nimport { ApiPackage, type IApiPackageOptions, type IApiPackageJson } from './ApiPackage.js';\nimport { ApiProperty, type IApiPropertyOptions } from './ApiProperty.js';\nimport { ApiPropertySignature, type IApiPropertySignatureOptions } from './ApiPropertySignature.js';\nimport { ApiTypeAlias, type IApiTypeAliasOptions, type IApiTypeAliasJson } from './ApiTypeAlias.js';\nimport { ApiVariable, type IApiVariableOptions, type IApiVariableJson } from './ApiVariable.js';\nimport { ApiJsonSchemaVersion, type DeserializerContext } from './DeserializerContext.js';\n\ntype DocgenAccess = 'private' | 'protected' | 'public';\ntype DocgenScope = 'global' | 'instance' | 'static';\ntype DocgenDeprecated = boolean | string;\n\ninterface DocgenMetaJson {\n\tfile: string;\n\tline: number;\n\tpath: string;\n}\n\ninterface DocgenTypeJson {\n\tnames?: string[] | undefined;\n}\n\ninterface DocgenVarJson {\n\tdescription?: string;\n\tnullable?: boolean;\n\ttypes?: string[][][];\n}\ntype DocgenVarTypeJson = DocgenVarJson | string[][][];\ninterface DocgenExceptionJson {\n\tdescription?: string;\n\tnullable?: boolean;\n\ttype: DocgenTypeJson;\n}\n\ninterface DocgenExternalJson {\n\tdescription: string;\n\tmeta: DocgenMetaJson;\n\tname: string;\n\tsee?: string[];\n}\n\ninterface DocgenTypedefJson {\n\taccess?: DocgenAccess;\n\tdeprecated?: DocgenDeprecated;\n\tdescription: string;\n\tmeta: DocgenMetaJson;\n\tname: string;\n\tparams?: DocgenParamJson[];\n\tprops?: DocgenParamJson[];\n\treturns?: DocgenVarTypeJson[];\n\tsee?: string[];\n\ttype: DocgenVarTypeJson;\n}\n\ninterface DocgenEventJson {\n\tdeprecated?: DocgenDeprecated;\n\tdescription: string;\n\tmeta: DocgenMetaJson;\n\tname: string;\n\tparams?: DocgenParamJson[];\n\tsee?: string[];\n}\n\ninterface DocgenParamJson {\n\tdefault?: string;\n\tdescription: string;\n\tname: string;\n\tnullable?: boolean;\n\toptional?: boolean;\n\ttype: DocgenVarTypeJson;\n\tvariable?: string;\n}\n\ninterface DocgenConstructorJson {\n\taccess?: DocgenAccess;\n\tdescription: string;\n\tname: string;\n\tparams?: DocgenParamJson[];\n\tsee?: string[];\n}\n\ninterface DocgenMethodJson {\n\tabstract: boolean;\n\taccess?: DocgenAccess;\n\tasync?: boolean;\n\tdeprecated?: DocgenDeprecated;\n\tdescription: string;\n\temits?: string[];\n\texamples?: string[];\n\tgenerator?: boolean;\n\timplements?: string[];\n\tinherited?: boolean;\n\tinherits?: string;\n\tmeta: DocgenMetaJson;\n\tname: string;\n\tparams?: DocgenParamJson[];\n\treturns?: DocgenVarTypeJson[];\n\tscope: DocgenScope;\n\tsee?: string[];\n\tthrows?: DocgenExceptionJson[];\n}\n\ninterface DocgenPropertyJson {\n\tabstract?: boolean;\n\taccess?: DocgenAccess;\n\tdefault?: string;\n\tdeprecated?: DocgenDeprecated;\n\tdescription: string;\n\tmeta: DocgenMetaJson;\n\tname: string;\n\tnullable?: boolean;\n\tprops?: DocgenPropertyJson[];\n\treadonly?: boolean;\n\tscope: DocgenScope;\n\tsee?: string[];\n\ttype: DocgenVarTypeJson;\n}\ninterface DocgenClassJson {\n\tabstract?: boolean;\n\taccess?: DocgenAccess;\n\tconstruct: DocgenConstructorJson;\n\tdeprecated?: DocgenDeprecated | string;\n\tdescription: string;\n\tevents?: DocgenEventJson[];\n\textends?: DocgenVarTypeJson;\n\timplements?: DocgenVarTypeJson;\n\tmeta: DocgenMetaJson;\n\tmethods?: DocgenMethodJson[];\n\tname: string;\n\tprops?: DocgenPropertyJson[];\n\tsee?: string[];\n}\ntype DocgenInterfaceJson = DocgenClassJson;\n\nexport interface DocgenJson {\n\tclasses: DocgenClassJson[];\n\texternals: DocgenExternalJson[];\n\tfunctions: DocgenMethodJson[];\n\tinterfaces: DocgenInterfaceJson[];\n\tmeta: {\n\t\tdate: number;\n\t\tformat: number;\n\t\tgenerator: string;\n\t};\n\ttypedefs: DocgenTypedefJson[];\n}\n\nfunction formatVarType(type: DocgenVarTypeJson): string {\n\treturn (Array.isArray(type) ? type : (type.types ?? []))\n\t\t.map((t1) => t1.map((t2) => t2.join('')).join(''))\n\t\t.join(' | ');\n}\n\nfunction getFirstType(type: DocgenVarTypeJson): string {\n\treturn (Array.isArray(type) ? type[0]?.[0]?.[0] : type.types?.[0]?.[0]?.[0]) ?? 'unknown';\n}\n\n// function mapEvent(_event: DocgenEventJson, _package: string, _parent: DocgenClassJson): void {}\n\nfunction mapVarType(type: DocgenVarTypeJson, _package: string): IExcerptToken[] {\n\tconst mapper = Array.isArray(type) ? type : (type.types ?? []);\n\treturn mapper.flatMap((typ) =>\n\t\ttyp.reduce<IExcerptToken[]>(\n\t\t\t(arr, [_class, symbol]) => [\n\t\t\t\t...arr,\n\t\t\t\t{\n\t\t\t\t\tkind: ExcerptTokenKind.Reference,\n\t\t\t\t\ttext: _class ?? 'unknown',\n\t\t\t\t\tcanonicalReference: `${_package}!${_class}:class`,\n\t\t\t\t},\n\t\t\t\t{ kind: ExcerptTokenKind.Content, text: symbol ?? '' },\n\t\t\t],\n\t\t\t[],\n\t\t),\n\t);\n}\n\nfunction mapProp(\n\tprop: DocgenPropertyJson,\n\t_package: string,\n\t// eslint-disable-next-line @typescript-eslint/no-duplicate-type-constituents\n\tparent: DocgenClassJson | DocgenInterfaceJson,\n): IApiNameMixinJson & IApiOptionalMixinJson & IApiPropertyItemJson & IApiReadonlyMixinJson & IApiReleaseTagMixinJson {\n\tconst mappedVarType = mapVarType(prop.type, _package);\n\treturn {\n\t\tkind: ApiItemKind.Property,\n\t\tname: prop.name,\n\t\tisOptional: Boolean(prop.nullable),\n\t\tisReadonly: Boolean(prop.readonly),\n\t\tdocComment: `/**\\n * ${prop.description}\\n${prop.see?.map((see) => ` * @see ${see}\\n`).join('') ?? ''}${\n\t\t\tprop.readonly ? ' * @readonly\\n' : ''\n\t\t} */`,\n\t\texcerptTokens: [\n\t\t\t{\n\t\t\t\tkind: ExcerptTokenKind.Content,\n\t\t\t\ttext: `${prop.access} ${prop.scope === 'static' ? 'static ' : ''}${prop.readonly ? 'readonly ' : ''}${\n\t\t\t\t\tprop.name\n\t\t\t\t} :`,\n\t\t\t},\n\t\t\t...mappedVarType,\n\t\t\t{\n\t\t\t\tkind: ExcerptTokenKind.Reference,\n\t\t\t\ttext: formatVarType(prop.type),\n\t\t\t\tcanonicalReference: `${_package}!${getFirstType(prop.type)}:class`,\n\t\t\t},\n\t\t\t{ kind: ExcerptTokenKind.Content, text: ';' },\n\t\t],\n\t\tpropertyTypeTokenRange: { startIndex: 1, endIndex: 1 + mappedVarType.length },\n\t\tcanonicalReference: `${_package}!${parent.name}#${prop.name}:member`,\n\t\treleaseTag: prop.access === 'public' ? 'Public' : 'Internal',\n\t\tfileLine: prop.meta.line,\n\t\tfileUrlPath: `${prop.meta.path.slice(`packages/${_package}/`.length)}/${prop.meta.file}`,\n\t};\n}\n\nfunction mapParam(\n\tparam: DocgenParamJson,\n\tindex: number,\n\t_package: string,\n\tparamTokens: number[],\n): IApiParameterOptions {\n\treturn {\n\t\tparameterName: param.name.startsWith('...') ? param.name.slice(3) : param.name,\n\t\tisOptional: Boolean(param.optional),\n\t\tisRest: param.name.startsWith('...'),\n\t\tparameterTypeTokenRange: {\n\t\t\tstartIndex: 1 + index + paramTokens.slice(0, index).reduce((akk, num) => akk + num, 0),\n\t\t\tendIndex: 1 + index + paramTokens.slice(0, index + 1).reduce((akk, num) => akk + num, 0),\n\t\t},\n\t\tdefaultValue: param.default,\n\t};\n}\n\ninterface IApiMethodJson\n\textends\n\t\tIApiAbstractMixinJson,\n\t\tIApiDeclaredItemJson,\n\t\tIApiNameMixinJson,\n\t\tIApiOptionalMixinJson,\n\t\tIApiParameterListJson,\n\t\tIApiProtectedMixinJson,\n\t\tIApiReleaseTagMixinJson,\n\t\tIApiReturnTypeMixinJson,\n\t\tIApiStaticMixinJson,\n\t\tIApiTypeParameterListMixinJson {}\n\ninterface IApiConstructorJson\n\textends IApiParameterListJson, IApiProtectedMixinJson, IApiReleaseTagMixinJson, IApiDeclaredItemJson {}\n\nfunction mapMethod(method: DocgenMethodJson, _package: string, parent?: DocgenClassJson): IApiMethodJson {\n\tconst excerptTokens: IExcerptToken[] = [];\n\texcerptTokens.push({\n\t\tkind: ExcerptTokenKind.Content,\n\t\ttext: `${\n\t\t\tmethod.scope === 'global'\n\t\t\t\t? `export function ${method.name}(`\n\t\t\t\t: `${method.access}${method.scope === 'static' ? ' static' : ''} ${method.name}(`\n\t\t}${\n\t\t\tmethod.params?.length\n\t\t\t\t? `${method.params[0]!.name}${method.params[0]!.nullable || method.params[0]!.optional ? '?' : ''}`\n\t\t\t\t: '): '\n\t\t}`,\n\t});\n\tconst paramTokens: number[] = [];\n\tfor (let index = 0; index < (method.params?.length ?? 0) - 1; index++) {\n\t\tconst newTokens = mapVarType(method.params![index]!.type, _package);\n\t\tparamTokens.push(newTokens.length);\n\t\texcerptTokens.push(...newTokens);\n\t\texcerptTokens.push({\n\t\t\tkind: ExcerptTokenKind.Content,\n\t\t\ttext: `, ${method.params![index + 1]!.name}${\n\t\t\t\tmethod.params![index + 1]!.nullable || method.params![index + 1]!.optional ? '?' : ''\n\t\t\t}: `,\n\t\t});\n\t}\n\n\tif (method.params?.length) {\n\t\tconst newTokens = mapVarType(method.params[method.params.length - 1]!.type, _package);\n\t\tparamTokens.push(newTokens.length);\n\t\texcerptTokens.push(...newTokens);\n\t\texcerptTokens.push({ kind: ExcerptTokenKind.Content, text: `): ` });\n\t}\n\n\tconst returnTokens = mapVarType(method.returns?.[0] ?? [], _package);\n\texcerptTokens.push(...returnTokens);\n\n\texcerptTokens.push({ kind: ExcerptTokenKind.Content, text: ';' });\n\n\treturn {\n\t\tkind: parent ? ApiItemKind.Method : ApiItemKind.Function,\n\t\tname: method.name,\n\t\tisAbstract: method.abstract,\n\t\tisOptional: false,\n\t\tisProtected: method.access === 'protected',\n\t\tisStatic: method.scope === 'static',\n\t\tcanonicalReference: `${_package}!${parent ? `${parent.name}!${method.name}:member` : `${method.name}:function`}`,\n\t\toverloadIndex: 1,\n\t\tparameters: method.params?.map((param, index) => mapParam(param, index, _package, paramTokens)) ?? [],\n\t\treleaseTag: method.access === 'public' ? 'Public' : 'Internal',\n\t\treturnTypeTokenRange: method.returns?.length\n\t\t\t? method.params?.length\n\t\t\t\t? { startIndex: 2 + 2 * method.params.length, endIndex: 3 + 2 * method.params.length }\n\t\t\t\t: { startIndex: 1, endIndex: 2 }\n\t\t\t: { startIndex: 0, endIndex: 0 },\n\t\ttypeParameters: [],\n\t\tdocComment: `/**\\n * ${method.description}\\n${\n\t\t\tmethod.params?.map((param) => ` * @param ${param.name} - ${param.description}\\n`).join('') ?? ''\n\t\t}${\n\t\t\tmethod.returns?.length && !Array.isArray(method.returns[0]) ? ` * @returns ${method.returns[0]!.description}` : ''\n\t\t} */`,\n\t\texcerptTokens,\n\t\tfileLine: method.meta.line,\n\t\tfileUrlPath: `${method.meta.path.slice(`packages/${_package}/`.length)}/${method.meta.file}`,\n\t};\n}\n\nexport class Deserializer {\n\tpublic static deserialize(context: DeserializerContext, jsonObject: IApiItemJson): ApiItem {\n\t\tconst options: Partial<IApiItemOptions> = {};\n\n\t\tswitch (jsonObject.kind) {\n\t\t\tcase ApiItemKind.Class:\n\t\t\t\tApiClass.onDeserializeInto(options, context, jsonObject as IApiClassJson);\n\t\t\t\treturn new ApiClass(options as IApiClassOptions);\n\t\t\tcase ApiItemKind.CallSignature:\n\t\t\t\tApiCallSignature.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson);\n\t\t\t\treturn new ApiCallSignature(options as IApiCallSignatureOptions);\n\t\t\tcase ApiItemKind.Constructor:\n\t\t\t\tApiConstructor.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson);\n\t\t\t\treturn new ApiConstructor(options as IApiConstructorOptions);\n\t\t\tcase ApiItemKind.ConstructSignature:\n\t\t\t\tApiConstructSignature.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson);\n\t\t\t\treturn new ApiConstructSignature(options as IApiConstructSignatureOptions);\n\t\t\tcase ApiItemKind.EntryPoint:\n\t\t\t\tApiEntryPoint.onDeserializeInto(options, context, jsonObject);\n\t\t\t\treturn new ApiEntryPoint(options as IApiEntryPointOptions);\n\t\t\tcase ApiItemKind.Enum:\n\t\t\t\tApiEnum.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson);\n\t\t\t\treturn new ApiEnum(options as IApiEnumOptions);\n\t\t\tcase ApiItemKind.EnumMember:\n\t\t\t\tApiEnumMember.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson);\n\t\t\t\treturn new ApiEnumMember(options as IApiEnumMemberOptions);\n\t\t\tcase ApiItemKind.Event:\n\t\t\t\tApiEvent.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson);\n\t\t\t\treturn new ApiEvent(options as IApiEventOptions);\n\t\t\tcase ApiItemKind.Function:\n\t\t\t\tApiFunction.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson);\n\t\t\t\treturn new ApiFunction(options as IApiFunctionOptions);\n\t\t\tcase ApiItemKind.IndexSignature:\n\t\t\t\tApiIndexSignature.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson);\n\t\t\t\treturn new ApiIndexSignature(options as IApiIndexSignatureOptions);\n\t\t\tcase ApiItemKind.Interface:\n\t\t\t\tApiInterface.onDeserializeInto(options, context, jsonObject as IApiInterfaceJson);\n\t\t\t\treturn new ApiInterface(options as IApiInterfaceOptions);\n\t\t\tcase ApiItemKind.Method:\n\t\t\t\tApiMethod.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson);\n\t\t\t\treturn new ApiMethod(options as IApiMethodOptions);\n\t\t\tcase ApiItemKind.MethodSignature:\n\t\t\t\tApiMethodSignature.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson);\n\t\t\t\treturn new ApiMethodSignature(options as IApiMethodSignatureOptions);\n\t\t\tcase ApiItemKind.Model:\n\t\t\t\treturn new ApiModel();\n\t\t\tcase ApiItemKind.Namespace:\n\t\t\t\tApiNamespace.onDeserializeInto(options, context, jsonObject as IApiDeclaredItemJson);\n\t\t\t\treturn new ApiNamespace(options as IApiNamespaceOptions);\n\t\t\tcase ApiItemKind.Package:\n\t\t\t\tApiPackage.onDeserializeInto(options, context, jsonObject as IApiPackageJson);\n\t\t\t\treturn new ApiPackage(options as IApiPackageOptions);\n\t\t\tcase ApiItemKind.Property:\n\t\t\t\tApiProperty.onDeserializeInto(options, context, jsonObject as IApiPropertyItemJson);\n\t\t\t\treturn new ApiProperty(options as IApiPropertyOptions);\n\t\t\tcase ApiItemKind.PropertySignature:\n\t\t\t\tApiPropertySignature.onDeserializeInto(options, context, jsonObject as IApiPropertyItemJson);\n\t\t\t\treturn new ApiPropertySignature(options as IApiPropertySignatureOptions);\n\t\t\tcase ApiItemKind.TypeAlias:\n\t\t\t\tApiTypeAlias.onDeserializeInto(options, context, jsonObject as IApiTypeAliasJson);\n\t\t\t\treturn new ApiTypeAlias(options as IApiTypeAliasOptions);\n\t\t\tcase ApiItemKind.Variable:\n\t\t\t\tApiVariable.onDeserializeInto(options, context, jsonObject as IApiVariableJson);\n\t\t\t\treturn new ApiVariable(options as IApiVariableOptions);\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Failed to deserialize unsupported API item type ${JSON.stringify(jsonObject.kind)}`);\n\t\t}\n\t}\n\n\tpublic static deserializeDocgen(jsonObject: DocgenJson, _package: string) {\n\t\tconst context: DeserializerContext = {\n\t\t\tapiJsonFilename: 'docs.json',\n\t\t\ttsdocConfiguration: new TSDocConfiguration(),\n\t\t\tversionToDeserialize: ApiJsonSchemaVersion.V_1011,\n\t\t\ttoolPackage: jsonObject.meta.generator,\n\t\t\ttoolVersion: jsonObject.meta.format.toString(),\n\t\t};\n\n\t\tlet members: (IApiClassJson | IApiInterfaceJson | IApiMethodJson | IApiTypeAliasJson)[] = [];\n\n\t\tfor (const _class of jsonObject.classes) {\n\t\t\tconst classMembers: (IApiConstructorJson | IApiMethodJson | IApiPropertyItemJson)[] = [\n\t\t\t\t// ..._class.events.map((event) => mapEvent(event, _package, _class)),\n\t\t\t\t...(_class.props?.map((prop) => mapProp(prop, _package, _class)) ?? []),\n\t\t\t\t...(_class.methods?.map((method) => mapMethod(method, _package, _class)) ?? []),\n\t\t\t];\n\t\t\tif (_class.construct) {\n\t\t\t\tconst excerptTokens: IExcerptToken[] = [\n\t\t\t\t\t{\n\t\t\t\t\t\tkind: ExcerptTokenKind.Content,\n\t\t\t\t\t\ttext: `${_class.construct.access} constructor(${\n\t\t\t\t\t\t\t_class.construct.params?.length ? `${_class.construct.params[0]?.name}: ` : ');'\n\t\t\t\t\t\t}`,\n\t\t\t\t\t},\n\t\t\t\t];\n\n\t\t\t\tconst paramTokens: number[] = [];\n\t\t\t\tfor (let index = 0; index < (_class.construct.params?.length ?? 0) - 1; index++) {\n\t\t\t\t\tconst newTokens = mapVarType(_class.construct.params![index]!.type, _package);\n\t\t\t\t\tparamTokens.push(newTokens.length);\n\t\t\t\t\texcerptTokens.push(...newTokens);\n\t\t\t\t\texcerptTokens.push({\n\t\t\t\t\t\tkind: ExcerptTokenKind.Content,\n\t\t\t\t\t\ttext: `, ${_class.construct.params![index + 1]?.name}: `,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (_class.construct.params?.length) {\n\t\t\t\t\tconst newTokens = mapVarType(_class.construct.params[_class.construct.params.length - 1]!.type, _package);\n\t\t\t\t\tparamTokens.push(newTokens.length);\n\t\t\t\t\texcerptTokens.push(...newTokens);\n\t\t\t\t\texcerptTokens.push({ kind: ExcerptTokenKind.Content, text: ');' });\n\t\t\t\t}\n\n\t\t\t\tclassMembers.unshift({\n\t\t\t\t\tparameters:\n\t\t\t\t\t\t_class.construct.params?.map((param, index) => mapParam(param, index, _package, paramTokens)) ?? [],\n\t\t\t\t\tisProtected: _class.construct.access === 'protected',\n\t\t\t\t\treleaseTag: _class.construct.access === 'public' ? 'Public' : 'Internal',\n\t\t\t\t\tdocComment: `/*+\\n * ${_class.construct.description}\\n${\n\t\t\t\t\t\t_class.construct.params?.map((param) => ` * @param ${param.name} - ${param.description}\\n`).join('') ?? ''\n\t\t\t\t\t} */`,\n\t\t\t\t\texcerptTokens,\n\t\t\t\t\tkind: ApiItemKind.Constructor,\n\t\t\t\t\tcanonicalReference: `${_package}!${_class.name}:constructor`,\n\t\t\t\t\toverloadIndex: 0,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst excerptTokens: IExcerptToken[] = [\n\t\t\t\t{\n\t\t\t\t\tkind: ExcerptTokenKind.Content,\n\t\t\t\t\ttext: `${_class.access === 'public' ? 'export ' : ''}declare class ${_class.name}${\n\t\t\t\t\t\t_class.extends ? ' extends ' : _class.implements ? ' implements ' : ''\n\t\t\t\t\t}`,\n\t\t\t\t},\n\t\t\t];\n\n\t\t\tif (_class.extends)\n\t\t\t\texcerptTokens.push({\n\t\t\t\t\tkind: ExcerptTokenKind.Reference,\n\t\t\t\t\ttext: formatVarType(_class.extends) ?? '',\n\t\t\t\t\tcanonicalReference: `${_package}!${getFirstType(_class.extends) ?? ''}:class`,\n\t\t\t\t});\n\n\t\t\tif (_class.extends && _class.implements)\n\t\t\t\texcerptTokens.push({ kind: ExcerptTokenKind.Content, text: ' implements ' });\n\n\t\t\tif (_class.implements)\n\t\t\t\texcerptTokens.push({\n\t\t\t\t\tkind: ExcerptTokenKind.Reference,\n\t\t\t\t\ttext: formatVarType(_class.implements) ?? '',\n\t\t\t\t\tcanonicalReference: `${_package}!${getFirstType(_class.implements) ?? ''}:class`,\n\t\t\t\t});\n\n\t\t\tmembers.push({\n\t\t\t\tmembers: classMembers,\n\t\t\t\tkind: ApiItemKind.Class,\n\t\t\t\tcanonicalReference: `${_package}!${_class.name}:class`,\n\t\t\t\tname: _class.name,\n\t\t\t\textendsTokenRange: _class.extends ? { startIndex: 1, endIndex: 2, typeParameters: [] } : undefined,\n\t\t\t\texcerptTokens,\n\t\t\t\timplementsTokenRanges: _class.implements\n\t\t\t\t\t? [{ startIndex: _class.extends ? 3 : 1, endIndex: _class.extends ? 4 : 2, typeParameters: [] }]\n\t\t\t\t\t: [],\n\t\t\t\ttypeParameters: [],\n\t\t\t\treleaseTag: _class.access === 'public' ? 'Public' : 'Internal',\n\t\t\t\tdocComment: `/**\\n * ${_class.description}\\n${_class.see?.map((see) => ` * @see ${see}\\n`).join('') ?? ''} */`,\n\t\t\t\tisExported: _class.access === 'public',\n\t\t\t\tisAbstract: Boolean(_class.abstract),\n\t\t\t\tfileLine: _class.meta.line,\n\t\t\t\tfileUrlPath: `${_class.meta.path.slice(`packages/${_package}/`.length)}/${_class.meta.file}`,\n\t\t\t});\n\t\t}\n\n\t\tmembers = [\n\t\t\t...members,\n\t\t\t...jsonObject.functions.map((_func) => mapMethod(_func, _package)),\n\t\t\t...jsonObject.interfaces.map((_interface) => ({\n\t\t\t\tmembers: [\n\t\t\t\t\t...(_interface.props?.map((prop) => mapProp(prop, _package, _interface)) ?? []),\n\t\t\t\t\t...(_interface.methods?.map((method) => mapMethod(method, _package, _interface)) ?? []),\n\t\t\t\t],\n\t\t\t\tkind: ApiItemKind.Interface,\n\t\t\t\tcanonicalReference: `${_package}!${_interface.name}:interface`,\n\t\t\t\tname: _interface.name,\n\t\t\t\textendsTokenRanges: [{ startIndex: 0, endIndex: 0, typeParameters: [] }],\n\t\t\t\texcerptTokens: [\n\t\t\t\t\t{\n\t\t\t\t\t\tkind: ExcerptTokenKind.Content,\n\t\t\t\t\t\ttext: `${_interface.access === 'public' ? 'export ' : ''}interface ${_interface.name}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\ttypeParameters: [],\n\t\t\t\treleaseTag: _interface.access === 'public' ? 'Public' : 'Internal',\n\t\t\t\tdocComment: `/**\\n * ${_interface.description}\\n${\n\t\t\t\t\t_interface.see?.map((see) => ` * @see ${see}\\n`).join('') ?? ''\n\t\t\t\t} */`,\n\t\t\t\tisExported: _interface.access === 'public',\n\t\t\t\tfileLine: _interface.meta.line,\n\t\t\t\tfileUrlPath: `${_interface.meta.path.slice(`packages/${_package}/`.length)}/${_interface.meta.file}`,\n\t\t\t})),\n\t\t];\n\n\t\tconst reworkedJson: IApiDocumentedItemJson &\n\t\t\tIApiItemContainerJson &\n\t\t\tIApiNameMixinJson &\n\t\t\tIApiPackageJson & { members: (IApiItemContainerJson & IApiNameMixinJson)[] } = {\n\t\t\tprojectFolderUrl: `https://github.com/discordjs/discord.js/tree/main/packages/${_package}`,\n\t\t\tmetadata: { ...context, tsdocConfig: context.tsdocConfiguration, schemaVersion: context.versionToDeserialize },\n\t\t\tcanonicalReference: `!${_package}`,\n\t\t\tkind: ApiItemKind.Package,\n\t\t\tname: _package,\n\t\t\tmembers: [\n\t\t\t\t{\n\t\t\t\t\tmembers,\n\t\t\t\t\tname: _package,\n\t\t\t\t\tkind: ApiItemKind.EntryPoint,\n\t\t\t\t\tcanonicalReference: `${_package}!`,\n\t\t\t\t},\n\t\t\t],\n\t\t\tdocComment: '',\n\t\t};\n\n\t\treturn Deserializer.deserialize(context, reworkedJson);\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/DeserializerContext.ts",
    "content": "/* eslint-disable @typescript-eslint/prefer-literal-enum-member */\n// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { TSDocConfiguration } from '@microsoft/tsdoc';\n\nexport enum ApiJsonSchemaVersion {\n\t/**\n\t * The initial release.\n\t */\n\tV_1000 = 1_000,\n\n\t/**\n\t * Add support for type parameters and type alias types.\n\t */\n\tV_1001 = 1_001,\n\n\t/**\n\t * Remove `canonicalReference` field.  This field was for diagnostic purposes only and was never deserialized.\n\t */\n\tV_1002 = 1_002,\n\n\t/**\n\t * Reintroduce the `canonicalReference` field using the experimental new TSDoc declaration reference notation.\n\t *\n\t * This is not a breaking change because this field is never deserialized; it is provided for informational\n\t * purposes only.\n\t */\n\tV_1003 = 1_003,\n\n\t/**\n\t * Add a `tsdocConfig` field that tracks the TSDoc configuration for parsing doc comments.\n\t *\n\t * This is not a breaking change because an older implementation will still work correctly.  The\n\t * custom tags will be skipped over by the parser.\n\t */\n\tV_1004 = 1_004,\n\n\t/**\n\t * Add an `isOptional` field to `Parameter` and `TypeParameter` to track whether a function parameter is optional.\n\t *\n\t * When loading older JSON files, the value defaults to `false`.\n\t */\n\tV_1005 = 1_005,\n\n\t/**\n\t * Add an `isProtected` field to `ApiConstructor`, `ApiMethod`, and `ApiProperty` to\n\t * track whether a class member has the `protected` modifier.\n\t *\n\t * Add an `isReadonly` field to `ApiProperty`, `ApiPropertySignature`, and `ApiVariable` to\n\t * track whether the item is readonly.\n\t *\n\t * When loading older JSON files, the values default to `false`.\n\t */\n\tV_1006 = 1_006,\n\n\t/**\n\t * Add `ApiItemContainerMixin.preserveMemberOrder` to support enums that preserve their original sort order.\n\t *\n\t * When loading older JSON files, the value default to `false`.\n\t */\n\tV_1007 = 1_007,\n\n\t/**\n\t * Add an `initializerTokenRange` field to `ApiProperty` and `ApiVariable` to track the item's\n\t * initializer.\n\t *\n\t * When loading older JSON files, this range is empty.\n\t */\n\tV_1008 = 1_008,\n\n\t/**\n\t * Add an `isReadonly` field to `ApiIndexSignature` to track whether the item is readonly.\n\t *\n\t * When loading older JSON files, the values defaults to `false`.\n\t */\n\tV_1009 = 1_009,\n\n\t/**\n\t * Add a `fileUrlPath` field to `ApiDeclaredItem` to track the URL to a declared item's source file.\n\t *\n\t * When loading older JSON files, the value defaults to `undefined`.\n\t */\n\tV_1010 = 1_010,\n\n\t/**\n\t * Add an `isAbstract` field to `ApiClass`, `ApiMethod`, and `ApiProperty` to\n\t * track whether the item is abstract.\n\t *\n\t * When loading older JSON files, the value defaults to `false`.\n\t */\n\tV_1011 = 1_011,\n\n\t/**\n\t * Add a `fileLine`and `fileColumn` field to track source code location\n\t */\n\tV_1012 = 1_012,\n\n\t/**\n\t * Make tsdocConfiguration optional\n\t */\n\tV_1013 = 1_013,\n\n\t/**\n\t * The current latest .api.json schema version.\n\t *\n\t * IMPORTANT: When incrementing this number, consider whether `OLDEST_SUPPORTED` or `OLDEST_FORWARDS_COMPATIBLE`\n\t * should be updated.\n\t */\n\tLATEST = V_1013,\n\n\t/**\n\t * The oldest .api.json schema version that is still supported for backwards compatibility.\n\t *\n\t * This must be updated if you change to the file format and do not implement compatibility logic for\n\t * deserializing the older representation.\n\t */\n\tOLDEST_SUPPORTED = V_1001,\n\n\t/**\n\t * Used to assign `IApiPackageMetadataJson.oldestForwardsCompatibleVersion`.\n\t *\n\t * This value must be \\<= `ApiJsonSchemaVersion.LATEST`.  It must be reset to the `LATEST` value\n\t * if the older library would not be able to deserialize your new file format.  Adding a nonessential field\n\t * is generally okay.  Removing, modifying, or reinterpreting existing fields is NOT safe.\n\t */\n\tOLDEST_FORWARDS_COMPATIBLE = V_1013,\n}\n\nexport class DeserializerContext {\n\t/**\n\t * The path of the file being deserialized, which may be useful for diagnostic purposes.\n\t */\n\tpublic readonly apiJsonFilename: string;\n\n\t/**\n\t * Metadata from `IApiPackageMetadataJson.toolPackage`.\n\t */\n\tpublic readonly toolPackage: string;\n\n\t/**\n\t * Metadata from `IApiPackageMetadataJson.toolVersion`.\n\t */\n\tpublic readonly toolVersion: string;\n\n\t/**\n\t * The version of the schema being deserialized, as obtained from `IApiPackageMetadataJson.schemaVersion`.\n\t */\n\tpublic readonly versionToDeserialize: ApiJsonSchemaVersion;\n\n\t/**\n\t * The TSDoc configuration for the context.\n\t */\n\tpublic readonly tsdocConfiguration: TSDocConfiguration;\n\n\tpublic constructor(options: DeserializerContext) {\n\t\tthis.apiJsonFilename = options.apiJsonFilename;\n\t\tthis.toolPackage = options.toolPackage;\n\t\tthis.toolVersion = options.toolVersion;\n\t\tthis.versionToDeserialize = options.versionToDeserialize;\n\t\tthis.tsdocConfiguration = options.tsdocConfiguration;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/HeritageType.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { Excerpt, IExcerptTokenRange } from '../mixins/Excerpt.js';\n\n/**\n * Represents a type referenced via an \"extends\" or \"implements\" heritage clause for a TypeScript class\n * or interface.\n *\n * @remarks\n *\n * For example, consider this declaration:\n *\n * ```ts\n * export class Widget extends Controls.WidgetBase implements Controls.IWidget, IDisposable {\n *   // . . .\n * }\n * ```\n *\n * The heritage types are `Controls.WidgetBase`, `Controls.IWidget`, and `IDisposable`.\n * @public\n */\nexport class HeritageType {\n\t/**\n\t * An excerpt corresponding to the referenced type.\n\t *\n\t * @remarks\n\t *\n\t * For example, consider this declaration:\n\t *\n\t * ```ts\n\t * export class Widget extends Controls.WidgetBase implements Controls.IWidget, IDisposable {\n\t *   // . . .\n\t * }\n\t * ```\n\t *\n\t * The excerpt might be `Controls.WidgetBase`, `Controls.IWidget`, or `IDisposable`.\n\t */\n\tpublic readonly excerpt: Excerpt;\n\n\tpublic readonly typeParameters?: IExcerptTokenRange[];\n\n\tpublic constructor(excerpt: Excerpt, typeParameters: IExcerptTokenRange[]) {\n\t\tthis.excerpt = excerpt;\n\t\tthis.typeParameters = typeParameters;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/ModelReferenceResolver.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { type DocDeclarationReference, type DocMemberSelector, SelectorKind } from '@microsoft/tsdoc';\nimport { type ApiItem, ApiItemKind } from '../items/ApiItem.js';\nimport { ApiItemContainerMixin } from '../mixins/ApiItemContainerMixin.js';\nimport { ApiParameterListMixin } from '../mixins/ApiParameterListMixin.js';\nimport type { ApiEntryPoint } from './ApiEntryPoint.js';\nimport type { ApiMethod } from './ApiMethod.js';\nimport type { ApiModel } from './ApiModel.js';\nimport type { ApiPackage } from './ApiPackage.js';\n\n/**\n * Result object for {@link ApiModel.resolveDeclarationReference}.\n *\n * @public\n */\nexport interface IResolveDeclarationReferenceResult {\n\t/**\n\t * If resolvedApiItem is undefined, then this will always contain an error message explaining why the\n\t * resolution failed.\n\t */\n\terrorMessage: string | undefined;\n\n\t/**\n\t * The referenced ApiItem, if the declaration reference could be resolved.\n\t */\n\tresolvedApiItem: ApiItem | undefined;\n}\n\n/**\n * This resolves a TSDoc declaration reference by walking the `ApiModel` hierarchy.\n *\n * @remarks\n *\n * This class is analogous to `AstReferenceResolver` from the `@microsoft/api-extractor` project,\n * which resolves declaration references by walking the compiler state.\n */\nexport class ModelReferenceResolver {\n\tprivate readonly _apiModel: ApiModel;\n\n\tpublic constructor(apiModel: ApiModel) {\n\t\tthis._apiModel = apiModel;\n\t}\n\n\tpublic resolve(\n\t\tdeclarationReference: DocDeclarationReference,\n\t\tcontextApiItem: ApiItem | undefined,\n\t): IResolveDeclarationReferenceResult {\n\t\tconst result: IResolveDeclarationReferenceResult = {\n\t\t\tresolvedApiItem: undefined,\n\t\t\terrorMessage: undefined,\n\t\t};\n\n\t\tlet apiPackage: ApiPackage | undefined;\n\n\t\t// Is this an absolute reference?\n\t\tif (declarationReference.packageName === undefined) {\n\t\t\t// If the package name is omitted, try to infer it from the context\n\t\t\tif (contextApiItem !== undefined) {\n\t\t\t\tapiPackage = contextApiItem.getAssociatedPackage();\n\t\t\t}\n\n\t\t\tif (apiPackage === undefined) {\n\t\t\t\tresult.errorMessage = `The reference does not include a package name, and the package could not be inferred from the context`;\n\t\t\t\treturn result;\n\t\t\t}\n\t\t} else {\n\t\t\tapiPackage = this._apiModel.tryGetPackageByName(declarationReference.packageName);\n\t\t\tif (apiPackage === undefined) {\n\t\t\t\tresult.errorMessage = `The package \"${declarationReference.packageName}\" could not be located`;\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\n\t\t// Remove the leading / in the import path\n\t\tconst importPath: string = (declarationReference.importPath || '').replace(/^\\//, '');\n\n\t\tconst foundEntryPoints: readonly ApiEntryPoint[] = apiPackage.findEntryPointsByPath(importPath);\n\t\tif (foundEntryPoints.length < 1) {\n\t\t\tresult.errorMessage = `The import path \"${importPath}\" could not be resolved`;\n\t\t\treturn result;\n\t\t}\n\n\t\tlet currentItem: ApiItem = foundEntryPoints[0]!;\n\n\t\t// Now search for the member reference\n\t\tfor (const memberReference of declarationReference.memberReferences) {\n\t\t\tif (memberReference.memberSymbol !== undefined) {\n\t\t\t\tresult.errorMessage = `Symbols are not yet supported in declaration references`;\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tif (memberReference.memberIdentifier === undefined) {\n\t\t\t\tresult.errorMessage = `Missing member identifier`;\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst identifier: string = memberReference.memberIdentifier.identifier;\n\n\t\t\tif (!ApiItemContainerMixin.isBaseClassOf(currentItem)) {\n\t\t\t\t// For example, {@link MyClass.myMethod.X} is invalid because methods cannot contain members\n\t\t\t\tresult.errorMessage = `Unable to resolve ${JSON.stringify(\n\t\t\t\t\tidentifier,\n\t\t\t\t)} because ${currentItem.getScopedNameWithinPackage()} cannot act as a container`;\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst foundMembers: readonly ApiItem[] = currentItem.findMembersByName(identifier);\n\t\t\tif (foundMembers.length === 0) {\n\t\t\t\tresult.errorMessage = `The member reference ${JSON.stringify(identifier)} was not found`;\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst memberSelector: DocMemberSelector | undefined = memberReference.selector;\n\t\t\tif (memberSelector === undefined) {\n\t\t\t\tif (foundMembers.length > 1) {\n\t\t\t\t\tconst foundClass: ApiItem | undefined = foundMembers.find((member) => member.kind === ApiItemKind.Class);\n\t\t\t\t\tconst foundEvent: ApiItem | undefined = foundMembers.find((member) => member.kind === ApiItemKind.Event);\n\t\t\t\t\tif (\n\t\t\t\t\t\tfoundClass &&\n\t\t\t\t\t\tfoundMembers.filter((member) => member.kind === ApiItemKind.Interface).length === foundMembers.length - 1\n\t\t\t\t\t) {\n\t\t\t\t\t\tcurrentItem = foundClass;\n\t\t\t\t\t} else if (\n\t\t\t\t\t\tfoundMembers.every((member) => member.kind === ApiItemKind.Method && (member as ApiMethod).overloadIndex)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcurrentItem = foundMembers.find((member) => (member as ApiMethod).overloadIndex === 1)!;\n\t\t\t\t\t} else if (\n\t\t\t\t\t\tfoundEvent &&\n\t\t\t\t\t\tfoundMembers.filter((member) => member.kind === ApiItemKind.Method).length === foundMembers.length - 1\n\t\t\t\t\t) {\n\t\t\t\t\t\tcurrentItem = foundEvent;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult.errorMessage = `The member reference ${JSON.stringify(identifier)} was ambiguous`;\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tcurrentItem = foundMembers[0]!;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlet memberSelectorResult: IResolveDeclarationReferenceResult;\n\t\t\t\tswitch (memberSelector.selectorKind) {\n\t\t\t\t\tcase SelectorKind.System:\n\t\t\t\t\t\tmemberSelectorResult = this._selectUsingSystemSelector(foundMembers, memberSelector, identifier);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase SelectorKind.Index:\n\t\t\t\t\t\tmemberSelectorResult = this._selectUsingIndexSelector(foundMembers, memberSelector, identifier);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tresult.errorMessage = `The selector \"${memberSelector.selector}\" is not a supported selector type`;\n\t\t\t\t\t\treturn result;\n\t\t\t\t}\n\n\t\t\t\tif (memberSelectorResult.resolvedApiItem === undefined) {\n\t\t\t\t\treturn memberSelectorResult;\n\t\t\t\t}\n\n\t\t\t\tcurrentItem = memberSelectorResult.resolvedApiItem;\n\t\t\t}\n\t\t}\n\n\t\tresult.resolvedApiItem = currentItem;\n\t\treturn result;\n\t}\n\n\tprivate _selectUsingSystemSelector(\n\t\tfoundMembers: readonly ApiItem[],\n\t\tmemberSelector: DocMemberSelector,\n\t\tidentifier: string,\n\t): IResolveDeclarationReferenceResult {\n\t\tconst result: IResolveDeclarationReferenceResult = {\n\t\t\tresolvedApiItem: undefined,\n\t\t\terrorMessage: undefined,\n\t\t};\n\n\t\tconst selectorName: string = memberSelector.selector;\n\n\t\tlet selectorItemKind: ApiItemKind;\n\t\tswitch (selectorName) {\n\t\t\tcase 'class':\n\t\t\t\tselectorItemKind = ApiItemKind.Class;\n\t\t\t\tbreak;\n\t\t\tcase 'enum':\n\t\t\t\tselectorItemKind = ApiItemKind.Enum;\n\t\t\t\tbreak;\n\t\t\tcase 'function':\n\t\t\t\tselectorItemKind = ApiItemKind.Function;\n\t\t\t\tbreak;\n\t\t\tcase 'interface':\n\t\t\t\tselectorItemKind = ApiItemKind.Interface;\n\t\t\t\tbreak;\n\t\t\tcase 'namespace':\n\t\t\t\tselectorItemKind = ApiItemKind.Namespace;\n\t\t\t\tbreak;\n\t\t\tcase 'type':\n\t\t\t\tselectorItemKind = ApiItemKind.TypeAlias;\n\t\t\t\tbreak;\n\t\t\tcase 'variable':\n\t\t\t\tselectorItemKind = ApiItemKind.Variable;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tresult.errorMessage = `Unsupported system selector \"${selectorName}\"`;\n\t\t\t\treturn result;\n\t\t}\n\n\t\tconst matches: ApiItem[] = foundMembers.filter((x) => x.kind === selectorItemKind);\n\t\tif (matches.length === 0) {\n\t\t\tresult.errorMessage = `A declaration for \"${identifier}\" was not found that matches the TSDoc selector \"${selectorName}\"`;\n\t\t\treturn result;\n\t\t}\n\n\t\tif (matches.length > 1) {\n\t\t\tresult.errorMessage = `More than one declaration \"${identifier}\" matches the TSDoc selector \"${selectorName}\"`;\n\t\t}\n\n\t\tresult.resolvedApiItem = matches[0];\n\t\treturn result;\n\t}\n\n\tprivate _selectUsingIndexSelector(\n\t\tfoundMembers: readonly ApiItem[],\n\t\tmemberSelector: DocMemberSelector,\n\t\tidentifier: string,\n\t): IResolveDeclarationReferenceResult {\n\t\tconst result: IResolveDeclarationReferenceResult = {\n\t\t\tresolvedApiItem: undefined,\n\t\t\terrorMessage: undefined,\n\t\t};\n\n\t\tconst selectedMembers: ApiItem[] = [];\n\n\t\tconst selectorOverloadIndex: number = Number.parseInt(memberSelector.selector, 10);\n\t\tfor (const foundMember of foundMembers) {\n\t\t\tif (ApiParameterListMixin.isBaseClassOf(foundMember) && foundMember.overloadIndex === selectorOverloadIndex) {\n\t\t\t\tselectedMembers.push(foundMember);\n\t\t\t}\n\t\t}\n\n\t\tif (selectedMembers.length === 0) {\n\t\t\tresult.errorMessage =\n\t\t\t\t`An overload for ${JSON.stringify(identifier)} was not found that matches` +\n\t\t\t\t` the TSDoc selector \":${selectorOverloadIndex}\"`;\n\t\t\treturn result;\n\t\t}\n\n\t\tif (selectedMembers.length === 1) {\n\t\t\tresult.resolvedApiItem = selectedMembers[0];\n\t\t\treturn result;\n\t\t}\n\n\t\tresult.errorMessage = `The member reference ${JSON.stringify(identifier)} was ambiguous`;\n\t\treturn result;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/Parameter.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type * as tsdoc from '@microsoft/tsdoc';\nimport { ApiDocumentedItem } from '../items/ApiDocumentedItem.js';\nimport type { ApiParameterListMixin } from '../mixins/ApiParameterListMixin.js';\nimport type { Excerpt } from '../mixins/Excerpt.js';\n\n/**\n * Constructor options for {@link Parameter}.\n *\n * @public\n */\nexport interface IParameterOptions {\n\tdefaultValue: string | undefined;\n\tisOptional: boolean;\n\tisRest: boolean;\n\tname: string;\n\tparameterTypeExcerpt: Excerpt;\n\tparent: ApiParameterListMixin;\n}\n\n/**\n * Represents a named parameter for a function-like declaration.\n *\n * @remarks\n *\n * `Parameter` represents a TypeScript declaration such as `x: number` in this example:\n *\n * ```ts\n * export function add(x: number, y: number): number {\n *   return x + y;\n * }\n * ```\n *\n * `Parameter` objects belong to the {@link (ApiParameterListMixin:interface).parameters} collection.\n * @public\n */\nexport class Parameter {\n\t/**\n\t * An {@link Excerpt} that describes the type of the parameter.\n\t */\n\tpublic readonly parameterTypeExcerpt: Excerpt;\n\n\t/**\n\t * The parameter name.\n\t */\n\tpublic name: string;\n\n\t/**\n\t * Whether the parameter is optional.\n\t */\n\tpublic isOptional: boolean;\n\n\t/**\n\t * Whether the parameter is a rest parameter\n\t */\n\tpublic isRest: boolean;\n\n\t/**\n\t * The default value for this parameter if optional\n\t */\n\tpublic defaultValue: string | undefined;\n\n\tprivate readonly _parent: ApiParameterListMixin;\n\n\tpublic constructor(options: IParameterOptions) {\n\t\tthis.name = options.name;\n\t\tthis.parameterTypeExcerpt = options.parameterTypeExcerpt;\n\t\tthis.isOptional = options.isOptional;\n\t\tthis.isRest = options.isRest;\n\t\tthis._parent = options.parent;\n\t\tthis.defaultValue = options.defaultValue;\n\t}\n\n\t/**\n\t * Returns the `@param` documentation for this parameter, if present.\n\t */\n\tpublic get tsdocParamBlock(): tsdoc.DocParamBlock | undefined {\n\t\tif (this._parent instanceof ApiDocumentedItem && this._parent.tsdocComment) {\n\t\t\treturn this._parent.tsdocComment.params.tryGetBlockByName(this.name);\n\t\t}\n\n\t\treturn undefined;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/SourceLocation.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * Constructor options for `SourceLocation`.\n *\n * @public\n */\nexport interface ISourceLocationOptions {\n\t/**\n\t * The file URL path relative to the `projectFolder` and `projectFolderURL` fields as\n\t * defined in the `api-extractor.json` config.\n\t */\n\tfileUrlPath?: string | undefined;\n\n\t/**\n\t * The project folder URL as defined by the `api-extractor.json` config `projectFolderUrl`\n\t * setting.\n\t */\n\tprojectFolderUrl?: string | undefined;\n\n\t/**\n\t * The column number in the source file. The first column number is 1.\n\t */\n\tsourceFileColumn?: number | undefined;\n\n\t/**\n\t * The line number in the source file. The first line number is 1.\n\t */\n\tsourceFileLine?: number | undefined;\n}\n\n/**\n * The source location where a given API item is declared.\n *\n * @remarks\n * The source location points to the `.ts` source file where the API item was originally\n * declared. However, in some cases, if source map resolution fails, it falls back to pointing\n * to the `.d.ts` file instead.\n * @public\n */\nexport class SourceLocation {\n\tprivate readonly _projectFolderUrl?: string | undefined;\n\n\tprivate readonly _fileUrlPath?: string | undefined;\n\n\tprivate readonly _fileLine?: number | undefined;\n\n\tprivate readonly _fileColumn?: number | undefined;\n\n\tpublic constructor(options: ISourceLocationOptions) {\n\t\tthis._projectFolderUrl = options.projectFolderUrl;\n\t\tthis._fileUrlPath = options.fileUrlPath;\n\t\tthis._fileLine = options.sourceFileLine;\n\t\tthis._fileColumn = options.sourceFileColumn;\n\t}\n\n\t/**\n\t * Returns the file URL to the given source location. Returns `undefined` if the file URL\n\t * cannot be determined.\n\t */\n\tpublic get fileUrl(): string | undefined {\n\t\tif (this._projectFolderUrl === undefined || this._fileUrlPath === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tlet projectFolderUrl: string = this._projectFolderUrl;\n\t\tif (!projectFolderUrl.endsWith('/')) {\n\t\t\tprojectFolderUrl += '/';\n\t\t}\n\n\t\tconst url: URL = new URL(this._fileUrlPath, projectFolderUrl);\n\t\treturn url.href;\n\t}\n\n\t/**\n\t * The line in the `fileUrlPath` where the API item is declared.\n\t */\n\tpublic get fileLine(): number | undefined {\n\t\treturn this._fileLine;\n\t}\n\n\t/**\n\t * The column in the `fileUrlPath` where the API item is declared.\n\t */\n\tpublic get fileColumn(): number | undefined {\n\t\treturn this._fileColumn;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/src/model/TypeParameter.ts",
    "content": "// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type * as tsdoc from '@microsoft/tsdoc';\nimport { ApiDocumentedItem } from '../items/ApiDocumentedItem.js';\nimport type { ApiTypeParameterListMixin } from '../mixins/ApiTypeParameterListMixin.js';\nimport type { Excerpt } from '../mixins/Excerpt.js';\n\n/**\n * Constructor options for {@link TypeParameter}.\n *\n * @public\n */\nexport interface ITypeParameterOptions {\n\tconstraintExcerpt: Excerpt;\n\tdefaultTypeExcerpt: Excerpt;\n\tisOptional: boolean;\n\tname: string;\n\tparent: ApiTypeParameterListMixin;\n}\n\n/**\n * Represents a named type parameter for a generic declaration.\n *\n * @remarks\n *\n * `TypeParameter` represents a TypeScript declaration such as `T` in this example:\n *\n * ```ts\n * interface IIdentifier {\n *     getCode(): string;\n * }\n *\n * class BarCode implements IIdentifier {\n *     private _value: number;\n *     public getCode(): string { return this._value.toString(); }\n * }\n *\n * class Book<TIdentifier extends IIdentifier = BarCode> {\n *     public identifier: TIdentifier;\n * }\n * ```\n *\n * `TypeParameter` objects belong to the {@link (ApiTypeParameterListMixin:interface).typeParameters} collection.\n * @public\n */\nexport class TypeParameter {\n\t/**\n\t * An {@link Excerpt} that describes the base constraint of the type parameter.\n\t *\n\t * @remarks\n\t * In the example below, the `constraintExcerpt` would correspond to the `IIdentifier` subexpression:\n\t *\n\t * ```ts\n\t * class Book<TIdentifier extends IIdentifier = BarCode> {\n\t *     public identifier: TIdentifier;\n\t * }\n\t * ```\n\t */\n\tpublic readonly constraintExcerpt: Excerpt;\n\n\t/**\n\t * An {@link Excerpt} that describes the default type of the type parameter.\n\t *\n\t * @remarks\n\t * In the example below, the `defaultTypeExcerpt` would correspond to the `BarCode` subexpression:\n\t *\n\t * ```ts\n\t * class Book<TIdentifier extends IIdentifier = BarCode> {\n\t *     public identifier: TIdentifier;\n\t * }\n\t * ```\n\t */\n\tpublic readonly defaultTypeExcerpt: Excerpt;\n\n\t/**\n\t * The parameter name.\n\t */\n\tpublic name: string;\n\n\t/**\n\t * Whether the type parameter is optional. True IFF there exists a `defaultTypeExcerpt`.\n\t */\n\tpublic isOptional: boolean;\n\n\tprivate readonly _parent: ApiTypeParameterListMixin;\n\n\tpublic constructor(options: ITypeParameterOptions) {\n\t\tthis.name = options.name;\n\t\tthis.constraintExcerpt = options.constraintExcerpt;\n\t\tthis.defaultTypeExcerpt = options.defaultTypeExcerpt;\n\t\tthis.isOptional = options.isOptional;\n\t\tthis._parent = options.parent;\n\t}\n\n\t/**\n\t * Returns the `@typeParam` documentation for this parameter, if present.\n\t */\n\tpublic get tsdocTypeParamBlock(): tsdoc.DocParamBlock | undefined {\n\t\tif (this._parent instanceof ApiDocumentedItem && this._parent.tsdocComment) {\n\t\t\treturn this._parent.tsdocComment.typeParams.tryGetBlockByName(this.name);\n\t\t}\n\n\t\treturn undefined;\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-model/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/api-extractor-model/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\"node\"],\n\t\t\"isolatedModules\": false\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/api-extractor-model/tsup.config.ts",
    "content": "import { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tminify: 'terser',\n});\n"
  },
  {
    "path": "packages/api-extractor-utils/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\n\n# Miscellaneous\n.turbo\n.tmp\n"
  },
  {
    "path": "packages/api-extractor-utils/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/api-extractor-utils/.prettierignore",
    "content": ".turbo\ncoverage\ndist\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/api-extractor-utils/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/api-extractor-utils/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2022 Noel Buechler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/api-extractor-utils/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested.  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/api-extractor-utils\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/api-extractor-utils/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/api-extractor-utils\",\n\t\"version\": \"1.0.0\",\n\t\"description\": \"Utilities for api-extractor\",\n\t\"private\": true,\n\t\"scripts\": {\n\t\t\"build\": \"tsc --noEmit && tsup\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src\",\n\t\t\"fmt\": \"pnpm run format\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"main\": \"./dist/index.js\",\n\t\"module\": \"./dist/index.mjs\",\n\t\"types\": \"./dist/index.d.ts\",\n\t\"directories\": {\n\t\t\"lib\": \"src\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Suneet Tipirneni <suneettipirneni@icloud.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/api-extractor-utils\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"@discordjs/api-extractor-model\": \"workspace:^\",\n\t\t\"@microsoft/tsdoc\": \"~0.15.1\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@types/node\": \"^24.10.13\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"terser\": \"^5.46.0\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/src/ApiNodeJSONEncoder.ts",
    "content": "import type {\n\tApiModel,\n\tApiPropertyItem,\n\tApiMethod,\n\tApiParameterListMixin,\n\tApiTypeParameterListMixin,\n\tApiClass,\n\tApiFunction,\n\tApiTypeAlias,\n\tApiEnum,\n\tApiInterface,\n\tApiMethodSignature,\n\tApiPropertySignature,\n\tApiVariable,\n\tApiItem,\n\tApiConstructor,\n\tApiItemContainerMixin,\n\tApiReturnTypeMixin,\n} from '@discordjs/api-extractor-model';\nimport { ApiDeclaredItem, ApiItemKind } from '@discordjs/api-extractor-model';\nimport { generateTypeParamData } from './TypeParameterJSONEncoder.js';\nimport { type TokenDocumentation, resolveName, genReference, genToken, genParameter, generatePath } from './parse.js';\nimport type { DocBlockJSON } from './tsdoc/CommentBlock.js';\nimport type { AnyDocNodeJSON } from './tsdoc/CommentNode.js';\nimport { type DocNodeContainerJSON, nodeContainer } from './tsdoc/CommentNodeContainer.js';\nimport { createCommentNode } from './tsdoc/index.js';\n\nexport interface ReferenceData {\n\tname: string;\n\tpath: string;\n}\n\nexport interface InheritanceData {\n\tparentKey: string;\n\tparentName: string;\n\tpath: string;\n}\n\nexport interface ApiInheritableJSON {\n\tinheritanceData: InheritanceData | null;\n}\n\nexport interface ApiItemJSON {\n\tcomment: AnyDocNodeJSON | null;\n\tcontainerKey: string;\n\tdeprecated: DocNodeContainerJSON | null;\n\texcerpt: string;\n\texcerptTokens: TokenDocumentation[];\n\tkind: string;\n\tname: string;\n\tpath: string[];\n\treferenceData: ReferenceData;\n\tremarks: DocNodeContainerJSON | null;\n\tsummary: DocNodeContainerJSON | null;\n}\n\nexport interface ApiPropertyItemJSON extends ApiItemJSON, ApiInheritableJSON {\n\toptional: boolean;\n\tpropertyTypeTokens: TokenDocumentation[];\n\treadonly: boolean;\n}\n\nexport interface ApiTypeParameterListJSON {\n\ttypeParameters: ApiTypeParameterJSON[];\n}\n\nexport interface ApiTypeParameterJSON {\n\tcommentBlock: DocBlockJSON | null;\n\tconstraintTokens: TokenDocumentation[];\n\tdefaultTokens: TokenDocumentation[];\n\tname: string;\n\toptional: boolean;\n}\n\nexport interface ApiParameterListJSON {\n\tparameters: ApiParameterJSON[];\n}\n\nexport interface ApiMethodSignatureJSON\n\textends ApiItemJSON, ApiTypeParameterListJSON, ApiParameterListJSON, ApiInheritableJSON {\n\tmergedSiblings: ApiMethodSignatureJSON[];\n\toptional: boolean;\n\toverloadIndex: number;\n\treturnTypeTokens: TokenDocumentation[];\n}\n\nexport interface ApiMethodJSON extends ApiMethodSignatureJSON {\n\tmergedSiblings: ApiMethodJSON[];\n\tprotected: boolean;\n\tstatic: boolean;\n}\n\nexport interface ApiParameterJSON {\n\tisOptional: boolean;\n\tname: string;\n\tparamCommentBlock: DocBlockJSON | null;\n\ttokens: TokenDocumentation[];\n}\n\nexport interface ApiClassJSON extends ApiItemJSON, ApiTypeParameterListJSON {\n\tconstructor: ApiConstructorJSON | null;\n\textendsTokens: TokenDocumentation[];\n\timplementsTokens: TokenDocumentation[][];\n\tmethods: ApiMethodJSON[];\n\tproperties: ApiPropertyItemJSON[];\n}\n\nexport interface ApiTypeAliasJSON extends ApiItemJSON, ApiTypeParameterListJSON {\n\ttypeTokens: TokenDocumentation[];\n}\n\nexport interface EnumMemberData {\n\tinitializerTokens: TokenDocumentation[];\n\tname: string;\n\tsummary: DocNodeContainerJSON | null;\n}\n\nexport interface ApiEnumJSON extends ApiItemJSON {\n\tmembers: EnumMemberData[];\n}\n\nexport interface ApiInterfaceJSON extends ApiItemJSON, ApiTypeParameterListJSON {\n\textendsTokens: TokenDocumentation[][] | null;\n\tmethods: ApiMethodSignatureJSON[];\n\tproperties: ApiPropertyItemJSON[];\n}\n\nexport interface ApiVariableJSON extends ApiItemJSON {\n\treadonly: boolean;\n\ttypeTokens: TokenDocumentation[];\n}\n\nexport interface ApiFunctionJSON extends ApiItemJSON, ApiTypeParameterListJSON, ApiParameterListJSON {\n\tmergedSiblings: ApiFunctionJSON[];\n\toverloadIndex: number;\n\treturnTypeTokens: TokenDocumentation[];\n}\n\nexport interface ApiConstructorJSON extends ApiItemJSON, ApiParameterListJSON {\n\tprotected: boolean;\n}\n\nexport type FunctionLike = ApiDeclaredItem & ApiParameterListMixin & ApiReturnTypeMixin & ApiTypeParameterListMixin;\n\nexport class ApiNodeJSONEncoder {\n\tpublic static encode(model: ApiModel, node: ApiItem, version: string) {\n\t\tif (!(node instanceof ApiDeclaredItem)) {\n\t\t\tconsole.log(`Cannot serialize node of type ${node.kind}`);\n\t\t\treturn undefined;\n\t\t}\n\n\t\tswitch (node.kind) {\n\t\t\tcase ApiItemKind.Class:\n\t\t\t\treturn this.encodeClass(model, node as ApiClass, version);\n\t\t\tcase ApiItemKind.Function:\n\t\t\t\treturn this.encodeFunction(model, node as ApiFunction, version);\n\t\t\tcase ApiItemKind.Interface:\n\t\t\t\treturn this.encodeInterface(model, node as ApiInterface, version);\n\t\t\tcase ApiItemKind.TypeAlias:\n\t\t\t\treturn this.encodeTypeAlias(model, node as ApiTypeAlias, version);\n\t\t\tcase ApiItemKind.Enum:\n\t\t\t\treturn this.encodeEnum(model, node as ApiEnum, version);\n\t\t\tcase ApiItemKind.Variable:\n\t\t\t\treturn this.encodeVariable(model, node as ApiVariable, version);\n\t\t\tdefault:\n\t\t\t\t// console.log(`Unknown API item kind: ${node.kind}`);\n\t\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tpublic static encodeItem(model: ApiModel, item: ApiDeclaredItem, version: string): ApiItemJSON {\n\t\tconst path = [];\n\t\tfor (const _item of item.getHierarchy()) {\n\t\t\tswitch (_item.kind) {\n\t\t\t\tcase 'None':\n\t\t\t\tcase 'EntryPoint':\n\t\t\t\tcase 'Model':\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tpath.push(resolveName(_item));\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tkind: item.kind,\n\t\t\tname: resolveName(item),\n\t\t\treferenceData: genReference(item, version),\n\t\t\texcerpt: item.excerpt.text,\n\t\t\texcerptTokens: item.excerpt.spannedTokens.map((token) => genToken(model, token, version)),\n\t\t\tremarks: item.tsdocComment?.remarksBlock\n\t\t\t\t? (createCommentNode(item.tsdocComment.remarksBlock, model, version, item.parent) as DocNodeContainerJSON)\n\t\t\t\t: null,\n\t\t\tsummary: item.tsdocComment?.summarySection\n\t\t\t\t? (createCommentNode(item.tsdocComment.summarySection, model, version, item.parent) as DocNodeContainerJSON)\n\t\t\t\t: null,\n\t\t\tdeprecated: item.tsdocComment?.deprecatedBlock\n\t\t\t\t? (createCommentNode(item.tsdocComment.deprecatedBlock, model, version, item.parent) as DocNodeContainerJSON)\n\t\t\t\t: null,\n\t\t\tpath,\n\t\t\tcontainerKey: item.containerKey,\n\t\t\tcomment: item.tsdocComment ? createCommentNode(item.tsdocComment, model, version, item.parent) : null,\n\t\t};\n\t}\n\n\tpublic static encodeParameterList(\n\t\tmodel: ApiModel,\n\t\titem: ApiDeclaredItem & ApiParameterListMixin,\n\t\tversion: string,\n\t): { parameters: ApiParameterJSON[] } {\n\t\treturn {\n\t\t\tparameters: item.parameters.map((param) => genParameter(model, param, version)),\n\t\t};\n\t}\n\n\tpublic static encodeTypeParameterList(\n\t\tmodel: ApiModel,\n\t\titem: ApiDeclaredItem & ApiTypeParameterListMixin,\n\t\tversion: string,\n\t): ApiTypeParameterListJSON {\n\t\treturn {\n\t\t\ttypeParameters: item.typeParameters.map((param) => generateTypeParamData(model, param, version, item.parent)),\n\t\t};\n\t}\n\n\tpublic static encodeProperty(\n\t\tmodel: ApiModel,\n\t\titem: ApiPropertyItem,\n\t\tparent: ApiItemContainerMixin,\n\t\tversion: string,\n\t): ApiPropertyItemJSON {\n\t\treturn {\n\t\t\t...this.encodeItem(model, item, version),\n\t\t\t...this.encodeInheritanceData(item, parent, version),\n\t\t\tpropertyTypeTokens: item.propertyTypeExcerpt.spannedTokens.map((token) => genToken(model, token, version)),\n\t\t\treadonly: item.isReadonly,\n\t\t\toptional: item.isOptional,\n\t\t};\n\t}\n\n\tpublic static encodeInheritanceData(\n\t\titem: ApiDeclaredItem,\n\t\tparent: ApiItemContainerMixin,\n\t\tversion: string,\n\t): ApiInheritableJSON {\n\t\treturn {\n\t\t\tinheritanceData:\n\t\t\t\titem.parent && item.parent.containerKey !== parent.containerKey\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tparentKey: item.parent.containerKey,\n\t\t\t\t\t\t\tparentName: item.parent.displayName,\n\t\t\t\t\t\t\tpath: generatePath(item.parent.getHierarchy(), version),\n\t\t\t\t\t\t}\n\t\t\t\t\t: null,\n\t\t};\n\t}\n\n\tpublic static encodeFunctionLike(model: ApiModel, item: FunctionLike, version: string) {\n\t\treturn {\n\t\t\t...this.encodeItem(model, item, version),\n\t\t\t...this.encodeParameterList(model, item, version),\n\t\t\t...this.encodeTypeParameterList(model, item, version),\n\t\t\treturnTypeTokens: item.returnTypeExcerpt.spannedTokens.map((token) => genToken(model, token, version)),\n\t\t\toverloadIndex: item.overloadIndex,\n\t\t};\n\t}\n\n\tpublic static encodeFunction(model: ApiModel, item: FunctionLike, version: string, nested = false): ApiFunctionJSON {\n\t\treturn {\n\t\t\t...this.encodeFunctionLike(model, item, version),\n\t\t\tmergedSiblings: nested\n\t\t\t\t? []\n\t\t\t\t: item.getMergedSiblings().map((item) => this.encodeFunction(model, item as ApiFunction, version, true)),\n\t\t};\n\t}\n\n\tpublic static encodeMethodSignature(\n\t\tmodel: ApiModel,\n\t\titem: ApiMethodSignature,\n\t\tparent: ApiItemContainerMixin,\n\t\tversion: string,\n\t\tnested = false,\n\t): ApiMethodSignatureJSON {\n\t\treturn {\n\t\t\t...this.encodeFunctionLike(model, item, version),\n\t\t\t...this.encodeInheritanceData(item, parent, version),\n\t\t\toptional: item.isOptional,\n\t\t\tmergedSiblings: nested\n\t\t\t\t? []\n\t\t\t\t: item\n\t\t\t\t\t\t.getMergedSiblings()\n\t\t\t\t\t\t.map((item) => this.encodeMethodSignature(model, item as ApiMethodSignature, parent, version, true)),\n\t\t};\n\t}\n\n\tpublic static encodeMethod(\n\t\tmodel: ApiModel,\n\t\titem: ApiMethod,\n\t\tparent: ApiItemContainerMixin,\n\t\tversion: string,\n\t\tnested = false,\n\t): ApiMethodJSON {\n\t\treturn {\n\t\t\t...this.encodeMethodSignature(model, item, parent, version),\n\t\t\tstatic: item.isStatic,\n\t\t\tprotected: item.isProtected,\n\t\t\tmergedSiblings: nested\n\t\t\t\t? []\n\t\t\t\t: item.getMergedSiblings().map((item) => this.encodeMethod(model, item as ApiMethod, parent, version, true)),\n\t\t};\n\t}\n\n\tpublic static encodeClass(model: ApiModel, item: ApiClass, version: string): ApiClassJSON {\n\t\tconst extendsExcerpt = item.extendsType?.excerpt;\n\n\t\tconst methods: ApiMethodJSON[] = [];\n\t\tconst properties: ApiPropertyItemJSON[] = [];\n\n\t\tlet constructor: ApiConstructor | undefined;\n\n\t\tfor (const member of item.findMembersWithInheritance().items) {\n\t\t\tswitch (member.kind) {\n\t\t\t\tcase ApiItemKind.Method:\n\t\t\t\t\tmethods.push(this.encodeMethod(model, member as ApiMethod, item, version));\n\t\t\t\t\tbreak;\n\t\t\t\tcase ApiItemKind.Property:\n\t\t\t\t\tproperties.push(this.encodeProperty(model, member as ApiPropertyItem, item, version));\n\t\t\t\t\tbreak;\n\t\t\t\tcase ApiItemKind.Constructor:\n\t\t\t\t\tconstructor = member as ApiConstructor;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\t...this.encodeItem(model, item, version),\n\t\t\t...this.encodeTypeParameterList(model, item, version),\n\t\t\tconstructor: constructor ? this.encodeConstructor(model, constructor, version) : null,\n\t\t\textendsTokens: extendsExcerpt ? extendsExcerpt.spannedTokens.map((token) => genToken(model, token, version)) : [],\n\t\t\timplementsTokens: item.implementsTypes.map((excerpt) =>\n\t\t\t\texcerpt.excerpt.spannedTokens.map((token) => genToken(model, token, version)),\n\t\t\t),\n\t\t\tmethods,\n\t\t\tproperties,\n\t\t};\n\t}\n\n\tpublic static encodeTypeAlias(model: ApiModel, item: ApiTypeAlias, version: string): ApiTypeAliasJSON {\n\t\treturn {\n\t\t\t...this.encodeItem(model, item, version),\n\t\t\t...this.encodeTypeParameterList(model, item, version),\n\t\t\ttypeTokens: item.typeExcerpt.spannedTokens.map((token) => genToken(model, token, version)),\n\t\t};\n\t}\n\n\tpublic static encodeEnum(model: ApiModel, item: ApiEnum, version: string): ApiEnumJSON {\n\t\treturn {\n\t\t\t...this.encodeItem(model, item, version),\n\t\t\tmembers: item.members.map((member) => ({\n\t\t\t\tname: member.name,\n\t\t\t\tinitializerTokens:\n\t\t\t\t\tmember.initializerExcerpt?.spannedTokens.map((token) => genToken(model, token, version)) ?? [],\n\t\t\t\tsummary: member.tsdocComment ? nodeContainer(member.tsdocComment.summarySection, model, version, member) : null,\n\t\t\t})),\n\t\t};\n\t}\n\n\tpublic static encodeInterface(model: ApiModel, item: ApiInterface, version: string): ApiInterfaceJSON {\n\t\tconst methods: ApiMethodSignatureJSON[] = [];\n\t\tconst properties: ApiPropertyItemJSON[] = [];\n\n\t\tfor (const member of item.findMembersWithInheritance().items) {\n\t\t\tswitch (member.kind) {\n\t\t\t\tcase ApiItemKind.MethodSignature:\n\t\t\t\t\tmethods.push(this.encodeMethodSignature(model, member as ApiMethodSignature, item, version));\n\t\t\t\t\tbreak;\n\t\t\t\tcase ApiItemKind.PropertySignature:\n\t\t\t\t\tproperties.push(this.encodeProperty(model, member as ApiPropertySignature, item, version));\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\t...this.encodeItem(model, item, version),\n\t\t\t...this.encodeTypeParameterList(model, item, version),\n\t\t\textendsTokens: item.extendsTypes.map((excerpt) =>\n\t\t\t\texcerpt.excerpt.spannedTokens.map((token) => genToken(model, token, version)),\n\t\t\t),\n\t\t\tmethods,\n\t\t\tproperties,\n\t\t};\n\t}\n\n\tpublic static encodeVariable(model: ApiModel, item: ApiVariable, version: string): ApiVariableJSON {\n\t\treturn {\n\t\t\t...this.encodeItem(model, item, version),\n\t\t\ttypeTokens: item.variableTypeExcerpt.spannedTokens.map((token) => genToken(model, token, version)),\n\t\t\treadonly: item.isReadonly,\n\t\t};\n\t}\n\n\tpublic static encodeConstructor(model: ApiModel, item: ApiConstructor, version: string): ApiConstructorJSON {\n\t\treturn {\n\t\t\t...this.encodeItem(model, item, version),\n\t\t\t...this.encodeParameterList(model, item, version),\n\t\t\tprotected: item.isProtected,\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/src/TypeParameterJSONEncoder.ts",
    "content": "import type { TypeParameter, ApiModel, ApiItem } from '@discordjs/api-extractor-model';\nimport { type TokenDocumentation, genToken } from './parse.js';\nimport { type DocBlockJSON, block } from './tsdoc/CommentBlock.js';\n\nexport interface TypeParameterData {\n\tcommentBlock: DocBlockJSON | null;\n\tconstraintTokens: TokenDocumentation[];\n\tdefaultTokens: TokenDocumentation[];\n\tname: string;\n\toptional: boolean;\n}\n\nexport function generateTypeParamData(\n\tmodel: ApiModel,\n\ttypeParam: TypeParameter,\n\tversion: string,\n\tparentItem?: ApiItem,\n): TypeParameterData {\n\tconst constraintTokens = typeParam.constraintExcerpt.spannedTokens.map((token) => genToken(model, token, version));\n\tconst defaultTokens = typeParam.defaultTypeExcerpt.spannedTokens.map((token) => genToken(model, token, version));\n\n\treturn {\n\t\tname: typeParam.name,\n\t\tconstraintTokens,\n\t\tdefaultTokens,\n\t\toptional: typeParam.isOptional,\n\t\tcommentBlock: typeParam.tsdocTypeParamBlock\n\t\t\t? block(typeParam.tsdocTypeParamBlock, model, version, parentItem)\n\t\t\t: null,\n\t};\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/src/index.ts",
    "content": "export * from './ApiNodeJSONEncoder.js';\nexport * from './parse.js';\nexport * from './tsdoc/index.js';\nexport * from './TypeParameterJSONEncoder.js';\n"
  },
  {
    "path": "packages/api-extractor-utils/src/parse.ts",
    "content": "import {\n\ttype ApiModel,\n\ttype ApiPackage,\n\ttype ApiItem,\n\tApiItemKind,\n\ttype Excerpt,\n\tExcerptTokenKind,\n\tApiNameMixin,\n\ttype ApiPropertyItem,\n\ttype ExcerptToken,\n\ttype Parameter,\n\ttype ApiFunction,\n\tApiDeclaredItem,\n\ttype ApiMethod,\n\ttype ApiMethodSignature,\n} from '@discordjs/api-extractor-model';\nimport type { DocNode, DocParagraph, DocPlainText } from '@microsoft/tsdoc';\nimport { type Meaning, ModuleSource } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport type { DocBlockJSON } from './tsdoc/CommentBlock.js';\nimport { createCommentNode } from './tsdoc/index.js';\n\nexport function findPackage(model: ApiModel, name: string): ApiPackage | undefined {\n\treturn (model.findMembersByName(name)[0] ?? model.findMembersByName(`@discordjs/${name}`)[0]) as\n\t\t| ApiPackage\n\t\t| undefined;\n}\n\nfunction hasOverloadIndex(item: ApiItem): item is ApiFunction | ApiMethod | ApiMethodSignature {\n\treturn 'overloadIndex' in item;\n}\n\nexport function generatePath(items: readonly ApiItem[], version: string) {\n\tlet path = '/docs/packages';\n\n\tfor (const item of items) {\n\t\tswitch (item.kind) {\n\t\t\tcase ApiItemKind.Model:\n\t\t\tcase ApiItemKind.EntryPoint:\n\t\t\t\tbreak;\n\t\t\tcase ApiItemKind.Package:\n\t\t\t\tpath += `/${item.displayName}`;\n\t\t\t\tbreak;\n\t\t\tcase ApiItemKind.Function:\n\t\t\t\tpath += `/${item.displayName}${\n\t\t\t\t\thasOverloadIndex(item) && item.overloadIndex > 1 ? `:${item.overloadIndex}` : ''\n\t\t\t\t}:${item.kind}`;\n\t\t\t\tbreak;\n\t\t\tcase ApiItemKind.Method:\n\t\t\tcase ApiItemKind.MethodSignature:\n\t\t\t\tpath += `#${item.displayName}${\n\t\t\t\t\thasOverloadIndex(item) && item.overloadIndex > 1 ? `:${item.overloadIndex}` : ''\n\t\t\t\t}`;\n\t\t\t\tbreak;\n\t\t\tcase ApiItemKind.Property:\n\t\t\tcase ApiItemKind.PropertySignature:\n\t\t\tcase ApiItemKind.Event:\n\t\t\tcase ApiItemKind.EnumMember:\n\t\t\t\tpath += `#${item.displayName}`;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tpath += `/${item.displayName}:${item.kind}`;\n\t\t}\n\t}\n\n\treturn path.includes('@discordjs/')\n\t\t? path.replace(/@discordjs\\/(?<package>.*)\\/(?<member>.*)?/, `$<package>/${version}/$<member>`)\n\t\t: path.replace(/(?<package>.*)\\/(?<member>.*)?/, `$<package>/${version}/$<member>`);\n}\n\nexport function resolveDocComment(item: ApiDeclaredItem) {\n\tif (!(item instanceof ApiDeclaredItem)) {\n\t\treturn null;\n\t}\n\n\tconst { tsdocComment } = item;\n\n\tif (!tsdocComment) {\n\t\treturn null;\n\t}\n\n\tconst { summarySection } = tsdocComment;\n\n\tfunction recurseNodes(node: DocNode | undefined): string | null {\n\t\tif (!node) {\n\t\t\treturn null;\n\t\t}\n\n\t\tswitch (node.kind) {\n\t\t\tcase 'Paragraph':\n\t\t\t\treturn recurseNodes(node as DocParagraph);\n\t\t\tcase 'PlainText':\n\t\t\t\treturn (node as DocPlainText).text;\n\t\t\tdefault:\n\t\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn recurseNodes(summarySection);\n}\n\nexport function findReferences(model: ApiModel, excerpt: Excerpt) {\n\tconst retVal: Set<ApiItem> = new Set();\n\n\tfor (const token of excerpt.spannedTokens) {\n\t\tswitch (token.kind) {\n\t\t\tcase ExcerptTokenKind.Reference: {\n\t\t\t\tconst item = model.resolveDeclarationReference(token.canonicalReference!, undefined).resolvedApiItem;\n\t\t\t\tif (!item) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tretVal.add(item);\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn retVal;\n}\n\nexport function resolveName(item: ApiItem) {\n\tif (ApiNameMixin.isBaseClassOf(item)) {\n\t\treturn item.name;\n\t}\n\n\treturn item.displayName;\n}\n\nexport function getProperties(item: ApiItem) {\n\tconst properties: ApiPropertyItem[] = [];\n\tfor (const member of item.members) {\n\t\tswitch (member.kind) {\n\t\t\tcase ApiItemKind.Property:\n\t\t\tcase ApiItemKind.PropertySignature:\n\t\t\tcase ApiItemKind.Method:\n\t\t\tcase ApiItemKind.MethodSignature:\n\t\t\t\tproperties.push(member as ApiPropertyItem);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn properties;\n}\n\nexport interface TokenDocumentation {\n\tkind: string;\n\tpath: string | null;\n\ttext: string;\n}\n\nexport interface ParameterDocumentation {\n\tisOptional: boolean;\n\tname: string;\n\tparamCommentBlock: DocBlockJSON | null;\n\ttokens: TokenDocumentation[];\n}\n\nfunction createDapiTypesURL(meaning: Meaning, name: string) {\n\tconst base = 'https://discord-api-types.dev/api/discord-api-types-v10';\n\n\tswitch (meaning) {\n\t\tcase 'type':\n\t\t\treturn `${base}#${name}`;\n\t\tdefault:\n\t\t\treturn `${base}/${meaning}/${name}`;\n\t}\n}\n\nexport function genReference(item: ApiItem, version: string) {\n\treturn {\n\t\tname: resolveName(item),\n\t\tpath: generatePath(item.getHierarchy(), version),\n\t};\n}\n\nexport function genToken(model: ApiModel, token: ExcerptToken, version: string) {\n\tif (token.canonicalReference) {\n\t\t// @ts-expect-error: Symbol is not publicly accessible\n\t\ttoken.canonicalReference._navigation = '.';\n\t}\n\n\tif (\n\t\ttoken.canonicalReference?.source instanceof ModuleSource &&\n\t\ttoken.canonicalReference.symbol &&\n\t\ttoken.canonicalReference.source.packageName === 'discord-api-types' &&\n\t\ttoken.canonicalReference.symbol.meaning\n\t) {\n\t\treturn {\n\t\t\tkind: token.kind,\n\t\t\ttext: token.text,\n\t\t\tpath: createDapiTypesURL(token.canonicalReference.symbol.meaning, token.text),\n\t\t};\n\t}\n\n\tconst item = token.canonicalReference\n\t\t? (model.resolveDeclarationReference(token.canonicalReference, undefined).resolvedApiItem ?? null)\n\t\t: null;\n\n\treturn {\n\t\tkind: token.kind,\n\t\ttext: token.text,\n\t\tpath: item ? generatePath(item.getHierarchy(), version) : null,\n\t};\n}\n\nexport function genParameter(model: ApiModel, param: Parameter, version: string): ParameterDocumentation {\n\treturn {\n\t\tname: param.name,\n\t\tisOptional: param.isOptional,\n\t\ttokens: param.parameterTypeExcerpt.spannedTokens.map((token) => genToken(model, token, version)),\n\t\tparamCommentBlock: param.tsdocParamBlock\n\t\t\t? (createCommentNode(param.tsdocParamBlock, model, version) as DocBlockJSON)\n\t\t\t: null,\n\t};\n}\n\nexport function getMembers(pkg: ApiPackage, version: string) {\n\treturn pkg.members[0]!.members.map((member) => ({\n\t\tname: member.displayName,\n\t\tkind: member.kind as string,\n\t\tpath: generatePath(member.getHierarchy(), version),\n\t\tcontainerKey: member.containerKey,\n\t\toverloadIndex: member.kind === 'Function' ? (member as ApiFunction).overloadIndex : null,\n\t}));\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/src/tsdoc/CommentBlock.ts",
    "content": "import type { ApiModel, ApiItem } from '@discordjs/api-extractor-model';\nimport type { DocBlock } from '@microsoft/tsdoc';\nimport { blockTag, type DocBlockTagJSON } from './CommentBlockTag.js';\nimport { type AnyDocNodeJSON, type DocNodeJSON, node } from './CommentNode.js';\nimport { createCommentNode } from './index.js';\n\nexport interface DocBlockJSON extends DocNodeJSON {\n\tcontent: AnyDocNodeJSON[];\n\ttag: DocBlockTagJSON;\n}\n\nexport function block(block: DocBlock, model: ApiModel, version: string, parentItem?: ApiItem) {\n\treturn {\n\t\t...node(block),\n\t\tcontent: block.content.nodes.map((node) => createCommentNode(node, model, version, parentItem)),\n\t\ttag: blockTag(block.blockTag),\n\t};\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/src/tsdoc/CommentBlockTag.ts",
    "content": "import type { DocBlockTag } from '@microsoft/tsdoc';\nimport { type DocNodeJSON, node } from './CommentNode.js';\n\nexport interface DocBlockTagJSON extends DocNodeJSON {\n\ttagName: string;\n}\n\nexport function blockTag(blockTag: DocBlockTag): DocBlockTagJSON {\n\treturn {\n\t\t...node(blockTag),\n\t\ttagName: blockTag.tagName,\n\t};\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/src/tsdoc/CommentCodeSpan.ts",
    "content": "import type { DocCodeSpan } from '@microsoft/tsdoc';\nimport { type DocNodeJSON, node } from './CommentNode.js';\n\nexport interface DocCodeSpanJSON extends DocNodeJSON {\n\tcode: string;\n}\n\nexport function codeSpan(codeSpan: DocCodeSpan): DocCodeSpanJSON {\n\treturn {\n\t\t...node(codeSpan),\n\t\tcode: codeSpan.code,\n\t};\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/src/tsdoc/CommentNode.ts",
    "content": "import type { DocNode, DocNodeKind } from '@microsoft/tsdoc';\nimport type { DocBlockJSON } from './CommentBlock.js';\nimport type { DocCodeSpanJSON } from './CommentCodeSpan.js';\nimport type { DocNodeContainerJSON } from './CommentNodeContainer.js';\nimport type { DocFencedCodeJSON } from './FencedCodeCommentNode.js';\nimport type { DocLinkTagJSON } from './LinkTagCommentNode.js';\nimport type { DocPlainTextJSON } from './PlainTextCommentNode.js';\nimport type { DocCommentJSON } from './RootComment.js';\n\nexport interface DocNodeJSON {\n\tkind: DocNodeKind;\n}\n\nexport type AnyDocNodeJSON =\n\t| DocBlockJSON\n\t| DocCodeSpanJSON\n\t| DocCommentJSON\n\t| DocFencedCodeJSON\n\t| DocLinkTagJSON\n\t| DocNodeContainerJSON\n\t| DocNodeJSON\n\t| DocPlainTextJSON;\n\nexport function node(node: DocNode): DocNodeJSON {\n\treturn {\n\t\tkind: node.kind as DocNodeKind,\n\t};\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/src/tsdoc/CommentNodeContainer.ts",
    "content": "import type { ApiItem, ApiModel } from '@discordjs/api-extractor-model';\nimport type { DocNodeContainer } from '@microsoft/tsdoc';\nimport { type AnyDocNodeJSON, type DocNodeJSON, node } from './CommentNode.js';\nimport { createCommentNode } from './index.js';\n\nexport interface DocNodeContainerJSON extends DocNodeJSON {\n\tnodes: AnyDocNodeJSON[];\n}\n\nexport function nodeContainer(\n\tcontainer: DocNodeContainer,\n\tmodel: ApiModel,\n\tversion: string,\n\tparentItem?: ApiItem,\n): DocNodeContainerJSON {\n\treturn {\n\t\t...node(container),\n\t\tnodes: container.nodes.map((node) => createCommentNode(node, model, version, parentItem)),\n\t};\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/src/tsdoc/FencedCodeCommentNode.ts",
    "content": "import type { DocFencedCode } from '@microsoft/tsdoc';\nimport { type DocNodeJSON, node } from './CommentNode.js';\n\nexport interface DocFencedCodeJSON extends DocNodeJSON {\n\tcode: string;\n\tlanguage: string;\n}\n\nexport function fencedCode(fencedCode: DocFencedCode) {\n\treturn {\n\t\t...node(fencedCode),\n\t\tlanguage: fencedCode.language,\n\t\tcode: fencedCode.code,\n\t};\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/src/tsdoc/LinkTagCommentNode.ts",
    "content": "import type { ApiItem, ApiModel } from '@discordjs/api-extractor-model';\nimport type { DocDeclarationReference, DocLinkTag } from '@microsoft/tsdoc';\nimport { resolveName, generatePath } from '../parse.js';\nimport { type DocNodeJSON, node } from './CommentNode.js';\n\ninterface LinkTagCodeLink {\n\tkind: string;\n\tname: string;\n\tpath: string;\n}\n\nexport interface DocLinkTagJSON extends DocNodeJSON {\n\tcodeDestination: LinkTagCodeLink | null;\n\ttext: string | null;\n\turlDestination: string | null;\n}\n\nexport function genLinkToken(\n\tmodel: ApiModel,\n\tref: DocDeclarationReference,\n\tcontext: ApiItem | null,\n\tversion: string,\n): LinkTagCodeLink | null {\n\tconst item = model.resolveDeclarationReference(ref, context ?? undefined).resolvedApiItem ?? null;\n\n\tif (!item) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tname: resolveName(item),\n\t\tkind: item.kind,\n\t\tpath: generatePath(item.getHierarchy(), version),\n\t};\n}\n\nexport function linkTagNode(\n\tlinkNode: DocLinkTag,\n\tmodel: ApiModel,\n\tversion: string,\n\tparentItem?: ApiItem,\n): DocLinkTagJSON {\n\t// If we weren't provided a parent object, fallback to the package entrypoint.\n\tconst packageEntryPoint = linkNode.codeDestination?.importPath\n\t\t? model.getAssociatedPackage()?.findEntryPointsByPath(linkNode.codeDestination.importPath)[0]\n\t\t: null;\n\n\tconst codeDestination = linkNode.codeDestination\n\t\t? genLinkToken(model, linkNode.codeDestination, parentItem ?? packageEntryPoint ?? null, version)\n\t\t: null;\n\tconst text = linkNode.linkText ?? null;\n\tconst urlDestination = linkNode.urlDestination ?? null;\n\n\treturn {\n\t\t...node(linkNode),\n\t\ttext,\n\t\tcodeDestination,\n\t\turlDestination,\n\t};\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/src/tsdoc/ParamBlock.ts",
    "content": "import type { ApiItem, ApiModel } from '@discordjs/api-extractor-model';\nimport type { DocParamBlock } from '@microsoft/tsdoc';\nimport { block, type DocBlockJSON } from './CommentBlock.js';\n\ninterface DocParamBlockJSON extends DocBlockJSON {\n\tname: string;\n}\n\nexport function paramBlock(\n\tparamBlock: DocParamBlock,\n\tmodel: ApiModel,\n\tversion: string,\n\tparentItem?: ApiItem,\n): DocParamBlockJSON {\n\treturn {\n\t\t...block(paramBlock, model, version, parentItem),\n\t\tname: paramBlock.parameterName,\n\t};\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/src/tsdoc/PlainTextCommentNode.ts",
    "content": "import type { DocPlainText } from '@microsoft/tsdoc';\nimport { type DocNodeJSON, node } from './CommentNode.js';\n\nexport interface DocPlainTextJSON extends DocNodeJSON {\n\ttext: string;\n}\n\nexport function plainTextNode(plainTextNode: DocPlainText): DocPlainTextJSON {\n\treturn {\n\t\t...node(plainTextNode),\n\t\ttext: plainTextNode.text,\n\t};\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/src/tsdoc/RootComment.ts",
    "content": "import type { ApiItem, ApiModel } from '@discordjs/api-extractor-model';\nimport type { DocComment } from '@microsoft/tsdoc';\nimport { block, type DocBlockJSON } from './CommentBlock.js';\nimport { type DocNodeJSON, node } from './CommentNode.js';\nimport { createCommentNode } from './index.js';\n\nexport interface DocCommentJSON extends DocNodeJSON {\n\tcustomBlocks: DocBlockJSON[];\n\tdeprecated: DocNodeJSON[];\n\tremarks: DocNodeJSON[];\n\tsummary: DocNodeJSON[];\n}\n\nexport function comment(comment: DocComment, model: ApiModel, version: string, parentItem?: ApiItem): DocCommentJSON {\n\treturn {\n\t\t...node(comment),\n\t\tsummary: comment.summarySection.nodes.map((node) => createCommentNode(node, model, version, parentItem)),\n\t\tremarks:\n\t\t\tcomment.remarksBlock?.content.nodes.map((node) => createCommentNode(node, model, version, parentItem)) ?? [],\n\t\tdeprecated:\n\t\t\tcomment.deprecatedBlock?.content.nodes.map((node) => createCommentNode(node, model, version, parentItem)) ?? [],\n\t\tcustomBlocks: comment.customBlocks.map((_block) => block(_block, model, version, parentItem)),\n\t};\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/src/tsdoc/index.ts",
    "content": "import type { ApiModel, ApiItem } from '@discordjs/api-extractor-model';\nimport {\n\ttype DocNode,\n\ttype DocPlainText,\n\ttype DocLinkTag,\n\ttype DocParagraph,\n\ttype DocFencedCode,\n\tDocNodeKind,\n\ttype DocBlock,\n\ttype DocComment,\n\ttype DocCodeSpan,\n\ttype DocParamBlock,\n} from '@microsoft/tsdoc';\nimport { block } from './CommentBlock.js';\nimport { codeSpan } from './CommentCodeSpan.js';\nimport { node as _node, type AnyDocNodeJSON } from './CommentNode.js';\nimport { nodeContainer } from './CommentNodeContainer.js';\nimport { fencedCode } from './FencedCodeCommentNode.js';\nimport { linkTagNode } from './LinkTagCommentNode.js';\nimport { paramBlock } from './ParamBlock.js';\nimport { plainTextNode } from './PlainTextCommentNode.js';\nimport { comment } from './RootComment.js';\n\nexport function createCommentNode(\n\tnode: DocNode,\n\tmodel: ApiModel,\n\tversion: string,\n\tparentItem?: ApiItem,\n): AnyDocNodeJSON {\n\tswitch (node.kind) {\n\t\tcase DocNodeKind.PlainText:\n\t\t\treturn plainTextNode(node as DocPlainText);\n\t\tcase DocNodeKind.LinkTag:\n\t\t\treturn linkTagNode(node as DocLinkTag, model, version, parentItem);\n\t\tcase DocNodeKind.Paragraph:\n\t\tcase DocNodeKind.Section:\n\t\t\treturn nodeContainer(node as DocParagraph, model, version, parentItem);\n\t\tcase DocNodeKind.FencedCode:\n\t\t\treturn fencedCode(node as DocFencedCode);\n\t\tcase DocNodeKind.CodeSpan:\n\t\t\treturn codeSpan(node as DocCodeSpan);\n\t\tcase DocNodeKind.Block:\n\t\t\treturn block(node as DocBlock, model, version, parentItem);\n\t\tcase DocNodeKind.ParamBlock:\n\t\t\treturn paramBlock(node as DocParamBlock, model, version, parentItem);\n\t\tcase DocNodeKind.Comment:\n\t\t\treturn comment(node as DocComment, model, version, parentItem);\n\t\tdefault:\n\t\t\treturn _node(node);\n\t}\n}\n\nexport * from './CommentNode.js';\nexport * from './CommentNodeContainer.js';\nexport * from './CommentBlock.js';\nexport * from './CommentBlockTag.js';\nexport * from './CommentCodeSpan.js';\nexport * from './FencedCodeCommentNode.js';\nexport * from './LinkTagCommentNode.js';\nexport * from './ParamBlock.js';\nexport * from './PlainTextCommentNode.js';\nexport * from './RootComment.js';\n"
  },
  {
    "path": "packages/api-extractor-utils/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"skipDefaultLibCheck\": true,\n\t\t\"skipLibCheck\": true\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/api-extractor-utils/tsup.config.ts",
    "content": "import { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tminify: 'terser',\n});\n"
  },
  {
    "path": "packages/brokers/.cliff-jumperrc.json",
    "content": "{\n\t\"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n\t\"name\": \"brokers\",\n\t\"org\": \"discordjs\",\n\t\"packagePath\": \"packages/brokers\",\n\t\"identifierBase\": false\n}\n"
  },
  {
    "path": "packages/brokers/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\ndist-docs\n\n# Docs\ndocs/**/*\n!docs/README.md\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/brokers/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/brokers/.prettierignore",
    "content": ".turbo\ncoverage\ndist\ndist-docs\ndocs/docs.api.json\nCHANGELOG.md\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/brokers/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/brokers/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n# [@discordjs/brokers@1.0.0](https://github.com/discordjs/discord.js/compare/@discordjs/brokers@0.3.0...@discordjs/brokers@1.0.0) - (2024-09-01)\n\n## Refactor\n\n- **brokers:** Re-design API to make groups a constructor option (#10297) ([38a37b5](https://github.com/discordjs/discord.js/commit/38a37b5caf06913131c6dc2dc5cc258aecfe2266))\n- **brokers:** Make option props more correct (#10242) ([393ded4](https://github.com/discordjs/discord.js/commit/393ded4ea14e73b2bb42226f57896130329f88ca))\n  - **BREAKING CHANGE:** Classes now take redis client as standalone parameter, various props from the base option interface moved to redis options\n\n# [@discordjs/brokers@0.3.0](https://github.com/discordjs/discord.js/compare/@discordjs/brokers@0.2.3...@discordjs/brokers@0.3.0) - (2024-05-04)\n\n## Bug Fixes\n\n- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))\n\n## Documentation\n\n- Split docs.api.json into multiple json files ([597340f](https://github.com/discordjs/discord.js/commit/597340f288437c35da8c703d9b621274de60d880))\n\n## Features\n\n- Local and preview detection ([79fbda3](https://github.com/discordjs/discord.js/commit/79fbda3aac6d4f0f8bfb193e797d09cbe331d315))\n\n## Refactor\n\n- Docs (#10126) ([18cce83](https://github.com/discordjs/discord.js/commit/18cce83d80598c430218775c53441b6b2ecdc776))\n- Use interfaces for AsyncEventEmitter event maps (#10044) ([adfd9cd](https://github.com/discordjs/discord.js/commit/adfd9cd3b32cfabdcc45ec90f535b2852a3ca4a6))\n\n# [@discordjs/brokers@0.2.2](https://github.com/discordjs/discord.js/compare/@discordjs/brokers@0.2.1...@discordjs/brokers@0.2.2) - (2023-08-17)\n\n## Documentation\n\n- Update Node.js requirement to 16.11.0 (#9764) ([188877c](https://github.com/discordjs/discord.js/commit/188877c50af70f0d5cffb246620fa277435c6ce6))\n\n# [@discordjs/brokers@0.2.1](https://github.com/discordjs/discord.js/compare/@discordjs/brokers@0.2.0...@discordjs/brokers@0.2.1) - (2023-05-01)\n\n## Bug Fixes\n\n- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2))\n\n## Documentation\n\n- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9))\n- Use `@link` in `@see` (#9348) ([d66d113](https://github.com/discordjs/discord.js/commit/d66d1133331b81563588db4500c63a18c3c3dfae))\n\n# [@discordjs/brokers@0.2.1](https://github.com/discordjs/discord.js/compare/@discordjs/brokers@0.2.0...@discordjs/brokers@0.2.1) - (2023-05-01)\n\n## Bug Fixes\n\n- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2))\n\n## Documentation\n\n- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9))\n- Use `@link` in `@see` (#9348) ([d66d113](https://github.com/discordjs/discord.js/commit/d66d1133331b81563588db4500c63a18c3c3dfae))\n\n# [@discordjs/brokers@0.2.0](https://github.com/discordjs/discord.js/compare/@discordjs/brokers@0.1.0...@discordjs/brokers@0.2.0) - (2023-04-01)\n\n## Bug Fixes\n\n- **scripts:** Accessing tsComment ([d8d5f31](https://github.com/discordjs/discord.js/commit/d8d5f31d3927fd1de62f1fa3a1a6e454243ad87b))\n- **WebSocketShard:** Proper error bubbling (#9119) ([9681f34](https://github.com/discordjs/discord.js/commit/9681f348770b0e2ff9b7c96b1c30575dd950e2ed))\n\n## Features\n\n- **website:** Render syntax and mdx on the server (#9086) ([ee5169e](https://github.com/discordjs/discord.js/commit/ee5169e0aadd7bbfcd752aae614ec0f69602b68b))\n- **website:** Add support for source file links (#9048) ([f6506e9](https://github.com/discordjs/discord.js/commit/f6506e99c496683ee0ab67db0726b105b929af38))\n\n# [@discordjs/brokers@0.1.0](https://github.com/discordjs/discord.js/tree/@discordjs/brokers@0.1.0) - (2022-11-23)\n\n## Bug Fixes\n\n- **brokers:** Publish the scripts folder (#8794) ([0bcc18a](https://github.com/discordjs/discord.js/commit/0bcc18a0bdd8f1e1ebb974126a460d2743547b34))\n- **BaseRedisBroker:** Proper import path to lua script (#8776) ([e7cbc1b](https://github.com/discordjs/discord.js/commit/e7cbc1bf111b09b64accfd95e82ad9f3a408fc4c))\n\n## Features\n\n- @discordjs/brokers (#8548) ([bf9aa18](https://github.com/discordjs/discord.js/commit/bf9aa1858dab2e1bca3be390ce2392b99d208dbf))\n\n"
  },
  {
    "path": "packages/brokers/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2022 Noel Buechler\n   Copyright 2022 Denis Cristea\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/brokers/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/brokers\"><img src=\"https://img.shields.io/npm/v/@discordjs/brokers.svg?maxAge=3600\" alt=\"npm version\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/brokers\"><img src=\"https://img.shields.io/npm/dt/@discordjs/brokers.svg?maxAge=3600\" alt=\"npm downloads\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/commits/main/packages/brokers\"><img alt=\"Last commit.\" src=\"https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fbrokers\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t\t<a href=\"https://codecov.io/gh/discordjs/discord.js\"><img src=\"https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=brokers\" alt=\"Code coverage\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## About\n\n`@discordjs/brokers` is a powerful set of message brokers\n\n## Installation\n\n**Node.js 22.12.0 or newer is required.**\n\n```sh\nnpm install @discordjs/brokers\nyarn add @discordjs/brokers\npnpm add @discordjs/brokers\n```\n\n## Example usage\n\nThese examples use [ES modules](https://nodejs.org/api/esm.html#enabling).\n\n### pub sub\n\n```ts\n// publisher.js\nimport { PubSubRedisBroker } from '@discordjs/brokers';\nimport Redis from 'ioredis';\n\n// Considering this only pushes events, the group and name are not important.\nconst broker = new PubSubRedisBroker(new Redis(), { group: 'noop', name: 'noop' });\n\nawait broker.publish('test', 'Hello World!');\nawait broker.destroy();\n\n// subscriber.js\nimport { PubSubRedisBroker } from '@discordjs/brokers';\nimport Redis from 'ioredis';\n\nconst broker = new PubSubRedisBroker(new Redis(), {\n\t// This is the consumer group name. You should make sure to not re-use this\n\t// across different applications in your stack, unless you absolutely know\n\t// what you're doing.\n\tgroup: 'subscribers',\n\t// With the assumption that this service will scale to more than one instance,\n\t// you MUST ensure `UNIQUE_CONSUMER_ID` is unique across all of them and\n\t// also deterministic (i.e. if instance-1 restarts, it should still be instance-1)\n\tname: `consumer-${UNIQUE_CONSUMER_ID}`,\n});\nbroker.on('test', ({ data, ack }) => {\n\tconsole.log(data);\n\tvoid ack();\n});\n\nawait broker.subscribe(['test']);\n```\n\n### RPC\n\n```ts\n// caller.js\nimport { RPCRedisBroker } from '@discordjs/brokers';\nimport Redis from 'ioredis';\n\nconst broker = new RPCRedisBroker(new Redis(), { group: 'noop', name: 'noop' });\n\nconsole.log(await broker.call('testcall', 'Hello World!'));\nawait broker.destroy();\n\n// responder.js\nimport { RPCRedisBroker } from '@discordjs/brokers';\nimport Redis from 'ioredis';\n\nconst broker = new RPCRedisBroker(new Redis(), {\n\t// Equivalent to the group/name in pubsub, refer to the previous example.\n\tgroup: 'responders',\n\tname: `consumer-${UNIQUE_ID}`,\n});\nbroker.on('testcall', ({ data, ack, reply }) => {\n\tconsole.log('responder', data);\n\tvoid ack();\n\tvoid reply(`Echo: ${data}`);\n});\n\nawait broker.subscribe(['testcall']);\n```\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Documentation][documentation]\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [npm][npm]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the\n[documentation][documentation].  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs/packages/brokers/stable\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/brokers\n[npm]: https://www.npmjs.com/package/@discordjs/brokers\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/brokers/__tests__/index.test.ts",
    "content": "import type Redis from 'ioredis';\nimport { test, expect, vi } from 'vitest';\nimport { PubSubRedisBroker } from '../src/index.js';\n\nvi.mock('node:fs', () => ({\n\treadFileSync: vi.fn(),\n}));\n\nconst mockRedisClient = {\n\tdefineCommand: vi.fn(),\n\txadd: vi.fn(),\n\tduplicate: vi.fn(() => mockRedisClient),\n} as unknown as Redis;\n\ntest('pubsub with custom encoding', async () => {\n\tconst encode = vi.fn((data) => data);\n\n\tconst broker = new PubSubRedisBroker(mockRedisClient, { encode, name: 'yeet', group: 'group' });\n\tawait broker.publish('test', 'test');\n\texpect(encode).toHaveBeenCalledWith('test');\n});\n"
  },
  {
    "path": "packages/brokers/api-extractor.json",
    "content": "{\n\t\"extends\": \"../../api-extractor.json\",\n\t\"docModel\": {\n\t\t\"projectFolderUrl\": \"https://github.com/discordjs/discord.js/tree/main/packages/brokers\"\n\t}\n}\n"
  },
  {
    "path": "packages/brokers/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t\t{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length %}\\\n\t\\n### New Contributors\\n\n\t{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\\\n\t\t* @{{ contributor.username }} made their first contribution in #{{ contributor.pr_number }}\n\t{% endfor %}\\\n{% endif %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"@discordjs/brokers@[0-9]*\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/brokers/docs/README.md",
    "content": "## [View the documentation here.](https://discord.js.org/docs/packages/brokers/main)\n"
  },
  {
    "path": "packages/brokers/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/brokers\",\n\t\"version\": \"1.0.0\",\n\t\"description\": \"Powerful set of message brokers\",\n\t\"scripts\": {\n\t\t\"test\": \"vitest run --config ../../vitest.config.ts\",\n\t\t\"build\": \"tsc --noEmit --lib ESNext,DOM && tsup\",\n\t\t\"build:docs\": \"tsc -p tsconfig.docs.json --lib ESNext,DOM\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src __tests__\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src __tests__\",\n\t\t\"fmt\": \"pnpm run format\",\n\t\t\"docs\": \"pnpm run build:docs && api-extractor run --local --minify && generate-split-documentation\",\n\t\t\"prepack\": \"pnpm run lint && pnpm run test && pnpm run build\",\n\t\t\"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/brokers/*'\",\n\t\t\"release\": \"cliff-jumper\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"main\": \"./dist/index.js\",\n\t\"module\": \"./dist/index.mjs\",\n\t\"types\": \"./dist/index.d.ts\",\n\t\"directories\": {\n\t\t\"lib\": \"src\",\n\t\t\"test\": \"__tests__\"\n\t},\n\t\"files\": [\n\t\t\"dist\",\n\t\t\"scripts\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"Amish Shah <amishshah.2k@gmail.com>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"Aura Roman <kyradiscord@gmail.com>\",\n\t\t\"DD <didinele.dev@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"discord\",\n\t\t\"api\",\n\t\t\"message\",\n\t\t\"brokers\",\n\t\t\"redis\",\n\t\t\"discordapp\",\n\t\t\"discordjs\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/brokers\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"@discordjs/core\": \"workspace:^\",\n\t\t\"@discordjs/ws\": \"workspace:^\",\n\t\t\"@msgpack/msgpack\": \"^3.1.3\",\n\t\t\"@vladfrangu/async_event_emitter\": \"^2.4.7\",\n\t\t\"ioredis\": \"^5.9.3\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@discordjs/api-extractor\": \"workspace:^\",\n\t\t\"@discordjs/scripts\": \"workspace:^\",\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@types/node\": \"^22.19.11\",\n\t\t\"@vitest/coverage-v8\": \"^4.0.18\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"esbuild-plugin-version-injector\": \"^1.2.1\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vitest\": \"^4.0.18\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/brokers/scripts/xcleangroup.lua",
    "content": "local info = redis.call('XINFO', 'CONSUMERS', KEYS[1], ARGS[1])\nlocal empty = true\n\nfor k, consumer in pairs(info) do\n  if consumer['idle'] != 0 then\n    empty = false\n    break\n  end\nend\n\nif empty then\n  redis.call('XGROUP', 'DESTROY', KEYS[1], ARGS[1])\n  return true\nend\n\nreturn false\n"
  },
  {
    "path": "packages/brokers/src/brokers/Broker.ts",
    "content": "import { Buffer } from 'node:buffer';\nimport { encode, decode } from '@msgpack/msgpack';\nimport type { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';\n\n/**\n * Base options for a broker implementation\n */\nexport interface BaseBrokerOptions {\n\t/**\n\t * Function to use for decoding messages\n\t */\n\t// eslint-disable-next-line @typescript-eslint/method-signature-style\n\tdecode?: (data: Buffer) => unknown;\n\t/**\n\t * Function to use for encoding messages\n\t */\n\t// eslint-disable-next-line @typescript-eslint/method-signature-style\n\tencode?: (data: unknown) => Buffer;\n}\n\n/**\n * Default broker options\n */\nexport const DefaultBrokerOptions = {\n\tencode: (data): Buffer => {\n\t\tconst encoded = encode(data);\n\t\treturn Buffer.from(encoded.buffer, encoded.byteOffset, encoded.byteLength);\n\t},\n\tdecode: (data): unknown => decode(data),\n} as const satisfies Required<BaseBrokerOptions>;\n\nexport type ToEventMap<\n\tTRecord extends Record<string, any[]>,\n\tTResponses extends Record<keyof TRecord, any> | undefined = undefined,\n> = {\n\t[TKey in keyof TRecord]: [\n\t\tevent: TResponses extends Record<keyof TRecord, any>\n\t\t\t? { ack(): Promise<void>; reply(data: TResponses[TKey]): Promise<void> }\n\t\t\t: { ack(): Promise<void>; data: TRecord[TKey] },\n\t];\n};\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface IBaseBroker<TEvents extends {}> {\n\t/**\n\t * Subscribes to the given events\n\t */\n\tsubscribe(events: (keyof TEvents)[]): Promise<void>;\n\t/**\n\t * Unsubscribes from the given events\n\t */\n\tunsubscribe(events: (keyof TEvents)[]): Promise<void>;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface IPubSubBroker<TEvents extends {}>\n\textends IBaseBroker<TEvents>, AsyncEventEmitter<ToEventMap<TEvents>> {\n\t/**\n\t * Publishes an event\n\t */\n\tpublish<Event extends keyof TEvents>(event: Event, data: TEvents[Event]): Promise<void>;\n}\n\nexport interface IRPCBroker<TEvents extends Record<string, any[]>, TResponses extends Record<keyof TEvents, any>>\n\textends IBaseBroker<TEvents>, AsyncEventEmitter<ToEventMap<TEvents, TResponses>> {\n\t/**\n\t * Makes an RPC call\n\t */\n\tcall<Event extends keyof TEvents>(\n\t\tevent: Event,\n\t\tdata: TEvents[Event],\n\t\ttimeoutDuration?: number,\n\t): Promise<TResponses[Event]>;\n}\n"
  },
  {
    "path": "packages/brokers/src/brokers/redis/BaseRedis.ts",
    "content": "import type { Buffer } from 'node:buffer';\nimport { randomBytes } from 'node:crypto';\nimport { readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';\nimport type { Redis } from 'ioredis';\nimport { ReplyError } from 'ioredis';\nimport type { BaseBrokerOptions, IBaseBroker, ToEventMap } from '../Broker.js';\nimport { DefaultBrokerOptions } from '../Broker.js';\n\ntype RedisReadGroupData = [Buffer, [Buffer, Buffer[]][]][];\n\n// For some reason ioredis doesn't have those typed, but they exist\ndeclare module 'ioredis' {\n\tinterface Redis {\n\t\txclaimBuffer(\n\t\t\tkey: Buffer | string,\n\t\t\tgroup: Buffer | string,\n\t\t\tconsumer: Buffer | string,\n\t\t\tminIdleTime: number,\n\t\t\tid: Buffer | string,\n\t\t\t...args: (Buffer | string)[]\n\t\t): Promise<string[]>;\n\t\txreadgroupBuffer(...args: (Buffer | string)[]): Promise<RedisReadGroupData | null>;\n\t}\n}\n\nexport const kUseRandomGroupName = Symbol.for('djs.brokers.useRandomGroupName');\n\n/**\n * Options specific for a Redis broker\n */\nexport interface RedisBrokerOptions extends BaseBrokerOptions {\n\t/**\n\t * How long to block for messages when polling\n\t */\n\tblockTimeout?: number;\n\t/**\n\t * Consumer group name to use for this broker. For fanning out events, use {@link kUseRandomGroupName}\n\t *\n\t * @see {@link https://redis.io/commands/xreadgroup/}\n\t */\n\tgroup: string | typeof kUseRandomGroupName;\n\t/**\n\t * Max number of messages to poll at once\n\t */\n\tmaxChunk?: number;\n\t/**\n\t * How many times a message can be delivered to a consumer before it is considered dead.\n\t * This is used to prevent messages from being stuck in the queue forever if a consumer is\n\t * unable to process them.\n\t */\n\tmaxDeliveredTimes?: number;\n\t/**\n\t * How long a message should be idle for before allowing it to be claimed by another consumer.\n\t * Note that too high of a value can lead to a high delay in processing messages during a service downscale,\n\t * while too low of a value can lead to messages being too eagerly claimed by other consumers during an instance\n\t * restart (which is most likely not actually that problematic)\n\t */\n\tmessageIdleTime?: number;\n\t/**\n\t * Unique consumer name.\n\t *\n\t * @see {@link https://redis.io/commands/xreadgroup/}\n\t */\n\tname: string;\n}\n\n/**\n * Default broker options for redis\n */\nexport const DefaultRedisBrokerOptions = {\n\t...DefaultBrokerOptions,\n\tmaxChunk: 10,\n\tmaxDeliveredTimes: 3,\n\tmessageIdleTime: 3_000,\n\tblockTimeout: 5_000,\n} as const satisfies Required<Omit<RedisBrokerOptions, 'group' | 'name'>>;\n\n/**\n * Helper class with shared Redis logic\n */\nexport abstract class BaseRedisBroker<\n\tTEvents extends Record<string, any[]>,\n\tTResponses extends Record<keyof TEvents, any> | undefined = undefined,\n>\n\textends AsyncEventEmitter<ToEventMap<TEvents, TResponses>>\n\timplements IBaseBroker<TEvents>\n{\n\t/**\n\t * Used for Redis queues, see the 3rd argument taken by {@link https://redis.io/commands/xadd | xadd}\n\t */\n\tpublic static readonly STREAM_DATA_KEY = 'data' as const;\n\n\t/**\n\t * Options this broker is using\n\t */\n\tprotected readonly options: Required<RedisBrokerOptions>;\n\n\t/**\n\t * Events this broker has subscribed to\n\t */\n\tprotected readonly subscribedEvents = new Set<string>();\n\n\t/**\n\t * Internal copy of the Redis client being used to read incoming payloads\n\t */\n\tprotected readonly streamReadClient: Redis;\n\n\t/**\n\t * The group being used by this broker.\n\t *\n\t * @privateRemarks\n\t * Stored as its own field to do the \"use random group\" resolution in the constructor.\n\t */\n\tprotected readonly group: string;\n\n\t/**\n\t * Whether this broker is currently polling events\n\t */\n\tprotected listening = false;\n\n\tpublic constructor(\n\t\tprotected readonly redisClient: Redis,\n\t\toptions: RedisBrokerOptions,\n\t) {\n\t\tsuper();\n\t\tthis.options = { ...DefaultRedisBrokerOptions, ...options };\n\t\tthis.group = this.options.group === kUseRandomGroupName ? randomBytes(16).toString('hex') : this.options.group;\n\t\tredisClient.defineCommand('xcleangroup', {\n\t\t\tnumberOfKeys: 1,\n\t\t\tlua: readFileSync(resolve(__dirname, '..', 'scripts', 'xcleangroup.lua'), 'utf8'),\n\t\t});\n\t\tthis.streamReadClient = redisClient.duplicate();\n\t}\n\n\t/**\n\t * {@inheritDoc IBaseBroker.subscribe}\n\t */\n\tpublic async subscribe(events: (keyof TEvents)[]): Promise<void> {\n\t\tawait Promise.all(\n\t\t\t// @ts-expect-error: Intended\n\t\t\tevents.map(async (event) => {\n\t\t\t\tthis.subscribedEvents.add(event as string);\n\t\t\t\ttry {\n\t\t\t\t\treturn await this.redisClient.xgroup('CREATE', event as string, this.group, 0, 'MKSTREAM');\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!(error instanceof ReplyError)) {\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\t\tvoid this.listen();\n\t}\n\n\t/**\n\t * {@inheritDoc IBaseBroker.unsubscribe}\n\t */\n\tpublic async unsubscribe(events: (keyof TEvents)[]): Promise<void> {\n\t\tconst commands: unknown[][] = Array.from({ length: events.length * 2 });\n\t\tfor (let idx = 0; idx < commands.length; idx += 2) {\n\t\t\tconst event = events[idx / 2];\n\t\t\tcommands[idx] = ['xgroup', 'delconsumer', event as string, this.options.group, this.options.name];\n\t\t\tcommands[idx + 1] = ['xcleangroup', event as string, this.options.group];\n\t\t}\n\n\t\tawait this.redisClient.pipeline(commands).exec();\n\n\t\tfor (const event of events) {\n\t\t\tthis.subscribedEvents.delete(event as string);\n\t\t}\n\t}\n\n\t/**\n\t * Begins polling for events, firing them to {@link BaseRedisBroker.emitEvent}\n\t */\n\tprotected async listen(): Promise<void> {\n\t\tif (this.listening) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.listening = true;\n\n\t\t// Enter regular polling\n\t\twhile (this.subscribedEvents.size > 0) {\n\t\t\ttry {\n\t\t\t\tawait this.claimAndEmitDeadEvents();\n\t\t\t} catch (error) {\n\t\t\t\t// @ts-expect-error: Intended\n\t\t\t\tthis.emit('error', error);\n\t\t\t\t// We don't break here to keep the loop running even if dead event processing fails\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t// As per docs, '>' means \"give me a new message\"\n\t\t\t\tconst data = await this.readGroup('>', this.options.blockTimeout);\n\t\t\t\tif (!data) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tawait this.processMessages(data);\n\t\t\t} catch (error) {\n\t\t\t\t// @ts-expect-error: Intended\n\t\t\t\tthis.emit('error', error);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tthis.listening = false;\n\t}\n\n\tprivate async readGroup(fromId: string, block: number): Promise<RedisReadGroupData> {\n\t\tconst data = await this.streamReadClient.xreadgroupBuffer(\n\t\t\t'GROUP',\n\t\t\tthis.group,\n\t\t\tthis.options.name,\n\t\t\t'COUNT',\n\t\t\tString(this.options.maxChunk),\n\t\t\t'BLOCK',\n\t\t\tString(block),\n\t\t\t'STREAMS',\n\t\t\t...this.subscribedEvents,\n\t\t\t...Array.from({ length: this.subscribedEvents.size }, () => fromId),\n\t\t);\n\n\t\treturn data ?? [];\n\t}\n\n\tprivate async processMessages(data: RedisReadGroupData): Promise<void> {\n\t\tfor (const [event, messages] of data) {\n\t\t\tconst eventName = event.toString('utf8');\n\n\t\t\tfor (const [id, packet] of messages) {\n\t\t\t\tconst idx = packet.findIndex((value, idx) => value.toString('utf8') === 'data' && idx % 2 === 0);\n\t\t\t\tif (idx < 0) continue;\n\n\t\t\t\tconst payload = packet[idx + 1];\n\t\t\t\tif (!payload) continue;\n\n\t\t\t\tthis.emitEvent(id, this.group, eventName, this.options.decode(payload));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async claimAndEmitDeadEvents(): Promise<void> {\n\t\tfor (const stream of this.subscribedEvents) {\n\t\t\t// Get up to N oldest pending messages (note: a pending message is a message that has been read, but never ACKed)\n\t\t\tconst pending = (await this.streamReadClient.xpending(\n\t\t\t\tstream,\n\t\t\t\tthis.group,\n\t\t\t\t'-',\n\t\t\t\t'+',\n\t\t\t\tthis.options.maxChunk,\n\t\t\t\t// See: https://redis.io/docs/latest/commands/xpending/#extended-form-of-xpending\n\t\t\t)) as [id: string, consumer: string, idleMs: number, deliveredTimes: number][];\n\n\t\t\tfor (const [id, consumer, idleMs, deliveredTimes] of pending) {\n\t\t\t\t// Technically xclaim checks for us anyway, but why not avoid an extra call?\n\t\t\t\tif (idleMs < this.options.messageIdleTime) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (deliveredTimes > this.options.maxDeliveredTimes) {\n\t\t\t\t\t// This message is dead. It has repeatedly failed being processed by a consumer.\n\t\t\t\t\tawait this.streamReadClient.xdel(stream, this.group, id);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Try to claim the message if we don't already own it (this may fail if another consumer has already claimed it)\n\t\t\t\tif (consumer !== this.options.name) {\n\t\t\t\t\tconst claimed = await this.streamReadClient.xclaimBuffer(\n\t\t\t\t\t\tstream,\n\t\t\t\t\t\tthis.group,\n\t\t\t\t\t\tthis.options.name,\n\t\t\t\t\t\tMath.max(this.options.messageIdleTime, 1),\n\t\t\t\t\t\tid,\n\t\t\t\t\t\t'JUSTID',\n\t\t\t\t\t);\n\n\t\t\t\t\t// Another consumer got the message before us\n\t\t\t\t\tif (!claimed?.length) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Fetch message body\n\t\t\t\tconst entries = await this.streamReadClient.xrangeBuffer(stream, id, id);\n\t\t\t\t// No idea how this could happen, frankly!\n\t\t\t\tif (!entries?.length) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst [msgId, fields] = entries[0]!;\n\t\t\t\tconst idx = fields.findIndex((value, idx) => value.toString('utf8') === 'data' && idx % 2 === 0);\n\t\t\t\tif (idx < 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst payload = fields[idx + 1];\n\t\t\t\tif (!payload) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tthis.emitEvent(msgId, this.group, stream, this.options.decode(payload));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Destroys the broker, closing all connections\n\t */\n\tpublic async destroy() {\n\t\tawait this.unsubscribe([...this.subscribedEvents]);\n\t\tthis.streamReadClient.disconnect();\n\t\tthis.redisClient.disconnect();\n\t}\n\n\t/**\n\t * Handles an incoming Redis event\n\t */\n\tprotected abstract emitEvent(id: Buffer, group: string, event: string, data: unknown): unknown;\n}\n"
  },
  {
    "path": "packages/brokers/src/brokers/redis/PubSubRedis.ts",
    "content": "import type { Buffer } from 'node:buffer';\nimport type { IPubSubBroker } from '../Broker.js';\nimport { BaseRedisBroker } from './BaseRedis.js';\n\n/**\n * PubSub broker powered by Redis\n *\n * @example\n * ```ts\n * // publisher.js\n * import { PubSubRedisBroker } from '@discordjs/brokers';\n * import Redis from 'ioredis';\n *\n * const broker = new PubSubRedisBroker(new Redis());\n *\n * await broker.publish('test', 'Hello World!');\n * await broker.destroy();\n *\n * // subscriber.js\n * import { PubSubRedisBroker } from '@discordjs/brokers';\n * import Redis from 'ioredis';\n *\n * const broker = new PubSubRedisBroker(new Redis());\n * \tbroker.on('test', ({ data, ack }) => {\n * \tconsole.log(data);\n * \tvoid ack();\n * });\n *\n * await broker.subscribe('subscribers', ['test']);\n * ```\n */\nexport class PubSubRedisBroker<TEvents extends Record<string, any>>\n\textends BaseRedisBroker<TEvents>\n\timplements IPubSubBroker<TEvents>\n{\n\t/**\n\t * {@inheritDoc IPubSubBroker.publish}\n\t */\n\tpublic async publish<Event extends keyof TEvents>(event: Event, data: TEvents[Event]): Promise<void> {\n\t\tawait this.redisClient.xadd(event as string, '*', BaseRedisBroker.STREAM_DATA_KEY, this.options.encode(data));\n\t}\n\n\tprotected emitEvent(id: Buffer, group: string, event: string, data: unknown) {\n\t\tconst payload: { ack(): Promise<void>; data: unknown } = {\n\t\t\tdata,\n\t\t\tack: async () => {\n\t\t\t\tawait this.redisClient.xack(event, group, id);\n\t\t\t},\n\t\t};\n\n\t\t// @ts-expect-error: Intended\n\t\tthis.emit(event, payload);\n\t}\n}\n"
  },
  {
    "path": "packages/brokers/src/brokers/redis/RPCRedis.ts",
    "content": "import type { Buffer } from 'node:buffer';\nimport type Redis from 'ioredis/built/Redis.js';\nimport type { IRPCBroker } from '../Broker.js';\nimport type { RedisBrokerOptions } from './BaseRedis.js';\nimport { BaseRedisBroker, DefaultRedisBrokerOptions } from './BaseRedis.js';\n\ninterface InternalPromise {\n\treject(error: any): void;\n\tresolve(data: any): void;\n\ttimeout: NodeJS.Timeout;\n}\n\n/**\n * Options specific for an RPC Redis broker\n */\nexport interface RPCRedisBrokerOptions extends RedisBrokerOptions {\n\ttimeout?: number;\n}\n\n/**\n * Default values used for the {@link RPCRedisBrokerOptions}\n */\nexport const DefaultRPCRedisBrokerOptions = {\n\t...DefaultRedisBrokerOptions,\n\ttimeout: 5_000,\n} as const satisfies Required<Omit<RPCRedisBrokerOptions, 'group' | 'name'>>;\n\n/**\n * RPC broker powered by Redis\n *\n * @example\n * ```ts\n * // caller.js\n * import { RPCRedisBroker } from '@discordjs/brokers';\n * import Redis from 'ioredis';\n *\n * const broker = new RPCRedisBroker(new Redis());\n *\n * console.log(await broker.call('testcall', 'Hello World!'));\n * await broker.destroy();\n *\n * // responder.js\n * import { RPCRedisBroker } from '@discordjs/brokers';\n * import Redis from 'ioredis';\n *\n * const broker = new RPCRedisBroker(new Redis());\n * broker.on('testcall', ({ data, ack, reply }) => {\n * \tconsole.log('responder', data);\n * \tvoid ack();\n * \tvoid reply(`Echo: ${data}`);\n * });\n *\n * await broker.subscribe('responders', ['testcall']);\n * ```\n */\nexport class RPCRedisBroker<TEvents extends Record<string, any[]>, TResponses extends Record<keyof TEvents, any>>\n\textends BaseRedisBroker<TEvents, TResponses>\n\timplements IRPCBroker<TEvents, TResponses>\n{\n\t/**\n\t * Options this broker is using\n\t */\n\tprotected override readonly options: Required<RPCRedisBrokerOptions>;\n\n\t/**\n\t * @internal\n\t */\n\tprotected readonly promises = new Map<string, InternalPromise>();\n\n\tpublic constructor(redisClient: Redis, options: RPCRedisBrokerOptions) {\n\t\tsuper(redisClient, options);\n\t\tthis.options = { ...DefaultRPCRedisBrokerOptions, ...options };\n\n\t\tthis.streamReadClient.on('messageBuffer', (channel: Buffer, message: Buffer) => {\n\t\t\tconst [, id] = channel.toString().split(':');\n\t\t\tif (id && this.promises.has(id)) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/unbound-method\n\t\t\t\tconst { resolve, timeout } = this.promises.get(id)!;\n\t\t\t\tresolve(this.options.decode(message));\n\t\t\t\tclearTimeout(timeout);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * {@inheritDoc IRPCBroker.call}\n\t */\n\tpublic async call<Event extends keyof TEvents>(\n\t\tevent: Event,\n\t\tdata: TEvents[Event],\n\t\ttimeoutDuration: number = this.options.timeout,\n\t): Promise<TResponses[Event]> {\n\t\tconst id = await this.redisClient.xadd(\n\t\t\tevent as string,\n\t\t\t'*',\n\t\t\tBaseRedisBroker.STREAM_DATA_KEY,\n\t\t\tthis.options.encode(data),\n\t\t);\n\t\t// This id! assertion is valid. From redis docs:\n\t\t// \"The command returns a Null reply when used with the NOMKSTREAM option and the key doesn't exist.\"\n\t\t// See: https://redis.io/commands/xadd/\n\t\tconst rpcChannel = `${event as string}:${id!}`;\n\n\t\t// Construct the error here for better stack traces\n\t\tconst timedOut = new Error(`timed out after ${timeoutDuration}ms`);\n\n\t\tawait this.streamReadClient.subscribe(rpcChannel);\n\t\treturn new Promise<TResponses[Event]>((resolve, reject) => {\n\t\t\tconst timeout = setTimeout(() => reject(timedOut), timeoutDuration).unref();\n\n\t\t\tthis.promises.set(id!, { resolve, reject, timeout });\n\t\t\t// eslint-disable-next-line promise/prefer-await-to-then\n\t\t}).finally(() => {\n\t\t\tvoid this.streamReadClient.unsubscribe(rpcChannel);\n\t\t\tthis.promises.delete(id!);\n\t\t});\n\t}\n\n\tprotected emitEvent(id: Buffer, event: string, data: unknown) {\n\t\tconst payload: { ack(): Promise<void>; data: unknown; reply(data: unknown): Promise<void> } = {\n\t\t\tdata,\n\t\t\tack: async () => {\n\t\t\t\tawait this.redisClient.xack(event, this.group, id);\n\t\t\t},\n\t\t\treply: async (data) => {\n\t\t\t\tawait this.redisClient.publish(`${event}:${id.toString()}`, this.options.encode(data));\n\t\t\t},\n\t\t};\n\n\t\t// @ts-expect-error: Intended\n\t\tthis.emit(event, payload);\n\t}\n}\n"
  },
  {
    "path": "packages/brokers/src/brokers/redis/RedisGateway.ts",
    "content": "import type { Gateway, GatewayDispatchPayload, GatewaySendPayload, GatewayDispatchEvents } from '@discordjs/core';\nimport type { ManagerShardEventsMap, WebSocketShardEvents } from '@discordjs/ws';\nimport { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';\nimport type { PubSubRedisBroker } from './PubSubRedis.js';\n\nexport type DiscordEvents = {\n\t[K in GatewayDispatchEvents]: GatewayDispatchPayload & {\n\t\tt: K;\n\t};\n};\n\ninterface BrokerProps<Payload> {\n\tpayload: Payload;\n\tshardId: number;\n}\n\ninterface Events extends DiscordEvents {\n\t// eslint-disable-next-line @typescript-eslint/no-use-before-define\n\t[RedisGateway.GatewaySendEvent]: GatewaySendPayload;\n}\n\nexport type RedisBrokerDiscordEvents = {\n\t[K in keyof Events]: BrokerProps<Events[K]>;\n};\n\n/**\n * RedisGateway is an implementation for core's Gateway interface built on top of our Redis brokers.\n *\n * Some important notes:\n * - Instances for this class are for your consumers/services that need the gateway. Naturally, the events passed into\n * `init` are the only ones the core client will be able to emit\n * - You can also opt to use the class as-is without `@discordjs/core`, if you so desire. Events are properly typed\n * - You need to implement your own gateway service. Refer to the example below for how that would look like. This class\n * offers some static methods and properties that help in this errand. It is extremely important that you `publish`\n * events as the receiving service expects, and also that you handle GatewaySend events.\n * - One drawback to using this directly with `@discordjs/core` is that you lose granular control over when to `ack`\n * events. This implementation `ack`s as soon as the event is emitted to listeners. In practice, this means that if your\n * service crashes while handling an event, it's pretty arbitrary wether that event gets re-processed on restart or not.\n * (Mostly dependant on if your handler is async or not, and also if the `ack` call has time to go through).\n *\n * @example\n * ```ts\n * // gateway-service/index.ts\n * import { RedisGateway, PubSubRedisBroker, kUseRandomGroupName } from '@discordjs/brokers';\n * import Redis from 'ioredis';\n *\n * // the `name` here probably should be env-determined if you need to scale this. see the main README for more information.\n * // also, we use a random group because we do NOT want work-balancing on gateway_send events.\n * const broker = new PubSubRedisBroker(new Redis(), { group: kUseRandomGroupName, name: 'send-consumer-1' });\n * const gateway = new WebSocketManager(gatewayOptionsHere); // see @discordjs/ws for examples.\n *\n * // emit events over the broker\n * gateway.on(WebSocketShardEvents.Dispatch, (...data) => void broker.publish(...RedisGateway.toPublishArgs(data)));\n *\n * // listen to payloads we should send to Discord\n * broker.on(RedisGateway.GatewaySendEvent, async ({ data: { payload, shardId }, ack }) => {\n * \tawait gateway.send(shardId, payload);\n * \tawait ack();\n * });\n * await broker.subscribe([RedisGateway.GatewaySendEvent]);\n * await gateway.connect();\n * ```\n *\n * ```ts\n * // other-service/index.ts\n * import { RedisGateway, PubSubRedisBroker, kUseRandomGroupName } from '@discordjs/brokers';\n * import Redis from 'ioredis';\n *\n * // the name here should absolutely be env-determined, see the main README for more information.\n * const broker = new PubSubRedisBroker(new Redis(), { group: 'my-service-name', name: 'service-name-instance-1' });\n * // unfortunately, we have to know the shard count. ideally this should be an env var\n * const gateway = new RedisGateway(broker, Number.parseInt(process.env.SHARD_COUNT, 10));\n *\n * const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);\n * const client = new Client({ rest, gateway });\n *\n * // set up your client as you normally would with core\n *\n * // subscribe to the events that you want\n * await gateway.init([GatewayDispatchEvents.GuildCreate, GatewayDispatchEvents.MessageCreate]);\n * ```\n */\nexport class RedisGateway\n\textends AsyncEventEmitter<{ dispatch: ManagerShardEventsMap[WebSocketShardEvents.Dispatch] }>\n\timplements Gateway\n{\n\t/**\n\t * Event used over the broker used to tell shards to send a payload to Discord.\n\t */\n\tpublic static readonly GatewaySendEvent = 'gateway_send' as const;\n\n\t/**\n\t * Converts a dispatch event from `@discordjs/ws` to arguments for a `broker.publish` call.\n\t */\n\tpublic static toPublishArgs(\n\t\tdata: ManagerShardEventsMap[WebSocketShardEvents.Dispatch],\n\t): [GatewayDispatchEvents, BrokerProps<GatewayDispatchPayload>] {\n\t\tconst [payload, shardId] = data;\n\t\treturn [payload.t, { shardId, payload }];\n\t}\n\n\tpublic constructor(\n\t\tprivate readonly broker: PubSubRedisBroker<RedisBrokerDiscordEvents>,\n\t\tprivate readonly shardCount: number,\n\t) {\n\t\tsuper();\n\t}\n\n\tpublic getShardCount(): number {\n\t\treturn this.shardCount;\n\t}\n\n\tpublic async send(shardId: number, payload: GatewaySendPayload): Promise<void> {\n\t\tawait this.broker.publish(RedisGateway.GatewaySendEvent, { payload, shardId });\n\t}\n\n\tpublic async init(events: GatewayDispatchEvents[]) {\n\t\tfor (const event of events) {\n\t\t\t// async_event_emitter nukes our types on this one.\n\t\t\tthis.broker.on(\n\t\t\t\tevent,\n\t\t\t\t({\n\t\t\t\t\tack,\n\t\t\t\t\tdata: { payload, shardId },\n\t\t\t\t}: {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/method-signature-style\n\t\t\t\t\tack: () => Promise<void>;\n\t\t\t\t\tdata: BrokerProps<GatewayDispatchPayload>;\n\t\t\t\t}) => {\n\t\t\t\t\tthis.emit('dispatch', payload, shardId);\n\t\t\t\t\tvoid ack();\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\tawait this.broker.subscribe(events);\n\t}\n}\n"
  },
  {
    "path": "packages/brokers/src/index.ts",
    "content": "export * from './brokers/redis/BaseRedis.js';\nexport * from './brokers/redis/PubSubRedis.js';\nexport * from './brokers/redis/RedisGateway.js';\nexport * from './brokers/redis/RPCRedis.js';\n\nexport * from './brokers/Broker.js';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/brokers#readme | @discordjs/brokers} version\n * that you are currently using.\n *\n * @privateRemarks This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild.\n */\nexport const version = '[VI]{{inject}}[/VI]' as string;\n"
  },
  {
    "path": "packages/brokers/tsconfig.docs.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.docs.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist-docs\"\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/brokers/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/brokers/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/brokers/tsconfig.test.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"noEmit\": true,\n\t\t\"skipLibCheck\": true\n\t},\n\t\"include\": [\"__tests__/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/brokers/tsup.config.ts",
    "content": "import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector';\nimport { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tesbuildPlugins: [esbuildPluginVersionInjector()],\n});\n"
  },
  {
    "path": "packages/builders/.cliff-jumperrc.json",
    "content": "{\n\t\"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n\t\"name\": \"builders\",\n\t\"org\": \"discordjs\",\n\t\"packagePath\": \"packages/builders\",\n\t\"identifierBase\": false\n}\n"
  },
  {
    "path": "packages/builders/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\ndist-docs\n\n# Docs\ndocs/**/*\n!docs/README.md\n!docs/examples/**/*\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/builders/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/builders/.prettierignore",
    "content": ".turbo\ncoverage\ndist\ndist-docs\ndocs/docs.api.json\nCHANGELOG.md\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/builders/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/builders/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n# [@discordjs/builders@1.11.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.10.1...@discordjs/builders@1.11.0) - (2025-04-25)\n\n## Features\n\n- Components v2 in builders v1 (#10787) ([118e682](https://github.com/discordjs/discord.js/commit/118e6826821b3b90f5923e40f167747e0658cfd1))\n\n# [@discordjs/builders@1.10.1](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.10.0...@discordjs/builders@1.10.1) - (2025-02-10)\n\n## Bug Fixes\n\n- **EmbedBuilder:** Allow empty `name` and `value` on fields (#10747) ([49ef3a8](https://github.com/discordjs/discord.js/commit/49ef3a833eab23d426d5c667e28aa493ddc9cb6c))\n\n# [@discordjs/builders@1.9.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.8.2...@discordjs/builders@1.9.0) - (2024-09-01)\n\n## Features\n\n- User-installable apps (#10227) ([fc0b6f7](https://github.com/discordjs/discord.js/commit/fc0b6f7f8ebd94a4a05fac0c76e49b23752a8e65))\n- **builders:** Update to @sapphire/shapeshift v4 (#10291) ([2d5531f](https://github.com/discordjs/discord.js/commit/2d5531f35c6b4d70f83e46b99c284030108dcf5c))\n- **SlashCommandBuilder:** Add explicit command type when building (#10395) ([b2970bb](https://github.com/discordjs/discord.js/commit/b2970bb2dddf70d2d918fda825059315f35d23f3))\n- Premium buttons (#10353) ([4f59b74](https://github.com/discordjs/discord.js/commit/4f59b740d01b9ff2213949708a36e17da32b89c3))\n- Add user-installable apps support  (#10348) ([9c76bbe](https://github.com/discordjs/discord.js/commit/9c76bbea172d49320f7fdac19ec1a43a49d05116))\n\n# [@discordjs/builders@1.8.2](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.8.1...@discordjs/builders@1.8.2) - (2024-06-02)\n\n## Bug Fixes\n\n- **SlashCommandBuilder:** Add missing shared properties (#10255) ([29fd89f](https://github.com/discordjs/discord.js/commit/29fd89f23c22ac5b4ce0a3ed34f5d27e28b1a0b8))\n\n## Documentation\n\n- **SelectMenuBuilder:** Correct grammatical errors  (#10309) ([aae2faf](https://github.com/discordjs/discord.js/commit/aae2faf9e923a268f84c8b7fb3283aea09dca586))\n- **TextInputBuilder:** Correct constructor documentation (#10308) ([c1e6890](https://github.com/discordjs/discord.js/commit/c1e6890132d5597a6ebd9d79383ec572582c0601))\n- **MappedComponentTypes:** Fix \"inpiut\" typo (#10306) ([29a50bb](https://github.com/discordjs/discord.js/commit/29a50bb476e8e84896dbaec96c6009589afaafbf))\n\n# [@discordjs/builders@1.8.1](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.8.0...@discordjs/builders@1.8.1) - (2024-05-05)\n\n## Bug Fixes\n\n- Slashcommand builder type split (#10253) ([07c1210](https://github.com/discordjs/discord.js/commit/07c12101e534fdce836a94bc571b53f75979ea86))\n- Don't mutate user provided array (#10014) ([7ea3638](https://github.com/discordjs/discord.js/commit/7ea3638dbcf38926596fb5da8b85040e70f1b98b))\n- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))\n\n## Documentation\n\n- Split docs.api.json into multiple json files ([597340f](https://github.com/discordjs/discord.js/commit/597340f288437c35da8c703d9b621274de60d880))\n\n## Features\n\n- **api-extractor:** Support `export * as ___` syntax (#10173) ([1c5de21](https://github.com/discordjs/discord.js/commit/1c5de21a2905fe21b54dea805013f089ed9000d0))\n- Allow RestOrArray for command option builders (#10175) ([a1a3a95](https://github.com/discordjs/discord.js/commit/a1a3a95c94194a8ab789d567a778b376e13ea973))\n- Local and preview detection ([79fbda3](https://github.com/discordjs/discord.js/commit/79fbda3aac6d4f0f8bfb193e797d09cbe331d315))\n\n## Refactor\n\n- Docs (#10126) ([18cce83](https://github.com/discordjs/discord.js/commit/18cce83d80598c430218775c53441b6b2ecdc776))\n- Make builders types great again (#10026) ([a0c83a2](https://github.com/discordjs/discord.js/commit/a0c83a254c21dad5ac14b649a95ded57d6678d95))\n\n# [@discordjs/builders@1.8.1](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.8.0...@discordjs/builders@1.8.1) - (2024-05-05)\n\n## Bug Fixes\n\n- Slashcommand builder type split (#10253) ([07c1210](https://github.com/discordjs/discord.js/commit/07c12101e534fdce836a94bc571b53f75979ea86))\n\n# [@discordjs/builders@1.8.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.7.0...@discordjs/builders@1.8.0) - (2024-05-04)\n\n## Bug Fixes\n\n- Don't mutate user provided array (#10014) ([7ea3638](https://github.com/discordjs/discord.js/commit/7ea3638dbcf38926596fb5da8b85040e70f1b98b))\n- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))\n\n## Documentation\n\n- Split docs.api.json into multiple json files ([597340f](https://github.com/discordjs/discord.js/commit/597340f288437c35da8c703d9b621274de60d880))\n\n## Features\n\n- **api-extractor:** Support `export * as ___` syntax (#10173) ([1c5de21](https://github.com/discordjs/discord.js/commit/1c5de21a2905fe21b54dea805013f089ed9000d0))\n- Allow RestOrArray for command option builders (#10175) ([a1a3a95](https://github.com/discordjs/discord.js/commit/a1a3a95c94194a8ab789d567a778b376e13ea973))\n- Local and preview detection ([79fbda3](https://github.com/discordjs/discord.js/commit/79fbda3aac6d4f0f8bfb193e797d09cbe331d315))\n\n## Refactor\n\n- Docs (#10126) ([18cce83](https://github.com/discordjs/discord.js/commit/18cce83d80598c430218775c53441b6b2ecdc776))\n- Make builders types great again (#10026) ([a0c83a2](https://github.com/discordjs/discord.js/commit/a0c83a254c21dad5ac14b649a95ded57d6678d95))\n\n# [@discordjs/builders@1.7.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.6.5...@discordjs/builders@1.7.0) - (2023-11-12)\n\n## Features\n\n- Default select menu values (#9867) ([4ff3ea4](https://github.com/discordjs/discord.js/commit/4ff3ea4a1bcb708973fbbbc84aaede1f7643e630))\n- Add media channels (#9662) ([571aedd](https://github.com/discordjs/discord.js/commit/571aedd58aeb5ac677f2a94a4a2851c4378a70b0))\n\n# [@discordjs/builders@1.6.5](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.6.4...@discordjs/builders@1.6.5) - (2023-08-17)\n\n## Documentation\n\n- Update Node.js requirement to 16.11.0 (#9764) ([188877c](https://github.com/discordjs/discord.js/commit/188877c50af70f0d5cffb246620fa277435c6ce6))\n\n# [@discordjs/builders@1.6.3](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.6.2...@discordjs/builders@1.6.3) - (2023-05-01)\n\n## Refactor\n\n- Remove `@discordjs/util` re-export (#9488) ([54ceedf](https://github.com/discordjs/discord.js/commit/54ceedf6c535d4641643d4106b6286cbef09de4a))\n\n# [@discordjs/builders@1.6.2](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.6.1...@discordjs/builders@1.6.2) - (2023-05-01)\n\n## Bug Fixes\n\n- **BaseSelectMenuBuilder:** Modify class to be `abstract` (#9358) ([ca4de2d](https://github.com/discordjs/discord.js/commit/ca4de2d9c6bc204e85d1b7eae7eabd23dbeb4475))\n- Correct `@link` tags that involve parents (#9351) ([fbbce3e](https://github.com/discordjs/discord.js/commit/fbbce3eb4ba20bc0c4806ca2259d1f86001594be))\n- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2))\n\n## Documentation\n\n- Reference package names properly (#9426) ([d6bca9b](https://github.com/discordjs/discord.js/commit/d6bca9bb4d976dc069a5039250db7d5b3e9142ef))\n- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9))\n- **builders:** Add some basic documentation (#9359) ([8073561](https://github.com/discordjs/discord.js/commit/8073561824f911d1a18d0b4f1de39f452bc69fa9))\n- Use `@link` in `@see` (#9348) ([d66d113](https://github.com/discordjs/discord.js/commit/d66d1133331b81563588db4500c63a18c3c3dfae))\n\n# [@discordjs/builders@1.6.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.5.0...@discordjs/builders@1.6.0) - (2023-04-01)\n\n## Bug Fixes\n\n- **scripts:** Accessing tsComment ([d8d5f31](https://github.com/discordjs/discord.js/commit/d8d5f31d3927fd1de62f1fa3a1a6e454243ad87b))\n\n## Features\n\n- **website:** Render syntax and mdx on the server (#9086) ([ee5169e](https://github.com/discordjs/discord.js/commit/ee5169e0aadd7bbfcd752aae614ec0f69602b68b))\n\n# [@discordjs/builders@1.5.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.4.0...@discordjs/builders@1.5.0) - (2023-03-12)\n\n## Documentation\n\n- **EmbedBuilder#spliceFields:** Fix a typo (#9159) ([4367ab9](https://github.com/discordjs/discord.js/commit/4367ab930227048868db3ed8437f6c4507ff32e1))\n- Fix version export (#9049) ([8b70f49](https://github.com/discordjs/discord.js/commit/8b70f497a1207e30edebdecd12b926c981c13d28))\n\n## Features\n\n- **website:** Add support for source file links (#9048) ([f6506e9](https://github.com/discordjs/discord.js/commit/f6506e99c496683ee0ab67db0726b105b929af38))\n- **StringSelectMenu:** Add `spliceOptions()` (#8937) ([a6941d5](https://github.com/discordjs/discord.js/commit/a6941d536ce24ed2b5446a154cbc886b2b97c63a))\n- Add support for nsfw commands (#7976) ([7a51344](https://github.com/discordjs/discord.js/commit/7a5134459c5f06864bf74631d83b96d9c21b72d8))\n- Add `@discordjs/formatters` (#8889) ([3fca638](https://github.com/discordjs/discord.js/commit/3fca638a8470dcea2f79ddb9f18526dbc0017c88))\n\n## Styling\n\n- Run prettier (#9041) ([2798ba1](https://github.com/discordjs/discord.js/commit/2798ba1eb3d734f0cf2eeccd2e16cfba6804873b))\n\n# [@discordjs/builders@1.4.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.3.0...@discordjs/builders@1.4.0) - (2022-11-28)\n\n## Bug Fixes\n\n- Pin @types/node version ([9d8179c](https://github.com/discordjs/discord.js/commit/9d8179c6a78e1c7f9976f852804055964d5385d4))\n\n## Features\n\n- New select menus (#8793) ([5152abf](https://github.com/discordjs/discord.js/commit/5152abf7285581abf7689e9050fdc56c4abb1e2b))\n- Allow punctuation characters in context menus (#8783) ([b521366](https://github.com/discordjs/discord.js/commit/b5213664fa66746daab1673ebe2adf2db3d1522c))\n\n## Typings\n\n- **Formatters:** Allow boolean in `formatEmoji` (#8823) ([ec37f13](https://github.com/discordjs/discord.js/commit/ec37f137fd4fca0fdbdb8a5c83abf32362a8f285))\n\n# [@discordjs/builders@1.3.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.2.0...@discordjs/builders@1.3.0) - (2022-10-08)\n\n## Bug Fixes\n\n- Allow adding forums to `channelTypes` (#8658) ([b1e190c](https://github.com/discordjs/discord.js/commit/b1e190c4f0773a1a739625f5b41026f593515370))\n- **SlashCommandBuilder:** Missing methods in subcommand builder (#8583) ([1c5b78f](https://github.com/discordjs/discord.js/commit/1c5b78fd2130f09c951459cf4c2d637f46c3c2c9))\n- Footer / sidebar / deprecation alert ([ba3e0ed](https://github.com/discordjs/discord.js/commit/ba3e0ed348258fe8e51eefb4aa7379a1230616a9))\n\n## Documentation\n\n- **builders/components:** Document constructors (#8636) ([8444576](https://github.com/discordjs/discord.js/commit/8444576f45da5fdddbf8ba2d91b4cb31a3b51c04))\n- Change name (#8604) ([dd5a089](https://github.com/discordjs/discord.js/commit/dd5a08944c258a847fc4377f1d5e953264ab47d0))\n- Use remarks instead of `Note` in descriptions (#8597) ([f3ce4a7](https://github.com/discordjs/discord.js/commit/f3ce4a75d0c4eafc89a1f0ce9f4964bcbcdae6da))\n\n## Features\n\n- Web-components (#8715) ([0ac3e76](https://github.com/discordjs/discord.js/commit/0ac3e766bd9dbdeb106483fa4bb085d74de346a2))\n- Add `@discordjs/util` (#8591) ([b2ec865](https://github.com/discordjs/discord.js/commit/b2ec865765bf94181473864a627fb63ea8173fd3))\n- Add `chatInputApplicationCommandMention` formatter (#8546) ([d08a57c](https://github.com/discordjs/discord.js/commit/d08a57cadd9d69a734077cc1902d931ab10336db))\n\n## Refactor\n\n- Replace usage of deprecated `ChannelType`s (#8625) ([669c3cd](https://github.com/discordjs/discord.js/commit/669c3cd2566eac68ef38ab522dd6378ba761e8b3))\n- Website components (#8600) ([c334157](https://github.com/discordjs/discord.js/commit/c3341570d983aea9ecc419979d5a01de658c9d67))\n- Use `eslint-config-neon` for packages. (#8579) ([edadb9f](https://github.com/discordjs/discord.js/commit/edadb9fe5dfd9ff51a3cfc9b25cb242d3f9f5241))\n\n## Testing\n\n- Rename incorrect test (#8596) ([ce991dd](https://github.com/discordjs/discord.js/commit/ce991dd1d883f6785b5f4b4b3ac80ef21cb304e7))\n\n## Typings\n\n- **interactions:** Fix `{Slash,ContextMenu}CommandBuilder#toJSON` (#8568) ([b7eb96d](https://github.com/discordjs/discord.js/commit/b7eb96d45670616521fbcca28a657793d91605c7))\n\n# [@discordjs/builders@1.2.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.1.0...@discordjs/builders@1.2.0) - (2022-08-22)\n\n## Features\n\n- **website:** Show `constructor` information (#8540) ([e42fd16](https://github.com/discordjs/discord.js/commit/e42fd1636973b10dd7ed6fb4280ee1a4a8f82007))\n- **website:** Show descriptions for `@typeParam` blocks (#8523) ([e475b63](https://github.com/discordjs/discord.js/commit/e475b63f257f6261d73cb89fee9ecbcdd84e2a6b))\n- **website:** Show parameter descriptions (#8519) ([7f415a2](https://github.com/discordjs/discord.js/commit/7f415a2502bf7ce2025dbcfed9017b0635a19966))\n- **WebSocketShard:** Support new resume url (#8480) ([bc06cc6](https://github.com/discordjs/discord.js/commit/bc06cc638d2f57ab5c600e8cdb6afc8eb2180166))\n\n## Refactor\n\n- Docs design (#8487) ([4ab1d09](https://github.com/discordjs/discord.js/commit/4ab1d09997a18879a9eb9bda39df6f15aa22557e))\n\n# [@discordjs/builders@1.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.16.0...@discordjs/builders@1.1.0) - (2022-07-29)\n\n## Bug Fixes\n\n- Use proper format for `@link` text (#8384) ([2655639](https://github.com/discordjs/discord.js/commit/26556390a3800e954974a00c1328ff47d3e67e9a))\n- **Formatters:** Add newline in `codeBlock` (#8369) ([5d8bd03](https://github.com/discordjs/discord.js/commit/5d8bd030d60ef364de3ef5f9963da8bda5c4efd4))\n- **selectMenu:** Allow json to be used for select menu options (#8322) ([6a2d0d8](https://github.com/discordjs/discord.js/commit/6a2d0d8e96d157d5b85cee7f17bffdfff4240074))\n\n## Documentation\n\n- Use link tags (#8382) ([5494791](https://github.com/discordjs/discord.js/commit/549479131318c659f86f0eb18578d597e22522d3))\n\n## Features\n\n- Add channel & message URL formatters (#8371) ([a7deb8f](https://github.com/discordjs/discord.js/commit/a7deb8f89830ead6185c5fb46a49688b6d209ed1))\n\n## Testing\n\n- **builders:** Improve coverage (#8274) ([b7e6238](https://github.com/discordjs/discord.js/commit/b7e62380f2e6b9324d6bba9b9eaa5315080bf66a))\n\n# [@discordjs/builders@0.16.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.15.0...@discordjs/builders@0.16.0) - (2022-07-17)\n\n## Bug Fixes\n\n- Slash command name regex (#8265) ([32f9056](https://github.com/discordjs/discord.js/commit/32f9056b15edede3bab07de96afb4b56d3a9ecca))\n- **TextInputBuilder:** Parse `custom_id`, `label`, and `style` (#8216) ([2d9dfa3](https://github.com/discordjs/discord.js/commit/2d9dfa3c6ea4bb972da2f7e088d148b798c866d9))\n\n## Documentation\n\n- Add codecov coverage badge to readmes (#8226) ([f6db285](https://github.com/discordjs/discord.js/commit/f6db285c073898a749fe4591cbd4463d1896daf5))\n\n## Features\n\n- **builder:** Add max min length in string option (#8214) ([96c8d21](https://github.com/discordjs/discord.js/commit/96c8d21f95eb366c46ae23505ba9054f44821b25))\n- Codecov (#8219) ([f10f4cd](https://github.com/discordjs/discord.js/commit/f10f4cdcd88ca6be7ec735ed3a415ba13da83db0))\n- **docgen:** Update typedoc ([b3346f4](https://github.com/discordjs/discord.js/commit/b3346f4b9b3d4f96443506643d4631dc1c6d7b21))\n- Website (#8043) ([127931d](https://github.com/discordjs/discord.js/commit/127931d1df7a2a5c27923c2f2151dbf3824e50cc))\n- **docgen:** Typescript support ([3279b40](https://github.com/discordjs/discord.js/commit/3279b40912e6aa61507bedb7db15a2b8668de44b))\n- Docgen package (#8029) ([8b979c0](https://github.com/discordjs/discord.js/commit/8b979c0245c42fd824d8e98745ee869f5360fc86))\n\n## Refactor\n\n- **builder:** Remove `unsafe*Builder`s (#8074) ([a4d1862](https://github.com/discordjs/discord.js/commit/a4d18629828234f43f03d1bd4851d4b727c6903b))\n- Remove @sindresorhus/is as it's now esm only (#8133) ([c6f285b](https://github.com/discordjs/discord.js/commit/c6f285b7b089b004776fbeb444fe973a68d158d8))\n- Move all the config files to root (#8033) ([769ea0b](https://github.com/discordjs/discord.js/commit/769ea0bfe78c4f1d413c6b397c604ffe91e39c6a))\n\n## Typings\n\n- Remove expect error (#8242) ([7e6dbaa](https://github.com/discordjs/discord.js/commit/7e6dbaaed900c07d1a04e23bbbf9cd0d1b0501c5))\n- **builder:** Remove casting (#8241) ([8198da5](https://github.com/discordjs/discord.js/commit/8198da5cd0898e06954615a2287853321e7ebbd4))\n\n# [@discordjs/builders@0.15.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.14.0...@discordjs/builders@0.15.0) - (2022-06-06)\n\n## Features\n\n- Allow builders to accept rest params and arrays (#7874) ([ad75be9](https://github.com/discordjs/discord.js/commit/ad75be9a9cf90c8624495df99b75177e6c24022f))\n- Use vitest instead of jest for more speed ([8d8e6c0](https://github.com/discordjs/discord.js/commit/8d8e6c03decd7352a2aa180f6e5bc1a13602539b))\n- Add scripts package for locally used scripts ([f2ae1f9](https://github.com/discordjs/discord.js/commit/f2ae1f9348bfd893332a9060f71a8a5f272a1b8b))\n\n# [@discordjs/builders@0.14.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.7.0...@discordjs/builders@0.14.0) - (2022-06-04)\n\n## Bug Fixes\n\n- **builders:** Leftover invalid null type ([8a7cd10](https://github.com/discordjs/discord.js/commit/8a7cd10554a2a71cd2fe7f6a177b5f4f43464348))\n- **SlashCommandBuilder:** Import `Permissions` correctly (#7921) ([7ce641d](https://github.com/discordjs/discord.js/commit/7ce641d33a4af6586d5e7beffbe7d38619dcf1a2))\n- Add localizations for subcommand builders and option choices (#7862) ([c1b5e73](https://github.com/discordjs/discord.js/commit/c1b5e731daa9cbbfca03a046e47cb1221ee1ed7c))\n\n## Features\n\n- Export types from `interactions/slashCommands/mixins` (#7942) ([68d5169](https://github.com/discordjs/discord.js/commit/68d5169f66c96f8fe5be17a1c01cdd5155607ab2))\n- **builders:** Add new command permissions v2 (#7861) ([de3f157](https://github.com/discordjs/discord.js/commit/de3f1573f07dda294cc0fbb1ca4b659eb2388a12))\n- **builders:** Improve embed errors and predicates (#7795) ([ec8d87f](https://github.com/discordjs/discord.js/commit/ec8d87f93272cc9987f9613735c0361680c4ed1e))\n\n## Refactor\n\n- Use arrays instead of rest parameters for builders (#7759) ([29293d7](https://github.com/discordjs/discord.js/commit/29293d7bbb5ed463e52e5a5853817e5a09cf265b))\n\n## Styling\n\n- Cleanup tests and tsup configs ([6b8ef20](https://github.com/discordjs/discord.js/commit/6b8ef20cb3af5b5cfd176dd0aa0a1a1e98551629))\n\n# [@discordjs/builders@0.13.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.12.0...@discordjs/builders@0.13.0) - (2022-04-17)\n\n## Bug Fixes\n\n- Validate select menu options (#7566) ([b1d63d9](https://github.com/discordjs/discord.js/commit/b1d63d919a61f309ac89f27016b0f148678dac2b))\n- **SelectMenu:** Set `placeholder` max to 150 (#7538) ([dcd4797](https://github.com/discordjs/discord.js/commit/dcd479767b6ec980a373f2ea1f22754f41661c1e))\n- Only check `instanceof Component` once (#7546) ([0aa4851](https://github.com/discordjs/discord.js/commit/0aa48516a4e33497e8e8dc50da164a57cdee09d3))\n- **builders:** Allow negative min/max value of number/integer option (#7484) ([3baa340](https://github.com/discordjs/discord.js/commit/3baa340821b8ecf8a16253bc0917a1033250d7c9))\n- **components:** SetX should take rest parameters (#7461) ([3617359](https://github.com/discordjs/discord.js/commit/36173590a712f041b087b7882054805a8bd42dae))\n- Unsafe embed builder field normalization (#7418) ([b936103](https://github.com/discordjs/discord.js/commit/b936103395121cb21a8c616f669ddab1d2efb0f1))\n- Fix some typos (#7393) ([92a04f4](https://github.com/discordjs/discord.js/commit/92a04f4d98f6c6760214034cc8f5a1eaa78893c7))\n- **builders:** Make type optional in constructor (#7391) ([4abb28c](https://github.com/discordjs/discord.js/commit/4abb28c0a1256c57a60369a6b8ec9e98c265b489))\n- Don't create new instances of builders classes (#7343) ([d6b56d0](https://github.com/discordjs/discord.js/commit/d6b56d0080c4c5f8ace731f1e8bcae0c9d3fb5a5))\n\n## Documentation\n\n- Completely fix builders example link (#7543) ([1a14c0c](https://github.com/discordjs/discord.js/commit/1a14c0ca562ea173d363a770a0437209f461fd23))\n- Add slash command builders example, fixes #7338 (#7339) ([3ae6f3c](https://github.com/discordjs/discord.js/commit/3ae6f3c313091151245d6e6b52337b459ecfc765))\n\n## Features\n\n- Slash command localization for builders (#7683) ([40b9a1d](https://github.com/discordjs/discord.js/commit/40b9a1d67d0b508ec593e030913acd8161cd17f8))\n- Add API v10 support (#7477) ([72577c4](https://github.com/discordjs/discord.js/commit/72577c4bfd02524a27afb6ff4aebba9301a690d3))\n- Add support for module: NodeNext in TS and ESM (#7598) ([8f1986a](https://github.com/discordjs/discord.js/commit/8f1986a6aa98365e09b00e84ad5f9f354ab61f3d))\n- Add Modals and Text Inputs (#7023) ([ed92015](https://github.com/discordjs/discord.js/commit/ed920156344233241a21b0c0b99736a3a855c23c))\n- Add missing `v13` component methods (#7466) ([f7257f0](https://github.com/discordjs/discord.js/commit/f7257f07655076eabfe355cb6a53260b39ca9670))\n- **builders:** Add attachment command option type (#7203) ([ae0f35f](https://github.com/discordjs/discord.js/commit/ae0f35f51d68dfa5a7dc43d161ef9365171debdb))\n- **components:** Add unsafe message component builders (#7387) ([6b6222b](https://github.com/discordjs/discord.js/commit/6b6222bf513d1ee8cd98fba0ad313def560b864f))\n- **embed:** Add setFields (#7322) ([bcc5cda](https://github.com/discordjs/discord.js/commit/bcc5cda8a902ddb28c7e3578e0f29b4272832624))\n\n## Refactor\n\n- Remove nickname parsing (#7736) ([78a3afc](https://github.com/discordjs/discord.js/commit/78a3afcd7fdac358e06764cc0d675e1215c785f3))\n- Replace zod with shapeshift (#7547) ([3c0bbac](https://github.com/discordjs/discord.js/commit/3c0bbac82fa9988af4a62ff00c66d149fbe6b921))\n- Remove store channels (#7634) ([aedddb8](https://github.com/discordjs/discord.js/commit/aedddb875e740e1f1bd77f06ce1b361fd3b7bc36))\n- Allow builders to accept emoji strings (#7616) ([fb9a9c2](https://github.com/discordjs/discord.js/commit/fb9a9c221121ee1c7986f9c775b77b9691a0ae15))\n- Don't return builders from API data (#7584) ([549716e](https://github.com/discordjs/discord.js/commit/549716e4fcec89ca81216a6d22aa8e623175e37a))\n- Remove obsolete builder methods (#7590) ([10607db](https://github.com/discordjs/discord.js/commit/10607dbdafe257c5cbf5b952b7eecec4919e8b4a))\n- **Embed:** Remove add field (#7522) ([8478d2f](https://github.com/discordjs/discord.js/commit/8478d2f4de9ac013733850cbbc67902f7c5abc55))\n- Make `data` public in builders (#7486) ([ba31203](https://github.com/discordjs/discord.js/commit/ba31203a0ad96e0a00f8312c397889351e4c5cfd))\n- **embed:** Remove array support in favor of rest params (#7498) ([b3fa2ec](https://github.com/discordjs/discord.js/commit/b3fa2ece402839008738ad3adce3db958445838d))\n- **components:** Default set boolean methods to true (#7502) ([b122149](https://github.com/discordjs/discord.js/commit/b12214922cea2f43afbe6b1555a74a3c8e16f798))\n- Make public builder props getters (#7422) ([e8252ed](https://github.com/discordjs/discord.js/commit/e8252ed3b981a4b7e4013f12efadd2f5d9318d3e))\n- **builders-methods:** Make methods consistent (#7395) ([f495364](https://github.com/discordjs/discord.js/commit/f4953647ff9f39127978c73bf8a62c08462802ca))\n- Remove conditional autocomplete option return types (#7396) ([0909824](https://github.com/discordjs/discord.js/commit/09098240bfb13b8afafa4ab549f06d236e0ff1c9))\n- **embed:** Mark properties as readonly (#7332) ([31768fc](https://github.com/discordjs/discord.js/commit/31768fcd69ed5b4566a340bda89ce881418e8272))\n\n## Typings\n\n- Fix regressions (#7649) ([5748dbe](https://github.com/discordjs/discord.js/commit/5748dbe08783beb80c526de38ccd105eb0e82664))\n\n# [@discordjs/builders@0.12.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.11.0...@discordjs/builders@0.12.0) - (2022-01-24)\n\n## Bug Fixes\n\n- **builders:** Dont export `Button` component stuff twice (#7289) ([86d9d06](https://github.com/discordjs/discord.js/commit/86d9d0674347c08d056cd054cb4ce4253195bf94))\n\n## Documentation\n\n- **SlashCommandSubcommands:** Updating old links from Discord developer portal (#7224) ([bd7a6f2](https://github.com/discordjs/discord.js/commit/bd7a6f265212624199fb0b2ddc8ece39759c63de))\n\n## Features\n\n- Add components to /builders (#7195) ([2bb40fd](https://github.com/discordjs/discord.js/commit/2bb40fd767cf5918e3ba422ff73082734bfa05b0))\n\n## Typings\n\n- Make `required` a boolean (#7307) ([c10afea](https://github.com/discordjs/discord.js/commit/c10afeadc702ab98bec5e077b3b92494a9596f9c))\n"
  },
  {
    "path": "packages/builders/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2021 Noel Buechler\n   Copyright 2021 Vlad Frangu\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/builders/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/builders\"><img src=\"https://img.shields.io/npm/v/@discordjs/builders.svg?maxAge=3600\" alt=\"npm version\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/builders\"><img src=\"https://img.shields.io/npm/dt/@discordjs/builders.svg?maxAge=3600\" alt=\"npm downloads\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/commits/main/packages/builders\"><img alt=\"Last commit.\" src=\"https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fbuilders\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t\t<a href=\"https://codecov.io/gh/discordjs/discord.js\"><img src=\"https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=builders\" alt=\"Code coverage\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## About\n\n`@discordjs/builders` is a utility package for easily building Discord API payloads.\n\n## Installation\n\n**Node.js 22.12.0 or newer is required.**\n\n```sh\nnpm install @discordjs/builders\nyarn add @discordjs/builders\npnpm add @discordjs/builders\n```\n\n## Examples\n\nYou can find examples of how to use the builders in the [Slash Command Builders][example] examples.\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Documentation][documentation]\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [npm][npm]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the\n[documentation][documentation].  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[example]: https://github.com/discordjs/discord.js/blob/main/packages/builders/docs/examples/Slash%20Command%20Builders.md\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs/packages/builders/stable\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/builders\n[npm]: https://www.npmjs.com/package/@discordjs/builders\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/builders/__tests__/components/actionRow.test.ts",
    "content": "import {\n\tButtonStyle,\n\tComponentType,\n\ttype APIActionRowComponent,\n\ttype APIComponentInMessageActionRow,\n} from 'discord-api-types/v10';\nimport { describe, test, expect } from 'vitest';\nimport {\n\tActionRowBuilder,\n\tcreateComponentBuilder,\n\tPrimaryButtonBuilder,\n\tStringSelectMenuBuilder,\n\tStringSelectMenuOptionBuilder,\n} from '../../src/index.js';\n\nconst rowWithButtonData: APIActionRowComponent<APIComponentInMessageActionRow> = {\n\ttype: ComponentType.ActionRow,\n\tcomponents: [\n\t\t{\n\t\t\ttype: ComponentType.Button,\n\t\t\tlabel: 'test',\n\t\t\tcustom_id: '123',\n\t\t\tstyle: ButtonStyle.Primary,\n\t\t},\n\t],\n};\n\nconst rowWithSelectMenuData: APIActionRowComponent<APIComponentInMessageActionRow> = {\n\ttype: ComponentType.ActionRow,\n\tcomponents: [\n\t\t{\n\t\t\ttype: ComponentType.StringSelect,\n\t\t\tcustom_id: '1234',\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tlabel: 'one',\n\t\t\t\t\tvalue: 'one',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: 'two',\n\t\t\t\t\tvalue: 'two',\n\t\t\t\t},\n\t\t\t],\n\t\t\tmax_values: 2,\n\t\t\tmin_values: 2,\n\t\t},\n\t],\n};\n\ndescribe('Action Row Components', () => {\n\tdescribe('Assertion Tests', () => {\n\t\ttest('GIVEN valid JSON input THEN valid JSON output is given', () => {\n\t\t\tconst actionRowData: APIActionRowComponent<APIComponentInMessageActionRow> = {\n\t\t\t\ttype: ComponentType.ActionRow,\n\t\t\t\tcomponents: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: ComponentType.Button,\n\t\t\t\t\t\tlabel: 'button',\n\t\t\t\t\t\tstyle: ButtonStyle.Primary,\n\t\t\t\t\t\tcustom_id: 'test',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: ComponentType.Button,\n\t\t\t\t\t\tlabel: 'link',\n\t\t\t\t\t\tstyle: ButtonStyle.Link,\n\t\t\t\t\t\turl: 'https://google.com',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\n\t\t\texpect(new ActionRowBuilder(actionRowData).toJSON()).toEqual(actionRowData);\n\t\t\texpect(() => createComponentBuilder({ type: ComponentType.ActionRow, components: [] })).not.toThrowError();\n\t\t});\n\n\t\ttest('GIVEN valid builder options THEN valid JSON output is given', () => {\n\t\t\tconst rowWithButtonData: APIActionRowComponent<APIComponentInMessageActionRow> = {\n\t\t\t\ttype: ComponentType.ActionRow,\n\t\t\t\tcomponents: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: ComponentType.Button,\n\t\t\t\t\t\tlabel: 'test',\n\t\t\t\t\t\tcustom_id: '123',\n\t\t\t\t\t\tstyle: ButtonStyle.Primary,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\n\t\t\tconst rowWithSelectMenuData: APIActionRowComponent<APIComponentInMessageActionRow> = {\n\t\t\t\ttype: ComponentType.ActionRow,\n\t\t\t\tcomponents: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: ComponentType.StringSelect,\n\t\t\t\t\t\tcustom_id: '1234',\n\t\t\t\t\t\toptions: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlabel: 'one',\n\t\t\t\t\t\t\t\tvalue: 'one',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlabel: 'two',\n\t\t\t\t\t\t\t\tvalue: 'two',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tmax_values: 1,\n\t\t\t\t\t\tmin_values: 1,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\n\t\t\texpect(new ActionRowBuilder(rowWithButtonData).toJSON()).toEqual(rowWithButtonData);\n\t\t\texpect(new ActionRowBuilder(rowWithSelectMenuData).toJSON()).toEqual(rowWithSelectMenuData);\n\t\t\texpect(() => createComponentBuilder({ type: ComponentType.ActionRow, components: [] })).not.toThrowError();\n\t\t});\n\n\t\ttest('GIVEN valid builder options THEN valid JSON output is given 2', () => {\n\t\t\tconst button = new PrimaryButtonBuilder().setLabel('test').setCustomId('123');\n\t\t\tconst selectMenu = new StringSelectMenuBuilder()\n\t\t\t\t.setCustomId('1234')\n\t\t\t\t.setMaxValues(2)\n\t\t\t\t.setMinValues(2)\n\t\t\t\t.setOptions(\n\t\t\t\t\tnew StringSelectMenuOptionBuilder().setLabel('one').setValue('one'),\n\t\t\t\t\tnew StringSelectMenuOptionBuilder().setLabel('two').setValue('two'),\n\t\t\t\t)\n\t\t\t\t.setOptions([\n\t\t\t\t\tnew StringSelectMenuOptionBuilder().setLabel('one').setValue('one'),\n\t\t\t\t\tnew StringSelectMenuOptionBuilder().setLabel('two').setValue('two'),\n\t\t\t\t]);\n\n\t\t\texpect(new ActionRowBuilder().addPrimaryButtonComponents(button).toJSON()).toEqual(rowWithButtonData);\n\t\t\texpect(new ActionRowBuilder().addStringSelectMenuComponent(selectMenu).toJSON()).toEqual(rowWithSelectMenuData);\n\t\t\texpect(new ActionRowBuilder().addPrimaryButtonComponents([button]).toJSON()).toEqual(rowWithButtonData);\n\t\t});\n\n\t\ttest('GIVEN 2 select menus THEN it throws', () => {\n\t\t\tconst selectMenu = new StringSelectMenuBuilder()\n\t\t\t\t.setCustomId('1234')\n\t\t\t\t.setOptions(\n\t\t\t\t\tnew StringSelectMenuOptionBuilder().setLabel('one').setValue('one'),\n\t\t\t\t\tnew StringSelectMenuOptionBuilder().setLabel('two').setValue('two'),\n\t\t\t\t);\n\n\t\t\texpect(() =>\n\t\t\t\tnew ActionRowBuilder()\n\t\t\t\t\t.addStringSelectMenuComponent(selectMenu)\n\t\t\t\t\t.addStringSelectMenuComponent(selectMenu)\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrowError();\n\t\t});\n\n\t\ttest('GIVEN a button and a select menu THEN it throws', () => {\n\t\t\tconst button = new PrimaryButtonBuilder().setLabel('test').setCustomId('123');\n\t\t\tconst selectMenu = new StringSelectMenuBuilder()\n\t\t\t\t.setCustomId('1234')\n\t\t\t\t.setOptions(\n\t\t\t\t\tnew StringSelectMenuOptionBuilder().setLabel('one').setValue('one'),\n\t\t\t\t\tnew StringSelectMenuOptionBuilder().setLabel('two').setValue('two'),\n\t\t\t\t);\n\n\t\t\texpect(() =>\n\t\t\t\tnew ActionRowBuilder().addStringSelectMenuComponent(selectMenu).addPrimaryButtonComponents(button).toJSON(),\n\t\t\t).toThrowError();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/components/button.test.ts",
    "content": "import {\n\tButtonStyle,\n\tComponentType,\n\ttype APIButtonComponentWithCustomId,\n\ttype APIButtonComponentWithURL,\n} from 'discord-api-types/v10';\nimport { describe, test, expect } from 'vitest';\nimport {\n\tPrimaryButtonBuilder,\n\tPremiumButtonBuilder,\n\tLinkButtonBuilder,\n\tDangerButtonBuilder,\n\tSecondaryButtonBuilder,\n} from '../../src/index.js';\n\nconst longStr =\n\t'looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong';\n\ndescribe('Button Components', () => {\n\tdescribe('Assertion Tests', () => {\n\t\ttest('GIVEN valid fields THEN builder does not throw', () => {\n\t\t\texpect(() => new PrimaryButtonBuilder().setCustomId('custom').setLabel('test').toJSON()).not.toThrowError();\n\n\t\t\texpect(() => {\n\t\t\t\tconst button = new PrimaryButtonBuilder()\n\t\t\t\t\t.setCustomId('custom')\n\t\t\t\t\t.setLabel('test')\n\t\t\t\t\t.setDisabled(true)\n\t\t\t\t\t.setEmoji({ name: 'test' });\n\n\t\t\t\tbutton.toJSON();\n\t\t\t}).not.toThrowError();\n\n\t\t\texpect(() => {\n\t\t\t\tconst button = new SecondaryButtonBuilder().setCustomId('custom').setLabel('a'.repeat(80));\n\t\t\t\tbutton.toJSON();\n\t\t\t}).not.toThrowError();\n\n\t\t\texpect(() => {\n\t\t\t\tconst button = new DangerButtonBuilder().setCustomId('custom').setEmoji({ name: 'ok' });\n\t\t\t\tbutton.toJSON();\n\t\t\t}).not.toThrowError();\n\n\t\t\texpect(() => {\n\t\t\t\tconst button = new LinkButtonBuilder().setURL('https://discord.js.org').setLabel('a'.repeat(80));\n\t\t\t\tbutton.toJSON();\n\t\t\t}).not.toThrowError();\n\n\t\t\texpect(() => {\n\t\t\t\tconst button = new LinkButtonBuilder().setURL('https://discord.js.org').setEmoji({ name: 'ok' });\n\t\t\t\tbutton.toJSON();\n\t\t\t}).not.toThrowError();\n\n\t\t\texpect(() => {\n\t\t\t\tconst button = new PremiumButtonBuilder().setSKUId('123456789012345678');\n\t\t\t\tbutton.toJSON();\n\t\t\t}).not.toThrowError();\n\n\t\t\texpect(() => new LinkButtonBuilder().setLabel('label').setURL('https://google.com').toJSON()).not.toThrowError();\n\t\t});\n\n\t\ttest('GIVEN invalid fields THEN build does throw', () => {\n\t\t\texpect(() => {\n\t\t\t\tnew PrimaryButtonBuilder().setCustomId(longStr).toJSON();\n\t\t\t}).toThrowError();\n\n\t\t\texpect(() => {\n\t\t\t\t// @ts-expect-error: Invalid emoji\n\t\t\t\tconst button = new PrimaryButtonBuilder().setEmoji('test');\n\t\t\t\tbutton.toJSON();\n\t\t\t}).toThrowError();\n\n\t\t\texpect(() => {\n\t\t\t\tconst button = new PrimaryButtonBuilder();\n\t\t\t\tbutton.toJSON();\n\t\t\t}).toThrowError();\n\n\t\t\texpect(() => {\n\t\t\t\tconst button = new PrimaryButtonBuilder().setCustomId('test');\n\t\t\t\tbutton.toJSON();\n\t\t\t}).toThrowError();\n\n\t\t\t// @ts-expect-error: Invalid style\n\t\t\texpect(() => new PrimaryButtonBuilder().setCustomId('hi').setStyle(24).toJSON()).toThrowError();\n\t\t\texpect(() => new PrimaryButtonBuilder().setCustomId('hi').setLabel(longStr).toJSON()).toThrowError();\n\t\t\t// @ts-expect-error: Invalid parameter for disabled\n\t\t\texpect(() => new PrimaryButtonBuilder().setCustomId('hi').setDisabled(0).toJSON()).toThrowError();\n\t\t\t// @ts-expect-error: Invalid emoji\n\t\t\texpect(() => new PrimaryButtonBuilder().setCustomId('hi').setEmoji('foo').toJSON()).toThrowError();\n\n\t\t\texpect(() =>\n\t\t\t\tnew LinkButtonBuilder()\n\t\t\t\t\t.setLabel('label')\n\t\t\t\t\t.setURL(`https://google.com/${'a'.repeat(512)}`)\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrowError();\n\t\t});\n\n\t\ttest('GiVEN valid input THEN valid JSON outputs are given', () => {\n\t\t\tconst interactionData: APIButtonComponentWithCustomId = {\n\t\t\t\ttype: ComponentType.Button,\n\t\t\t\tcustom_id: 'test',\n\t\t\t\tlabel: 'test',\n\t\t\t\tstyle: ButtonStyle.Primary,\n\t\t\t\tdisabled: true,\n\t\t\t};\n\n\t\t\texpect(new PrimaryButtonBuilder(interactionData).toJSON()).toEqual(interactionData);\n\n\t\t\texpect(\n\t\t\t\tnew PrimaryButtonBuilder()\n\t\t\t\t\t.setCustomId(interactionData.custom_id)\n\t\t\t\t\t.setLabel(interactionData.label!)\n\t\t\t\t\t.setDisabled(interactionData.disabled)\n\t\t\t\t\t.toJSON(),\n\t\t\t).toEqual(interactionData);\n\n\t\t\tconst linkData: APIButtonComponentWithURL = {\n\t\t\t\ttype: ComponentType.Button,\n\t\t\t\tlabel: 'test',\n\t\t\t\tstyle: ButtonStyle.Link,\n\t\t\t\tdisabled: true,\n\t\t\t\turl: 'https://google.com',\n\t\t\t};\n\n\t\t\texpect(new LinkButtonBuilder(linkData).toJSON()).toEqual(linkData);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/components/components.test.ts",
    "content": "import {\n\tButtonStyle,\n\tComponentType,\n\tTextInputStyle,\n\ttype APIButtonComponent,\n\ttype APISelectMenuComponent,\n\ttype APITextInputComponent,\n\ttype APIActionRowComponent,\n\ttype APIComponentInMessageActionRow,\n} from 'discord-api-types/v10';\nimport { describe, test, expect } from 'vitest';\nimport {\n\tActionRowBuilder,\n\tcreateComponentBuilder,\n\tCustomIdButtonBuilder,\n\tStringSelectMenuBuilder,\n\tTextInputBuilder,\n} from '../../src/index.js';\n\ndescribe('createComponentBuilder', () => {\n\ttest.each([StringSelectMenuBuilder, TextInputBuilder])(\n\t\t'passing an instance of %j should return itself',\n\t\t(Builder) => {\n\t\t\tconst builder = new Builder();\n\t\t\texpect(createComponentBuilder(builder)).toBe(builder);\n\t\t},\n\t);\n\n\ttest('GIVEN an action row component THEN returns a ActionRowBuilder', () => {\n\t\tconst actionRow: APIActionRowComponent<APIComponentInMessageActionRow> = {\n\t\t\tcomponents: [],\n\t\t\ttype: ComponentType.ActionRow,\n\t\t};\n\n\t\texpect(createComponentBuilder(actionRow)).toBeInstanceOf(ActionRowBuilder);\n\t});\n\n\ttest('GIVEN a button component THEN returns a ButtonBuilder', () => {\n\t\tconst button: APIButtonComponent = {\n\t\t\tcustom_id: 'abc',\n\t\t\tstyle: ButtonStyle.Primary,\n\t\t\ttype: ComponentType.Button,\n\t\t};\n\n\t\texpect(createComponentBuilder(button)).toBeInstanceOf(CustomIdButtonBuilder);\n\t});\n\n\ttest('GIVEN a select menu component THEN returns a StringSelectMenuBuilder', () => {\n\t\tconst selectMenu: APISelectMenuComponent = {\n\t\t\tcustom_id: 'abc',\n\t\t\toptions: [],\n\t\t\ttype: ComponentType.StringSelect,\n\t\t};\n\n\t\texpect(createComponentBuilder(selectMenu)).toBeInstanceOf(StringSelectMenuBuilder);\n\t});\n\n\ttest('GIVEN a text input component THEN returns a TextInputBuilder', () => {\n\t\tconst textInput: APITextInputComponent = {\n\t\t\tcustom_id: 'abc',\n\t\t\tlabel: 'abc',\n\t\t\tstyle: TextInputStyle.Short,\n\t\t\ttype: ComponentType.TextInput,\n\t\t};\n\n\t\texpect(createComponentBuilder(textInput)).toBeInstanceOf(TextInputBuilder);\n\t});\n\n\ttest('GIVEN an unknown component type THEN throws error', () => {\n\t\t// @ts-expect-error: Unknown component type\n\t\texpect(() => createComponentBuilder({ type: 'invalid' })).toThrowError();\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/components/fileUpload.test.ts",
    "content": "import type { APIFileUploadComponent } from 'discord-api-types/v10';\nimport { ComponentType } from 'discord-api-types/v10';\nimport { describe, test, expect } from 'vitest';\nimport { FileUploadBuilder } from '../../src/components/fileUpload/FileUpload.js';\n\nconst fileUploadComponent = () => new FileUploadBuilder();\n\ndescribe('File Upload Components', () => {\n\tdescribe('Assertion Tests', () => {\n\t\ttest('GIVEN valid fields THEN builder does not throw', () => {\n\t\t\texpect(() => {\n\t\t\t\tfileUploadComponent().setCustomId('foobar').toJSON();\n\t\t\t}).not.toThrowError();\n\n\t\t\texpect(() => {\n\t\t\t\tfileUploadComponent().setCustomId('foobar').setMinValues(2).setMaxValues(9).toJSON();\n\t\t\t}).not.toThrowError();\n\t\t});\n\t});\n\n\ttest('GIVEN invalid fields THEN builder throws', () => {\n\t\texpect(() => fileUploadComponent().toJSON()).toThrowError();\n\n\t\texpect(() => fileUploadComponent().setCustomId('test').setId(4.4).toJSON()).toThrowError();\n\n\t\texpect(() => {\n\t\t\tfileUploadComponent().setCustomId('a'.repeat(500)).toJSON();\n\t\t}).toThrowError();\n\n\t\texpect(() => {\n\t\t\tfileUploadComponent().setCustomId('a').setMaxValues(55).toJSON();\n\t\t}).toThrowError();\n\n\t\texpect(() => {\n\t\t\tfileUploadComponent().setCustomId('a').setMinValues(-1).toJSON();\n\t\t}).toThrowError();\n\t});\n\n\ttest('GIVEN valid input THEN valid JSON outputs are given', () => {\n\t\tconst fileUploadData = {\n\t\t\ttype: ComponentType.FileUpload,\n\t\t\tcustom_id: 'custom id',\n\t\t\tmin_values: 5,\n\t\t\tmax_values: 6,\n\t\t\trequired: false,\n\t\t} satisfies APIFileUploadComponent;\n\n\t\texpect(new FileUploadBuilder(fileUploadData).toJSON()).toEqual(fileUploadData);\n\n\t\texpect(\n\t\t\tfileUploadComponent()\n\t\t\t\t.setCustomId(fileUploadData.custom_id)\n\t\t\t\t.setMaxValues(fileUploadData.max_values)\n\t\t\t\t.setMinValues(fileUploadData.min_values)\n\t\t\t\t.setRequired(fileUploadData.required)\n\t\t\t\t.toJSON(),\n\t\t).toEqual(fileUploadData);\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/components/label.test.ts",
    "content": "import type {\n\tAPIFileUploadComponent,\n\tAPILabelComponent,\n\tAPIStringSelectComponent,\n\tAPITextInputComponent,\n} from 'discord-api-types/v10';\nimport { ComponentType, TextInputStyle } from 'discord-api-types/v10';\nimport { describe, test, expect } from 'vitest';\nimport { LabelBuilder } from '../../src/index.js';\n\ndescribe('Label components', () => {\n\tdescribe('Assertion Tests', () => {\n\t\ttest('GIVEN valid fields THEN builder does not throw', () => {\n\t\t\texpect(() =>\n\t\t\t\tnew LabelBuilder()\n\t\t\t\t\t.setLabel('label')\n\t\t\t\t\t.setStringSelectMenuComponent((stringSelectMenu) =>\n\t\t\t\t\t\tstringSelectMenu\n\t\t\t\t\t\t\t.setCustomId('test')\n\t\t\t\t\t\t\t.setOptions((stringSelectMenuOption) => stringSelectMenuOption.setLabel('label').setValue('value'))\n\t\t\t\t\t\t\t.setRequired(),\n\t\t\t\t\t)\n\t\t\t\t\t.toJSON(),\n\t\t\t).not.toThrow();\n\n\t\t\texpect(() =>\n\t\t\t\tnew LabelBuilder()\n\t\t\t\t\t.setLabel('label')\n\t\t\t\t\t.setId(5)\n\t\t\t\t\t.setTextInputComponent((textInput) =>\n\t\t\t\t\t\ttextInput.setCustomId('test').setStyle(TextInputStyle.Paragraph).setRequired(),\n\t\t\t\t\t)\n\t\t\t\t\t.toJSON(),\n\t\t\t).not.toThrow();\n\n\t\t\texpect(() =>\n\t\t\t\tnew LabelBuilder()\n\t\t\t\t\t.setLabel('label')\n\t\t\t\t\t.setId(5)\n\t\t\t\t\t.setFileUploadComponent((fileUpload) => fileUpload.setCustomId('test'))\n\t\t\t\t\t.toJSON(),\n\t\t\t).not.toThrow();\n\t\t});\n\n\t\ttest('GIVEN invalid fields THEN build does throw', () => {\n\t\t\texpect(() => new LabelBuilder().toJSON()).toThrow();\n\t\t\texpect(() => new LabelBuilder().setId(5).toJSON()).toThrow();\n\t\t\texpect(() => new LabelBuilder().setLabel('label').toJSON()).toThrow();\n\n\t\t\texpect(() =>\n\t\t\t\tnew LabelBuilder()\n\t\t\t\t\t.setLabel('l'.repeat(1_000))\n\t\t\t\t\t.setStringSelectMenuComponent((stringSelectMenu) => stringSelectMenu)\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrow();\n\n\t\t\texpect(() =>\n\t\t\t\tnew LabelBuilder()\n\t\t\t\t\t.setLabel('l'.repeat(1_000))\n\t\t\t\t\t.setFileUploadComponent((fileUpload) => fileUpload)\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrow();\n\t\t});\n\n\t\ttest('GIVEN valid input THEN valid JSON outputs are given', () => {\n\t\t\tconst labelWithTextInputData = {\n\t\t\t\ttype: ComponentType.Label,\n\t\t\t\tcomponent: {\n\t\t\t\t\ttype: ComponentType.TextInput,\n\t\t\t\t\tcustom_id: 'custom_id',\n\t\t\t\t\tplaceholder: 'placeholder',\n\t\t\t\t\tstyle: TextInputStyle.Paragraph,\n\t\t\t\t} satisfies APITextInputComponent,\n\t\t\t\tlabel: 'label',\n\t\t\t\tdescription: 'description',\n\t\t\t\tid: 5,\n\t\t\t} satisfies APILabelComponent;\n\n\t\t\tconst labelWithStringSelectData = {\n\t\t\t\ttype: ComponentType.Label,\n\t\t\t\tcomponent: {\n\t\t\t\t\ttype: ComponentType.StringSelect,\n\t\t\t\t\tcustom_id: 'custom_id',\n\t\t\t\t\tplaceholder: 'placeholder',\n\t\t\t\t\toptions: [\n\t\t\t\t\t\t{ label: 'first', value: 'first' },\n\t\t\t\t\t\t{ label: 'second', value: 'second' },\n\t\t\t\t\t],\n\t\t\t\t\trequired: true,\n\t\t\t\t} satisfies APIStringSelectComponent,\n\t\t\t\tlabel: 'label',\n\t\t\t\tdescription: 'description',\n\t\t\t\tid: 5,\n\t\t\t} satisfies APILabelComponent;\n\n\t\t\tconst labelWithFileUploadData = {\n\t\t\t\ttype: ComponentType.Label,\n\t\t\t\tcomponent: {\n\t\t\t\t\ttype: ComponentType.FileUpload,\n\t\t\t\t\tcustom_id: 'custom_id',\n\t\t\t\t\tmin_values: 9,\n\t\t\t\t\trequired: true,\n\t\t\t\t} satisfies APIFileUploadComponent,\n\t\t\t\tlabel: 'label',\n\t\t\t\tdescription: 'description',\n\t\t\t\tid: 5,\n\t\t\t} satisfies APILabelComponent;\n\n\t\t\texpect(new LabelBuilder(labelWithTextInputData).toJSON()).toEqual(labelWithTextInputData);\n\t\t\texpect(new LabelBuilder(labelWithStringSelectData).toJSON()).toEqual(labelWithStringSelectData);\n\n\t\t\texpect(\n\t\t\t\tnew LabelBuilder()\n\t\t\t\t\t.setTextInputComponent((textInput) =>\n\t\t\t\t\t\ttextInput.setCustomId('custom_id').setPlaceholder('placeholder').setStyle(TextInputStyle.Paragraph),\n\t\t\t\t\t)\n\t\t\t\t\t.setLabel('label')\n\t\t\t\t\t.setDescription('description')\n\t\t\t\t\t.setId(5)\n\t\t\t\t\t.toJSON(),\n\t\t\t).toEqual(labelWithTextInputData);\n\n\t\t\texpect(\n\t\t\t\tnew LabelBuilder()\n\t\t\t\t\t.setStringSelectMenuComponent((stringSelectMenu) =>\n\t\t\t\t\t\tstringSelectMenu\n\t\t\t\t\t\t\t.setCustomId('custom_id')\n\t\t\t\t\t\t\t.setPlaceholder('placeholder')\n\t\t\t\t\t\t\t.setOptions(\n\t\t\t\t\t\t\t\t(stringSelectMenuOption) => stringSelectMenuOption.setLabel('first').setValue('first'),\n\t\t\t\t\t\t\t\t(stringSelectMenuOption) => stringSelectMenuOption.setLabel('second').setValue('second'),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.setRequired(),\n\t\t\t\t\t)\n\t\t\t\t\t.setLabel('label')\n\t\t\t\t\t.setDescription('description')\n\t\t\t\t\t.setId(5)\n\t\t\t\t\t.toJSON(),\n\t\t\t).toEqual(labelWithStringSelectData);\n\n\t\t\texpect(\n\t\t\t\tnew LabelBuilder()\n\t\t\t\t\t.setFileUploadComponent((fileUpload) => fileUpload.setCustomId('custom_id').setMinValues(9).setRequired())\n\t\t\t\t\t.setLabel('label')\n\t\t\t\t\t.setDescription('description')\n\t\t\t\t\t.setId(5)\n\t\t\t\t\t.toJSON(),\n\t\t\t).toEqual(labelWithFileUploadData);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/components/selectMenu.test.ts",
    "content": "import { ComponentType, type APISelectMenuComponent, type APISelectMenuOption } from 'discord-api-types/v10';\nimport { describe, test, expect } from 'vitest';\nimport { StringSelectMenuBuilder, StringSelectMenuOptionBuilder } from '../../src/index.js';\n\nconst selectMenu = () => new StringSelectMenuBuilder();\nconst selectMenuWithId = () => new StringSelectMenuBuilder({ custom_id: 'hi' });\nconst selectMenuOption = () => new StringSelectMenuOptionBuilder();\n\nconst longStr = 'a'.repeat(256);\nconst selectMenuOptionLabelAboveLimit = 'a'.repeat(101);\nconst selectMenuOptionValueAboveLimit = 'a'.repeat(101);\nconst selectMenuOptionDescriptionAboveLimit = 'a'.repeat(101);\n\nconst selectMenuOptionData: APISelectMenuOption = {\n\tlabel: 'test',\n\tvalue: 'test',\n\temoji: { name: 'test' },\n\tdefault: true,\n\tdescription: 'test',\n};\n\nconst selectMenuDataWithoutOptions = {\n\ttype: ComponentType.StringSelect,\n\tcustom_id: 'test',\n\tmax_values: 1,\n\tmin_values: 1,\n\tdisabled: true,\n\tplaceholder: 'test',\n\trequired: false,\n} as const;\n\nconst selectMenuData: APISelectMenuComponent = {\n\t...selectMenuDataWithoutOptions,\n\toptions: [selectMenuOptionData],\n};\n\nfunction makeStringSelectMenuWithOptions() {\n\tconst selectMenu = new StringSelectMenuBuilder();\n\tselectMenu.addOptions(\n\t\t{ label: 'foo', value: 'bar' },\n\t\t{ label: 'foo2', value: 'bar2' },\n\t\t{ label: 'foo3', value: 'bar3' },\n\t);\n\treturn selectMenu;\n}\n\nfunction mapStringSelectMenuOptionBuildersToJson(selectMenu: StringSelectMenuBuilder) {\n\treturn selectMenu.options.map((option) => option.toJSON());\n}\n\ndescribe('Select Menu Components', () => {\n\tdescribe('Assertion Tests', () => {\n\t\ttest('GIVEN valid inputs THEN Select Menu does not throw', () => {\n\t\t\texpect(() =>\n\t\t\t\tselectMenu().setCustomId('foo').addOptions({ label: 'test', value: 'test' }).toJSON(),\n\t\t\t).not.toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId().setMaxValues(10).addOptions({ label: 'test', value: 'test' }).toJSON(),\n\t\t\t).not.toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId()\n\t\t\t\t\t.setMinValues(3)\n\t\t\t\t\t.addOptions(\n\t\t\t\t\t\t{ label: 'test1', value: 'test1' },\n\t\t\t\t\t\t{ label: 'test2', value: 'test2' },\n\t\t\t\t\t\t{ label: 'test3', value: 'test3' },\n\t\t\t\t\t)\n\t\t\t\t\t.toJSON(),\n\t\t\t).not.toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId().setDisabled(true).addOptions({ label: 'test', value: 'test' }).toJSON(),\n\t\t\t).not.toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId().setDisabled().addOptions({ label: 'test', value: 'test' }).toJSON(),\n\t\t\t).not.toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId().setPlaceholder('description').addOptions({ label: 'test', value: 'test' }).toJSON(),\n\t\t\t).not.toThrowError();\n\t\t\tconst option = selectMenuOption()\n\t\t\t\t.setLabel('test')\n\t\t\t\t.setValue('test')\n\t\t\t\t.setDefault(true)\n\t\t\t\t.setEmoji({ name: 'test' })\n\t\t\t\t.setDescription('description');\n\t\t\texpect(() => selectMenuWithId().addOptions(option).toJSON()).not.toThrowError();\n\t\t\texpect(() => selectMenuWithId().setOptions(option).toJSON()).not.toThrowError();\n\t\t\texpect(() => selectMenuWithId().setOptions({ label: 'test', value: 'test' }).toJSON()).not.toThrowError();\n\t\t\texpect(() => selectMenuWithId().addOptions([option]).toJSON()).not.toThrowError();\n\t\t\texpect(() => selectMenuWithId().setOptions([option]).toJSON()).not.toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId()\n\t\t\t\t\t.setOptions([{ label: 'test', value: 'test' }])\n\t\t\t\t\t.toJSON(),\n\t\t\t).not.toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId()\n\t\t\t\t\t.addOptions({\n\t\t\t\t\t\tlabel: 'test',\n\t\t\t\t\t\tvalue: 'test',\n\t\t\t\t\t\temoji: {\n\t\t\t\t\t\t\tid: '123',\n\t\t\t\t\t\t\tname: 'test',\n\t\t\t\t\t\t\tanimated: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\t.addOptions([\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlabel: 'test',\n\t\t\t\t\t\t\tvalue: 'test',\n\t\t\t\t\t\t\temoji: {\n\t\t\t\t\t\t\t\tid: '123',\n\t\t\t\t\t\t\t\tname: 'test',\n\t\t\t\t\t\t\t\tanimated: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t])\n\t\t\t\t\t.toJSON(),\n\t\t\t).not.toThrowError();\n\n\t\t\tconst options = Array.from<APISelectMenuOption>({ length: 25 }).fill({ label: 'test', value: 'test' });\n\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId()\n\t\t\t\t\t.addOptions(...options)\n\t\t\t\t\t.toJSON(),\n\t\t\t).not.toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId()\n\t\t\t\t\t.setOptions(...options)\n\t\t\t\t\t.toJSON(),\n\t\t\t).not.toThrowError();\n\t\t\texpect(() => selectMenuWithId().addOptions(options).toJSON()).not.toThrowError();\n\t\t\texpect(() => selectMenuWithId().setOptions(options).toJSON()).not.toThrowError();\n\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId()\n\t\t\t\t\t.addOptions({ label: 'test', value: 'test' })\n\n\t\t\t\t\t.addOptions(...Array.from<APISelectMenuOption>({ length: 24 }).fill({ label: 'test', value: 'test' }))\n\t\t\t\t\t.toJSON(),\n\t\t\t).not.toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId()\n\t\t\t\t\t.addOptions([{ label: 'test', value: 'test' }])\n\t\t\t\t\t.addOptions(Array.from<APISelectMenuOption>({ length: 24 }).fill({ label: 'test', value: 'test' }))\n\t\t\t\t\t.toJSON(),\n\t\t\t).not.toThrowError();\n\t\t});\n\n\t\ttest('GIVEN invalid inputs THEN Select Menu does throw', () => {\n\t\t\texpect(() => selectMenu().setCustomId(longStr).toJSON()).toThrowError();\n\t\t\texpect(() => selectMenuWithId().setMaxValues(30).toJSON()).toThrowError();\n\t\t\texpect(() => selectMenuWithId().setMinValues(-20).toJSON()).toThrowError();\n\t\t\t// @ts-expect-error: Invalid disabled value\n\t\t\texpect(() => selectMenuWithId().setDisabled(0).toJSON()).toThrowError();\n\t\t\texpect(() => selectMenuWithId().setPlaceholder(longStr).toJSON()).toThrowError();\n\t\t\t// @ts-expect-error: Invalid option\n\t\t\texpect(() => selectMenuWithId().addOptions({ label: 'test' }).toJSON()).toThrowError();\n\t\t\texpect(() => selectMenuWithId().addOptions({ label: longStr, value: 'test' }).toJSON()).toThrowError();\n\t\t\texpect(() => selectMenuWithId().addOptions({ value: longStr, label: 'test' }).toJSON()).toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId().addOptions({ label: 'test', value: 'test', description: longStr }).toJSON(),\n\t\t\t).toThrowError();\n\t\t\texpect(() =>\n\t\t\t\t// @ts-expect-error: Invalid option\n\t\t\t\tselectMenuWithId().addOptions({ label: 'test', value: 'test', default: 100 }).toJSON(),\n\t\t\t).toThrowError();\n\t\t\t// @ts-expect-error: Invalid option\n\t\t\texpect(() => selectMenuWithId().addOptions({ value: 'test' }).toJSON()).toThrowError();\n\t\t\t// @ts-expect-error: Invalid option\n\t\t\texpect(() => selectMenuWithId().addOptions({ default: true }).toJSON()).toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId()\n\t\t\t\t\t// @ts-expect-error: Invalid option\n\t\t\t\t\t.addOptions([{ label: 'test' }])\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId()\n\t\t\t\t\t.addOptions([{ label: longStr, value: 'test' }])\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId()\n\t\t\t\t\t.addOptions([{ value: longStr, label: 'test' }])\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId()\n\t\t\t\t\t.addOptions([{ label: 'test', value: 'test', description: longStr }])\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId()\n\t\t\t\t\t// @ts-expect-error: Invalid option\n\t\t\t\t\t.addOptions([{ label: 'test', value: 'test', default: 100 }])\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId()\n\t\t\t\t\t// @ts-expect-error: Invalid option\n\t\t\t\t\t.addOptions([{ value: 'test' }])\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId()\n\t\t\t\t\t// @ts-expect-error: Invalid option\n\t\t\t\t\t.addOptions([{ default: true }])\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrowError();\n\n\t\t\tconst tooManyOptions = Array.from<APISelectMenuOption>({ length: 26 }).fill({ label: 'test', value: 'test' });\n\n\t\t\texpect(() =>\n\t\t\t\tselectMenu()\n\t\t\t\t\t.setOptions(...tooManyOptions)\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrowError();\n\t\t\texpect(() => selectMenu().setOptions(tooManyOptions).toJSON()).toThrowError();\n\n\t\t\texpect(() =>\n\t\t\t\tselectMenu()\n\t\t\t\t\t.addOptions({ label: 'test', value: 'test' })\n\t\t\t\t\t.addOptions(...tooManyOptions)\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tselectMenu()\n\t\t\t\t\t.addOptions([{ label: 'test', value: 'test' }])\n\t\t\t\t\t.addOptions(tooManyOptions)\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrowError();\n\n\t\t\texpect(() => {\n\t\t\t\tselectMenuOption()\n\t\t\t\t\t.setLabel(selectMenuOptionLabelAboveLimit)\n\t\t\t\t\t.setValue(selectMenuOptionValueAboveLimit)\n\t\t\t\t\t// @ts-expect-error: Invalid default value\n\t\t\t\t\t.setDefault(-1)\n\t\t\t\t\t// @ts-expect-error: Invalid emoji\n\t\t\t\t\t.setEmoji({ name: 1 })\n\t\t\t\t\t.setDescription(selectMenuOptionDescriptionAboveLimit)\n\t\t\t\t\t.toJSON();\n\t\t\t}).toThrowError();\n\t\t});\n\n\t\ttest('GIVEN valid option types THEN does not throw', () => {\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId()\n\t\t\t\t\t.addOptions({\n\t\t\t\t\t\tlabel: 'test',\n\t\t\t\t\t\tvalue: 'test',\n\t\t\t\t\t})\n\t\t\t\t\t.toJSON(),\n\t\t\t).not.toThrowError();\n\n\t\t\texpect(() =>\n\t\t\t\tselectMenuWithId().addOptions(selectMenuOption().setLabel('test').setValue('test')).toJSON(),\n\t\t\t).not.toThrowError();\n\t\t});\n\n\t\ttest('GIVEN valid JSON input THEN valid JSON history is correct', () => {\n\t\t\texpect(\n\t\t\t\tnew StringSelectMenuBuilder(selectMenuDataWithoutOptions)\n\t\t\t\t\t.addOptions(new StringSelectMenuOptionBuilder(selectMenuOptionData))\n\t\t\t\t\t.toJSON(),\n\t\t\t).toEqual(selectMenuData);\n\t\t\texpect(\n\t\t\t\tnew StringSelectMenuBuilder(selectMenuDataWithoutOptions)\n\t\t\t\t\t.addOptions([new StringSelectMenuOptionBuilder(selectMenuOptionData)])\n\t\t\t\t\t.toJSON(),\n\t\t\t).toEqual(selectMenuData);\n\t\t\texpect(new StringSelectMenuOptionBuilder(selectMenuOptionData).toJSON()).toEqual(selectMenuOptionData);\n\t\t});\n\n\t\ttest('GIVEN a StringSelectMenuBuilder using StringSelectMenuBuilder#spliceOptions works', () => {\n\t\t\texpect(\n\t\t\t\tmapStringSelectMenuOptionBuildersToJson(makeStringSelectMenuWithOptions().spliceOptions(0, 1)),\n\t\t\t).toStrictEqual([\n\t\t\t\t{ label: 'foo2', value: 'bar2' },\n\t\t\t\t{ label: 'foo3', value: 'bar3' },\n\t\t\t]);\n\n\t\t\texpect(\n\t\t\t\tmapStringSelectMenuOptionBuildersToJson(\n\t\t\t\t\tmakeStringSelectMenuWithOptions().spliceOptions(0, 1, selectMenuOptionData),\n\t\t\t\t),\n\t\t\t).toStrictEqual([selectMenuOptionData, { label: 'foo2', value: 'bar2' }, { label: 'foo3', value: 'bar3' }]);\n\n\t\t\texpect(\n\t\t\t\tmapStringSelectMenuOptionBuildersToJson(\n\t\t\t\t\tmakeStringSelectMenuWithOptions().spliceOptions(0, 3, selectMenuOptionData),\n\t\t\t\t),\n\t\t\t).toStrictEqual([selectMenuOptionData]);\n\n\t\t\texpect(() =>\n\t\t\t\tmakeStringSelectMenuWithOptions()\n\t\t\t\t\t.spliceOptions(0, 0, ...Array.from({ length: 26 }, () => selectMenuOptionData))\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrowError();\n\n\t\t\texpect(() =>\n\t\t\t\tmakeStringSelectMenuWithOptions()\n\t\t\t\t\t.setOptions(Array.from({ length: 25 }, () => selectMenuOptionData))\n\t\t\t\t\t.spliceOptions(-1, 2, selectMenuOptionData, selectMenuOptionData)\n\t\t\t\t\t.toJSON(),\n\t\t\t).toThrowError();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/components/textInput.test.ts",
    "content": "import { ComponentType, TextInputStyle, type APITextInputComponent } from 'discord-api-types/v10';\nimport { describe, test, expect } from 'vitest';\nimport { TextInputBuilder } from '../../src/components/textInput/TextInput.js';\n\nconst textInputComponent = () => new TextInputBuilder();\n\ndescribe('Text Input Components', () => {\n\tdescribe('Assertion Tests', () => {\n\t\ttest('GIVEN valid fields THEN builder does not throw', () => {\n\t\t\texpect(() => {\n\t\t\t\ttextInputComponent().setCustomId('foobar').setStyle(TextInputStyle.Paragraph).toJSON();\n\t\t\t}).not.toThrowError();\n\n\t\t\texpect(() => {\n\t\t\t\ttextInputComponent().setCustomId('foobar').setValue('').setStyle(TextInputStyle.Paragraph).toJSON();\n\t\t\t}).not.toThrowError();\n\n\t\t\texpect(() => {\n\t\t\t\ttextInputComponent()\n\t\t\t\t\t.setCustomId('foobar')\n\t\t\t\t\t.setMaxLength(100)\n\t\t\t\t\t.setMinLength(1)\n\t\t\t\t\t.setPlaceholder('bar')\n\t\t\t\t\t.setRequired(true)\n\t\t\t\t\t.setStyle(TextInputStyle.Paragraph)\n\t\t\t\t\t.toJSON();\n\t\t\t}).not.toThrowError();\n\n\t\t\texpect(() => {\n\t\t\t\ttextInputComponent().setCustomId('Custom').setStyle(TextInputStyle.Short).toJSON();\n\t\t\t}).not.toThrowError();\n\t\t});\n\t});\n\n\ttest('GIVEN invalid fields THEN builder throws', () => {\n\t\texpect(() => textInputComponent().toJSON()).toThrowError();\n\t\texpect(() => {\n\t\t\ttextInputComponent()\n\t\t\t\t.setCustomId('a'.repeat(500))\n\t\t\t\t.setMaxLength(100)\n\t\t\t\t.setPlaceholder('a'.repeat(500))\n\t\t\t\t.setStyle(3 as TextInputStyle)\n\t\t\t\t.toJSON();\n\t\t}).toThrowError();\n\t});\n\n\ttest('GIVEN valid input THEN valid JSON outputs are given', () => {\n\t\tconst textInputData = {\n\t\t\ttype: ComponentType.TextInput,\n\t\t\tcustom_id: 'custom id',\n\t\t\tplaceholder: 'placeholder',\n\t\t\tmax_length: 100,\n\t\t\tmin_length: 10,\n\t\t\tvalue: 'value',\n\t\t\trequired: false,\n\t\t\tstyle: TextInputStyle.Paragraph,\n\t\t} satisfies APITextInputComponent;\n\n\t\texpect(new TextInputBuilder(textInputData).toJSON()).toEqual(textInputData);\n\t\texpect(\n\t\t\ttextInputComponent()\n\t\t\t\t.setCustomId(textInputData.custom_id)\n\t\t\t\t.setPlaceholder(textInputData.placeholder)\n\t\t\t\t.setMaxLength(textInputData.max_length)\n\t\t\t\t.setMinLength(textInputData.min_length)\n\t\t\t\t.setValue(textInputData.value)\n\t\t\t\t.setRequired(textInputData.required)\n\t\t\t\t.setStyle(textInputData.style)\n\t\t\t\t.toJSON(),\n\t\t).toEqual(textInputData);\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/components/v2/container.test.ts",
    "content": "import {\n\ttype APIActionRowComponent,\n\ttype APIButtonComponent,\n\ttype APIContainerComponent,\n\tButtonStyle,\n\tComponentType,\n\tSeparatorSpacingSize,\n} from 'discord-api-types/v10';\nimport { describe, test, expect } from 'vitest';\nimport { createComponentBuilder } from '../../../src/components/Components.js';\nimport { ContainerBuilder } from '../../../src/components/v2/Container.js';\nimport { SeparatorBuilder } from '../../../src/components/v2/Separator.js';\nimport { TextDisplayBuilder } from '../../../src/components/v2/TextDisplay.js';\nimport { MediaGalleryBuilder, SectionBuilder } from '../../../src/index.js';\n\nconst containerWithTextDisplay: APIContainerComponent = {\n\ttype: ComponentType.Container,\n\tcomponents: [\n\t\t{\n\t\t\ttype: ComponentType.TextDisplay,\n\t\t\tcontent: 'test',\n\t\t\tid: 123,\n\t\t},\n\t],\n};\n\nconst button = {\n\ttype: ComponentType.Button as const,\n\tstyle: ButtonStyle.Primary as const,\n\tcustom_id: 'test',\n\tlabel: 'test',\n};\n\nconst actionRow: APIActionRowComponent<APIButtonComponent> = {\n\ttype: ComponentType.ActionRow,\n\tcomponents: [button],\n};\n\nconst containerWithSeparatorData: APIContainerComponent = {\n\ttype: ComponentType.Container,\n\tcomponents: [\n\t\t{\n\t\t\ttype: ComponentType.Separator,\n\t\t\tid: 1_234,\n\t\t\tspacing: SeparatorSpacingSize.Small,\n\t\t\tdivider: false,\n\t\t},\n\t],\n\taccent_color: 0x00ff00,\n};\n\nconst containerWithSeparatorDataNoColor: APIContainerComponent = {\n\ttype: ComponentType.Container,\n\tcomponents: [\n\t\t{\n\t\t\ttype: ComponentType.Separator,\n\t\t\tid: 1_234,\n\t\t\tspacing: SeparatorSpacingSize.Small,\n\t\t\tdivider: false,\n\t\t},\n\t],\n};\n\ndescribe('Container Components', () => {\n\tdescribe('Assertion Tests', () => {\n\t\ttest('GIVEN valid components THEN do not throw', () => {\n\t\t\texpect(() => new ContainerBuilder().addSeparatorComponents(new SeparatorBuilder()).toJSON()).not.toThrowError();\n\t\t\texpect(() => new ContainerBuilder().spliceComponents(0, 0, new SeparatorBuilder()).toJSON()).not.toThrowError();\n\t\t\texpect(() => new ContainerBuilder().addSeparatorComponents([new SeparatorBuilder()]).toJSON()).not.toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tnew ContainerBuilder().spliceComponents(0, 0, [{ type: ComponentType.Separator }]).toJSON(),\n\t\t\t).not.toThrowError();\n\t\t});\n\n\t\ttest('GIVEN valid JSON input THEN valid JSON output is given', () => {\n\t\t\tconst containerData: APIContainerComponent = {\n\t\t\t\ttype: ComponentType.Container,\n\t\t\t\tcomponents: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: ComponentType.TextDisplay,\n\t\t\t\t\t\tcontent: 'test',\n\t\t\t\t\t\tid: 3,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: ComponentType.Separator,\n\t\t\t\t\t\tspacing: SeparatorSpacingSize.Large,\n\t\t\t\t\t\tdivider: true,\n\t\t\t\t\t\tid: 4,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: ComponentType.File,\n\t\t\t\t\t\tfile: {\n\t\t\t\t\t\t\turl: 'attachment://file.png',\n\t\t\t\t\t\t},\n\t\t\t\t\t\tspoiler: false,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\taccent_color: 0xff00ff,\n\t\t\t\tspoiler: true,\n\t\t\t};\n\n\t\t\texpect(new ContainerBuilder(containerData).toJSON()).toEqual(containerData);\n\t\t\texpect(() => createComponentBuilder({ type: ComponentType.Container, components: [] })).not.toThrowError();\n\t\t});\n\n\t\ttest('GIVEN valid builder options THEN valid JSON output is given', () => {\n\t\t\tconst containerWithTextDisplay: APIContainerComponent = {\n\t\t\t\ttype: ComponentType.Container,\n\t\t\t\tcomponents: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: ComponentType.TextDisplay,\n\t\t\t\t\t\tcontent: 'test',\n\t\t\t\t\t\tid: 123,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\n\t\t\tconst containerWithSeparatorData: APIContainerComponent = {\n\t\t\t\ttype: ComponentType.Container,\n\t\t\t\tcomponents: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: ComponentType.Separator,\n\t\t\t\t\t\tid: 1_234,\n\t\t\t\t\t\tspacing: SeparatorSpacingSize.Small,\n\t\t\t\t\t\tdivider: false,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\taccent_color: 0x00ff00,\n\t\t\t};\n\n\t\t\texpect(new ContainerBuilder(containerWithTextDisplay).toJSON()).toEqual(containerWithTextDisplay);\n\t\t\texpect(new ContainerBuilder(containerWithSeparatorData).toJSON()).toEqual(containerWithSeparatorData);\n\t\t\texpect(() => createComponentBuilder({ type: ComponentType.Container, components: [] })).not.toThrowError();\n\t\t});\n\n\t\ttest('GIVEN valid builder options THEN valid JSON output is given 2', () => {\n\t\t\tconst textDisplay = new TextDisplayBuilder().setContent('test').setId(123);\n\t\t\tconst separator = new SeparatorBuilder().setId(1_234).setSpacing(SeparatorSpacingSize.Small).setDivider(false);\n\n\t\t\texpect(new ContainerBuilder().addTextDisplayComponents(textDisplay).toJSON()).toEqual(containerWithTextDisplay);\n\t\t\texpect(new ContainerBuilder().addSeparatorComponents(separator).toJSON()).toEqual(\n\t\t\t\tcontainerWithSeparatorDataNoColor,\n\t\t\t);\n\t\t\texpect(new ContainerBuilder().addTextDisplayComponents([textDisplay]).toJSON()).toEqual(containerWithTextDisplay);\n\t\t\texpect(new ContainerBuilder().addSeparatorComponents([separator]).toJSON()).toEqual(\n\t\t\t\tcontainerWithSeparatorDataNoColor,\n\t\t\t);\n\t\t});\n\n\t\ttest('GIVEN valid accent color THEN valid JSON output is given', () => {\n\t\t\texpect(\n\t\t\t\tnew ContainerBuilder({\n\t\t\t\t\tcomponents: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: ComponentType.TextDisplay,\n\t\t\t\t\t\t\tcontent: 'test',\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t})\n\t\t\t\t\t.setAccentColor(0xff00ff)\n\t\t\t\t\t.toJSON(),\n\t\t\t).toEqual({\n\t\t\t\ttype: ComponentType.Container,\n\t\t\t\tcomponents: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: ComponentType.TextDisplay,\n\t\t\t\t\t\tcontent: 'test',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\taccent_color: 0xff00ff,\n\t\t\t});\n\t\t\texpect(new ContainerBuilder(containerWithSeparatorData).clearAccentColor().toJSON()).toEqual(\n\t\t\t\tcontainerWithSeparatorDataNoColor,\n\t\t\t);\n\t\t});\n\n\t\ttest('GIVEN valid method parameters THEN valid JSON is given', () => {\n\t\t\texpect(\n\t\t\t\tnew ContainerBuilder()\n\t\t\t\t\t.addMediaGalleryComponents(\n\t\t\t\t\t\tnew MediaGalleryBuilder()\n\t\t\t\t\t\t\t.addItems({ media: { url: 'https://discord.com' } })\n\t\t\t\t\t\t\t.setId(3)\n\t\t\t\t\t\t\t.clearId(),\n\t\t\t\t\t)\n\t\t\t\t\t.setSpoiler()\n\t\t\t\t\t.toJSON(),\n\t\t\t).toEqual({\n\t\t\t\ttype: ComponentType.Container,\n\t\t\t\tcomponents: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: ComponentType.MediaGallery,\n\t\t\t\t\t\titems: [{ media: { url: 'https://discord.com' } }],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tspoiler: true,\n\t\t\t});\n\t\t\texpect(\n\t\t\t\tnew ContainerBuilder()\n\t\t\t\t\t.addSectionComponents(\n\t\t\t\t\t\tnew SectionBuilder()\n\t\t\t\t\t\t\t.addTextDisplayComponents({ type: ComponentType.TextDisplay, content: 'test' })\n\t\t\t\t\t\t\t.setPrimaryButtonAccessory(button),\n\t\t\t\t\t)\n\t\t\t\t\t.addFileComponents({ type: ComponentType.File, file: { url: 'attachment://discord.png' } })\n\t\t\t\t\t.setSpoiler(false)\n\t\t\t\t\t.setId(5)\n\t\t\t\t\t.toJSON(),\n\t\t\t).toEqual({\n\t\t\t\ttype: ComponentType.Container,\n\t\t\t\tcomponents: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: ComponentType.Section,\n\t\t\t\t\t\tcomponents: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: ComponentType.TextDisplay,\n\t\t\t\t\t\t\t\tcontent: 'test',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\taccessory: button,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: ComponentType.File,\n\t\t\t\t\t\tfile: { url: 'attachment://discord.png' },\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tspoiler: false,\n\t\t\t\tid: 5,\n\t\t\t});\n\t\t\texpect(new ContainerBuilder().addActionRowComponents(actionRow).setSpoiler(true).toJSON()).toEqual({\n\t\t\t\ttype: ComponentType.Container,\n\t\t\t\tcomponents: [actionRow],\n\t\t\t\tspoiler: true,\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/components/v2/file.test.ts",
    "content": "import { ComponentType } from 'discord-api-types/v10';\nimport { describe, expect, test } from 'vitest';\nimport { FileBuilder } from '../../../src/components/v2/File';\n\nconst dummy = {\n\ttype: ComponentType.File as const,\n\tfile: { url: 'attachment://owo.png' },\n};\n\ndescribe('File', () => {\n\tdescribe('File url', () => {\n\t\ttest('GIVEN a file with a pre-defined url THEN return valid toJSON data', () => {\n\t\t\tconst file = new FileBuilder({ file: { url: 'attachment://owo.png' } });\n\t\t\texpect(file.toJSON()).toEqual({ ...dummy, file: { url: 'attachment://owo.png' } });\n\t\t});\n\n\t\ttest('GIVEN a file using File#setURL THEN return valid toJSON data', () => {\n\t\t\tconst file = new FileBuilder();\n\t\t\tfile.setURL('attachment://uwu.png');\n\n\t\t\texpect(file.toJSON()).toEqual({ ...dummy, file: { url: 'attachment://uwu.png' } });\n\t\t});\n\n\t\ttest('GIVEN a file with an invalid url THEN throws error', () => {\n\t\t\tconst file = new FileBuilder();\n\t\t\tfile.setURL('https://google.com');\n\n\t\t\texpect(() => file.toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('File spoiler', () => {\n\t\ttest('GIVEN a file with a pre-defined spoiler status THEN return valid toJSON data', () => {\n\t\t\tconst file = new FileBuilder({ ...dummy, spoiler: true });\n\t\t\texpect(file.toJSON()).toEqual({ ...dummy, spoiler: true });\n\t\t});\n\n\t\ttest('GIVEN a file using File#setSpoiler THEN return valid toJSON data', () => {\n\t\t\tconst file = new FileBuilder({ ...dummy });\n\t\t\tfile.setSpoiler(false);\n\n\t\t\texpect(file.toJSON()).toEqual({ ...dummy, spoiler: false });\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/components/v2/mediaGallery.test.ts",
    "content": "import { ComponentType } from 'discord-api-types/v10';\nimport { describe, expect, test } from 'vitest';\nimport { MediaGalleryBuilder } from '../../../src/components/v2/MediaGallery';\nimport { MediaGalleryItemBuilder } from '../../../src/components/v2/MediaGalleryItem';\n\ndescribe('MediaGallery', () => {\n\ttest('GIVEN an empty media gallery THEN throws error', () => {\n\t\tconst gallery = new MediaGalleryBuilder();\n\t\texpect(() => gallery.toJSON()).toThrow();\n\t});\n\n\tdescribe('MediaGallery items', () => {\n\t\ttest('GIVEN a media gallery with pre-defined items THEN return valid toJSON data', () => {\n\t\t\tconst items = [\n\t\t\t\t{ media: { url: 'https://google.com' } },\n\t\t\t\t{ media: { url: 'https://discord.com' }, description: 'Discord' },\n\t\t\t];\n\n\t\t\tconst gallery = new MediaGalleryBuilder({\n\t\t\t\ttype: ComponentType.MediaGallery,\n\t\t\t\titems,\n\t\t\t});\n\n\t\t\texpect(gallery.toJSON()).toEqual({\n\t\t\t\ttype: ComponentType.MediaGallery,\n\t\t\t\titems,\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN a media gallery with items added via addItems THEN return valid toJSON data', () => {\n\t\t\tconst gallery = new MediaGalleryBuilder();\n\t\t\tconst item1 = new MediaGalleryItemBuilder().setURL('https://google.com');\n\t\t\tconst item2 = new MediaGalleryItemBuilder().setURL('https://discord.com').setDescription('Discord');\n\n\t\t\tgallery.addItems(item1, item2);\n\n\t\t\texpect(gallery.toJSON()).toEqual({\n\t\t\t\ttype: ComponentType.MediaGallery,\n\t\t\t\titems: [\n\t\t\t\t\t{ media: { url: 'https://google.com' } },\n\t\t\t\t\t{ media: { url: 'https://discord.com' }, description: 'Discord' },\n\t\t\t\t],\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN a media gallery with items added via addItems with raw objects THEN return valid toJSON data', () => {\n\t\t\tconst gallery = new MediaGalleryBuilder();\n\n\t\t\tgallery.addItems(\n\t\t\t\t{ media: { url: 'https://google.com' } },\n\t\t\t\t{ media: { url: 'https://discord.com' }, description: 'Discord' },\n\t\t\t);\n\n\t\t\texpect(gallery.toJSON()).toEqual({\n\t\t\t\ttype: ComponentType.MediaGallery,\n\t\t\t\titems: [\n\t\t\t\t\t{ media: { url: 'https://google.com' } },\n\t\t\t\t\t{ media: { url: 'https://discord.com' }, description: 'Discord' },\n\t\t\t\t],\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN a media gallery with items added via addItems with builder functions THEN return valid toJSON data', () => {\n\t\t\tconst gallery = new MediaGalleryBuilder();\n\n\t\t\tgallery.addItems(\n\t\t\t\t(builder) => builder.setURL('https://google.com'),\n\t\t\t\t(builder) => builder.setURL('https://discord.com').setDescription('Discord'),\n\t\t\t);\n\n\t\t\texpect(gallery.toJSON()).toEqual({\n\t\t\t\ttype: ComponentType.MediaGallery,\n\t\t\t\titems: [\n\t\t\t\t\t{ media: { url: 'https://google.com' } },\n\t\t\t\t\t{ media: { url: 'https://discord.com' }, description: 'Discord' },\n\t\t\t\t],\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN a media gallery with array of items passed to addItems THEN return valid toJSON data', () => {\n\t\t\tconst gallery = new MediaGalleryBuilder();\n\t\t\tconst items = [\n\t\t\t\tnew MediaGalleryItemBuilder().setURL('https://google.com'),\n\t\t\t\tnew MediaGalleryItemBuilder().setURL('https://discord.com').setDescription('Discord'),\n\t\t\t];\n\n\t\t\tgallery.addItems(items);\n\n\t\t\texpect(gallery.toJSON()).toEqual({\n\t\t\t\ttype: ComponentType.MediaGallery,\n\t\t\t\titems: [\n\t\t\t\t\t{ media: { url: 'https://google.com' } },\n\t\t\t\t\t{ media: { url: 'https://discord.com' }, description: 'Discord' },\n\t\t\t\t],\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN a media gallery with items added via addItems with builder functions THEN return valid toJSON data', () => {\n\t\t\tconst gallery = new MediaGalleryBuilder();\n\n\t\t\tgallery\n\t\t\t\t.addItems(\n\t\t\t\t\tnew MediaGalleryItemBuilder().setURL('https://google.com'),\n\t\t\t\t\tnew MediaGalleryItemBuilder().setURL('https://discord.com').setDescription('Discord'),\n\t\t\t\t)\n\t\t\t\t.spliceItems(1, 1, new MediaGalleryItemBuilder().setURL('https://discord.js.org').setDescription('Discord.JS'));\n\n\t\t\texpect(gallery.toJSON()).toEqual({\n\t\t\t\ttype: ComponentType.MediaGallery,\n\t\t\t\titems: [\n\t\t\t\t\t{ media: { url: 'https://google.com' } },\n\t\t\t\t\t{ media: { url: 'https://discord.js.org' }, description: 'Discord.JS' },\n\t\t\t\t],\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/components/v2/mediaGalleryItem.test.ts",
    "content": "import { describe, expect, test } from 'vitest';\nimport { MediaGalleryItemBuilder } from '../../../src/components/v2/MediaGalleryItem';\n\nconst dummy = {\n\tmedia: { url: 'https://google.com' },\n};\n\ndescribe('MediaGalleryItem', () => {\n\tdescribe('MediaGalleryItem url', () => {\n\t\ttest('GIVEN a media gallery item with a pre-defined url THEN return valid toJSON data', () => {\n\t\t\tconst item = new MediaGalleryItemBuilder({ media: { url: 'https://google.com' } });\n\t\t\texpect(item.toJSON()).toEqual({ media: { url: 'https://google.com' } });\n\t\t});\n\n\t\ttest('GIVEN a media gallery item with a set url THEN return valid toJSON data', () => {\n\t\t\tconst item = new MediaGalleryItemBuilder().setURL('https://google.com');\n\t\t\texpect(item.toJSON()).toEqual({ media: { url: 'https://google.com' } });\n\t\t});\n\n\t\ttest.each(['owo', 'discord://user'])(\n\t\t\t'GIVEN a media gallery item with an invalid URL (%s) THEN throws error',\n\t\t\t(input) => {\n\t\t\t\tconst item = new MediaGalleryItemBuilder();\n\n\t\t\t\titem.setURL(input);\n\t\t\t\texpect(() => item.toJSON()).toThrowError();\n\t\t\t},\n\t\t);\n\t});\n\n\tdescribe('MediaGalleryItem description', () => {\n\t\ttest('GIVEN a media gallery item with a pre-defined description THEN return valid toJSON data', () => {\n\t\t\tconst item = new MediaGalleryItemBuilder({ ...dummy, description: 'foo' });\n\t\t\texpect(item.toJSON()).toEqual({ ...dummy, description: 'foo' });\n\t\t});\n\n\t\ttest('GIVEN a media gallery item with a set description THEN return valid toJSON data', () => {\n\t\t\tconst item = new MediaGalleryItemBuilder({ ...dummy });\n\t\t\titem.setDescription('foo');\n\n\t\t\texpect(item.toJSON()).toEqual({ ...dummy, description: 'foo' });\n\t\t});\n\n\t\ttest('GIVEN a media gallery item with a pre-defined description THEN unset description THEN return valid toJSON data', () => {\n\t\t\tconst item = new MediaGalleryItemBuilder({ description: 'foo', ...dummy });\n\t\t\titem.clearDescription();\n\n\t\t\texpect(item.toJSON()).toEqual({ ...dummy });\n\t\t});\n\n\t\ttest('GIVEN a media gallery item with an invalid description THEN throws error', () => {\n\t\t\tconst item = new MediaGalleryItemBuilder();\n\n\t\t\titem.setDescription('a'.repeat(1_025));\n\t\t\texpect(() => item.toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('MediaGalleryItem spoiler', () => {\n\t\ttest('GIVEN a media gallery item with a pre-defined spoiler status THEN return valid toJSON data', () => {\n\t\t\tconst item = new MediaGalleryItemBuilder({ ...dummy, spoiler: true });\n\t\t\texpect(item.toJSON()).toEqual({ ...dummy, spoiler: true });\n\t\t});\n\n\t\ttest('GIVEN a media gallery item with a set spoiler status THEN return valid toJSON data', () => {\n\t\t\tconst item = new MediaGalleryItemBuilder({ ...dummy });\n\t\t\titem.setSpoiler(false);\n\n\t\t\texpect(item.toJSON()).toEqual({ ...dummy, spoiler: false });\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/components/v2/section.test.ts",
    "content": "import { ButtonStyle, ComponentType } from 'discord-api-types/v10';\nimport { describe, expect, test } from 'vitest';\nimport { PrimaryButtonBuilder } from '../../../src/components/button/CustomIdButton';\nimport { SectionBuilder } from '../../../src/components/v2/Section';\nimport { TextDisplayBuilder } from '../../../src/components/v2/TextDisplay';\nimport { ThumbnailBuilder } from '../../../src/components/v2/Thumbnail';\n\ndescribe('Section', () => {\n\tdescribe('Validation', () => {\n\t\ttest('GIVEN empty section builder THEN throws error on toJSON', () => {\n\t\t\tconst section = new SectionBuilder();\n\t\t\texpect(() => section.toJSON()).toThrowError();\n\t\t});\n\n\t\ttest('GIVEN section with text components but no accessory THEN throws error on toJSON', () => {\n\t\t\tconst section = new SectionBuilder().addTextDisplayComponents(new TextDisplayBuilder().setContent('Hello world'));\n\t\t\texpect(() => section.toJSON()).toThrowError();\n\t\t});\n\n\t\ttest('GIVEN section with accessory but no text components THEN throws error on toJSON', () => {\n\t\t\tconst section = new SectionBuilder().setThumbnailAccessory(\n\t\t\t\tnew ThumbnailBuilder().setURL('https://example.com/image.png'),\n\t\t\t);\n\t\t\texpect(() => section.toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Text display components', () => {\n\t\ttest('GIVEN section with predefined text components THEN returns valid toJSON data', () => {\n\t\t\tconst section = new SectionBuilder({\n\t\t\t\tcomponents: [{ type: ComponentType.TextDisplay, content: 'Hello world' }],\n\t\t\t\taccessory: { type: ComponentType.Thumbnail, media: { url: 'https://example.com/image.png' } },\n\t\t\t});\n\n\t\t\texpect(section.toJSON()).toEqual({\n\t\t\t\ttype: ComponentType.Section,\n\t\t\t\tcomponents: [{ type: ComponentType.TextDisplay, content: 'Hello world' }],\n\t\t\t\taccessory: { type: ComponentType.Thumbnail, media: { url: 'https://example.com/image.png' } },\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN section with added text components THEN returns valid toJSON data', () => {\n\t\t\tconst section = new SectionBuilder()\n\t\t\t\t.addTextDisplayComponents(new TextDisplayBuilder().setContent('Hello world'))\n\t\t\t\t.setThumbnailAccessory(new ThumbnailBuilder().setURL('https://example.com/image.png'));\n\n\t\t\texpect(section.toJSON()).toEqual({\n\t\t\t\ttype: ComponentType.Section,\n\t\t\t\tcomponents: [{ type: ComponentType.TextDisplay, content: 'Hello world' }],\n\t\t\t\taccessory: { type: ComponentType.Thumbnail, media: { url: 'https://example.com/image.png' } },\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN section with multiple text components THEN returns valid toJSON data', () => {\n\t\t\tconst section = new SectionBuilder()\n\t\t\t\t.addTextDisplayComponents(\n\t\t\t\t\tnew TextDisplayBuilder().setContent('Line 1'),\n\t\t\t\t\tnew TextDisplayBuilder().setContent('Line 2'),\n\t\t\t\t\tnew TextDisplayBuilder().setContent('Line 3'),\n\t\t\t\t)\n\t\t\t\t.setThumbnailAccessory(new ThumbnailBuilder().setURL('https://example.com/image.png'));\n\n\t\t\texpect(section.toJSON()).toEqual({\n\t\t\t\ttype: ComponentType.Section,\n\t\t\t\tcomponents: [\n\t\t\t\t\t{ type: ComponentType.TextDisplay, content: 'Line 1' },\n\t\t\t\t\t{ type: ComponentType.TextDisplay, content: 'Line 2' },\n\t\t\t\t\t{ type: ComponentType.TextDisplay, content: 'Line 3' },\n\t\t\t\t],\n\t\t\t\taccessory: { type: ComponentType.Thumbnail, media: { url: 'https://example.com/image.png' } },\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN section with spliced text components THEN returns valid toJSON data', () => {\n\t\t\tconst section = new SectionBuilder()\n\t\t\t\t.addTextDisplayComponents(\n\t\t\t\t\tnew TextDisplayBuilder().setContent('Original 1'),\n\t\t\t\t\tnew TextDisplayBuilder().setContent('Will be removed'),\n\t\t\t\t\tnew TextDisplayBuilder().setContent('Original 3'),\n\t\t\t\t)\n\t\t\t\t.spliceTextDisplayComponents(1, 1, new TextDisplayBuilder().setContent('Replacement'))\n\t\t\t\t.setThumbnailAccessory(new ThumbnailBuilder().setURL('https://example.com/image.png'));\n\n\t\t\texpect(section.toJSON()).toEqual({\n\t\t\t\ttype: ComponentType.Section,\n\t\t\t\tcomponents: [\n\t\t\t\t\t{ type: ComponentType.TextDisplay, content: 'Original 1' },\n\t\t\t\t\t{ type: ComponentType.TextDisplay, content: 'Replacement' },\n\t\t\t\t\t{ type: ComponentType.TextDisplay, content: 'Original 3' },\n\t\t\t\t],\n\t\t\t\taccessory: { type: ComponentType.Thumbnail, media: { url: 'https://example.com/image.png' } },\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('Accessory components', () => {\n\t\ttest('GIVEN section with thumbnail accessory THEN returns valid toJSON data', () => {\n\t\t\tconst section = new SectionBuilder()\n\t\t\t\t.addTextDisplayComponents(new TextDisplayBuilder().setContent('Hello world'))\n\t\t\t\t.setThumbnailAccessory(new ThumbnailBuilder().setURL('https://example.com/image.png'));\n\n\t\t\texpect(section.toJSON()).toEqual({\n\t\t\t\ttype: ComponentType.Section,\n\t\t\t\tcomponents: [{ type: ComponentType.TextDisplay, content: 'Hello world' }],\n\t\t\t\taccessory: { type: ComponentType.Thumbnail, media: { url: 'https://example.com/image.png' } },\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN section with primary button accessory THEN returns valid toJSON data', () => {\n\t\t\tconst section = new SectionBuilder()\n\t\t\t\t.addTextDisplayComponents(new TextDisplayBuilder().setContent('Hello world'))\n\t\t\t\t.setPrimaryButtonAccessory(new PrimaryButtonBuilder().setCustomId('click_me').setLabel('Click me'));\n\n\t\t\texpect(section.toJSON()).toEqual({\n\t\t\t\ttype: ComponentType.Section,\n\t\t\t\tcomponents: [{ type: ComponentType.TextDisplay, content: 'Hello world' }],\n\t\t\t\taccessory: {\n\t\t\t\t\ttype: ComponentType.Button,\n\t\t\t\t\tstyle: 1,\n\t\t\t\t\tcustom_id: 'click_me',\n\t\t\t\t\tlabel: 'Click me',\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN section with primary button accessory JSON THEN returns valid toJSON data', () => {\n\t\t\tconst section = new SectionBuilder()\n\t\t\t\t.addTextDisplayComponents(new TextDisplayBuilder().setContent('Hello world'))\n\t\t\t\t.setPrimaryButtonAccessory({\n\t\t\t\t\ttype: ComponentType.Button,\n\t\t\t\t\tstyle: ButtonStyle.Primary,\n\t\t\t\t\tcustom_id: 'click_me',\n\t\t\t\t\tlabel: 'Click me',\n\t\t\t\t});\n\n\t\t\texpect(section.toJSON()).toEqual({\n\t\t\t\ttype: ComponentType.Section,\n\t\t\t\tcomponents: [{ type: ComponentType.TextDisplay, content: 'Hello world' }],\n\t\t\t\taccessory: {\n\t\t\t\t\ttype: ComponentType.Button,\n\t\t\t\t\tstyle: 1,\n\t\t\t\t\tcustom_id: 'click_me',\n\t\t\t\t\tlabel: 'Click me',\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN changing accessory type THEN returns the latest accessory in toJSON', () => {\n\t\t\tconst section = new SectionBuilder()\n\t\t\t\t.addTextDisplayComponents(new TextDisplayBuilder().setContent('Hello world'))\n\t\t\t\t.setThumbnailAccessory(new ThumbnailBuilder().setURL('https://example.com/image.png'))\n\t\t\t\t.setPrimaryButtonAccessory(new PrimaryButtonBuilder().setCustomId('click_me').setLabel('Click me'));\n\n\t\t\texpect(section.toJSON()).toEqual({\n\t\t\t\ttype: ComponentType.Section,\n\t\t\t\tcomponents: [{ type: ComponentType.TextDisplay, content: 'Hello world' }],\n\t\t\t\taccessory: {\n\t\t\t\t\ttype: ComponentType.Button,\n\t\t\t\t\tstyle: 1,\n\t\t\t\t\tcustom_id: 'click_me',\n\t\t\t\t\tlabel: 'Click me',\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/components/v2/separator.test.ts",
    "content": "import { ComponentType, SeparatorSpacingSize } from 'discord-api-types/v10';\nimport { describe, expect, test } from 'vitest';\nimport { SeparatorBuilder } from '../../../src/components/v2/Separator';\n\ndescribe('Separator', () => {\n\tdescribe('Divider', () => {\n\t\ttest('GIVEN a separator with a pre-defined divider THEN return valid toJSON data', () => {\n\t\t\tconst separator = new SeparatorBuilder({ divider: true });\n\t\t\texpect(separator.toJSON()).toEqual({ type: ComponentType.Separator, divider: true });\n\t\t});\n\n\t\ttest('GIVEN a separator with a set divider THEN return valid toJSON data', () => {\n\t\t\tconst separator = new SeparatorBuilder().setDivider(false);\n\t\t\texpect(separator.toJSON()).toEqual({ type: ComponentType.Separator, divider: false });\n\t\t});\n\t});\n\n\tdescribe('Spacing', () => {\n\t\ttest('GIVEN a separator with a pre-defined spacing THEN return valid toJSON data', () => {\n\t\t\tconst separator = new SeparatorBuilder({ spacing: SeparatorSpacingSize.Small });\n\t\t\texpect(separator.toJSON()).toEqual({ type: ComponentType.Separator, spacing: SeparatorSpacingSize.Small });\n\t\t});\n\n\t\ttest('GIVEN a separator with a set spacing THEN return valid toJSON data', () => {\n\t\t\tconst separator = new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Large);\n\t\t\texpect(separator.toJSON()).toEqual({ type: ComponentType.Separator, spacing: SeparatorSpacingSize.Large });\n\t\t});\n\n\t\ttest('GIVEN a separator with a set spacing THEN clear spacing THEN return valid toJSON data', () => {\n\t\t\tconst separator = new SeparatorBuilder({ spacing: SeparatorSpacingSize.Small });\n\t\t\tseparator.clearSpacing();\n\t\t\texpect(separator.toJSON()).toEqual({ type: ComponentType.Separator });\n\t\t});\n\t});\n\n\tdescribe('Invalid id', () => {\n\t\ttest('GIVEN a separator with a set spacing and an invalid set id THEN throws error', () => {\n\t\t\tconst separator = new SeparatorBuilder().setSpacing(SeparatorSpacingSize.Large).setId(-1);\n\t\t\texpect(() => separator.toJSON()).toThrowError();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/components/v2/textDisplay.test.ts",
    "content": "import { ComponentType } from 'discord-api-types/v10';\nimport { describe, expect, test } from 'vitest';\nimport { TextDisplayBuilder } from '../../../src/components/v2/TextDisplay';\n\ndescribe('TextDisplay', () => {\n\tdescribe('TextDisplay content', () => {\n\t\ttest('GIVEN a text display with a pre-defined content THEN return valid toJSON data', () => {\n\t\t\tconst textDisplay = new TextDisplayBuilder({ content: 'foo' });\n\t\t\texpect(textDisplay.toJSON()).toEqual({ type: ComponentType.TextDisplay, content: 'foo' });\n\t\t});\n\n\t\ttest('GIVEN a text display with a set content THEN return valid toJSON data', () => {\n\t\t\tconst textDisplay = new TextDisplayBuilder().setContent('foo');\n\t\t\texpect(textDisplay.toJSON()).toEqual({ type: ComponentType.TextDisplay, content: 'foo' });\n\t\t});\n\n\t\ttest('GIVEN a text display with a set content with an invalid id THEN throws error', () => {\n\t\t\tconst textDisplay = new TextDisplayBuilder().setContent('foo').setId(5.5);\n\t\t\texpect(() => textDisplay.toJSON()).toThrowError();\n\t\t});\n\n\t\ttest('GIVEN a text display with a pre-defined content THEN overwritten content THEN return valid toJSON data', () => {\n\t\t\tconst textDisplay = new TextDisplayBuilder({ content: 'foo' });\n\t\t\ttextDisplay.setContent('bar');\n\t\t\texpect(textDisplay.toJSON()).toEqual({ type: ComponentType.TextDisplay, content: 'bar' });\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/components/v2/thumbnail.test.ts",
    "content": "import { ComponentType } from 'discord-api-types/v10';\nimport { describe, expect, test } from 'vitest';\nimport { ThumbnailBuilder } from '../../../src/components/v2/Thumbnail';\n\nconst dummy = {\n\ttype: ComponentType.Thumbnail as const,\n\tmedia: { url: 'https://google.com' },\n};\n\ndescribe('Thumbnail', () => {\n\tdescribe('Thumbnail url', () => {\n\t\ttest('GIVEN a thumbnail with a pre-defined url THEN return valid toJSON data', () => {\n\t\t\tconst thumbnail = new ThumbnailBuilder({ media: { url: 'https://google.com' } });\n\t\t\texpect(thumbnail.toJSON()).toEqual({ type: ComponentType.Thumbnail, media: { url: 'https://google.com' } });\n\t\t});\n\n\t\ttest('GIVEN a thumbnail with a set url THEN return valid toJSON data', () => {\n\t\t\tconst thumbnail = new ThumbnailBuilder().setURL('https://google.com');\n\t\t\texpect(thumbnail.toJSON()).toEqual({ type: ComponentType.Thumbnail, media: { url: 'https://google.com' } });\n\t\t});\n\n\t\ttest.each(['owo', 'discord://user'])('GIVEN an embed with an invalid URL (%s) THEN throws error', (input) => {\n\t\t\tconst thumbnail = new ThumbnailBuilder();\n\n\t\t\tthumbnail.setURL(input);\n\t\t\texpect(() => thumbnail.toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Thumbnail description', () => {\n\t\ttest('GIVEN a thumbnail with a pre-defined description THEN return valid toJSON data', () => {\n\t\t\tconst thumbnail = new ThumbnailBuilder({ ...dummy, description: 'foo' });\n\t\t\texpect(thumbnail.toJSON()).toEqual({ ...dummy, description: 'foo' });\n\t\t});\n\n\t\ttest('GIVEN a thumbnail with a set description THEN return valid toJSON data', () => {\n\t\t\tconst thumbnail = new ThumbnailBuilder({ ...dummy });\n\t\t\tthumbnail.setDescription('foo');\n\n\t\t\texpect(thumbnail.toJSON()).toEqual({ ...dummy, description: 'foo' });\n\t\t});\n\n\t\ttest('GIVEN a thumbnail with a pre-defined description THEN unset description THEN return valid toJSON data', () => {\n\t\t\tconst thumbnail = new ThumbnailBuilder({ description: 'foo', ...dummy });\n\t\t\tthumbnail.clearDescription();\n\n\t\t\texpect(thumbnail.toJSON()).toEqual({ ...dummy });\n\t\t});\n\n\t\ttest('GIVEN a thumbnail with an invalid description THEN throws error', () => {\n\t\t\tconst thumbnail = new ThumbnailBuilder();\n\n\t\t\tthumbnail.setDescription('a'.repeat(1_025));\n\t\t\texpect(() => thumbnail.toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Thumbnail spoiler', () => {\n\t\ttest('GIVEN a thumbnail with a pre-defined spoiler status THEN return valid toJSON data', () => {\n\t\t\tconst thumbnail = new ThumbnailBuilder({ ...dummy, spoiler: true });\n\t\t\texpect(thumbnail.toJSON()).toEqual({ ...dummy, spoiler: true });\n\t\t});\n\n\t\ttest('GIVEN a thumbnail with a set spoiler status THEN return valid toJSON data', () => {\n\t\t\tconst thumbnail = new ThumbnailBuilder({ ...dummy });\n\t\t\tthumbnail.setSpoiler(false);\n\n\t\t\texpect(thumbnail.toJSON()).toEqual({ ...dummy, spoiler: false });\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/interactions/ChatInputCommands/ChatInputCommands.test.ts",
    "content": "import {\n\tApplicationCommandType,\n\tApplicationIntegrationType,\n\tChannelType,\n\tInteractionContextType,\n\tLocale,\n\tPermissionFlagsBits,\n} from 'discord-api-types/v10';\nimport { describe, test, expect } from 'vitest';\nimport {\n\tChatInputCommandBooleanOption,\n\tChatInputCommandBuilder,\n\tChatInputCommandChannelOption,\n\tChatInputCommandIntegerOption,\n\tChatInputCommandMentionableOption,\n\tChatInputCommandNumberOption,\n\tChatInputCommandRoleOption,\n\tChatInputCommandAttachmentOption,\n\tChatInputCommandStringOption,\n\tChatInputCommandSubcommandBuilder,\n\tChatInputCommandSubcommandGroupBuilder,\n\tChatInputCommandUserOption,\n} from '../../../src/index.js';\n\nconst getBuilder = () => new ChatInputCommandBuilder();\nconst getNamedBuilder = () => getBuilder().setName('example').setDescription('Example command');\nconst getStringOption = () => new ChatInputCommandStringOption().setName('owo').setDescription('Testing 123');\nconst getIntegerOption = () => new ChatInputCommandIntegerOption().setName('owo').setDescription('Testing 123');\nconst getNumberOption = () => new ChatInputCommandNumberOption().setName('owo').setDescription('Testing 123');\nconst getBooleanOption = () => new ChatInputCommandBooleanOption().setName('owo').setDescription('Testing 123');\nconst getUserOption = () => new ChatInputCommandUserOption().setName('owo').setDescription('Testing 123');\nconst getChannelOption = () => new ChatInputCommandChannelOption().setName('owo').setDescription('Testing 123');\nconst getRoleOption = () => new ChatInputCommandRoleOption().setName('owo').setDescription('Testing 123');\nconst getAttachmentOption = () => new ChatInputCommandAttachmentOption().setName('owo').setDescription('Testing 123');\nconst getMentionableOption = () => new ChatInputCommandMentionableOption().setName('owo').setDescription('Testing 123');\nconst getSubcommandGroup = () =>\n\tnew ChatInputCommandSubcommandGroupBuilder().setName('owo').setDescription('Testing 123');\nconst getSubcommand = () => new ChatInputCommandSubcommandBuilder().setName('owo').setDescription('Testing 123');\n\nclass Collection {\n\tpublic readonly [Symbol.toStringTag] = 'Map';\n}\n\ndescribe('ChatInput Commands', () => {\n\tdescribe('ChatInputCommandBuilder', () => {\n\t\tdescribe('Builder with no options', () => {\n\t\t\ttest('GIVEN empty builder THEN throw error when calling toJSON', () => {\n\t\t\t\texpect(() => getBuilder().toJSON()).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN valid builder THEN does not throw error', () => {\n\t\t\t\texpect(() => getBuilder().setName('example').setDescription('Example command').toJSON()).not.toThrowError();\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Builder with simple options', () => {\n\t\t\ttest('GIVEN valid builder THEN returns type included', () => {\n\t\t\t\texpect(getNamedBuilder().toJSON()).includes({ type: ApplicationCommandType.ChatInput });\n\t\t\t});\n\n\t\t\ttest('GIVEN valid builder with options THEN does not throw error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetBuilder()\n\t\t\t\t\t\t.setName('example')\n\t\t\t\t\t\t.setDescription('Example command')\n\t\t\t\t\t\t.addBooleanOptions((boolean) =>\n\t\t\t\t\t\t\tboolean.setName('iscool').setDescription('Are we cool or what?').setRequired(true),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addChannelOptions((channel) => channel.setName('iscool').setDescription('Are we cool or what?'))\n\t\t\t\t\t\t.addMentionableOptions((mentionable) =>\n\t\t\t\t\t\t\tmentionable.setName('iscool').setDescription('Are we cool or what?'),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addRoleOptions((role) => role.setName('iscool').setDescription('Are we cool or what?'))\n\t\t\t\t\t\t.addUserOptions((user) => user.setName('iscool').setDescription('Are we cool or what?'))\n\t\t\t\t\t\t.addIntegerOptions((integer) =>\n\t\t\t\t\t\t\tinteger\n\t\t\t\t\t\t\t\t.setName('iscool')\n\t\t\t\t\t\t\t\t.setDescription('Are we cool or what?')\n\t\t\t\t\t\t\t\t.addChoices({ name: 'Very cool', value: 1_000 })\n\t\t\t\t\t\t\t\t.addChoices([{ name: 'Even cooler', value: 2_000 }]),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addNumberOptions((number) =>\n\t\t\t\t\t\t\tnumber\n\t\t\t\t\t\t\t\t.setName('iscool')\n\t\t\t\t\t\t\t\t.setDescription('Are we cool or what?')\n\t\t\t\t\t\t\t\t.addChoices({ name: 'Very cool', value: 1.5 })\n\t\t\t\t\t\t\t\t.addChoices([{ name: 'Even cooler', value: 2.5 }]),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addStringOptions((string) =>\n\t\t\t\t\t\t\tstring\n\t\t\t\t\t\t\t\t.setName('iscool')\n\t\t\t\t\t\t\t\t.setDescription('Are we cool or what?')\n\t\t\t\t\t\t\t\t.addChoices({ name: 'Fancy Pants', value: 'fp_1' }, { name: 'Fancy Shoes', value: 'fs_1' })\n\t\t\t\t\t\t\t\t.addChoices([{ name: 'The Whole shebang', value: 'all' }]),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addIntegerOptions((integer) =>\n\t\t\t\t\t\t\tinteger.setName('iscool').setDescription('Are we cool or what?').setAutocomplete(true),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addNumberOptions((number) =>\n\t\t\t\t\t\t\tnumber.setName('iscool').setDescription('Are we cool or what?').setAutocomplete(true),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addStringOptions((string) =>\n\t\t\t\t\t\t\tstring.setName('iscool').setDescription('Are we cool or what?').setAutocomplete(true),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN a builder with invalid autocomplete THEN does throw an error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\t// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error\n\t\t\t\t\tgetNamedBuilder().addStringOptions(getStringOption().setAutocomplete('not a boolean')).toJSON(),\n\t\t\t\t).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN a builder with both choices and autocomplete THEN does throw an error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.addStringOptions(\n\t\t\t\t\t\t\tgetStringOption().setAutocomplete(true).addChoices({ name: 'Fancy Pants', value: 'fp_1' }),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).toThrowError();\n\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.addStringOptions(\n\t\t\t\t\t\t\tgetStringOption()\n\t\t\t\t\t\t\t\t.setAutocomplete(true)\n\t\t\t\t\t\t\t\t.addChoices(\n\t\t\t\t\t\t\t\t\t{ name: 'Fancy Pants', value: 'fp_1' },\n\t\t\t\t\t\t\t\t\t{ name: 'Fancy Shoes', value: 'fs_1' },\n\t\t\t\t\t\t\t\t\t{ name: 'The Whole shebang', value: 'all' },\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).toThrowError();\n\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.addStringOptions(\n\t\t\t\t\t\t\tgetStringOption().addChoices({ name: 'Fancy Pants', value: 'fp_1' }).setAutocomplete(true),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN a builder with valid channel options and channel_types THEN does not throw an error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.addChannelOptions(\n\t\t\t\t\t\t\tgetChannelOption().addChannelTypes(ChannelType.GuildText).addChannelTypes([ChannelType.GuildVoice]),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\n\t\t\t\texpect(() => {\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.addChannelOptions(getChannelOption().addChannelTypes(ChannelType.GuildAnnouncement, ChannelType.GuildText))\n\t\t\t\t\t\t.toJSON();\n\t\t\t\t}).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN a builder with valid channel options and channel_types THEN does throw an error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\t// @ts-expect-error: Invalid channel type\n\t\t\t\t\tgetNamedBuilder().addChannelOptions(getChannelOption().addChannelTypes(100)).toJSON(),\n\t\t\t\t).toThrowError();\n\n\t\t\t\texpect(() =>\n\t\t\t\t\t// @ts-expect-error: Invalid channel types\n\t\t\t\t\tgetNamedBuilder().addChannelOptions(getChannelOption().addChannelTypes(100, 200)).toJSON(),\n\t\t\t\t).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN a builder with invalid number min/max options THEN does throw an error', () => {\n\t\t\t\t// @ts-expect-error: Invalid max value\n\t\t\t\texpect(() => getNamedBuilder().addNumberOptions(getNumberOption().setMaxValue('test')).toJSON()).toThrowError();\n\n\t\t\t\texpect(() =>\n\t\t\t\t\t// @ts-expect-error: Invalid max value\n\t\t\t\t\tgetNamedBuilder().addIntegerOptions(getIntegerOption().setMaxValue('test')).toJSON(),\n\t\t\t\t).toThrowError();\n\n\t\t\t\t// @ts-expect-error: Invalid min value\n\t\t\t\texpect(() => getNamedBuilder().addNumberOptions(getNumberOption().setMinValue('test')).toJSON()).toThrowError();\n\n\t\t\t\texpect(() =>\n\t\t\t\t\t// @ts-expect-error: Invalid min value\n\t\t\t\t\tgetNamedBuilder().addIntegerOptions(getIntegerOption().setMinValue('test')).toJSON(),\n\t\t\t\t).toThrowError();\n\n\t\t\t\texpect(() => getNamedBuilder().addIntegerOptions(getIntegerOption().setMinValue(1.5)).toJSON()).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN a builder with valid number min/max options THEN does not throw an error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder().addIntegerOptions(getIntegerOption().setMinValue(1)).toJSON(),\n\t\t\t\t).not.toThrowError();\n\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder().addNumberOptions(getNumberOption().setMinValue(1.5)).toJSON(),\n\t\t\t\t).not.toThrowError();\n\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder().addIntegerOptions(getIntegerOption().setMaxValue(1)).toJSON(),\n\t\t\t\t).not.toThrowError();\n\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder().addNumberOptions(getNumberOption().setMaxValue(1.5)).toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN an already built builder THEN does not throw an error', () => {\n\t\t\t\texpect(() => getNamedBuilder().addStringOptions(getStringOption()).toJSON()).not.toThrowError();\n\n\t\t\t\texpect(() => getNamedBuilder().addIntegerOptions(getIntegerOption()).toJSON()).not.toThrowError();\n\n\t\t\t\texpect(() => getNamedBuilder().addNumberOptions(getNumberOption()).toJSON()).not.toThrowError();\n\n\t\t\t\texpect(() => getNamedBuilder().addBooleanOptions(getBooleanOption()).toJSON()).not.toThrowError();\n\n\t\t\t\texpect(() => getNamedBuilder().addUserOptions(getUserOption()).toJSON()).not.toThrowError();\n\n\t\t\t\texpect(() => getNamedBuilder().addChannelOptions(getChannelOption()).toJSON()).not.toThrowError();\n\n\t\t\t\texpect(() => getNamedBuilder().addRoleOptions(getRoleOption()).toJSON()).not.toThrowError();\n\n\t\t\t\texpect(() => getNamedBuilder().addAttachmentOptions(getAttachmentOption()).toJSON()).not.toThrowError();\n\n\t\t\t\texpect(() => getNamedBuilder().addMentionableOptions(getMentionableOption()).toJSON()).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN invalid name THEN throw error', () => {\n\t\t\t\texpect(() => getBuilder().setName('TEST_COMMAND').setDescription(':3').toJSON()).toThrowError();\n\t\t\t\texpect(() => getBuilder().setName('ĂĂĂĂĂĂ').setDescription(':3').toJSON()).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN valid names THEN does not throw error', () => {\n\t\t\t\texpect(() => getBuilder().setName('hi_there').setDescription(':3').toJSON()).not.toThrowError();\n\t\t\t\texpect(() => getBuilder().setName('o_comandă').setDescription(':3').toJSON()).not.toThrowError();\n\t\t\t\texpect(() => getBuilder().setName('どうも').setDescription(':3').toJSON()).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN invalid returns for builder THEN throw error', () => {\n\t\t\t\t// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error\n\t\t\t\texpect(() => getNamedBuilder().addBooleanOptions(true).toJSON()).toThrowError();\n\n\t\t\t\t// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error\n\t\t\t\texpect(() => getNamedBuilder().addBooleanOptions(null).toJSON()).toThrowError();\n\n\t\t\t\t// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error\n\t\t\t\texpect(() => getNamedBuilder().addBooleanOptions(undefined).toJSON()).toThrowError();\n\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error\n\t\t\t\t\t\t.addBooleanOptions(() => ChatInputCommandStringOption)\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).toThrowError();\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error\n\t\t\t\t\t\t.addBooleanOptions(() => new Collection())\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN an option that is autocompletable and has choices, THEN passing nothing to setChoices should not throw an error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder().addStringOptions(getStringOption().setAutocomplete(true).setChoices()).toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN an option that is autocompletable, THEN setting choices should throw an error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.addStringOptions(getStringOption().setAutocomplete(true).setChoices({ name: 'owo', value: 'uwu' }))\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN an option, THEN setting choices should not throw an error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.addStringOptions(getStringOption().setChoices({ name: 'owo', value: 'uwu' }))\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN valid builder with NSFW, THEN does not throw error', () => {\n\t\t\t\texpect(() => getNamedBuilder().setName('foo').setDescription('foo').setNSFW(true).toJSON()).not.toThrowError();\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Builder with subcommand (group) options', () => {\n\t\t\ttest('GIVEN builder with subcommand group THEN does not throw error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.addSubcommandGroups((group) =>\n\t\t\t\t\t\t\tgroup.setName('group').setDescription('Group us together!').addSubcommands(getSubcommand()),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN builder with subcommand THEN does not throw error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.addSubcommands((subcommand) => subcommand.setName('boop').setDescription('Boops a fellow nerd (you)'))\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN builder with subcommand THEN has regular ChatInput command fields', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetBuilder()\n\t\t\t\t\t\t.setName('name')\n\t\t\t\t\t\t.setDescription('description')\n\t\t\t\t\t\t.addSubcommands((option) => option.setName('ye').setDescription('ye'))\n\t\t\t\t\t\t.addSubcommands((option) => option.setName('no').setDescription('no'))\n\t\t\t\t\t\t.setDefaultMemberPermissions(1n)\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN builder with already built subcommand group THEN does not throw error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder().addSubcommandGroups(getSubcommandGroup().addSubcommands(getSubcommand())).toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN builder with already built subcommand THEN does not throw error', () => {\n\t\t\t\texpect(() => getNamedBuilder().addSubcommands(getSubcommand()).toJSON()).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN builder with already built subcommand with options THEN does not throw error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder().addSubcommands(getSubcommand().addBooleanOptions(getBooleanOption())).toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN builder with a subcommand that tries to add an invalid result THEN throw error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\t// @ts-expect-error: Checking if check works JS-side too\n\t\t\t\t\tgetNamedBuilder().addSubcommands(getSubcommand()).addIntegerOptions(getInteger()).toJSON(),\n\t\t\t\t).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN no valid return for an addSubcommand(Group) method THEN throw error', () => {\n\t\t\t\t// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error\n\t\t\t\texpect(() => getNamedBuilder().addSubcommands(getSubcommandGroup()).toJSON()).toThrowError();\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Subcommand group builder', () => {\n\t\t\ttest('GIVEN no valid subcommand THEN throw error', () => {\n\t\t\t\texpect(() => getSubcommandGroup().addSubcommands().toJSON()).toThrowError();\n\n\t\t\t\t// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error\n\t\t\t\texpect(() => getSubcommandGroup().addSubcommands(getSubcommandGroup()).toJSON()).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN a valid subcommand THEN does not throw an error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetSubcommandGroup()\n\t\t\t\t\t\t.addSubcommands((sub) => sub.setName('sub').setDescription('Testing 123'))\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Subcommand builder', () => {\n\t\t\ttest('GIVEN a valid subcommand with options THEN does not throw error', () => {\n\t\t\t\texpect(() => getSubcommand().addBooleanOptions(getBooleanOption()).toJSON()).not.toThrowError();\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Subcommand builder and subcommand group builder', () => {\n\t\t\ttest('GIVEN both types THEN does not throw error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.addSubcommands(getSubcommand())\n\t\t\t\t\t\t.addSubcommandGroups(getSubcommandGroup().addSubcommands(getSubcommand()))\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\t\t});\n\n\t\tdescribe('ChatInput command localizations', () => {\n\t\t\tconst expectedSingleLocale = { [Locale.EnglishUS]: 'foobar' };\n\t\t\tconst expectedMultipleLocales = {\n\t\t\t\t...expectedSingleLocale,\n\t\t\t\tbg: 'test',\n\t\t\t};\n\n\t\t\ttest('GIVEN valid name localizations THEN does not throw error', () => {\n\t\t\t\texpect(() => getNamedBuilder().setNameLocalization(Locale.EnglishUS, 'foobar').toJSON()).not.toThrowError();\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.setNameLocalizations({ [Locale.EnglishUS]: 'foobar' })\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN invalid name localizations THEN does throw error', () => {\n\t\t\t\t// @ts-expect-error: Invalid localization\n\t\t\t\texpect(() => getNamedBuilder().setNameLocalization('en-U', 'foobar').toJSON()).toThrowError();\n\t\t\t\t// @ts-expect-error: Invalid localization\n\t\t\t\texpect(() => getNamedBuilder().setNameLocalizations({ 'en-U': 'foobar' }).toJSON()).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN valid name localizations THEN valid data is stored', () => {\n\t\t\t\texpect(getNamedBuilder().setNameLocalization(Locale.EnglishUS, 'foobar').toJSON().name_localizations).toEqual(\n\t\t\t\t\texpectedSingleLocale,\n\t\t\t\t);\n\t\t\t\texpect(\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.setNameLocalizations({ [Locale.EnglishUS]: 'foobar', bg: 'test' })\n\t\t\t\t\t\t.toJSON().name_localizations,\n\t\t\t\t).toEqual(expectedMultipleLocales);\n\t\t\t\texpect(getNamedBuilder().clearNameLocalizations().toJSON().name_localizations).toBeUndefined();\n\t\t\t\texpect(getNamedBuilder().clearNameLocalization(Locale.EnglishUS).toJSON().name_localizations).toEqual({\n\t\t\t\t\t[Locale.EnglishUS]: undefined,\n\t\t\t\t});\n\t\t\t});\n\n\t\t\ttest('GIVEN valid description localizations THEN does not throw error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder().setDescriptionLocalization(Locale.EnglishUS, 'foobar').toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.setDescriptionLocalizations({ [Locale.EnglishUS]: 'foobar' })\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN invalid description localizations THEN does throw error', () => {\n\t\t\t\t// @ts-expect-error: Invalid localization description\n\t\t\t\texpect(() => getNamedBuilder().setDescriptionLocalization('en-U', 'foobar').toJSON()).toThrowError();\n\t\t\t\t// @ts-expect-error: Invalid localization description\n\t\t\t\texpect(() => getNamedBuilder().setDescriptionLocalizations({ 'en-U': 'foobar' }).toJSON()).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN valid description localizations THEN valid data is stored', () => {\n\t\t\t\texpect(\n\t\t\t\t\tgetNamedBuilder().setDescriptionLocalization(Locale.EnglishUS, 'foobar').toJSON(false)\n\t\t\t\t\t\t.description_localizations,\n\t\t\t\t).toEqual(expectedSingleLocale);\n\t\t\t\texpect(\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.setDescriptionLocalizations({ [Locale.EnglishUS]: 'foobar', bg: 'test' })\n\t\t\t\t\t\t.toJSON(false).description_localizations,\n\t\t\t\t).toEqual(expectedMultipleLocales);\n\t\t\t\texpect(\n\t\t\t\t\tgetNamedBuilder().clearDescriptionLocalizations().toJSON(false).description_localizations,\n\t\t\t\t).toBeUndefined();\n\t\t\t\texpect(\n\t\t\t\t\tgetNamedBuilder().clearDescriptionLocalization(Locale.EnglishUS).toJSON(false).description_localizations,\n\t\t\t\t).toEqual({\n\t\t\t\t\t[Locale.EnglishUS]: undefined,\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\tdescribe('permissions', () => {\n\t\t\ttest('GIVEN valid permission string THEN does not throw error', () => {\n\t\t\t\texpect(() => getNamedBuilder().setDefaultMemberPermissions('1').toJSON()).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN valid permission bitfield THEN does not throw error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.setDefaultMemberPermissions(PermissionFlagsBits.AddReactions | PermissionFlagsBits.AttachFiles)\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN null permissions THEN does not throw error', () => {\n\t\t\t\texpect(() => getNamedBuilder().clearDefaultMemberPermissions().toJSON()).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN invalid inputs THEN does throw error', () => {\n\t\t\t\texpect(() => getNamedBuilder().setDefaultMemberPermissions('1.1').toJSON()).toThrowError();\n\t\t\t\texpect(() => getNamedBuilder().setDefaultMemberPermissions(1.1).toJSON()).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN valid permission with options THEN does not throw error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder().addBooleanOptions(getBooleanOption()).setDefaultMemberPermissions('1').toJSON(),\n\t\t\t\t).not.toThrowError();\n\n\t\t\t\texpect(() => getNamedBuilder().addChannelOptions(getChannelOption()).toJSON()).not.toThrowError();\n\t\t\t});\n\t\t});\n\n\t\tdescribe('contexts', () => {\n\t\t\ttest('GIVEN a builder with valid contexts THEN does not throw an error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder().setContexts([InteractionContextType.Guild, InteractionContextType.BotDM]).toJSON(),\n\t\t\t\t).not.toThrowError();\n\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder().setContexts(InteractionContextType.Guild, InteractionContextType.BotDM).toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN a builder with invalid contexts THEN does throw an error', () => {\n\t\t\t\t// @ts-expect-error: Invalid contexts\n\t\t\t\texpect(() => getNamedBuilder().setContexts(999).toJSON()).toThrowError();\n\n\t\t\t\t// @ts-expect-error: Invalid contexts\n\t\t\t\texpect(() => getNamedBuilder().setContexts([999, 998]).toJSON()).toThrowError();\n\t\t\t});\n\t\t});\n\n\t\tdescribe('integration types', () => {\n\t\t\ttest('GIVEN a builder with valid integration types THEN does not throw an error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetNamedBuilder()\n\t\t\t\t\t\t.setIntegrationTypes(ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall)\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN a builder with invalid integration types THEN does throw an error', () => {\n\t\t\t\t// @ts-expect-error: Invalid integration types\n\t\t\t\texpect(() => getNamedBuilder().setIntegrationTypes(999).toJSON()).toThrowError();\n\n\t\t\t\t// @ts-expect-error: Invalid integration types\n\t\t\t\texpect(() => getNamedBuilder().setIntegrationTypes([999, 998]).toJSON()).toThrowError();\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/interactions/ChatInputCommands/Options.test.ts",
    "content": "import {\n\tApplicationCommandOptionType,\n\tChannelType,\n\ttype APIApplicationCommandAttachmentOption,\n\ttype APIApplicationCommandBooleanOption,\n\ttype APIApplicationCommandChannelOption,\n\ttype APIApplicationCommandIntegerOption,\n\ttype APIApplicationCommandMentionableOption,\n\ttype APIApplicationCommandNumberOption,\n\ttype APIApplicationCommandRoleOption,\n\ttype APIApplicationCommandStringOption,\n\ttype APIApplicationCommandUserOption,\n} from 'discord-api-types/v10';\nimport { describe, test, expect } from 'vitest';\nimport {\n\tChatInputCommandAttachmentOption,\n\tChatInputCommandBooleanOption,\n\tChatInputCommandChannelOption,\n\tChatInputCommandIntegerOption,\n\tChatInputCommandMentionableOption,\n\tChatInputCommandNumberOption,\n\tChatInputCommandRoleOption,\n\tChatInputCommandStringOption,\n\tChatInputCommandUserOption,\n} from '../../../src/index.js';\n\nconst getBooleanOption = () =>\n\tnew ChatInputCommandBooleanOption().setName('owo').setDescription('Testing 123').setRequired(true);\n\nconst getChannelOption = () =>\n\tnew ChatInputCommandChannelOption()\n\t\t.setName('owo')\n\t\t.setDescription('Testing 123')\n\t\t.setRequired(true)\n\t\t.addChannelTypes(ChannelType.GuildText);\n\nconst getStringOption = () =>\n\tnew ChatInputCommandStringOption().setName('owo').setDescription('Testing 123').setRequired(true);\n\nconst getIntegerOption = () =>\n\tnew ChatInputCommandIntegerOption()\n\t\t.setName('owo')\n\t\t.setDescription('Testing 123')\n\t\t.setRequired(true)\n\t\t.setMinValue(-1)\n\t\t.setMaxValue(10);\n\nconst getNumberOption = () =>\n\tnew ChatInputCommandNumberOption()\n\t\t.setName('owo')\n\t\t.setDescription('Testing 123')\n\t\t.setRequired(true)\n\t\t.setMinValue(-1.23)\n\t\t.setMaxValue(10);\n\nconst getUserOption = () =>\n\tnew ChatInputCommandUserOption().setName('owo').setDescription('Testing 123').setRequired(true);\n\nconst getRoleOption = () =>\n\tnew ChatInputCommandRoleOption().setName('owo').setDescription('Testing 123').setRequired(true);\n\nconst getMentionableOption = () =>\n\tnew ChatInputCommandMentionableOption().setName('owo').setDescription('Testing 123').setRequired(true);\n\nconst getAttachmentOption = () =>\n\tnew ChatInputCommandAttachmentOption().setName('attachment').setDescription('attachment').setRequired(true);\n\ndescribe('Application Command toJSON() results', () => {\n\ttest('GIVEN a boolean option THEN calling toJSON should return a valid JSON', () => {\n\t\texpect(getBooleanOption().toJSON()).toEqual<APIApplicationCommandBooleanOption>({\n\t\t\tname: 'owo',\n\t\t\tdescription: 'Testing 123',\n\t\t\ttype: ApplicationCommandOptionType.Boolean,\n\t\t\trequired: true,\n\t\t});\n\t});\n\n\ttest('GIVEN a channel option THEN calling toJSON should return a valid JSON', () => {\n\t\texpect(getChannelOption().toJSON()).toEqual<APIApplicationCommandChannelOption>({\n\t\t\tname: 'owo',\n\t\t\tdescription: 'Testing 123',\n\t\t\ttype: ApplicationCommandOptionType.Channel,\n\t\t\trequired: true,\n\t\t\tchannel_types: [ChannelType.GuildText],\n\t\t});\n\t});\n\n\ttest('GIVEN a integer option THEN calling toJSON should return a valid JSON', () => {\n\t\texpect(getIntegerOption().toJSON()).toEqual<APIApplicationCommandIntegerOption>({\n\t\t\tname: 'owo',\n\t\t\tdescription: 'Testing 123',\n\t\t\ttype: ApplicationCommandOptionType.Integer,\n\t\t\trequired: true,\n\t\t\tmax_value: 10,\n\t\t\tmin_value: -1,\n\t\t});\n\n\t\texpect(getIntegerOption().setAutocomplete(true).setChoices().toJSON()).toEqual<APIApplicationCommandIntegerOption>({\n\t\t\tname: 'owo',\n\t\t\tdescription: 'Testing 123',\n\t\t\ttype: ApplicationCommandOptionType.Integer,\n\t\t\trequired: true,\n\t\t\tmax_value: 10,\n\t\t\tmin_value: -1,\n\t\t\tautocomplete: true,\n\t\t\tchoices: [],\n\t\t});\n\n\t\texpect(\n\t\t\tgetIntegerOption().addChoices({ name: 'uwu', value: 1 }).toJSON(),\n\t\t).toEqual<APIApplicationCommandIntegerOption>({\n\t\t\tname: 'owo',\n\t\t\tdescription: 'Testing 123',\n\t\t\ttype: ApplicationCommandOptionType.Integer,\n\t\t\trequired: true,\n\t\t\tmax_value: 10,\n\t\t\tmin_value: -1,\n\t\t\tchoices: [{ name: 'uwu', value: 1 }],\n\t\t});\n\t});\n\n\ttest('GIVEN a mentionable option THEN calling toJSON should return a valid JSON', () => {\n\t\texpect(getMentionableOption().toJSON()).toEqual<APIApplicationCommandMentionableOption>({\n\t\t\tname: 'owo',\n\t\t\tdescription: 'Testing 123',\n\t\t\ttype: ApplicationCommandOptionType.Mentionable,\n\t\t\trequired: true,\n\t\t});\n\t});\n\n\ttest('GIVEN a number option THEN calling toJSON should return a valid JSON', () => {\n\t\texpect(getNumberOption().toJSON()).toEqual<APIApplicationCommandNumberOption>({\n\t\t\tname: 'owo',\n\t\t\tdescription: 'Testing 123',\n\t\t\ttype: ApplicationCommandOptionType.Number,\n\t\t\trequired: true,\n\t\t\tmax_value: 10,\n\t\t\tmin_value: -1.23,\n\t\t});\n\n\t\texpect(getNumberOption().setAutocomplete(true).setChoices().toJSON()).toEqual<APIApplicationCommandNumberOption>({\n\t\t\tname: 'owo',\n\t\t\tdescription: 'Testing 123',\n\t\t\ttype: ApplicationCommandOptionType.Number,\n\t\t\trequired: true,\n\t\t\tmax_value: 10,\n\t\t\tmin_value: -1.23,\n\t\t\tautocomplete: true,\n\t\t\t// TODO\n\t\t\tchoices: [],\n\t\t});\n\n\t\texpect(getNumberOption().addChoices({ name: 'uwu', value: 1 }).toJSON()).toEqual<APIApplicationCommandNumberOption>(\n\t\t\t{\n\t\t\t\tname: 'owo',\n\t\t\t\tdescription: 'Testing 123',\n\t\t\t\ttype: ApplicationCommandOptionType.Number,\n\t\t\t\trequired: true,\n\t\t\t\tmax_value: 10,\n\t\t\t\tmin_value: -1.23,\n\t\t\t\tchoices: [{ name: 'uwu', value: 1 }],\n\t\t\t},\n\t\t);\n\t});\n\n\ttest('GIVEN a role option THEN calling toJSON should return a valid JSON', () => {\n\t\texpect(getRoleOption().toJSON()).toEqual<APIApplicationCommandRoleOption>({\n\t\t\tname: 'owo',\n\t\t\tdescription: 'Testing 123',\n\t\t\ttype: ApplicationCommandOptionType.Role,\n\t\t\trequired: true,\n\t\t});\n\t});\n\n\ttest('GIVEN a string option THEN calling toJSON should return a valid JSON', () => {\n\t\texpect(getStringOption().setMinLength(1).setMaxLength(10).toJSON()).toEqual<APIApplicationCommandStringOption>({\n\t\t\tname: 'owo',\n\t\t\tdescription: 'Testing 123',\n\t\t\ttype: ApplicationCommandOptionType.String,\n\t\t\trequired: true,\n\t\t\tmax_length: 10,\n\t\t\tmin_length: 1,\n\t\t});\n\n\t\texpect(getStringOption().setAutocomplete(true).setChoices().toJSON()).toEqual<APIApplicationCommandStringOption>({\n\t\t\tname: 'owo',\n\t\t\tdescription: 'Testing 123',\n\t\t\ttype: ApplicationCommandOptionType.String,\n\t\t\trequired: true,\n\t\t\tautocomplete: true,\n\t\t\t// TODO\n\t\t\tchoices: [],\n\t\t});\n\n\t\texpect(\n\t\t\tgetStringOption().addChoices({ name: 'uwu', value: '1' }).toJSON(),\n\t\t).toEqual<APIApplicationCommandStringOption>({\n\t\t\tname: 'owo',\n\t\t\tdescription: 'Testing 123',\n\t\t\ttype: ApplicationCommandOptionType.String,\n\t\t\trequired: true,\n\t\t\tchoices: [{ name: 'uwu', value: '1' }],\n\t\t});\n\t});\n\n\ttest('GIVEN a user option THEN calling toJSON should return a valid JSON', () => {\n\t\texpect(getUserOption().toJSON()).toEqual<APIApplicationCommandUserOption>({\n\t\t\tname: 'owo',\n\t\t\tdescription: 'Testing 123',\n\t\t\ttype: ApplicationCommandOptionType.User,\n\t\t\trequired: true,\n\t\t});\n\t});\n\n\ttest('GIVEN an attachment option THEN calling toJSON should return a valid JSON', () => {\n\t\texpect(getAttachmentOption().toJSON()).toEqual<APIApplicationCommandAttachmentOption>({\n\t\t\tname: 'attachment',\n\t\t\tdescription: 'attachment',\n\t\t\ttype: ApplicationCommandOptionType.Attachment,\n\t\t\trequired: true,\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/interactions/ContextMenuCommands.test.ts",
    "content": "import { ApplicationIntegrationType, InteractionContextType, Locale, PermissionFlagsBits } from 'discord-api-types/v10';\nimport { describe, test, expect } from 'vitest';\nimport { MessageContextCommandBuilder } from '../../src/index.js';\n\nconst getBuilder = () => new MessageContextCommandBuilder();\n\ndescribe('Context Menu Commands', () => {\n\tdescribe('ContextMenuCommandBuilder', () => {\n\t\tdescribe('Builder tests', () => {\n\t\t\ttest('GIVEN empty builder THEN throw error when calling toJSON', () => {\n\t\t\t\texpect(() => getBuilder().toJSON()).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN invalid name THEN throw error', () => {\n\t\t\t\texpect(() => getBuilder().setName(' ').toJSON()).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN valid names THEN does not throw error', () => {\n\t\t\t\texpect(() => getBuilder().setName('hi_there').toJSON()).not.toThrowError();\n\n\t\t\t\texpect(() => getBuilder().setName('A COMMAND').toJSON()).not.toThrowError();\n\n\t\t\t\t// Translation: a_command\n\t\t\t\texpect(() => getBuilder().setName('o_comandă').toJSON()).not.toThrowError();\n\n\t\t\t\t// Translation: thx (according to GTranslate)\n\t\t\t\texpect(() => getBuilder().setName('どうも').toJSON()).not.toThrowError();\n\n\t\t\t\texpect(() => getBuilder().setName('🎉').toJSON()).not.toThrowError();\n\t\t\t\texpect(() => getBuilder().setName('🫆').toJSON()).not.toThrowError();\n\t\t\t\texpect(() => getBuilder().setName('🎉 abc').toJSON()).not.toThrowError();\n\t\t\t\texpect(() => getBuilder().setName('🫆 abc').toJSON()).not.toThrowError();\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Context menu command localizations', () => {\n\t\t\tconst expectedSingleLocale = { [Locale.EnglishUS]: 'foobar' };\n\t\t\tconst expectedMultipleLocales = {\n\t\t\t\t...expectedSingleLocale,\n\t\t\t\tbg: 'test',\n\t\t\t};\n\n\t\t\ttest('GIVEN valid name localizations THEN does not throw error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetBuilder().setName('test').setNameLocalization(Locale.EnglishUS, 'foobar').toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetBuilder()\n\t\t\t\t\t\t.setName('test')\n\t\t\t\t\t\t.setNameLocalizations({ [Locale.EnglishUS]: 'foobar' })\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN invalid name localizations THEN does throw error', () => {\n\t\t\t\t// @ts-expect-error: Invalid localization\n\t\t\t\texpect(() => getBuilder().setNameLocalization('en-U', 'foobar').toJSON()).toThrowError();\n\t\t\t\t// @ts-expect-error: Invalid localization\n\t\t\t\texpect(() => getBuilder().setNameLocalizations({ 'en-U': 'foobar' }).toJSON()).toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN valid name localizations THEN valid data is stored', () => {\n\t\t\t\texpect(\n\t\t\t\t\tgetBuilder().setName('hi').setNameLocalization(Locale.EnglishUS, 'foobar').toJSON().name_localizations,\n\t\t\t\t).toEqual(expectedSingleLocale);\n\t\t\t\texpect(\n\t\t\t\t\tgetBuilder()\n\t\t\t\t\t\t.setName('hi')\n\t\t\t\t\t\t.setNameLocalizations({ [Locale.EnglishUS]: 'foobar', bg: 'test' })\n\t\t\t\t\t\t.toJSON().name_localizations,\n\t\t\t\t).toEqual(expectedMultipleLocales);\n\t\t\t\texpect(getBuilder().setName('hi').clearNameLocalizations().toJSON().name_localizations).toBeUndefined();\n\t\t\t\texpect(getBuilder().setName('hi').clearNameLocalization(Locale.EnglishUS).toJSON().name_localizations).toEqual({\n\t\t\t\t\t[Locale.EnglishUS]: undefined,\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\tdescribe('permissions', () => {\n\t\t\ttest('GIVEN valid permission string THEN does not throw error', () => {\n\t\t\t\texpect(() => getBuilder().setName('test').setDefaultMemberPermissions('1').toJSON()).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN valid permission bitfield THEN does not throw error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetBuilder()\n\t\t\t\t\t\t.setName('test')\n\t\t\t\t\t\t.setDefaultMemberPermissions(PermissionFlagsBits.AddReactions | PermissionFlagsBits.AttachFiles)\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN invalid inputs THEN does throw error', () => {\n\t\t\t\texpect(() => getBuilder().setName('hi').setDefaultMemberPermissions('1.1').toJSON()).toThrowError();\n\n\t\t\t\texpect(() => getBuilder().setName('hi').setDefaultMemberPermissions(1.1).toJSON()).toThrowError();\n\t\t\t});\n\t\t});\n\n\t\tdescribe('contexts', () => {\n\t\t\ttest('GIVEN a builder with valid contexts THEN does not throw an error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetBuilder()\n\t\t\t\t\t\t.setName('test')\n\t\t\t\t\t\t.setContexts([InteractionContextType.Guild, InteractionContextType.BotDM])\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetBuilder().setName('test').setContexts(InteractionContextType.Guild, InteractionContextType.BotDM).toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN a builder with invalid contexts THEN does throw an error', () => {\n\t\t\t\t// @ts-expect-error: Invalid contexts\n\t\t\t\texpect(() => getBuilder().setName('hi').setContexts(999).toJSON()).toThrowError();\n\n\t\t\t\t// @ts-expect-error: Invalid contexts\n\t\t\t\texpect(() => getBuilder().setName('hi').setContexts([999, 998]).toJSON()).toThrowError();\n\t\t\t});\n\t\t});\n\n\t\tdescribe('integration types', () => {\n\t\t\ttest('GIVEN a builder with valid integration types THEN does not throw an error', () => {\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetBuilder()\n\t\t\t\t\t\t.setName('test')\n\t\t\t\t\t\t.setIntegrationTypes([ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall])\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\n\t\t\t\texpect(() =>\n\t\t\t\t\tgetBuilder()\n\t\t\t\t\t\t.setName('test')\n\t\t\t\t\t\t.setIntegrationTypes(ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall)\n\t\t\t\t\t\t.toJSON(),\n\t\t\t\t).not.toThrowError();\n\t\t\t});\n\n\t\t\ttest('GIVEN a builder with invalid integration types THEN does throw an error', () => {\n\t\t\t\t// @ts-expect-error: Invalid integration types\n\t\t\t\texpect(() => getBuilder().setName('hi').setIntegrationTypes(999).toJSON()).toThrowError();\n\n\t\t\t\t// @ts-expect-error: Invalid integration types\n\t\t\t\texpect(() => getBuilder().setName('hi').setIntegrationTypes([999, 998]).toJSON()).toThrowError();\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/interactions/modal.test.ts",
    "content": "import { ComponentType, TextInputStyle, type APIModalInteractionResponseCallbackData } from 'discord-api-types/v10';\nimport { describe, test, expect } from 'vitest';\nimport { ModalBuilder, TextInputBuilder, LabelBuilder, TextDisplayBuilder } from '../../src/index.js';\n\nconst modal = () => new ModalBuilder();\n\nconst label = () =>\n\tnew LabelBuilder()\n\t\t.setLabel('label')\n\t\t.setTextInputComponent(new TextInputBuilder().setCustomId('text').setStyle(TextInputStyle.Short));\n\nconst textDisplay = () => new TextDisplayBuilder().setContent('text');\n\ndescribe('Modals', () => {\n\ttest('GIVEN valid fields THEN builder does not throw', () => {\n\t\texpect(() =>\n\t\t\tmodal().setTitle('test').setCustomId('foobar').addLabelComponents(label()).toJSON(),\n\t\t).not.toThrowError();\n\n\t\texpect(() =>\n\t\t\tmodal().setTitle('test').setCustomId('foobar').addLabelComponents(label()).toJSON(),\n\t\t).not.toThrowError();\n\n\t\texpect(() =>\n\t\t\tmodal().setTitle('test').setCustomId('foobar').addTextDisplayComponents(textDisplay()).toJSON(),\n\t\t).not.toThrowError();\n\t});\n\n\ttest('GIVEN invalid fields THEN builder does throw', () => {\n\t\texpect(() => modal().setTitle('test').setCustomId('foobar').toJSON()).toThrowError();\n\n\t\t// @ts-expect-error: Custom id is invalid\n\t\texpect(() => modal().setTitle('test').setCustomId(42).toJSON()).toThrowError();\n\t});\n\n\ttest('GIVEN valid input THEN valid JSON outputs are given', () => {\n\t\tconst modalData = {\n\t\t\ttitle: 'title',\n\t\t\tcustom_id: 'custom id',\n\t\t\tcomponents: [\n\t\t\t\t{\n\t\t\t\t\ttype: ComponentType.Label,\n\t\t\t\t\tid: 33,\n\t\t\t\t\tlabel: 'label',\n\t\t\t\t\tdescription: 'description',\n\t\t\t\t\tcomponent: {\n\t\t\t\t\t\ttype: ComponentType.TextInput,\n\t\t\t\t\t\tstyle: TextInputStyle.Paragraph,\n\t\t\t\t\t\tcustom_id: 'custom id',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: ComponentType.TextDisplay,\n\t\t\t\t\tcontent: 'yooooooooo',\n\t\t\t\t},\n\t\t\t],\n\t\t} satisfies APIModalInteractionResponseCallbackData;\n\n\t\texpect(new ModalBuilder(modalData).toJSON()).toEqual(modalData);\n\n\t\texpect(\n\t\t\tmodal()\n\t\t\t\t.setTitle(modalData.title)\n\t\t\t\t.setCustomId('custom id')\n\t\t\t\t.addLabelComponents(\n\t\t\t\t\tnew LabelBuilder()\n\t\t\t\t\t\t.setId(33)\n\t\t\t\t\t\t.setLabel('label')\n\t\t\t\t\t\t.setDescription('description')\n\t\t\t\t\t\t.setTextInputComponent(new TextInputBuilder().setCustomId('custom id').setStyle(TextInputStyle.Paragraph)),\n\t\t\t\t)\n\t\t\t\t.addTextDisplayComponents((textDisplay) => textDisplay.setContent('yooooooooo'))\n\t\t\t\t.toJSON(),\n\t\t).toEqual(modalData);\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/messages/embed.test.ts",
    "content": "import { embedLength } from '@discordjs/util';\nimport { describe, test, expect } from 'vitest';\nimport { EmbedBuilder } from '../../src/index.js';\n\nconst alpha = 'abcdefghijklmnopqrstuvwxyz';\n\nconst dummy = {\n\ttitle: 'ooooo aaaaa uuuuuu aaaa',\n};\n\nconst base = {\n\tauthor: undefined,\n\tfields: [],\n\tfooter: undefined,\n};\n\ndescribe('Embed', () => {\n\tdescribe('Embed getters', () => {\n\t\ttest('GIVEN an embed with specific amount of characters THEN returns amount of characters', () => {\n\t\t\tconst embed = new EmbedBuilder({\n\t\t\t\ttitle: alpha,\n\t\t\t\tdescription: alpha,\n\t\t\t\tfields: [{ name: alpha, value: alpha }],\n\t\t\t\tauthor: { name: alpha },\n\t\t\t\tfooter: { text: alpha },\n\t\t\t});\n\n\t\t\texpect(embedLength(embed.toJSON())).toEqual(alpha.length * 6);\n\t\t});\n\n\t\ttest('GIVEN an embed with zero characters THEN returns amount of characters', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\n\t\t\texpect(embedLength(embed.toJSON(false))).toEqual(0);\n\t\t});\n\t});\n\n\tdescribe('Embed title', () => {\n\t\ttest('GIVEN an embed with a pre-defined title THEN return valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({ title: 'foo' });\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, title: 'foo' });\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#setTitle THEN return valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\t\t\tembed.setTitle('foo');\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, title: 'foo' });\n\t\t});\n\n\t\ttest('GIVEN an embed with a pre-defined title THEN unset title THEN return valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({ title: 'foo', description: ':3' });\n\t\t\tembed.clearTitle();\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, description: ':3', title: undefined });\n\t\t});\n\n\t\ttest('GIVEN an embed with an invalid title THEN throws error', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\n\t\t\tembed.setTitle('a'.repeat(257));\n\n\t\t\texpect(() => embed.toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Embed description', () => {\n\t\ttest('GIVEN an embed with a pre-defined description THEN return valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({ description: 'foo' });\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, description: 'foo' });\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#setDescription THEN return valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\t\t\tembed.setDescription('foo');\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, description: 'foo' });\n\t\t});\n\n\t\ttest('GIVEN an embed with a pre-defined description THEN unset description THEN return valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({ description: 'foo', ...dummy });\n\t\t\tembed.clearDescription();\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, ...dummy, description: undefined });\n\t\t});\n\n\t\ttest('GIVEN an embed with an invalid description THEN throws error', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\n\t\t\tembed.setDescription('a'.repeat(4_097));\n\t\t\texpect(() => embed.toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Embed URL', () => {\n\t\ttest('GIVEN an embed with a pre-defined url THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({ url: 'https://discord.js.org/', ...dummy });\n\t\t\texpect(embed.toJSON()).toStrictEqual({\n\t\t\t\t...base,\n\t\t\t\t...dummy,\n\t\t\t\turl: 'https://discord.js.org/',\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#setURL THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder(dummy);\n\t\t\tembed.setURL('https://discord.js.org/');\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({\n\t\t\t\t...base,\n\t\t\t\t...dummy,\n\t\t\t\turl: 'https://discord.js.org/',\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN an embed with a pre-defined title THEN unset title THEN return valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({ url: 'https://discord.js.org', ...dummy });\n\t\t\tembed.clearURL();\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, ...dummy, url: undefined });\n\t\t});\n\n\t\ttest.each(['owo', 'discord://user'])('GIVEN an embed with an invalid URL THEN throws error', (input) => {\n\t\t\tconst embed = new EmbedBuilder();\n\n\t\t\tembed.setURL(input);\n\t\t\texpect(() => embed.toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Embed Color', () => {\n\t\ttest('GIVEN an embed with a pre-defined color THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({ color: 0xff0000, ...dummy });\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, ...dummy, color: 0xff0000 });\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#setColor THEN returns valid toJSON data', () => {\n\t\t\texpect(new EmbedBuilder(dummy).setColor(0xff0000).toJSON()).toStrictEqual({ ...base, ...dummy, color: 0xff0000 });\n\t\t});\n\n\t\ttest('GIVEN an embed with a pre-defined color THEN unset color THEN return valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({ ...dummy, color: 0xff0000 });\n\t\t\tembed.clearColor();\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, ...dummy, color: undefined });\n\t\t});\n\n\t\ttest('GIVEN an embed with an invalid color THEN throws error', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\n\t\t\t// @ts-expect-error: Invalid color\n\t\t\tembed.setColor('RED');\n\t\t\texpect(() => embed.toJSON()).toThrowError();\n\n\t\t\t// @ts-expect-error: Invalid color\n\t\t\tembed.setColor([42, 36]);\n\t\t\texpect(() => embed.toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Embed Timestamp', () => {\n\t\tconst now = new Date();\n\n\t\ttest('GIVEN an embed with a pre-defined timestamp THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({ timestamp: now.toISOString(), ...dummy });\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, ...dummy, timestamp: now.toISOString() });\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#setTimestamp (with Date) THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder(dummy);\n\t\t\tembed.setTimestamp(now);\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, ...dummy, timestamp: now.toISOString() });\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#setTimestamp (with int) THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder(dummy);\n\t\t\tembed.setTimestamp(now.getTime());\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, ...dummy, timestamp: now.toISOString() });\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#setTimestamp (default) THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder(dummy);\n\t\t\tembed.setTimestamp();\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, ...dummy, timestamp: embed.toJSON().timestamp });\n\t\t});\n\n\t\ttest('GIVEN an embed with a pre-defined timestamp THEN unset timestamp THEN return valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({ timestamp: now.toISOString(), ...dummy });\n\t\t\tembed.clearTimestamp();\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, ...dummy, timestamp: undefined });\n\t\t});\n\t});\n\n\tdescribe('Embed Thumbnail', () => {\n\t\ttest('GIVEN an embed with a pre-defined thumbnail THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({ thumbnail: { url: 'https://discord.js.org/static/logo.svg' } });\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, thumbnail: { url: 'https://discord.js.org/static/logo.svg' } });\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#setThumbnail THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\t\t\tembed.setThumbnail('https://discord.js.org/static/logo.svg');\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, thumbnail: { url: 'https://discord.js.org/static/logo.svg' } });\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#setThumbnail with attachment protocol THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\t\t\tembed.setThumbnail('attachment://discordjs.webp');\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, thumbnail: { url: 'attachment://discordjs.webp' } });\n\t\t});\n\n\t\ttest('GIVEN an embed with a pre-defined thumbnail THEN unset thumbnail THEN return valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({ thumbnail: { url: 'https://discord.js.org/static/logo.svg' }, ...dummy });\n\t\t\tembed.clearThumbnail();\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, ...dummy, thumbnail: undefined });\n\t\t});\n\n\t\ttest('GIVEN an embed with an invalid thumbnail THEN throws error', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\n\t\t\tembed.setThumbnail('owo');\n\t\t\texpect(() => embed.toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Embed Image', () => {\n\t\ttest('GIVEN an embed with a pre-defined image THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({ image: { url: 'https://discord.js.org/static/logo.svg' } });\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, image: { url: 'https://discord.js.org/static/logo.svg' } });\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#setImage with attachment protocol THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\t\t\tembed.setImage('attachment://discordjs.webp');\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, image: { url: 'attachment://discordjs.webp' } });\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#setImage THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\t\t\tembed.setImage('https://discord.js.org/static/logo.svg');\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, image: { url: 'https://discord.js.org/static/logo.svg' } });\n\t\t});\n\n\t\ttest('GIVEN an embed with a pre-defined image THEN unset image THEN return valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({ image: { url: 'https://discord.js/org/static/logo.svg' }, ...dummy });\n\t\t\tembed.clearImage();\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, ...dummy, image: undefined });\n\t\t});\n\n\t\ttest('GIVEN an embed with an invalid image THEN throws error', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\n\t\t\tembed.setImage('owo');\n\t\t\texpect(() => embed.toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Embed Author', () => {\n\t\ttest('GIVEN an embed with a pre-defined author THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({\n\t\t\t\tauthor: { name: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg', url: 'https://discord.js.org' },\n\t\t\t});\n\t\t\texpect(embed.toJSON()).toStrictEqual({\n\t\t\t\t...base,\n\t\t\t\tauthor: { name: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg', url: 'https://discord.js.org' },\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#setAuthor THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\t\t\tembed.setAuthor((author) =>\n\t\t\t\tauthor.setName('Wumpus').setIconURL('https://discord.js.org/static/logo.svg').setURL('https://discord.js.org'),\n\t\t\t);\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({\n\t\t\t\t...base,\n\t\t\t\tauthor: { name: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg', url: 'https://discord.js.org' },\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN an embed with a pre-defined author THEN unset author THEN return valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({\n\t\t\t\tauthor: { name: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg', url: 'https://discord.js.org' },\n\t\t\t\t...dummy,\n\t\t\t});\n\t\t\tembed.clearAuthor();\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, ...dummy, author: undefined });\n\t\t});\n\n\t\ttest('GIVEN an embed with an invalid author name THEN throws error', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\n\t\t\tembed.setAuthor({ name: 'a'.repeat(257) });\n\t\t\texpect(() => embed.toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Embed Footer', () => {\n\t\ttest('GIVEN an embed with a pre-defined footer THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({\n\t\t\t\tfooter: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' },\n\t\t\t});\n\t\t\texpect(embed.toJSON()).toStrictEqual({\n\t\t\t\t...base,\n\t\t\t\tfooter: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' },\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#setAuthor THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\t\t\tembed.setFooter({ text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' });\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({\n\t\t\t\t...base,\n\t\t\t\tfooter: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' },\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN an embed with a pre-defined footer THEN unset footer THEN return valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({\n\t\t\t\t...dummy,\n\t\t\t\tfooter: { text: 'Wumpus', icon_url: 'https://discord.js.org/static/logo.svg' },\n\t\t\t});\n\t\t\tembed.clearFooter();\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, ...dummy, footer: undefined });\n\t\t});\n\n\t\ttest('GIVEN an embed with invalid footer text THEN throws error', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\n\t\t\tembed.setFooter({ text: 'a'.repeat(2_049) });\n\t\t\texpect(() => embed.toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Embed Fields', () => {\n\t\ttest('GIVEN an embed with a pre-defined field THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder({\n\t\t\t\tfields: [{ name: 'foo', value: 'bar' }],\n\t\t\t});\n\t\t\texpect(embed.toJSON()).toStrictEqual({ ...base, fields: [{ name: 'foo', value: 'bar' }] });\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#addFields THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\t\t\tembed.addFields({ name: 'foo', value: 'bar' });\n\t\t\tembed.addFields([\n\t\t\t\t{ name: 'foo', value: 'bar' },\n\t\t\t\t{ name: '', value: '' },\n\t\t\t]);\n\n\t\t\texpect(embed.toJSON()).toStrictEqual({\n\t\t\t\t...base,\n\t\t\t\tfields: [\n\t\t\t\t\t{ name: 'foo', value: 'bar' },\n\t\t\t\t\t{ name: 'foo', value: 'bar' },\n\t\t\t\t\t{ name: '', value: '' },\n\t\t\t\t],\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#spliceFields THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\t\t\tembed.addFields({ name: 'foo', value: 'bar' }, { name: 'foo', value: 'baz' });\n\n\t\t\texpect(embed.spliceFields(0, 1).toJSON()).toStrictEqual({ ...base, fields: [{ name: 'foo', value: 'baz' }] });\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#spliceFields THEN returns valid toJSON data 2', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\t\t\tembed.addFields(...Array.from({ length: 23 }, () => ({ name: 'foo', value: 'bar' })));\n\n\t\t\tembed.spliceFields(0, 3, ...Array.from({ length: 5 }, () => ({ name: 'foo', value: 'bar' })));\n\t\t\texpect(() => embed.toJSON()).not.toThrowError();\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#spliceFields that adds additional fields resulting in fields > 25 THEN throws error', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\t\t\tembed.addFields(...Array.from({ length: 23 }, () => ({ name: 'foo', value: 'bar' })));\n\n\t\t\tembed.spliceFields(0, 3, ...Array.from({ length: 8 }, () => ({ name: 'foo', value: 'bar' })));\n\t\t\texpect(() => embed.toJSON()).toThrowError();\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#setFields THEN returns valid toJSON data', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\n\t\t\tembed.setFields(...Array.from({ length: 25 }, () => ({ name: 'foo', value: 'bar' })));\n\t\t\texpect(() => embed.toJSON()).not.toThrowError();\n\n\t\t\tembed.setFields(Array.from({ length: 25 }, () => ({ name: 'foo', value: 'bar' })));\n\t\t\texpect(() => embed.toJSON()).not.toThrowError();\n\t\t});\n\n\t\ttest('GIVEN an embed using Embed#setFields that sets more than 25 fields THEN throws error', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\n\t\t\tembed.setFields(...Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' })));\n\t\t\texpect(() => embed.toJSON()).toThrowError();\n\n\t\t\tembed.setFields(Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' })));\n\t\t\texpect(() => embed.toJSON()).toThrowError();\n\t\t});\n\n\t\ttest('GIVEN invalid field amount THEN throws error', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\n\t\t\tembed.addFields(...Array.from({ length: 26 }, () => ({ name: 'foo', value: 'bar' })));\n\t\t\texpect(() => embed.toJSON()).toThrowError();\n\t\t});\n\n\t\ttest('GIVEN invalid field name length THEN throws error', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\n\t\t\tembed.addFields({ name: 'a'.repeat(257), value: 'bar' });\n\t\t\texpect(() => embed.toJSON()).toThrowError();\n\t\t});\n\n\t\ttest('GIVEN invalid field value length THEN throws error', () => {\n\t\t\tconst embed = new EmbedBuilder();\n\n\t\t\tembed.addFields({ name: '', value: 'a'.repeat(1_025) });\n\t\t\texpect(() => embed.toJSON()).toThrowError();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/messages/fileBody.test.ts",
    "content": "import { Buffer } from 'node:buffer';\nimport type { RawFile } from '@discordjs/util';\nimport { test, expect } from 'vitest';\nimport { AttachmentBuilder, MessageBuilder } from '../../src/index.js';\n\ntest('AttachmentBuilder stores and exposes file data', () => {\n\tconst data = Buffer.from('hello world');\n\tconst attachment = new AttachmentBuilder()\n\t\t.setId(1)\n\t\t.setFilename('greeting.txt')\n\t\t.setFileData(data)\n\t\t.setFileContentType('text/plain');\n\n\texpect(attachment.getRawFile()).toStrictEqual({\n\t\tcontentType: 'text/plain',\n\t\tdata,\n\t\tkey: 'files[1]',\n\t\tname: 'greeting.txt',\n\t});\n\n\tattachment.clearFileData();\n\tattachment.clearFileContentType();\n\tattachment.clearFilename();\n\texpect(attachment.getRawFile()).toBe(undefined);\n});\n\ntest('AttachmentBuilder handles 0 as a valid id', () => {\n\tconst data = Buffer.from('test data');\n\tconst attachment = new AttachmentBuilder().setId(0).setFilename('test.txt').setFileData(data);\n\n\texpect(attachment.getRawFile()).toStrictEqual({\n\t\tdata,\n\t\tkey: 'files[0]',\n\t\tname: 'test.txt',\n\t});\n});\n\ntest('MessageBuilder.toFileBody returns JSON body and files', () => {\n\tconst msg = new MessageBuilder().setContent('here is a file').addAttachments(\n\t\tnew AttachmentBuilder()\n\t\t\t.setId(0)\n\t\t\t.setFilename('file.bin')\n\t\t\t.setFileData(Buffer.from([1, 2, 3]))\n\t\t\t.setFileContentType('application/octet-stream'),\n\t);\n\n\tconst { body, files } = msg.toFileBody();\n\n\t// body should match toJSON()\n\texpect(body).toStrictEqual(msg.toJSON());\n\n\t// files should contain the uploaded file\n\texpect(files).toHaveLength(1);\n\tconst [fileEntry] = files as [RawFile];\n\texpect(fileEntry.name).toBe('file.bin');\n\texpect(fileEntry.contentType).toBe('application/octet-stream');\n\texpect(fileEntry.data).toBeDefined();\n});\n\ntest('MessageBuilder.toFileBody returns empty files when attachments reference existing uploads', () => {\n\tconst msg = new MessageBuilder().addAttachments(\n\t\tnew AttachmentBuilder().setId('1234567890123456789').setFilename('existing.png'),\n\t);\n\n\tconst { body, files } = msg.toFileBody();\n\texpect(body).toEqual(msg.toJSON());\n\texpect(files.length).toBe(0);\n});\n"
  },
  {
    "path": "packages/builders/__tests__/messages/message.test.ts",
    "content": "import { AllowedMentionsTypes, MessageFlags } from 'discord-api-types/v10';\nimport { describe, test, expect } from 'vitest';\nimport { AllowedMentionsBuilder, EmbedBuilder, MessageBuilder } from '../../src/index.js';\n\nconst base = {\n\tallowed_mentions: undefined,\n\tattachments: [],\n\tcomponents: [],\n\tembeds: [],\n\tmessage_reference: undefined,\n\tpoll: undefined,\n};\n\ndescribe('Message', () => {\n\ttest('GIVEN a message with pre-defined content THEN return valid toJSON data', () => {\n\t\tconst message = new MessageBuilder({ content: 'foo' });\n\t\texpect(message.toJSON()).toStrictEqual({ ...base, content: 'foo' });\n\t});\n\n\ttest('GIVEN bad action row THEN it throws', () => {\n\t\tconst message = new MessageBuilder().addActionRowComponents((row) =>\n\t\t\trow.addTextInputComponent((input) => input.setCustomId('abc')),\n\t\t);\n\t\texpect(() => message.toJSON()).toThrow();\n\t});\n\n\ttest('GIVEN empty allowed mentions THEN return valid toJSON data', () => {\n\t\tconst allowedMentions = new AllowedMentionsBuilder();\n\t\texpect(allowedMentions.toJSON()).toStrictEqual({});\n\n\t\tconst message = new MessageBuilder().setContent('test').setAllowedMentions();\n\n\t\texpect(message.toJSON()).toStrictEqual({\n\t\t\t...base,\n\t\t\tallowed_mentions: {},\n\t\t\tcontent: 'test',\n\t\t});\n\t});\n\n\ttest('GIVEN parse: [users] and empty users THEN return valid toJSON data', () => {\n\t\tconst allowedMentions = new AllowedMentionsBuilder();\n\t\tallowedMentions.setUsers();\n\t\tallowedMentions.setParse(AllowedMentionsTypes.User);\n\t\texpect(allowedMentions.toJSON()).toStrictEqual({ parse: [AllowedMentionsTypes.User], users: [] });\n\t});\n\n\ttest('GIVEN parse: [roles] and empty roles THEN return valid toJSON data', () => {\n\t\tconst allowedMentions = new AllowedMentionsBuilder();\n\t\tallowedMentions.setRoles();\n\t\tallowedMentions.setParse(AllowedMentionsTypes.Role);\n\t\texpect(allowedMentions.toJSON()).toStrictEqual({ parse: [AllowedMentionsTypes.Role], roles: [] });\n\t});\n\n\ttest('GIVEN specific users and parse: [users] THEN it throws', () => {\n\t\tconst allowedMentions = new AllowedMentionsBuilder();\n\t\tallowedMentions.setUsers('123');\n\t\tallowedMentions.setParse(AllowedMentionsTypes.User);\n\t\texpect(() => allowedMentions.toJSON()).toThrow();\n\t});\n\n\ttest('GIVEN specific roles and parse: [roles] THEN it throws', () => {\n\t\tconst allowedMentions = new AllowedMentionsBuilder();\n\t\tallowedMentions.setRoles('123');\n\t\tallowedMentions.setParse(AllowedMentionsTypes.Role);\n\t\texpect(() => allowedMentions.toJSON()).toThrow();\n\t});\n\n\ttest('GIVEN tons of data THEN return valid toJSON data', () => {\n\t\tconst message = new MessageBuilder()\n\t\t\t.setContent('foo')\n\t\t\t.setNonce(123)\n\t\t\t.setTTS()\n\t\t\t.addEmbeds(new EmbedBuilder().setTitle('foo').setDescription('bar'))\n\t\t\t.setAllowedMentions({ parse: [AllowedMentionsTypes.Role] })\n\t\t\t.setMessageReference({ channel_id: '123', message_id: '123' })\n\t\t\t.addActionRowComponents((row) =>\n\t\t\t\trow.addPrimaryButtonComponents((button) => button.setCustomId('abc').setLabel('def')),\n\t\t\t)\n\t\t\t.setStickerIds('123', '456')\n\t\t\t.addAttachments((attachment) => attachment.setId(0).setFilename('abc'))\n\t\t\t.setFlags(MessageFlags.Ephemeral)\n\t\t\t.setEnforceNonce(false)\n\t\t\t.updatePoll((poll) => poll.addAnswers({ poll_media: { text: 'foo' } }).setQuestion({ text: 'foo' }));\n\n\t\texpect(message.toJSON()).toStrictEqual({\n\t\t\tcontent: 'foo',\n\t\t\tnonce: 123,\n\t\t\ttts: true,\n\t\t\tembeds: [{ title: 'foo', description: 'bar', author: undefined, fields: [], footer: undefined }],\n\t\t\tallowed_mentions: { parse: ['roles'] },\n\t\t\tmessage_reference: { channel_id: '123', message_id: '123' },\n\t\t\tcomponents: [\n\t\t\t\t{\n\t\t\t\t\ttype: 1,\n\t\t\t\t\tcomponents: [{ type: 2, custom_id: 'abc', label: 'def', style: 1 }],\n\t\t\t\t},\n\t\t\t],\n\t\t\tsticker_ids: ['123', '456'],\n\t\t\tattachments: [{ id: 0, filename: 'abc' }],\n\t\t\tflags: 64,\n\t\t\tenforce_nonce: false,\n\t\t\tpoll: {\n\t\t\t\tquestion: { text: 'foo' },\n\t\t\t\tanswers: [{ poll_media: { text: 'foo' } }],\n\t\t\t},\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/messages/poll.test.ts",
    "content": "import { PollLayoutType, type RESTAPIPoll } from 'discord-api-types/v10';\nimport { describe, test, expect } from 'vitest';\nimport { PollAnswerMediaBuilder, PollBuilder, PollQuestionBuilder } from '../../src/index.js';\n\nconst dummyData = {\n\tquestion: {\n\t\ttext: '.',\n\t},\n\tanswers: [],\n} satisfies RESTAPIPoll;\n\nconst dummyDataWithAnswer = {\n\t...dummyData,\n\tanswers: [\n\t\t{\n\t\t\tpoll_media: {\n\t\t\t\ttext: '.',\n\t\t\t},\n\t\t},\n\t],\n} satisfies RESTAPIPoll;\n\ndescribe('Poll', () => {\n\tdescribe('Poll question', () => {\n\t\ttest('GIVEN a poll with pre-defined question text THEN return valid toJSON data', () => {\n\t\t\tconst poll = new PollBuilder({ ...dummyDataWithAnswer, question: { text: 'foo' } });\n\n\t\t\texpect(poll.toJSON()).toStrictEqual({ ...dummyDataWithAnswer, question: { text: 'foo' } });\n\t\t});\n\n\t\ttest('GIVEN a poll with question text THEN return valid toJSON data', () => {\n\t\t\tconst poll = new PollBuilder(dummyDataWithAnswer);\n\n\t\t\tpoll.setQuestion({ text: 'foo' });\n\n\t\t\texpect(poll.toJSON()).toStrictEqual({ ...dummyDataWithAnswer, question: { text: 'foo' } });\n\t\t});\n\n\t\ttest('GIVEN a poll with invalid question THEN throws error', () => {\n\t\t\texpect(() => new PollQuestionBuilder().setText('.'.repeat(301)).toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Poll duration', () => {\n\t\ttest('GIVEN a poll with pre-defined duration THEN return valid toJSON data', () => {\n\t\t\tconst poll = new PollBuilder({ duration: 1, ...dummyDataWithAnswer });\n\n\t\t\texpect(poll.toJSON()).toStrictEqual({ duration: 1, ...dummyDataWithAnswer });\n\t\t});\n\n\t\ttest('GIVEN a poll with duration THEN return valid toJSON data', () => {\n\t\t\tconst poll = new PollBuilder(dummyDataWithAnswer);\n\n\t\t\tpoll.setDuration(1);\n\n\t\t\texpect(poll.toJSON()).toStrictEqual({ duration: 1, ...dummyDataWithAnswer });\n\t\t});\n\n\t\ttest('GIVEN a poll with invalid duration THEN throws error', () => {\n\t\t\tconst poll = new PollBuilder(dummyDataWithAnswer);\n\n\t\t\texpect(() => poll.setDuration(999).toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Poll layout type', () => {\n\t\ttest('GIVEN a poll with pre-defined layout type THEN return valid toJSON data', () => {\n\t\t\tconst poll = new PollBuilder({ ...dummyDataWithAnswer, layout_type: PollLayoutType.Default });\n\n\t\t\texpect(poll.toJSON()).toStrictEqual({ layout_type: PollLayoutType.Default, ...dummyDataWithAnswer });\n\t\t});\n\n\t\ttest('GIVEN a poll with layout type THEN return valid toJSON data', () => {\n\t\t\tconst poll = new PollBuilder(dummyDataWithAnswer);\n\n\t\t\tpoll.setLayoutType(PollLayoutType.Default);\n\n\t\t\texpect(poll.toJSON()).toStrictEqual({ layout_type: PollLayoutType.Default, ...dummyDataWithAnswer });\n\t\t});\n\n\t\ttest('GIVEN a poll with invalid layout type THEN throws error', () => {\n\t\t\tconst poll = new PollBuilder(dummyDataWithAnswer);\n\n\t\t\t// @ts-expect-error Invalid layout type\n\t\t\texpect(() => poll.setLayoutType(-1).toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Poll multi select', () => {\n\t\ttest('GIVEN a poll with pre-defined multi select enabled THEN return valid toJSON data', () => {\n\t\t\tconst poll = new PollBuilder({ allow_multiselect: true, ...dummyDataWithAnswer });\n\n\t\t\texpect(poll.toJSON()).toStrictEqual({ allow_multiselect: true, ...dummyDataWithAnswer });\n\t\t});\n\n\t\ttest('GIVEN a poll with multi select enabled THEN return valid toJSON data', () => {\n\t\t\tconst poll = new PollBuilder(dummyDataWithAnswer);\n\n\t\t\tpoll.setMultiSelect();\n\n\t\t\texpect(poll.toJSON()).toStrictEqual({ allow_multiselect: true, ...dummyDataWithAnswer });\n\t\t});\n\n\t\ttest('GIVEN a poll with invalid multi select value THEN throws error', () => {\n\t\t\tconst poll = new PollBuilder(dummyDataWithAnswer);\n\n\t\t\t// @ts-expect-error Invalid multi-select value\n\t\t\texpect(() => poll.setMultiSelect('string').toJSON()).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Poll answers', () => {\n\t\ttest('GIVEN a poll without answers THEN throws error', () => {\n\t\t\tconst poll = new PollBuilder(dummyData);\n\n\t\t\texpect(() => poll.toJSON()).toThrowError();\n\t\t});\n\n\t\ttest('GIVEN a poll with pre-defined answer THEN returns valid toJSON data', () => {\n\t\t\tconst poll = new PollBuilder({\n\t\t\t\t...dummyData,\n\t\t\t\tanswers: [{ poll_media: { text: 'foo' } }],\n\t\t\t});\n\t\t\texpect(poll.toJSON()).toStrictEqual({\n\t\t\t\t...dummyData,\n\t\t\t\tanswers: [{ poll_media: { text: 'foo' } }],\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN a poll using PollBuilder#addAnswers THEN returns valid toJSON data', () => {\n\t\t\tconst poll = new PollBuilder(dummyData);\n\n\t\t\tpoll.addAnswers({ poll_media: { text: 'foo' } });\n\t\t\tpoll.addAnswers([{ poll_media: { text: 'foo' } }]);\n\n\t\t\texpect(poll.toJSON()).toStrictEqual({\n\t\t\t\t...dummyData,\n\t\t\t\tanswers: [{ poll_media: { text: 'foo' } }, { poll_media: { text: 'foo' } }],\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN a poll using PollBuilder#spliceAnswers THEN returns valid toJSON data', () => {\n\t\t\tconst poll = new PollBuilder(dummyData);\n\n\t\t\tpoll.addAnswers({ poll_media: { text: 'foo' } }, { poll_media: { text: 'bar' } });\n\n\t\t\texpect(poll.spliceAnswers(0, 1).toJSON()).toStrictEqual({\n\t\t\t\t...dummyData,\n\t\t\t\tanswers: [{ poll_media: { text: 'bar' } }],\n\t\t\t});\n\t\t});\n\n\t\ttest('GIVEN a poll using PollBuilder#spliceAnswers THEN returns valid toJSON data 2', () => {\n\t\t\tconst poll = new PollBuilder(dummyData);\n\n\t\t\tpoll.addAnswers(...Array.from({ length: 8 }, () => ({ poll_media: { text: 'foo' } })));\n\n\t\t\texpect(() =>\n\t\t\t\tpoll.spliceAnswers(0, 3, ...Array.from({ length: 2 }, () => ({ poll_media: { text: 'foo' } }))).toJSON(),\n\t\t\t).not.toThrowError();\n\t\t});\n\n\t\ttest('GIVEN a poll using PollBuilder#spliceAnswers that adds additional answers resulting in answers > 10 THEN throws error', () => {\n\t\t\tconst poll = new PollBuilder();\n\n\t\t\tpoll.addAnswers(...Array.from({ length: 8 }, () => ({ poll_media: { text: 'foo' } })));\n\n\t\t\texpect(() =>\n\t\t\t\tpoll.spliceAnswers(0, 3, ...Array.from({ length: 8 }, () => ({ poll_media: { text: 'foo' } }))).toJSON(),\n\t\t\t).toThrowError();\n\t\t});\n\n\t\ttest('GIVEN a poll using PollBuilder#setAnswers THEN returns valid toJSON data', () => {\n\t\t\tconst poll = new PollBuilder(dummyData);\n\n\t\t\texpect(() =>\n\t\t\t\tpoll.setAnswers(...Array.from({ length: 10 }, () => ({ poll_media: { text: 'foo' } }))).toJSON(),\n\t\t\t).not.toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tpoll.setAnswers(Array.from({ length: 10 }, () => ({ poll_media: { text: 'foo' } }))).toJSON(),\n\t\t\t).not.toThrowError();\n\t\t});\n\n\t\ttest('GIVEN a poll using PollBuilder#setAnswers that sets more than 10 answers THEN throws error', () => {\n\t\t\tconst poll = new PollBuilder(dummyData);\n\n\t\t\texpect(() =>\n\t\t\t\tpoll.setAnswers(...Array.from({ length: 11 }, () => ({ poll_media: { text: 'foo' } }))).toJSON(),\n\t\t\t).toThrowError();\n\t\t\texpect(() =>\n\t\t\t\tpoll.setAnswers(Array.from({ length: 11 }, () => ({ poll_media: { text: 'foo' } }))).toJSON(),\n\t\t\t).toThrowError();\n\t\t});\n\n\t\tdescribe('GIVEN invalid answer amount THEN throws error', () => {\n\t\t\ttest('1', () => {\n\t\t\t\tconst poll = new PollBuilder(dummyData);\n\n\t\t\t\texpect(() =>\n\t\t\t\t\tpoll.addAnswers(...Array.from({ length: 11 }, () => ({ poll_media: { text: 'foo' } }))).toJSON(),\n\t\t\t\t).toThrowError();\n\t\t\t});\n\t\t});\n\n\t\tdescribe('GIVEN invalid answer THEN throws error', () => {\n\t\t\ttest('2', () => {\n\t\t\t\tconst poll = new PollBuilder().setQuestion({ text: '.' });\n\n\t\t\t\t// @ts-expect-error Invalid answer\n\t\t\t\texpect(() => poll.addAnswers({}).toJSON()).toThrowError();\n\t\t\t});\n\t\t});\n\n\t\tdescribe('GIVEN invalid answer text length THEN throws error', () => {\n\t\t\ttest('3', () => {\n\t\t\t\texpect(() => new PollAnswerMediaBuilder().setText('.'.repeat(56)).toJSON()).toThrowError();\n\t\t\t});\n\t\t});\n\n\t\tdescribe('GIVEN invalid answer text THEN throws error', () => {\n\t\t\ttest('4', () => {\n\t\t\t\texpect(() => new PollAnswerMediaBuilder().setText('').toJSON()).toThrowError();\n\t\t\t});\n\t\t});\n\n\t\tdescribe('GIVEN invalid answer emoji THEN throws error', () => {\n\t\t\ttest('5', () => {\n\t\t\t\t// @ts-expect-error Invalid emoji\n\t\t\t\texpect(() => new PollAnswerMediaBuilder().setEmoji('').toJSON()).toThrowError();\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/builders/__tests__/types.test-d.ts",
    "content": "import { expectTypeOf } from 'vitest';\nimport {\n\tChatInputCommandBuilder,\n\tChatInputCommandStringOption,\n\tChatInputCommandSubcommandBuilder,\n} from '../src/index.js';\n\nconst getBuilder = () => new ChatInputCommandBuilder();\nconst getStringOption = () => new ChatInputCommandStringOption().setName('owo').setDescription('Testing 123');\nconst getSubcommand = () => new ChatInputCommandSubcommandBuilder().setName('owo').setDescription('Testing 123');\n\ntype BuilderPropsOnly<Type = ChatInputCommandBuilder> = Pick<\n\tType,\n\tkeyof {\n\t\t[Key in keyof Type as Type[Key] extends (...args: any) => any ? never : Key]: any;\n\t}\n>;\n\nexpectTypeOf(getBuilder().addStringOptions(getStringOption())).toMatchTypeOf<BuilderPropsOnly>();\n\nexpectTypeOf(getBuilder().addSubcommands(getSubcommand())).toMatchTypeOf<BuilderPropsOnly>();\n"
  },
  {
    "path": "packages/builders/__tests__/util.test.ts",
    "content": "import { describe, test, expect } from 'vitest';\nimport { z } from 'zod';\nimport {\n\tenableValidators,\n\tdisableValidators,\n\tisValidationEnabled,\n\tnormalizeArray,\n\tValidationError,\n} from '../src/index.js';\nimport { validate } from '../src/util/validation.js';\n\ndescribe('validation', () => {\n\ttest('enables validation', () => {\n\t\tenableValidators();\n\t\texpect(isValidationEnabled()).toBeTruthy();\n\t});\n\n\ttest('disables validation', () => {\n\t\tdisableValidators();\n\t\texpect(isValidationEnabled()).toBeFalsy();\n\t});\n\n\ttest('validation error', () => {\n\t\ttry {\n\t\t\tvalidate(z.never(), 1, true);\n\t\t\tthrow new Error('validation should have failed');\n\t\t} catch (error) {\n\t\t\texpect(error).toBeInstanceOf(ValidationError);\n\t\t\texpect((error as ValidationError).message).toBe('✖ Invalid input: expected never, received number');\n\t\t\texpect((error as ValidationError).cause).toBeInstanceOf(z.ZodError);\n\t\t}\n\t});\n});\n\ndescribe('normalizeArray', () => {\n\ttest('normalizes an array or array (when input is an array)', () => {\n\t\texpect(normalizeArray([[1, 2, 3]])).toEqual([1, 2, 3]);\n\t});\n\n\ttest('normalizes an array (when input is rest parameter)', () => {\n\t\texpect(normalizeArray([1, 2, 3])).toEqual([1, 2, 3]);\n\t});\n\n\ttest('always returns a clone', () => {\n\t\tconst arr = [1, 2, 3];\n\t\texpect(normalizeArray([arr])).toEqual(arr);\n\t\texpect(normalizeArray([arr])).not.toBe(arr);\n\t});\n});\n"
  },
  {
    "path": "packages/builders/api-extractor.json",
    "content": "{\n\t\"extends\": \"../../api-extractor.json\",\n\t\"docModel\": {\n\t\t\"projectFolderUrl\": \"https://github.com/discordjs/discord.js/tree/main/packages/builders\"\n\t}\n}\n"
  },
  {
    "path": "packages/builders/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t\t{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length %}\\\n\t\\n### New Contributors\\n\n\t{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\\\n\t\t* @{{ contributor.username }} made their first contribution in #{{ contributor.pr_number }}\n\t{% endfor %}\\\n{% endif %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"@discordjs/builders@[0-9]*\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/builders/docs/README.md",
    "content": "## [View the documentation here.](https://discord.js.org/docs/packages/builders/main)\n"
  },
  {
    "path": "packages/builders/docs/examples/Slash Command Builders.md",
    "content": "# Slash Command Builders\n\n## Ping command\n\n```ts\nimport { SlashCommandBuilder } from '@discordjs/builders';\n\n// Create a slash command builder\nconst pingCommand = new SlashCommandBuilder().setName('ping').setDescription('Check if this interaction is responsive');\n\n// Get the raw data that can be sent to Discord\nconst rawData = pingCommand.toJSON();\n```\n\n## Arguments\n\n```ts\nimport { SlashCommandBuilder } from '@discordjs/builders';\n\n// Creates a boop command\nconst boopCommand = new SlashCommandBuilder()\n\t.setName('boop')\n\t.setDescription('Boops the specified user, as many times as you want')\n\t.addUserOption((option) => option.setName('user').setDescription('The user to boop').setRequired(true))\n\n\t// Adds an integer option\n\t.addIntegerOption((option) =>\n\t\toption.setName('boop_amount').setDescription('How many times should the user be booped (defaults to 1)'),\n\t)\n\n\t// Supports choices too!\n\t.addIntegerOption((option) =>\n\t\toption\n\t\t\t.setName('boop_reminder')\n\t\t\t.setDescription('How often should we remind you to boop the user')\n\t\t\t.addChoices({ name: 'Every day', value: 1 }, { name: 'Weekly', value: 7 }),\n\t);\n\n// Get the final raw data that can be sent to Discord\nconst rawData = boopCommand.toJSON();\n```\n\n## Subcommands and subcommand groups\n\n```ts\nimport { SlashCommandBuilder } from '@discordjs/builders';\n\nconst pointsCommand = new SlashCommandBuilder()\n\t.setName('points')\n\t.setDescription('Lists or manages user points')\n\n\t// Add a manage group\n\t.addSubcommandGroup((group) =>\n\t\tgroup\n\t\t\t.setName('manage')\n\t\t\t.setDescription('Shows or manages points in the server')\n\t\t\t.addSubcommand((subcommand) =>\n\t\t\t\tsubcommand\n\t\t\t\t\t.setName('user_points')\n\t\t\t\t\t.setDescription(\"Alters a user's points\")\n\t\t\t\t\t.addUserOption((option) =>\n\t\t\t\t\t\toption.setName('user').setDescription('The user whose points to alter').setRequired(true),\n\t\t\t\t\t)\n\t\t\t\t\t.addStringOption((option) =>\n\t\t\t\t\t\toption\n\t\t\t\t\t\t\t.setName('action')\n\t\t\t\t\t\t\t.setDescription('What action should be taken with the users points?')\n\t\t\t\t\t\t\t.addChoices(\n\t\t\t\t\t\t\t\t{ name: 'Add points', value: 'add' },\n\t\t\t\t\t\t\t\t{ name: 'Remove points', value: 'remove' },\n\t\t\t\t\t\t\t\t{ name: 'Reset points', value: 'reset' },\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.setRequired(true),\n\t\t\t\t\t)\n\t\t\t\t\t.addIntegerOption((option) => option.setName('points').setDescription('Points to add or remove')),\n\t\t\t),\n\t)\n\n\t// Add an information group\n\t.addSubcommandGroup((group) =>\n\t\tgroup\n\t\t\t.setName('info')\n\t\t\t.setDescription('Shows information about points in the guild')\n\t\t\t.addSubcommand((subcommand) =>\n\t\t\t\tsubcommand.setName('total').setDescription('Tells you the total amount of points given in the guild'),\n\t\t\t)\n\t\t\t.addSubcommand((subcommand) =>\n\t\t\t\tsubcommand\n\t\t\t\t\t.setName('user')\n\t\t\t\t\t.setDescription(\"Lists a user's points\")\n\t\t\t\t\t.addUserOption((option) =>\n\t\t\t\t\t\toption.setName('user').setDescription('The user whose points to list').setRequired(true),\n\t\t\t\t\t),\n\t\t\t),\n\t);\n\n// Get the final raw data that can be sent to Discord\nconst rawData = pointsCommand.toJSON();\n```\n"
  },
  {
    "path": "packages/builders/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/builders\",\n\t\"version\": \"1.11.1\",\n\t\"description\": \"A set of builders that you can use when creating your bot\",\n\t\"scripts\": {\n\t\t\"test\": \"vitest run --config ../../vitest.config.ts\",\n\t\t\"build\": \"tsc --noEmit && tsup\",\n\t\t\"build:docs\": \"tsc -p tsconfig.docs.json\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src __tests__\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src __tests__\",\n\t\t\"fmt\": \"pnpm run format\",\n\t\t\"docs\": \"pnpm run build:docs && api-extractor run --local --minify && generate-split-documentation\",\n\t\t\"prepack\": \"pnpm run lint && pnpm run test && pnpm run build\",\n\t\t\"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/builders/*'\",\n\t\t\"release\": \"cliff-jumper\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"main\": \"./dist/index.js\",\n\t\"module\": \"./dist/index.mjs\",\n\t\"types\": \"./dist/index.d.ts\",\n\t\"directories\": {\n\t\t\"lib\": \"src\",\n\t\t\"test\": \"__tests__\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"Amish Shah <amishshah.2k@gmail.com>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"discord\",\n\t\t\"api\",\n\t\t\"bot\",\n\t\t\"client\",\n\t\t\"node\",\n\t\t\"discordapp\",\n\t\t\"discordjs\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/builders\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"@discordjs/util\": \"workspace:^\",\n\t\t\"discord-api-types\": \"^0.38.41\",\n\t\t\"ts-mixer\": \"^6.0.4\",\n\t\t\"tslib\": \"^2.8.1\",\n\t\t\"zod\": \"^4.3.6\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@discordjs/api-extractor\": \"workspace:^\",\n\t\t\"@discordjs/scripts\": \"workspace:^\",\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@types/node\": \"^22.19.11\",\n\t\t\"@vitest/coverage-v8\": \"^4.0.18\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"esbuild-plugin-version-injector\": \"^1.2.1\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vitest\": \"^4.0.18\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/Assertions.ts",
    "content": "import { Locale } from 'discord-api-types/v10';\nimport { z } from 'zod';\n\nexport const idPredicate = z.int().min(0).max(2_147_483_647).optional();\nexport const customIdPredicate = z.string().min(1).max(100);\nexport const snowflakePredicate = z.string().regex(/^(?:0|[1-9]\\d*)$/);\n\nexport const memberPermissionsPredicate = z.coerce.bigint();\n\nexport const localeMapPredicate = z.strictObject(\n\tObject.fromEntries(Object.values(Locale).map((loc) => [loc, z.string().optional()])) as Record<\n\t\tLocale,\n\t\tz.ZodOptional<z.ZodString>\n\t>,\n);\n"
  },
  {
    "path": "packages/builders/src/components/ActionRow.ts",
    "content": "import type {\n\tAPITextInputComponent,\n\tAPIActionRowComponent,\n\tAPIComponentInActionRow,\n\tAPIChannelSelectComponent,\n\tAPIMentionableSelectComponent,\n\tAPIRoleSelectComponent,\n\tAPIStringSelectComponent,\n\tAPIUserSelectComponent,\n\tAPIButtonComponentWithCustomId,\n\tAPIButtonComponentWithSKUId,\n\tAPIButtonComponentWithURL,\n} from 'discord-api-types/v10';\nimport { ComponentType } from 'discord-api-types/v10';\nimport { normalizeArray, type RestOrArray } from '../util/normalizeArray.js';\nimport { resolveBuilder } from '../util/resolveBuilder.js';\nimport { validate } from '../util/validation.js';\nimport { actionRowPredicate } from './Assertions.js';\nimport { ComponentBuilder } from './Component.js';\nimport type { AnyActionRowComponentBuilder } from './Components.js';\nimport { createComponentBuilder } from './Components.js';\nimport {\n\tDangerButtonBuilder,\n\tPrimaryButtonBuilder,\n\tSecondaryButtonBuilder,\n\tSuccessButtonBuilder,\n} from './button/CustomIdButton.js';\nimport { LinkButtonBuilder } from './button/LinkButton.js';\nimport { PremiumButtonBuilder } from './button/PremiumButton.js';\nimport { ChannelSelectMenuBuilder } from './selectMenu/ChannelSelectMenu.js';\nimport { MentionableSelectMenuBuilder } from './selectMenu/MentionableSelectMenu.js';\nimport { RoleSelectMenuBuilder } from './selectMenu/RoleSelectMenu.js';\nimport { StringSelectMenuBuilder } from './selectMenu/StringSelectMenu.js';\nimport { UserSelectMenuBuilder } from './selectMenu/UserSelectMenu.js';\nimport { TextInputBuilder } from './textInput/TextInput.js';\n\nexport interface ActionRowBuilderData extends Partial<\n\tOmit<APIActionRowComponent<APIComponentInActionRow>, 'components'>\n> {\n\tcomponents: AnyActionRowComponentBuilder[];\n}\n\n/**\n * A builder that creates API-compatible JSON data for action rows.\n */\nexport class ActionRowBuilder extends ComponentBuilder<APIActionRowComponent<APIComponentInActionRow>> {\n\t/**\n\t * @internal\n\t */\n\tprotected readonly data: ActionRowBuilderData;\n\n\t/**\n\t * The components within this action row.\n\t */\n\tpublic get components(): readonly AnyActionRowComponentBuilder[] {\n\t\treturn this.data.components;\n\t}\n\n\t/**\n\t * Creates a new action row.\n\t *\n\t * @param data - The API data to create this action row with\n\t * @example\n\t * Creating an action row from an API data object:\n\t * ```ts\n\t * const actionRow = new ActionRowBuilder({\n\t * \tcomponents: [\n\t * \t\t{\n\t * \t\t\tcustom_id: \"custom id\",\n\t * \t\t\tlabel: \"Type something\",\n\t * \t\t\tstyle: TextInputStyle.Short,\n\t * \t\t\ttype: ComponentType.TextInput,\n\t * \t\t},\n\t * \t],\n\t * });\n\t * ```\n\t * @example\n\t * Creating an action row using setters and API data:\n\t * ```ts\n\t * const actionRow = new ActionRowBuilder({\n\t * \tcomponents: [\n\t * \t\t{\n\t * \t\t\tcustom_id: \"custom id\",\n\t * \t\t\tlabel: \"Click me\",\n\t * \t\t\tstyle: ButtonStyle.Primary,\n\t * \t\t\ttype: ComponentType.Button,\n\t * \t\t},\n\t * \t],\n\t * })\n\t * \t.addComponents(button2, button3);\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APIActionRowComponent<APIComponentInActionRow>> = {}) {\n\t\tsuper();\n\n\t\tconst { components = [], ...rest } = data;\n\n\t\tthis.data = {\n\t\t\t...structuredClone(rest),\n\t\t\tcomponents: components.map((component) => createComponentBuilder(component)),\n\t\t\ttype: ComponentType.ActionRow,\n\t\t};\n\t}\n\n\t/**\n\t * Adds primary button components to this action row.\n\t *\n\t * @param input - The buttons to add\n\t */\n\tpublic addPrimaryButtonComponents(\n\t\t...input: RestOrArray<\n\t\t\tAPIButtonComponentWithCustomId | PrimaryButtonBuilder | ((builder: PrimaryButtonBuilder) => PrimaryButtonBuilder)\n\t\t>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((component) => resolveBuilder(component, PrimaryButtonBuilder));\n\n\t\tthis.data.components.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds secondary button components to this action row.\n\t *\n\t * @param input - The buttons to add\n\t */\n\tpublic addSecondaryButtonComponents(\n\t\t...input: RestOrArray<\n\t\t\t| APIButtonComponentWithCustomId\n\t\t\t| SecondaryButtonBuilder\n\t\t\t| ((builder: SecondaryButtonBuilder) => SecondaryButtonBuilder)\n\t\t>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((component) => resolveBuilder(component, SecondaryButtonBuilder));\n\n\t\tthis.data.components.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds success button components to this action row.\n\t *\n\t * @param input - The buttons to add\n\t */\n\tpublic addSuccessButtonComponents(\n\t\t...input: RestOrArray<\n\t\t\tAPIButtonComponentWithCustomId | SuccessButtonBuilder | ((builder: SuccessButtonBuilder) => SuccessButtonBuilder)\n\t\t>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((component) => resolveBuilder(component, SuccessButtonBuilder));\n\n\t\tthis.data.components.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds danger button components to this action row.\n\t */\n\tpublic addDangerButtonComponents(\n\t\t...input: RestOrArray<\n\t\t\tAPIButtonComponentWithCustomId | DangerButtonBuilder | ((builder: DangerButtonBuilder) => DangerButtonBuilder)\n\t\t>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((component) => resolveBuilder(component, DangerButtonBuilder));\n\n\t\tthis.data.components.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Generically add any type of component to this action row, only takes in an instance of a component builder.\n\t */\n\tpublic addComponents(...input: RestOrArray<AnyActionRowComponentBuilder>): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tthis.data.components.push(...normalized);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds SKU id button components to this action row.\n\t *\n\t * @param input - The buttons to add\n\t */\n\tpublic addPremiumButtonComponents(\n\t\t...input: RestOrArray<\n\t\t\tAPIButtonComponentWithSKUId | PremiumButtonBuilder | ((builder: PremiumButtonBuilder) => PremiumButtonBuilder)\n\t\t>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((component) => resolveBuilder(component, PremiumButtonBuilder));\n\n\t\tthis.data.components.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds URL button components to this action row.\n\t *\n\t * @param input - The buttons to add\n\t */\n\tpublic addLinkButtonComponents(\n\t\t...input: RestOrArray<\n\t\t\tAPIButtonComponentWithURL | LinkButtonBuilder | ((builder: LinkButtonBuilder) => LinkButtonBuilder)\n\t\t>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((component) => resolveBuilder(component, LinkButtonBuilder));\n\n\t\tthis.data.components.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds a channel select menu component to this action row.\n\t *\n\t * @param input - A function that returns a component builder or an already built builder\n\t */\n\tpublic addChannelSelectMenuComponent(\n\t\tinput:\n\t\t\t| APIChannelSelectComponent\n\t\t\t| ChannelSelectMenuBuilder\n\t\t\t| ((builder: ChannelSelectMenuBuilder) => ChannelSelectMenuBuilder),\n\t): this {\n\t\tthis.data.components.push(resolveBuilder(input, ChannelSelectMenuBuilder));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds a mentionable select menu component to this action row.\n\t *\n\t * @param input - A function that returns a component builder or an already built builder\n\t */\n\tpublic addMentionableSelectMenuComponent(\n\t\tinput:\n\t\t\t| APIMentionableSelectComponent\n\t\t\t| MentionableSelectMenuBuilder\n\t\t\t| ((builder: MentionableSelectMenuBuilder) => MentionableSelectMenuBuilder),\n\t): this {\n\t\tthis.data.components.push(resolveBuilder(input, MentionableSelectMenuBuilder));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds a role select menu component to this action row.\n\t *\n\t * @param input - A function that returns a component builder or an already built builder\n\t */\n\tpublic addRoleSelectMenuComponent(\n\t\tinput: APIRoleSelectComponent | RoleSelectMenuBuilder | ((builder: RoleSelectMenuBuilder) => RoleSelectMenuBuilder),\n\t): this {\n\t\tthis.data.components.push(resolveBuilder(input, RoleSelectMenuBuilder));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds a string select menu component to this action row.\n\t *\n\t * @param input - A function that returns a component builder or an already built builder\n\t */\n\tpublic addStringSelectMenuComponent(\n\t\tinput:\n\t\t\t| APIStringSelectComponent\n\t\t\t| StringSelectMenuBuilder\n\t\t\t| ((builder: StringSelectMenuBuilder) => StringSelectMenuBuilder),\n\t): this {\n\t\tthis.data.components.push(resolveBuilder(input, StringSelectMenuBuilder));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds a user select menu component to this action row.\n\t *\n\t * @param input - A function that returns a component builder or an already built builder\n\t */\n\tpublic addUserSelectMenuComponent(\n\t\tinput: APIUserSelectComponent | UserSelectMenuBuilder | ((builder: UserSelectMenuBuilder) => UserSelectMenuBuilder),\n\t): this {\n\t\tthis.data.components.push(resolveBuilder(input, UserSelectMenuBuilder));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds a text input component to this action row.\n\t *\n\t * @param input - A function that returns a component builder or an already built builder\n\t */\n\tpublic addTextInputComponent(\n\t\tinput: APITextInputComponent | TextInputBuilder | ((builder: TextInputBuilder) => TextInputBuilder),\n\t): this {\n\t\tthis.data.components.push(resolveBuilder(input, TextInputBuilder));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes, replaces, or inserts components for this action row.\n\t *\n\t * @remarks\n\t * This method behaves similarly\n\t * to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.\n\t *\n\t * It's useful for modifying and adjusting order of the already-existing components of an action row.\n\t * @example\n\t * Remove the first component:\n\t * ```ts\n\t * actionRow.spliceComponents(0, 1);\n\t * ```\n\t * @example\n\t * Remove the first n components:\n\t * ```ts\n\t * const n = 4;\n\t * actionRow.spliceComponents(0, n);\n\t * ```\n\t * @example\n\t * Remove the last component:\n\t * ```ts\n\t * actionRow.spliceComponents(-1, 1);\n\t * ```\n\t * @param index - The index to start at\n\t * @param deleteCount - The number of components to remove\n\t * @param components - The replacing component objects\n\t */\n\tpublic spliceComponents(index: number, deleteCount: number, ...components: AnyActionRowComponentBuilder[]): this {\n\t\tthis.data.components.splice(index, deleteCount, ...components);\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): APIActionRowComponent<APIComponentInActionRow> {\n\t\tconst { components, ...rest } = this.data;\n\n\t\tconst data = {\n\t\t\t...structuredClone(rest),\n\t\t\tcomponents: components.map((component) => component.toJSON(validationOverride)),\n\t\t};\n\n\t\tvalidate(actionRowPredicate, data, validationOverride);\n\n\t\treturn data as APIActionRowComponent<APIComponentInActionRow>;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/Assertions.ts",
    "content": "import { ButtonStyle, ChannelType, ComponentType, SelectMenuDefaultValueType } from 'discord-api-types/v10';\nimport { z } from 'zod';\nimport { idPredicate, customIdPredicate, snowflakePredicate } from '../Assertions.js';\n\nexport const emojiPredicate = z\n\t.strictObject({\n\t\tid: snowflakePredicate.optional(),\n\t\tname: z.string().min(1).max(32).optional(),\n\t\tanimated: z.boolean().optional(),\n\t})\n\t.refine((data) => data.id !== undefined || data.name !== undefined, {\n\t\terror: \"Either 'id' or 'name' must be provided\",\n\t});\n\nconst buttonPredicateBase = z.strictObject({\n\ttype: z.literal(ComponentType.Button),\n\tdisabled: z.boolean().optional(),\n});\n\nconst buttonLabelPredicate = z.string().min(1).max(80);\n\nconst buttonCustomIdPredicateBase = buttonPredicateBase\n\t.extend({\n\t\tcustom_id: customIdPredicate,\n\t\temoji: emojiPredicate.optional(),\n\t\tlabel: buttonLabelPredicate.optional(),\n\t})\n\t.refine((data) => data.emoji !== undefined || data.label !== undefined, {\n\t\tmessage: 'Buttons with a custom id must have either an emoji or a label.',\n\t});\n\nconst buttonPrimaryPredicate = buttonCustomIdPredicateBase.safeExtend({ style: z.literal(ButtonStyle.Primary) });\nconst buttonSecondaryPredicate = buttonCustomIdPredicateBase.safeExtend({ style: z.literal(ButtonStyle.Secondary) });\nconst buttonSuccessPredicate = buttonCustomIdPredicateBase.safeExtend({ style: z.literal(ButtonStyle.Success) });\nconst buttonDangerPredicate = buttonCustomIdPredicateBase.safeExtend({ style: z.literal(ButtonStyle.Danger) });\n\nconst buttonLinkPredicate = buttonPredicateBase\n\t.extend({\n\t\tstyle: z.literal(ButtonStyle.Link),\n\t\turl: z.url({ protocol: /^(?:https?|discord)$/ }).max(512),\n\t\temoji: emojiPredicate.optional(),\n\t\tlabel: buttonLabelPredicate.optional(),\n\t})\n\t.refine((data) => data.emoji !== undefined || data.label !== undefined, {\n\t\tmessage: 'Link buttons must have either an emoji or a label.',\n\t});\n\nconst buttonPremiumPredicate = buttonPredicateBase.extend({\n\tstyle: z.literal(ButtonStyle.Premium),\n\tsku_id: snowflakePredicate,\n});\n\nexport const buttonPredicate = z.discriminatedUnion('style', [\n\tbuttonLinkPredicate,\n\tbuttonPrimaryPredicate,\n\tbuttonSecondaryPredicate,\n\tbuttonSuccessPredicate,\n\tbuttonDangerPredicate,\n\tbuttonPremiumPredicate,\n]);\n\nconst selectMenuBasePredicate = z.object({\n\tid: idPredicate,\n\tplaceholder: z.string().max(150).optional(),\n\tmin_values: z.number().min(0).max(25).optional(),\n\tmax_values: z.number().min(0).max(25).optional(),\n\tcustom_id: customIdPredicate,\n\tdisabled: z.boolean().optional(),\n});\n\nexport const selectMenuChannelPredicate = selectMenuBasePredicate.extend({\n\ttype: z.literal(ComponentType.ChannelSelect),\n\tchannel_types: z.enum(ChannelType).array().optional(),\n\tdefault_values: z\n\t\t.object({ id: snowflakePredicate, type: z.literal(SelectMenuDefaultValueType.Channel) })\n\t\t.array()\n\t\t.max(25)\n\t\t.optional(),\n});\n\nexport const selectMenuMentionablePredicate = selectMenuBasePredicate.extend({\n\ttype: z.literal(ComponentType.MentionableSelect),\n\tdefault_values: z\n\t\t.object({\n\t\t\tid: snowflakePredicate,\n\t\t\ttype: z.literal([SelectMenuDefaultValueType.Role, SelectMenuDefaultValueType.User]),\n\t\t})\n\t\t.array()\n\t\t.max(25)\n\t\t.optional(),\n});\n\nexport const selectMenuRolePredicate = selectMenuBasePredicate.extend({\n\ttype: z.literal(ComponentType.RoleSelect),\n\tdefault_values: z\n\t\t.object({ id: snowflakePredicate, type: z.literal(SelectMenuDefaultValueType.Role) })\n\t\t.array()\n\t\t.max(25)\n\t\t.optional(),\n});\n\nexport const selectMenuStringOptionPredicate = z.object({\n\tlabel: z.string().min(1).max(100),\n\tvalue: z.string().min(1).max(100),\n\tdescription: z.string().min(1).max(100).optional(),\n\temoji: emojiPredicate.optional(),\n\tdefault: z.boolean().optional(),\n});\n\nexport const selectMenuStringPredicate = selectMenuBasePredicate\n\t.extend({\n\t\ttype: z.literal(ComponentType.StringSelect),\n\t\toptions: selectMenuStringOptionPredicate.array().min(1).max(25),\n\t})\n\t.check((ctx) => {\n\t\tconst addIssue = (name: string, minimum: number) =>\n\t\t\tctx.issues.push({\n\t\t\t\tcode: 'too_small',\n\t\t\t\tmessage: `The number of options must be greater than or equal to ${name}`,\n\t\t\t\tinclusive: true,\n\t\t\t\tminimum,\n\t\t\t\ttype: 'number',\n\t\t\t\tpath: ['options'],\n\t\t\t\torigin: 'number',\n\t\t\t\tinput: minimum,\n\t\t\t});\n\n\t\tif (ctx.value.min_values !== undefined && ctx.value.options.length < ctx.value.min_values) {\n\t\t\taddIssue('min_values', ctx.value.min_values);\n\t\t}\n\n\t\tif (\n\t\t\tctx.value.min_values !== undefined &&\n\t\t\tctx.value.max_values !== undefined &&\n\t\t\tctx.value.min_values > ctx.value.max_values\n\t\t) {\n\t\t\tctx.issues.push({\n\t\t\t\tcode: 'too_big',\n\t\t\t\tmessage: `The maximum amount of options must be greater than or equal to the minimum amount of options`,\n\t\t\t\tinclusive: true,\n\t\t\t\tmaximum: ctx.value.max_values,\n\t\t\t\ttype: 'number',\n\t\t\t\tpath: ['min_values'],\n\t\t\t\torigin: 'number',\n\t\t\t\tinput: ctx.value.min_values,\n\t\t\t});\n\t\t}\n\t});\n\nexport const selectMenuUserPredicate = selectMenuBasePredicate.extend({\n\ttype: z.literal(ComponentType.UserSelect),\n\tdefault_values: z\n\t\t.object({ id: snowflakePredicate, type: z.literal(SelectMenuDefaultValueType.User) })\n\t\t.array()\n\t\t.max(25)\n\t\t.optional(),\n});\n\nexport const actionRowPredicate = z.object({\n\tid: idPredicate,\n\ttype: z.literal(ComponentType.ActionRow),\n\tcomponents: z.union([\n\t\tz\n\t\t\t.object({ type: z.literal(ComponentType.Button) })\n\t\t\t.array()\n\t\t\t.min(1)\n\t\t\t.max(5),\n\t\tz\n\t\t\t.object({\n\t\t\t\ttype: z.literal([\n\t\t\t\t\tComponentType.ChannelSelect,\n\t\t\t\t\tComponentType.MentionableSelect,\n\t\t\t\t\tComponentType.StringSelect,\n\t\t\t\t\tComponentType.RoleSelect,\n\t\t\t\t\tComponentType.TextInput,\n\t\t\t\t\tComponentType.UserSelect,\n\t\t\t\t]),\n\t\t\t})\n\t\t\t.array()\n\t\t\t.length(1),\n\t]),\n});\n"
  },
  {
    "path": "packages/builders/src/components/Component.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type { APIBaseComponent, ComponentType } from 'discord-api-types/v10';\n\nexport interface ComponentBuilderBaseData {\n\tid?: number | undefined;\n}\n\n/**\n * The base component builder that contains common symbols for all sorts of components.\n *\n * @typeParam Component - The type of API data that is stored within the builder\n */\nexport abstract class ComponentBuilder<\n\tComponent extends APIBaseComponent<ComponentType>,\n> implements JSONEncodable<Component> {\n\t/**\n\t * @internal\n\t */\n\tprotected abstract readonly data: ComponentBuilderBaseData;\n\n\t/**\n\t * Sets the id of this component.\n\t *\n\t * @param id - The id to use\n\t */\n\tpublic setId(id: number) {\n\t\tthis.data.id = id;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the id of this component, defaulting to a default incremented id.\n\t */\n\tpublic clearId() {\n\t\tthis.data.id = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic abstract toJSON(validationOverride?: boolean): Component;\n}\n"
  },
  {
    "path": "packages/builders/src/components/Components.ts",
    "content": "import type {\n\tAPIBaseComponent,\n\tAPIButtonComponent,\n\tAPIMessageComponent,\n\tAPIModalComponent,\n\tAPISectionAccessoryComponent,\n} from 'discord-api-types/v10';\nimport { ButtonStyle, ComponentType } from 'discord-api-types/v10';\nimport { ActionRowBuilder } from './ActionRow.js';\nimport { ComponentBuilder } from './Component.js';\nimport type { BaseButtonBuilder } from './button/Button.js';\nimport {\n\tDangerButtonBuilder,\n\tPrimaryButtonBuilder,\n\tSecondaryButtonBuilder,\n\tSuccessButtonBuilder,\n} from './button/CustomIdButton.js';\nimport { LinkButtonBuilder } from './button/LinkButton.js';\nimport { PremiumButtonBuilder } from './button/PremiumButton.js';\nimport { FileUploadBuilder } from './fileUpload/FileUpload.js';\nimport { LabelBuilder } from './label/Label.js';\nimport { ChannelSelectMenuBuilder } from './selectMenu/ChannelSelectMenu.js';\nimport { MentionableSelectMenuBuilder } from './selectMenu/MentionableSelectMenu.js';\nimport { RoleSelectMenuBuilder } from './selectMenu/RoleSelectMenu.js';\nimport { StringSelectMenuBuilder } from './selectMenu/StringSelectMenu.js';\nimport { UserSelectMenuBuilder } from './selectMenu/UserSelectMenu.js';\nimport { TextInputBuilder } from './textInput/TextInput.js';\nimport { ContainerBuilder } from './v2/Container.js';\nimport { FileBuilder } from './v2/File.js';\nimport { MediaGalleryBuilder } from './v2/MediaGallery.js';\nimport { SectionBuilder } from './v2/Section.js';\nimport { SeparatorBuilder } from './v2/Separator.js';\nimport { TextDisplayBuilder } from './v2/TextDisplay.js';\nimport { ThumbnailBuilder } from './v2/Thumbnail.js';\n\n/**\n * The builders that may be used as top-level components on messages\n */\nexport type MessageTopLevelComponentBuilder =\n\t| ActionRowBuilder\n\t| ContainerBuilder\n\t| FileBuilder\n\t| MediaGalleryBuilder\n\t| SectionBuilder\n\t| SeparatorBuilder\n\t| TextDisplayBuilder;\n\n/**\n * The builders that may be used for messages.\n */\nexport type MessageComponentBuilder =\n\t| MessageActionRowComponentBuilder\n\t| MessageTopLevelComponentBuilder\n\t| ThumbnailBuilder;\n\n/**\n * The builders that may be used for modals.\n */\nexport type ModalComponentBuilder =\n\t| ActionRowBuilder\n\t| FileUploadBuilder\n\t| LabelBuilder\n\t| ModalActionRowComponentBuilder;\n\n/**\n * Any button builder\n */\nexport type ButtonBuilder =\n\t| DangerButtonBuilder\n\t| LinkButtonBuilder\n\t| PremiumButtonBuilder\n\t| PrimaryButtonBuilder\n\t| SecondaryButtonBuilder\n\t| SuccessButtonBuilder;\n\n/**\n * The builders that may be used within an action row for messages.\n */\nexport type MessageActionRowComponentBuilder =\n\t| ButtonBuilder\n\t| ChannelSelectMenuBuilder\n\t| MentionableSelectMenuBuilder\n\t| RoleSelectMenuBuilder\n\t| StringSelectMenuBuilder\n\t| UserSelectMenuBuilder;\n\n/**\n * The builders that may be used within an action row for modals.\n */\nexport type ModalActionRowComponentBuilder = TextInputBuilder;\n\n/**\n * Any action row component builder.\n */\nexport type AnyActionRowComponentBuilder = MessageActionRowComponentBuilder | ModalActionRowComponentBuilder;\n\n/**\n * Any modal component builder.\n */\nexport type AnyModalComponentBuilder = FileUploadBuilder | LabelBuilder | TextDisplayBuilder;\n\n/**\n * Components here are mapped to their respective builder.\n */\nexport interface MappedComponentTypes {\n\t/**\n\t * The action row component type is associated with an {@link ActionRowBuilder}.\n\t */\n\t[ComponentType.ActionRow]: ActionRowBuilder;\n\t/**\n\t * The button component type is associated with a {@link BaseButtonBuilder}.\n\t */\n\t[ComponentType.Button]: ButtonBuilder;\n\t/**\n\t * The string select component type is associated with a {@link StringSelectMenuBuilder}.\n\t */\n\t[ComponentType.StringSelect]: StringSelectMenuBuilder;\n\t/**\n\t * The text input component type is associated with a {@link TextInputBuilder}.\n\t */\n\t[ComponentType.TextInput]: TextInputBuilder;\n\t/**\n\t * The user select component type is associated with a {@link UserSelectMenuBuilder}.\n\t */\n\t[ComponentType.UserSelect]: UserSelectMenuBuilder;\n\t/**\n\t * The role select component type is associated with a {@link RoleSelectMenuBuilder}.\n\t */\n\t[ComponentType.RoleSelect]: RoleSelectMenuBuilder;\n\t/**\n\t * The mentionable select component type is associated with a {@link MentionableSelectMenuBuilder}.\n\t */\n\t[ComponentType.MentionableSelect]: MentionableSelectMenuBuilder;\n\t/**\n\t * The channel select component type is associated with a {@link ChannelSelectMenuBuilder}.\n\t */\n\t[ComponentType.ChannelSelect]: ChannelSelectMenuBuilder;\n\t/**\n\t * The thumbnail component type is associated with a {@link ThumbnailBuilder}.\n\t */\n\t[ComponentType.Thumbnail]: ThumbnailBuilder;\n\t/**\n\t * The file component type is associated with a {@link FileBuilder}.\n\t */\n\t[ComponentType.File]: FileBuilder;\n\t/**\n\t * The separator component type is associated with a {@link SeparatorBuilder}.\n\t */\n\t[ComponentType.Separator]: SeparatorBuilder;\n\t/**\n\t * The text display component type is associated with a {@link TextDisplayBuilder}.\n\t */\n\t[ComponentType.TextDisplay]: TextDisplayBuilder;\n\t/**\n\t * The media gallery component type is associated with a {@link MediaGalleryBuilder}.\n\t */\n\t[ComponentType.MediaGallery]: MediaGalleryBuilder;\n\t/**\n\t * The section component type is associated with a {@link SectionBuilder}.\n\t */\n\t[ComponentType.Section]: SectionBuilder;\n\t/**\n\t * The container component type is associated with a {@link ContainerBuilder}.\n\t */\n\t[ComponentType.Container]: ContainerBuilder;\n\t/**\n\t * The label component type is associated with a {@link LabelBuilder}.\n\t */\n\t[ComponentType.Label]: LabelBuilder;\n\t/**\n\t * The file upload component type is associated with a {@link FileUploadBuilder}.\n\t */\n\t[ComponentType.FileUpload]: FileUploadBuilder;\n}\n\n/**\n * Factory for creating components from API data.\n *\n * @typeParam ComponentType - The type of component to use\n * @param data - The API data to transform to a component class\n */\nexport function createComponentBuilder<ComponentType extends keyof MappedComponentTypes>(\n\t// eslint-disable-next-line @typescript-eslint/sort-type-constituents\n\tdata: (APIModalComponent | APIMessageComponent) & { type: ComponentType },\n): MappedComponentTypes[ComponentType];\n\n/**\n * Factory for creating components from API data.\n *\n * @typeParam ComponentBuilder - The type of component to use\n * @param data - The API data to transform to a component class\n */\nexport function createComponentBuilder<ComponentBuilder extends MessageComponentBuilder | ModalComponentBuilder>(\n\tdata: ComponentBuilder,\n): ComponentBuilder;\n\nexport function createComponentBuilder(\n\tdata: APIMessageComponent | APIModalComponent | MessageComponentBuilder,\n): ComponentBuilder<APIBaseComponent<ComponentType>> {\n\tif (data instanceof ComponentBuilder) {\n\t\treturn data;\n\t}\n\n\t// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check\n\tswitch (data.type) {\n\t\tcase ComponentType.ActionRow:\n\t\t\treturn new ActionRowBuilder(data);\n\t\tcase ComponentType.Button:\n\t\t\treturn createButtonBuilder(data);\n\t\tcase ComponentType.StringSelect:\n\t\t\treturn new StringSelectMenuBuilder(data);\n\t\tcase ComponentType.TextInput:\n\t\t\treturn new TextInputBuilder(data);\n\t\tcase ComponentType.UserSelect:\n\t\t\treturn new UserSelectMenuBuilder(data);\n\t\tcase ComponentType.RoleSelect:\n\t\t\treturn new RoleSelectMenuBuilder(data);\n\t\tcase ComponentType.MentionableSelect:\n\t\t\treturn new MentionableSelectMenuBuilder(data);\n\t\tcase ComponentType.ChannelSelect:\n\t\t\treturn new ChannelSelectMenuBuilder(data);\n\t\tcase ComponentType.Thumbnail:\n\t\t\treturn new ThumbnailBuilder(data);\n\t\tcase ComponentType.File:\n\t\t\treturn new FileBuilder(data);\n\t\tcase ComponentType.Separator:\n\t\t\treturn new SeparatorBuilder(data);\n\t\tcase ComponentType.TextDisplay:\n\t\t\treturn new TextDisplayBuilder(data);\n\t\tcase ComponentType.MediaGallery:\n\t\t\treturn new MediaGalleryBuilder(data);\n\t\tcase ComponentType.Section:\n\t\t\treturn new SectionBuilder(data);\n\t\tcase ComponentType.Container:\n\t\t\treturn new ContainerBuilder(data);\n\t\tcase ComponentType.Label:\n\t\t\treturn new LabelBuilder(data);\n\t\tcase ComponentType.FileUpload:\n\t\t\treturn new FileUploadBuilder(data);\n\t\tdefault:\n\t\t\t// TODO: add back @ts-expect-error This case can still occur if we get a newer unsupported component type\n\t\t\tthrow new Error(`Cannot properly serialize component type: ${data.type}`);\n\t}\n}\n\nfunction createButtonBuilder(data: APIButtonComponent): ButtonBuilder {\n\tswitch (data.style) {\n\t\tcase ButtonStyle.Primary:\n\t\t\treturn new PrimaryButtonBuilder(data);\n\t\tcase ButtonStyle.Secondary:\n\t\t\treturn new SecondaryButtonBuilder(data);\n\t\tcase ButtonStyle.Success:\n\t\t\treturn new SuccessButtonBuilder(data);\n\t\tcase ButtonStyle.Danger:\n\t\t\treturn new DangerButtonBuilder(data);\n\t\tcase ButtonStyle.Link:\n\t\t\treturn new LinkButtonBuilder(data);\n\t\tcase ButtonStyle.Premium:\n\t\t\treturn new PremiumButtonBuilder(data);\n\t\tdefault:\n\t\t\t// @ts-expect-error This case can still occur if we get a newer unsupported button style\n\t\t\tthrow new Error(`Cannot properly serialize button with style: ${data.style}`);\n\t}\n}\n\nexport function resolveAccessoryComponent(component: APISectionAccessoryComponent) {\n\tswitch (component.type) {\n\t\tcase ComponentType.Button:\n\t\t\treturn createButtonBuilder(component);\n\t\tcase ComponentType.Thumbnail:\n\t\t\treturn new ThumbnailBuilder(component);\n\t\tdefault:\n\t\t\t// @ts-expect-error This case can still occur if we get a newer unsupported component type\n\t\t\tthrow new Error(`Cannot properly serialize section accessory component: ${component.type}`);\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/button/Button.ts",
    "content": "import type { APIButtonComponent } from 'discord-api-types/v10';\nimport { validate } from '../../util/validation.js';\nimport { buttonPredicate } from '../Assertions.js';\nimport { ComponentBuilder } from '../Component.js';\n\n/**\n * A builder that creates API-compatible JSON data for buttons.\n */\nexport abstract class BaseButtonBuilder<ButtonData extends APIButtonComponent> extends ComponentBuilder<ButtonData> {\n\t/**\n\t * @internal\n\t */\n\tdeclare protected readonly data: Partial<ButtonData>;\n\n\t/**\n\t * Sets whether this button is disabled.\n\t *\n\t * @param disabled - Whether to disable this button\n\t */\n\tpublic setDisabled(disabled = true) {\n\t\tthis.data.disabled = disabled;\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): ButtonData {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(buttonPredicate, clone, validationOverride);\n\n\t\treturn clone as ButtonData;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/button/CustomIdButton.ts",
    "content": "import { ButtonStyle, ComponentType, type APIButtonComponentWithCustomId } from 'discord-api-types/v10';\nimport { Mixin } from 'ts-mixer';\nimport { BaseButtonBuilder } from './Button.js';\nimport { EmojiOrLabelButtonMixin } from './mixins/EmojiOrLabelButtonMixin.js';\n\nexport type CustomIdButtonStyle = APIButtonComponentWithCustomId['style'];\n\n/**\n * A builder that creates API-compatible JSON data for buttons with custom IDs.\n *\n * @mixes {@link BaseButtonBuilder}\\<{@link discord-api-types/v10#(APIButtonComponentWithCustomId:interface)}\\>\n * @mixes {@link EmojiOrLabelButtonMixin}\n */\nexport abstract class CustomIdButtonBuilder extends Mixin(\n\tBaseButtonBuilder<APIButtonComponentWithCustomId>,\n\tEmojiOrLabelButtonMixin,\n) {\n\tprotected override readonly data: Partial<APIButtonComponentWithCustomId>;\n\n\tprotected constructor(data: Partial<APIButtonComponentWithCustomId> = {}) {\n\t\tsuper();\n\t\tthis.data = { ...structuredClone(data), type: ComponentType.Button };\n\t}\n\n\t/**\n\t * Sets the custom id for this button.\n\t *\n\t * @remarks\n\t * This method is only applicable to buttons that are not using the `Link` button style.\n\t * @param customId - The custom id to use\n\t */\n\tpublic setCustomId(customId: string) {\n\t\tthis.data.custom_id = customId;\n\t\treturn this;\n\t}\n}\n\n/**\n * A builder that creates API-compatible JSON data for buttons with custom IDs (using the primary style).\n */\nexport class PrimaryButtonBuilder extends CustomIdButtonBuilder {\n\tpublic constructor(data: Partial<APIButtonComponentWithCustomId> = {}) {\n\t\tsuper({ ...data, style: ButtonStyle.Primary });\n\t}\n}\n\n/**\n * A builder that creates API-compatible JSON data for buttons with custom IDs (using the secondary style).\n */\nexport class SecondaryButtonBuilder extends CustomIdButtonBuilder {\n\tpublic constructor(data: Partial<APIButtonComponentWithCustomId> = {}) {\n\t\tsuper({ ...data, style: ButtonStyle.Secondary });\n\t}\n}\n\n/**\n * A builder that creates API-compatible JSON data for buttons with custom IDs (using the success style).\n */\nexport class SuccessButtonBuilder extends CustomIdButtonBuilder {\n\tpublic constructor(data: Partial<APIButtonComponentWithCustomId> = {}) {\n\t\tsuper({ ...data, style: ButtonStyle.Success });\n\t}\n}\n\n/**\n * A builder that creates API-compatible JSON data for buttons with custom IDs (using the danger style).\n */\nexport class DangerButtonBuilder extends CustomIdButtonBuilder {\n\tpublic constructor(data: Partial<APIButtonComponentWithCustomId> = {}) {\n\t\tsuper({ ...data, style: ButtonStyle.Danger });\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/button/LinkButton.ts",
    "content": "import {\n\tButtonStyle,\n\tComponentType,\n\ttype APIButtonComponent,\n\ttype APIButtonComponentWithURL,\n} from 'discord-api-types/v10';\nimport { Mixin } from 'ts-mixer';\nimport { BaseButtonBuilder } from './Button.js';\nimport { EmojiOrLabelButtonMixin } from './mixins/EmojiOrLabelButtonMixin.js';\n\n/**\n * A builder that creates API-compatible JSON data for buttons with links.\n *\n * @mixes {@link BaseButtonBuilder}\\<{@link discord-api-types/v10#(APIButtonComponentWithURL:interface)}\\>\n * @mixes {@link EmojiOrLabelButtonMixin}\n */\nexport class LinkButtonBuilder extends Mixin(BaseButtonBuilder<APIButtonComponentWithURL>, EmojiOrLabelButtonMixin) {\n\tprotected override readonly data: Partial<APIButtonComponentWithURL>;\n\n\tpublic constructor(data: Partial<APIButtonComponent> = {}) {\n\t\tsuper();\n\t\tthis.data = { ...structuredClone(data), type: ComponentType.Button, style: ButtonStyle.Link };\n\t}\n\n\t/**\n\t * Sets the URL for this button.\n\t *\n\t * @remarks\n\t * This method is only available to buttons using the `Link` button style.\n\t * Only three types of URL schemes are currently supported: `https://`, `http://`, and `discord://`.\n\t * @param url - The URL to use\n\t */\n\tpublic setURL(url: string) {\n\t\tthis.data.url = url;\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/button/PremiumButton.ts",
    "content": "import type { APIButtonComponentWithSKUId, Snowflake } from 'discord-api-types/v10';\nimport { ButtonStyle, ComponentType } from 'discord-api-types/v10';\nimport { BaseButtonBuilder } from './Button.js';\n\n/**\n * A builder that creates API-compatible JSON data for premium buttons.\n */\nexport class PremiumButtonBuilder extends BaseButtonBuilder<APIButtonComponentWithSKUId> {\n\tprotected override readonly data: Partial<APIButtonComponentWithSKUId>;\n\n\tpublic constructor(data: Partial<APIButtonComponentWithSKUId> = {}) {\n\t\tsuper();\n\t\tthis.data = { ...structuredClone(data), type: ComponentType.Button, style: ButtonStyle.Premium };\n\t}\n\n\t/**\n\t * Sets the SKU id that represents a purchasable SKU for this button.\n\t *\n\t * @remarks Only available when using premium-style buttons.\n\t * @param skuId - The SKU id to use\n\t */\n\tpublic setSKUId(skuId: Snowflake) {\n\t\tthis.data.sku_id = skuId;\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/button/mixins/EmojiOrLabelButtonMixin.ts",
    "content": "import type { APIButtonComponent, APIButtonComponentWithSKUId, APIMessageComponentEmoji } from 'discord-api-types/v10';\n\nexport interface EmojiOrLabelButtonData extends Pick<\n\tExclude<APIButtonComponent, APIButtonComponentWithSKUId>,\n\t'emoji' | 'label'\n> {}\n\n/**\n * A mixin that adds emoji and label symbols to a button builder.\n */\nexport class EmojiOrLabelButtonMixin {\n\t/**\n\t * @internal\n\t */\n\tdeclare protected readonly data: EmojiOrLabelButtonData;\n\n\t/**\n\t * Sets the emoji to display on this button.\n\t *\n\t * @param emoji - The emoji to use\n\t */\n\tpublic setEmoji(emoji: APIMessageComponentEmoji) {\n\t\tthis.data.emoji = emoji;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the emoji on this button.\n\t */\n\tpublic clearEmoji() {\n\t\tthis.data.emoji = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the label for this button.\n\t *\n\t * @param label - The label to use\n\t */\n\tpublic setLabel(label: string) {\n\t\tthis.data.label = label;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the label on this button.\n\t */\n\tpublic clearLabel() {\n\t\tthis.data.label = undefined;\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/fileUpload/Assertions.ts",
    "content": "import { ComponentType } from 'discord-api-types/v10';\nimport { z } from 'zod';\nimport { customIdPredicate, idPredicate } from '../../Assertions';\n\nexport const fileUploadPredicate = z.object({\n\ttype: z.literal(ComponentType.FileUpload),\n\tid: idPredicate,\n\tcustom_id: customIdPredicate,\n\tmin_values: z.int().min(0).max(10).optional(),\n\tmax_values: z.int().min(1).max(10).optional(),\n\trequired: z.boolean().optional(),\n});\n"
  },
  {
    "path": "packages/builders/src/components/fileUpload/FileUpload.ts",
    "content": "import type { APIFileUploadComponent } from 'discord-api-types/v10';\nimport { ComponentType } from 'discord-api-types/v10';\nimport { validate } from '../../util/validation.js';\nimport { ComponentBuilder } from '../Component.js';\nimport { fileUploadPredicate } from './Assertions.js';\n\n/**\n * A builder that creates API-compatible JSON data for file uploads.\n */\nexport class FileUploadBuilder extends ComponentBuilder<APIFileUploadComponent> {\n\t/**\n\t * @internal\n\t */\n\tprotected readonly data: Partial<APIFileUploadComponent>;\n\n\t/**\n\t * Creates a new file upload.\n\t *\n\t * @param data - The API data to create this file upload with\n\t * @example\n\t * Creating a file upload from an API data object:\n\t * ```ts\n\t * const fileUpload = new FileUploadBuilder({\n\t * \tcustom_id: \"file_upload\",\n\t *  min_values: 2,\n\t *  max_values: 5,\n\t * });\n\t * ```\n\t * @example\n\t * Creating a file upload using setters and API data:\n\t * ```ts\n\t * const fileUpload = new FileUploadBuilder({\n\t * \tcustom_id: \"file_upload\",\n\t *  min_values: 2,\n\t *  max_values: 5,\n\t * }).setRequired();\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APIFileUploadComponent> = {}) {\n\t\tsuper();\n\t\tthis.data = { ...structuredClone(data), type: ComponentType.FileUpload };\n\t}\n\n\t/**\n\t * Sets the custom id for this file upload.\n\t *\n\t * @param customId - The custom id to use\n\t */\n\tpublic setCustomId(customId: string) {\n\t\tthis.data.custom_id = customId;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the minimum number of file uploads required.\n\t *\n\t * @param minValues - The minimum values that must be uploaded\n\t */\n\tpublic setMinValues(minValues: number) {\n\t\tthis.data.min_values = minValues;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the minimum values.\n\t */\n\tpublic clearMinValues() {\n\t\tthis.data.min_values = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the maximum number of file uploads required.\n\t *\n\t * @param maxValues - The maximum values that can be uploaded\n\t */\n\tpublic setMaxValues(maxValues: number) {\n\t\tthis.data.max_values = maxValues;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the maximum values.\n\t */\n\tpublic clearMaxValues() {\n\t\tthis.data.max_values = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets whether this file upload is required.\n\t *\n\t * @param required - Whether this file upload is required\n\t */\n\tpublic setRequired(required = true) {\n\t\tthis.data.required = required;\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic toJSON(validationOverride?: boolean): APIFileUploadComponent {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(fileUploadPredicate, clone, validationOverride);\n\n\t\treturn clone as APIFileUploadComponent;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/label/Assertions.ts",
    "content": "import { ComponentType } from 'discord-api-types/v10';\nimport { z } from 'zod';\nimport { idPredicate } from '../../Assertions';\nimport {\n\tselectMenuChannelPredicate,\n\tselectMenuMentionablePredicate,\n\tselectMenuRolePredicate,\n\tselectMenuStringPredicate,\n\tselectMenuUserPredicate,\n} from '../Assertions';\nimport { fileUploadPredicate } from '../fileUpload/Assertions';\nimport { textInputPredicate } from '../textInput/Assertions';\n\nexport const labelPredicate = z.object({\n\tid: idPredicate,\n\ttype: z.literal(ComponentType.Label),\n\tlabel: z.string().min(1).max(45),\n\tdescription: z.string().min(1).max(100).optional(),\n\tcomponent: z.union([\n\t\tselectMenuStringPredicate,\n\t\ttextInputPredicate,\n\t\tselectMenuUserPredicate,\n\t\tselectMenuRolePredicate,\n\t\tselectMenuMentionablePredicate,\n\t\tselectMenuChannelPredicate,\n\t\tfileUploadPredicate,\n\t]),\n});\n"
  },
  {
    "path": "packages/builders/src/components/label/Label.ts",
    "content": "import type {\n\tAPIChannelSelectComponent,\n\tAPIFileUploadComponent,\n\tAPILabelComponent,\n\tAPIMentionableSelectComponent,\n\tAPIRoleSelectComponent,\n\tAPIStringSelectComponent,\n\tAPITextInputComponent,\n\tAPIUserSelectComponent,\n} from 'discord-api-types/v10';\nimport { ComponentType } from 'discord-api-types/v10';\nimport { resolveBuilder } from '../../util/resolveBuilder.js';\nimport { validate } from '../../util/validation.js';\nimport { ComponentBuilder } from '../Component.js';\nimport { createComponentBuilder } from '../Components.js';\nimport { FileUploadBuilder } from '../fileUpload/FileUpload.js';\nimport { ChannelSelectMenuBuilder } from '../selectMenu/ChannelSelectMenu.js';\nimport { MentionableSelectMenuBuilder } from '../selectMenu/MentionableSelectMenu.js';\nimport { RoleSelectMenuBuilder } from '../selectMenu/RoleSelectMenu.js';\nimport { StringSelectMenuBuilder } from '../selectMenu/StringSelectMenu.js';\nimport { UserSelectMenuBuilder } from '../selectMenu/UserSelectMenu.js';\nimport { TextInputBuilder } from '../textInput/TextInput.js';\nimport { labelPredicate } from './Assertions.js';\n\nexport interface LabelBuilderData extends Partial<Omit<APILabelComponent, 'component'>> {\n\tcomponent?:\n\t\t| ChannelSelectMenuBuilder\n\t\t| FileUploadBuilder\n\t\t| MentionableSelectMenuBuilder\n\t\t| RoleSelectMenuBuilder\n\t\t| StringSelectMenuBuilder\n\t\t| TextInputBuilder\n\t\t| UserSelectMenuBuilder;\n}\n\n/**\n * A builder that creates API-compatible JSON data for labels.\n */\nexport class LabelBuilder extends ComponentBuilder<APILabelComponent> {\n\t/**\n\t * @internal\n\t */\n\tprotected readonly data: LabelBuilderData;\n\n\t/**\n\t * Creates a new label.\n\t *\n\t * @param data - The API data to create this label with\n\t * @example\n\t * Creating a label from an API data object:\n\t * ```ts\n\t * const label = new LabelBuilder({\n\t * \tlabel: \"label\",\n\t * \tcomponent,\n\t * });\n\t * ```\n\t * @example\n\t * Creating a label using setters and API data:\n\t * ```ts\n\t * const label = new LabelBuilder({\n\t * \tlabel: 'label',\n\t * \tcomponent,\n\t * }).setContent('new text');\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APILabelComponent> = {}) {\n\t\tsuper();\n\n\t\tconst { component, ...rest } = data;\n\n\t\tthis.data = {\n\t\t\t...structuredClone(rest),\n\t\t\t// @ts-expect-error Upcoming components update.\n\t\t\tcomponent: component ? createComponentBuilder(component) : undefined,\n\t\t\ttype: ComponentType.Label,\n\t\t};\n\t}\n\n\t/**\n\t * Sets the label for this label.\n\t *\n\t * @param label - The label to use\n\t */\n\tpublic setLabel(label: string) {\n\t\tthis.data.label = label;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the description for this label.\n\t *\n\t * @param description - The description to use\n\t */\n\tpublic setDescription(description: string) {\n\t\tthis.data.description = description;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the description for this label.\n\t */\n\tpublic clearDescription() {\n\t\tthis.data.description = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a string select menu component to this label.\n\t *\n\t * @param input - A function that returns a component builder or an already built builder\n\t */\n\tpublic setStringSelectMenuComponent(\n\t\tinput:\n\t\t\t| APIStringSelectComponent\n\t\t\t| StringSelectMenuBuilder\n\t\t\t| ((builder: StringSelectMenuBuilder) => StringSelectMenuBuilder),\n\t): this {\n\t\tthis.data.component = resolveBuilder(input, StringSelectMenuBuilder);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a user select menu component to this label.\n\t *\n\t * @param input - A function that returns a component builder or an already built builder\n\t */\n\tpublic setUserSelectMenuComponent(\n\t\tinput: APIUserSelectComponent | UserSelectMenuBuilder | ((builder: UserSelectMenuBuilder) => UserSelectMenuBuilder),\n\t): this {\n\t\tthis.data.component = resolveBuilder(input, UserSelectMenuBuilder);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a role select menu component to this label.\n\t *\n\t * @param input - A function that returns a component builder or an already built builder\n\t */\n\tpublic setRoleSelectMenuComponent(\n\t\tinput: APIRoleSelectComponent | RoleSelectMenuBuilder | ((builder: RoleSelectMenuBuilder) => RoleSelectMenuBuilder),\n\t): this {\n\t\tthis.data.component = resolveBuilder(input, RoleSelectMenuBuilder);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a mentionable select menu component to this label.\n\t *\n\t * @param input - A function that returns a component builder or an already built builder\n\t */\n\tpublic setMentionableSelectMenuComponent(\n\t\tinput:\n\t\t\t| APIMentionableSelectComponent\n\t\t\t| MentionableSelectMenuBuilder\n\t\t\t| ((builder: MentionableSelectMenuBuilder) => MentionableSelectMenuBuilder),\n\t): this {\n\t\tthis.data.component = resolveBuilder(input, MentionableSelectMenuBuilder);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a channel select menu component to this label.\n\t *\n\t * @param input - A function that returns a component builder or an already built builder\n\t */\n\tpublic setChannelSelectMenuComponent(\n\t\tinput:\n\t\t\t| APIChannelSelectComponent\n\t\t\t| ChannelSelectMenuBuilder\n\t\t\t| ((builder: ChannelSelectMenuBuilder) => ChannelSelectMenuBuilder),\n\t): this {\n\t\tthis.data.component = resolveBuilder(input, ChannelSelectMenuBuilder);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a text input component to this label.\n\t *\n\t * @param input - A function that returns a component builder or an already built builder\n\t */\n\tpublic setTextInputComponent(\n\t\tinput: APITextInputComponent | TextInputBuilder | ((builder: TextInputBuilder) => TextInputBuilder),\n\t): this {\n\t\tthis.data.component = resolveBuilder(input, TextInputBuilder);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a file upload component to this label.\n\t *\n\t * @param input - A function that returns a component builder or an already built builder\n\t */\n\tpublic setFileUploadComponent(\n\t\tinput: APIFileUploadComponent | FileUploadBuilder | ((builder: FileUploadBuilder) => FileUploadBuilder),\n\t): this {\n\t\tthis.data.component = resolveBuilder(input, FileUploadBuilder);\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): APILabelComponent {\n\t\tconst { component, ...rest } = this.data;\n\n\t\tconst data = {\n\t\t\t...structuredClone(rest),\n\t\t\t// The label predicate validates the component.\n\t\t\tcomponent: component?.toJSON(false),\n\t\t};\n\n\t\tvalidate(labelPredicate, data, validationOverride);\n\n\t\treturn data as APILabelComponent;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/selectMenu/BaseSelectMenu.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type { APISelectMenuComponent } from 'discord-api-types/v10';\nimport { ComponentBuilder } from '../Component.js';\n\n/**\n * The base select menu builder that contains common symbols for select menu builders.\n *\n * @typeParam Data - The type of API data that is stored within the builder\n */\nexport abstract class BaseSelectMenuBuilder<Data extends APISelectMenuComponent>\n\textends ComponentBuilder<Data>\n\timplements JSONEncodable<APISelectMenuComponent>\n{\n\t/**\n\t * @internal\n\t */\n\tprotected abstract override readonly data: Partial<\n\t\tPick<Data, 'custom_id' | 'disabled' | 'id' | 'max_values' | 'min_values' | 'placeholder' | 'required'>\n\t>;\n\n\t/**\n\t * Sets the placeholder for this select menu.\n\t *\n\t * @param placeholder - The placeholder to use\n\t */\n\tpublic setPlaceholder(placeholder: string) {\n\t\tthis.data.placeholder = placeholder;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the placeholder for this select menu.\n\t */\n\tpublic clearPlaceholder() {\n\t\tthis.data.placeholder = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the minimum values that must be selected in the select menu.\n\t *\n\t * @param minValues - The minimum values that must be selected\n\t */\n\tpublic setMinValues(minValues: number) {\n\t\tthis.data.min_values = minValues;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the maximum values that can be selected in the select menu.\n\t *\n\t * @param maxValues - The maximum values that can be selected\n\t */\n\tpublic setMaxValues(maxValues: number) {\n\t\tthis.data.max_values = maxValues;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the custom id for this select menu.\n\t *\n\t * @param customId - The custom id to use\n\t */\n\tpublic setCustomId(customId: string) {\n\t\tthis.data.custom_id = customId;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets whether this select menu is disabled.\n\t *\n\t * @param disabled - Whether this select menu is disabled\n\t */\n\tpublic setDisabled(disabled = true) {\n\t\tthis.data.disabled = disabled;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets whether this select menu is required.\n\t *\n\t * @remarks Only for use in modals.\n\t * @param required - Whether this string select menu is required\n\t */\n\tpublic setRequired(required = true) {\n\t\tthis.data.required = required;\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/selectMenu/ChannelSelectMenu.ts",
    "content": "import {\n\ttype APIChannelSelectComponent,\n\ttype ChannelType,\n\ttype Snowflake,\n\tComponentType,\n\tSelectMenuDefaultValueType,\n} from 'discord-api-types/v10';\nimport { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';\nimport { validate } from '../../util/validation.js';\nimport { selectMenuChannelPredicate } from '../Assertions.js';\nimport { BaseSelectMenuBuilder } from './BaseSelectMenu.js';\n\n/**\n * A builder that creates API-compatible JSON data for channel select menus.\n */\nexport class ChannelSelectMenuBuilder extends BaseSelectMenuBuilder<APIChannelSelectComponent> {\n\tprotected override readonly data: Partial<APIChannelSelectComponent>;\n\n\t/**\n\t * Creates a new channel select menu.\n\t *\n\t * @param data - The API data to create this channel select menu with\n\t * @example\n\t * Creating a select menu from an API data object:\n\t * ```ts\n\t * const selectMenu = new ChannelSelectMenuBuilder({\n\t * \tcustom_id: 'a cool select menu',\n\t * \tplaceholder: 'select an option',\n\t * \tmax_values: 2,\n\t * });\n\t * ```\n\t * @example\n\t * Creating a select menu using setters and API data:\n\t * ```ts\n\t * const selectMenu = new ChannelSelectMenuBuilder({\n\t * \tcustom_id: 'a cool select menu',\n\t * })\n\t * \t.addChannelTypes(ChannelType.GuildText, ChannelType.GuildAnnouncement)\n\t * \t.setMinValues(2);\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APIChannelSelectComponent> = {}) {\n\t\tsuper();\n\t\tthis.data = { ...structuredClone(data), type: ComponentType.ChannelSelect };\n\t}\n\n\t/**\n\t * Adds channel types to this select menu.\n\t *\n\t * @param types - The channel types to use\n\t */\n\tpublic addChannelTypes(...types: RestOrArray<ChannelType>) {\n\t\tconst normalizedTypes = normalizeArray(types);\n\t\tthis.data.channel_types ??= [];\n\t\tthis.data.channel_types.push(...normalizedTypes);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets channel types for this select menu.\n\t *\n\t * @param types - The channel types to use\n\t */\n\tpublic setChannelTypes(...types: RestOrArray<ChannelType>) {\n\t\tconst normalizedTypes = normalizeArray(types);\n\t\tthis.data.channel_types ??= [];\n\t\tthis.data.channel_types.splice(0, this.data.channel_types.length, ...normalizedTypes);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds default channels to this auto populated select menu.\n\t *\n\t * @param channels - The channels to add\n\t */\n\tpublic addDefaultChannels(...channels: RestOrArray<Snowflake>) {\n\t\tconst normalizedValues = normalizeArray(channels);\n\t\tthis.data.default_values ??= [];\n\n\t\tthis.data.default_values.push(\n\t\t\t...normalizedValues.map((id) => ({\n\t\t\t\tid,\n\t\t\t\ttype: SelectMenuDefaultValueType.Channel as const,\n\t\t\t})),\n\t\t);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets default channels for this auto populated select menu.\n\t *\n\t * @param channels - The channels to set\n\t */\n\tpublic setDefaultChannels(...channels: RestOrArray<Snowflake>) {\n\t\tconst normalizedValues = normalizeArray(channels);\n\n\t\tthis.data.default_values = normalizedValues.map((id) => ({\n\t\t\tid,\n\t\t\ttype: SelectMenuDefaultValueType.Channel as const,\n\t\t}));\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): APIChannelSelectComponent {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(selectMenuChannelPredicate, clone, validationOverride);\n\n\t\treturn clone as APIChannelSelectComponent;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/selectMenu/MentionableSelectMenu.ts",
    "content": "import {\n\ttype APIMentionableSelectComponent,\n\ttype APISelectMenuDefaultValue,\n\ttype Snowflake,\n\tComponentType,\n\tSelectMenuDefaultValueType,\n} from 'discord-api-types/v10';\nimport { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';\nimport { validate } from '../../util/validation.js';\nimport { selectMenuMentionablePredicate } from '../Assertions.js';\nimport { BaseSelectMenuBuilder } from './BaseSelectMenu.js';\n\n/**\n * A builder that creates API-compatible JSON data for mentionable select menus.\n */\nexport class MentionableSelectMenuBuilder extends BaseSelectMenuBuilder<APIMentionableSelectComponent> {\n\tprotected override readonly data: Partial<APIMentionableSelectComponent>;\n\n\t/**\n\t * Creates a new mentionable select menu.\n\t *\n\t * @param data - The API data to create this mentionable select menu with\n\t * @example\n\t * Creating a select menu from an API data object:\n\t * ```ts\n\t * const selectMenu = new MentionableSelectMenuBuilder({\n\t * \tcustom_id: 'a cool select menu',\n\t * \tplaceholder: 'select an option',\n\t * \tmax_values: 2,\n\t * });\n\t * ```\n\t * @example\n\t * Creating a select menu using setters and API data:\n\t * ```ts\n\t * const selectMenu = new MentionableSelectMenuBuilder({\n\t * \tcustom_id: 'a cool select menu',\n\t * })\n\t * \t.setMinValues(1);\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APIMentionableSelectComponent> = {}) {\n\t\tsuper();\n\t\tthis.data = { ...structuredClone(data), type: ComponentType.MentionableSelect };\n\t}\n\n\t/**\n\t * Adds default roles to this auto populated select menu.\n\t *\n\t * @param roles - The roles to add\n\t */\n\tpublic addDefaultRoles(...roles: RestOrArray<Snowflake>) {\n\t\tconst normalizedValues = normalizeArray(roles);\n\t\tthis.data.default_values ??= [];\n\n\t\tthis.data.default_values.push(\n\t\t\t...normalizedValues.map((id) => ({\n\t\t\t\tid,\n\t\t\t\ttype: SelectMenuDefaultValueType.Role as const,\n\t\t\t})),\n\t\t);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds default users to this auto populated select menu.\n\t *\n\t * @param users - The users to add\n\t */\n\tpublic addDefaultUsers(...users: RestOrArray<Snowflake>) {\n\t\tconst normalizedValues = normalizeArray(users);\n\t\tthis.data.default_values ??= [];\n\n\t\tthis.data.default_values.push(\n\t\t\t...normalizedValues.map((id) => ({\n\t\t\t\tid,\n\t\t\t\ttype: SelectMenuDefaultValueType.User as const,\n\t\t\t})),\n\t\t);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds default values to this auto populated select menu.\n\t *\n\t * @param values - The values to add\n\t */\n\tpublic addDefaultValues(\n\t\t...values: RestOrArray<\n\t\t\t| APISelectMenuDefaultValue<SelectMenuDefaultValueType.Role>\n\t\t\t| APISelectMenuDefaultValue<SelectMenuDefaultValueType.User>\n\t\t>\n\t) {\n\t\tconst normalizedValues = normalizeArray(values);\n\t\tthis.data.default_values ??= [];\n\t\tthis.data.default_values.push(...normalizedValues);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets default values for this auto populated select menu.\n\t *\n\t * @param values - The values to set\n\t */\n\tpublic setDefaultValues(\n\t\t...values: RestOrArray<\n\t\t\t| APISelectMenuDefaultValue<SelectMenuDefaultValueType.Role>\n\t\t\t| APISelectMenuDefaultValue<SelectMenuDefaultValueType.User>\n\t\t>\n\t) {\n\t\tconst normalizedValues = normalizeArray(values);\n\t\tthis.data.default_values = normalizedValues;\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): APIMentionableSelectComponent {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(selectMenuMentionablePredicate, clone, validationOverride);\n\n\t\treturn clone as APIMentionableSelectComponent;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/selectMenu/RoleSelectMenu.ts",
    "content": "import {\n\ttype APIRoleSelectComponent,\n\ttype Snowflake,\n\tComponentType,\n\tSelectMenuDefaultValueType,\n} from 'discord-api-types/v10';\nimport { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';\nimport { validate } from '../../util/validation.js';\nimport { selectMenuRolePredicate } from '../Assertions.js';\nimport { BaseSelectMenuBuilder } from './BaseSelectMenu.js';\n\n/**\n * A builder that creates API-compatible JSON data for role select menus.\n */\nexport class RoleSelectMenuBuilder extends BaseSelectMenuBuilder<APIRoleSelectComponent> {\n\tprotected override readonly data: Partial<APIRoleSelectComponent>;\n\n\t/**\n\t * Creates a new role select menu.\n\t *\n\t * @param data - The API data to create this role select menu with\n\t * @example\n\t * Creating a select menu from an API data object:\n\t * ```ts\n\t * const selectMenu = new RoleSelectMenuBuilder({\n\t * \tcustom_id: 'a cool select menu',\n\t * \tplaceholder: 'select an option',\n\t * \tmax_values: 2,\n\t * });\n\t * ```\n\t * @example\n\t * Creating a select menu using setters and API data:\n\t * ```ts\n\t * const selectMenu = new RoleSelectMenuBuilder({\n\t * \tcustom_id: 'a cool select menu',\n\t * })\n\t * \t.setMinValues(1);\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APIRoleSelectComponent> = {}) {\n\t\tsuper();\n\t\tthis.data = { ...structuredClone(data), type: ComponentType.RoleSelect };\n\t}\n\n\t/**\n\t * Adds default roles to this auto populated select menu.\n\t *\n\t * @param roles - The roles to add\n\t */\n\tpublic addDefaultRoles(...roles: RestOrArray<Snowflake>) {\n\t\tconst normalizedValues = normalizeArray(roles);\n\t\tthis.data.default_values ??= [];\n\n\t\tthis.data.default_values.push(\n\t\t\t...normalizedValues.map((id) => ({\n\t\t\t\tid,\n\t\t\t\ttype: SelectMenuDefaultValueType.Role as const,\n\t\t\t})),\n\t\t);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets default roles for this auto populated select menu.\n\t *\n\t * @param roles - The roles to set\n\t */\n\tpublic setDefaultRoles(...roles: RestOrArray<Snowflake>) {\n\t\tconst normalizedValues = normalizeArray(roles);\n\n\t\tthis.data.default_values = normalizedValues.map((id) => ({\n\t\t\tid,\n\t\t\ttype: SelectMenuDefaultValueType.Role as const,\n\t\t}));\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): APIRoleSelectComponent {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(selectMenuRolePredicate, clone, validationOverride);\n\n\t\treturn clone as APIRoleSelectComponent;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/selectMenu/StringSelectMenu.ts",
    "content": "import { ComponentType } from 'discord-api-types/v10';\nimport type { APIStringSelectComponent, APISelectMenuOption } from 'discord-api-types/v10';\nimport { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';\nimport { resolveBuilder } from '../../util/resolveBuilder.js';\nimport { validate } from '../../util/validation.js';\nimport { selectMenuStringPredicate } from '../Assertions.js';\nimport { BaseSelectMenuBuilder } from './BaseSelectMenu.js';\nimport { StringSelectMenuOptionBuilder } from './StringSelectMenuOption.js';\n\nexport interface StringSelectMenuData extends Partial<Omit<APIStringSelectComponent, 'options'>> {\n\toptions: StringSelectMenuOptionBuilder[];\n\trequired?: boolean;\n}\n\n/**\n * A builder that creates API-compatible JSON data for string select menus.\n */\nexport class StringSelectMenuBuilder extends BaseSelectMenuBuilder<APIStringSelectComponent> {\n\tprotected override readonly data: StringSelectMenuData;\n\n\t/**\n\t * The options for this select menu.\n\t */\n\tpublic get options(): readonly StringSelectMenuOptionBuilder[] {\n\t\treturn this.data.options;\n\t}\n\n\t/**\n\t * Creates a new string select menu.\n\t *\n\t * @param data - The API data to create this string select menu with\n\t * @example\n\t * Creating a select menu from an API data object:\n\t * ```ts\n\t * const selectMenu = new StringSelectMenuBuilder({\n\t * \tcustom_id: 'a cool select menu',\n\t * \tplaceholder: 'select an option',\n\t * \tmax_values: 2,\n\t * \toptions: [\n\t * \t\t{ label: 'option 1', value: '1' },\n\t * \t\t{ label: 'option 2', value: '2' },\n\t * \t\t{ label: 'option 3', value: '3' },\n\t * \t],\n\t * });\n\t * ```\n\t * @example\n\t * Creating a select menu using setters and API data:\n\t * ```ts\n\t * const selectMenu = new StringSelectMenuBuilder({\n\t * \tcustom_id: 'a cool select menu',\n\t * })\n\t * \t.setMinValues(1)\n\t * \t.addOptions({\n\t * \t\tlabel: 'Catchy',\n\t * \t\tvalue: 'catch',\n\t * \t});\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APIStringSelectComponent> = {}) {\n\t\tsuper();\n\n\t\tconst { options = [], ...rest } = data;\n\n\t\tthis.data = {\n\t\t\t...structuredClone(rest),\n\t\t\toptions: options.map((option) => new StringSelectMenuOptionBuilder(option)),\n\t\t\ttype: ComponentType.StringSelect,\n\t\t};\n\t}\n\n\t/**\n\t * Adds options to this select menu.\n\t *\n\t * @param options - The options to add\n\t */\n\tpublic addOptions(\n\t\t...options: RestOrArray<\n\t\t\t| APISelectMenuOption\n\t\t\t| StringSelectMenuOptionBuilder\n\t\t\t| ((builder: StringSelectMenuOptionBuilder) => StringSelectMenuOptionBuilder)\n\t\t>\n\t) {\n\t\tconst normalizedOptions = normalizeArray(options);\n\t\tconst resolved = normalizedOptions.map((option) => resolveBuilder(option, StringSelectMenuOptionBuilder));\n\n\t\tthis.data.options.push(...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the options for this select menu.\n\t *\n\t * @param options - The options to set\n\t */\n\tpublic setOptions(\n\t\t...options: RestOrArray<\n\t\t\t| APISelectMenuOption\n\t\t\t| StringSelectMenuOptionBuilder\n\t\t\t| ((builder: StringSelectMenuOptionBuilder) => StringSelectMenuOptionBuilder)\n\t\t>\n\t) {\n\t\treturn this.spliceOptions(0, this.options.length, ...normalizeArray(options));\n\t}\n\n\t/**\n\t * Removes, replaces, or inserts options for this select menu.\n\t *\n\t * @remarks\n\t * This method behaves similarly\n\t * to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.\n\t * It's useful for modifying and adjusting the order of existing options.\n\t * @example\n\t * Remove the first option:\n\t * ```ts\n\t * selectMenu.spliceOptions(0, 1);\n\t * ```\n\t * @example\n\t * Remove the first n option:\n\t * ```ts\n\t * const n = 4;\n\t * selectMenu.spliceOptions(0, n);\n\t * ```\n\t * @example\n\t * Remove the last option:\n\t * ```ts\n\t * selectMenu.spliceOptions(-1, 1);\n\t * ```\n\t * @param index - The index to start at\n\t * @param deleteCount - The number of options to remove\n\t * @param options - The replacing option objects or builders\n\t */\n\tpublic spliceOptions(\n\t\tindex: number,\n\t\tdeleteCount: number,\n\t\t...options: (\n\t\t\t| APISelectMenuOption\n\t\t\t| StringSelectMenuOptionBuilder\n\t\t\t| ((builder: StringSelectMenuOptionBuilder) => StringSelectMenuOptionBuilder)\n\t\t)[]\n\t) {\n\t\tconst resolved = options.map((option) => resolveBuilder(option, StringSelectMenuOptionBuilder));\n\n\t\tthis.data.options ??= [];\n\t\tthis.data.options.splice(index, deleteCount, ...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): APIStringSelectComponent {\n\t\tconst { options, ...rest } = this.data;\n\t\tconst data = {\n\t\t\t...(structuredClone(rest) as APIStringSelectComponent),\n\t\t\t// selectMenuStringPredicate covers the validation of options\n\t\t\toptions: options.map((option) => option.toJSON(false)),\n\t\t};\n\n\t\tvalidate(selectMenuStringPredicate, data, validationOverride);\n\n\t\treturn data as APIStringSelectComponent;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/selectMenu/StringSelectMenuOption.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type { APIMessageComponentEmoji, APISelectMenuOption } from 'discord-api-types/v10';\nimport { validate } from '../../util/validation.js';\nimport { selectMenuStringOptionPredicate } from '../Assertions.js';\n\n/**\n * A builder that creates API-compatible JSON data for string select menu options.\n */\nexport class StringSelectMenuOptionBuilder implements JSONEncodable<APISelectMenuOption> {\n\tprivate readonly data: Partial<APISelectMenuOption>;\n\n\t/**\n\t * Creates a new string select menu option.\n\t *\n\t * @param data - The API data to create this string select menu option with\n\t * @example\n\t * Creating a string select menu option from an API data object:\n\t * ```ts\n\t * const selectMenuOption = new SelectMenuOptionBuilder({\n\t * \tlabel: 'catchy label',\n\t * \tvalue: '1',\n\t * });\n\t * ```\n\t * @example\n\t * Creating a string select menu option using setters and API data:\n\t * ```ts\n\t * const selectMenuOption = new SelectMenuOptionBuilder({\n\t * \tdefault: true,\n\t * \tvalue: '1',\n\t * })\n\t * \t.setLabel('woah');\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APISelectMenuOption> = {}) {\n\t\tthis.data = structuredClone(data);\n\t}\n\n\t/**\n\t * Sets the label for this option.\n\t *\n\t * @param label - The label to use\n\t */\n\tpublic setLabel(label: string) {\n\t\tthis.data.label = label;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the value for this option.\n\t *\n\t * @param value - The value to use\n\t */\n\tpublic setValue(value: string) {\n\t\tthis.data.value = value;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the description for this option.\n\t *\n\t * @param description - The description to use\n\t */\n\tpublic setDescription(description: string) {\n\t\tthis.data.description = description;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the description for this option.\n\t */\n\tpublic clearDescription() {\n\t\tthis.data.description = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets whether this option is selected by default.\n\t *\n\t * @param isDefault - Whether this option is selected by default\n\t */\n\tpublic setDefault(isDefault = true) {\n\t\tthis.data.default = isDefault;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the emoji to display for this option.\n\t *\n\t * @param emoji - The emoji to use\n\t */\n\tpublic setEmoji(emoji: APIMessageComponentEmoji) {\n\t\tthis.data.emoji = emoji;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the emoji for this option.\n\t */\n\tpublic clearEmoji() {\n\t\tthis.data.emoji = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic toJSON(validationOverride?: boolean): APISelectMenuOption {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(selectMenuStringOptionPredicate, clone, validationOverride);\n\n\t\treturn clone as APISelectMenuOption;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/selectMenu/UserSelectMenu.ts",
    "content": "import {\n\ttype APIUserSelectComponent,\n\ttype Snowflake,\n\tComponentType,\n\tSelectMenuDefaultValueType,\n} from 'discord-api-types/v10';\nimport { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';\nimport { validate } from '../../util/validation.js';\nimport { selectMenuUserPredicate } from '../Assertions.js';\nimport { BaseSelectMenuBuilder } from './BaseSelectMenu.js';\n\n/**\n * A builder that creates API-compatible JSON data for user select menus.\n */\nexport class UserSelectMenuBuilder extends BaseSelectMenuBuilder<APIUserSelectComponent> {\n\tprotected override readonly data: Partial<APIUserSelectComponent>;\n\n\t/**\n\t * Creates a new user select menu.\n\t *\n\t * @param data - The API data to create this user select menu with\n\t * @example\n\t * Creating a select menu from an API data object:\n\t * ```ts\n\t * const selectMenu = new UserSelectMenuBuilder({\n\t * \tcustom_id: 'a cool select menu',\n\t * \tplaceholder: 'select an option',\n\t * \tmax_values: 2,\n\t * });\n\t * ```\n\t * @example\n\t * Creating a select menu using setters and API data:\n\t * ```ts\n\t * const selectMenu = new UserSelectMenuBuilder({\n\t * \tcustom_id: 'a cool select menu',\n\t * })\n\t * \t.setMinValues(1);\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APIUserSelectComponent> = {}) {\n\t\tsuper();\n\t\tthis.data = { ...structuredClone(data), type: ComponentType.UserSelect };\n\t}\n\n\t/**\n\t * Adds default users to this auto populated select menu.\n\t *\n\t * @param users - The users to add\n\t */\n\tpublic addDefaultUsers(...users: RestOrArray<Snowflake>) {\n\t\tconst normalizedValues = normalizeArray(users);\n\n\t\tthis.data.default_values ??= [];\n\t\tthis.data.default_values.push(\n\t\t\t...normalizedValues.map((id) => ({\n\t\t\t\tid,\n\t\t\t\ttype: SelectMenuDefaultValueType.User as const,\n\t\t\t})),\n\t\t);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets default users for this auto populated select menu.\n\t *\n\t * @param users - The users to set\n\t */\n\tpublic setDefaultUsers(...users: RestOrArray<Snowflake>) {\n\t\tconst normalizedValues = normalizeArray(users);\n\n\t\tthis.data.default_values = normalizedValues.map((id) => ({\n\t\t\tid,\n\t\t\ttype: SelectMenuDefaultValueType.User as const,\n\t\t}));\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): APIUserSelectComponent {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(selectMenuUserPredicate, clone, validationOverride);\n\n\t\treturn clone as APIUserSelectComponent;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/textInput/Assertions.ts",
    "content": "import { ComponentType, TextInputStyle } from 'discord-api-types/v10';\nimport { z } from 'zod';\nimport { customIdPredicate, idPredicate } from '../../Assertions.js';\n\nexport const textInputPredicate = z.object({\n\tid: idPredicate,\n\ttype: z.literal(ComponentType.TextInput),\n\tcustom_id: customIdPredicate,\n\tstyle: z.enum(TextInputStyle),\n\tmin_length: z.number().min(0).max(4_000).optional(),\n\tmax_length: z.number().min(1).max(4_000).optional(),\n\tplaceholder: z.string().max(100).optional(),\n\tvalue: z.string().min(0).max(4_000).optional(),\n\trequired: z.boolean().optional(),\n});\n"
  },
  {
    "path": "packages/builders/src/components/textInput/TextInput.ts",
    "content": "import { ComponentType, type TextInputStyle, type APITextInputComponent } from 'discord-api-types/v10';\nimport { validate } from '../../util/validation.js';\nimport { ComponentBuilder } from '../Component.js';\nimport { textInputPredicate } from './Assertions.js';\n\n/**\n * A builder that creates API-compatible JSON data for text inputs.\n */\nexport class TextInputBuilder extends ComponentBuilder<APITextInputComponent> {\n\t/**\n\t * @internal\n\t */\n\tprotected readonly data: Partial<APITextInputComponent>;\n\n\t/**\n\t * Creates a new text input.\n\t *\n\t * @param data - The API data to create this text input with\n\t * @example\n\t * Creating a text input from an API data object:\n\t * ```ts\n\t * const textInput = new TextInputBuilder({\n\t * \tcustom_id: 'a cool text input',\n\t * \tplaceholder: 'Type something',\n\t * \tstyle: TextInputStyle.Short,\n\t * });\n\t * ```\n\t * @example\n\t * Creating a text input using setters and API data:\n\t * ```ts\n\t * const textInput = new TextInputBuilder({\n\t * \tplaceholder: 'Type something else',\n\t * })\n\t * \t.setCustomId('woah')\n\t * \t.setStyle(TextInputStyle.Paragraph);\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APITextInputComponent> = {}) {\n\t\tsuper();\n\t\tthis.data = { ...structuredClone(data), type: ComponentType.TextInput };\n\t}\n\n\t/**\n\t * Sets the custom id for this text input.\n\t *\n\t * @param customId - The custom id to use\n\t */\n\tpublic setCustomId(customId: string) {\n\t\tthis.data.custom_id = customId;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the style for this text input.\n\t *\n\t * @param style - The style to use\n\t */\n\tpublic setStyle(style: TextInputStyle) {\n\t\tthis.data.style = style;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the minimum length of text for this text input.\n\t *\n\t * @param minLength - The minimum length of text for this text input\n\t */\n\tpublic setMinLength(minLength: number) {\n\t\tthis.data.min_length = minLength;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the minimum length of text for this text input.\n\t */\n\tpublic clearMinLength() {\n\t\tthis.data.min_length = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the maximum length of text for this text input.\n\t *\n\t * @param maxLength - The maximum length of text for this text input\n\t */\n\tpublic setMaxLength(maxLength: number) {\n\t\tthis.data.max_length = maxLength;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the maximum length of text for this text input.\n\t */\n\tpublic clearMaxLength() {\n\t\tthis.data.max_length = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the placeholder for this text input.\n\t *\n\t * @param placeholder - The placeholder to use\n\t */\n\tpublic setPlaceholder(placeholder: string) {\n\t\tthis.data.placeholder = placeholder;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the placeholder for this text input.\n\t */\n\tpublic clearPlaceholder() {\n\t\tthis.data.placeholder = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the value for this text input.\n\t *\n\t * @param value - The value to use\n\t */\n\tpublic setValue(value: string) {\n\t\tthis.data.value = value;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the value for this text input.\n\t */\n\tpublic clearValue() {\n\t\tthis.data.value = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets whether this text input is required.\n\t *\n\t * @param required - Whether this text input is required\n\t */\n\tpublic setRequired(required = true) {\n\t\tthis.data.required = required;\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic toJSON(validationOverride?: boolean): APITextInputComponent {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(textInputPredicate, clone, validationOverride);\n\n\t\treturn clone as APITextInputComponent;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/v2/Assertions.ts",
    "content": "import { ComponentType, SeparatorSpacingSize } from 'discord-api-types/v10';\nimport { z } from 'zod';\nimport { idPredicate } from '../../Assertions.js';\nimport { actionRowPredicate } from '../Assertions.js';\n\nconst unfurledMediaItemPredicate = z.object({\n\turl: z.url({ protocol: /^(?:https?|attachment)$/ }),\n});\n\nexport const thumbnailPredicate = z.object({\n\ttype: z.literal(ComponentType.Thumbnail),\n\tid: idPredicate,\n\tmedia: unfurledMediaItemPredicate,\n\tdescription: z.string().min(1).max(1_024).nullish(),\n\tspoiler: z.boolean().optional(),\n});\n\nconst unfurledMediaItemAttachmentOnlyPredicate = z.object({\n\turl: z.url({ protocol: /^attachment$/ }),\n});\n\nexport const filePredicate = z.object({\n\ttype: z.literal(ComponentType.File),\n\tid: idPredicate,\n\tfile: unfurledMediaItemAttachmentOnlyPredicate,\n\tspoiler: z.boolean().optional(),\n});\n\nexport const separatorPredicate = z.object({\n\ttype: z.literal(ComponentType.Separator),\n\tid: idPredicate,\n\tdivider: z.boolean().optional(),\n\tspacing: z.enum(SeparatorSpacingSize).optional(),\n});\n\nexport const textDisplayPredicate = z.object({\n\ttype: z.literal(ComponentType.TextDisplay),\n\tid: idPredicate,\n\tcontent: z.string().min(1).max(4_000),\n});\n\nexport const mediaGalleryItemPredicate = z.object({\n\tid: idPredicate,\n\tmedia: unfurledMediaItemPredicate,\n\tdescription: z.string().min(1).max(1_024).nullish(),\n\tspoiler: z.boolean().optional(),\n});\n\nexport const mediaGalleryPredicate = z.object({\n\ttype: z.literal(ComponentType.MediaGallery),\n\tid: idPredicate,\n\titems: z.array(mediaGalleryItemPredicate).min(1).max(10),\n});\n\nexport const sectionPredicate = z.object({\n\ttype: z.literal(ComponentType.Section),\n\tid: idPredicate,\n\tcomponents: z.array(textDisplayPredicate).min(1).max(3),\n\taccessory: z.union([\n\t\tz.object({ type: z.literal(ComponentType.Button) }),\n\t\tz.object({ type: z.literal(ComponentType.Thumbnail) }),\n\t]),\n});\n\nexport const containerPredicate = z.object({\n\ttype: z.literal(ComponentType.Container),\n\tid: idPredicate,\n\tcomponents: z\n\t\t.array(\n\t\t\tz.union([\n\t\t\t\tactionRowPredicate,\n\t\t\t\tfilePredicate,\n\t\t\t\tmediaGalleryPredicate,\n\t\t\t\tsectionPredicate,\n\t\t\t\tseparatorPredicate,\n\t\t\t\ttextDisplayPredicate,\n\t\t\t]),\n\t\t)\n\t\t.min(1),\n\tspoiler: z.boolean().optional(),\n\taccent_color: z.int().min(0).max(0xffffff).nullish(),\n});\n"
  },
  {
    "path": "packages/builders/src/components/v2/Container.ts",
    "content": "import {\n\ttype APIComponentInMessageActionRow,\n\ttype APISeparatorComponent,\n\ttype APIActionRowComponent,\n\ttype APIFileComponent,\n\ttype APITextDisplayComponent,\n\ttype APIContainerComponent,\n\ttype APIComponentInContainer,\n\ttype APIMediaGalleryComponent,\n\ttype APISectionComponent,\n\tComponentType,\n} from 'discord-api-types/v10';\nimport { normalizeArray, type RestOrArray } from '../../util/normalizeArray';\nimport { resolveBuilder } from '../../util/resolveBuilder';\nimport { validate } from '../../util/validation';\nimport { ActionRowBuilder } from '../ActionRow.js';\nimport { ComponentBuilder } from '../Component.js';\nimport { createComponentBuilder } from '../Components';\nimport { containerPredicate } from './Assertions';\nimport { FileBuilder } from './File.js';\nimport { MediaGalleryBuilder } from './MediaGallery';\nimport { SectionBuilder } from './Section';\nimport { SeparatorBuilder } from './Separator.js';\nimport { TextDisplayBuilder } from './TextDisplay';\n\nexport type ContainerComponentBuilders =\n\t| ActionRowBuilder\n\t| FileBuilder\n\t| MediaGalleryBuilder\n\t| SectionBuilder\n\t| SeparatorBuilder\n\t| TextDisplayBuilder;\n\nexport interface ContainerBuilderData extends Partial<Omit<APIContainerComponent, 'components'>> {\n\tcomponents: ContainerComponentBuilders[];\n}\n\n/**\n * A builder that creates API-compatible JSON data for containers.\n */\nexport class ContainerBuilder extends ComponentBuilder<APIContainerComponent> {\n\t/**\n\t * @internal\n\t */\n\tprotected readonly data: ContainerBuilderData;\n\n\t/**\n\t * Gets the components within this container.\n\t */\n\tpublic get components(): readonly ContainerComponentBuilders[] {\n\t\treturn this.data.components;\n\t}\n\n\t/**\n\t * Creates a new container builder.\n\t *\n\t * @param data - The API data to create the container with\n\t */\n\tpublic constructor(data: Partial<APIContainerComponent> = {}) {\n\t\tsuper();\n\n\t\tconst { components = [], ...rest } = data;\n\n\t\tthis.data = {\n\t\t\t...structuredClone(rest),\n\t\t\tcomponents: components.map((component) => createComponentBuilder(component)),\n\t\t\ttype: ComponentType.Container,\n\t\t};\n\t}\n\n\t/**\n\t * Sets the accent color of this container.\n\t *\n\t * @param color - The color to use\n\t */\n\tpublic setAccentColor(color: number) {\n\t\tthis.data.accent_color = color;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the accent color of this container.\n\t */\n\tpublic clearAccentColor() {\n\t\tthis.data.accent_color = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the spoiler status of this container.\n\t *\n\t * @param spoiler - The spoiler status to use\n\t */\n\tpublic setSpoiler(spoiler = true) {\n\t\tthis.data.spoiler = spoiler;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds action row components to this container.\n\t *\n\t * @param input - The action row to add\n\t */\n\tpublic addActionRowComponents(\n\t\t...input: RestOrArray<\n\t\t\t| ActionRowBuilder\n\t\t\t| APIActionRowComponent<APIComponentInMessageActionRow>\n\t\t\t| ((builder: ActionRowBuilder) => ActionRowBuilder)\n\t\t>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((component) => resolveBuilder(component, ActionRowBuilder));\n\n\t\tthis.data.components.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds file components to this container.\n\t *\n\t * @param input - The file components to add\n\t */\n\tpublic addFileComponents(\n\t\t...input: RestOrArray<APIFileComponent | FileBuilder | ((builder: FileBuilder) => FileBuilder)>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((component) => resolveBuilder(component, FileBuilder));\n\n\t\tthis.data.components.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds media gallery components to this container.\n\t *\n\t * @param input - The media gallery components to add\n\t */\n\tpublic addMediaGalleryComponents(\n\t\t...input: RestOrArray<\n\t\t\tAPIMediaGalleryComponent | MediaGalleryBuilder | ((builder: MediaGalleryBuilder) => MediaGalleryBuilder)\n\t\t>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((component) => resolveBuilder(component, MediaGalleryBuilder));\n\n\t\tthis.data.components.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds section components to this container.\n\t *\n\t * @param input - The section components to add\n\t */\n\tpublic addSectionComponents(\n\t\t...input: RestOrArray<APISectionComponent | SectionBuilder | ((builder: SectionBuilder) => SectionBuilder)>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((component) => resolveBuilder(component, SectionBuilder));\n\n\t\tthis.data.components.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds separator components to this container.\n\t *\n\t * @param input - The separator components to add\n\t */\n\tpublic addSeparatorComponents(\n\t\t...input: RestOrArray<APISeparatorComponent | SeparatorBuilder | ((builder: SeparatorBuilder) => SeparatorBuilder)>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((component) => resolveBuilder(component, SeparatorBuilder));\n\n\t\tthis.data.components.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds text display components to this container.\n\t *\n\t * @param input - The text display components to add\n\t */\n\tpublic addTextDisplayComponents(\n\t\t...input: RestOrArray<\n\t\t\tAPITextDisplayComponent | TextDisplayBuilder | ((builder: TextDisplayBuilder) => TextDisplayBuilder)\n\t\t>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((component) => resolveBuilder(component, TextDisplayBuilder));\n\n\t\tthis.data.components.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes, replaces, or inserts components for this container\n\t *\n\t * @remarks\n\t * This method behaves similarly\n\t * to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.\n\t *\n\t * It's useful for modifying and adjusting order of the already-existing components of a container.\n\t * @example\n\t * Remove the first component:\n\t * ```ts\n\t * container.spliceComponents(0, 1);\n\t * ```\n\t * @example\n\t * Remove the first n components:\n\t * ```ts\n\t * const n = 4;\n\t * container.spliceComponents(0, n);\n\t * ```\n\t * @example\n\t * Remove the last component:\n\t * ```ts\n\t * container.spliceComponents(-1, 1);\n\t * ```\n\t * @param index - The index to start at\n\t * @param deleteCount - The number of components to remove\n\t * @param components - The replacing component objects\n\t */\n\tpublic spliceComponents(\n\t\tindex: number,\n\t\tdeleteCount: number,\n\t\t...components: RestOrArray<APIComponentInContainer | ContainerComponentBuilders>\n\t): this {\n\t\tconst normalized = normalizeArray(components);\n\t\tconst resolved = normalized.map((component) =>\n\t\t\tcomponent instanceof ComponentBuilder ? component : createComponentBuilder(component),\n\t\t);\n\n\t\tthis.data.components.splice(index, deleteCount, ...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): APIContainerComponent {\n\t\tconst { components, ...rest } = this.data;\n\n\t\tconst data = {\n\t\t\t...structuredClone(rest),\n\t\t\tcomponents: components.map((component) => component.toJSON(false)),\n\t\t};\n\n\t\tvalidate(containerPredicate, data, validationOverride);\n\n\t\treturn data as APIContainerComponent;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/v2/File.ts",
    "content": "import { ComponentType, type APIFileComponent } from 'discord-api-types/v10';\nimport { validate } from '../../util/validation.js';\nimport { ComponentBuilder } from '../Component.js';\nimport { filePredicate } from './Assertions.js';\n\n/**\n * A builder that creates API-compatible JSON data for files.\n */\nexport class FileBuilder extends ComponentBuilder<APIFileComponent> {\n\t/**\n\t * @internal\n\t */\n\tprotected readonly data: Partial<APIFileComponent>;\n\n\t/**\n\t * Creates a new file.\n\t *\n\t * @param data - The API data to create this file with\n\t * @example\n\t * Creating a file from an API data object:\n\t * ```ts\n\t * const file = new FileBuilder({\n\t * \tspoiler: true,\n\t * \tfile: {\n\t * \t\turl: 'attachment://file.png',\n\t * \t},\n\t * });\n\t * ```\n\t * @example\n\t * Creating a file using setters and API data:\n\t * ```ts\n\t * const file = new FileBuilder({\n\t * \tfile: {\n\t * \t\turl: 'attachment://image.jpg',\n\t * \t},\n\t * })\n\t * \t.setSpoiler(false);\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APIFileComponent> = {}) {\n\t\tsuper();\n\n\t\tconst { file, ...rest } = data;\n\n\t\tthis.data = {\n\t\t\t...structuredClone(rest),\n\t\t\tfile: file && { url: file.url },\n\t\t\ttype: ComponentType.File,\n\t\t};\n\t}\n\n\t/**\n\t * Sets the spoiler status of this file.\n\t *\n\t * @param spoiler - The spoiler status to use\n\t */\n\tpublic setSpoiler(spoiler = true) {\n\t\tthis.data.spoiler = spoiler;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the media URL of this file.\n\t *\n\t * @param url - The URL to use\n\t */\n\tpublic setURL(url: string) {\n\t\tthis.data.file = { url };\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): APIFileComponent {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(filePredicate, clone, validationOverride);\n\n\t\treturn clone as APIFileComponent;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/v2/MediaGallery.ts",
    "content": "import { type APIMediaGalleryItem, type APIMediaGalleryComponent, ComponentType } from 'discord-api-types/v10';\nimport { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';\nimport { resolveBuilder } from '../../util/resolveBuilder.js';\nimport { validate } from '../../util/validation.js';\nimport { ComponentBuilder } from '../Component.js';\nimport { mediaGalleryPredicate } from './Assertions.js';\nimport { MediaGalleryItemBuilder } from './MediaGalleryItem.js';\n\nexport interface MediaGalleryBuilderData extends Partial<Omit<APIMediaGalleryComponent, 'items'>> {\n\titems: MediaGalleryItemBuilder[];\n}\n\n/**\n * A builder that creates API-compatible JSON data for media galleries.\n */\nexport class MediaGalleryBuilder extends ComponentBuilder<APIMediaGalleryComponent> {\n\t/**\n\t * @internal\n\t */\n\tprotected readonly data: MediaGalleryBuilderData;\n\n\t/**\n\t * The items in this media gallery.\n\t */\n\tpublic get items(): readonly MediaGalleryItemBuilder[] {\n\t\treturn this.data.items;\n\t}\n\n\t/**\n\t * Creates a new media gallery.\n\t *\n\t * @param data - The API data to create this container with\n\t * @example\n\t * Creating a media gallery from an API data object:\n\t * ```ts\n\t * const mediaGallery = new MediaGalleryBuilder({\n\t * \titems: [\n\t * \t\t{\n\t * \t\t\tdescription: \"Some text here\",\n\t * \t\t\tmedia: {\n\t * \t\t\t\turl: 'https://cdn.discordapp.com/embed/avatars/2.png',\n\t * \t\t\t},\n\t * \t\t},\n\t * \t],\n\t * });\n\t * ```\n\t * @example\n\t * Creating a media gallery using setters and API data:\n\t * ```ts\n\t * const mediaGallery = new MediaGalleryBuilder({\n\t * \titems: [\n\t * \t\t{\n\t * \t\t\tdescription: \"alt text\",\n\t * \t\t\tmedia: {\n\t * \t\t\t\turl: 'https://cdn.discordapp.com/embed/avatars/5.png',\n\t * \t\t\t},\n\t * \t\t},\n\t * \t],\n\t * })\n\t * \t.addItems(item2, item3);\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APIMediaGalleryComponent> = {}) {\n\t\tsuper();\n\n\t\tconst { items = [], ...rest } = data;\n\n\t\tthis.data = {\n\t\t\t...structuredClone(rest),\n\t\t\titems: items.map((item) => new MediaGalleryItemBuilder(item)),\n\t\t\ttype: ComponentType.MediaGallery,\n\t\t};\n\t}\n\n\t/**\n\t * Adds a media gallery item to this media gallery.\n\t *\n\t * @param input - The items to add\n\t */\n\tpublic addItems(\n\t\t...input: RestOrArray<\n\t\t\tAPIMediaGalleryItem | MediaGalleryItemBuilder | ((builder: MediaGalleryItemBuilder) => MediaGalleryItemBuilder)\n\t\t>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((item) => resolveBuilder(item, MediaGalleryItemBuilder));\n\n\t\tthis.data.items.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes, replaces, or inserts media gallery items for this media gallery.\n\t *\n\t * @param index - The index to start removing, replacing or inserting items\n\t * @param deleteCount - The amount of items to remove\n\t * @param items - The items to insert\n\t */\n\tpublic spliceItems(\n\t\tindex: number,\n\t\tdeleteCount: number,\n\t\t...items: RestOrArray<\n\t\t\tAPIMediaGalleryItem | MediaGalleryItemBuilder | ((builder: MediaGalleryItemBuilder) => MediaGalleryItemBuilder)\n\t\t>\n\t) {\n\t\tconst normalized = normalizeArray(items);\n\t\tconst resolved = normalized.map((item) => resolveBuilder(item, MediaGalleryItemBuilder));\n\n\t\tthis.data.items.splice(index, deleteCount, ...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): APIMediaGalleryComponent {\n\t\tconst { items, ...rest } = this.data;\n\n\t\tconst data = {\n\t\t\t...structuredClone(rest),\n\t\t\titems: items.map((item) => item.toJSON(false)),\n\t\t};\n\n\t\tvalidate(mediaGalleryPredicate, data, validationOverride);\n\n\t\treturn data as APIMediaGalleryComponent;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/v2/MediaGalleryItem.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type { APIMediaGalleryItem } from 'discord-api-types/v10';\nimport { validate } from '../../util/validation.js';\nimport { mediaGalleryItemPredicate } from './Assertions.js';\n\nexport class MediaGalleryItemBuilder implements JSONEncodable<APIMediaGalleryItem> {\n\tprivate readonly data: Partial<APIMediaGalleryItem>;\n\n\t/**\n\t * Creates a new media gallery item.\n\t *\n\t * @param data - The API data to create this media gallery item with\n\t * @example\n\t * Creating a media gallery item from an API data object:\n\t * ```ts\n\t * const item = new MediaGalleryItemBuilder({\n\t * \tdescription: \"Some text here\",\n\t * \tmedia: {\n\t * \t\turl: 'https://cdn.discordapp.com/embed/avatars/2.png',\n\t * \t},\n\t * });\n\t * ```\n\t * @example\n\t * Creating a media gallery item using setters and API data:\n\t * ```ts\n\t * const item = new MediaGalleryItemBuilder({\n\t * \tmedia: {\n\t * \t\turl: 'https://cdn.discordapp.com/embed/avatars/5.png',\n\t * \t},\n\t * })\n\t * \t.setDescription(\"alt text\");\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APIMediaGalleryItem> = {}) {\n\t\tthis.data = structuredClone(data);\n\t}\n\n\t/**\n\t * Sets the source URL of this media gallery item.\n\t *\n\t * @param url - The URL to use\n\t */\n\tpublic setURL(url: string) {\n\t\tthis.data.media = { url };\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the description of this thumbnail.\n\t *\n\t * @param description - The description to use\n\t */\n\tpublic setDescription(description: string) {\n\t\tthis.data.description = description;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the description of this thumbnail.\n\t */\n\tpublic clearDescription() {\n\t\tthis.data.description = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the spoiler status of this thumbnail.\n\t *\n\t * @param spoiler - The spoiler status to use\n\t */\n\tpublic setSpoiler(spoiler = true) {\n\t\tthis.data.spoiler = spoiler;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Transforms this object to its JSON format\n\t */\n\tpublic toJSON(validationOverride?: boolean): APIMediaGalleryItem {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(mediaGalleryItemPredicate, clone, validationOverride);\n\n\t\treturn clone as APIMediaGalleryItem;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/v2/Section.ts",
    "content": "import type {\n\tAPITextDisplayComponent,\n\tAPISectionComponent,\n\tAPIButtonComponentWithCustomId,\n\tAPIThumbnailComponent,\n\tAPIButtonComponentWithSKUId,\n\tAPIButtonComponentWithURL,\n\tButtonStyle,\n} from 'discord-api-types/v10';\nimport { ComponentType } from 'discord-api-types/v10';\nimport { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';\nimport { resolveBuilder } from '../../util/resolveBuilder.js';\nimport { validate } from '../../util/validation.js';\nimport { ComponentBuilder } from '../Component.js';\nimport { resolveAccessoryComponent, type ButtonBuilder } from '../Components.js';\nimport {\n\tDangerButtonBuilder,\n\tPrimaryButtonBuilder,\n\tSecondaryButtonBuilder,\n\tSuccessButtonBuilder,\n} from '../button/CustomIdButton.js';\nimport { LinkButtonBuilder } from '../button/LinkButton.js';\nimport { PremiumButtonBuilder } from '../button/PremiumButton.js';\nimport { sectionPredicate } from './Assertions.js';\nimport { TextDisplayBuilder } from './TextDisplay.js';\nimport { ThumbnailBuilder } from './Thumbnail.js';\n\nexport type SectionBuilderAccessory = ButtonBuilder | ThumbnailBuilder;\n\nexport interface SectionBuilderData extends Partial<Omit<APISectionComponent, 'accessory' | 'components'>> {\n\taccessory?: SectionBuilderAccessory;\n\tcomponents: TextDisplayBuilder[];\n}\n\n/**\n * A builder that creates API-compatible JSON data for sections.\n */\nexport class SectionBuilder extends ComponentBuilder<APISectionComponent> {\n\t/**\n\t * @internal\n\t */\n\tprotected readonly data: SectionBuilderData;\n\n\t/**\n\t * The components within this section.\n\t */\n\tpublic get components(): readonly TextDisplayBuilder[] {\n\t\treturn this.data.components;\n\t}\n\n\t/**\n\t * Creates a new section.\n\t *\n\t * @param data - The API data to create this section with\n\t * @example\n\t * Creating a section from an API data object:\n\t * ```ts\n\t * const section = new SectionBuilder({\n\t * \tcomponents: [\n\t * \t\t{\n\t * \t\t\tcontent: \"Some text here\",\n\t * \t\t\ttype: ComponentType.TextDisplay,\n\t * \t\t},\n\t * \t],\n\t *  accessory: {\n\t *      media: {\n\t *          url: 'https://cdn.discordapp.com/embed/avatars/3.png',\n\t *      },\n\t *  }\n\t * });\n\t * ```\n\t * @example\n\t * Creating a section using setters and API data:\n\t * ```ts\n\t * const section = new SectionBuilder({\n\t * \tcomponents: [\n\t * \t\t{\n\t * \t\t\tcontent: \"# Heading\",\n\t * \t\t\ttype: ComponentType.TextDisplay,\n\t * \t\t},\n\t * \t],\n\t * })\n\t * \t.setPrimaryButtonAccessory(button);\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APISectionComponent> = {}) {\n\t\tsuper();\n\n\t\tconst { components = [], accessory, ...rest } = data;\n\n\t\tthis.data = {\n\t\t\t...structuredClone(rest),\n\t\t\taccessory: accessory && resolveAccessoryComponent(accessory),\n\t\t\tcomponents: components.map((component) => new TextDisplayBuilder(component)),\n\t\t\ttype: ComponentType.Section,\n\t\t};\n\t}\n\n\t/**\n\t * Adds text display components to this section.\n\t *\n\t * @param input - The text display components to add\n\t */\n\tpublic addTextDisplayComponents(\n\t\t...input: RestOrArray<\n\t\t\tAPITextDisplayComponent | TextDisplayBuilder | ((builder: TextDisplayBuilder) => TextDisplayBuilder)\n\t\t>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((component) => resolveBuilder(component, TextDisplayBuilder));\n\n\t\tthis.data.components.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a primary button component to be the accessory of this section.\n\t *\n\t * @param input - The button to set as the accessory\n\t */\n\tpublic setPrimaryButtonAccessory(\n\t\tinput:\n\t\t\t| PrimaryButtonBuilder\n\t\t\t| ((builder: PrimaryButtonBuilder) => PrimaryButtonBuilder)\n\t\t\t| (APIButtonComponentWithCustomId & { style: ButtonStyle.Primary }),\n\t): this {\n\t\tconst builder = resolveBuilder(input, PrimaryButtonBuilder);\n\n\t\tthis.data.accessory = builder;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a secondary button component to be the accessory of this section.\n\t *\n\t * @param input - The button to set as the accessory\n\t */\n\tpublic setSecondaryButtonAccessory(\n\t\tinput:\n\t\t\t| SecondaryButtonBuilder\n\t\t\t| ((builder: SecondaryButtonBuilder) => SecondaryButtonBuilder)\n\t\t\t| (APIButtonComponentWithCustomId & { style: ButtonStyle.Secondary }),\n\t): this {\n\t\tconst builder = resolveBuilder(input, SecondaryButtonBuilder);\n\n\t\tthis.data.accessory = builder;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a success button component to be the accessory of this section.\n\t *\n\t * @param input - The button to set as the accessory\n\t */\n\tpublic setSuccessButtonAccessory(\n\t\tinput:\n\t\t\t| SuccessButtonBuilder\n\t\t\t| ((builder: SuccessButtonBuilder) => SuccessButtonBuilder)\n\t\t\t| (APIButtonComponentWithCustomId & { style: ButtonStyle.Success }),\n\t): this {\n\t\tconst builder = resolveBuilder(input, SuccessButtonBuilder);\n\n\t\tthis.data.accessory = builder;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a danger button component to be the accessory of this section.\n\t *\n\t * @param input - The button to set as the accessory\n\t */\n\tpublic setDangerButtonAccessory(\n\t\tinput:\n\t\t\t| DangerButtonBuilder\n\t\t\t| ((builder: DangerButtonBuilder) => DangerButtonBuilder)\n\t\t\t| (APIButtonComponentWithCustomId & { style: ButtonStyle.Danger }),\n\t): this {\n\t\tconst builder = resolveBuilder(input, DangerButtonBuilder);\n\n\t\tthis.data.accessory = builder;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a SKU id button component to be the accessory of this section.\n\t *\n\t * @param input - The button to set as the accessory\n\t */\n\tpublic setPremiumButtonAccessory(\n\t\tinput:\n\t\t\t| APIButtonComponentWithSKUId\n\t\t\t| PremiumButtonBuilder\n\t\t\t| ((builder: PremiumButtonBuilder) => PremiumButtonBuilder),\n\t): this {\n\t\tconst builder = resolveBuilder(input, PremiumButtonBuilder);\n\n\t\tthis.data.accessory = builder;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a URL button component to be the accessory of this section.\n\t *\n\t * @param input - The button to set as the accessory\n\t */\n\tpublic setLinkButtonAccessory(\n\t\tinput: APIButtonComponentWithURL | LinkButtonBuilder | ((builder: LinkButtonBuilder) => LinkButtonBuilder),\n\t): this {\n\t\tconst builder = resolveBuilder(input, LinkButtonBuilder);\n\n\t\tthis.data.accessory = builder;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a thumbnail component to be the accessory of this section.\n\t *\n\t * @param input - The thumbnail to set as the accessory\n\t */\n\tpublic setThumbnailAccessory(\n\t\tinput: APIThumbnailComponent | ThumbnailBuilder | ((builder: ThumbnailBuilder) => ThumbnailBuilder),\n\t): this {\n\t\tconst builder = resolveBuilder(input, ThumbnailBuilder);\n\n\t\tthis.data.accessory = builder;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes, replaces, or inserts text display components for this section.\n\t *\n\t * @param index - The index to start removing, replacing or inserting text display components\n\t * @param deleteCount - The amount of text display components to remove\n\t * @param components - The text display components to insert\n\t */\n\tpublic spliceTextDisplayComponents(\n\t\tindex: number,\n\t\tdeleteCount: number,\n\t\t...components: RestOrArray<\n\t\t\tAPITextDisplayComponent | TextDisplayBuilder | ((builder: TextDisplayBuilder) => TextDisplayBuilder)\n\t\t>\n\t): this {\n\t\tconst normalized = normalizeArray(components);\n\t\tconst resolved = normalized.map((component) => resolveBuilder(component, TextDisplayBuilder));\n\n\t\tthis.data.components.splice(index, deleteCount, ...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): APISectionComponent {\n\t\tconst { components, accessory, ...rest } = this.data;\n\n\t\tconst data = {\n\t\t\t...structuredClone(rest),\n\t\t\tcomponents: components.map((component) => component.toJSON(false)),\n\t\t\taccessory: accessory?.toJSON(validationOverride),\n\t\t};\n\n\t\tvalidate(sectionPredicate, data, validationOverride);\n\n\t\treturn data as APISectionComponent;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/v2/Separator.ts",
    "content": "import type { SeparatorSpacingSize, APISeparatorComponent } from 'discord-api-types/v10';\nimport { ComponentType } from 'discord-api-types/v10';\nimport { validate } from '../../util/validation.js';\nimport { ComponentBuilder } from '../Component.js';\nimport { separatorPredicate } from './Assertions.js';\n\n/**\n * A builder that creates API-compatible JSON data for separators.\n */\nexport class SeparatorBuilder extends ComponentBuilder<APISeparatorComponent> {\n\t/**\n\t * @internal\n\t */\n\tprotected readonly data: Partial<APISeparatorComponent>;\n\n\t/**\n\t * Creates a new separator.\n\t *\n\t * @param data - The API data to create this separator with\n\t * @example\n\t * Creating a separator from an API data object:\n\t * ```ts\n\t * const separator = new SeparatorBuilder({\n\t * \tspacing: SeparatorSpacingSize.Small,\n\t *  divider: true,\n\t * });\n\t * ```\n\t * @example\n\t * Creating a separator using setters and API data:\n\t * ```ts\n\t * const separator = new SeparatorBuilder({\n\t * \tspacing: SeparatorSpacingSize.Large,\n\t * })\n\t * \t.setDivider(false);\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APISeparatorComponent> = {}) {\n\t\tsuper();\n\t\tthis.data = {\n\t\t\t...structuredClone(data),\n\t\t\ttype: ComponentType.Separator,\n\t\t};\n\t}\n\n\t/**\n\t * Sets whether this separator should show a divider line.\n\t *\n\t * @param divider - Whether to show a divider line\n\t */\n\tpublic setDivider(divider = true) {\n\t\tthis.data.divider = divider;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the spacing of this separator.\n\t *\n\t * @param spacing - The spacing to use\n\t */\n\tpublic setSpacing(spacing: SeparatorSpacingSize) {\n\t\tthis.data.spacing = spacing;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the spacing of this separator.\n\t */\n\tpublic clearSpacing() {\n\t\tthis.data.spacing = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): APISeparatorComponent {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(separatorPredicate, clone, validationOverride);\n\n\t\treturn clone as APISeparatorComponent;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/v2/TextDisplay.ts",
    "content": "import type { APITextDisplayComponent } from 'discord-api-types/v10';\nimport { ComponentType } from 'discord-api-types/v10';\nimport { validate } from '../../util/validation.js';\nimport { ComponentBuilder } from '../Component.js';\nimport { textDisplayPredicate } from './Assertions.js';\n\n/**\n * A builder that creates API-compatible JSON data for text displays.\n */\nexport class TextDisplayBuilder extends ComponentBuilder<APITextDisplayComponent> {\n\t/**\n\t * @internal\n\t */\n\tprotected readonly data: Partial<APITextDisplayComponent>;\n\n\t/**\n\t * Creates a new text display.\n\t *\n\t * @param data - The API data to create this text display with\n\t * @example\n\t * Creating a text display from an API data object:\n\t * ```ts\n\t * const textDisplay = new TextDisplayBuilder({\n\t * \tcontent: 'some text',\n\t * });\n\t * ```\n\t * @example\n\t * Creating a text display using setters and API data:\n\t * ```ts\n\t * const textDisplay = new TextDisplayBuilder({\n\t * \tcontent: 'old text',\n\t * })\n\t * \t.setContent('new text');\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APITextDisplayComponent> = {}) {\n\t\tsuper();\n\t\tthis.data = {\n\t\t\t...structuredClone(data),\n\t\t\ttype: ComponentType.TextDisplay,\n\t\t};\n\t}\n\n\t/**\n\t * Sets the text of this text display.\n\t *\n\t * @param content - The text to use\n\t */\n\tpublic setContent(content: string) {\n\t\tthis.data.content = content;\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc ComponentBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): APITextDisplayComponent {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(textDisplayPredicate, clone, validationOverride);\n\n\t\treturn clone as APITextDisplayComponent;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/components/v2/Thumbnail.ts",
    "content": "import type { APIThumbnailComponent } from 'discord-api-types/v10';\nimport { ComponentType } from 'discord-api-types/v10';\nimport { validate } from '../../util/validation.js';\nimport { ComponentBuilder } from '../Component.js';\nimport { thumbnailPredicate } from './Assertions.js';\n\n/**\n * A builder that creates API-compatible JSON data for thumbnails.\n */\nexport class ThumbnailBuilder extends ComponentBuilder<APIThumbnailComponent> {\n\t/**\n\t * @internal\n\t */\n\tprotected readonly data: Partial<APIThumbnailComponent>;\n\n\t/**\n\t * Creates a new thumbnail.\n\t *\n\t * @param data - The API data to create this thumbnail with\n\t * @example\n\t * Creating a thumbnail from an API data object:\n\t * ```ts\n\t * const thumbnail = new ThumbnailBuilder({\n\t * \tdescription: 'some text',\n\t *  media: {\n\t *      url: 'https://cdn.discordapp.com/embed/avatars/4.png',\n\t *  },\n\t * });\n\t * ```\n\t * @example\n\t * Creating a thumbnail using setters and API data:\n\t * ```ts\n\t * const thumbnail = new ThumbnailBuilder({\n\t * \tmedia: {\n\t *      url: 'attachment://image.png',\n\t *  },\n\t * })\n\t * \t.setDescription('alt text');\n\t * ```\n\t */\n\tpublic constructor(data: Partial<APIThumbnailComponent> = {}) {\n\t\tsuper();\n\n\t\tconst { media, ...rest } = data;\n\n\t\tthis.data = {\n\t\t\t...structuredClone(rest),\n\t\t\tmedia: media && { url: media.url },\n\t\t\ttype: ComponentType.Thumbnail,\n\t\t};\n\t}\n\n\t/**\n\t * Sets the description of this thumbnail.\n\t *\n\t * @param description - The description to use\n\t */\n\tpublic setDescription(description: string) {\n\t\tthis.data.description = description;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the description of this thumbnail.\n\t */\n\tpublic clearDescription() {\n\t\tthis.data.description = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the spoiler status of this thumbnail.\n\t *\n\t * @param spoiler - The spoiler status to use\n\t */\n\tpublic setSpoiler(spoiler = true) {\n\t\tthis.data.spoiler = spoiler;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the media URL of this thumbnail.\n\t *\n\t * @param url - The URL to use\n\t */\n\tpublic setURL(url: string) {\n\t\tthis.data.media = { url };\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritdoc ComponentBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): APIThumbnailComponent {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(thumbnailPredicate, clone, validationOverride);\n\n\t\treturn clone as APIThumbnailComponent;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/index.ts",
    "content": "export * from './components/button/mixins/EmojiOrLabelButtonMixin.js';\nexport * from './components/button/Button.js';\nexport * from './components/button/CustomIdButton.js';\nexport * from './components/button/LinkButton.js';\nexport * from './components/button/PremiumButton.js';\n\nexport * from './components/fileUpload/FileUpload.js';\nexport * from './components/fileUpload/Assertions.js';\n\nexport * from './components/label/Label.js';\nexport * from './components/label/Assertions.js';\n\nexport * from './components/selectMenu/BaseSelectMenu.js';\nexport * from './components/selectMenu/ChannelSelectMenu.js';\nexport * from './components/selectMenu/MentionableSelectMenu.js';\nexport * from './components/selectMenu/RoleSelectMenu.js';\nexport * from './components/selectMenu/StringSelectMenu.js';\nexport * from './components/selectMenu/StringSelectMenuOption.js';\nexport * from './components/selectMenu/UserSelectMenu.js';\n\nexport * from './components/textInput/TextInput.js';\nexport * from './components/textInput/Assertions.js';\n\nexport * from './components/ActionRow.js';\nexport * from './components/Assertions.js';\nexport * from './components/Component.js';\nexport * from './components/Components.js';\n\nexport * from './components/v2/Assertions.js';\nexport * from './components/v2/Container.js';\nexport * from './components/v2/File.js';\nexport * from './components/v2/MediaGallery.js';\nexport * from './components/v2/MediaGalleryItem.js';\nexport * from './components/v2/Section.js';\nexport * from './components/v2/Separator.js';\nexport * from './components/v2/TextDisplay.js';\nexport * from './components/v2/Thumbnail.js';\n\nexport * from './interactions/commands/chatInput/mixins/ApplicationCommandNumericOptionMinMaxValueMixin.js';\nexport * from './interactions/commands/chatInput/mixins/ApplicationCommandOptionChannelTypesMixin.js';\nexport * from './interactions/commands/chatInput/mixins/ApplicationCommandOptionWithAutocompleteMixin.js';\nexport * from './interactions/commands/chatInput/mixins/ApplicationCommandOptionWithChoicesMixin.js';\nexport * from './interactions/commands/chatInput/mixins/SharedChatInputCommandOptions.js';\nexport * from './interactions/commands/chatInput/mixins/SharedSubcommands.js';\n\nexport * from './interactions/commands/chatInput/options/ApplicationCommandOptionBase.js';\nexport * from './interactions/commands/chatInput/options/boolean.js';\nexport * from './interactions/commands/chatInput/options/channel.js';\nexport * from './interactions/commands/chatInput/options/integer.js';\nexport * from './interactions/commands/chatInput/options/mentionable.js';\nexport * from './interactions/commands/chatInput/options/number.js';\nexport * from './interactions/commands/chatInput/options/role.js';\nexport * from './interactions/commands/chatInput/options/attachment.js';\nexport * from './interactions/commands/chatInput/options/string.js';\nexport * from './interactions/commands/chatInput/options/user.js';\n\nexport * from './interactions/commands/chatInput/Assertions.js';\nexport * from './interactions/commands/chatInput/ChatInputCommand.js';\nexport * from './interactions/commands/chatInput/ChatInputCommandSubcommands.js';\n\nexport * from './interactions/commands/contextMenu/Assertions.js';\nexport * from './interactions/commands/contextMenu/ContextMenuCommand.js';\nexport * from './interactions/commands/contextMenu/MessageCommand.js';\nexport * from './interactions/commands/contextMenu/UserCommand.js';\n\nexport * from './interactions/commands/Command.js';\nexport * from './interactions/commands/SharedName.js';\nexport * from './interactions/commands/SharedNameAndDescription.js';\n\nexport * from './interactions/modals/Assertions.js';\nexport * from './interactions/modals/Modal.js';\n\nexport * from './messages/embed/Assertions.js';\nexport * from './messages/embed/Embed.js';\nexport * from './messages/embed/EmbedAuthor.js';\nexport * from './messages/embed/EmbedField.js';\nexport * from './messages/embed/EmbedFooter.js';\n\nexport * from './messages/poll/Assertions.js';\nexport * from './messages/poll/Poll.js';\nexport * from './messages/poll/PollAnswer.js';\nexport * from './messages/poll/PollAnswerMedia.js';\nexport * from './messages/poll/PollMedia.js';\nexport * from './messages/poll/PollQuestion.js';\n\nexport * from './messages/AllowedMentions.js';\nexport * from './messages/Assertions.js';\nexport * from './messages/Attachment.js';\nexport * from './messages/Message.js';\nexport * from './messages/MessageReference.js';\n\nexport * from './util/normalizeArray.js';\nexport * from './util/resolveBuilder.js';\nexport { disableValidators, enableValidators, isValidationEnabled } from './util/validation.js';\nexport * from './util/ValidationError.js';\n\nexport * from './Assertions.js';\n\n// We expose this type in our public API. We shouldn't assume every user of builders is also using REST\nexport type { RawFile } from '@discordjs/util';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/builders#readme | @discordjs/builders} version\n * that you are currently using.\n *\n * @privateRemarks This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild.\n */\nexport const version = '[VI]{{inject}}[/VI]' as string;\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/Command.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type {\n\tApplicationIntegrationType,\n\tInteractionContextType,\n\tPermissions,\n\tRESTPostAPIApplicationCommandsJSONBody,\n} from 'discord-api-types/v10';\nimport type { RestOrArray } from '../../util/normalizeArray.js';\nimport { normalizeArray } from '../../util/normalizeArray.js';\n\nexport interface CommandData extends Partial<\n\tPick<RESTPostAPIApplicationCommandsJSONBody, 'contexts' | 'default_member_permissions' | 'integration_types' | 'nsfw'>\n> {}\n\n/**\n * The base class for all command builders.\n */\nexport abstract class CommandBuilder<\n\tCommand extends RESTPostAPIApplicationCommandsJSONBody,\n> implements JSONEncodable<Command> {\n\t/**\n\t * The API data associated with this command.\n\t *\n\t * @internal\n\t */\n\tdeclare protected readonly data: CommandData;\n\n\t/**\n\t * Sets the contexts of this command.\n\t *\n\t * @param contexts - The contexts\n\t */\n\tpublic setContexts(...contexts: RestOrArray<InteractionContextType>) {\n\t\tthis.data.contexts = normalizeArray(contexts);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the integration types of this command.\n\t *\n\t * @param integrationTypes - The integration types\n\t */\n\tpublic setIntegrationTypes(...integrationTypes: RestOrArray<ApplicationIntegrationType>) {\n\t\tthis.data.integration_types = normalizeArray(integrationTypes);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the default permissions a member should have in order to run the command.\n\t *\n\t * @remarks\n\t * You can set this to `'0'` to disable the command by default.\n\t * @param permissions - The permissions bit field to set\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions}\n\t */\n\tpublic setDefaultMemberPermissions(permissions: Permissions | bigint | number) {\n\t\tthis.data.default_member_permissions = typeof permissions === 'string' ? permissions : permissions.toString();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the default permissions a member should have in order to run the command.\n\t */\n\tpublic clearDefaultMemberPermissions() {\n\t\tthis.data.default_member_permissions = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets whether this command is NSFW.\n\t *\n\t * @param nsfw - Whether this command is NSFW\n\t */\n\tpublic setNSFW(nsfw = true) {\n\t\tthis.data.nsfw = nsfw;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic abstract toJSON(validationOverride?: boolean): Command;\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/SharedName.ts",
    "content": "import type { Locale, RESTPostAPIApplicationCommandsJSONBody } from 'discord-api-types/v10';\n\nexport interface SharedNameData extends Partial<\n\tPick<RESTPostAPIApplicationCommandsJSONBody, 'name_localizations' | 'name'>\n> {}\n\n/**\n * This mixin holds name and description symbols for chat input commands.\n */\nexport class SharedName {\n\t/**\n\t * @internal\n\t */\n\tprotected readonly data: SharedNameData = {};\n\n\t/**\n\t * Sets the name of this command.\n\t *\n\t * @param name - The name to use\n\t */\n\tpublic setName(name: string): this {\n\t\tthis.data.name = name;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a name localization for this command.\n\t *\n\t * @param locale - The locale to set\n\t * @param localizedName - The localized name for the given `locale`\n\t */\n\tpublic setNameLocalization(locale: Locale, localizedName: string) {\n\t\tthis.data.name_localizations ??= {};\n\t\tthis.data.name_localizations[locale] = localizedName;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears a name localization for this command.\n\t *\n\t * @param locale - The locale to clear\n\t */\n\tpublic clearNameLocalization(locale: Locale) {\n\t\tthis.data.name_localizations ??= {};\n\t\tthis.data.name_localizations[locale] = undefined;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the name localizations for this command.\n\t *\n\t * @param localizedNames - The object of localized names to set\n\t */\n\tpublic setNameLocalizations(localizedNames: Partial<Record<Locale, string>>) {\n\t\tthis.data.name_localizations = structuredClone(localizedNames);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears all name localizations for this command.\n\t */\n\tpublic clearNameLocalizations() {\n\t\tthis.data.name_localizations = undefined;\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/SharedNameAndDescription.ts",
    "content": "import type { APIApplicationCommand, Locale } from 'discord-api-types/v10';\nimport type { SharedNameData } from './SharedName.js';\nimport { SharedName } from './SharedName.js';\n\nexport interface SharedNameAndDescriptionData\n\textends SharedNameData, Partial<Pick<APIApplicationCommand, 'description_localizations' | 'description'>> {}\n\n/**\n * This mixin holds name and description symbols for chat input commands.\n */\nexport class SharedNameAndDescription extends SharedName {\n\t/**\n\t * @internal\n\t */\n\tprotected override readonly data: SharedNameAndDescriptionData = {};\n\n\t/**\n\t * Sets the description of this command.\n\t *\n\t * @param description - The description to use\n\t */\n\tpublic setDescription(description: string) {\n\t\tthis.data.description = description;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a description localization for this command.\n\t *\n\t * @param locale - The locale to set\n\t * @param localizedDescription - The localized description for the given `locale`\n\t */\n\tpublic setDescriptionLocalization(locale: Locale, localizedDescription: string) {\n\t\tthis.data.description_localizations ??= {};\n\t\tthis.data.description_localizations[locale] = localizedDescription;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears a description localization for this command.\n\t *\n\t * @param locale - The locale to clear\n\t */\n\tpublic clearDescriptionLocalization(locale: Locale) {\n\t\tthis.data.description_localizations ??= {};\n\t\tthis.data.description_localizations[locale] = undefined;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the description localizations for this command.\n\t *\n\t * @param localizedDescriptions - The object of localized descriptions to set\n\t */\n\tpublic setDescriptionLocalizations(localizedDescriptions: Partial<Record<Locale, string>>) {\n\t\tthis.data.description_localizations = structuredClone(localizedDescriptions);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears all description localizations for this command.\n\t */\n\tpublic clearDescriptionLocalizations() {\n\t\tthis.data.description_localizations = undefined;\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/Assertions.ts",
    "content": "import {\n\tApplicationIntegrationType,\n\tInteractionContextType,\n\tApplicationCommandOptionType,\n\tApplicationCommandType,\n} from 'discord-api-types/v10';\nimport { z } from 'zod';\nimport { localeMapPredicate, memberPermissionsPredicate } from '../../../Assertions.js';\nimport { ApplicationCommandOptionAllowedChannelTypes } from './mixins/ApplicationCommandOptionChannelTypesMixin.js';\n\nconst namePredicate = z\n\t.string()\n\t.min(1)\n\t.max(32)\n\t.regex(/^[\\p{Ll}\\p{Lm}\\p{Lo}\\p{N}\\p{sc=Devanagari}\\p{sc=Thai}_-]+$/u);\n\nconst descriptionPredicate = z.string().min(1).max(100);\n\nconst sharedNameAndDescriptionPredicate = z.object({\n\tname: namePredicate,\n\tname_localizations: localeMapPredicate.optional(),\n\tdescription: descriptionPredicate,\n\tdescription_localizations: localeMapPredicate.optional(),\n});\n\nconst numericMixinNumberOptionPredicate = z.object({\n\tmax_value: z.float32().optional(),\n\tmin_value: z.float32().optional(),\n});\n\nconst numericMixinIntegerOptionPredicate = z.object({\n\tmax_value: z.int().optional(),\n\tmin_value: z.int().optional(),\n});\n\nconst channelMixinOptionPredicate = z.object({\n\tchannel_types: z.literal(ApplicationCommandOptionAllowedChannelTypes).array().optional(),\n});\n\nconst autocompleteMixinOptionPredicate = z.object({\n\tautocomplete: z.literal(true),\n\tchoices: z.union([z.never(), z.never().array(), z.undefined()]),\n});\n\nconst choiceValueStringPredicate = z.string().min(1).max(100);\nconst choiceValueNumberPredicate = z.number();\nconst choiceBasePredicate = z.object({\n\tname: choiceValueStringPredicate,\n\tname_localizations: localeMapPredicate.optional(),\n});\nconst choiceStringPredicate = z.object({\n\t...choiceBasePredicate.shape,\n\tvalue: choiceValueStringPredicate,\n});\nconst choiceNumberPredicate = z.object({\n\t...choiceBasePredicate.shape,\n\tvalue: choiceValueNumberPredicate,\n});\n\nconst choiceBaseMixinPredicate = z.object({\n\tautocomplete: z.literal(false).optional(),\n});\nconst choiceStringMixinPredicate = z.object({\n\t...choiceBaseMixinPredicate.shape,\n\tchoices: choiceStringPredicate.array().max(25).optional(),\n});\nconst choiceNumberMixinPredicate = z.object({\n\t...choiceBaseMixinPredicate.shape,\n\tchoices: choiceNumberPredicate.array().max(25).optional(),\n});\n\nexport const baseBasicOptionPredicate = z.object({\n\t...sharedNameAndDescriptionPredicate.shape,\n\trequired: z.boolean().optional(),\n});\n\nexport const attachmentOptionPredicate = z.object({\n\t...baseBasicOptionPredicate.shape,\n\ttype: z.literal(ApplicationCommandOptionType.Attachment),\n});\n\nexport const booleanOptionPredicate = z.object({\n\t...baseBasicOptionPredicate.shape,\n\ttype: z.literal(ApplicationCommandOptionType.Boolean),\n});\n\nexport const mentionableOptionPredicate = z.object({\n\t...baseBasicOptionPredicate.shape,\n\ttype: z.literal(ApplicationCommandOptionType.Mentionable),\n});\n\nexport const roleOptionPredicate = z.object({\n\t...baseBasicOptionPredicate.shape,\n\ttype: z.literal(ApplicationCommandOptionType.Role),\n});\n\nexport const userOptionPredicate = z.object({\n\t...baseBasicOptionPredicate.shape,\n\ttype: z.literal(ApplicationCommandOptionType.User),\n});\n\nconst autocompleteOrStringChoicesMixinOptionPredicate = z.discriminatedUnion('autocomplete', [\n\tautocompleteMixinOptionPredicate,\n\tchoiceStringMixinPredicate,\n]);\n\nconst autocompleteOrNumberChoicesMixinOptionPredicate = z.discriminatedUnion('autocomplete', [\n\tautocompleteMixinOptionPredicate,\n\tchoiceNumberMixinPredicate,\n]);\n\nexport const channelOptionPredicate = z.object({\n\t...baseBasicOptionPredicate.shape,\n\t...channelMixinOptionPredicate.shape,\n\ttype: z.literal(ApplicationCommandOptionType.Channel),\n});\n\nexport const integerOptionPredicate = z\n\t.object({\n\t\t...baseBasicOptionPredicate.shape,\n\t\t...numericMixinIntegerOptionPredicate.shape,\n\t\ttype: z.literal(ApplicationCommandOptionType.Integer),\n\t})\n\t.and(autocompleteOrNumberChoicesMixinOptionPredicate);\n\nexport const numberOptionPredicate = z\n\t.object({\n\t\t...baseBasicOptionPredicate.shape,\n\t\t...numericMixinNumberOptionPredicate.shape,\n\t\ttype: z.literal(ApplicationCommandOptionType.Number),\n\t})\n\t.and(autocompleteOrNumberChoicesMixinOptionPredicate);\n\nexport const stringOptionPredicate = z\n\t.object({\n\t\t...baseBasicOptionPredicate.shape,\n\t\tmax_length: z.number().min(1).max(6_000).optional(),\n\t\tmin_length: z.number().min(0).max(6_000).optional(),\n\t\ttype: z.literal(ApplicationCommandOptionType.String),\n\t})\n\t.and(autocompleteOrStringChoicesMixinOptionPredicate);\n\nconst basicOptionPredicates = [\n\tattachmentOptionPredicate,\n\tbooleanOptionPredicate,\n\tchannelOptionPredicate,\n\tintegerOptionPredicate,\n\tmentionableOptionPredicate,\n\tnumberOptionPredicate,\n\troleOptionPredicate,\n\tstringOptionPredicate,\n\tuserOptionPredicate,\n];\n\nexport const chatInputCommandSubcommandPredicate = z.object({\n\t...sharedNameAndDescriptionPredicate.shape,\n\ttype: z.literal(ApplicationCommandOptionType.Subcommand),\n\toptions: z.array(z.union(basicOptionPredicates)).max(25).optional(),\n});\n\nexport const chatInputCommandSubcommandGroupPredicate = z.object({\n\t...sharedNameAndDescriptionPredicate.shape,\n\ttype: z.literal(ApplicationCommandOptionType.SubcommandGroup),\n\toptions: z.array(chatInputCommandSubcommandPredicate).min(1).max(25),\n});\n\nexport const chatInputCommandPredicate = z.object({\n\t...sharedNameAndDescriptionPredicate.shape,\n\tcontexts: z.array(z.enum(InteractionContextType)).optional(),\n\tdefault_member_permissions: memberPermissionsPredicate.optional(),\n\tintegration_types: z.array(z.enum(ApplicationIntegrationType)).optional(),\n\tnsfw: z.boolean().optional(),\n\toptions: z\n\t\t.union([\n\t\t\tz.array(z.union(basicOptionPredicates)).max(25),\n\t\t\tz.array(z.union([chatInputCommandSubcommandPredicate, chatInputCommandSubcommandGroupPredicate])).max(25),\n\t\t])\n\t\t.optional(),\n\ttype: z.literal(ApplicationCommandType.ChatInput).optional(),\n});\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/ChatInputCommand.ts",
    "content": "import { ApplicationCommandType, type RESTPostAPIChatInputApplicationCommandsJSONBody } from 'discord-api-types/v10';\nimport { Mixin } from 'ts-mixer';\nimport { validate } from '../../../util/validation.js';\nimport { CommandBuilder } from '../Command.js';\nimport { SharedNameAndDescription } from '../SharedNameAndDescription.js';\nimport { chatInputCommandPredicate } from './Assertions.js';\nimport { SharedChatInputCommandOptions } from './mixins/SharedChatInputCommandOptions.js';\nimport { SharedChatInputCommandSubcommands } from './mixins/SharedSubcommands.js';\n\n/**\n * A builder that creates API-compatible JSON data for chat input commands.\n *\n * @mixes {@link CommandBuilder}\\<{@link discord-api-types/v10#(RESTPostAPIChatInputApplicationCommandsJSONBody:interface)}\\>\n * @mixes {@link SharedChatInputCommandOptions}\n * @mixes {@link SharedNameAndDescription}\n * @mixes {@link SharedChatInputCommandSubcommands}\n */\nexport class ChatInputCommandBuilder extends Mixin(\n\tCommandBuilder<RESTPostAPIChatInputApplicationCommandsJSONBody>,\n\tSharedChatInputCommandOptions,\n\tSharedNameAndDescription,\n\tSharedChatInputCommandSubcommands,\n) {\n\t/**\n\t * {@inheritDoc CommandBuilder.toJSON}\n\t */\n\tpublic toJSON(validationOverride?: boolean): RESTPostAPIChatInputApplicationCommandsJSONBody {\n\t\tconst { options, ...rest } = this.data;\n\n\t\tconst data: RESTPostAPIChatInputApplicationCommandsJSONBody = {\n\t\t\t...structuredClone(rest as Omit<RESTPostAPIChatInputApplicationCommandsJSONBody, 'options'>),\n\t\t\ttype: ApplicationCommandType.ChatInput,\n\t\t\toptions: options?.map((option) => option.toJSON(false)),\n\t\t};\n\n\t\tvalidate(chatInputCommandPredicate, data, validationOverride);\n\n\t\treturn data;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/ChatInputCommandSubcommands.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type {\n\tAPIApplicationCommandSubcommandOption,\n\tAPIApplicationCommandSubcommandGroupOption,\n} from 'discord-api-types/v10';\nimport { ApplicationCommandOptionType } from 'discord-api-types/v10';\nimport { Mixin } from 'ts-mixer';\nimport { normalizeArray, type RestOrArray } from '../../../util/normalizeArray.js';\nimport { resolveBuilder } from '../../../util/resolveBuilder.js';\nimport { validate } from '../../../util/validation.js';\nimport type { SharedNameAndDescriptionData } from '../SharedNameAndDescription.js';\nimport { SharedNameAndDescription } from '../SharedNameAndDescription.js';\nimport { chatInputCommandSubcommandGroupPredicate, chatInputCommandSubcommandPredicate } from './Assertions.js';\nimport { SharedChatInputCommandOptions } from './mixins/SharedChatInputCommandOptions.js';\n\nexport interface ChatInputCommandSubcommandGroupData {\n\toptions?: ChatInputCommandSubcommandBuilder[];\n}\n\n/**\n * Represents a folder for subcommands.\n *\n * @see {@link https://discord.com/developers/docs/interactions/application-commands#subcommands-and-subcommand-groups}\n */\nexport class ChatInputCommandSubcommandGroupBuilder\n\textends SharedNameAndDescription\n\timplements JSONEncodable<APIApplicationCommandSubcommandGroupOption>\n{\n\t/**\n\t * The API data associated with this subcommand group.\n\t *\n\t * @internal\n\t */\n\tdeclare protected readonly data: ChatInputCommandSubcommandGroupData & SharedNameAndDescriptionData;\n\n\t/**\n\t * The options within this subcommand group.\n\t */\n\tpublic get options(): readonly ChatInputCommandSubcommandBuilder[] {\n\t\treturn (this.data.options ??= []);\n\t}\n\n\t/**\n\t * Adds a new subcommand to this group.\n\t *\n\t * @param input - A function that returns a subcommand builder or an already built builder\n\t */\n\tpublic addSubcommands(\n\t\t...input: RestOrArray<\n\t\t\t| ChatInputCommandSubcommandBuilder\n\t\t\t| ((subcommandGroup: ChatInputCommandSubcommandBuilder) => ChatInputCommandSubcommandBuilder)\n\t\t>\n\t) {\n\t\tconst normalized = normalizeArray(input);\n\t\t// eslint-disable-next-line @typescript-eslint/no-use-before-define\n\t\tconst result = normalized.map((builder) => resolveBuilder(builder, ChatInputCommandSubcommandBuilder));\n\n\t\tthis.data.options ??= [];\n\t\tthis.data.options.push(...result);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic toJSON(validationOverride?: boolean): APIApplicationCommandSubcommandGroupOption {\n\t\tconst { options, ...rest } = this.data;\n\n\t\tconst data = {\n\t\t\t...(structuredClone(rest) as Omit<APIApplicationCommandSubcommandGroupOption, 'type'>),\n\t\t\ttype: ApplicationCommandOptionType.SubcommandGroup as const,\n\t\t\toptions: options?.map((option) => option.toJSON(false)) ?? [],\n\t\t};\n\n\t\tvalidate(chatInputCommandSubcommandGroupPredicate, data, validationOverride);\n\n\t\treturn data;\n\t}\n}\n\n/**\n * A builder that creates API-compatible JSON data for chat input command subcommands.\n *\n * @mixes {@link SharedNameAndDescription}\n * @mixes {@link SharedChatInputCommandOptions}\n * @see {@link https://discord.com/developers/docs/interactions/application-commands#subcommands-and-subcommand-groups}\n */\nexport class ChatInputCommandSubcommandBuilder\n\textends Mixin(SharedNameAndDescription, SharedChatInputCommandOptions)\n\timplements JSONEncodable<APIApplicationCommandSubcommandOption>\n{\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic toJSON(validationOverride?: boolean): APIApplicationCommandSubcommandOption {\n\t\tconst { options, ...rest } = this.data;\n\n\t\tconst data = {\n\t\t\t...(structuredClone(rest) as Omit<APIApplicationCommandSubcommandOption, 'type'>),\n\t\t\ttype: ApplicationCommandOptionType.Subcommand as const,\n\t\t\toptions: options?.map((option) => option.toJSON(false)) ?? [],\n\t\t};\n\n\t\tvalidate(chatInputCommandSubcommandPredicate, data, validationOverride);\n\n\t\treturn data;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/mixins/ApplicationCommandNumericOptionMinMaxValueMixin.ts",
    "content": "import type { APIApplicationCommandIntegerOption } from 'discord-api-types/v10';\n\nexport interface ApplicationCommandNumericOptionMinMaxValueData extends Pick<\n\tAPIApplicationCommandIntegerOption,\n\t'max_value' | 'min_value'\n> {}\n\n/**\n * This mixin holds minimum and maximum symbols used for options.\n */\nexport abstract class ApplicationCommandNumericOptionMinMaxValueMixin {\n\t/**\n\t * @internal\n\t */\n\tdeclare protected readonly data: ApplicationCommandNumericOptionMinMaxValueData;\n\n\t/**\n\t * Sets the maximum number value of this option.\n\t *\n\t * @param max - The maximum value this option can be\n\t */\n\tpublic setMaxValue(max: number): this {\n\t\tthis.data.max_value = max;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes the maximum number value of this option.\n\t */\n\tpublic clearMaxValue(): this {\n\t\tthis.data.max_value = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the minimum number value of this option.\n\t *\n\t * @param min - The minimum value this option can be\n\t */\n\tpublic setMinValue(min: number): this {\n\t\tthis.data.min_value = min;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes the minimum number value of this option.\n\t */\n\tpublic clearMinValue(): this {\n\t\tthis.data.min_value = undefined;\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/mixins/ApplicationCommandOptionChannelTypesMixin.ts",
    "content": "import {\n\ttype ApplicationCommandOptionAllowedChannelType,\n\ttype APIApplicationCommandChannelOption,\n\tChannelType,\n} from 'discord-api-types/v10';\nimport { normalizeArray, type RestOrArray } from '../../../../util/normalizeArray';\n\nexport const ApplicationCommandOptionAllowedChannelTypes = [\n\tChannelType.GuildText,\n\tChannelType.GuildVoice,\n\tChannelType.GuildCategory,\n\tChannelType.GuildAnnouncement,\n\tChannelType.AnnouncementThread,\n\tChannelType.PublicThread,\n\tChannelType.PrivateThread,\n\tChannelType.GuildStageVoice,\n\tChannelType.GuildForum,\n\tChannelType.GuildMedia,\n] as const satisfies readonly ApplicationCommandOptionAllowedChannelType[];\n\nexport interface ApplicationCommandOptionChannelTypesData extends Pick<\n\tAPIApplicationCommandChannelOption,\n\t'channel_types'\n> {}\n\n/**\n * This mixin holds channel type symbols used for options.\n */\nexport class ApplicationCommandOptionChannelTypesMixin {\n\t/**\n\t * @internal\n\t */\n\tdeclare protected readonly data: ApplicationCommandOptionChannelTypesData;\n\n\t/**\n\t * Adds channel types to this option.\n\t *\n\t * @param channelTypes - The channel types\n\t */\n\tpublic addChannelTypes(...channelTypes: RestOrArray<ApplicationCommandOptionAllowedChannelType>) {\n\t\tthis.data.channel_types ??= [];\n\t\tthis.data.channel_types.push(...normalizeArray(channelTypes));\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the channel types for this option.\n\t *\n\t * @param channelTypes - The channel types\n\t */\n\tpublic setChannelTypes(...channelTypes: RestOrArray<ApplicationCommandOptionAllowedChannelType>) {\n\t\tthis.data.channel_types = normalizeArray(channelTypes);\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/mixins/ApplicationCommandOptionWithAutocompleteMixin.ts",
    "content": "import type {\n\tAPIApplicationCommandIntegerOption,\n\tAPIApplicationCommandNumberOption,\n\tAPIApplicationCommandStringOption,\n} from 'discord-api-types/v10';\n\nexport type AutocompletableOptions =\n\t| APIApplicationCommandIntegerOption\n\t| APIApplicationCommandNumberOption\n\t| APIApplicationCommandStringOption;\n\nexport interface ApplicationCommandOptionWithAutocompleteData extends Pick<AutocompletableOptions, 'autocomplete'> {}\n\n/**\n * This mixin holds choices and autocomplete symbols used for options.\n */\nexport class ApplicationCommandOptionWithAutocompleteMixin {\n\t/**\n\t * @internal\n\t */\n\tdeclare protected readonly data: ApplicationCommandOptionWithAutocompleteData;\n\n\t/**\n\t * Whether this option uses autocomplete.\n\t *\n\t * @param autocomplete - Whether this option should use autocomplete\n\t */\n\tpublic setAutocomplete(autocomplete = true): this {\n\t\tthis.data.autocomplete = autocomplete;\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/mixins/ApplicationCommandOptionWithChoicesMixin.ts",
    "content": "import type { APIApplicationCommandOptionChoice } from 'discord-api-types/v10';\nimport { normalizeArray, type RestOrArray } from '../../../../util/normalizeArray.js';\n\n// Unlike other places, we're not `Pick`ing from discord-api-types. The union includes `[]` and it breaks everything.\nexport interface ApplicationCommandOptionWithChoicesData {\n\tchoices?: APIApplicationCommandOptionChoice<number | string>[];\n}\n\n/**\n * This mixin holds choices and autocomplete symbols used for options.\n *\n * @typeParam ChoiceType - The type of the choices within this option\n */\nexport class ApplicationCommandOptionWithChoicesMixin<ChoiceType extends number | string> {\n\t/**\n\t * @internal\n\t */\n\tdeclare protected readonly data: ApplicationCommandOptionWithChoicesData;\n\n\t/**\n\t * Adds multiple choices to this option.\n\t *\n\t * @param choices - The choices to add\n\t */\n\tpublic addChoices(...choices: RestOrArray<APIApplicationCommandOptionChoice<ChoiceType>>): this {\n\t\tconst normalizedChoices = normalizeArray(choices);\n\n\t\tthis.data.choices ??= [];\n\t\tthis.data.choices.push(...normalizedChoices);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets multiple choices for this option.\n\t *\n\t * @param choices - The choices to set\n\t */\n\tpublic setChoices(...choices: RestOrArray<APIApplicationCommandOptionChoice<ChoiceType>>): this {\n\t\tthis.data.choices = normalizeArray(choices);\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/mixins/SharedChatInputCommandOptions.ts",
    "content": "import { normalizeArray, type RestOrArray } from '../../../../util/normalizeArray.js';\nimport { resolveBuilder } from '../../../../util/resolveBuilder.js';\nimport type { ApplicationCommandOptionBase } from '../options/ApplicationCommandOptionBase.js';\nimport { ChatInputCommandAttachmentOption } from '../options/attachment.js';\nimport { ChatInputCommandBooleanOption } from '../options/boolean.js';\nimport { ChatInputCommandChannelOption } from '../options/channel.js';\nimport { ChatInputCommandIntegerOption } from '../options/integer.js';\nimport { ChatInputCommandMentionableOption } from '../options/mentionable.js';\nimport { ChatInputCommandNumberOption } from '../options/number.js';\nimport { ChatInputCommandRoleOption } from '../options/role.js';\nimport { ChatInputCommandStringOption } from '../options/string.js';\nimport { ChatInputCommandUserOption } from '../options/user.js';\n\nexport interface SharedChatInputCommandOptionsData {\n\toptions?: ApplicationCommandOptionBase[];\n}\n\n/**\n * This mixin holds symbols that can be shared in chat input command options.\n */\nexport class SharedChatInputCommandOptions {\n\t/**\n\t * @internal\n\t */\n\tdeclare protected readonly data: SharedChatInputCommandOptionsData;\n\n\t/**\n\t * The options within this command.\n\t */\n\tpublic get options(): readonly ApplicationCommandOptionBase[] {\n\t\treturn (this.data.options ??= []);\n\t}\n\n\t/**\n\t * Adds boolean options.\n\t *\n\t * @param options - Options to add\n\t */\n\tpublic addBooleanOptions(\n\t\t...options: RestOrArray<\n\t\t\tChatInputCommandBooleanOption | ((builder: ChatInputCommandBooleanOption) => ChatInputCommandBooleanOption)\n\t\t>\n\t) {\n\t\treturn this.sharedAddOptions(ChatInputCommandBooleanOption, ...options);\n\t}\n\n\t/**\n\t * Adds user options.\n\t *\n\t * @param options - Options to add\n\t */\n\tpublic addUserOptions(\n\t\t...options: RestOrArray<\n\t\t\tChatInputCommandUserOption | ((builder: ChatInputCommandUserOption) => ChatInputCommandUserOption)\n\t\t>\n\t) {\n\t\treturn this.sharedAddOptions(ChatInputCommandUserOption, ...options);\n\t}\n\n\t/**\n\t * Adds channel options.\n\t *\n\t * @param options - Options to add\n\t */\n\tpublic addChannelOptions(\n\t\t...options: RestOrArray<\n\t\t\tChatInputCommandChannelOption | ((builder: ChatInputCommandChannelOption) => ChatInputCommandChannelOption)\n\t\t>\n\t) {\n\t\treturn this.sharedAddOptions(ChatInputCommandChannelOption, ...options);\n\t}\n\n\t/**\n\t * Adds role options.\n\t *\n\t * @param options - Options to add\n\t */\n\tpublic addRoleOptions(\n\t\t...options: RestOrArray<\n\t\t\tChatInputCommandRoleOption | ((builder: ChatInputCommandRoleOption) => ChatInputCommandRoleOption)\n\t\t>\n\t) {\n\t\treturn this.sharedAddOptions(ChatInputCommandRoleOption, ...options);\n\t}\n\n\t/**\n\t * Adds attachment options.\n\t *\n\t * @param options - Options to add\n\t */\n\tpublic addAttachmentOptions(\n\t\t...options: RestOrArray<\n\t\t\t| ChatInputCommandAttachmentOption\n\t\t\t| ((builder: ChatInputCommandAttachmentOption) => ChatInputCommandAttachmentOption)\n\t\t>\n\t) {\n\t\treturn this.sharedAddOptions(ChatInputCommandAttachmentOption, ...options);\n\t}\n\n\t/**\n\t * Adds mentionable options.\n\t *\n\t * @param options - Options to add\n\t */\n\tpublic addMentionableOptions(\n\t\t...options: RestOrArray<\n\t\t\t| ChatInputCommandMentionableOption\n\t\t\t| ((builder: ChatInputCommandMentionableOption) => ChatInputCommandMentionableOption)\n\t\t>\n\t) {\n\t\treturn this.sharedAddOptions(ChatInputCommandMentionableOption, ...options);\n\t}\n\n\t/**\n\t * Adds string options.\n\t *\n\t * @param options - Options to add\n\t */\n\tpublic addStringOptions(\n\t\t...options: RestOrArray<\n\t\t\tChatInputCommandStringOption | ((builder: ChatInputCommandStringOption) => ChatInputCommandStringOption)\n\t\t>\n\t) {\n\t\treturn this.sharedAddOptions(ChatInputCommandStringOption, ...options);\n\t}\n\n\t/**\n\t * Adds integer options.\n\t *\n\t * @param options - Options to add\n\t */\n\tpublic addIntegerOptions(\n\t\t...options: RestOrArray<\n\t\t\tChatInputCommandIntegerOption | ((builder: ChatInputCommandIntegerOption) => ChatInputCommandIntegerOption)\n\t\t>\n\t) {\n\t\treturn this.sharedAddOptions(ChatInputCommandIntegerOption, ...options);\n\t}\n\n\t/**\n\t * Adds number options.\n\t *\n\t * @param options - Options to add\n\t */\n\tpublic addNumberOptions(\n\t\t...options: RestOrArray<\n\t\t\tChatInputCommandNumberOption | ((builder: ChatInputCommandNumberOption) => ChatInputCommandNumberOption)\n\t\t>\n\t) {\n\t\treturn this.sharedAddOptions(ChatInputCommandNumberOption, ...options);\n\t}\n\n\t/**\n\t * Removes, replaces, or inserts options for this command.\n\t *\n\t * @remarks\n\t * This method behaves similarly\n\t * to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.\n\t *\n\t * It's useful for modifying and adjusting order of the already-existing options for this command.\n\t * @example\n\t * Remove the first option:\n\t * ```ts\n\t * actionRow.spliceOptions(0, 1);\n\t * ```\n\t * @example\n\t * Remove the first n options:\n\t * ```ts\n\t * const n = 4;\n\t * actionRow.spliceOptions(0, n);\n\t * ```\n\t * @example\n\t * Remove the last option:\n\t * ```ts\n\t * actionRow.spliceOptions(-1, 1);\n\t * ```\n\t * @param index - The index to start at\n\t * @param deleteCount - The number of options to remove\n\t * @param options - The replacing option objects\n\t */\n\tpublic spliceOptions(index: number, deleteCount: number, ...options: ApplicationCommandOptionBase[]): this {\n\t\tthis.data.options ??= [];\n\t\tthis.data.options.splice(index, deleteCount, ...options);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Where the actual adding magic happens. ✨\n\t *\n\t * @internal\n\t */\n\tprivate sharedAddOptions<OptionBuilder extends ApplicationCommandOptionBase>(\n\t\tInstance: new () => OptionBuilder,\n\t\t...options: RestOrArray<OptionBuilder | ((builder: OptionBuilder) => OptionBuilder)>\n\t): this {\n\t\tconst normalized = normalizeArray(options);\n\t\tconst resolved = normalized.map((option) => resolveBuilder(option, Instance));\n\n\t\tthis.data.options ??= [];\n\t\tthis.data.options.push(...resolved);\n\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/mixins/SharedSubcommands.ts",
    "content": "import type { RestOrArray } from '../../../../util/normalizeArray.js';\nimport { normalizeArray } from '../../../../util/normalizeArray.js';\nimport { resolveBuilder } from '../../../../util/resolveBuilder.js';\nimport {\n\tChatInputCommandSubcommandGroupBuilder,\n\tChatInputCommandSubcommandBuilder,\n} from '../ChatInputCommandSubcommands.js';\n\nexport interface SharedChatInputCommandSubcommandsData {\n\toptions?: (ChatInputCommandSubcommandBuilder | ChatInputCommandSubcommandGroupBuilder)[];\n}\n\n/**\n * This mixin holds symbols that can be shared in chat input subcommands.\n */\nexport class SharedChatInputCommandSubcommands {\n\t/**\n\t * @internal\n\t */\n\tdeclare protected readonly data: SharedChatInputCommandSubcommandsData;\n\n\t/**\n\t * Adds subcommand groups to this command.\n\t *\n\t * @param input - Subcommand groups to add\n\t */\n\tpublic addSubcommandGroups(\n\t\t...input: RestOrArray<\n\t\t\t| ChatInputCommandSubcommandGroupBuilder\n\t\t\t| ((subcommandGroup: ChatInputCommandSubcommandGroupBuilder) => ChatInputCommandSubcommandGroupBuilder)\n\t\t>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((value) => resolveBuilder(value, ChatInputCommandSubcommandGroupBuilder));\n\n\t\tthis.data.options ??= [];\n\t\tthis.data.options.push(...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds subcommands to this command.\n\t *\n\t * @param input - Subcommands to add\n\t */\n\tpublic addSubcommands(\n\t\t...input: RestOrArray<\n\t\t\t| ChatInputCommandSubcommandBuilder\n\t\t\t| ((subcommandGroup: ChatInputCommandSubcommandBuilder) => ChatInputCommandSubcommandBuilder)\n\t\t>\n\t): this {\n\t\tconst normalized = normalizeArray(input);\n\t\tconst resolved = normalized.map((value) => resolveBuilder(value, ChatInputCommandSubcommandBuilder));\n\n\t\tthis.data.options ??= [];\n\t\tthis.data.options.push(...resolved);\n\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/options/ApplicationCommandOptionBase.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type {\n\tAPIApplicationCommandBasicOption,\n\tAPIApplicationCommandOption,\n\tApplicationCommandOptionType,\n} from 'discord-api-types/v10';\nimport type { z } from 'zod';\nimport { validate } from '../../../../util/validation.js';\nimport type { SharedNameAndDescriptionData } from '../../SharedNameAndDescription.js';\nimport { SharedNameAndDescription } from '../../SharedNameAndDescription.js';\n\nexport interface ApplicationCommandOptionBaseData extends Partial<Pick<APIApplicationCommandOption, 'required'>> {\n\ttype: ApplicationCommandOptionType;\n}\n\n/**\n * The base application command option builder that contains common symbols for application command builders.\n */\nexport abstract class ApplicationCommandOptionBase\n\textends SharedNameAndDescription\n\timplements JSONEncodable<APIApplicationCommandBasicOption>\n{\n\t/**\n\t * @internal\n\t */\n\tprotected static readonly predicate: z.ZodType;\n\n\t/**\n\t * @internal\n\t */\n\tdeclare protected readonly data: ApplicationCommandOptionBaseData & SharedNameAndDescriptionData;\n\n\t/**\n\t * Creates a new application command option builder.\n\t *\n\t * @param type - The type of the option\n\t */\n\tpublic constructor(type: ApplicationCommandOptionType) {\n\t\tsuper();\n\t\tthis.data.type = type;\n\t}\n\n\t/**\n\t * Sets whether this option is required.\n\t *\n\t * @param required - Whether this option should be required\n\t */\n\tpublic setRequired(required = true) {\n\t\tthis.data.required = required;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic toJSON(validationOverride?: boolean): APIApplicationCommandBasicOption {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate((this.constructor as typeof ApplicationCommandOptionBase).predicate, clone, validationOverride);\n\n\t\treturn clone as APIApplicationCommandBasicOption;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/options/attachment.ts",
    "content": "import { ApplicationCommandOptionType } from 'discord-api-types/v10';\nimport { attachmentOptionPredicate } from '../Assertions.js';\nimport { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase.js';\n\n/**\n * A chat input command attachment option.\n */\nexport class ChatInputCommandAttachmentOption extends ApplicationCommandOptionBase {\n\t/**\n\t * @internal\n\t */\n\tprotected static override readonly predicate = attachmentOptionPredicate;\n\n\t/**\n\t * Creates a new attachment option.\n\t */\n\tpublic constructor() {\n\t\tsuper(ApplicationCommandOptionType.Attachment);\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/options/boolean.ts",
    "content": "import { ApplicationCommandOptionType } from 'discord-api-types/v10';\nimport { booleanOptionPredicate } from '../Assertions.js';\nimport { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase.js';\n\n/**\n * A chat input command boolean option.\n */\nexport class ChatInputCommandBooleanOption extends ApplicationCommandOptionBase {\n\t/**\n\t * @internal\n\t */\n\tprotected static override readonly predicate = booleanOptionPredicate;\n\n\t/**\n\t * Creates a new boolean option.\n\t */\n\tpublic constructor() {\n\t\tsuper(ApplicationCommandOptionType.Boolean);\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/options/channel.ts",
    "content": "import { ApplicationCommandOptionType } from 'discord-api-types/v10';\nimport { Mixin } from 'ts-mixer';\nimport { channelOptionPredicate } from '../Assertions.js';\nimport { ApplicationCommandOptionChannelTypesMixin } from '../mixins/ApplicationCommandOptionChannelTypesMixin.js';\nimport { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase.js';\n\n/**\n * A chat input command channel option.\n *\n * @mixes {@link ApplicationCommandOptionBase}\n * @mixes {@link ApplicationCommandOptionChannelTypesMixin}\n */\nexport class ChatInputCommandChannelOption extends Mixin(\n\tApplicationCommandOptionBase,\n\tApplicationCommandOptionChannelTypesMixin,\n) {\n\t/**\n\t * @internal\n\t */\n\tprotected static override readonly predicate = channelOptionPredicate;\n\n\t/**\n\t * Creates a new channel option.\n\t */\n\tpublic constructor() {\n\t\tsuper(ApplicationCommandOptionType.Channel);\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/options/integer.ts",
    "content": "import { ApplicationCommandOptionType } from 'discord-api-types/v10';\nimport { Mixin } from 'ts-mixer';\nimport { integerOptionPredicate } from '../Assertions.js';\nimport { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin.js';\nimport { ApplicationCommandOptionWithAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithAutocompleteMixin.js';\nimport { ApplicationCommandOptionWithChoicesMixin } from '../mixins/ApplicationCommandOptionWithChoicesMixin.js';\nimport { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase.js';\n\n/**\n * A chat input command integer option.\n *\n * @mixes {@link ApplicationCommandOptionBase}\n * @mixes {@link ApplicationCommandNumericOptionMinMaxValueMixin}\n * @mixes {@link ApplicationCommandOptionWithAutocompleteMixin}\n * @mixes {@link ApplicationCommandOptionWithChoicesMixin}\\<number\\>\n */\nexport class ChatInputCommandIntegerOption extends Mixin(\n\tApplicationCommandOptionBase,\n\tApplicationCommandNumericOptionMinMaxValueMixin,\n\tApplicationCommandOptionWithAutocompleteMixin,\n\tApplicationCommandOptionWithChoicesMixin<number>,\n) {\n\t/**\n\t * @internal\n\t */\n\tprotected static override readonly predicate = integerOptionPredicate;\n\n\t/**\n\t * Creates a new integer option.\n\t */\n\tpublic constructor() {\n\t\tsuper(ApplicationCommandOptionType.Integer);\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/options/mentionable.ts",
    "content": "import { ApplicationCommandOptionType } from 'discord-api-types/v10';\nimport { mentionableOptionPredicate } from '../Assertions.js';\nimport { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase.js';\n\n/**\n * A chat input command mentionable option.\n */\nexport class ChatInputCommandMentionableOption extends ApplicationCommandOptionBase {\n\t/**\n\t * @internal\n\t */\n\tprotected static override readonly predicate = mentionableOptionPredicate;\n\n\t/**\n\t * Creates a new mentionable option.\n\t */\n\tpublic constructor() {\n\t\tsuper(ApplicationCommandOptionType.Mentionable);\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/options/number.ts",
    "content": "import { ApplicationCommandOptionType } from 'discord-api-types/v10';\nimport { Mixin } from 'ts-mixer';\nimport { numberOptionPredicate } from '../Assertions.js';\nimport { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin.js';\nimport { ApplicationCommandOptionWithAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithAutocompleteMixin.js';\nimport { ApplicationCommandOptionWithChoicesMixin } from '../mixins/ApplicationCommandOptionWithChoicesMixin.js';\nimport { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase.js';\n\n/**\n * A chat input command number option.\n *\n * @mixes {@link ApplicationCommandOptionBase}\n * @mixes {@link ApplicationCommandNumericOptionMinMaxValueMixin}\n * @mixes {@link ApplicationCommandOptionWithAutocompleteMixin}\n * @mixes {@link ApplicationCommandOptionWithChoicesMixin}\\<number\\>\n */\nexport class ChatInputCommandNumberOption extends Mixin(\n\tApplicationCommandOptionBase,\n\tApplicationCommandNumericOptionMinMaxValueMixin,\n\tApplicationCommandOptionWithAutocompleteMixin,\n\tApplicationCommandOptionWithChoicesMixin<number>,\n) {\n\t/**\n\t * @internal\n\t */\n\tprotected static override readonly predicate = numberOptionPredicate;\n\n\t/**\n\t * Creates a new number option.\n\t */\n\tpublic constructor() {\n\t\tsuper(ApplicationCommandOptionType.Number);\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/options/role.ts",
    "content": "import { ApplicationCommandOptionType } from 'discord-api-types/v10';\nimport { roleOptionPredicate } from '../Assertions.js';\nimport { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase.js';\n\n/**\n * A chat input command role option.\n */\nexport class ChatInputCommandRoleOption extends ApplicationCommandOptionBase {\n\t/**\n\t * @internal\n\t */\n\tprotected static override readonly predicate = roleOptionPredicate;\n\n\t/**\n\t * Creates a new role option.\n\t */\n\tpublic constructor() {\n\t\tsuper(ApplicationCommandOptionType.Role);\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/options/string.ts",
    "content": "import { ApplicationCommandOptionType, type APIApplicationCommandStringOption } from 'discord-api-types/v10';\nimport { Mixin } from 'ts-mixer';\nimport { stringOptionPredicate } from '../Assertions.js';\nimport type { ApplicationCommandOptionWithAutocompleteData } from '../mixins/ApplicationCommandOptionWithAutocompleteMixin.js';\nimport { ApplicationCommandOptionWithAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithAutocompleteMixin.js';\nimport type { ApplicationCommandOptionWithChoicesData } from '../mixins/ApplicationCommandOptionWithChoicesMixin.js';\nimport { ApplicationCommandOptionWithChoicesMixin } from '../mixins/ApplicationCommandOptionWithChoicesMixin.js';\nimport { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase.js';\nimport type { ApplicationCommandOptionBaseData } from './ApplicationCommandOptionBase.js';\n\n/**\n * A chat input command string option.\n *\n * @mixes {@link ApplicationCommandOptionBase}\n * @mixes {@link ApplicationCommandOptionWithAutocompleteMixin}\n * @mixes {@link ApplicationCommandOptionWithChoicesMixin}\\<string\\>\n */\nexport class ChatInputCommandStringOption extends Mixin(\n\tApplicationCommandOptionBase,\n\tApplicationCommandOptionWithAutocompleteMixin,\n\tApplicationCommandOptionWithChoicesMixin<string>,\n) {\n\t/**\n\t * @internal\n\t */\n\tprotected static override readonly predicate = stringOptionPredicate;\n\n\t/**\n\t * @internal\n\t */\n\tdeclare protected readonly data: ApplicationCommandOptionBaseData &\n\t\tApplicationCommandOptionWithAutocompleteData &\n\t\tApplicationCommandOptionWithChoicesData &\n\t\tPartial<Pick<APIApplicationCommandStringOption, 'max_length' | 'min_length'>>;\n\n\t/**\n\t * Creates a new string option builder.\n\t */\n\tpublic constructor() {\n\t\tsuper(ApplicationCommandOptionType.String);\n\t}\n\n\t/**\n\t * Sets the maximum length of this string option.\n\t *\n\t * @param max - The maximum length this option can be\n\t */\n\tpublic setMaxLength(max: number): this {\n\t\tthis.data.max_length = max;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the maximum length of this string option.\n\t */\n\tpublic clearMaxLength(): this {\n\t\tthis.data.max_length = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the minimum length of this string option.\n\t *\n\t * @param min - The minimum length this option can be\n\t */\n\tpublic setMinLength(min: number): this {\n\t\tthis.data.min_length = min;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the minimum length of this string option.\n\t */\n\tpublic clearMinLength(): this {\n\t\tthis.data.min_length = undefined;\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/chatInput/options/user.ts",
    "content": "import { ApplicationCommandOptionType } from 'discord-api-types/v10';\nimport { userOptionPredicate } from '../Assertions.js';\nimport { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase.js';\n\n/**\n * A chat input command user option.\n */\nexport class ChatInputCommandUserOption extends ApplicationCommandOptionBase {\n\t/**\n\t * @internal\n\t */\n\tprotected static override readonly predicate = userOptionPredicate;\n\n\t/**\n\t * Creates a new user option.\n\t */\n\tpublic constructor() {\n\t\tsuper(ApplicationCommandOptionType.User);\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/contextMenu/Assertions.ts",
    "content": "import { ApplicationCommandType, ApplicationIntegrationType, InteractionContextType } from 'discord-api-types/v10';\nimport { z } from 'zod';\nimport { localeMapPredicate, memberPermissionsPredicate } from '../../../Assertions.js';\n\nconst namePredicate = z\n\t.string()\n\t.min(1)\n\t.max(32)\n\t.refine((val) => val.trim().length > 0, {\n\t\terror: 'Must not consist of only whitespace.',\n\t});\n\nconst contextsPredicate = z.array(z.enum(InteractionContextType));\nconst integrationTypesPredicate = z.array(z.enum(ApplicationIntegrationType));\n\nconst baseContextMenuCommandPredicate = z.object({\n\tcontexts: contextsPredicate.optional(),\n\tdefault_member_permissions: memberPermissionsPredicate.optional(),\n\tname: namePredicate,\n\tname_localizations: localeMapPredicate.optional(),\n\tintegration_types: integrationTypesPredicate.optional(),\n\tnsfw: z.boolean().optional(),\n});\n\nexport const userCommandPredicate = baseContextMenuCommandPredicate.extend({\n\ttype: z.literal(ApplicationCommandType.User),\n});\n\nexport const messageCommandPredicate = baseContextMenuCommandPredicate.extend({\n\ttype: z.literal(ApplicationCommandType.Message),\n});\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/contextMenu/ContextMenuCommand.ts",
    "content": "import type { ApplicationCommandType, RESTPostAPIContextMenuApplicationCommandsJSONBody } from 'discord-api-types/v10';\nimport { Mixin } from 'ts-mixer';\nimport { CommandBuilder } from '../Command.js';\nimport { SharedName } from '../SharedName.js';\n\n/**\n * The type a context menu command can be.\n */\nexport type ContextMenuCommandType = ApplicationCommandType.Message | ApplicationCommandType.User;\n\n/**\n * A builder that creates API-compatible JSON data for context menu commands.\n *\n * @mixes {@link CommandBuilder}\\<{@link discord-api-types/v10#(RESTPostAPIContextMenuApplicationCommandsJSONBody:interface)}\\>\n * @mixes {@link SharedName}\n */\nexport abstract class ContextMenuCommandBuilder extends Mixin(\n\tCommandBuilder<RESTPostAPIContextMenuApplicationCommandsJSONBody>,\n\tSharedName,\n) {\n\t/**\n\t * The API data associated with this context menu command.\n\t *\n\t * @internal\n\t */\n\tprotected override readonly data: Partial<RESTPostAPIContextMenuApplicationCommandsJSONBody>;\n\n\t/**\n\t * Creates a new context menu command.\n\t *\n\t * @param data - The API data to create this context menu command with\n\t */\n\tpublic constructor(data: Partial<RESTPostAPIContextMenuApplicationCommandsJSONBody> = {}) {\n\t\tsuper();\n\t\tthis.data = structuredClone(data);\n\t}\n\n\t/**\n\t * {@inheritDoc CommandBuilder.toJSON}\n\t */\n\tpublic abstract override toJSON(validationOverride?: boolean): RESTPostAPIContextMenuApplicationCommandsJSONBody;\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/contextMenu/MessageCommand.ts",
    "content": "import { ApplicationCommandType, type RESTPostAPIContextMenuApplicationCommandsJSONBody } from 'discord-api-types/v10';\nimport { validate } from '../../../util/validation.js';\nimport { messageCommandPredicate } from './Assertions.js';\nimport { ContextMenuCommandBuilder } from './ContextMenuCommand.js';\n\n/**\n * A builder that creates API-compatible JSON data for message context menu commands.\n */\nexport class MessageContextCommandBuilder extends ContextMenuCommandBuilder {\n\t/**\n\t * {@inheritDoc CommandBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): RESTPostAPIContextMenuApplicationCommandsJSONBody {\n\t\tconst data = { ...structuredClone(this.data), type: ApplicationCommandType.Message };\n\t\tvalidate(messageCommandPredicate, data, validationOverride);\n\n\t\treturn data as RESTPostAPIContextMenuApplicationCommandsJSONBody;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/commands/contextMenu/UserCommand.ts",
    "content": "import { ApplicationCommandType, type RESTPostAPIContextMenuApplicationCommandsJSONBody } from 'discord-api-types/v10';\nimport { validate } from '../../../util/validation.js';\nimport { userCommandPredicate } from './Assertions.js';\nimport { ContextMenuCommandBuilder } from './ContextMenuCommand.js';\n\n/**\n * A builder that creates API-compatible JSON data for user context menu commands.\n */\nexport class UserContextCommandBuilder extends ContextMenuCommandBuilder {\n\t/**\n\t * {@inheritDoc CommandBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): RESTPostAPIContextMenuApplicationCommandsJSONBody {\n\t\tconst data = { ...structuredClone(this.data), type: ApplicationCommandType.User };\n\t\tvalidate(userCommandPredicate, data, validationOverride);\n\n\t\treturn data as RESTPostAPIContextMenuApplicationCommandsJSONBody;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/interactions/modals/Assertions.ts",
    "content": "import { ComponentType } from 'discord-api-types/v10';\nimport { z } from 'zod';\nimport { customIdPredicate } from '../../Assertions.js';\nimport { labelPredicate } from '../../components/label/Assertions.js';\nimport { textDisplayPredicate } from '../../components/v2/Assertions.js';\n\nconst titlePredicate = z.string().min(1).max(45);\n\nexport const modalPredicate = z.object({\n\ttitle: titlePredicate,\n\tcustom_id: customIdPredicate,\n\tcomponents: z\n\t\t.union([\n\t\t\tz.object({\n\t\t\t\ttype: z.literal(ComponentType.ActionRow),\n\t\t\t\tcomponents: z\n\t\t\t\t\t.object({ type: z.literal(ComponentType.TextInput) })\n\t\t\t\t\t.array()\n\t\t\t\t\t.length(1),\n\t\t\t}),\n\t\t\tlabelPredicate,\n\t\t\ttextDisplayPredicate,\n\t\t])\n\t\t.array()\n\t\t.min(1)\n\t\t.max(5),\n});\n"
  },
  {
    "path": "packages/builders/src/interactions/modals/Modal.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type {\n\tAPILabelComponent,\n\tAPIModalInteractionResponseCallbackData,\n\tAPITextDisplayComponent,\n} from 'discord-api-types/v10';\nimport type { ActionRowBuilder } from '../../components/ActionRow.js';\nimport type { AnyModalComponentBuilder } from '../../components/Components.js';\nimport { createComponentBuilder } from '../../components/Components.js';\nimport { LabelBuilder } from '../../components/label/Label.js';\nimport { TextDisplayBuilder } from '../../components/v2/TextDisplay.js';\nimport { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';\nimport { resolveBuilder } from '../../util/resolveBuilder.js';\nimport { validate } from '../../util/validation.js';\nimport { modalPredicate } from './Assertions.js';\n\nexport interface ModalBuilderData extends Partial<Omit<APIModalInteractionResponseCallbackData, 'components'>> {\n\tcomponents: (ActionRowBuilder | AnyModalComponentBuilder)[];\n}\n\n/**\n * A builder that creates API-compatible JSON data for modals.\n */\nexport class ModalBuilder implements JSONEncodable<APIModalInteractionResponseCallbackData> {\n\t/**\n\t * The API data associated with this modal.\n\t */\n\tprivate readonly data: ModalBuilderData;\n\n\t/**\n\t * The components within this modal.\n\t */\n\tpublic get components(): readonly (ActionRowBuilder | AnyModalComponentBuilder)[] {\n\t\treturn this.data.components;\n\t}\n\n\t/**\n\t * Creates a new modal.\n\t *\n\t * @param data - The API data to create this modal with\n\t */\n\tpublic constructor(data: Partial<APIModalInteractionResponseCallbackData> = {}) {\n\t\tconst { components = [], ...rest } = data;\n\n\t\tthis.data = {\n\t\t\t...structuredClone(rest),\n\t\t\tcomponents: components.map((component) => createComponentBuilder(component)),\n\t\t};\n\t}\n\n\t/**\n\t * Sets the title of this modal.\n\t *\n\t * @param title - The title to use\n\t */\n\tpublic setTitle(title: string) {\n\t\tthis.data.title = title;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the custom id of this modal.\n\t *\n\t * @param customId - The custom id to use\n\t */\n\tpublic setCustomId(customId: string) {\n\t\tthis.data.custom_id = customId;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds label components to this modal.\n\t *\n\t * @param components - The components to add\n\t */\n\tpublic addLabelComponents(\n\t\t...components: RestOrArray<APILabelComponent | LabelBuilder | ((builder: LabelBuilder) => LabelBuilder)>\n\t) {\n\t\tconst normalized = normalizeArray(components);\n\t\tconst resolved = normalized.map((label) => resolveBuilder(label, LabelBuilder));\n\n\t\tthis.data.components.push(...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds text display components to this modal.\n\t *\n\t * @param components - The components to add\n\t */\n\tpublic addTextDisplayComponents(\n\t\t...components: RestOrArray<\n\t\t\tAPITextDisplayComponent | TextDisplayBuilder | ((builder: TextDisplayBuilder) => TextDisplayBuilder)\n\t\t>\n\t) {\n\t\tconst normalized = normalizeArray(components);\n\t\tconst resolved = normalized.map((row) => resolveBuilder(row, TextDisplayBuilder));\n\n\t\tthis.data.components.push(...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes, replaces, or inserts components for this modal.\n\t *\n\t * @remarks\n\t * This method behaves similarly\n\t * to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.\n\t * The maximum amount of components that can be added is 5.\n\t *\n\t * It's useful for modifying and adjusting order of the already-existing components of a modal.\n\t * @example\n\t * Remove the first component:\n\t * ```ts\n\t * modal.spliceComponents(0, 1);\n\t * ```\n\t * @example\n\t * Remove the first n components:\n\t * ```ts\n\t * const n = 4;\n\t * modal.spliceComponents(0, n);\n\t * ```\n\t * @example\n\t * Remove the last component:\n\t * ```ts\n\t * modal.spliceComponents(-1, 1);\n\t * ```\n\t * @param index - The index to start at\n\t * @param deleteCount - The number of components to remove\n\t * @param components - The replacing components\n\t */\n\tpublic spliceComponents(index: number, deleteCount: number, ...components: AnyModalComponentBuilder[]): this {\n\t\tthis.data.components.splice(index, deleteCount, ...components);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic toJSON(validationOverride?: boolean): APIModalInteractionResponseCallbackData {\n\t\tconst { components, ...rest } = this.data;\n\n\t\tconst data = {\n\t\t\t...structuredClone(rest),\n\t\t\tcomponents: components.map((component) => component.toJSON(validationOverride)),\n\t\t};\n\n\t\tvalidate(modalPredicate, data, validationOverride);\n\n\t\treturn data as APIModalInteractionResponseCallbackData;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/messages/AllowedMentions.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type { AllowedMentionsTypes, APIAllowedMentions, Snowflake } from 'discord-api-types/v10';\nimport { normalizeArray, type RestOrArray } from '../util/normalizeArray.js';\nimport { validate } from '../util/validation.js';\nimport { allowedMentionPredicate } from './Assertions.js';\n\n/**\n * A builder that creates API-compatible JSON data for allowed mentions.\n */\nexport class AllowedMentionsBuilder implements JSONEncodable<APIAllowedMentions> {\n\t/**\n\t * The API data associated with these allowed mentions.\n\t */\n\tprivate readonly data: Partial<APIAllowedMentions>;\n\n\t/**\n\t * Creates a new allowed mentions builder.\n\t *\n\t * @param data - The API data to create this allowed mentions with\n\t */\n\tpublic constructor(data: Partial<APIAllowedMentions> = {}) {\n\t\tthis.data = structuredClone(data);\n\t}\n\n\t/**\n\t * Sets the types of mentions to parse from the content.\n\t *\n\t * @param parse - The types of mentions to parse from the content\n\t */\n\tpublic setParse(...parse: RestOrArray<AllowedMentionsTypes>): this {\n\t\tthis.data.parse = normalizeArray(parse);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the parse mention types.\n\t */\n\tpublic clearParse(): this {\n\t\tthis.data.parse = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the roles to mention.\n\t *\n\t * @param roles - The roles to mention\n\t */\n\tpublic setRoles(...roles: RestOrArray<Snowflake>): this {\n\t\tthis.data.roles = normalizeArray(roles);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds roles to mention.\n\t *\n\t * @param roles - The roles to mention\n\t */\n\tpublic addRoles(...roles: RestOrArray<Snowflake>): this {\n\t\tthis.data.roles ??= [];\n\t\tthis.data.roles.push(...normalizeArray(roles));\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes, replaces, or inserts roles.\n\t *\n\t * @remarks\n\t * This method behaves similarly\n\t * to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.\n\t *\n\t * It's useful for modifying and adjusting order of the already-existing roles.\n\t * @example\n\t * Remove the first role:\n\t * ```ts\n\t * allowedMentions.spliceRoles(0, 1);\n\t * ```\n\t * @example\n\t * Remove the first n roles:\n\t * ```ts\n\t * const n = 4;\n\t * allowedMentions.spliceRoles(0, n);\n\t * ```\n\t * @example\n\t * Remove the last role:\n\t * ```ts\n\t * allowedMentions.spliceRoles(-1, 1);\n\t * ```\n\t * @param index - The index to start at\n\t * @param deleteCount - The number of roles to remove\n\t * @param roles - The replacing role ids\n\t */\n\tpublic spliceRoles(index: number, deleteCount: number, ...roles: RestOrArray<Snowflake>): this {\n\t\tthis.data.roles ??= [];\n\t\tthis.data.roles.splice(index, deleteCount, ...normalizeArray(roles));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the roles to mention.\n\t */\n\tpublic clearRoles(): this {\n\t\tthis.data.roles = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the users to mention.\n\t *\n\t * @param users - The users to mention\n\t */\n\tpublic setUsers(...users: RestOrArray<Snowflake>): this {\n\t\tthis.data.users = normalizeArray(users);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds users to mention.\n\t *\n\t * @param users - The users to mention\n\t */\n\tpublic addUsers(...users: RestOrArray<Snowflake>): this {\n\t\tthis.data.users ??= [];\n\t\tthis.data.users.push(...normalizeArray(users));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes, replaces, or inserts users.\n\t *\n\t * @remarks\n\t * This method behaves similarly\n\t * to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.\n\t *\n\t * It's useful for modifying and adjusting order of the already-existing users.\n\t * @example\n\t * Remove the first user:\n\t * ```ts\n\t * allowedMentions.spliceUsers(0, 1);\n\t * ```\n\t * @example\n\t * Remove the first n users:\n\t * ```ts\n\t * const n = 4;\n\t * allowedMentions.spliceUsers(0, n);\n\t * ```\n\t * @example\n\t * Remove the last user:\n\t * ```ts\n\t * allowedMentions.spliceUsers(-1, 1);\n\t * ```\n\t * @param index - The index to start at\n\t * @param deleteCount - The number of users to remove\n\t * @param users - The replacing user ids\n\t */\n\tpublic spliceUsers(index: number, deleteCount: number, ...users: RestOrArray<Snowflake>): this {\n\t\tthis.data.users ??= [];\n\t\tthis.data.users.splice(index, deleteCount, ...normalizeArray(users));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the users to mention.\n\t */\n\tpublic clearUsers(): this {\n\t\tthis.data.users = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * For replies, sets whether to mention the author of the message being replied to.\n\t *\n\t * @param repliedUser - Whether to mention the author of the message being replied to\n\t */\n\tpublic setRepliedUser(repliedUser = true): this {\n\t\tthis.data.replied_user = repliedUser;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic toJSON(validationOverride?: boolean): APIAllowedMentions {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(allowedMentionPredicate, clone, validationOverride);\n\n\t\treturn clone as APIAllowedMentions;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/messages/Assertions.ts",
    "content": "import { Buffer } from 'node:buffer';\nimport { AllowedMentionsTypes, ComponentType, MessageFlags, MessageReferenceType } from 'discord-api-types/v10';\nimport { z } from 'zod';\nimport { snowflakePredicate } from '../Assertions.js';\nimport { embedPredicate } from './embed/Assertions.js';\nimport { pollPredicate } from './poll/Assertions.js';\n\nconst fileKeyRegex = /^files\\[(?<placeholder>\\d+?)]$/;\n\nexport const rawFilePredicate = z.object({\n\tdata: z.union([z.instanceof(Buffer), z.instanceof(Uint8Array), z.string()]),\n\tname: z.string().min(1),\n\tcontentType: z.string().optional(),\n\tkey: z.string().regex(fileKeyRegex).optional(),\n});\n\nexport const attachmentPredicate = z.object({\n\t// As a string it only makes sense for edits when we do have an attachment snowflake\n\tid: z.union([snowflakePredicate, z.number()]),\n\tdescription: z.string().max(1_024).optional(),\n\tduration_secs: z\n\t\t.number()\n\t\t.max(2 ** 31 - 1)\n\t\t.optional(),\n\tfilename: z.string().max(1_024).optional(),\n\ttitle: z.string().max(1_024).optional(),\n\twaveform: z.string().max(400).optional(),\n});\n\nexport const allowedMentionPredicate = z\n\t.object({\n\t\tparse: z.enum(AllowedMentionsTypes).array().optional(),\n\t\troles: z.string().array().max(100).optional(),\n\t\tusers: z.string().array().max(100).optional(),\n\t\treplied_user: z.boolean().optional(),\n\t})\n\t.refine(\n\t\t(data) =>\n\t\t\t!(\n\t\t\t\t(data.parse?.includes(AllowedMentionsTypes.User) && data.users?.length) ||\n\t\t\t\t(data.parse?.includes(AllowedMentionsTypes.Role) && data.roles?.length)\n\t\t\t),\n\t\t{\n\t\t\terror:\n\t\t\t\t'Cannot specify both parse: [\"users\"] and non-empty users array, or parse: [\"roles\"] and non-empty roles array. These are mutually exclusive',\n\t\t},\n\t);\n\nexport const messageReferencePredicate = z.object({\n\tchannel_id: z.string().optional(),\n\tfail_if_not_exists: z.boolean().optional(),\n\tguild_id: z.string().optional(),\n\tmessage_id: z.string(),\n\ttype: z.enum(MessageReferenceType).optional(),\n});\n\nconst baseMessagePredicate = z.object({\n\tnonce: z.union([z.string().max(25), z.number()]).optional(),\n\ttts: z.boolean().optional(),\n\tallowed_mentions: allowedMentionPredicate.optional(),\n\tmessage_reference: messageReferencePredicate.optional(),\n\tattachments: attachmentPredicate.array().max(10).optional(),\n\tenforce_nonce: z.boolean().optional(),\n});\n\nconst basicActionRowPredicate = z.object({\n\ttype: z.literal(ComponentType.ActionRow),\n\tcomponents: z\n\t\t.object({\n\t\t\ttype: z.literal([\n\t\t\t\tComponentType.Button,\n\t\t\t\tComponentType.ChannelSelect,\n\t\t\t\tComponentType.MentionableSelect,\n\t\t\t\tComponentType.RoleSelect,\n\t\t\t\tComponentType.StringSelect,\n\t\t\t\tComponentType.UserSelect,\n\t\t\t]),\n\t\t})\n\t\t.array(),\n});\n\nconst messageNoComponentsV2Predicate = baseMessagePredicate\n\t.extend({\n\t\tcontent: z.string().max(2_000).optional(),\n\t\tembeds: embedPredicate.array().max(10).optional(),\n\t\tsticker_ids: z.array(z.string()).max(3).optional(),\n\t\tpoll: pollPredicate.optional(),\n\t\tcomponents: basicActionRowPredicate.array().max(5).optional(),\n\t\tflags: z\n\t\t\t.int()\n\t\t\t.optional()\n\t\t\t.refine((flags) => !flags || (flags & MessageFlags.IsComponentsV2) === 0, {\n\t\t\t\terror: 'Cannot set content, embeds, stickers, or poll with IsComponentsV2 flag set',\n\t\t\t}),\n\t})\n\t.refine(\n\t\t(data) =>\n\t\t\tdata.content !== undefined ||\n\t\t\t(data.embeds !== undefined && data.embeds.length > 0) ||\n\t\t\tdata.poll !== undefined ||\n\t\t\t(data.attachments !== undefined && data.attachments.length > 0) ||\n\t\t\t(data.components !== undefined && data.components.length > 0) ||\n\t\t\t(data.sticker_ids !== undefined && data.sticker_ids.length > 0),\n\t\t{ error: 'Messages must have content, embeds, a poll, attachments, components or stickers' },\n\t);\n\nconst allTopLevelComponentsPredicate = z\n\t.union([\n\t\tbasicActionRowPredicate,\n\t\tz.object({\n\t\t\ttype: z.literal([\n\t\t\t\t// Components v2\n\t\t\t\tComponentType.Container,\n\t\t\t\tComponentType.File,\n\t\t\t\tComponentType.MediaGallery,\n\t\t\t\tComponentType.Section,\n\t\t\t\tComponentType.Separator,\n\t\t\t\tComponentType.TextDisplay,\n\t\t\t\tComponentType.Thumbnail,\n\t\t\t]),\n\t\t}),\n\t])\n\t.array()\n\t.min(1)\n\t.max(10);\n\nconst messageComponentsV2Predicate = baseMessagePredicate.extend({\n\tcomponents: allTopLevelComponentsPredicate,\n\tflags: z.int().refine((flags) => (flags & MessageFlags.IsComponentsV2) === MessageFlags.IsComponentsV2, {\n\t\terror: 'Must set IsComponentsV2 flag to use Components V2',\n\t}),\n\t// These fields cannot be set\n\tcontent: z.string().length(0).nullish(),\n\tembeds: z.array(z.never()).nullish(),\n\tsticker_ids: z.array(z.never()).nullish(),\n\tpoll: z.null().optional(),\n});\n\nexport const messagePredicate = z.union([messageNoComponentsV2Predicate, messageComponentsV2Predicate]);\n\n// This validator does not assert file.key <-> attachment.id coherence. This is fine, because the builders\n// should effectively guarantee that.\nexport const fileBodyMessagePredicate = z.object({\n\tbody: messagePredicate,\n\t// No min length to support message edits\n\tfiles: rawFilePredicate.array().max(10),\n});\n"
  },
  {
    "path": "packages/builders/src/messages/Attachment.ts",
    "content": "import type { Buffer } from 'node:buffer';\nimport type { JSONEncodable, RawFile } from '@discordjs/util';\nimport type { RESTAPIAttachment, Snowflake } from 'discord-api-types/v10';\nimport { validate } from '../util/validation.js';\nimport { attachmentPredicate } from './Assertions.js';\n\n/**\n * A builder that creates API-compatible JSON data for attachments.\n */\nexport class AttachmentBuilder implements JSONEncodable<RESTAPIAttachment> {\n\t/**\n\t * The API data associated with this attachment.\n\t */\n\tprivate readonly data: Partial<RESTAPIAttachment>;\n\n\t/**\n\t * This data is not included in the output of `toJSON()`. For this class specifically, this refers to binary data\n\t * that will wind up being included in the multipart/form-data request, if used with the `MessageBuilder`.\n\t * To retrieve this data, use {@link getRawFile}.\n\t *\n\t * @remarks This cannot be set via the constructor, primarily because of the behavior described\n\t * {@link https://discord.com/developers/docs/reference#editing-message-attachments | here}.\n\t * That is, when editing a message's attachments, you should only be providing file data for new attachments.\n\t */\n\tprivate readonly fileData: Partial<Pick<RawFile, 'contentType' | 'data'>>;\n\n\t/**\n\t * Creates a new attachment builder.\n\t *\n\t * @param data - The API data to create this attachment with\n\t * @example\n\t * ```ts\n\t * const attachment = new AttachmentBuilder().setId(1).setFileData(':)').setFilename('smiley.txt')\n\t * ```\n\t * @remarks Please note that the `id` field is required, it's rather easy to miss!\n\t */\n\tpublic constructor(data: Partial<RESTAPIAttachment> = {}) {\n\t\tthis.data = structuredClone(data);\n\t\tthis.fileData = {};\n\t}\n\n\t/**\n\t * Sets the id of the attachment.\n\t *\n\t * @param id - The id of the attachment\n\t */\n\tpublic setId(id: Snowflake | number): this {\n\t\tthis.data.id = id;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the description of this attachment.\n\t *\n\t * @param description - The description of the attachment\n\t */\n\tpublic setDescription(description: string): this {\n\t\tthis.data.description = description;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the description of this attachment.\n\t */\n\tpublic clearDescription(): this {\n\t\tthis.data.description = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the duration of this attachment (audio clips).\n\t *\n\t * @param duration - The duration of the attachment in seconds\n\t */\n\tpublic setDuration(duration: number): this {\n\t\tthis.data.duration_secs = duration;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the duration of this attachment.\n\t */\n\tpublic clearDuration(): this {\n\t\tthis.data.duration_secs = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the filename of this attachment.\n\t *\n\t * @param filename - The filename of the attachment\n\t */\n\tpublic setFilename(filename: string): this {\n\t\tthis.data.filename = filename;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the filename of this attachment.\n\t */\n\tpublic clearFilename(): this {\n\t\tthis.data.filename = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the file data to upload with this attachment.\n\t *\n\t * @param data - The file data\n\t * @remarks Note that this data is NOT included in the {@link toJSON} output. To retrieve it, use {@link getRawFile}.\n\t */\n\tpublic setFileData(data: Buffer | Uint8Array | string): this {\n\t\tthis.fileData.data = data;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the file data from this attachment.\n\t */\n\tpublic clearFileData(): this {\n\t\tthis.fileData.data = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the content type of the file data to upload with this attachment.\n\t *\n\t * @remarks Note that this data is NOT included in the {@link toJSON} output. To retrieve it, use {@link getRawFile}.\n\t */\n\tpublic setFileContentType(contentType: string): this {\n\t\tthis.fileData.contentType = contentType;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the content type of the file data from this attachment.\n\t */\n\tpublic clearFileContentType(): this {\n\t\tthis.fileData.contentType = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Converts this attachment to a {@link RawFile} for uploading.\n\t *\n\t * @returns A {@link RawFile} object, or `undefined` if no file data is set\n\t */\n\tpublic getRawFile(): Partial<RawFile> | undefined {\n\t\tif (!this.fileData?.data) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn {\n\t\t\t...this.fileData,\n\t\t\tname: this.data.filename,\n\t\t\tkey: this.data.id === undefined ? undefined : `files[${this.data.id}]`,\n\t\t};\n\t}\n\n\t/**\n\t * Sets the title of this attachment.\n\t *\n\t * @param title - The title of the attachment\n\t */\n\tpublic setTitle(title: string): this {\n\t\tthis.data.title = title;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the title of this attachment.\n\t */\n\tpublic clearTitle(): this {\n\t\tthis.data.title = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the waveform of this attachment (audio clips).\n\t *\n\t * @param waveform - The waveform of the attachment\n\t */\n\tpublic setWaveform(waveform: string): this {\n\t\tthis.data.waveform = waveform;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the waveform of this attachment.\n\t */\n\tpublic clearWaveform(): this {\n\t\tthis.data.waveform = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic toJSON(validationOverride?: boolean): RESTAPIAttachment {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(attachmentPredicate, clone, validationOverride);\n\n\t\treturn clone as RESTAPIAttachment;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/messages/Message.ts",
    "content": "import type { FileBodyEncodable, FileBodyEncodableResult, JSONEncodable, RawFile } from '@discordjs/util';\nimport type {\n\tAPIActionRowComponent,\n\tAPIAllowedMentions,\n\tAPIAttachment,\n\tAPIEmbed,\n\tAPIComponentInMessageActionRow,\n\tAPIMessageReference,\n\tAPIPoll,\n\tRESTPostAPIChannelMessageJSONBody,\n\tSnowflake,\n\tMessageFlags,\n\tAPIContainerComponent,\n\tAPIFileComponent,\n\tAPIMediaGalleryComponent,\n\tAPISectionComponent,\n\tAPISeparatorComponent,\n\tAPITextDisplayComponent,\n\tAPIMessageTopLevelComponent,\n} from 'discord-api-types/v10';\nimport { ActionRowBuilder } from '../components/ActionRow.js';\nimport { ComponentBuilder } from '../components/Component.js';\nimport type { MessageTopLevelComponentBuilder } from '../components/Components.js';\nimport { createComponentBuilder } from '../components/Components.js';\nimport { ContainerBuilder } from '../components/v2/Container.js';\nimport { FileBuilder } from '../components/v2/File.js';\nimport { MediaGalleryBuilder } from '../components/v2/MediaGallery.js';\nimport { SectionBuilder } from '../components/v2/Section.js';\nimport { SeparatorBuilder } from '../components/v2/Separator.js';\nimport { TextDisplayBuilder } from '../components/v2/TextDisplay.js';\nimport { normalizeArray, type RestOrArray } from '../util/normalizeArray.js';\nimport { resolveBuilder } from '../util/resolveBuilder.js';\nimport { validate } from '../util/validation.js';\nimport { AllowedMentionsBuilder } from './AllowedMentions.js';\nimport { fileBodyMessagePredicate, messagePredicate } from './Assertions.js';\nimport { AttachmentBuilder } from './Attachment.js';\nimport { MessageReferenceBuilder } from './MessageReference.js';\nimport { EmbedBuilder } from './embed/Embed.js';\nimport { PollBuilder } from './poll/Poll.js';\n\nexport interface MessageBuilderData extends Partial<\n\tOmit<\n\t\tRESTPostAPIChannelMessageJSONBody,\n\t\t'allowed_mentions' | 'attachments' | 'components' | 'embeds' | 'message_reference' | 'poll'\n\t>\n> {\n\tallowed_mentions?: AllowedMentionsBuilder;\n\tattachments: AttachmentBuilder[];\n\tcomponents: MessageTopLevelComponentBuilder[];\n\tembeds: EmbedBuilder[];\n\tmessage_reference?: MessageReferenceBuilder;\n\tpoll?: PollBuilder;\n}\n\n/**\n * A builder that creates API-compatible JSON data for messages.\n */\nexport class MessageBuilder\n\timplements JSONEncodable<RESTPostAPIChannelMessageJSONBody>, FileBodyEncodable<RESTPostAPIChannelMessageJSONBody>\n{\n\t/**\n\t * The API data associated with this message.\n\t */\n\tprivate readonly data: MessageBuilderData;\n\n\t/**\n\t * Gets the attachments of this message.\n\t */\n\tpublic get attachments(): readonly AttachmentBuilder[] {\n\t\treturn this.data.attachments;\n\t}\n\n\t/**\n\t * Gets the components of this message.\n\t */\n\tpublic get components(): readonly MessageTopLevelComponentBuilder[] {\n\t\treturn this.data.components;\n\t}\n\n\t/**\n\t * Gets the embeds of this message.\n\t */\n\tpublic get embeds(): readonly EmbedBuilder[] {\n\t\treturn this.data.embeds;\n\t}\n\n\t/**\n\t * Creates a new message builder.\n\t *\n\t * @param data - The API data to create this message with\n\t */\n\tpublic constructor(data: Partial<RESTPostAPIChannelMessageJSONBody> = {}) {\n\t\tconst { attachments = [], embeds = [], components = [], message_reference, poll, allowed_mentions, ...rest } = data;\n\n\t\tthis.data = {\n\t\t\t...structuredClone(rest),\n\t\t\tallowed_mentions: allowed_mentions && new AllowedMentionsBuilder(allowed_mentions),\n\t\t\tattachments: attachments.map((attachment) => new AttachmentBuilder(attachment)),\n\t\t\tembeds: embeds.map((embed) => new EmbedBuilder(embed)),\n\t\t\tpoll: poll && new PollBuilder(poll),\n\t\t\tcomponents: components.map((component) => createComponentBuilder(component)),\n\t\t\tmessage_reference: message_reference && new MessageReferenceBuilder(message_reference),\n\t\t};\n\t}\n\n\t/**\n\t * Sets the content of the message.\n\t *\n\t * @param content - The content to set\n\t */\n\tpublic setContent(content: string): this {\n\t\tthis.data.content = content;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the content of the message.\n\t */\n\tpublic clearContent(): this {\n\t\tthis.data.content = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the nonce of the message.\n\t *\n\t * @param nonce - The nonce to set\n\t */\n\tpublic setNonce(nonce: number | string): this {\n\t\tthis.data.nonce = nonce;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the nonce of the message.\n\t */\n\tpublic clearNonce(): this {\n\t\tthis.data.nonce = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets whether the message is TTS.\n\t *\n\t * @param tts - Whether the message is TTS\n\t */\n\tpublic setTTS(tts = true): this {\n\t\tthis.data.tts = tts;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Appends embeds to this message.\n\t *\n\t * @remarks\n\t * The maximum amount of embeds that can be added is 10.\n\t * @example\n\t * Using an array:\n\t * ```ts\n\t * const embeds: APIEmbed[] = ...;\n\t * const message = new MessageBuilder()\n\t * \t.addEmbeds(embeds);\n\t * ```\n\t * @example\n\t * Using rest parameters (variadic):\n\t * ```ts\n\t * const message = new MessageBuilder()\n\t * \t.addEmbeds(\n\t * \t\t{ title: 'Embed 1' },\n\t * \t\t{ title: 'Embed 2' },\n\t * \t);\n\t * ```\n\t * @param embeds - The embeds to add\n\t */\n\tpublic addEmbeds(...embeds: RestOrArray<APIEmbed | EmbedBuilder | ((builder: EmbedBuilder) => EmbedBuilder)>): this {\n\t\tthis.data.embeds ??= [];\n\n\t\tconst resolved = normalizeArray(embeds).map((embed) => resolveBuilder(embed, EmbedBuilder));\n\t\tthis.data.embeds.push(...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes, replaces, or inserts embeds for this message.\n\t *\n\t * @remarks\n\t * This method behaves similarly\n\t * to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.\n\t *\n\t * It's useful for modifying and adjusting order of the already-existing embeds of a message.\n\t * @example\n\t * Remove the first embed:\n\t * ```ts\n\t * message.spliceEmbeds(0, 1);\n\t * ```\n\t * @example\n\t * Remove the first n embeds:\n\t * ```ts\n\t * const n = 4;\n\t * message.spliceEmbeds(0, n);\n\t * ```\n\t * @example\n\t * Remove the last embed:\n\t * ```ts\n\t * message.spliceEmbeds(-1, 1);\n\t * ```\n\t * @param start - The index to start at\n\t * @param deleteCount - The amount of embeds to remove\n\t * @param embeds - The embeds to insert\n\t */\n\tpublic spliceEmbeds(\n\t\tstart: number,\n\t\tdeleteCount: number,\n\t\t...embeds: RestOrArray<APIEmbed | EmbedBuilder | ((builder: EmbedBuilder) => EmbedBuilder)>\n\t): this {\n\t\tthis.data.embeds ??= [];\n\t\tconst resolved = normalizeArray(embeds).map((embed) => resolveBuilder(embed, EmbedBuilder));\n\n\t\tthis.data.embeds.splice(start, deleteCount, ...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the embeds for this message.\n\t *\n\t * @param embeds - The embeds to set\n\t */\n\tpublic setEmbeds(...embeds: RestOrArray<APIEmbed | EmbedBuilder | ((builder: EmbedBuilder) => EmbedBuilder)>): this {\n\t\treturn this.spliceEmbeds(0, this.embeds.length, ...normalizeArray(embeds));\n\t}\n\n\t/**\n\t * Sets the allowed mentions for this message.\n\t *\n\t * @param allowedMentions - The allowed mentions to set\n\t */\n\tpublic setAllowedMentions(\n\t\tallowedMentions:\n\t\t\t| AllowedMentionsBuilder\n\t\t\t| APIAllowedMentions\n\t\t\t| ((builder: AllowedMentionsBuilder) => AllowedMentionsBuilder) = new AllowedMentionsBuilder(),\n\t): this {\n\t\tthis.data.allowed_mentions = resolveBuilder(allowedMentions, AllowedMentionsBuilder);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Updates the allowed mentions for this message (and creates it if it doesn't exist)\n\t *\n\t * @param updater - The function to update the allowed mentions with\n\t */\n\tpublic updateAllowedMentions(updater: (builder: AllowedMentionsBuilder) => void): this {\n\t\tupdater((this.data.allowed_mentions ??= new AllowedMentionsBuilder()));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the allowed mentions for this message.\n\t */\n\tpublic clearAllowedMentions(): this {\n\t\tthis.data.allowed_mentions = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the message reference for this message.\n\t *\n\t * @param reference - The reference to set\n\t */\n\tpublic setMessageReference(\n\t\treference:\n\t\t\t| APIMessageReference\n\t\t\t| MessageReferenceBuilder\n\t\t\t| ((builder: MessageReferenceBuilder) => MessageReferenceBuilder),\n\t): this {\n\t\tthis.data.message_reference = resolveBuilder(reference, MessageReferenceBuilder);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Updates the message reference for this message (and creates it if it doesn't exist)\n\t *\n\t * @param updater - The function to update the message reference with\n\t */\n\tpublic updateMessageReference(updater: (builder: MessageReferenceBuilder) => void): this {\n\t\tupdater((this.data.message_reference ??= new MessageReferenceBuilder()));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the message reference for this message.\n\t */\n\tpublic clearMessageReference(): this {\n\t\tthis.data.message_reference = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds action row components to this message.\n\t *\n\t * @param components - The action row components to add\n\t */\n\tpublic addActionRowComponents(\n\t\t...components: RestOrArray<\n\t\t\t| ActionRowBuilder\n\t\t\t| APIActionRowComponent<APIComponentInMessageActionRow>\n\t\t\t| ((builder: ActionRowBuilder) => ActionRowBuilder)\n\t\t>\n\t): this {\n\t\tthis.data.components ??= [];\n\n\t\tconst resolved = normalizeArray(components).map((component) => resolveBuilder(component, ActionRowBuilder));\n\t\tthis.data.components.push(...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds container components to this message.\n\t *\n\t * @param components - The container components to add\n\t */\n\tpublic addContainerComponents(\n\t\t...components: RestOrArray<\n\t\t\tAPIContainerComponent | ContainerBuilder | ((builder: ContainerBuilder) => ContainerBuilder)\n\t\t>\n\t): this {\n\t\tthis.data.components ??= [];\n\n\t\tconst resolved = normalizeArray(components).map((component) => resolveBuilder(component, ContainerBuilder));\n\t\tthis.data.components.push(...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds file components to this message.\n\t *\n\t * @param components - The file components to add\n\t */\n\tpublic addFileComponents(\n\t\t...components: RestOrArray<APIFileComponent | FileBuilder | ((builder: FileBuilder) => FileBuilder)>\n\t): this {\n\t\tthis.data.components ??= [];\n\n\t\tconst resolved = normalizeArray(components).map((component) => resolveBuilder(component, FileBuilder));\n\t\tthis.data.components.push(...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds media gallery components to this message.\n\t *\n\t * @param components - The media gallery components to add\n\t */\n\tpublic addMediaGalleryComponents(\n\t\t...components: RestOrArray<\n\t\t\tAPIMediaGalleryComponent | MediaGalleryBuilder | ((builder: MediaGalleryBuilder) => MediaGalleryBuilder)\n\t\t>\n\t): this {\n\t\tthis.data.components ??= [];\n\n\t\tconst resolved = normalizeArray(components).map((component) => resolveBuilder(component, MediaGalleryBuilder));\n\t\tthis.data.components.push(...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds section components to this message.\n\t *\n\t * @param components - The section components to add\n\t */\n\tpublic addSectionComponents(\n\t\t...components: RestOrArray<APISectionComponent | SectionBuilder | ((builder: SectionBuilder) => SectionBuilder)>\n\t): this {\n\t\tthis.data.components ??= [];\n\n\t\tconst resolved = normalizeArray(components).map((component) => resolveBuilder(component, SectionBuilder));\n\t\tthis.data.components.push(...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds separator components to this message.\n\t *\n\t * @param components - The separator components to add\n\t */\n\tpublic addSeparatorComponents(\n\t\t...components: RestOrArray<\n\t\t\tAPISeparatorComponent | SeparatorBuilder | ((builder: SeparatorBuilder) => SeparatorBuilder)\n\t\t>\n\t): this {\n\t\tthis.data.components ??= [];\n\n\t\tconst resolved = normalizeArray(components).map((component) => resolveBuilder(component, SeparatorBuilder));\n\t\tthis.data.components.push(...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds text display components to this message.\n\t *\n\t * @param components - The text display components to add\n\t */\n\tpublic addTextDisplayComponents(\n\t\t...components: RestOrArray<\n\t\t\tAPITextDisplayComponent | TextDisplayBuilder | ((builder: TextDisplayBuilder) => TextDisplayBuilder)\n\t\t>\n\t): this {\n\t\tthis.data.components ??= [];\n\n\t\tconst resolved = normalizeArray(components).map((component) => resolveBuilder(component, TextDisplayBuilder));\n\t\tthis.data.components.push(...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes, replaces, or inserts components for this message.\n\t *\n\t * @remarks\n\t * This method behaves similarly\n\t * to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.\n\t *\n\t * It's useful for modifying and adjusting order of the already-existing components of a message.\n\t * @example\n\t * Remove the first component:\n\t * ```ts\n\t * message.spliceComponents(0, 1);\n\t * ```\n\t * @example\n\t * Remove the first n components:\n\t * ```ts\n\t * const n = 4;\n\t * message.spliceComponents(0, n);\n\t * ```\n\t * @example\n\t * Remove the last component:\n\t * ```ts\n\t * message.spliceComponents(-1, 1);\n\t * ```\n\t * @param start - The index to start at\n\t * @param deleteCount - The amount of components to remove\n\t * @param components - The components to insert\n\t */\n\tpublic spliceComponents(\n\t\tstart: number,\n\t\tdeleteCount: number,\n\t\t...components: RestOrArray<APIMessageTopLevelComponent | MessageTopLevelComponentBuilder>\n\t): this {\n\t\tthis.data.components ??= [];\n\t\tconst resolved = normalizeArray(components).map((component) =>\n\t\t\tcomponent instanceof ComponentBuilder ? component : createComponentBuilder(component),\n\t\t);\n\n\t\tthis.data.components.splice(start, deleteCount, ...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the sticker ids of this message.\n\t *\n\t * @param stickerIds - The ids of the stickers to set\n\t */\n\tpublic setStickerIds(...stickerIds: RestOrArray<Snowflake>): this {\n\t\treturn this.spliceStickerIds(0, this.data.sticker_ids?.length ?? 0, ...normalizeArray(stickerIds));\n\t}\n\n\t/**\n\t * Adds sticker ids to this message.\n\t *\n\t * @param stickerIds - The ids of the stickers to add\n\t */\n\tpublic addStickerIds(...stickerIds: RestOrArray<Snowflake>): this {\n\t\tthis.data.sticker_ids ??= [] as unknown as MessageBuilderData['sticker_ids'];\n\t\tthis.data.sticker_ids!.push(...normalizeArray(stickerIds));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes, replaces, or inserts sticker ids for this message.\n\t *\n\t * @remarks\n\t * This method behaves similarly\n\t * to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.\n\t *\n\t * It's useful for modifying and adjusting order of the already-existing sticker ids of a message.\n\t * @example\n\t * Remove the first sticker id:\n\t * ```ts\n\t * message.spliceStickerIds(0, 1);\n\t * ```\n\t * @example\n\t * Remove the first n sticker ids:\n\t * ```ts\n\t * const n = 4;\n\t * message.spliceStickerIds(0, n);\n\t * ```\n\t * @example\n\t * Remove the last sticker id:\n\t * ```ts\n\t * message.spliceStickerIds(-1, 1);\n\t * ```\n\t * @param index - The index to start at\n\t * @param deleteCount - The amount of sticker ids to remove\n\t * @param stickerIds - The sticker ids to insert\n\t */\n\tpublic spliceStickerIds(index: number, deleteCount: number, ...stickerIds: RestOrArray<Snowflake>): this {\n\t\tthis.data.sticker_ids ??= [] as unknown as MessageBuilderData['sticker_ids'];\n\t\tthis.data.sticker_ids!.splice(index, deleteCount, ...normalizeArray(stickerIds));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets attachments for this message.\n\t *\n\t * @param attachments - The attachments to set\n\t */\n\tpublic setAttachments(\n\t\t...attachments: RestOrArray<APIAttachment | AttachmentBuilder | ((builder: AttachmentBuilder) => AttachmentBuilder)>\n\t): this {\n\t\treturn this.spliceAttachments(0, this.data.attachments.length, ...normalizeArray(attachments));\n\t}\n\n\t/**\n\t * Adds attachments to this message.\n\t *\n\t * @param attachments - The attachments to add\n\t */\n\tpublic addAttachments(\n\t\t...attachments: RestOrArray<APIAttachment | AttachmentBuilder | ((builder: AttachmentBuilder) => AttachmentBuilder)>\n\t): this {\n\t\tconst resolved = normalizeArray(attachments).map((attachment) => resolveBuilder(attachment, AttachmentBuilder));\n\t\tthis.data.attachments.push(...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes, replaces, or inserts attachments for this message.\n\t *\n\t * @remarks\n\t * This method behaves similarly\n\t * to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.\n\t *\n\t * It's useful for modifying and adjusting order of the already-existing attachments of a message.\n\t * @example\n\t * Remove the first attachment:\n\t * ```ts\n\t * message.spliceAttachments(0, 1);\n\t * ```\n\t * @example\n\t * Remove the first n attachments:\n\t * ```ts\n\t * const n = 4;\n\t * message.spliceAttachments(0, n);\n\t * ```\n\t * @example\n\t * Remove the last attachment:\n\t * ```ts\n\t * message.spliceAttachments(-1, 1);\n\t * ```\n\t * @param start - The index to start at\n\t * @param deleteCount - The amount of attachments to remove\n\t * @param attachments - The attachments to insert\n\t */\n\tpublic spliceAttachments(\n\t\tstart: number,\n\t\tdeleteCount: number,\n\t\t...attachments: RestOrArray<APIAttachment | AttachmentBuilder | ((builder: AttachmentBuilder) => AttachmentBuilder)>\n\t): this {\n\t\tconst resolved = normalizeArray(attachments).map((attachment) => resolveBuilder(attachment, AttachmentBuilder));\n\t\tthis.data.attachments.splice(start, deleteCount, ...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the flags for this message.\n\t *\n\t * @param flags - The flags to set\n\t */\n\tpublic setFlags(flags: MessageFlags): this {\n\t\tthis.data.flags = flags;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the flags for this message.\n\t */\n\tpublic clearFlags(): this {\n\t\tthis.data.flags = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets whether to enforce recent uniqueness of the nonce of this message.\n\t *\n\t * @param enforceNonce - Whether to enforce recent uniqueness of the nonce of this message\n\t */\n\tpublic setEnforceNonce(enforceNonce = true): this {\n\t\tthis.data.enforce_nonce = enforceNonce;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the poll for this message.\n\t *\n\t * @param poll - The poll to set\n\t */\n\tpublic setPoll(poll: APIPoll | PollBuilder | ((builder: PollBuilder) => PollBuilder)): this {\n\t\tthis.data.poll = resolveBuilder(poll, PollBuilder);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Updates the poll for this message (and creates it if it doesn't exist)\n\t *\n\t * @param updater - The function to update the poll with\n\t */\n\tpublic updatePoll(updater: (builder: PollBuilder) => void): this {\n\t\tupdater((this.data.poll ??= new PollBuilder()));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the poll for this message.\n\t */\n\tpublic clearPoll(): this {\n\t\tthis.data.poll = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic toJSON(validationOverride?: boolean): RESTPostAPIChannelMessageJSONBody {\n\t\tconst { poll, allowed_mentions, attachments, embeds, components, message_reference, ...rest } = this.data;\n\n\t\tconst data = {\n\t\t\t...structuredClone(rest),\n\t\t\t// Wherever we pass false, it's covered by the messagePredicate already\n\t\t\tpoll: poll?.toJSON(false),\n\t\t\tallowed_mentions: allowed_mentions?.toJSON(false),\n\t\t\tattachments: attachments.map((attachment) => attachment.toJSON(false)),\n\t\t\tembeds: embeds.map((embed) => embed.toJSON(false)),\n\t\t\t// Here, the messagePredicate does specific constraints rather than using the componentPredicate\n\t\t\tcomponents: components.map((component) => component.toJSON(validationOverride)),\n\t\t\tmessage_reference: message_reference?.toJSON(false),\n\t\t};\n\n\t\tvalidate(messagePredicate, data, validationOverride);\n\n\t\treturn data as RESTPostAPIChannelMessageJSONBody;\n\t}\n\n\t/**\n\t * Serializes this builder to both JSON body and file data for multipart/form-data requests.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t * @remarks\n\t * This method extracts file data from attachments that have files set via {@link AttachmentBuilder.setFileData}.\n\t * The returned body includes attachment metadata, while files contains the binary data for upload.\n\t */\n\tpublic toFileBody(validationOverride?: boolean): FileBodyEncodableResult<RESTPostAPIChannelMessageJSONBody> {\n\t\tconst body = this.toJSON(false);\n\n\t\tconst files: RawFile[] = [];\n\t\tfor (const attachment of this.data.attachments) {\n\t\t\tconst rawFile = attachment.getRawFile();\n\t\t\t// Only if data or content type are set, since that implies the intent is to send a new file.\n\t\t\t// In case it's contentType but not data, a validation error will be thrown right after.\n\t\t\tif (rawFile?.data || rawFile?.contentType) {\n\t\t\t\tfiles.push(rawFile as RawFile);\n\t\t\t}\n\t\t}\n\n\t\tconst combined = { body, files };\n\t\tvalidate(fileBodyMessagePredicate, combined, validationOverride);\n\n\t\treturn combined as FileBodyEncodableResult<RESTPostAPIChannelMessageJSONBody>;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/messages/MessageReference.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type { MessageReferenceType, RESTAPIMessageReference, Snowflake } from 'discord-api-types/v10';\nimport { validate } from '../util/validation.js';\nimport { messageReferencePredicate } from './Assertions.js';\n\n/**\n * A builder that creates API-compatible JSON data for message references.\n */\nexport class MessageReferenceBuilder implements JSONEncodable<RESTAPIMessageReference> {\n\t/**\n\t * The API data associated with this message reference.\n\t */\n\tprivate readonly data: Partial<RESTAPIMessageReference>;\n\n\t/**\n\t * Creates a new message reference builder.\n\t *\n\t * @param data - The API data to create this message reference with\n\t */\n\tpublic constructor(data: Partial<RESTAPIMessageReference> = {}) {\n\t\tthis.data = structuredClone(data);\n\t}\n\n\t/**\n\t * Sets the type of message reference this represents\n\t *\n\t * @param type - The type of message reference\n\t */\n\tpublic setType(type: MessageReferenceType): this {\n\t\tthis.data.type = type;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clear the type of message reference this represents\n\t */\n\tpublic clearType(): this {\n\t\tthis.data.type = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the id of the message being referenced\n\t *\n\t * @param messageId - The id of the message being referenced\n\t */\n\tpublic setMessageId(messageId: Snowflake): this {\n\t\tthis.data.message_id = messageId;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the id of the channel being referenced\n\t *\n\t * @param channelId - The id of the channel being referenced\n\t */\n\tpublic setChannelId(channelId: Snowflake): this {\n\t\tthis.data.channel_id = channelId;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clear the id of the channel being referenced\n\t */\n\tpublic clearChannelId(): this {\n\t\tthis.data.channel_id = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the id of the guild being referenced\n\t *\n\t * @param guildId - The id of the guild being referenced\n\t */\n\tpublic setGuildId(guildId: Snowflake): this {\n\t\tthis.data.guild_id = guildId;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clear the id of the guild being referenced\n\t */\n\tpublic clearGuildId(): this {\n\t\tthis.data.guild_id = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets whether to fail the message creation if the referenced message does not exist\n\t *\n\t * @param failIfNotExists - Whether to fail the message creation if the referenced message does not exist\n\t */\n\tpublic setFailIfNotExists(failIfNotExists = true): this {\n\t\tthis.data.fail_if_not_exists = failIfNotExists;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic toJSON(validationOverride?: boolean): RESTAPIMessageReference {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(messageReferencePredicate, clone, validationOverride);\n\n\t\treturn clone as RESTAPIMessageReference;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/messages/embed/Assertions.ts",
    "content": "import { embedLength } from '@discordjs/util';\nimport { z } from 'zod';\n\nconst namePredicate = z.string().max(256);\n\nconst URLPredicate = z.url({ protocol: /^https?$/ });\n\nconst URLWithAttachmentProtocolPredicate = z.url({ protocol: /^(?:https?|attachment)$/ });\n\nexport const embedFieldPredicate = z.object({\n\tname: namePredicate,\n\tvalue: z.string().max(1_024),\n\tinline: z.boolean().optional(),\n});\n\nexport const embedAuthorPredicate = z.object({\n\tname: namePredicate.min(1),\n\ticon_url: URLWithAttachmentProtocolPredicate.optional(),\n\turl: URLPredicate.optional(),\n});\n\nexport const embedFooterPredicate = z.object({\n\ttext: z.string().min(1).max(2_048),\n\ticon_url: URLWithAttachmentProtocolPredicate.optional(),\n});\n\nexport const embedPredicate = z\n\t.object({\n\t\ttitle: namePredicate.min(1).optional(),\n\t\tdescription: z.string().min(1).max(4_096).optional(),\n\t\turl: URLPredicate.optional(),\n\t\ttimestamp: z.string().optional(),\n\t\tcolor: z.int().min(0).max(0xffffff).optional(),\n\t\tfooter: embedFooterPredicate.optional(),\n\t\timage: z.object({ url: URLWithAttachmentProtocolPredicate }).optional(),\n\t\tthumbnail: z.object({ url: URLWithAttachmentProtocolPredicate }).optional(),\n\t\tauthor: embedAuthorPredicate.optional(),\n\t\tfields: z.array(embedFieldPredicate).max(25).optional(),\n\t})\n\t.refine(\n\t\t(embed) =>\n\t\t\tembed.title !== undefined ||\n\t\t\tembed.description !== undefined ||\n\t\t\t(embed.fields !== undefined && embed.fields.length > 0) ||\n\t\t\tembed.footer !== undefined ||\n\t\t\tembed.author !== undefined ||\n\t\t\tembed.image !== undefined ||\n\t\t\tembed.thumbnail !== undefined,\n\t\t{\n\t\t\terror: 'Embed must have at least a title, description, a field, a footer, an author, an image, OR a thumbnail.',\n\t\t},\n\t)\n\t.refine((embed) => embedLength(embed) <= 6_000, { error: 'Embeds must not exceed 6000 characters in total.' });\n"
  },
  {
    "path": "packages/builders/src/messages/embed/Embed.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type { APIEmbed, APIEmbedAuthor, APIEmbedField, APIEmbedFooter } from 'discord-api-types/v10';\nimport type { RestOrArray } from '../../util/normalizeArray.js';\nimport { normalizeArray } from '../../util/normalizeArray.js';\nimport { resolveBuilder } from '../../util/resolveBuilder.js';\nimport { validate } from '../../util/validation.js';\nimport { embedPredicate } from './Assertions.js';\nimport { EmbedAuthorBuilder } from './EmbedAuthor.js';\nimport { EmbedFieldBuilder } from './EmbedField.js';\nimport { EmbedFooterBuilder } from './EmbedFooter.js';\n\n/**\n * Data stored in the process of constructing an embed.\n */\nexport interface EmbedBuilderData extends Omit<APIEmbed, 'author' | 'fields' | 'footer'> {\n\tauthor?: EmbedAuthorBuilder;\n\tfields: EmbedFieldBuilder[];\n\tfooter?: EmbedFooterBuilder;\n}\n\n/**\n * A builder that creates API-compatible JSON data for embeds.\n */\nexport class EmbedBuilder implements JSONEncodable<APIEmbed> {\n\t/**\n\t * The API data associated with this embed.\n\t */\n\tprivate readonly data: EmbedBuilderData;\n\n\t/**\n\t * Gets the fields of this embed.\n\t */\n\tpublic get fields(): readonly EmbedFieldBuilder[] {\n\t\treturn this.data.fields;\n\t}\n\n\t/**\n\t * Creates a new embed.\n\t *\n\t * @param data - The API data to create this embed with\n\t */\n\tpublic constructor(data: Partial<APIEmbed> = {}) {\n\t\tconst { author, fields = [], footer, ...rest } = data;\n\n\t\tthis.data = {\n\t\t\t...structuredClone(rest),\n\t\t\tauthor: author && new EmbedAuthorBuilder(author),\n\t\t\tfields: fields.map((field) => new EmbedFieldBuilder(field)),\n\t\t\tfooter: footer && new EmbedFooterBuilder(footer),\n\t\t};\n\t}\n\n\t/**\n\t * Appends fields to the embed.\n\t *\n\t * @remarks\n\t * This method accepts either an array of fields or a variable number of field parameters.\n\t * The maximum amount of fields that can be added is 25.\n\t * @example\n\t * Using an array:\n\t * ```ts\n\t * const fields: APIEmbedField[] = ...;\n\t * const embed = new EmbedBuilder()\n\t * \t.addFields(fields);\n\t * ```\n\t * @example\n\t * Using rest parameters (variadic):\n\t * ```ts\n\t * const embed = new EmbedBuilder()\n\t * \t.addFields(\n\t * \t\t{ name: 'Field 1', value: 'Value 1' },\n\t * \t\t{ name: 'Field 2', value: 'Value 2' },\n\t * \t);\n\t * ```\n\t * @param fields - The fields to add\n\t */\n\tpublic addFields(\n\t\t...fields: RestOrArray<APIEmbedField | EmbedFieldBuilder | ((builder: EmbedFieldBuilder) => EmbedFieldBuilder)>\n\t): this {\n\t\tconst normalizedFields = normalizeArray(fields);\n\t\tconst resolved = normalizedFields.map((field) => resolveBuilder(field, EmbedFieldBuilder));\n\n\t\tthis.data.fields.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes, replaces, or inserts fields for this embed.\n\t *\n\t * @remarks\n\t * This method behaves similarly\n\t * to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.\n\t * The maximum amount of fields that can be added is 25.\n\t *\n\t * It's useful for modifying and adjusting order of the already-existing fields of an embed.\n\t * @example\n\t * Remove the first field:\n\t * ```ts\n\t * embed.spliceFields(0, 1);\n\t * ```\n\t * @example\n\t * Remove the first n fields:\n\t * ```ts\n\t * const n = 4;\n\t * embed.spliceFields(0, n);\n\t * ```\n\t * @example\n\t * Remove the last field:\n\t * ```ts\n\t * embed.spliceFields(-1, 1);\n\t * ```\n\t * @param index - The index to start at\n\t * @param deleteCount - The number of fields to remove\n\t * @param fields - The replacing field objects\n\t */\n\tpublic spliceFields(\n\t\tindex: number,\n\t\tdeleteCount: number,\n\t\t...fields: (APIEmbedField | EmbedFieldBuilder | ((builder: EmbedFieldBuilder) => EmbedFieldBuilder))[]\n\t): this {\n\t\tconst resolved = fields.map((field) => resolveBuilder(field, EmbedFieldBuilder));\n\t\tthis.data.fields.splice(index, deleteCount, ...resolved);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the fields for this embed.\n\t *\n\t * @remarks\n\t * This method is an alias for {@link EmbedBuilder.spliceFields}. More specifically,\n\t * it splices the entire array of fields, replacing them with the provided fields.\n\t *\n\t * You can set a maximum of 25 fields.\n\t * @param fields - The fields to set\n\t */\n\tpublic setFields(\n\t\t...fields: RestOrArray<APIEmbedField | EmbedFieldBuilder | ((builder: EmbedFieldBuilder) => EmbedFieldBuilder)>\n\t): this {\n\t\tthis.spliceFields(0, this.data.fields.length, ...normalizeArray(fields));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the author of this embed.\n\t *\n\t * @param options - The options to use\n\t */\n\tpublic setAuthor(\n\t\toptions: APIEmbedAuthor | EmbedAuthorBuilder | ((builder: EmbedAuthorBuilder) => EmbedAuthorBuilder),\n\t): this {\n\t\tthis.data.author = resolveBuilder(options, EmbedAuthorBuilder);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Updates the author of this embed (and creates it if it doesn't exist).\n\t *\n\t * @param updater - The function to update the author with\n\t */\n\tpublic updateAuthor(updater: (builder: EmbedAuthorBuilder) => void) {\n\t\tupdater((this.data.author ??= new EmbedAuthorBuilder()));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the author of this embed.\n\t */\n\tpublic clearAuthor(): this {\n\t\tthis.data.author = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the color of this embed.\n\t *\n\t * @param color - The color to use\n\t */\n\tpublic setColor(color: number): this {\n\t\tthis.data.color = color;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the color of this embed.\n\t */\n\tpublic clearColor(): this {\n\t\tthis.data.color = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the description of this embed.\n\t *\n\t * @param description - The description to use\n\t */\n\tpublic setDescription(description: string): this {\n\t\tthis.data.description = description;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the description of this embed.\n\t */\n\tpublic clearDescription(): this {\n\t\tthis.data.description = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the footer of this embed.\n\t *\n\t * @param options - The footer to use\n\t */\n\tpublic setFooter(\n\t\toptions: APIEmbedFooter | EmbedFooterBuilder | ((builder: EmbedFooterBuilder) => EmbedFooterBuilder),\n\t): this {\n\t\tthis.data.footer = resolveBuilder(options, EmbedFooterBuilder);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Updates the footer of this embed (and creates it if it doesn't exist).\n\t *\n\t * @param updater - The function to update the footer with\n\t */\n\tpublic updateFooter(updater: (builder: EmbedFooterBuilder) => void) {\n\t\tupdater((this.data.footer ??= new EmbedFooterBuilder()));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the footer of this embed.\n\t */\n\tpublic clearFooter(): this {\n\t\tthis.data.footer = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the image of this embed.\n\t *\n\t * @param url - The image URL to use\n\t */\n\tpublic setImage(url: string): this {\n\t\tthis.data.image = { url };\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the image of this embed.\n\t */\n\tpublic clearImage(): this {\n\t\tthis.data.image = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the thumbnail of this embed.\n\t *\n\t * @param url - The thumbnail URL to use\n\t */\n\tpublic setThumbnail(url: string): this {\n\t\tthis.data.thumbnail = { url };\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the thumbnail of this embed.\n\t */\n\tpublic clearThumbnail(): this {\n\t\tthis.data.thumbnail = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the timestamp of this embed.\n\t *\n\t * @param timestamp - The timestamp or date to use\n\t */\n\tpublic setTimestamp(timestamp: Date | number | string = Date.now()): this {\n\t\tthis.data.timestamp = new Date(timestamp).toISOString();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the timestamp of this embed.\n\t */\n\tpublic clearTimestamp(): this {\n\t\tthis.data.timestamp = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the title for this embed.\n\t *\n\t * @param title - The title to use\n\t */\n\tpublic setTitle(title: string): this {\n\t\tthis.data.title = title;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the title of this embed.\n\t */\n\tpublic clearTitle(): this {\n\t\tthis.data.title = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the URL of this embed.\n\t *\n\t * @param url - The URL to use\n\t */\n\tpublic setURL(url: string): this {\n\t\tthis.data.url = url;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the URL of this embed.\n\t */\n\tpublic clearURL(): this {\n\t\tthis.data.url = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic toJSON(validationOverride?: boolean): APIEmbed {\n\t\tconst { author, fields, footer, ...rest } = this.data;\n\n\t\tconst data = {\n\t\t\t...structuredClone(rest),\n\t\t\t// Disable validation because the embedPredicate below will validate those as well\n\t\t\tauthor: author?.toJSON(false),\n\t\t\tfields: fields.map((field) => field.toJSON(false)),\n\t\t\tfooter: footer?.toJSON(false),\n\t\t};\n\n\t\tvalidate(embedPredicate, data, validationOverride);\n\n\t\treturn data;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/messages/embed/EmbedAuthor.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type { APIEmbedAuthor } from 'discord-api-types/v10';\nimport { validate } from '../../util/validation.js';\nimport { embedAuthorPredicate } from './Assertions.js';\n\n/**\n * A builder that creates API-compatible JSON data for the embed author.\n */\nexport class EmbedAuthorBuilder implements JSONEncodable<APIEmbedAuthor> {\n\t/**\n\t * The API data associated with this embed author.\n\t */\n\tprivate readonly data: Partial<APIEmbedAuthor>;\n\n\t/**\n\t * Creates a new embed author.\n\t *\n\t * @param data - The API data to create this embed author with\n\t */\n\tpublic constructor(data: Partial<APIEmbedAuthor> = {}) {\n\t\tthis.data = structuredClone(data);\n\t}\n\n\t/**\n\t * Sets the name for this embed author.\n\t *\n\t * @param name - The name to use\n\t */\n\tpublic setName(name: string): this {\n\t\tthis.data.name = name;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the URL for this embed author.\n\t *\n\t * @param url - The url to use\n\t */\n\tpublic setURL(url: string): this {\n\t\tthis.data.url = url;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the URL for this embed author.\n\t */\n\tpublic clearURL(): this {\n\t\tthis.data.url = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the icon URL for this embed author.\n\t *\n\t * @param iconURL - The icon URL to use\n\t */\n\tpublic setIconURL(iconURL: string): this {\n\t\tthis.data.icon_url = iconURL;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the icon URL for this embed author.\n\t */\n\tpublic clearIconURL(): this {\n\t\tthis.data.icon_url = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic toJSON(validationOverride?: boolean): APIEmbedAuthor {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(embedAuthorPredicate, clone, validationOverride);\n\n\t\treturn clone as APIEmbedAuthor;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/messages/embed/EmbedField.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type { APIEmbedField } from 'discord-api-types/v10';\nimport { validate } from '../../util/validation.js';\nimport { embedFieldPredicate } from './Assertions.js';\n\n/**\n * A builder that creates API-compatible JSON data for embed fields.\n */\nexport class EmbedFieldBuilder implements JSONEncodable<APIEmbedField> {\n\t/**\n\t * The API data associated with this embed field.\n\t */\n\tprivate readonly data: Partial<APIEmbedField>;\n\n\t/**\n\t * Creates a new embed field.\n\t *\n\t * @param data - The API data to create this embed field with\n\t */\n\tpublic constructor(data: Partial<APIEmbedField> = {}) {\n\t\tthis.data = structuredClone(data);\n\t}\n\n\t/**\n\t * Sets the name for this embed field.\n\t *\n\t * @param name - The name to use\n\t */\n\tpublic setName(name: string): this {\n\t\tthis.data.name = name;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the value for this embed field.\n\t *\n\t * @param value - The value to use\n\t */\n\tpublic setValue(value: string): this {\n\t\tthis.data.value = value;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets whether this field should display inline.\n\t *\n\t * @param inline - Whether this field should display inline\n\t */\n\tpublic setInline(inline = true): this {\n\t\tthis.data.inline = inline;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic toJSON(validationOverride?: boolean): APIEmbedField {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(embedFieldPredicate, clone, validationOverride);\n\n\t\treturn clone as APIEmbedField;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/messages/embed/EmbedFooter.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type { APIEmbedFooter } from 'discord-api-types/v10';\nimport { validate } from '../../util/validation.js';\nimport { embedFooterPredicate } from './Assertions.js';\n\n/**\n * A builder that creates API-compatible JSON data for the embed footer.\n */\nexport class EmbedFooterBuilder implements JSONEncodable<APIEmbedFooter> {\n\t/**\n\t * The API data associated with this embed footer.\n\t */\n\tprivate readonly data: Partial<APIEmbedFooter>;\n\n\t/**\n\t * Creates a new embed footer.\n\t *\n\t * @param data - The API data to create this embed footer with\n\t */\n\tpublic constructor(data: Partial<APIEmbedFooter> = {}) {\n\t\tthis.data = structuredClone(data);\n\t}\n\n\t/**\n\t * Sets the text for this embed footer.\n\t *\n\t * @param text - The text to use\n\t */\n\tpublic setText(text: string): this {\n\t\tthis.data.text = text;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the url for this embed footer.\n\t *\n\t * @param url - The url to use\n\t */\n\tpublic setIconURL(url: string): this {\n\t\tthis.data.icon_url = url;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the icon URL for this embed footer.\n\t */\n\tpublic clearIconURL(): this {\n\t\tthis.data.icon_url = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic toJSON(validationOverride?: boolean): APIEmbedFooter {\n\t\tconst clone = structuredClone(this.data);\n\t\tvalidate(embedFooterPredicate, clone, validationOverride);\n\n\t\treturn clone as APIEmbedFooter;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/messages/poll/Assertions.ts",
    "content": "import { PollLayoutType } from 'discord-api-types/v10';\nimport { z } from 'zod';\nimport { emojiPredicate } from '../../components/Assertions';\n\nexport const pollQuestionPredicate = z.object({ text: z.string().min(1).max(300) });\n\nexport const pollAnswerMediaPredicate = z.object({\n\ttext: z.string().min(1).max(55),\n\temoji: emojiPredicate.optional(),\n});\n\nexport const pollAnswerPredicate = z.object({ poll_media: pollAnswerMediaPredicate });\n\nexport const pollPredicate = z.object({\n\tquestion: pollQuestionPredicate,\n\tanswers: z.array(pollAnswerPredicate).min(1).max(10),\n\tduration: z.number().min(1).max(768).optional(),\n\tallow_multiselect: z.boolean().optional(),\n\tlayout_type: z.enum(PollLayoutType).optional(),\n});\n"
  },
  {
    "path": "packages/builders/src/messages/poll/Poll.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type { RESTAPIPoll, APIPollMedia, PollLayoutType, APIPollAnswer } from 'discord-api-types/v10';\nimport { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';\nimport { resolveBuilder } from '../../util/resolveBuilder.js';\nimport { validate } from '../../util/validation.js';\nimport { pollPredicate } from './Assertions';\nimport { PollAnswerBuilder } from './PollAnswer.js';\nimport { PollQuestionBuilder } from './PollQuestion.js';\n\nexport interface PollData extends Omit<RESTAPIPoll, 'answers' | 'question'> {\n\tanswers: PollAnswerBuilder[];\n\tquestion: PollQuestionBuilder;\n}\n\n/**\n * A builder that creates API-compatible JSON data for polls.\n */\nexport class PollBuilder implements JSONEncodable<RESTAPIPoll> {\n\t/**\n\t * The API data associated with this poll.\n\t */\n\tprivate readonly data: PollData;\n\n\t/**\n\t * Gets the answers of this poll.\n\t */\n\tpublic get answers(): readonly PollAnswerBuilder[] {\n\t\treturn this.data.answers;\n\t}\n\n\t/**\n\t * Creates a new poll.\n\t *\n\t * @param data - The API data to create this poll with\n\t */\n\tpublic constructor(data: Partial<RESTAPIPoll> = {}) {\n\t\tconst { question, answers = [], ...rest } = data;\n\n\t\tthis.data = {\n\t\t\t...structuredClone(rest),\n\t\t\tquestion: new PollQuestionBuilder(question),\n\t\t\tanswers: answers.map((answer) => new PollAnswerBuilder(answer)),\n\t\t};\n\t}\n\n\t/**\n\t * Appends answers to the poll.\n\t *\n\t * @remarks\n\t * This method accepts either an array of answers or a variable number of answer parameters.\n\t * The maximum amount of answers that can be added is 10.\n\t * @example\n\t * Using an array:\n\t * ```ts\n\t * const answers: APIPollMedia[] = ...;\n\t * const poll = new PollBuilder()\n\t * \t.addAnswers(answers);\n\t * ```\n\t * @example\n\t * Using rest parameters (variadic):\n\t * ```ts\n\t * const poll = new PollBuilder()\n\t * \t.addAnswers(\n\t * \t\t{ text: 'Answer 1' },\n\t * \t\t{ text: 'Answer 2' },\n\t * \t);\n\t * ```\n\t * @param answers - The answers to add\n\t */\n\tpublic addAnswers(\n\t\t...answers: RestOrArray<\n\t\t\tOmit<APIPollAnswer, 'answer_id'> | PollAnswerBuilder | ((builder: PollAnswerBuilder) => PollAnswerBuilder)\n\t\t>\n\t): this {\n\t\tconst normalizedAnswers = normalizeArray(answers);\n\t\tconst resolved = normalizedAnswers.map((answer) => resolveBuilder(answer, PollAnswerBuilder));\n\n\t\tthis.data.answers.push(...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes, replaces, or inserts answers for this poll.\n\t *\n\t * @remarks\n\t * This method behaves similarly\n\t * to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.\n\t * The maximum amount of answers that can be added is 10.\n\t *\n\t * It's useful for modifying and adjusting order of the already-existing answers of a poll.\n\t * @example\n\t * Remove the first answer:\n\t * ```ts\n\t * poll.spliceAnswers(0, 1);\n\t * ```\n\t * @example\n\t * Remove the first n answers:\n\t * ```ts\n\t * const n = 4;\n\t * poll.spliceAnswers(0, n);\n\t * ```\n\t * @example\n\t * Remove the last answer:\n\t * ```ts\n\t * poll.spliceAnswers(-1, 1);\n\t * ```\n\t * @param index - The index to start at\n\t * @param deleteCount - The number of answers to remove\n\t * @param answers - The replacing answer objects\n\t */\n\tpublic spliceAnswers(\n\t\tindex: number,\n\t\tdeleteCount: number,\n\t\t...answers: (\n\t\t\t| Omit<APIPollAnswer, 'answer_id'>\n\t\t\t| PollAnswerBuilder\n\t\t\t| ((builder: PollAnswerBuilder) => PollAnswerBuilder)\n\t\t)[]\n\t): this {\n\t\tconst normalizedAnswers = normalizeArray(answers);\n\t\tconst resolved = normalizedAnswers.map((answer) => resolveBuilder(answer, PollAnswerBuilder));\n\n\t\tthis.data.answers.splice(index, deleteCount, ...resolved);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the answers for this poll.\n\t *\n\t * @remarks\n\t * This method is an alias for {@link PollBuilder.spliceAnswers}. More specifically,\n\t * it splices the entire array of answers, replacing them with the provided answers.\n\t *\n\t * You can set a maximum of 10 answers.\n\t * @param answers - The answers to set\n\t */\n\tpublic setAnswers(\n\t\t...answers: RestOrArray<\n\t\t\tOmit<APIPollAnswer, 'answer_id'> | PollAnswerBuilder | ((builder: PollAnswerBuilder) => PollAnswerBuilder)\n\t\t>\n\t): this {\n\t\treturn this.spliceAnswers(0, this.data.answers.length, ...normalizeArray(answers));\n\t}\n\n\t/**\n\t * Sets the question for this poll.\n\t *\n\t * @param options - The data to use for this poll's question\n\t */\n\tpublic setQuestion(\n\t\toptions:\n\t\t\t| Omit<APIPollMedia, 'emoji'>\n\t\t\t| PollQuestionBuilder\n\t\t\t| ((builder: PollQuestionBuilder) => PollQuestionBuilder),\n\t): this {\n\t\tthis.data.question = resolveBuilder(options, PollQuestionBuilder);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Updates the question of this poll.\n\t *\n\t * @param updater - The function to update the question with\n\t */\n\tpublic updateQuestion(updater: (builder: PollQuestionBuilder) => void): this {\n\t\tupdater(this.data.question);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the layout type for this poll.\n\t *\n\t * @remarks\n\t * This method is redundant while only one type of poll layout exists (`PollLayoutType.Default`)\n\t * with Discord using that as the layout type if none is specified.\n\t * @param type - The type of poll layout to use\n\t */\n\tpublic setLayoutType(type: PollLayoutType): this {\n\t\tthis.data.layout_type = type;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the layout type for this poll.\n\t */\n\tpublic clearLayoutType(): this {\n\t\tthis.data.layout_type = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets whether multi-select is enabled for this poll.\n\t *\n\t * @param multiSelect - Whether to allow multi-select\n\t */\n\tpublic setMultiSelect(multiSelect = true): this {\n\t\tthis.data.allow_multiselect = multiSelect;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets how long this poll will be open for in hours.\n\t *\n\t * @remarks\n\t * Minimum duration is `1`, with maximum duration being `768` (32 days).\n\t * Default if none specified is `24` (one day).\n\t * @param duration - The amount of hours this poll will be open for\n\t */\n\tpublic setDuration(duration: number): this {\n\t\tthis.data.duration = duration;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the duration for this poll.\n\t */\n\tpublic clearDuration(): this {\n\t\tthis.data.duration = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic toJSON(validationOverride?: boolean): RESTAPIPoll {\n\t\tconst { answers, question, ...rest } = this.data;\n\n\t\tconst data = {\n\t\t\t...structuredClone(rest),\n\t\t\t// Disable validation because the pollPredicate below will validate those as well\n\t\t\tanswers: answers.map((answer) => answer.toJSON(false)),\n\t\t\tquestion: question.toJSON(false),\n\t\t};\n\n\t\tvalidate(pollPredicate, data, validationOverride);\n\n\t\treturn data;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/messages/poll/PollAnswer.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\nimport type { APIPollAnswer, APIPollMedia } from 'discord-api-types/v10';\nimport { resolveBuilder } from '../../util/resolveBuilder';\nimport { validate } from '../../util/validation';\nimport { pollAnswerPredicate } from './Assertions';\nimport { PollAnswerMediaBuilder } from './PollAnswerMedia';\n\nexport interface PollAnswerData extends Omit<APIPollAnswer, 'answer_id' | 'poll_media'> {\n\tpoll_media: PollAnswerMediaBuilder;\n}\n\n/**\n * A builder that creates API-compatible JSON data for poll answers.\n */\nexport class PollAnswerBuilder implements JSONEncodable<Omit<APIPollAnswer, 'answer_id'>> {\n\t/**\n\t * The API data associated with this poll answer.\n\t */\n\tprivate readonly data: PollAnswerData;\n\n\t/**\n\t * Creates a new poll answer.\n\t *\n\t * @param data - The API data to create this poll answer with\n\t */\n\tpublic constructor(data: Partial<Omit<APIPollAnswer, 'answer_id'>> = {}) {\n\t\tconst { poll_media, ...rest } = data;\n\n\t\tthis.data = {\n\t\t\t...structuredClone(rest),\n\t\t\tpoll_media: new PollAnswerMediaBuilder(poll_media),\n\t\t};\n\t}\n\n\t/**\n\t * Sets the media for this poll answer.\n\t *\n\t * @param options - The data to use for this poll answer's media\n\t */\n\tpublic setMedia(\n\t\toptions: APIPollMedia | PollAnswerMediaBuilder | ((builder: PollAnswerMediaBuilder) => PollAnswerMediaBuilder),\n\t): this {\n\t\tthis.data.poll_media = resolveBuilder(options, PollAnswerMediaBuilder);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Updates the media of this poll answer.\n\t *\n\t * @param updater - The function to update the media with\n\t */\n\tpublic updateMedia(updater: (builder: PollAnswerMediaBuilder) => void): this {\n\t\tupdater(this.data.poll_media);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic toJSON(validationOverride?: boolean): Omit<APIPollAnswer, 'answer_id'> {\n\t\tconst { poll_media, ...rest } = this.data;\n\n\t\tconst data = {\n\t\t\t...structuredClone(rest),\n\t\t\t// Disable validation because the pollAnswerPredicate below will validate this as well\n\t\t\tpoll_media: poll_media.toJSON(false),\n\t\t};\n\n\t\tvalidate(pollAnswerPredicate, data, validationOverride);\n\n\t\treturn data;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/messages/poll/PollAnswerMedia.ts",
    "content": "import type { APIPartialEmoji, APIPollMedia } from 'discord-api-types/v10';\nimport { validate } from '../../util/validation.js';\nimport { pollAnswerMediaPredicate } from './Assertions.js';\nimport { PollMediaBuilder } from './PollMedia.js';\n\n/**\n * A builder that creates API-compatible JSON data for the media of a poll answer.\n */\nexport class PollAnswerMediaBuilder extends PollMediaBuilder {\n\t/**\n\t * Sets the emoji for this poll answer media.\n\t *\n\t * @param emoji - The emoji to use\n\t */\n\tpublic setEmoji(emoji: APIPartialEmoji): this {\n\t\tthis.data.emoji = emoji;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clears the emoji for this poll answer media.\n\t */\n\tpublic clearEmoji(): this {\n\t\tthis.data.emoji = undefined;\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@inheritDoc PollMediaBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): APIPollMedia {\n\t\tconst clone = structuredClone(this.data);\n\n\t\tvalidate(pollAnswerMediaPredicate, clone, validationOverride);\n\n\t\treturn clone;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/messages/poll/PollMedia.ts",
    "content": "import type { APIPollMedia } from 'discord-api-types/v10';\n\n/**\n * The base poll media builder that contains common symbols for poll media builders.\n */\nexport abstract class PollMediaBuilder {\n\t/**\n\t * The API data associated with this poll media.\n\t *\n\t * @internal\n\t */\n\tprotected readonly data: Partial<APIPollMedia>;\n\n\t/**\n\t * Creates new poll media.\n\t *\n\t * @param data - The API data to create this poll media with\n\t */\n\tpublic constructor(data: Partial<APIPollMedia> = {}) {\n\t\tthis.data = structuredClone(data);\n\t}\n\n\t/**\n\t * Sets the text for this poll media.\n\t *\n\t * @param text - The text to use\n\t */\n\tpublic setText(text: string): this {\n\t\tthis.data.text = text;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Serializes this builder to API-compatible JSON data.\n\t *\n\t * Note that by disabling validation, there is no guarantee that the resulting object will be valid.\n\t *\n\t * @param validationOverride - Force validation to run/not run regardless of your global preference\n\t */\n\tpublic abstract toJSON(validationOverride?: boolean): APIPollMedia;\n}\n"
  },
  {
    "path": "packages/builders/src/messages/poll/PollQuestion.ts",
    "content": "import type { APIPollMedia } from 'discord-api-types/v10';\nimport { validate } from '../../util/validation.js';\nimport { pollQuestionPredicate } from './Assertions.js';\nimport { PollMediaBuilder } from './PollMedia.js';\n\n/**\n * A builder that creates API-compatible JSON data for a poll question.\n */\nexport class PollQuestionBuilder extends PollMediaBuilder {\n\t/**\n\t * {@inheritDoc PollMediaBuilder.toJSON}\n\t */\n\tpublic override toJSON(validationOverride?: boolean): Omit<APIPollMedia, 'emoji'> {\n\t\tconst clone = structuredClone(this.data);\n\n\t\tvalidate(pollQuestionPredicate, clone, validationOverride);\n\n\t\treturn clone;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/util/ValidationError.ts",
    "content": "import { z } from 'zod';\n\n/**\n * An error that is thrown when validation fails.\n */\nexport class ValidationError extends Error {\n\t/**\n\t * The underlying cause of the validation error.\n\t */\n\tpublic override readonly cause: z.ZodError;\n\n\t/**\n\t * @internal\n\t */\n\tpublic constructor(error: z.ZodError) {\n\t\tsuper(z.prettifyError(error));\n\n\t\tthis.name = 'ValidationError';\n\t\tthis.cause = error;\n\t}\n}\n"
  },
  {
    "path": "packages/builders/src/util/normalizeArray.ts",
    "content": "/**\n * Normalizes data that is a rest parameter or an array into an array with a depth of 1.\n *\n * @typeParam ItemType - The data that must satisfy {@link RestOrArray}.\n * @param arr - The (possibly variadic) data to normalize\n */\nexport function normalizeArray<ItemType>(arr: RestOrArray<ItemType>): ItemType[] {\n\tif (Array.isArray(arr[0])) return [...arr[0]];\n\treturn arr as ItemType[];\n}\n\n/**\n * Represents data that may be an array or came from a rest parameter.\n *\n * @remarks\n * This type is used throughout builders to ensure both an array and variadic arguments\n * may be used. It is normalized with {@link normalizeArray}.\n */\nexport type RestOrArray<Type> = Type[] | [Type[]];\n"
  },
  {
    "path": "packages/builders/src/util/resolveBuilder.ts",
    "content": "import type { JSONEncodable } from '@discordjs/util';\n\n/**\n * @privateRemarks\n * This is a type-guard util, because if you were to in-line `builder instanceof Constructor` in the `resolveBuilder`\n * function, TS doesn't narrow out the type `Builder`, causing a type error on the last return statement.\n * @internal\n */\nfunction isBuilder<Builder extends JSONEncodable<any>>(\n\tbuilder: unknown,\n\tConstructor: new () => Builder,\n): builder is Builder {\n\treturn builder instanceof Constructor;\n}\n\n/**\n * \"Resolves\" a builder from the 3 ways it can be input:\n * 1. A clean instance\n * 2. A data object that can be used to construct the builder\n * 3. A function that takes a builder and returns a builder e.g. `builder => builder.setFoo('bar')`\n *\n * @typeParam Builder - The builder type\n * @typeParam BuilderData - The data object that can be used to construct the builder\n * @param builder - The user input, as described in the function description\n * @param Constructor - The constructor of the builder\n */\nexport function resolveBuilder<Builder extends JSONEncodable<any>, BuilderData extends Record<PropertyKey, any>>(\n\tbuilder: Builder | BuilderData | ((builder: Builder) => Builder),\n\tConstructor: new (data?: BuilderData) => Builder,\n): Builder {\n\tif (isBuilder(builder, Constructor)) {\n\t\treturn builder;\n\t}\n\n\tif (typeof builder === 'function') {\n\t\treturn builder(new Constructor());\n\t}\n\n\treturn new Constructor(builder);\n}\n"
  },
  {
    "path": "packages/builders/src/util/validation.ts",
    "content": "import type { z } from 'zod';\nimport { ValidationError } from './ValidationError.js';\n\nlet validationEnabled = true;\n\n/**\n * Enables validators.\n *\n * @returns Whether validation is occurring.\n */\nexport function enableValidators() {\n\treturn (validationEnabled = true);\n}\n\n/**\n * Disables validators.\n *\n * @returns Whether validation is occurring.\n */\nexport function disableValidators() {\n\treturn (validationEnabled = false);\n}\n\n/**\n * Checks whether validation is occurring.\n */\nexport function isValidationEnabled() {\n\treturn validationEnabled;\n}\n\n/**\n * Parses a value with a given validator, accounting for whether validation is enabled.\n *\n * @param validator - The zod validator to use\n * @param value - The value to parse\n * @param validationOverride - Force validation to run/not run regardless of your global preference\n * @returns The result from parsing\n * @throws {@link ValidationError}\n * Throws if the value does not pass validation, if enabled.\n * @internal\n */\nexport function validate<Validator extends z.ZodType>(\n\tvalidator: Validator,\n\tvalue: unknown,\n\tvalidationOverride?: boolean,\n): z.output<Validator> {\n\tif (validationOverride === false || (validationOverride === undefined && !isValidationEnabled())) {\n\t\treturn value as z.output<Validator>;\n\t}\n\n\tconst result = validator.safeParse(value);\n\n\tif (!result.success) {\n\t\tthrow new ValidationError(result.error);\n\t}\n\n\treturn result.data;\n}\n"
  },
  {
    "path": "packages/builders/tsconfig.docs.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.docs.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist-docs\",\n\t\t\"exactOptionalPropertyTypes\": false\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/builders/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/builders/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"emitDecoratorMetadata\": true,\n\t\t\"exactOptionalPropertyTypes\": false\n\t},\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/builders/tsconfig.test.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"noEmit\": true,\n\t\t\"skipLibCheck\": true\n\t},\n\t\"include\": [\"__tests__/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/builders/tsdoc.json",
    "content": "{\n\t\"$schema\": \"https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json\",\n\t\"extends\": [\"@discordjs/api-extractor/extends/tsdoc-base.json\"]\n}\n"
  },
  {
    "path": "packages/builders/tsup.config.ts",
    "content": "import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector';\nimport { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tesbuildPlugins: [esbuildPluginVersionInjector()],\n});\n"
  },
  {
    "path": "packages/collection/.cliff-jumperrc.json",
    "content": "{\n\t\"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n\t\"name\": \"collection\",\n\t\"org\": \"discordjs\",\n\t\"packagePath\": \"packages/collection\",\n\t\"identifierBase\": false\n}\n"
  },
  {
    "path": "packages/collection/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\ndist-docs\n\n# Docs\ndocs/**/*\n!docs/README.md\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/collection/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/collection/.prettierignore",
    "content": ".turbo\ncoverage\ndist\ndist-docs\ndocs/docs.api.json\nCHANGELOG.md\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/collection/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/collection/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n# [@discordjs/collection@2.1.1](https://github.com/discordjs/discord.js/compare/@discordjs/collection@2.1.0...@discordjs/collection@2.1.1) - (2024-09-01)\n\n## Bug Fixes\n\n- **build:** Update to support strictBuiltinIteratorReturn (#10394) ([bf83db9](https://github.com/discordjs/discord.js/commit/bf83db9480e9f31d5dadee38a2d053a543150776))\n\n## Testing\n\n- Complete collection coverage (#10380) ([d8e94d8](https://github.com/discordjs/discord.js/commit/d8e94d8f10367d165d15904f7c7a31165842f9ec))\n\n## Typings\n\n- **collection:** Reduce* method signatures (#10405) ([6b38335](https://github.com/discordjs/discord.js/commit/6b383350a6de6d26b62cf62f619c89ffb0d6b0d1))\n\n# [@discordjs/collection@2.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/collection@2.0.0...@discordjs/collection@2.1.0) - (2024-05-04)\n\n## Bug Fixes\n\n- **ReadonlyCollection:** Omit `clear` method (#10148) ([c8bbdb7](https://github.com/discordjs/discord.js/commit/c8bbdb70f218f381b46b4a22230bc56dbbdf04f5))\n- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))\n\n## Documentation\n\n- Split docs.api.json into multiple json files ([597340f](https://github.com/discordjs/discord.js/commit/597340f288437c35da8c703d9b621274de60d880))\n\n## Features\n\n- Local and preview detection ([79fbda3](https://github.com/discordjs/discord.js/commit/79fbda3aac6d4f0f8bfb193e797d09cbe331d315))\n\n## Refactor\n\n- Docs (#10126) ([18cce83](https://github.com/discordjs/discord.js/commit/18cce83d80598c430218775c53441b6b2ecdc776))\n\n# [@discordjs/collection@2.0.0](https://github.com/discordjs/discord.js/compare/@discordjs/collection@1.5.3...@discordjs/collection@2.0.0) - (2023-11-12)\n\n## Documentation\n\n- **collection:** Minor article additions (#9868) ([a674989](https://github.com/discordjs/discord.js/commit/a674989fe27ba9ecd4f1510b07699aeda2f7f01d))\n\n## Features\n\n- Return entries instead of values in toJSON method (#9345) ([defeee5](https://github.com/discordjs/discord.js/commit/defeee5eecdcbf77fa8a5394ac8edd2c895defcc))\n- Align some methods with the Change By Copy proposal (#9207) ([65966ae](https://github.com/discordjs/discord.js/commit/65966ae6ec65254cb196aa7ee9c96c386b93d95e))\n  - **BREAKING CHANGE:** The `sorted` method has been renamed to `toSorted`\n- Align some methods with the Set Methods proposal (#8890) ([3b8df63](https://github.com/discordjs/discord.js/commit/3b8df63a5a8fcec3709ce0a79eb7e2571233c826))\n  - **BREAKING CHANGE:** The `intersect` method has been renamed to `intersection`\n  - **BREAKING CHANGE:** The `difference` method has been renamed to `symmetricDifference`\n  - **BREAKING CHANGE:** The `subtract` method has been renamed to `difference`\n- Support `findLast` and `reduceRight` methods (#9573) ([ac64508](https://github.com/discordjs/discord.js/commit/ac645084f03433372c297e02383a88532f9d385c))\n\n# [@discordjs/collection@1.5.3](https://github.com/discordjs/discord.js/compare/@discordjs/collection@1.5.2...@discordjs/collection@1.5.3) - (2023-08-17)\n\n## Documentation\n\n- Update Node.js requirement to 16.11.0 (#9764) ([188877c](https://github.com/discordjs/discord.js/commit/188877c50af70f0d5cffb246620fa277435c6ce6))\n\n# [@discordjs/collection@1.5.2](https://github.com/discordjs/discord.js/compare/@discordjs/collection@1.5.1...@discordjs/collection@1.5.2) - (2023-07-31)\n\n## Refactor\n\n- **collection:** Reduce `reduce`'s code (#9581) ([b85a3f2](https://github.com/discordjs/discord.js/commit/b85a3f2ddee8fc5974749b95fc07389a03093df2))\n\n# [@discordjs/collection@1.5.1](https://github.com/discordjs/discord.js/compare/@discordjs/collection@1.5.0...@discordjs/collection@1.5.1) - (2023-05-01)\n\n## Bug Fixes\n\n- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2))\n\n## Documentation\n\n- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9))\n\n# [@discordjs/collection@1.5.0](https://github.com/discordjs/discord.js/compare/@discordjs/collection@1.4.0...@discordjs/collection@1.5.0) - (2023-04-01)\n\n## Bug Fixes\n\n- **scripts:** Accessing tsComment ([d8d5f31](https://github.com/discordjs/discord.js/commit/d8d5f31d3927fd1de62f1fa3a1a6e454243ad87b))\n\n## Features\n\n- **website:** Render syntax and mdx on the server (#9086) ([ee5169e](https://github.com/discordjs/discord.js/commit/ee5169e0aadd7bbfcd752aae614ec0f69602b68b))\n\n## Refactor\n\n- **collection:** Fix/silence linter warnings (#9266) ([d6f4e60](https://github.com/discordjs/discord.js/commit/d6f4e60efd1a1796fc84dbbfbac4f9790e480a1c))\n\n# [@discordjs/collection@1.4.0](https://github.com/discordjs/discord.js/compare/@discordjs/collection@1.3.0...@discordjs/collection@1.4.0) - (2023-03-12)\n\n## Documentation\n\n- Fix version export (#9049) ([8b70f49](https://github.com/discordjs/discord.js/commit/8b70f497a1207e30edebdecd12b926c981c13d28))\n\n## Features\n\n- **website:** Add support for source file links (#9048) ([f6506e9](https://github.com/discordjs/discord.js/commit/f6506e99c496683ee0ab67db0726b105b929af38))\n\n## Refactor\n\n- Compare with `undefined` directly (#9191) ([869153c](https://github.com/discordjs/discord.js/commit/869153c3fdf155783e7c0ecebd3627b087c3a026))\n\n# [@discordjs/collection@1.3.0](https://github.com/discordjs/discord.js/compare/@discordjs/collection@1.2.0...@discordjs/collection@1.3.0) - (2022-11-28)\n\n## Bug Fixes\n\n- Pin @types/node version ([9d8179c](https://github.com/discordjs/discord.js/commit/9d8179c6a78e1c7f9976f852804055964d5385d4))\n\n## Features\n\n- Add `Collection#subtract()` (#8393) ([291f36c](https://github.com/discordjs/discord.js/commit/291f36cd736b5dea058145a1335bf7c78ec1d81d))\n\n# [@discordjs/collection@1.2.0](https://github.com/discordjs/discord.js/compare/@discordjs/collection@1.1.0...@discordjs/collection@1.2.0) - (2022-10-08)\n\n## Bug Fixes\n\n- Footer / sidebar / deprecation alert ([ba3e0ed](https://github.com/discordjs/discord.js/commit/ba3e0ed348258fe8e51eefb4aa7379a1230616a9))\n\n## Documentation\n\n- Change name (#8604) ([dd5a089](https://github.com/discordjs/discord.js/commit/dd5a08944c258a847fc4377f1d5e953264ab47d0))\n- Remove xml tag from collection#find (#8550) ([4032457](https://github.com/discordjs/discord.js/commit/40324574ebea9894cadcc967e0db0e4e21d62768))\n\n## Features\n\n- Web-components (#8715) ([0ac3e76](https://github.com/discordjs/discord.js/commit/0ac3e766bd9dbdeb106483fa4bb085d74de346a2))\n\n## Refactor\n\n- Website components (#8600) ([c334157](https://github.com/discordjs/discord.js/commit/c3341570d983aea9ecc419979d5a01de658c9d67))\n- Use `eslint-config-neon` for packages. (#8579) ([edadb9f](https://github.com/discordjs/discord.js/commit/edadb9fe5dfd9ff51a3cfc9b25cb242d3f9f5241))\n\n## Typings\n\n- **Collection:** Make fn return type unknown (#8676) ([822b7f2](https://github.com/discordjs/discord.js/commit/822b7f234af053c8f917b0a998b82abfccd33801))\n\n# [@discordjs/collection@1.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/collection@1.0.1...@discordjs/collection@1.1.0) - (2022-08-22)\n\n## Bug Fixes\n\n- Use proper format for `@link` text (#8384) ([2655639](https://github.com/discordjs/discord.js/commit/26556390a3800e954974a00c1328ff47d3e67e9a))\n\n## Documentation\n\n- Fence examples in codeblocks ([193b252](https://github.com/discordjs/discord.js/commit/193b252672440a860318d3c2968aedd9cb88e0ce))\n- Use link tags (#8382) ([5494791](https://github.com/discordjs/discord.js/commit/549479131318c659f86f0eb18578d597e22522d3))\n\n## Features\n\n- **website:** Show `constructor` information (#8540) ([e42fd16](https://github.com/discordjs/discord.js/commit/e42fd1636973b10dd7ed6fb4280ee1a4a8f82007))\n- **website:** Show descriptions for `@typeParam` blocks (#8523) ([e475b63](https://github.com/discordjs/discord.js/commit/e475b63f257f6261d73cb89fee9ecbcdd84e2a6b))\n\n## Refactor\n\n- **website:** Adjust typography (#8503) ([0f83402](https://github.com/discordjs/discord.js/commit/0f834029850d2448981596cf082ff59917018d66))\n- Docs design (#8487) ([4ab1d09](https://github.com/discordjs/discord.js/commit/4ab1d09997a18879a9eb9bda39df6f15aa22557e))\n\n# [@discordjs/collection@0.8.0](https://github.com/discordjs/discord.js/compare/@discordjs/collection@0.7.0...@discordjs/collection@0.8.0) - (2022-07-17)\n\n## Bug Fixes\n\n- **Collection:** Make error messages consistent (#8224) ([5bd6b28](https://github.com/discordjs/discord.js/commit/5bd6b28b3ebfced1cb9d23e83bd7c0def7a12404))\n- Check for function type (#8064) ([3bb9c0e](https://github.com/discordjs/discord.js/commit/3bb9c0e5c37311044ff41761b572ac4f91cda57c))\n\n## Documentation\n\n- Add codecov coverage badge to readmes (#8226) ([f6db285](https://github.com/discordjs/discord.js/commit/f6db285c073898a749fe4591cbd4463d1896daf5))\n\n## Features\n\n- Codecov (#8219) ([f10f4cd](https://github.com/discordjs/discord.js/commit/f10f4cdcd88ca6be7ec735ed3a415ba13da83db0))\n- **docgen:** Update typedoc ([b3346f4](https://github.com/discordjs/discord.js/commit/b3346f4b9b3d4f96443506643d4631dc1c6d7b21))\n- Website (#8043) ([127931d](https://github.com/discordjs/discord.js/commit/127931d1df7a2a5c27923c2f2151dbf3824e50cc))\n- **docgen:** Typescript support ([3279b40](https://github.com/discordjs/discord.js/commit/3279b40912e6aa61507bedb7db15a2b8668de44b))\n- Docgen package (#8029) ([8b979c0](https://github.com/discordjs/discord.js/commit/8b979c0245c42fd824d8e98745ee869f5360fc86))\n- Use vitest instead of jest for more speed ([8d8e6c0](https://github.com/discordjs/discord.js/commit/8d8e6c03decd7352a2aa180f6e5bc1a13602539b))\n- Add scripts package for locally used scripts ([f2ae1f9](https://github.com/discordjs/discord.js/commit/f2ae1f9348bfd893332a9060f71a8a5f272a1b8b))\n\n## Refactor\n\n- **collection:** Remove `default` property (#8055) ([c8f1690](https://github.com/discordjs/discord.js/commit/c8f1690896f55f06e05a83704262783cfc2bb91d))\n- **collection:** Remove default export (#8053) ([16810f3](https://github.com/discordjs/discord.js/commit/16810f3e410bf35ed7e6e7412d517ea74c792c5d))\n- Move all the config files to root (#8033) ([769ea0b](https://github.com/discordjs/discord.js/commit/769ea0bfe78c4f1d413c6b397c604ffe91e39c6a))\n\n## Testing\n\n- **collection:** Improve coverage (#8222) ([a51f721](https://github.com/discordjs/discord.js/commit/a51f7215eca67a0f46fba8b2d706f7ec6f6dc228))\n\n# [@discordjs/collection@0.7.0](https://github.com/discordjs/discord.js/compare/@discordjs/collection@2.0.0...@discordjs/collection@0.7.0) - (2022-06-04)\n\n## Styling\n\n- Cleanup tests and tsup configs ([6b8ef20](https://github.com/discordjs/discord.js/commit/6b8ef20cb3af5b5cfd176dd0aa0a1a1e98551629))\n\n# [@discordjs/collection@0.6.0](https://github.com/discordjs/discord.js/compare/@discordjs/collection@0.5.0...@discordjs/collection@0.6.0) - (2022-04-17)\n\n## Features\n\n- Add support for module: NodeNext in TS and ESM (#7598) ([8f1986a](https://github.com/discordjs/discord.js/commit/8f1986a6aa98365e09b00e84ad5f9f354ab61f3d))\n- **builders:** Add attachment command option type (#7203) ([ae0f35f](https://github.com/discordjs/discord.js/commit/ae0f35f51d68dfa5a7dc43d161ef9365171debdb))\n- **Collection:** Add merging functions (#7299) ([e4bd07b](https://github.com/discordjs/discord.js/commit/e4bd07b2394f227ea06b72eb6999de9ab3127b25))\n\n# [@discordjs/collection@0.5.0](https://github.com/discordjs/discord.js/compare/@discordjs/collection@0.4.0...@discordjs/collection@0.5.0) - (2022-01-24)\n\n## Refactor\n\n- Make `intersect` perform a true intersection (#7211) ([d8efba2](https://github.com/discordjs/discord.js/commit/d8efba24e09aa2a8dbf028fc57a561a56e7833fd))\n\n## Typings\n\n- Add `ReadonlyCollection` (#7245) ([db25f52](https://github.com/discordjs/discord.js/commit/db25f529b26d7c819c1c42ad3e26c2263ea2da0e))\n- **Collection:** Union types on `intersect` and `difference` (#7196) ([1f9b922](https://github.com/discordjs/discord.js/commit/1f9b9225f2066e9cc66c3355417139fd25cc403c))\n"
  },
  {
    "path": "packages/collection/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2021 Noel Buechler\n   Copyright 2015 Amish Shah\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/collection/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/collection\"><img src=\"https://img.shields.io/npm/v/@discordjs/collection.svg?maxAge=3600\" alt=\"npm version\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/collection\"><img src=\"https://img.shields.io/npm/dt/@discordjs/collection.svg?maxAge=3600\" alt=\"npm downloads\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/commits/main/packages/collection\"><img alt=\"Last commit.\" src=\"https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fcollection\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t\t<a href=\"https://codecov.io/gh/discordjs/discord.js\"><img src=\"https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=collection\" alt=\"Code coverage\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## About\n\n`@discordjs/collection` is a powerful utility data structure used in discord.js.\n\n## Installation\n\n**Node.js 22.12.0 or newer is required.**\n\n```sh\nnpm install @discordjs/collection\nyarn add @discordjs/collection\npnpm add @discordjs/collection\n```\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Documentation][documentation]\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [npm][npm]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the\n[documentation][documentation].  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs/packages/collection/stable\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/collection\n[npm]: https://www.npmjs.com/package/@discordjs/collection\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/collection/__tests__/collection.test.ts",
    "content": "/* eslint-disable unicorn/no-array-method-this-argument */\n/* eslint-disable id-length */\nimport { describe, test, expect } from 'vitest';\nimport { Collection } from '../src/index.js';\n\ntype TestCollection<Value> = Collection<string, Value>;\n\nfunction createCollection<Value = number>(): TestCollection<Value> {\n\treturn new Collection();\n}\n\nfunction createCollectionFrom<Value = number>(...entries: [key: string, value: Value][]): TestCollection<Value> {\n\treturn new Collection(entries);\n}\n\nfunction createTestCollection(): TestCollection<number> {\n\treturn createCollectionFrom(['a', 1], ['b', 2], ['c', 3]);\n}\n\nfunction expectInvalidFunctionError(cb: () => unknown, val?: unknown): void {\n\texpect(() => {\n\t\t// eslint-disable-next-line promise/prefer-await-to-callbacks\n\t\tcb();\n\t}).toThrowError(new TypeError(`${val} is not a function`));\n}\n\ntest('do basic map operations', () => {\n\tconst coll = createCollectionFrom(['a', 1]);\n\texpect(coll.size).toEqual(1);\n\texpect(coll.has('a')).toBeTruthy();\n\texpect(coll.get('a')).toStrictEqual(1);\n\tcoll.delete('a');\n\texpect(coll.has('a')).toBeFalsy();\n\texpect(coll.get('a')).toBeUndefined();\n\tcoll.clear();\n\texpect(coll.size).toStrictEqual(0);\n});\n\ntest('shallow clone the collection', () => {\n\tconst coll = createTestCollection();\n\tconst clone = coll.clone();\n\texpect([...coll.values()]).toStrictEqual([...clone.values()]);\n});\n\ntest('merge multiple collections', () => {\n\tconst coll1 = createCollectionFrom(['a', 1]);\n\tconst coll2 = createCollectionFrom(['b', 2]);\n\tconst coll3 = createCollectionFrom(['c', 3]);\n\tconst merged = coll1.concat(coll2, coll3);\n\texpect([...merged.values()]).toStrictEqual([1, 2, 3]);\n\texpect(coll1 !== merged).toBeTruthy();\n});\n\ntest('check equality of two collections', () => {\n\tconst coll1 = createCollectionFrom(['a', 1]);\n\tconst coll2 = createCollectionFrom(['a', 1]);\n\texpect(coll1.equals(coll2)).toBeTruthy();\n\tcoll2.set('b', 2);\n\texpect(coll1.equals(coll2)).toBeFalsy();\n\tcoll2.clear();\n\texpect(coll1.equals(coll2)).toBeFalsy();\n});\n\n// Specific method tests\n\ndescribe('at() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('positive index', () => {\n\t\texpect(coll.at(0)).toStrictEqual(1);\n\t});\n\n\ttest('positive non-integer index', () => {\n\t\texpect(coll.at(1.5)).toStrictEqual(2);\n\t});\n\n\ttest('negative index', () => {\n\t\texpect(coll.at(-1)).toStrictEqual(3);\n\t});\n\n\ttest('negative non-integer index', () => {\n\t\texpect(coll.at(-2.5)).toStrictEqual(2);\n\t});\n\n\ttest('invalid positive index', () => {\n\t\texpect(coll.at(3)).toBeUndefined();\n\t});\n\n\ttest('invalid negative index', () => {\n\t\texpect(coll.at(-4)).toBeUndefined();\n\t});\n});\n\ndescribe('combineEntries() tests', () => {\n\ttest('it adds entries together', () => {\n\t\tconst c = Collection.combineEntries(\n\t\t\t[\n\t\t\t\t['a', 1],\n\t\t\t\t['b', 2],\n\t\t\t\t['a', 2],\n\t\t\t],\n\t\t\t(x, y) => x + y,\n\t\t);\n\t\texpect([...c]).toStrictEqual([\n\t\t\t['a', 3],\n\t\t\t['b', 2],\n\t\t]);\n\t});\n\n\ttest('it really goes through all the entries', () => {\n\t\tconst c = Collection.combineEntries(\n\t\t\t[\n\t\t\t\t['a', [1]],\n\t\t\t\t['b', [2]],\n\t\t\t\t['a', [2]],\n\t\t\t],\n\t\t\t(x, y) => x.concat(y),\n\t\t);\n\t\texpect([...c]).toStrictEqual([\n\t\t\t['a', [1, 2]],\n\t\t\t['b', [2]],\n\t\t]);\n\t});\n});\n\ndescribe('difference() tests', () => {\n\tconst coll1 = createCollectionFrom(['a', 1], ['b', 2], ['c', 3]);\n\tconst coll2 = createCollectionFrom(['b', 2], ['d', 4], ['e', 5]);\n\n\ttest('it returns the difference the collections', () => {\n\t\texpect(coll1.difference(coll2)).toStrictEqual(createCollectionFrom(['a', 1], ['c', 3]));\n\t});\n\n\ttest('it returns the difference the collections from the opposite order', () => {\n\t\texpect(coll2.difference(coll1)).toStrictEqual(createCollectionFrom(['d', 4], ['e', 5]));\n\t});\n});\n\ndescribe('each() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('throws if fn is not a function', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.each());\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.each(123), 123);\n\t});\n\n\ttest('binds the thisArg', () => {\n\t\tcoll.each(function each() {\n\t\t\texpect(this).toBeNull();\n\t\t}, null);\n\t});\n\n\ttest('iterate over each item', () => {\n\t\tconst coll = createTestCollection();\n\t\tconst a: [string, number][] = [];\n\t\tcoll.each((v, k) => a.push([k, v]));\n\t\texpect(a).toStrictEqual([\n\t\t\t['a', 1],\n\t\t\t['b', 2],\n\t\t\t['c', 3],\n\t\t]);\n\t});\n});\n\ndescribe('ensure() tests', () => {\n\ttest('throws if defaultValueGenerator is not a function', () => {\n\t\tconst coll = createTestCollection();\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.ensure('d', 'abc'), 'abc');\n\t});\n\n\ttest('set new value if key does not exist', () => {\n\t\tconst coll = createTestCollection();\n\t\tcoll.ensure('d', () => 4);\n\t\texpect(coll.size).toStrictEqual(4);\n\t\texpect(coll.get('d')).toStrictEqual(4);\n\t});\n\n\ttest('return existing value if key exists', () => {\n\t\tconst coll = createTestCollection();\n\t\texpect(coll.ensure('b', () => 3)).toStrictEqual(2);\n\t\texpect(coll.get('b')).toStrictEqual(2);\n\t\texpect(coll.size).toStrictEqual(3);\n\t});\n});\n\ndescribe('equals() tests', () => {\n\tconst coll1 = createCollectionFrom(['a', 1], ['b', 2]);\n\tconst coll2 = createTestCollection();\n\n\ttest('returns false if no collection is passed', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpect(coll1.equals()).toBeFalsy();\n\t});\n\n\ttest('the same collection should be equal to itself', () => {\n\t\texpect(coll1.equals(coll1)).toBeTruthy();\n\t});\n\n\ttest('collections with different sizes should not be equal', () => {\n\t\texpect(coll1.equals(coll2)).toBeFalsy();\n\t});\n\n\ttest('collections with the same size but differing items should not be equal', () => {\n\t\tconst coll3 = createCollectionFrom(['a', 2], ['b', 3], ['c', 3]);\n\t\texpect(coll2.equals(coll3)).toBeFalsy();\n\t});\n\n\ttest('collections with undefined values should be compared correctly', () => {\n\t\tconst collWithUndefined1 = new Collection<string, number | undefined>([\n\t\t\t['a', 1],\n\t\t\t['b', undefined],\n\t\t]);\n\t\tconst collWithUndefined2 = new Collection<string, number | undefined>([\n\t\t\t['a', 1],\n\t\t\t['b', undefined],\n\t\t]);\n\t\tconst collWithDifferentKeys = new Collection<string, number | undefined>([\n\t\t\t['a', 1],\n\t\t\t['c', undefined],\n\t\t]);\n\t\texpect(collWithUndefined1.equals(collWithUndefined2)).toBeTruthy();\n\t\texpect(collWithUndefined1.equals(collWithDifferentKeys)).toBeFalsy();\n\t});\n});\n\ndescribe('every() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('throws if fn is not a function', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.every());\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.every(123), 123);\n\t});\n\n\ttest('binds the thisArg', () => {\n\t\tcoll.every(function every() {\n\t\t\texpect(this).toBeNull();\n\t\t\treturn true;\n\t\t}, null);\n\t});\n\n\ttest('returns true if every item passes the predicate', () => {\n\t\texpect(coll.every((v) => v < 4)).toBeTruthy();\n\t});\n\n\ttest(\"returns false if at least one item doesn't pass the predicate\", () => {\n\t\texpect(coll.every((x) => x === 2)).toBeFalsy();\n\t});\n});\n\ndescribe('filter() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('throws if fn is not a function', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.filter());\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.filter(123), 123);\n\t});\n\n\ttest('binds the thisArg', () => {\n\t\tcoll.filter(function filter() {\n\t\t\texpect(this).toBeNull();\n\t\t\treturn true;\n\t\t}, null);\n\t});\n\n\ttest('filter items from the collection', () => {\n\t\tconst coll = createTestCollection();\n\n\t\tconst filtered = coll.filter((x) => x % 2 === 1);\n\t\texpect(coll.size).toStrictEqual(3);\n\t\texpect(filtered.size).toStrictEqual(2);\n\t\texpect([...filtered.values()]).toStrictEqual([1, 3]);\n\t});\n});\n\ndescribe('find() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('throws if fn is not a function', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => createCollection().find());\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => createCollection().find(123), 123);\n\t});\n\n\ttest('binds the thisArg', () => {\n\t\tcoll.find(function find() {\n\t\t\texpect(this).toBeNull();\n\t\t\treturn true;\n\t\t}, null);\n\t});\n\n\ttest('find an item in the collection', () => {\n\t\tconst coll = createTestCollection();\n\t\texpect(coll.find((x) => x === 1)).toStrictEqual(1);\n\t\texpect(coll.find((x) => x === 10)).toBeUndefined();\n\t});\n});\n\ndescribe('findKey() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('throws if fn is not a function', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.findKey());\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.findKey(123), 123);\n\t});\n\n\ttest('binds the thisArg', () => {\n\t\tcoll.findKey(function findKey() {\n\t\t\texpect(this).toBeNull();\n\t\t\treturn true;\n\t\t}, null);\n\t});\n\n\ttest('should find a key', () => {\n\t\texpect(coll.findKey((v) => v === 2)).toEqual('b');\n\t});\n\n\ttest('returns undefined if no key matches', () => {\n\t\texpect(coll.findKey(() => false)).toBeUndefined();\n\t});\n});\n\ndescribe('first() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('returns undefined if the collection is empty', () => {\n\t\texpect(createCollection().first()).toBeUndefined();\n\t});\n\n\ttest('returns the first value', () => {\n\t\texpect(coll.first()).toStrictEqual(1);\n\t});\n\n\ttest('returns empty array if amount is 0', () => {\n\t\texpect(coll.first(0)).toStrictEqual([]);\n\t});\n\n\ttest('returns the values from the end if amount is negative', () => {\n\t\texpect(coll.first(-2)).toStrictEqual([2, 3]);\n\t});\n\n\ttest('returns the first value of the collection', () => {\n\t\texpect(coll.first()).toStrictEqual(1);\n\t});\n\n\ttest('returns all values of the collection when the amount is equal to the size', () => {\n\t\texpect(coll.first(3)).toStrictEqual([1, 2, 3]);\n\t});\n\n\ttest('returns all values of the collection when the amount is bigger than the size', () => {\n\t\texpect(coll.first(4)).toStrictEqual([1, 2, 3]);\n\t});\n});\n\ndescribe('firstKey() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('returns undefined if the collection is empty', () => {\n\t\texpect(createCollection().firstKey()).toBeUndefined();\n\t});\n\n\ttest('returns the first key', () => {\n\t\texpect(coll.firstKey()).toStrictEqual('a');\n\t});\n\n\ttest('returns empty array if amount is 0', () => {\n\t\texpect(coll.firstKey(0)).toStrictEqual([]);\n\t});\n\n\ttest('returns the keys from the end if amount is negative', () => {\n\t\texpect(coll.firstKey(-2)).toStrictEqual(['b', 'c']);\n\t});\n\n\ttest('returns the keys from the beginning if amount is positive', () => {\n\t\texpect(coll.firstKey(2)).toEqual(['a', 'b']);\n\t});\n\n\ttest('returns all keys of the collection when the amount is equal to the size', () => {\n\t\texpect(coll.firstKey(3)).toStrictEqual(['a', 'b', 'c']);\n\t});\n\n\ttest('returns all keys of the collection when the amount is bigger than the size', () => {\n\t\texpect(coll.firstKey(3)).toStrictEqual(['a', 'b', 'c']);\n\t});\n});\n\ndescribe('flatMap', () => {\n\ttest('flats items from collection into a single collection', () => {\n\t\tconst coll = new Collection<string, { a: Collection<string, number> }>();\n\t\tconst coll1 = createCollectionFrom(['z', 1], ['x', 2]);\n\t\tconst coll2 = createCollectionFrom(['c', 3], ['v', 4]);\n\t\tcoll.set('a', { a: coll1 });\n\t\tcoll.set('b', { a: coll2 });\n\t\tconst mapped = coll.flatMap((x) => x.a);\n\t\texpect([...mapped.values()]).toStrictEqual([1, 2, 3, 4]);\n\t});\n});\n\ndescribe('hasAll() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('all keys exist in the collection', () => {\n\t\texpect(coll.hasAll('a', 'b', 'c')).toBeTruthy();\n\t});\n\n\ttest('some keys exist in the collection', () => {\n\t\texpect(coll.hasAll('b', 'c', 'd')).toBeFalsy();\n\t});\n\n\ttest('no keys exist in the collection', () => {\n\t\texpect(coll.hasAll('d', 'e')).toBeFalsy();\n\t});\n});\n\ndescribe('hasAny() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('all keys exist in the collection', () => {\n\t\texpect(coll.hasAny('a', 'b')).toBeTruthy();\n\t});\n\n\ttest('some keys exist in the collection', () => {\n\t\texpect(coll.hasAny('c', 'd')).toBeTruthy();\n\t});\n\n\ttest('no keys exist in the collection', () => {\n\t\texpect(coll.hasAny('d', 'e')).toBeFalsy();\n\t});\n});\n\ndescribe('intersection() tests', () => {\n\tconst coll1 = createCollectionFrom(['a', 1], ['b', 2]);\n\tconst coll2 = createCollectionFrom(['a', 1], ['c', 3]);\n\n\ttest('it returns the intersection of the collections', () => {\n\t\tconst c = coll1.intersection(coll2);\n\t\texpect(c).toBeInstanceOf(Collection);\n\t\texpect(c.size).toStrictEqual(1);\n\n\t\texpect(c).toStrictEqual(createCollectionFrom(['a', 1]));\n\t});\n});\n\ndescribe('keyAt() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('positive index', () => {\n\t\texpect(coll.keyAt(0)).toStrictEqual('a');\n\t});\n\n\ttest('positive non-integer index', () => {\n\t\texpect(coll.keyAt(1.5)).toStrictEqual('b');\n\t});\n\n\ttest('negative index', () => {\n\t\texpect(coll.keyAt(-1)).toStrictEqual('c');\n\t});\n\n\ttest('negative non-integer index', () => {\n\t\texpect(coll.keyAt(-2.5)).toStrictEqual('b');\n\t});\n\n\ttest('invalid positive index', () => {\n\t\texpect(coll.keyAt(3)).toBeUndefined();\n\t});\n\n\ttest('invalid negative index', () => {\n\t\texpect(coll.keyAt(-4)).toBeUndefined();\n\t});\n});\n\ndescribe('last() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('returns undefined if the collection is empty', () => {\n\t\texpect(createCollection().last()).toBeUndefined();\n\t});\n\n\ttest('returns the last value', () => {\n\t\texpect(coll.last()).toStrictEqual(3);\n\t});\n\n\ttest('returns empty array if amount is 0', () => {\n\t\texpect(coll.last(0)).toStrictEqual([]);\n\t});\n\n\ttest('returns the values from the beginning if amount is negative', () => {\n\t\texpect(coll.last(-2)).toStrictEqual([1, 2]);\n\t});\n\n\ttest('returns the last value of the collection', () => {\n\t\texpect(coll.last()).toStrictEqual(3);\n\t});\n\n\ttest('returns all values of the collection when the amount is equal to the size', () => {\n\t\texpect(coll.last(3)).toStrictEqual([1, 2, 3]);\n\t});\n\n\ttest('returns all values of the collection when the amount is bigger than the size', () => {\n\t\texpect(coll.last(4)).toStrictEqual([1, 2, 3]);\n\t});\n});\n\ndescribe('lastKey() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('returns undefined if the collection is empty', () => {\n\t\texpect(createCollection().lastKey()).toBeUndefined();\n\t});\n\n\ttest('returns the last key', () => {\n\t\texpect(coll.lastKey()).toStrictEqual('c');\n\t});\n\n\ttest('returns empty array if amount is 0', () => {\n\t\texpect(coll.lastKey(0)).toStrictEqual([]);\n\t});\n\n\ttest('returns the keys from the beginning if amount is negative', () => {\n\t\texpect(coll.lastKey(-2)).toStrictEqual(['a', 'b']);\n\t});\n\n\ttest('returns the last n keys if the amount option is used', () => {\n\t\texpect(coll.lastKey(2)).toStrictEqual(['b', 'c']);\n\t});\n\n\ttest('returns all keys of the collection when the amount is equal to the size', () => {\n\t\texpect(coll.lastKey(3)).toStrictEqual(['a', 'b', 'c']);\n\t});\n\n\ttest('returns all keys of the collection when the amount is bigger than the size', () => {\n\t\texpect(coll.lastKey(4)).toStrictEqual(['a', 'b', 'c']);\n\t});\n});\n\ndescribe('map() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('throws if fn is not a function', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.map());\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.map(123), 123);\n\t});\n\n\ttest('binds the thisArg', () => {\n\t\tcoll.map(function map() {\n\t\t\texpect(this).toBeNull();\n\t\t\treturn true;\n\t\t}, null);\n\t});\n\n\ttest('map items in a collection into an array', () => {\n\t\tconst mapped = coll.map((x) => x + 1);\n\t\texpect(mapped).toStrictEqual([2, 3, 4]);\n\t});\n});\n\ndescribe('mapValues() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('throws if fn is not a function', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.mapValues());\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.mapValues(123), 123);\n\t});\n\n\ttest('binds the thisArg', () => {\n\t\tcoll.mapValues(function mapValues() {\n\t\t\texpect(this).toBeNull();\n\t\t\treturn true;\n\t\t}, null);\n\t});\n\n\ttest('map items in a collection into a collection', () => {\n\t\tconst mapped = coll.mapValues((x) => x + 1);\n\t\texpect([...mapped.values()]).toStrictEqual([2, 3, 4]);\n\t});\n});\n\ndescribe('merge() tests', () => {\n\tconst cL = createCollectionFrom(['L', 1], ['LR', 2]);\n\tconst cR = createCollectionFrom(['R', 3], ['LR', 4]);\n\n\ttest('merges two collection, with all keys together', () => {\n\t\tconst c = cL.merge(\n\t\t\tcR,\n\t\t\t(x) => ({ keep: true, value: `L${x}` }),\n\t\t\t(y) => ({ keep: true, value: `R${y}` }),\n\t\t\t(x, y) => ({ keep: true, value: `LR${x},${y}` }),\n\t\t);\n\t\texpect(c.get('L')).toStrictEqual('L1');\n\t\texpect(c.get('R')).toStrictEqual('R3');\n\t\texpect(c.get('LR')).toStrictEqual('LR2,4');\n\t\texpect(c.size).toStrictEqual(3);\n\t});\n\n\ttest('merges two collection, removing left entries', () => {\n\t\tconst c = cL.merge(\n\t\t\tcR,\n\t\t\t() => ({ keep: false }),\n\t\t\t(y) => ({ keep: true, value: `R${y}` }),\n\t\t\t(x, y) => ({ keep: true, value: `LR${x},${y}` }),\n\t\t);\n\t\texpect(c.get('R')).toStrictEqual('R3');\n\t\texpect(c.get('LR')).toStrictEqual('LR2,4');\n\t\texpect(c.size).toStrictEqual(2);\n\t});\n\n\ttest('merges two collection, removing right entries', () => {\n\t\tconst c = cL.merge(\n\t\t\tcR,\n\t\t\t(x) => ({ keep: true, value: `L${x}` }),\n\t\t\t() => ({ keep: false }),\n\t\t\t(x, y) => ({ keep: true, value: `LR${x},${y}` }),\n\t\t);\n\t\texpect(c.get('L')).toStrictEqual('L1');\n\t\texpect(c.get('LR')).toStrictEqual('LR2,4');\n\t\texpect(c.size).toStrictEqual(2);\n\t});\n\n\ttest('merges two collection, removing in-both entries', () => {\n\t\tconst c = cL.merge(\n\t\t\tcR,\n\t\t\t(x) => ({ keep: true, value: `L${x}` }),\n\t\t\t(y) => ({ keep: true, value: `R${y}` }),\n\t\t\t() => ({ keep: false }),\n\t\t);\n\t\texpect(c.get('L')).toStrictEqual('L1');\n\t\texpect(c.get('R')).toStrictEqual('R3');\n\t\texpect(c.size).toStrictEqual(2);\n\t});\n});\n\ndescribe('partition() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('throws if fn is not a function', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.partition());\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.partition(123), 123);\n\t});\n\n\ttest('binds the thisArg', () => {\n\t\tcoll.partition(function partition() {\n\t\t\texpect(this).toBeNull();\n\t\t\treturn true;\n\t\t}, null);\n\t});\n\n\ttest('partition a collection into two collections', () => {\n\t\tcoll.set('d', 4);\n\t\tcoll.set('e', 5);\n\t\tcoll.set('f', 6);\n\t\tconst [even, odd] = coll.partition((x) => x % 2 === 0);\n\t\texpect([...even.values()]).toStrictEqual([2, 4, 6]);\n\t\texpect([...odd.values()]).toStrictEqual([1, 3, 5]);\n\t});\n});\n\ndescribe('random() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('returns undefined if the collection is empty', () => {\n\t\texpect(createCollection().random()).toBeUndefined();\n\t});\n\n\ttest('returns empty array if the amount is 0', () => {\n\t\texpect(coll.random(0)).toStrictEqual([]);\n\t});\n\n\ttest('returns an item if amount is not passed', () => {\n\t\texpect(coll.random()).toBeDefined();\n\t});\n\n\ttest('random select from a collection', () => {\n\t\tconst coll = createCollection();\n\t\tconst chars = 'abcdefghijklmnopqrstuvwxyz';\n\t\tconst numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26];\n\n\t\tfor (let i = 0; i < chars.length; i++) coll.set(chars[i]!, numbers[i]!);\n\n\t\tconst random = coll.random(5);\n\t\texpect(random.length).toBe(5);\n\n\t\tconst set = new Set(random);\n\t\texpect(set.size).toBe(random.length);\n\t});\n\n\ttest('when random param > collection size', () => {\n\t\tconst coll = createCollectionFrom(['a', 3], ['b', 2], ['c', 1]);\n\n\t\tconst random = coll.random(5);\n\t\texpect(random.length).toEqual(coll.size);\n\t});\n});\n\ndescribe('randomKey() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('returns undefined if the collection is empty', () => {\n\t\texpect(createCollection().randomKey()).toBeUndefined();\n\t});\n\n\ttest('returns empty array if the amount is 0', () => {\n\t\texpect(coll.randomKey(0)).toStrictEqual([]);\n\t});\n\n\ttest('returns a key', () => {\n\t\texpect(coll.randomKey()).toBeDefined();\n\t});\n\n\ttest('returns n keys if the amount option is used', () => {\n\t\texpect(coll.randomKey(2)).toHaveLength(2);\n\t});\n});\n\ndescribe('reduce() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('throws if fn is not a function', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.reduce());\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.reduce(123), 123);\n\t});\n\n\ttest('reduce collection into a single value with initial value', () => {\n\t\tconst sum = coll.reduce((a, x) => a + x, 0);\n\t\texpect<number>(sum).toStrictEqual(6);\n\t});\n\n\ttest('reduce collection into a single value without initial value', () => {\n\t\tconst sum = coll.reduce((a, x) => a + x);\n\t\texpect<number>(sum).toStrictEqual(6);\n\t});\n\n\ttest('reduce collection into a single value with different accumulator type', () => {\n\t\tconst str = coll.reduce((a, x) => a.concat(x.toString()), '');\n\t\texpect<string>(str).toStrictEqual('123');\n\t});\n\n\ttest('reduce empty collection with initial value', () => {\n\t\tconst coll = createCollection();\n\t\texpect<number>(coll.reduce((a, x) => a + x, 0)).toStrictEqual(0);\n\t});\n\n\ttest('reduce empty collection without initial value', () => {\n\t\tconst coll = createCollection();\n\t\texpect(() => coll.reduce((a, x) => a + x)).toThrowError(\n\t\t\tnew TypeError('Reduce of empty collection with no initial value'),\n\t\t);\n\t});\n});\n\ndescribe('reduceRight() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('throws if fn is not a function', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.reduceRight());\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.reduceRight(123), 123);\n\t});\n\n\ttest('reduce collection into a single value with initial value', () => {\n\t\tconst sum = coll.reduceRight((a, x) => a + x, 0);\n\t\texpect<number>(sum).toStrictEqual(6);\n\t});\n\n\ttest('reduce collection into a single value without initial value', () => {\n\t\tconst sum = coll.reduceRight((a, x) => a + x);\n\t\texpect<number>(sum).toStrictEqual(6);\n\t});\n\n\ttest('reduce collection into a single value with different accumulator type', () => {\n\t\tconst str = coll.reduceRight((a, x) => a.concat(x.toString()), '');\n\t\texpect<string>(str).toStrictEqual('321');\n\t});\n\n\ttest('reduce empty collection with initial value', () => {\n\t\tconst coll = createCollection();\n\t\texpect<number>(coll.reduceRight((a, x) => a + x, 0)).toStrictEqual(0);\n\t});\n\n\ttest('reduce empty collection without initial value', () => {\n\t\tconst coll = createCollection();\n\t\texpect(() => coll.reduceRight((a, x) => a + x)).toThrowError(\n\t\t\tnew TypeError('Reduce of empty collection with no initial value'),\n\t\t);\n\t});\n});\n\ndescribe('reverse() tests', () => {\n\ttest('reverts the collection', () => {\n\t\tconst coll = createTestCollection();\n\n\t\tcoll.reverse();\n\n\t\texpect([...coll.values()]).toStrictEqual([3, 2, 1]);\n\t\texpect([...coll.keys()]).toStrictEqual(['c', 'b', 'a']);\n\t});\n});\n\ndescribe('some() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('throws if fn is not a function', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.some());\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.some(123), 123);\n\t});\n\n\ttest('returns false if no items pass the predicate', () => {\n\t\texpect(coll.some((v) => v > 3)).toBeFalsy();\n\t});\n});\n\ndescribe('sort() tests', () => {\n\ttest('sort a collection in place', () => {\n\t\tconst coll = createCollectionFrom(['a', 3], ['b', 2], ['c', 1]);\n\t\texpect([...coll.values()]).toStrictEqual([3, 2, 1]);\n\t\tcoll.sort((a, b) => a - b);\n\t\texpect([...coll.values()]).toStrictEqual([1, 2, 3]);\n\t});\n\n\tdescribe('defaultSort', () => {\n\t\ttest('stays the same if it is already sorted', () => {\n\t\t\tconst coll = createTestCollection();\n\t\t\texpect(coll.sort()).toStrictEqual(coll);\n\t\t});\n\n\t\ttest('stays the same if it is already sorted', () => {\n\t\t\tconst coll = createCollectionFrom(['a', 5], ['b', 3], ['c', 1]);\n\t\t\texpect(coll.sort()).toStrictEqual(createCollectionFrom(['c', 1], ['b', 3], ['a', 5]));\n\t\t});\n\n\t\tdescribe('returns correct sort order for test values', () => {\n\t\t\tconst defaultSort = Collection['defaultSort']; // eslint-disable-line @typescript-eslint/dot-notation\n\t\t\tconst testDefaultSortOrder = (firstValue: any, secondValue: any, result: number) => {\n\t\t\t\texpect(defaultSort(firstValue, secondValue)).toStrictEqual(result);\n\t\t\t\texpect(defaultSort(secondValue, firstValue)).toStrictEqual(result ? result * -1 : 0);\n\t\t\t};\n\n\t\t\ttest('correctly evaluates sort order of undefined', () => {\n\t\t\t\ttestDefaultSortOrder(undefined, undefined, 0);\n\t\t\t\ttestDefaultSortOrder(0, undefined, -1);\n\t\t\t});\n\n\t\t\ttest('correctly evaluates numeric values stringwise', () => {\n\t\t\t\ttestDefaultSortOrder(-1, -2, -1); // \"-1\" before \"-2\"\n\t\t\t\ttestDefaultSortOrder(1, '1', 0); // \"1\" equal to \"1\"\n\t\t\t\ttestDefaultSortOrder(1, '1.0', -1); // \"1\" before \"1.0\"\n\t\t\t\ttestDefaultSortOrder(1.1, '1.1', 0); // \"1.1\" equal to \"1.1\"\n\t\t\t\ttestDefaultSortOrder('01', 1, -1); // \"01\" before \"1\"\n\t\t\t\ttestDefaultSortOrder(1, 1n, 0); // \"1\" equal to \"1\"\n\t\t\t\ttestDefaultSortOrder(Number.NaN, 'NaN', 0); // \"NaN\" equal to \"NaN\"\n\t\t\t});\n\n\t\t\ttest('evaluates object literals as equal', () => {\n\t\t\t\ttestDefaultSortOrder({ a: 1 }, { b: 2 }, 0);\n\t\t\t});\n\t\t});\n\t});\n});\n\ndescribe('sweep() test', () => {\n\tconst coll = createTestCollection();\n\n\ttest('throws if fn is not a function', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.sweep());\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.sweep(123), 123);\n\t});\n\n\ttest('binds the thisArg', () => {\n\t\tcoll.sweep(function sweep() {\n\t\t\texpect(this).toBeNull();\n\t\t\treturn false;\n\t\t}, null);\n\t});\n\n\ttest('sweep items from the collection', () => {\n\t\tconst n1 = coll.sweep((x) => x === 2);\n\t\texpect(n1).toStrictEqual(1);\n\t\texpect([...coll.values()]).toStrictEqual([1, 3]);\n\t\tconst n2 = coll.sweep((x) => x === 4);\n\t\texpect(n2).toStrictEqual(0);\n\t\texpect([...coll.values()]).toStrictEqual([1, 3]);\n\t});\n});\n\ndescribe('symmetricDifference() tests', () => {\n\tconst coll1 = createCollectionFrom(['a', 1], ['b', 2], ['c', 3]);\n\tconst coll2 = createCollectionFrom(['b', 2], ['d', 4], ['e', 5]);\n\n\ttest('it returns the symmetric difference of the collections', () => {\n\t\texpect(coll1.symmetricDifference(coll2)).toStrictEqual(\n\t\t\tcreateCollectionFrom(['a', 1], ['c', 3], ['d', 4], ['e', 5]),\n\t\t);\n\t});\n});\n\ndescribe('tap() tests', () => {\n\tconst coll = createTestCollection();\n\n\ttest('throws if fn is not a function', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.tap());\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => coll.tap(123), 123);\n\t});\n\n\ttest('binds the thisArg', () => {\n\t\tcoll.tap(function tap(c) {\n\t\t\texpect(this).toBeNull();\n\t\t\texpect(c).toStrictEqual(coll);\n\t\t}, null);\n\t});\n\n\ttest('the collection should be the same', () => {\n\t\tcoll.tap((c) => expect(c).toStrictEqual(coll));\n\t});\n});\n\ndescribe('toJSON() tests', () => {\n\ttest('it returns the entries of the collection', () => {\n\t\tconst c = createTestCollection();\n\n\t\texpect(c.toJSON()).toStrictEqual([\n\t\t\t['a', 1],\n\t\t\t['b', 2],\n\t\t\t['c', 3],\n\t\t]);\n\t});\n});\n\ndescribe('union() tests', () => {\n\tconst coll1 = createCollectionFrom(['a', 1], ['b', 2]);\n\tconst coll2 = createCollectionFrom(['a', 1], ['c', 3]);\n\n\ttest('it returns the union of the collections', () => {\n\t\tconst c = coll1.union(coll2);\n\t\texpect(c).toBeInstanceOf(Collection);\n\t\texpect(c.size).toStrictEqual(3);\n\n\t\texpect(c).toStrictEqual(createCollectionFrom(['a', 1], ['b', 2], ['c', 3]));\n\t});\n});\n\ndescribe('groupBy() tests', () => {\n\ttest('returns a collection of grouped items', () => {\n\t\tconst items = [\n\t\t\t{ name: 'Alice', age: 20 },\n\t\t\t{ name: 'Bob', age: 20 },\n\t\t\t{ name: 'Charlie', age: 30 },\n\t\t];\n\n\t\texpect<Collection<number, typeof items>>(Collection.groupBy(items, (item) => item.age)).toStrictEqual(\n\t\t\tnew Collection<number, typeof items>([\n\t\t\t\t[\n\t\t\t\t\t20,\n\t\t\t\t\t[\n\t\t\t\t\t\t{ name: 'Alice', age: 20 },\n\t\t\t\t\t\t{ name: 'Bob', age: 20 },\n\t\t\t\t\t],\n\t\t\t\t],\n\t\t\t\t[30, [{ name: 'Charlie', age: 30 }]],\n\t\t\t]),\n\t\t);\n\t});\n});\n\ndescribe('toReversed() tests', () => {\n\ttest('reverses a collection', () => {\n\t\tconst coll = createTestCollection();\n\t\tconst reversed = coll.toReversed();\n\t\texpect([...reversed.entries()]).toStrictEqual([\n\t\t\t['c', 3],\n\t\t\t['b', 2],\n\t\t\t['a', 1],\n\t\t]);\n\t});\n\n\ttest('does not the modify original collection', () => {\n\t\tconst coll = createTestCollection();\n\t\tconst originalEntries = [...coll.entries()];\n\t\tconst reversed = coll.toReversed();\n\n\t\texpect(reversed).not.toBe(coll);\n\t\texpect([...coll.entries()]).toStrictEqual(originalEntries);\n\t});\n});\n\ndescribe('toSorted() tests', () => {\n\ttest('sorts a collection', () => {\n\t\tconst coll = createCollectionFrom(['a', 3], ['b', 2], ['c', 1]);\n\t\tconst sorted = coll.toSorted((a, b) => a - b);\n\t\texpect([...sorted.entries()]).toStrictEqual([\n\t\t\t['c', 1],\n\t\t\t['b', 2],\n\t\t\t['a', 3],\n\t\t]);\n\t});\n\n\ttest('does not modify the original collection', () => {\n\t\tconst coll = createCollectionFrom(['a', 3], ['b', 2], ['c', 1]);\n\t\tconst originalEntries = [...coll.entries()];\n\t\tconst sorted = coll.toSorted();\n\n\t\texpect(sorted).not.toBe(coll);\n\t\texpect([...coll.entries()]).toStrictEqual(originalEntries);\n\t});\n});\n\ndescribe('random thisArg tests', () => {\n\tconst coll = createCollectionFrom(['a', 3], ['b', 2], ['c', 1]) as Collection<string, unknown>;\n\n\tconst object = {};\n\tconst string = 'Hi';\n\tconst boolean = false;\n\tconst symbol = Symbol('testArg');\n\tconst array = [1, 2, 3];\n\n\tcoll.set('d', object);\n\tcoll.set('e', string);\n\tcoll.set('f', boolean);\n\tcoll.set('g', symbol);\n\tcoll.set('h', array);\n\n\ttest('thisArg test: number', () => {\n\t\tcoll.some(function thisArgTest1(value) {\n\t\t\texpect(this.valueOf()).toStrictEqual(1);\n\t\t\texpect(typeof this).toEqual('number');\n\t\t\treturn value === this;\n\t\t}, 1);\n\t});\n\n\ttest('thisArg test: object', () => {\n\t\tcoll.some(function thisArgTest2(value) {\n\t\t\texpect(this).toStrictEqual(object);\n\t\t\texpect(this.constructor === Object).toBeTruthy();\n\t\t\treturn value === this;\n\t\t}, object);\n\t});\n\n\ttest('thisArg test: string', () => {\n\t\tcoll.some(function thisArgTest3(value) {\n\t\t\texpect(this.valueOf()).toStrictEqual(string);\n\t\t\texpect(typeof this).toEqual('string');\n\t\t\treturn value === this;\n\t\t}, string);\n\t});\n\n\ttest('thisArg test: boolean', () => {\n\t\tcoll.some(function thisArgTest4(value) {\n\t\t\texpect(this.valueOf()).toStrictEqual(boolean);\n\t\t\texpect(typeof this).toEqual('boolean');\n\t\t\treturn value === this;\n\t\t}, boolean);\n\t});\n\n\ttest('thisArg test: symbol', () => {\n\t\tcoll.some(function thisArgTest5(value) {\n\t\t\texpect(this.valueOf()).toStrictEqual(symbol);\n\t\t\texpect(typeof this).toEqual('symbol');\n\t\t\treturn value === this;\n\t\t}, symbol);\n\t});\n\n\ttest('thisArg test: array', () => {\n\t\tcoll.some(function thisArgTest6(value) {\n\t\t\texpect(this).toStrictEqual(array);\n\t\t\texpect(Array.isArray(this)).toBeTruthy();\n\t\t\treturn value === this;\n\t\t}, array);\n\t});\n});\n\ndescribe('findLast() tests', () => {\n\tconst coll = createTestCollection();\n\ttest('it returns last matched element', () => {\n\t\texpect(coll.findLast((value) => value % 2 === 1)).toStrictEqual(3);\n\t});\n\n\ttest('returns undefined if no item matches', () => {\n\t\texpect(coll.findLast((value) => value === 10)).toBeUndefined();\n\t});\n\n\ttest('throws if fn is not a function', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => createCollection().findLast());\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => createCollection().findLast(123), 123);\n\t});\n\n\ttest('binds the thisArg', () => {\n\t\tcoll.findLast(function findLast() {\n\t\t\texpect(this).toBeNull();\n\t\t\treturn true;\n\t\t}, null);\n\t});\n});\n\ndescribe('findLastKey() tests', () => {\n\tconst coll = createTestCollection();\n\ttest('it returns last matched element', () => {\n\t\texpect(coll.findLastKey((value) => value % 2 === 1)).toStrictEqual('c');\n\t});\n\n\ttest('returns undefined if no item matches', () => {\n\t\texpect(coll.findLastKey((value) => value === 10)).toBeUndefined();\n\t});\n\n\ttest('throws if fn is not a function', () => {\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => createCollection().findLastKey());\n\t\t// @ts-expect-error: Invalid function\n\t\texpectInvalidFunctionError(() => createCollection().findLastKey(123), 123);\n\t});\n\n\ttest('binds the thisArg', () => {\n\t\tcoll.findLastKey(function findLastKey() {\n\t\t\texpect(this).toBeNull();\n\t\t\treturn true;\n\t\t}, null);\n\t});\n});\n\ndescribe('subclassing tests', () => {\n\tclass DerivedCollection<Key, Value> extends Collection<Key, Value> {}\n\n\ttest('constructor[Symbol.species]', () => {\n\t\texpect(DerivedCollection[Symbol.species]).toStrictEqual(DerivedCollection);\n\t});\n\n\tdescribe('methods that construct new collections return subclassed objects', () => {\n\t\tconst coll = new DerivedCollection();\n\n\t\ttest('filter()', () => {\n\t\t\texpect(coll.filter(Boolean)).toBeInstanceOf(DerivedCollection);\n\t\t});\n\t\ttest('partition()', () => {\n\t\t\tfor (const partition of coll.partition(Boolean)) {\n\t\t\t\texpect(partition).toBeInstanceOf(DerivedCollection);\n\t\t\t}\n\t\t});\n\t\ttest('flatMap()', () => {\n\t\t\texpect(coll.flatMap(() => new Collection())).toBeInstanceOf(DerivedCollection);\n\t\t});\n\t\ttest('mapValues()', () => {\n\t\t\texpect(coll.mapValues(Object)).toBeInstanceOf(DerivedCollection);\n\t\t});\n\t\ttest('clone()', () => {\n\t\t\texpect(coll.clone()).toBeInstanceOf(DerivedCollection);\n\t\t});\n\t\ttest('intersection()', () => {\n\t\t\texpect(coll.intersection(new Collection())).toBeInstanceOf(DerivedCollection);\n\t\t});\n\t\ttest('union()', () => {\n\t\t\texpect(coll.union(new Collection())).toBeInstanceOf(DerivedCollection);\n\t\t});\n\t\ttest('difference()', () => {\n\t\t\texpect(coll.difference(new Collection())).toBeInstanceOf(DerivedCollection);\n\t\t});\n\t\ttest('symmetricDifference()', () => {\n\t\t\texpect(coll.symmetricDifference(new Collection())).toBeInstanceOf(DerivedCollection);\n\t\t});\n\t\ttest('merge()', () => {\n\t\t\tconst fn = () => ({ keep: false }) as const; // eslint-disable-line unicorn/consistent-function-scoping\n\t\t\texpect(coll.merge(new Collection(), fn, fn, fn)).toBeInstanceOf(DerivedCollection);\n\t\t});\n\t\ttest('toReversed()', () => {\n\t\t\texpect(coll.toReversed()).toBeInstanceOf(DerivedCollection);\n\t\t});\n\t\ttest('toSorted()', () => {\n\t\t\texpect(coll.toSorted()).toBeInstanceOf(DerivedCollection);\n\t\t});\n\t\ttest('Collection.combineEntries()', () => {\n\t\t\texpect(DerivedCollection.combineEntries([], Object)).toBeInstanceOf(DerivedCollection);\n\t\t});\n\t\ttest('Collection.groupBy()', () => {\n\t\t\texpect(DerivedCollection.groupBy([], Object)).toBeInstanceOf(DerivedCollection);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/collection/api-extractor.json",
    "content": "{\n\t\"extends\": \"../../api-extractor.json\",\n\t\"docModel\": {\n\t\t\"projectFolderUrl\": \"https://github.com/discordjs/discord.js/tree/main/packages/collection\"\n\t}\n}\n"
  },
  {
    "path": "packages/collection/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t\t{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length %}\\\n\t\\n### New Contributors\\n\n\t{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\\\n\t\t* @{{ contributor.username }} made their first contribution in #{{ contributor.pr_number }}\n\t{% endfor %}\\\n{% endif %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"@discordjs/collection@[0-9]*\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/collection/docs/README.md",
    "content": "## [View the documentation here.](https://discord.js.org/docs/packages/collection/main)\n"
  },
  {
    "path": "packages/collection/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/collection\",\n\t\"version\": \"2.1.1\",\n\t\"description\": \"Utility data structure used in discord.js\",\n\t\"scripts\": {\n\t\t\"test\": \"vitest run --config ../../vitest.config.ts\",\n\t\t\"build\": \"tsc --noEmit && tsup\",\n\t\t\"build:docs\": \"tsc -p tsconfig.docs.json\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src __tests__\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src __tests__\",\n\t\t\"fmt\": \"pnpm run format\",\n\t\t\"docs\": \"pnpm run build:docs && api-extractor run --local --minify && generate-split-documentation\",\n\t\t\"prepack\": \"pnpm run lint && pnpm run test && pnpm run build\",\n\t\t\"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/collection/*'\",\n\t\t\"release\": \"cliff-jumper\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"main\": \"./dist/index.js\",\n\t\"module\": \"./dist/index.mjs\",\n\t\"types\": \"./dist/index.d.ts\",\n\t\"directories\": {\n\t\t\"lib\": \"src\",\n\t\t\"test\": \"__tests__\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"Amish Shah <amishshah.2k@gmail.com>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"map\",\n\t\t\"collection\",\n\t\t\"utility\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/collection\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"devDependencies\": {\n\t\t\"@discordjs/api-extractor\": \"workspace:^\",\n\t\t\"@discordjs/scripts\": \"workspace:^\",\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@types/node\": \"^22.19.11\",\n\t\t\"@vitest/coverage-v8\": \"^4.0.18\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"esbuild-plugin-version-injector\": \"^1.2.1\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vitest\": \"^4.0.18\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/collection/src/collection.ts",
    "content": "/* eslint-disable no-param-reassign */\n\n/**\n * Represents an immutable version of a collection\n */\nexport type ReadonlyCollection<Key, Value> = Omit<\n\tCollection<Key, Value>,\n\tkeyof Map<Key, Value> | 'ensure' | 'reverse' | 'sort' | 'sweep'\n> &\n\tReadonlyMap<Key, Value>;\n\nexport interface Collection<Key, Value> {\n\t/**\n\t * Ambient declaration to allow references to `this.constructor` in class methods.\n\t *\n\t * @internal\n\t */\n\tconstructor: typeof Collection;\n}\n\n/**\n * A Map with additional utility methods. This is used throughout discord.js rather than Arrays for anything that has\n * an ID, for significantly improved performance and ease-of-use.\n *\n * @typeParam Key - The key type this collection holds\n * @typeParam Value - The value type this collection holds\n */\n// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging\nexport class Collection<Key, Value> extends Map<Key, Value> {\n\t/**\n\t * Obtains the value of the given key if it exists, otherwise sets and returns the value provided by the default value generator.\n\t *\n\t * @param key - The key to get if it exists, or set otherwise\n\t * @param defaultValueGenerator - A function that generates the default value\n\t * @example\n\t * ```ts\n\t * collection.ensure(guildId, () => defaultGuildConfig);\n\t * ```\n\t */\n\tpublic ensure(key: Key, defaultValueGenerator: (key: Key, collection: this) => Value): Value {\n\t\tif (this.has(key)) return this.get(key)!;\n\t\tif (typeof defaultValueGenerator !== 'function') throw new TypeError(`${defaultValueGenerator} is not a function`);\n\t\tconst defaultValue = defaultValueGenerator(key, this);\n\t\tthis.set(key, defaultValue);\n\t\treturn defaultValue;\n\t}\n\n\t/**\n\t * Checks if all of the elements exist in the collection.\n\t *\n\t * @param keys - The keys of the elements to check for\n\t * @returns `true` if all of the elements exist, `false` if at least one does not exist.\n\t */\n\tpublic hasAll(...keys: Key[]) {\n\t\treturn keys.every((key) => super.has(key));\n\t}\n\n\t/**\n\t * Checks if any of the elements exist in the collection.\n\t *\n\t * @param keys - The keys of the elements to check for\n\t * @returns `true` if any of the elements exist, `false` if none exist.\n\t */\n\tpublic hasAny(...keys: Key[]) {\n\t\treturn keys.some((key) => super.has(key));\n\t}\n\n\t/**\n\t * Obtains the first value(s) in this collection.\n\t *\n\t * @param amount - Amount of values to obtain from the beginning\n\t * @returns A single value if no amount is provided or an array of values, starting from the end if amount is negative\n\t */\n\tpublic first(): Value | undefined;\n\tpublic first(amount: number): Value[];\n\tpublic first(amount?: number): Value | Value[] | undefined {\n\t\tif (amount === undefined) return this.values().next().value;\n\t\tif (amount < 0) return this.last(amount * -1);\n\t\tif (amount >= this.size) return [...this.values()];\n\n\t\tconst iter = this.values();\n\t\t// eslint-disable-next-line unicorn/no-new-array\n\t\tconst results: Value[] = new Array(amount);\n\t\tfor (let index = 0; index < amount; index++) {\n\t\t\tresults[index] = iter.next().value!;\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t/**\n\t * Obtains the first key(s) in this collection.\n\t *\n\t * @param amount - Amount of keys to obtain from the beginning\n\t * @returns A single key if no amount is provided or an array of keys, starting from the end if\n\t * amount is negative\n\t */\n\tpublic firstKey(): Key | undefined;\n\tpublic firstKey(amount: number): Key[];\n\tpublic firstKey(amount?: number): Key | Key[] | undefined {\n\t\tif (amount === undefined) return this.keys().next().value;\n\t\tif (amount < 0) return this.lastKey(amount * -1);\n\t\tif (amount >= this.size) return [...this.keys()];\n\n\t\tconst iter = this.keys();\n\t\t// eslint-disable-next-line unicorn/no-new-array\n\t\tconst results: Key[] = new Array(amount);\n\t\tfor (let index = 0; index < amount; index++) {\n\t\t\tresults[index] = iter.next().value!;\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t/**\n\t * Obtains the last value(s) in this collection.\n\t *\n\t * @param amount - Amount of values to obtain from the end\n\t * @returns A single value if no amount is provided or an array of values, starting from the start if\n\t * amount is negative\n\t */\n\tpublic last(): Value | undefined;\n\tpublic last(amount: number): Value[];\n\tpublic last(amount?: number): Value | Value[] | undefined {\n\t\tif (amount === undefined) return this.at(-1);\n\t\tif (!amount) return [];\n\t\tif (amount < 0) return this.first(amount * -1);\n\n\t\tconst arr = [...this.values()];\n\t\treturn arr.slice(amount * -1);\n\t}\n\n\t/**\n\t * Obtains the last key(s) in this collection.\n\t *\n\t * @param amount - Amount of keys to obtain from the end\n\t * @returns A single key if no amount is provided or an array of keys, starting from the start if\n\t * amount is negative\n\t */\n\tpublic lastKey(): Key | undefined;\n\tpublic lastKey(amount: number): Key[];\n\tpublic lastKey(amount?: number): Key | Key[] | undefined {\n\t\tif (amount === undefined) return this.keyAt(-1);\n\t\tif (!amount) return [];\n\t\tif (amount < 0) return this.firstKey(amount * -1);\n\n\t\tconst arr = [...this.keys()];\n\t\treturn arr.slice(amount * -1);\n\t}\n\n\t/**\n\t * Identical to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/at | Array.at()}.\n\t * Returns the item at a given index, allowing for positive and negative integers.\n\t * Negative integers count back from the last item in the collection.\n\t *\n\t * @param index - The index of the element to obtain\n\t */\n\tpublic at(index: number): Value | undefined {\n\t\tindex = Math.trunc(index);\n\t\tif (index >= 0) {\n\t\t\tif (index >= this.size) return undefined;\n\t\t} else {\n\t\t\tindex += this.size;\n\t\t\tif (index < 0) return undefined;\n\t\t}\n\n\t\tconst iter = this.values();\n\t\tfor (let skip = 0; skip < index; skip++) {\n\t\t\titer.next();\n\t\t}\n\n\t\treturn iter.next().value!;\n\t}\n\n\t/**\n\t * Identical to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/at | Array.at()}.\n\t * Returns the key at a given index, allowing for positive and negative integers.\n\t * Negative integers count back from the last item in the collection.\n\t *\n\t * @param index - The index of the key to obtain\n\t */\n\tpublic keyAt(index: number): Key | undefined {\n\t\tindex = Math.trunc(index);\n\t\tif (index >= 0) {\n\t\t\tif (index >= this.size) return undefined;\n\t\t} else {\n\t\t\tindex += this.size;\n\t\t\tif (index < 0) return undefined;\n\t\t}\n\n\t\tconst iter = this.keys();\n\t\tfor (let skip = 0; skip < index; skip++) {\n\t\t\titer.next();\n\t\t}\n\n\t\treturn iter.next().value!;\n\t}\n\n\t/**\n\t * Obtains unique random value(s) from this collection.\n\t *\n\t * @param amount - Amount of values to obtain randomly\n\t * @returns A single value if no amount is provided or an array of values\n\t */\n\tpublic random(): Value | undefined;\n\tpublic random(amount: number): Value[];\n\tpublic random(amount?: number): Value | Value[] | undefined {\n\t\tif (amount === undefined) return this.at(Math.floor(Math.random() * this.size));\n\t\tamount = Math.min(this.size, amount);\n\t\tif (!amount) return [];\n\n\t\tconst values = [...this.values()];\n\t\tfor (let sourceIndex = 0; sourceIndex < amount; sourceIndex++) {\n\t\t\tconst targetIndex = sourceIndex + Math.floor(Math.random() * (values.length - sourceIndex));\n\t\t\t[values[sourceIndex], values[targetIndex]] = [values[targetIndex]!, values[sourceIndex]!];\n\t\t}\n\n\t\treturn values.slice(0, amount);\n\t}\n\n\t/**\n\t * Obtains unique random key(s) from this collection.\n\t *\n\t * @param amount - Amount of keys to obtain randomly\n\t * @returns A single key if no amount is provided or an array\n\t */\n\tpublic randomKey(): Key | undefined;\n\tpublic randomKey(amount: number): Key[];\n\tpublic randomKey(amount?: number): Key | Key[] | undefined {\n\t\tif (amount === undefined) return this.keyAt(Math.floor(Math.random() * this.size));\n\t\tamount = Math.min(this.size, amount);\n\t\tif (!amount) return [];\n\n\t\tconst keys = [...this.keys()];\n\t\tfor (let sourceIndex = 0; sourceIndex < amount; sourceIndex++) {\n\t\t\tconst targetIndex = sourceIndex + Math.floor(Math.random() * (keys.length - sourceIndex));\n\t\t\t[keys[sourceIndex], keys[targetIndex]] = [keys[targetIndex]!, keys[sourceIndex]!];\n\t\t}\n\n\t\treturn keys.slice(0, amount);\n\t}\n\n\t/**\n\t * Identical to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse | Array.reverse()}\n\t * but returns a Collection instead of an Array.\n\t */\n\tpublic reverse() {\n\t\tconst entries = [...this.entries()].reverse();\n\t\tthis.clear();\n\t\tfor (const { 0: key, 1: value } of entries) this.set(key, value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Searches for a single item where the given function returns a truthy value. This behaves like\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/find | Array.find()}.\n\t * All collections used in Discord.js are mapped using their `id` property, and if you want to find by id you\n\t * should use the `get` method. See\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Map/get | MDN} for details.\n\t *\n\t * @param fn - The function to test with (should return a boolean)\n\t * @param thisArg - Value to use as `this` when executing the function\n\t * @example\n\t * ```ts\n\t * collection.find(user => user.username === 'Bob');\n\t * ```\n\t */\n\tpublic find<NewValue extends Value>(\n\t\tfn: (value: Value, key: Key, collection: this) => value is NewValue,\n\t): NewValue | undefined;\n\tpublic find(fn: (value: Value, key: Key, collection: this) => unknown): Value | undefined;\n\tpublic find<This, NewValue extends Value>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => value is NewValue,\n\t\tthisArg: This,\n\t): NewValue | undefined;\n\tpublic find<This>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => unknown,\n\t\tthisArg: This,\n\t): Value | undefined;\n\tpublic find(fn: (value: Value, key: Key, collection: this) => unknown, thisArg?: unknown): Value | undefined {\n\t\tif (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);\n\t\tif (thisArg !== undefined) fn = fn.bind(thisArg);\n\t\tfor (const { 0: key, 1: value } of this) {\n\t\t\tif (fn(value, key, this)) return value;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Searches for the key of a single item where the given function returns a truthy value. This behaves like\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex | Array.findIndex()},\n\t * but returns the key rather than the positional index.\n\t *\n\t * @param fn - The function to test with (should return a boolean)\n\t * @param thisArg - Value to use as `this` when executing the function\n\t * @example\n\t * ```ts\n\t * collection.findKey(user => user.username === 'Bob');\n\t * ```\n\t */\n\tpublic findKey<NewKey extends Key>(\n\t\tfn: (value: Value, key: Key, collection: this) => key is NewKey,\n\t): NewKey | undefined;\n\tpublic findKey(fn: (value: Value, key: Key, collection: this) => unknown): Key | undefined;\n\tpublic findKey<This, NewKey extends Key>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => key is NewKey,\n\t\tthisArg: This,\n\t): NewKey | undefined;\n\tpublic findKey<This>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => unknown,\n\t\tthisArg: This,\n\t): Key | undefined;\n\tpublic findKey(fn: (value: Value, key: Key, collection: this) => unknown, thisArg?: unknown): Key | undefined {\n\t\tif (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);\n\t\tif (thisArg !== undefined) fn = fn.bind(thisArg);\n\t\tfor (const { 0: key, 1: value } of this) {\n\t\t\tif (fn(value, key, this)) return key;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Searches for a last item where the given function returns a truthy value. This behaves like\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast | Array.findLast()}.\n\t *\n\t * @param fn - The function to test with (should return a boolean)\n\t * @param thisArg - Value to use as `this` when executing the function\n\t */\n\tpublic findLast<NewValue extends Value>(\n\t\tfn: (value: Value, key: Key, collection: this) => value is NewValue,\n\t): NewValue | undefined;\n\tpublic findLast(fn: (value: Value, key: Key, collection: this) => unknown): Value | undefined;\n\tpublic findLast<This, NewValue extends Value>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => value is NewValue,\n\t\tthisArg: This,\n\t): NewValue | undefined;\n\tpublic findLast<This>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => unknown,\n\t\tthisArg: This,\n\t): Value | undefined;\n\tpublic findLast(fn: (value: Value, key: Key, collection: this) => unknown, thisArg?: unknown): Value | undefined {\n\t\tif (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);\n\t\tif (thisArg !== undefined) fn = fn.bind(thisArg);\n\t\tconst entries = [...this.entries()];\n\t\tfor (let index = entries.length - 1; index >= 0; index--) {\n\t\t\tconst { 0: key, 1: value } = entries[index]!;\n\t\t\tif (fn(value, key, this)) return value;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Searches for the key of a last item where the given function returns a truthy value. This behaves like\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex | Array.findLastIndex()},\n\t * but returns the key rather than the positional index.\n\t *\n\t * @param fn - The function to test with (should return a boolean)\n\t * @param thisArg - Value to use as `this` when executing the function\n\t */\n\tpublic findLastKey<NewKey extends Key>(\n\t\tfn: (value: Value, key: Key, collection: this) => key is NewKey,\n\t): NewKey | undefined;\n\tpublic findLastKey(fn: (value: Value, key: Key, collection: this) => unknown): Key | undefined;\n\tpublic findLastKey<This, NewKey extends Key>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => key is NewKey,\n\t\tthisArg: This,\n\t): NewKey | undefined;\n\tpublic findLastKey<This>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => unknown,\n\t\tthisArg: This,\n\t): Key | undefined;\n\tpublic findLastKey(fn: (value: Value, key: Key, collection: this) => unknown, thisArg?: unknown): Key | undefined {\n\t\tif (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);\n\t\tif (thisArg !== undefined) fn = fn.bind(thisArg);\n\t\tconst entries = [...this.entries()];\n\t\tfor (let index = entries.length - 1; index >= 0; index--) {\n\t\t\tconst { 0: key, 1: value } = entries[index]!;\n\t\t\tif (fn(value, key, this)) return key;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Removes items that satisfy the provided filter function.\n\t *\n\t * @param fn - Function used to test (should return a boolean)\n\t * @param thisArg - Value to use as `this` when executing the function\n\t * @returns The number of removed entries\n\t */\n\tpublic sweep(fn: (value: Value, key: Key, collection: this) => unknown): number;\n\tpublic sweep<This>(fn: (this: This, value: Value, key: Key, collection: this) => unknown, thisArg: This): number;\n\tpublic sweep(fn: (value: Value, key: Key, collection: this) => unknown, thisArg?: unknown): number {\n\t\tif (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);\n\t\tif (thisArg !== undefined) fn = fn.bind(thisArg);\n\t\tconst previousSize = this.size;\n\t\tfor (const { 0: key, 1: value } of this) {\n\t\t\tif (fn(value, key, this)) this.delete(key);\n\t\t}\n\n\t\treturn previousSize - this.size;\n\t}\n\n\t/**\n\t * Identical to\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter | Array.filter()},\n\t * but returns a Collection instead of an Array.\n\t *\n\t * @param fn - The function to test with (should return a boolean)\n\t * @param thisArg - Value to use as `this` when executing the function\n\t * @example\n\t * ```ts\n\t * collection.filter(user => user.username === 'Bob');\n\t * ```\n\t */\n\tpublic filter<NewKey extends Key>(\n\t\tfn: (value: Value, key: Key, collection: this) => key is NewKey,\n\t): Collection<NewKey, Value>;\n\tpublic filter<NewValue extends Value>(\n\t\tfn: (value: Value, key: Key, collection: this) => value is NewValue,\n\t): Collection<Key, NewValue>;\n\tpublic filter(fn: (value: Value, key: Key, collection: this) => unknown): Collection<Key, Value>;\n\tpublic filter<This, NewKey extends Key>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => key is NewKey,\n\t\tthisArg: This,\n\t): Collection<NewKey, Value>;\n\tpublic filter<This, NewValue extends Value>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => value is NewValue,\n\t\tthisArg: This,\n\t): Collection<Key, NewValue>;\n\tpublic filter<This>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => unknown,\n\t\tthisArg: This,\n\t): Collection<Key, Value>;\n\tpublic filter(fn: (value: Value, key: Key, collection: this) => unknown, thisArg?: unknown): Collection<Key, Value> {\n\t\tif (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);\n\t\tif (thisArg !== undefined) fn = fn.bind(thisArg);\n\t\tconst results = new this.constructor[Symbol.species]<Key, Value>();\n\t\tfor (const { 0: key, 1: value } of this) {\n\t\t\tif (fn(value, key, this)) results.set(key, value);\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t/**\n\t * Partitions the collection into two collections where the first collection\n\t * contains the items that passed and the second contains the items that failed.\n\t *\n\t * @param fn - Function used to test (should return a boolean)\n\t * @param thisArg - Value to use as `this` when executing the function\n\t * @example\n\t * ```ts\n\t * const [big, small] = collection.partition(guild => guild.memberCount > 250);\n\t * ```\n\t */\n\tpublic partition<NewKey extends Key>(\n\t\tfn: (value: Value, key: Key, collection: this) => key is NewKey,\n\t): [Collection<NewKey, Value>, Collection<Exclude<Key, NewKey>, Value>];\n\tpublic partition<NewValue extends Value>(\n\t\tfn: (value: Value, key: Key, collection: this) => value is NewValue,\n\t): [Collection<Key, NewValue>, Collection<Key, Exclude<Value, NewValue>>];\n\tpublic partition(\n\t\tfn: (value: Value, key: Key, collection: this) => unknown,\n\t): [Collection<Key, Value>, Collection<Key, Value>];\n\tpublic partition<This, NewKey extends Key>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => key is NewKey,\n\t\tthisArg: This,\n\t): [Collection<NewKey, Value>, Collection<Exclude<Key, NewKey>, Value>];\n\tpublic partition<This, NewValue extends Value>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => value is NewValue,\n\t\tthisArg: This,\n\t): [Collection<Key, NewValue>, Collection<Key, Exclude<Value, NewValue>>];\n\tpublic partition<This>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => unknown,\n\t\tthisArg: This,\n\t): [Collection<Key, Value>, Collection<Key, Value>];\n\tpublic partition(\n\t\tfn: (value: Value, key: Key, collection: this) => unknown,\n\t\tthisArg?: unknown,\n\t): [Collection<Key, Value>, Collection<Key, Value>] {\n\t\tif (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);\n\t\tif (thisArg !== undefined) fn = fn.bind(thisArg);\n\t\tconst results: [Collection<Key, Value>, Collection<Key, Value>] = [\n\t\t\tnew this.constructor[Symbol.species]<Key, Value>(),\n\t\t\tnew this.constructor[Symbol.species]<Key, Value>(),\n\t\t];\n\t\tfor (const { 0: key, 1: value } of this) {\n\t\t\tif (fn(value, key, this)) {\n\t\t\t\tresults[0].set(key, value);\n\t\t\t} else {\n\t\t\t\tresults[1].set(key, value);\n\t\t\t}\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t/**\n\t * Maps each item into a Collection, then joins the results into a single Collection. Identical in behavior to\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap | Array.flatMap()}.\n\t *\n\t * @param fn - Function that produces a new Collection\n\t * @param thisArg - Value to use as `this` when executing the function\n\t * @example\n\t * ```ts\n\t * collection.flatMap(guild => guild.members.cache);\n\t * ```\n\t */\n\tpublic flatMap<NewValue>(\n\t\tfn: (value: Value, key: Key, collection: this) => Collection<Key, NewValue>,\n\t): Collection<Key, NewValue>;\n\tpublic flatMap<NewValue, This>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => Collection<Key, NewValue>,\n\t\tthisArg: This,\n\t): Collection<Key, NewValue>;\n\tpublic flatMap<NewValue>(\n\t\tfn: (value: Value, key: Key, collection: this) => Collection<Key, NewValue>,\n\t\tthisArg?: unknown,\n\t): Collection<Key, NewValue> {\n\t\t// eslint-disable-next-line unicorn/no-array-method-this-argument\n\t\tconst collections = this.map(fn, thisArg);\n\t\treturn new this.constructor[Symbol.species]<Key, NewValue>().concat(...collections);\n\t}\n\n\t/**\n\t * Maps each item to another value into an array. Identical in behavior to\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map | Array.map()}.\n\t *\n\t * @param fn - Function that produces an element of the new array, taking three arguments\n\t * @param thisArg - Value to use as `this` when executing the function\n\t * @example\n\t * ```ts\n\t * collection.map(user => user.tag);\n\t * ```\n\t */\n\tpublic map<NewValue>(fn: (value: Value, key: Key, collection: this) => NewValue): NewValue[];\n\tpublic map<This, NewValue>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => NewValue,\n\t\tthisArg: This,\n\t): NewValue[];\n\tpublic map<NewValue>(fn: (value: Value, key: Key, collection: this) => NewValue, thisArg?: unknown): NewValue[] {\n\t\tif (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);\n\t\tif (thisArg !== undefined) fn = fn.bind(thisArg);\n\t\tconst iter = this.entries();\n\t\t// eslint-disable-next-line unicorn/no-new-array\n\t\tconst results: NewValue[] = new Array(this.size);\n\t\tfor (let index = 0; index < this.size; index++) {\n\t\t\tconst { 0: key, 1: value } = iter.next().value!;\n\t\t\tresults[index] = fn(value, key, this);\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t/**\n\t * Maps each item to another value into a collection. Identical in behavior to\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map | Array.map()}.\n\t *\n\t * @param fn - Function that produces an element of the new collection, taking three arguments\n\t * @param thisArg - Value to use as `this` when executing the function\n\t * @example\n\t * ```ts\n\t * collection.mapValues(user => user.tag);\n\t * ```\n\t */\n\tpublic mapValues<NewValue>(fn: (value: Value, key: Key, collection: this) => NewValue): Collection<Key, NewValue>;\n\tpublic mapValues<This, NewValue>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => NewValue,\n\t\tthisArg: This,\n\t): Collection<Key, NewValue>;\n\tpublic mapValues<NewValue>(\n\t\tfn: (value: Value, key: Key, collection: this) => NewValue,\n\t\tthisArg?: unknown,\n\t): Collection<Key, NewValue> {\n\t\tif (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);\n\t\tif (thisArg !== undefined) fn = fn.bind(thisArg);\n\t\tconst coll = new this.constructor[Symbol.species]<Key, NewValue>();\n\t\tfor (const { 0: key, 1: value } of this) coll.set(key, fn(value, key, this));\n\t\treturn coll;\n\t}\n\n\t/**\n\t * Checks if there exists an item that passes a test. Identical in behavior to\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/some | Array.some()}.\n\t *\n\t * @param fn - Function used to test (should return a boolean)\n\t * @param thisArg - Value to use as `this` when executing the function\n\t * @example\n\t * ```ts\n\t * collection.some(user => user.discriminator === '0000');\n\t * ```\n\t */\n\tpublic some(fn: (value: Value, key: Key, collection: this) => unknown): boolean;\n\tpublic some<This>(fn: (this: This, value: Value, key: Key, collection: this) => unknown, thisArg: This): boolean;\n\tpublic some(fn: (value: Value, key: Key, collection: this) => unknown, thisArg?: unknown): boolean {\n\t\tif (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);\n\t\tif (thisArg !== undefined) fn = fn.bind(thisArg);\n\t\tfor (const { 0: key, 1: value } of this) {\n\t\t\tif (fn(value, key, this)) return true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Checks if all items passes a test. Identical in behavior to\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/every | Array.every()}.\n\t *\n\t * @param fn - Function used to test (should return a boolean)\n\t * @param thisArg - Value to use as `this` when executing the function\n\t * @example\n\t * ```ts\n\t * collection.every(user => !user.bot);\n\t * ```\n\t */\n\tpublic every<NewKey extends Key>(\n\t\tfn: (value: Value, key: Key, collection: this) => key is NewKey,\n\t): this is Collection<NewKey, Value>;\n\tpublic every<NewValue extends Value>(\n\t\tfn: (value: Value, key: Key, collection: this) => value is NewValue,\n\t): this is Collection<Key, NewValue>;\n\tpublic every(fn: (value: Value, key: Key, collection: this) => unknown): boolean;\n\tpublic every<This, NewKey extends Key>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => key is NewKey,\n\t\tthisArg: This,\n\t): this is Collection<NewKey, Value>;\n\tpublic every<This, NewValue extends Value>(\n\t\tfn: (this: This, value: Value, key: Key, collection: this) => value is NewValue,\n\t\tthisArg: This,\n\t): this is Collection<Key, NewValue>;\n\tpublic every<This>(fn: (this: This, value: Value, key: Key, collection: this) => unknown, thisArg: This): boolean;\n\tpublic every(fn: (value: Value, key: Key, collection: this) => unknown, thisArg?: unknown): boolean {\n\t\tif (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);\n\t\tif (thisArg !== undefined) fn = fn.bind(thisArg);\n\t\tfor (const { 0: key, 1: value } of this) {\n\t\t\tif (!fn(value, key, this)) return false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Applies a function to produce a single value. Identical in behavior to\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce | Array.reduce()}.\n\t *\n\t * @param fn - Function used to reduce, taking four arguments; `accumulator`, `currentValue`, `currentKey`,\n\t * and `collection`\n\t * @param initialValue - Starting value for the accumulator\n\t * @example\n\t * ```ts\n\t * collection.reduce((acc, guild) => acc + guild.memberCount, 0);\n\t * ```\n\t */\n\tpublic reduce(\n\t\tfn: (accumulator: Value, value: Value, key: Key, collection: this) => Value,\n\t\tinitialValue?: Value,\n\t): Value;\n\tpublic reduce<InitialValue>(\n\t\tfn: (accumulator: InitialValue, value: Value, key: Key, collection: this) => InitialValue,\n\t\tinitialValue: InitialValue,\n\t): InitialValue;\n\tpublic reduce<InitialValue>(\n\t\tfn: (accumulator: InitialValue, value: Value, key: Key, collection: this) => InitialValue,\n\t\tinitialValue?: InitialValue,\n\t): InitialValue {\n\t\tif (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);\n\t\tlet accumulator!: InitialValue;\n\n\t\tconst iterator = this.entries();\n\t\tif (initialValue === undefined) {\n\t\t\tif (this.size === 0) throw new TypeError('Reduce of empty collection with no initial value');\n\t\t\taccumulator = iterator.next().value![1] as unknown as InitialValue;\n\t\t} else {\n\t\t\taccumulator = initialValue;\n\t\t}\n\n\t\tfor (const { 0: key, 1: value } of iterator) {\n\t\t\taccumulator = fn(accumulator, value, key, this);\n\t\t}\n\n\t\treturn accumulator;\n\t}\n\n\t/**\n\t * Applies a function to produce a single value. Identical in behavior to\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/reduceRight | Array.reduceRight()}.\n\t *\n\t * @param fn - Function used to reduce, taking four arguments; `accumulator`, `value`, `key`, and `collection`\n\t * @param initialValue - Starting value for the accumulator\n\t */\n\tpublic reduceRight(\n\t\tfn: (accumulator: Value, value: Value, key: Key, collection: this) => Value,\n\t\tinitialValue?: Value,\n\t): Value;\n\tpublic reduceRight<InitialValue>(\n\t\tfn: (accumulator: InitialValue, value: Value, key: Key, collection: this) => InitialValue,\n\t\tinitialValue: InitialValue,\n\t): InitialValue;\n\tpublic reduceRight<InitialValue>(\n\t\tfn: (accumulator: InitialValue, value: Value, key: Key, collection: this) => InitialValue,\n\t\tinitialValue?: InitialValue,\n\t): InitialValue {\n\t\tif (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);\n\t\tconst entries = [...this.entries()];\n\t\tlet accumulator!: InitialValue;\n\n\t\tlet index: number;\n\t\tif (initialValue === undefined) {\n\t\t\tif (entries.length === 0) throw new TypeError('Reduce of empty collection with no initial value');\n\t\t\taccumulator = entries[entries.length - 1]![1] as unknown as InitialValue;\n\t\t\tindex = entries.length - 1;\n\t\t} else {\n\t\t\taccumulator = initialValue;\n\t\t\tindex = entries.length;\n\t\t}\n\n\t\twhile (--index >= 0) {\n\t\t\tconst { 0: key, 1: value } = entries[index]!;\n\t\t\taccumulator = fn(accumulator, value, key, this);\n\t\t}\n\n\t\treturn accumulator;\n\t}\n\n\t/**\n\t * Identical to\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Map/forEach | Map.forEach()},\n\t * but returns the collection instead of undefined.\n\t *\n\t * @param fn - Function to execute for each element\n\t * @param thisArg - Value to use as `this` when executing the function\n\t * @example\n\t * ```ts\n\t * collection\n\t *  .each(user => console.log(user.username))\n\t *  .filter(user => user.bot)\n\t *  .each(user => console.log(user.username));\n\t * ```\n\t */\n\tpublic each(fn: (value: Value, key: Key, collection: this) => void): this;\n\tpublic each<This>(fn: (this: This, value: Value, key: Key, collection: this) => void, thisArg: This): this;\n\tpublic each(fn: (value: Value, key: Key, collection: this) => void, thisArg?: unknown): this {\n\t\tif (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);\n\t\tif (thisArg !== undefined) fn = fn.bind(thisArg);\n\n\t\tfor (const { 0: key, 1: value } of this) {\n\t\t\tfn(value, key, this);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Runs a function on the collection and returns the collection.\n\t *\n\t * @param fn - Function to execute\n\t * @param thisArg - Value to use as `this` when executing the function\n\t * @example\n\t * ```ts\n\t * collection\n\t *  .tap(coll => console.log(coll.size))\n\t *  .filter(user => user.bot)\n\t *  .tap(coll => console.log(coll.size))\n\t * ```\n\t */\n\tpublic tap(fn: (collection: this) => void): this;\n\tpublic tap<This>(fn: (this: This, collection: this) => void, thisArg: This): this;\n\tpublic tap(fn: (collection: this) => void, thisArg?: unknown): this {\n\t\tif (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);\n\t\tif (thisArg !== undefined) fn = fn.bind(thisArg);\n\t\tfn(this);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Creates an identical shallow copy of this collection.\n\t *\n\t * @example\n\t * ```ts\n\t * const newColl = someColl.clone();\n\t * ```\n\t */\n\tpublic clone(): Collection<Key, Value> {\n\t\treturn new this.constructor[Symbol.species](this);\n\t}\n\n\t/**\n\t * Combines this collection with others into a new collection. None of the source collections are modified.\n\t *\n\t * @param collections - Collections to merge\n\t * @example\n\t * ```ts\n\t * const newColl = someColl.concat(someOtherColl, anotherColl, ohBoyAColl);\n\t * ```\n\t */\n\tpublic concat(...collections: ReadonlyCollection<Key, Value>[]) {\n\t\tconst newColl = this.clone();\n\t\tfor (const coll of collections) {\n\t\t\tfor (const { 0: key, 1: value } of coll) newColl.set(key, value);\n\t\t}\n\n\t\treturn newColl;\n\t}\n\n\t/**\n\t * Checks if this collection shares identical items with another.\n\t * This is different to checking for equality using equal-signs, because\n\t * the collections may be different objects, but contain the same data.\n\t *\n\t * @param collection - Collection to compare with\n\t * @returns Whether the collections have identical contents\n\t */\n\tpublic equals(collection: ReadonlyCollection<Key, Value>) {\n\t\tif (!collection) return false; // runtime check\n\t\tif (this === collection) return true;\n\t\tif (this.size !== collection.size) return false;\n\t\tfor (const { 0: key, 1: value } of this) {\n\t\t\tconst otherValue = collection.get(key);\n\t\t\t// If values differ, collections aren't equal.\n\t\t\t// For undefined values, we must also verify the key exists in the other collection,\n\t\t\t// since get() returns undefined for both missing keys and keys with undefined values.\n\t\t\tif (otherValue !== value || (otherValue === undefined && !collection.has(key))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * The sort method sorts the items of a collection in place and returns it.\n\t * If a comparison function is not provided, the function sorts by element values, using the same stringwise comparison algorithm as\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort | Array.sort()}.\n\t *\n\t * @param compareFunction - Specifies a function that defines the sort order. The return value of this function should be negative if\n\t * `a` comes before `b`, positive if `b` comes before `a`, or zero if `a` and `b` are considered equal.\n\t * @example\n\t * ```ts\n\t * collection.sort((userA, userB) => userA.createdTimestamp - userB.createdTimestamp);\n\t * ```\n\t */\n\tpublic sort(compareFunction: Comparator<Key, Value> = Collection.defaultSort) {\n\t\tconst entries = [...this.entries()];\n\t\tentries.sort((a, b): number => compareFunction(a[1], b[1], a[0], b[0]));\n\n\t\t// Perform clean-up\n\t\tsuper.clear();\n\n\t\t// Set the new entries\n\t\tfor (const { 0: key, 1: value } of entries) {\n\t\t\tsuper.set(key, value);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * The intersection method returns a new collection containing the items where the key is present in both collections.\n\t *\n\t * @param other - The other Collection to filter against\n\t * @example\n\t * ```ts\n\t * const col1 = new Collection([['a', 1], ['b', 2]]);\n\t * const col2 = new Collection([['a', 1], ['c', 3]]);\n\t * const intersection = col1.intersection(col2);\n\t * console.log(col1.intersection(col2));\n\t * // => Collection { 'a' => 1 }\n\t * ```\n\t */\n\tpublic intersection(other: ReadonlyCollection<Key, any>): Collection<Key, Value> {\n\t\tconst coll = new this.constructor[Symbol.species]<Key, Value>();\n\n\t\tfor (const { 0: key, 1: value } of this) {\n\t\t\tif (other.has(key)) coll.set(key, value);\n\t\t}\n\n\t\treturn coll;\n\t}\n\n\t/**\n\t * Returns a new collection containing the items where the key is present in either of the collections.\n\t *\n\t * @remarks\n\t *\n\t * If the collections have any items with the same key, the value from the first collection will be used.\n\t * @param other - The other Collection to filter against\n\t * @example\n\t * ```ts\n\t * const col1 = new Collection([['a', 1], ['b', 2]]);\n\t * const col2 = new Collection([['a', 1], ['b', 3], ['c', 3]]);\n\t * const union = col1.union(col2);\n\t * console.log(union);\n\t * // => Collection { 'a' => 1, 'b' => 2, 'c' => 3 }\n\t * ```\n\t */\n\tpublic union<OtherValue>(other: ReadonlyCollection<Key, OtherValue>): Collection<Key, OtherValue | Value> {\n\t\tconst coll = new this.constructor[Symbol.species]<Key, OtherValue | Value>(this);\n\n\t\tfor (const { 0: key, 1: value } of other) {\n\t\t\tif (!coll.has(key)) coll.set(key, value);\n\t\t}\n\n\t\treturn coll;\n\t}\n\n\t/**\n\t * Returns a new collection containing the items where the key is present in this collection but not the other.\n\t *\n\t * @param other - The other Collection to filter against\n\t * @example\n\t * ```ts\n\t * const col1 = new Collection([['a', 1], ['b', 2]]);\n\t * const col2 = new Collection([['a', 1], ['c', 3]]);\n\t * console.log(col1.difference(col2));\n\t * // => Collection { 'b' => 2 }\n\t * console.log(col2.difference(col1));\n\t * // => Collection { 'c' => 3 }\n\t * ```\n\t */\n\tpublic difference(other: ReadonlyCollection<Key, any>): Collection<Key, Value> {\n\t\tconst coll = new this.constructor[Symbol.species]<Key, Value>();\n\n\t\tfor (const { 0: key, 1: value } of this) {\n\t\t\tif (!other.has(key)) coll.set(key, value);\n\t\t}\n\n\t\treturn coll;\n\t}\n\n\t/**\n\t * Returns a new collection containing only the items where the keys are present in either collection, but not both.\n\t *\n\t * @param other - The other Collection to filter against\n\t * @example\n\t * ```ts\n\t * const col1 = new Collection([['a', 1], ['b', 2]]);\n\t * const col2 = new Collection([['a', 1], ['c', 3]]);\n\t * const symmetricDifference = col1.symmetricDifference(col2);\n\t * console.log(col1.symmetricDifference(col2));\n\t * // => Collection { 'b' => 2, 'c' => 3 }\n\t * ```\n\t */\n\tpublic symmetricDifference<OtherValue>(\n\t\tother: ReadonlyCollection<Key, OtherValue>,\n\t): Collection<Key, OtherValue | Value> {\n\t\tconst coll = new this.constructor[Symbol.species]<Key, OtherValue | Value>();\n\n\t\tfor (const { 0: key, 1: value } of this) {\n\t\t\tif (!other.has(key)) coll.set(key, value);\n\t\t}\n\n\t\tfor (const { 0: key, 1: value } of other) {\n\t\t\tif (!this.has(key)) coll.set(key, value);\n\t\t}\n\n\t\treturn coll;\n\t}\n\n\t/**\n\t * Merges two Collections together into a new Collection.\n\t *\n\t * @param other - The other Collection to merge with\n\t * @param whenInSelf - Function getting the result if the entry only exists in this Collection\n\t * @param whenInOther - Function getting the result if the entry only exists in the other Collection\n\t * @param whenInBoth - Function getting the result if the entry exists in both Collections\n\t * @example\n\t * ```ts\n\t * // Sums up the entries in two collections.\n\t * coll.merge(\n\t *  other,\n\t *  x => ({ keep: true, value: x }),\n\t *  y => ({ keep: true, value: y }),\n\t *  (x, y) => ({ keep: true, value: x + y }),\n\t * );\n\t * ```\n\t * @example\n\t * ```ts\n\t * // Intersects two collections in a left-biased manner.\n\t * coll.merge(\n\t *  other,\n\t *  x => ({ keep: false }),\n\t *  y => ({ keep: false }),\n\t *  (x, _) => ({ keep: true, value: x }),\n\t * );\n\t * ```\n\t */\n\tpublic merge<OtherValue, ResultValue>(\n\t\tother: ReadonlyCollection<Key, OtherValue>,\n\t\twhenInSelf: (value: Value, key: Key) => Keep<ResultValue>,\n\t\twhenInOther: (valueOther: OtherValue, key: Key) => Keep<ResultValue>,\n\t\twhenInBoth: (value: Value, valueOther: OtherValue, key: Key) => Keep<ResultValue>,\n\t): Collection<Key, ResultValue> {\n\t\tconst coll = new this.constructor[Symbol.species]<Key, ResultValue>();\n\t\tconst keys = new Set([...this.keys(), ...other.keys()]);\n\n\t\tfor (const key of keys) {\n\t\t\tconst hasInSelf = this.has(key);\n\t\t\tconst hasInOther = other.has(key);\n\n\t\t\tif (hasInSelf) {\n\t\t\t\tif (hasInOther) {\n\t\t\t\t\tconst result = whenInBoth(this.get(key)!, other.get(key)!, key);\n\t\t\t\t\tif (result.keep) coll.set(key, result.value);\n\t\t\t\t} else {\n\t\t\t\t\tconst result = whenInSelf(this.get(key)!, key);\n\t\t\t\t\tif (result.keep) coll.set(key, result.value);\n\t\t\t\t}\n\t\t\t} else if (hasInOther) {\n\t\t\t\tconst result = whenInOther(other.get(key)!, key);\n\t\t\t\tif (result.keep) coll.set(key, result.value);\n\t\t\t}\n\t\t}\n\n\t\treturn coll;\n\t}\n\n\t/**\n\t * Identical to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/toReversed | Array.toReversed()}\n\t * but returns a Collection instead of an Array.\n\t */\n\tpublic toReversed() {\n\t\treturn new this.constructor[Symbol.species](this).reverse();\n\t}\n\n\t/**\n\t * The toSorted method returns a shallow copy of the collection with the items sorted.\n\t * If a comparison function is not provided, the function sorts by element values, using the same stringwise comparison algorithm as\n\t * {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort | Array.sort()}.\n\t *\n\t * @param compareFunction - Specifies a function that defines the sort order. The return value of this function should be negative if\n\t * `a` comes before `b`, positive if `b` comes before `a`, or zero if `a` and `b` are considered equal.\n\t * @example\n\t * ```ts\n\t * const sortedCollection = collection.toSorted((userA, userB) => userA.createdTimestamp - userB.createdTimestamp);\n\t * ```\n\t */\n\tpublic toSorted(compareFunction: Comparator<Key, Value> = Collection.defaultSort): Collection<Key, Value> {\n\t\treturn new this.constructor[Symbol.species](this).sort(compareFunction);\n\t}\n\n\tpublic toJSON() {\n\t\t// toJSON is called recursively by JSON.stringify.\n\t\treturn [...this.entries()];\n\t}\n\n\t/**\n\t * Emulates the default sort comparison algorithm used in ECMAScript. Equivalent to calling the\n\t * {@link https://tc39.es/ecma262/multipage/indexed-collections.html#sec-comparearrayelements | CompareArrayElements}\n\t * operation with arguments `firstValue`, `secondValue` and `undefined`.\n\t */\n\tprivate static defaultSort<Value>(firstValue: Value, secondValue: Value): number {\n\t\tif (firstValue === undefined) return secondValue === undefined ? 0 : 1;\n\t\tif (secondValue === undefined) return -1;\n\n\t\tconst x = String(firstValue);\n\t\tconst y = String(secondValue);\n\t\tif (x < y) return -1;\n\t\tif (y < x) return 1;\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Creates a Collection from a list of entries.\n\t *\n\t * @param entries - The list of entries\n\t * @param combine - Function to combine an existing entry with a new one\n\t * @example\n\t * ```ts\n\t * Collection.combineEntries([[\"a\", 1], [\"b\", 2], [\"a\", 2]], (x, y) => x + y);\n\t * // returns Collection { \"a\" => 3, \"b\" => 2 }\n\t * ```\n\t */\n\tpublic static combineEntries<Key, Value>(\n\t\tentries: Iterable<[Key, Value]>,\n\t\tcombine: (firstValue: Value, secondValue: Value, key: Key) => Value,\n\t): Collection<Key, Value> {\n\t\tconst coll = new this[Symbol.species]<Key, Value>();\n\t\tfor (const { 0: key, 1: value } of entries) {\n\t\t\tif (coll.has(key)) {\n\t\t\t\tcoll.set(key, combine(coll.get(key)!, value, key));\n\t\t\t} else {\n\t\t\t\tcoll.set(key, value);\n\t\t\t}\n\t\t}\n\n\t\treturn coll;\n\t}\n\n\t/**\n\t * Identical to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Map/groupBy | Map.groupBy()}\n\t * but returns a Collection instead of a Map.\n\t */\n\tpublic static override groupBy<Key, Item>(\n\t\titems: Iterable<Item>,\n\t\tkeySelector: (item: Item, index: number) => Key,\n\t): Collection<Key, Item[]> {\n\t\treturn new this[Symbol.species]<Key, Item[]>(Map.groupBy(items, keySelector));\n\t}\n\n\t/**\n\t * @internal\n\t */\n\tdeclare public static readonly [Symbol.species]: typeof Collection;\n}\n\nexport type Keep<Value> = { keep: false } | { keep: true; value: Value };\n\nexport type Comparator<Key, Value> = (firstValue: Value, secondValue: Value, firstKey: Key, secondKey: Key) => number;\n"
  },
  {
    "path": "packages/collection/src/index.ts",
    "content": "export * from './collection.js';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/collection#readme | @discordjs/collection} version\n * that you are currently using.\n */\n// This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild\nexport const version = '[VI]{{inject}}[/VI]' as string;\n"
  },
  {
    "path": "packages/collection/tsconfig.docs.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.docs.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist-docs\"\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/collection/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/collection/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/collection/tsconfig.test.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"noEmit\": true,\n\t\t\"skipLibCheck\": true\n\t},\n\t\"include\": [\"__tests__/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/collection/tsup.config.ts",
    "content": "import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector';\nimport { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tesbuildPlugins: [esbuildPluginVersionInjector()],\n});\n"
  },
  {
    "path": "packages/core/.cliff-jumperrc.json",
    "content": "{\n\t\"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n\t\"name\": \"core\",\n\t\"org\": \"discordjs\",\n\t\"packagePath\": \"packages/core\",\n\t\"identifierBase\": false\n}\n"
  },
  {
    "path": "packages/core/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\ndist-docs\n\n# Docs\ndocs/**/*\n!docs/README.md\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/core/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/core/.prettierignore",
    "content": ".turbo\ncoverage\ndist\ndist-docs\ndocs/docs.api.json\nCHANGELOG.md\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/core/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/core/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n# [@discordjs/core@2.0.0](https://github.com/discordjs/discord.js/compare/@discordjs/core@1.2.0...@discordjs/core@2.0.0) - (2024-09-01)\n\n## Bug Fixes\n\n- **OAuth2API:** Enable token exchange without token (#10312) ([9b07036](https://github.com/discordjs/discord.js/commit/9b07036d707b123709480987d5741d6ba75b148b))\n\n## Documentation\n\n- **stageInstances:** Correct reference for stage instance creation (#10333) ([7f60a8f](https://github.com/discordjs/discord.js/commit/7f60a8fc5d412718e269774505b2ed4fc30a83cd))\n\n## Features\n\n- Use get sticker pack endpoint (#10445) ([1b1ae2f](https://github.com/discordjs/discord.js/commit/1b1ae2f0cb339170e4c0692eb43fbc966fd64030))\n- **VoiceState:** Add methods for fetching voice state (#10442) ([9907ff9](https://github.com/discordjs/discord.js/commit/9907ff915e7c72e7e980d68bf005763a3aacad1c))\n- Application emojis (#10399) ([5d92525](https://github.com/discordjs/discord.js/commit/5d92525596a0193fe65626119bb040c2eb9e945a))\n- **OAuth2API:** Add `revokeToken` method (#10440) ([69adc6f](https://github.com/discordjs/discord.js/commit/69adc6f4b9eb4fafe4a20b01137a270621f1365f))\n- Premium buttons (#10353) ([4f59b74](https://github.com/discordjs/discord.js/commit/4f59b740d01b9ff2213949708a36e17da32b89c3))\n- Add `reason` to `followAnnouncements` method (#10275) ([b36ec98](https://github.com/discordjs/discord.js/commit/b36ec983828c7001e47debcd435592ea026768d5))\n\n## Refactor\n\n- Use get guild role endpoint (#10443) ([bba0e72](https://github.com/discordjs/discord.js/commit/bba0e72e2283630b9f84b77d53525397036c6b31))\n- **ws:** Event layout (#10376) ([bf6761a](https://github.com/discordjs/discord.js/commit/bf6761a44adec1fe5017f6bf5d8bc0734916961f))\n  - **BREAKING CHANGE:** All events now emit shard id as its own param\n\n# [@discordjs/core@1.2.0](https://github.com/discordjs/discord.js/compare/@discordjs/core@1.1.1...@discordjs/core@1.2.0) - (2024-05-04)\n\n## Bug Fixes\n\n- **Gateway:** Export interface (#10060) ([ce84d3e](https://github.com/discordjs/discord.js/commit/ce84d3efee7186150c89698916e7211a2423a839))\n\n## Documentation\n\n- Remove duplicated words (#10178) ([26af386](https://github.com/discordjs/discord.js/commit/26af3868a5648042b7715a14b8ed8dd2f478345c))\n- Split docs.api.json into multiple json files ([597340f](https://github.com/discordjs/discord.js/commit/597340f288437c35da8c703d9b621274de60d880))\n\n## Features\n\n- Consumable entitlements (#10235) ([9978870](https://github.com/discordjs/discord.js/commit/997887069a00b732e62ba7bdceed714e3ede1079))\n- Polls (#10185) ([a1aeaeb](https://github.com/discordjs/discord.js/commit/a1aeaeb9d804b126dd525b6090c6f2ff9591cb9c))\n- **GuildsAPI:** Bulk ban users (#10202) ([bfc3b10](https://github.com/discordjs/discord.js/commit/bfc3b100dad97417b64ecc94d8f84135c3208072))\n- Local and preview detection ([79fbda3](https://github.com/discordjs/discord.js/commit/79fbda3aac6d4f0f8bfb193e797d09cbe331d315))\n- **guild:** Add `with_counts` to getting guilds (#10143) ([8c2abab](https://github.com/discordjs/discord.js/commit/8c2ababa786be470519e08846a1d843b406f9f50))\n- Premium application subscriptions (#9907) ([c4fcee3](https://github.com/discordjs/discord.js/commit/c4fcee3ef6021c440f162a5764d5d9465f06dc9b))\n\n## Refactor\n\n- Docs (#10126) ([18cce83](https://github.com/discordjs/discord.js/commit/18cce83d80598c430218775c53441b6b2ecdc776))\n- **oauth2:** Remove unnecessary dependency on 'node:url' (#10141) ([906ade9](https://github.com/discordjs/discord.js/commit/906ade9cc54ef3c162734e70215bef1b1cf1793e))\n- Use interfaces for AsyncEventEmitter event maps (#10044) ([adfd9cd](https://github.com/discordjs/discord.js/commit/adfd9cd3b32cfabdcc45ec90f535b2852a3ca4a6))\n\n# [@discordjs/core@1.1.1](https://github.com/discordjs/discord.js/tree/@discordjs/core@1.1.1) - (2023-11-18)\n\n## Bug Fixes\n\n- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))\n\n# [@discordjs/core@1.1.1](https://github.com/discordjs/discord.js/compare/@discordjs/core@1.1.0...@discordjs/core@1.1.1) - (2023-11-17)\n\n## Bug Fixes\n\n- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))\n\n# [@discordjs/core@1.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/core@1.0.1...@discordjs/core@1.1.0) - (2023-11-12)\n\n## Documentation\n\n- **stickers:** Reveal link in the website (#9870) ([332b624](https://github.com/discordjs/discord.js/commit/332b624aed648c707a1ba67da5535fcbf9c84497))\n- **ApplicationsAPI:** Fix `getCurrent()` options description (#9816) ([23a6424](https://github.com/discordjs/discord.js/commit/23a6424261d0d61db2742838f1b5803e3ee00625))\n\n## Features\n\n- **Client:** AsyncIterator-returning method for fetching members (#9771) ([fffe70a](https://github.com/discordjs/discord.js/commit/fffe70a039280830b2773818a776d821a6b1d3dd))\n- Add guild member (#9877) ([c051ed9](https://github.com/discordjs/discord.js/commit/c051ed94271a7f5e5dec9836571ad4856e28f3b5))\n- Onboarding mode and edit method (#9647) ([7671a83](https://github.com/discordjs/discord.js/commit/7671a836f4b080a0c0d42bbbacc6ddd1df7c0ba8))\n- Support new application properties and patch endpoint (#9709) ([1fe7247](https://github.com/discordjs/discord.js/commit/1fe72475286775cdfc68dad251ed662db7375ad1))\n- Implement `GET` current application (#9797) ([50106c7](https://github.com/discordjs/discord.js/commit/50106c77dbce34ccfac2a15e4ed6bfae4727b9ca))\n\n## Refactor\n\n- Stickers are free (no more \"premium\" packs) (#9791) ([e02a59b](https://github.com/discordjs/discord.js/commit/e02a59bbb6f57c6935230d120867519c1e84d10a))\n\n# [@discordjs/core@1.0.1](https://github.com/discordjs/discord.js/compare/@discordjs/core@1.0.0...@discordjs/core@1.0.1) - (2023-08-17)\n\n## Documentation\n\n- Update Node.js requirement to 16.11.0 (#9764) ([188877c](https://github.com/discordjs/discord.js/commit/188877c50af70f0d5cffb246620fa277435c6ce6))\n\n# [@discordjs/core@1.0.0](https://github.com/discordjs/discord.js/compare/@discordjs/core@0.6.0...@discordjs/core@1.0.0) - (2023-07-31)\n\n## Bug Fixes\n\n- **core:** Fix inconsistencies on `core` (#9680) ([6d5840c](https://github.com/discordjs/discord.js/commit/6d5840c61e5164c461b821fbd79b71b812aa046e))\n- **client:** Add missing application command permissions update event (#9639) ([2818d7c](https://github.com/discordjs/discord.js/commit/2818d7cc1d76c06252a5d89dbc48c4340cf23f3f))\n- **api:** Various fixes for overlooked stuff (#9588) ([6c7a5ed](https://github.com/discordjs/discord.js/commit/6c7a5ed1e7f05ca9350cb84c429c76acf3851fc0))\n- **GuildsAPI:** Use `level` rather than `mfa_level` when editing MFA (#9584) ([3535321](https://github.com/discordjs/discord.js/commit/3535321b98cec4a715aca19e8fd34e6d3b27975f))\n- **roleConnections:** Fix `body` type for `updateMetadataRecords()` (#9516) ([166c961](https://github.com/discordjs/discord.js/commit/166c9612611b8665a62d8a5f657f64b5a266d0f4))\n\n## Documentation\n\n- Define /core token in example (#9586) ([bc2798b](https://github.com/discordjs/discord.js/commit/bc2798b8ee33895506c4bc684b59bc8acefb615d))\n\n## Features\n\n- **WebhooksAPI:** Allow `with token` requests without bot auth (#9715) ([bc83cab](https://github.com/discordjs/discord.js/commit/bc83cabfdad76fec9352ddb9a7d488e058ede180))\n- Guild onboarding (#9120) ([dc73c93](https://github.com/discordjs/discord.js/commit/dc73c938ff9d04a0d7d57630faeb8e81ea343006))\n- **ChannelsAPI:** Add permission overwrites (#9651) ([78381a5](https://github.com/discordjs/discord.js/commit/78381a56cf9a122d0a44ab1b0966cb0d7691ad7d))\n- **api:** Add stage instances (#9578) ([985def3](https://github.com/discordjs/discord.js/commit/985def3f255b37891642172a3c83897c1d2749f6))\n- **GuildsAPI:** Add `removeMember()` (#9576) ([5d6eed6](https://github.com/discordjs/discord.js/commit/5d6eed64140029837043cf537033b97c40f39607))\n- **api:** Add `getMemberBans()` query options and `getMemberBan()` (#9569) ([590f5bc](https://github.com/discordjs/discord.js/commit/590f5bc38e6eab09e8d3d6cfd3967390202913c4))\n- **client:** Support more request member fields (#9475) ([1edd01a](https://github.com/discordjs/discord.js/commit/1edd01a7a494ee7604b81bc2a3ec25a55d957f92))\n\n## Refactor\n\n- **rest:** Switch api to fetch-like and provide strategies (#9416) ([cdaa0a3](https://github.com/discordjs/discord.js/commit/cdaa0a36f586459f1e5ede868c4250c7da90455c))\n  - **BREAKING CHANGE:** NodeJS v18+ is required when using node due to the use of global `fetch`\n  - **BREAKING CHANGE:** The raw method of REST now returns a web compatible `Respone` object.\n  - **BREAKING CHANGE:** The `parseResponse` utility method has been updated to operate on a web compatible `Response` object.\n  - **BREAKING CHANGE:** Many underlying internals have changed, some of which were exported.\n  - **BREAKING CHANGE:** `DefaultRestOptions` used to contain a default `agent`, which is now set to `null` instead.\n\n## Typings\n\n- Use `Snowflake` instead of `string` for snowflakes (#9583) ([1c4a12c](https://github.com/discordjs/discord.js/commit/1c4a12c7d62d060d655668a81d0ff4f1ae95607a))\n\n# [@discordjs/core@0.6.0](https://github.com/discordjs/discord.js/compare/@discordjs/core@0.5.2...@discordjs/core@0.6.0) - (2023-05-01)\n\n## Documentation\n\n- Update example usage (#9461) ([6212bff](https://github.com/discordjs/discord.js/commit/6212bffa30f4c6bbe6a81dc5b2b037e5b65d493c))\n- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9))\n\n## Features\n\n- **core:** Abstract gateway (#9410) ([5d1a4c2](https://github.com/discordjs/discord.js/commit/5d1a4c27d5ee2686c8fab6cad8bd97d8d0876e66))\n\n# [@discordjs/core@0.5.1](https://github.com/discordjs/discord.js/compare/@discordjs/core@0.5.0...@discordjs/core@0.5.1) - (2023-04-16)\n\n## Bug Fixes\n\n- **interactions:** Make `data` parameter optional (#9379) ([66dc401](https://github.com/discordjs/discord.js/commit/66dc4014fe4553f1dd73aaa7c32fd83e10bde263))\n- **core:** Support attachment editing on interactions (#9356) ([676307f](https://github.com/discordjs/discord.js/commit/676307ff5c6c4ef56a353b6fc74501a1080da869))\n- **core:** Missed optional options (#9311) ([6912faa](https://github.com/discordjs/discord.js/commit/6912faa9b3852adbacc7d0b002aae81be041f529))\n\n## Typings\n\n- **ChannelsAPI:** Use correct type for `editMessage` (#9399) ([0a1701b](https://github.com/discordjs/discord.js/commit/0a1701b0463919a895c518e5daa9836760d9b6cf))\n\n# [@discordjs/core@0.4.0](https://github.com/discordjs/discord.js/compare/@discordjs/core@0.3.0...@discordjs/core@0.4.0) - (2023-03-12)\n\n## Bug Fixes\n\n- **core:** Use `auth: false` for interaction callback methods (#9211) ([1b29099](https://github.com/discordjs/discord.js/commit/1b29099ed0b0deb98db844671aa23b4a84ec9c08))\n- **WebSocketShard:** Proper error bubbling (#9119) ([9681f34](https://github.com/discordjs/discord.js/commit/9681f348770b0e2ff9b7c96b1c30575dd950e2ed))\n- **oauth2:** Pass through body (#9106) ([483cbb3](https://github.com/discordjs/discord.js/commit/483cbb3b2abd2e3afadc3f814069d8e12bcf812b))\n\n## Documentation\n\n- Fix /core README example (#9201) ([f65ac2e](https://github.com/discordjs/discord.js/commit/f65ac2ea780e9f60123c611292f0d0b647106d4c))\n\n## Features\n\n- **core:** Adds `getWebhooks()` function for the channel API and for the guild API (#9043) ([c6f9c50](https://github.com/discordjs/discord.js/commit/c6f9c50ba9abf9555a2c40de3113a08765b830d5))\n- **website:** Add support for source file links (#9048) ([f6506e9](https://github.com/discordjs/discord.js/commit/f6506e99c496683ee0ab67db0726b105b929af38))\n- **core:** Implement some ws send events (#8941) ([816aed4](https://github.com/discordjs/discord.js/commit/816aed478e3035060697092d52ad2b58106be0ee))\n- **core:** Add oauth2 api support (#8938) ([36560c9](https://github.com/discordjs/discord.js/commit/36560c99559ea5d66d42e29fcf050b7d1c33cf6b))\n\n## Refactor\n\n- **core:** Move `setVoiceState` to `GuildsAPI` (#9228) ([dff131e](https://github.com/discordjs/discord.js/commit/dff131e8e4c24356d534a3dd42b33886ad30239f))\n\n## Typings\n\n- **MappedEvents:** Add `GuildAuditLogEntryCreate` (#9175) ([3492b19](https://github.com/discordjs/discord.js/commit/3492b194b5aabfb6214aa985667f5ed7188fa6e8))\n- Fix `GuildsAPI#getMembers` return type (#9037) ([158db47](https://github.com/discordjs/discord.js/commit/158db474b7514e9ff6ba6f48a89ad71c97a7088a))\n\n# [@discordjs/core@0.3.0](https://github.com/discordjs/discord.js/compare/@discordjs/core@0.2.0...@discordjs/core@0.3.0) - (2022-12-16)\n\n## Bug Fixes\n\n- **core:** Instantiate/export role connections ([166f742](https://github.com/discordjs/discord.js/commit/166f742d02d475a5044f935ee638ae1e25075b9c))\n\n# [@discordjs/core@0.2.0](https://github.com/discordjs/discord.js/tree/@discordjs/core@0.2.0) - (2022-12-16)\n\n## Bug Fixes\n\n- **thread:** `get()` route (#8897) ([3dede75](https://github.com/discordjs/discord.js/commit/3dede75621993428216196c60658e0c482aa9f61))\n- Remove casts when using `makeURLSearchParams()` (#8877) ([7430c8e](https://github.com/discordjs/discord.js/commit/7430c8e4c8e299acf750b46b6146c611b0c4941d))\n\n## Features\n\n- **core:** Add support for role connections (#8930) ([3d6fa24](https://github.com/discordjs/discord.js/commit/3d6fa248c07b2278504bbe8bafa17a3294971fd9))\n- Add links to each routes documentation (#8898) ([73300c7](https://github.com/discordjs/discord.js/commit/73300c75fae7df9af293f7c03b179236679fb753))\n- **interactions:** Add `messageId` parameter to `deleteReply()` (#8896) ([3f555d5](https://github.com/discordjs/discord.js/commit/3f555d5ddf53b778fc0e69e1ff77ec93d876dcdb))\n- Add `@discordjs/core` (#8736) ([2127b32](https://github.com/discordjs/discord.js/commit/2127b32d26dedeb44ec43d16ec2e2046919f9bb0))\n"
  },
  {
    "path": "packages/core/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n   \n   Copyright 2022 Noel Buechler\n   Copyright 2022 Suneet Tipirneni\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/core/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/core\"><img src=\"https://img.shields.io/npm/v/@discordjs/core.svg?maxAge=3600\" alt=\"npm version\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/core\"><img src=\"https://img.shields.io/npm/dt/@discordjs/core.svg?maxAge=3600\" alt=\"npm downloads\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/commits/main/packages/core\"><img alt=\"Last commit.\" src=\"https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fcore\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t\t<a href=\"https://codecov.io/gh/discordjs/discord.js\"><img src=\"https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=core\" alt=\"Code coverage\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## About\n\n`@discordjs/core` is a thinly abstracted wrapper around the \"core\" components of the Discord API: REST, and gateway.\n\n## Installation\n\n**Node.js 22.12.0 or newer is required.**\n\n```sh\nnpm install @discordjs/core\nyarn add @discordjs/core\npnpm add @discordjs/core\n```\n\n## Example usage\n\nThese examples use [ES modules](https://nodejs.org/api/esm.html#enabling).\n\n```ts\nimport {\n\tClient,\n\tGatewayDispatchEvents,\n\tGatewayIntentBits,\n\tInteractionType,\n\tMessageFlags,\n\ttype RESTGetAPIGatewayBotResult,\n} from '@discordjs/core';\nimport { REST } from '@discordjs/rest';\nimport { WebSocketManager } from '@discordjs/ws';\n\n// Create REST and WebSocket managers directly\nconst rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);\n\nconst gateway = new WebSocketManager({\n\ttoken: process.env.DISCORD_TOKEN,\n\tintents: GatewayIntentBits.GuildMessages | GatewayIntentBits.MessageContent,\n\tfetchGatewayInformation: () => rest.get('/gateway/bot') as Promise<RESTGetAPIGatewayBotResult>,\n});\n\n// Create a client to emit relevant events.\nconst client = new Client({ rest, gateway });\n\n// Listen for interactions\n// Each event contains an `api` prop along with the event data that allows you to interface with the Discord REST API\nclient.on(GatewayDispatchEvents.InteractionCreate, async ({ data: interaction, api }) => {\n\tif (interaction.type !== InteractionType.ApplicationCommand || interaction.data.name !== 'ping') {\n\t\treturn;\n\t}\n\n\tawait api.interactions.reply(interaction.id, interaction.token, { content: 'Pong!', flags: MessageFlags.Ephemeral });\n});\n\n// Listen for the ready event\nclient.once(GatewayDispatchEvents.Ready, () => console.log('Ready!'));\n\n// Start the WebSocket connection.\ngateway.connect();\n```\n\n## Independent REST API Usage\n\n```ts\nimport { API } from '@discordjs/core/http-only';\nimport { REST } from '@discordjs/rest';\n\n// Create REST instance\nconst rest = new REST({ version: '10' }).setToken(token);\n\n// Pass into API\nconst api = new API(rest);\n\n// Fetch a guild using the API wrapper\nconst guild = await api.guilds.get('1234567891011');\n```\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Documentation][documentation]\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [npm][npm]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the\n[documentation][documentation].  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs/packages/core/stable\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/core\n[npm]: https://www.npmjs.com/package/@discordjs/core\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/core/__tests__/types.test-d.ts",
    "content": "import { REST } from '@discordjs/rest';\nimport type {\n\tAPIActionRowComponent,\n\tAPIComponentInModalActionRow,\n\tRESTGetAPIChannelThreadMemberResult,\n\tRESTPostAPIInteractionCallbackWithResponseResult,\n} from 'discord-api-types/v10';\nimport { expectTypeOf, describe, test } from 'vitest';\nimport { API } from '../src/index.js';\n\nconst rest = new REST();\nconst api = new API(rest);\nconst SNOWFLAKE = '123456789012345678' as const;\nconst TOKEN = 'token' as const;\nconst MODAL_COMPONENTS: APIActionRowComponent<APIComponentInModalActionRow>[] = [] as const;\nconst boolValue = true as boolean;\n\ndescribe('Interaction with_response overloads.', () => {\n\ttest('Replying returns RESTPostAPIInteractionCallbackWithResponseResult.', () =>\n\t\texpectTypeOf(api.interactions.reply(SNOWFLAKE, TOKEN, { with_response: true })).toEqualTypeOf<\n\t\t\tPromise<RESTPostAPIInteractionCallbackWithResponseResult>\n\t\t>());\n\n\ttest('Replying returns undefined.', () => {\n\t\texpectTypeOf(api.interactions.reply(SNOWFLAKE, TOKEN, {})).toEqualTypeOf<Promise<undefined>>();\n\t\texpectTypeOf(api.interactions.reply(SNOWFLAKE, TOKEN, { with_response: false })).toEqualTypeOf<\n\t\t\tPromise<undefined>\n\t\t>();\n\t});\n\n\ttest('Replying returns either RESTPostAPIInteractionCallbackWithResponseResult or undefined.', () => {\n\t\texpectTypeOf(api.interactions.reply(SNOWFLAKE, TOKEN, { with_response: boolValue })).toEqualTypeOf<\n\t\t\tPromise<RESTPostAPIInteractionCallbackWithResponseResult | undefined>\n\t\t>();\n\t});\n\n\ttest('Defer returns RESTPostAPIInteractionCallbackWithResponseResult.', () =>\n\t\texpectTypeOf(api.interactions.defer(SNOWFLAKE, TOKEN, { with_response: true })).toEqualTypeOf<\n\t\t\tPromise<RESTPostAPIInteractionCallbackWithResponseResult>\n\t\t>());\n\n\ttest('Defer returns undefined.', () => {\n\t\texpectTypeOf(api.interactions.defer(SNOWFLAKE, TOKEN)).toEqualTypeOf<Promise<undefined>>();\n\t\texpectTypeOf(api.interactions.defer(SNOWFLAKE, TOKEN, { with_response: false })).toEqualTypeOf<\n\t\t\tPromise<undefined>\n\t\t>();\n\t});\n\n\ttest('Defer returns either RESTPostAPIInteractionCallbackWithResponseResult or undefined.', () => {\n\t\texpectTypeOf(api.interactions.defer(SNOWFLAKE, TOKEN, { with_response: boolValue })).toEqualTypeOf<\n\t\t\tPromise<RESTPostAPIInteractionCallbackWithResponseResult | undefined>\n\t\t>();\n\t});\n\n\ttest('Defer message update returns RESTPostAPIInteractionCallbackWithResponseResult.', () =>\n\t\texpectTypeOf(api.interactions.deferMessageUpdate(SNOWFLAKE, TOKEN, { with_response: true })).toEqualTypeOf<\n\t\t\tPromise<RESTPostAPIInteractionCallbackWithResponseResult>\n\t\t>());\n\n\ttest('Defer message update returns undefined.', () => {\n\t\texpectTypeOf(api.interactions.deferMessageUpdate(SNOWFLAKE, TOKEN)).toEqualTypeOf<Promise<undefined>>();\n\t\texpectTypeOf(api.interactions.deferMessageUpdate(SNOWFLAKE, TOKEN, { with_response: false })).toEqualTypeOf<\n\t\t\tPromise<undefined>\n\t\t>();\n\t});\n\n\ttest('Defer message update returns either RESTPostAPIInteractionCallbackWithResponseResult or undefined.', () => {\n\t\texpectTypeOf(api.interactions.deferMessageUpdate(SNOWFLAKE, TOKEN, { with_response: boolValue })).toEqualTypeOf<\n\t\t\tPromise<RESTPostAPIInteractionCallbackWithResponseResult | undefined>\n\t\t>();\n\t});\n\n\ttest('Update message returns RESTPostAPIInteractionCallbackWithResponseResult.', () =>\n\t\texpectTypeOf(api.interactions.updateMessage(SNOWFLAKE, TOKEN, { with_response: true })).toEqualTypeOf<\n\t\t\tPromise<RESTPostAPIInteractionCallbackWithResponseResult>\n\t\t>());\n\n\ttest('Update message returns undefined.', () => {\n\t\texpectTypeOf(api.interactions.updateMessage(SNOWFLAKE, TOKEN, {})).toEqualTypeOf<Promise<undefined>>();\n\t\texpectTypeOf(api.interactions.updateMessage(SNOWFLAKE, TOKEN, { with_response: false })).toEqualTypeOf<\n\t\t\tPromise<undefined>\n\t\t>();\n\t});\n\n\ttest('Update message returns either RESTPostAPIInteractionCallbackWithResponseResult or undefined.', () => {\n\t\texpectTypeOf(api.interactions.updateMessage(SNOWFLAKE, TOKEN, { with_response: boolValue })).toEqualTypeOf<\n\t\t\tPromise<RESTPostAPIInteractionCallbackWithResponseResult | undefined>\n\t\t>();\n\t});\n\n\ttest('Create autocomplete response returns RESTPostAPIInteractionCallbackWithResponseResult.', () =>\n\t\texpectTypeOf(api.interactions.createAutocompleteResponse(SNOWFLAKE, TOKEN, { with_response: true })).toEqualTypeOf<\n\t\t\tPromise<RESTPostAPIInteractionCallbackWithResponseResult>\n\t\t>());\n\n\ttest('Create autocomplete response returns undefined.', () => {\n\t\texpectTypeOf(api.interactions.createAutocompleteResponse(SNOWFLAKE, TOKEN, {})).toEqualTypeOf<Promise<undefined>>();\n\t\texpectTypeOf(api.interactions.createAutocompleteResponse(SNOWFLAKE, TOKEN, { with_response: false })).toEqualTypeOf<\n\t\t\tPromise<undefined>\n\t\t>();\n\t});\n\n\ttest('Create autocomplete response returns either RESTPostAPIInteractionCallbackWithResponseResult or undefined.', () => {\n\t\texpectTypeOf(\n\t\t\tapi.interactions.createAutocompleteResponse(SNOWFLAKE, TOKEN, { with_response: boolValue }),\n\t\t).toEqualTypeOf<Promise<RESTPostAPIInteractionCallbackWithResponseResult | undefined>>();\n\t});\n\n\ttest('Create modal returns RESTPostAPIInteractionCallbackWithResponseResult.', () =>\n\t\texpectTypeOf(\n\t\t\tapi.interactions.createModal(SNOWFLAKE, TOKEN, {\n\t\t\t\ttitle: '',\n\t\t\t\tcustom_id: '',\n\t\t\t\tcomponents: MODAL_COMPONENTS,\n\t\t\t\twith_response: true,\n\t\t\t}),\n\t\t).toEqualTypeOf<Promise<RESTPostAPIInteractionCallbackWithResponseResult>>());\n\n\ttest('Create modal returns undefined.', () => {\n\t\texpectTypeOf(\n\t\t\tapi.interactions.createModal(SNOWFLAKE, TOKEN, { title: '', custom_id: '', components: MODAL_COMPONENTS }),\n\t\t).toEqualTypeOf<Promise<undefined>>();\n\n\t\texpectTypeOf(\n\t\t\tapi.interactions.createModal(SNOWFLAKE, TOKEN, {\n\t\t\t\ttitle: '',\n\t\t\t\tcustom_id: '',\n\t\t\t\tcomponents: MODAL_COMPONENTS,\n\t\t\t\twith_response: false,\n\t\t\t}),\n\t\t).toEqualTypeOf<Promise<undefined>>();\n\t});\n\n\ttest('Create modal returns either RESTPostAPIInteractionCallbackWithResponseResult or undefined.', () => {\n\t\texpectTypeOf(\n\t\t\tapi.interactions.createModal(SNOWFLAKE, TOKEN, {\n\t\t\t\ttitle: '',\n\t\t\t\tcustom_id: '',\n\t\t\t\tcomponents: MODAL_COMPONENTS,\n\t\t\t\twith_response: boolValue,\n\t\t\t}),\n\t\t).toEqualTypeOf<Promise<RESTPostAPIInteractionCallbackWithResponseResult | undefined>>();\n\t});\n\n\ttest('Launch activity returns undefined.', () => {\n\t\texpectTypeOf(api.interactions.launchActivity(SNOWFLAKE, TOKEN, { with_response: false })).toEqualTypeOf<\n\t\t\tPromise<undefined>\n\t\t>();\n\t\texpectTypeOf(api.interactions.launchActivity(SNOWFLAKE, TOKEN)).toEqualTypeOf<Promise<undefined>>();\n\t});\n\n\ttest('Launch activity returns RESTPostAPIInteractionCallbackWithResponseResult.', () =>\n\t\texpectTypeOf(api.interactions.launchActivity(SNOWFLAKE, TOKEN, { with_response: true })).toEqualTypeOf<\n\t\t\tPromise<RESTPostAPIInteractionCallbackWithResponseResult>\n\t\t>());\n\n\ttest('Launch activity returns either RESTPostAPIInteractionCallbackWithResponseResult or undefined.', () =>\n\t\texpectTypeOf(api.interactions.launchActivity(SNOWFLAKE, TOKEN, { with_response: boolValue })).toEqualTypeOf<\n\t\t\tPromise<RESTPostAPIInteractionCallbackWithResponseResult | undefined>\n\t\t>());\n});\n\ndescribe('Thread member overloads.', () => {\n\ttest('Getting a thread member with with_member makes the guild member present.', () =>\n\t\texpectTypeOf(api.threads.getMember(SNOWFLAKE, SNOWFLAKE, { with_member: true })).toEqualTypeOf<\n\t\t\tPromise<Required<Pick<RESTGetAPIChannelThreadMemberResult, 'member'>> & RESTGetAPIChannelThreadMemberResult>\n\t\t>());\n\n\ttest('Getting a thread member without with_member returns RESTGetAPIChannelThreadMemberResult.', () => {\n\t\texpectTypeOf(api.threads.getMember(SNOWFLAKE, SNOWFLAKE, { with_member: false })).toEqualTypeOf<\n\t\t\tPromise<RESTGetAPIChannelThreadMemberResult>\n\t\t>();\n\n\t\texpectTypeOf(api.threads.getMember(SNOWFLAKE, SNOWFLAKE)).toEqualTypeOf<\n\t\t\tPromise<RESTGetAPIChannelThreadMemberResult>\n\t\t>();\n\t});\n});\n"
  },
  {
    "path": "packages/core/api-extractor.json",
    "content": "{\n\t\"extends\": \"../../api-extractor.json\",\n\t\"bundledPackages\": [\"discord-api-types\"],\n\t\"docModel\": {\n\t\t\"projectFolderUrl\": \"https://github.com/discordjs/discord.js/tree/main/packages/core\"\n\t}\n}\n"
  },
  {
    "path": "packages/core/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t\t{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length %}\\\n\t\\n### New Contributors\\n\n\t{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\\\n\t\t* @{{ contributor.username }} made their first contribution in #{{ contributor.pr_number }}\n\t{% endfor %}\\\n{% endif %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"@discordjs/core@[0-9]*\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/core/docs/README.md",
    "content": "## [View the documentation here.](https://discord.js.org/docs/packages/core/main)\n"
  },
  {
    "path": "packages/core/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/core\",\n\t\"version\": \"2.1.0\",\n\t\"description\": \"A thinly abstracted wrapper around the rest API, and gateway.\",\n\t\"scripts\": {\n\t\t\"test\": \"vitest run --config ../../vitest.config.ts\",\n\t\t\"build\": \"tsc --noEmit && tsup\",\n\t\t\"build:docs\": \"tsc -p tsconfig.docs.json\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src\",\n\t\t\"docs\": \"pnpm run build:docs && api-extractor run --local --minify && generate-split-documentation\",\n\t\t\"prepack\": \"pnpm run build && pnpm run lint\",\n\t\t\"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/core/*'\",\n\t\t\"release\": \"cliff-jumper\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t}\n\t\t},\n\t\t\"./http-only\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/http-only.d.ts\",\n\t\t\t\t\"default\": \"./dist/http-only.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/http-only.d.mts\",\n\t\t\t\t\"default\": \"./dist/http-only.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"main\": \"./dist/index.js\",\n\t\"module\": \"./dist/index.mjs\",\n\t\"types\": \"./dist/index.d.ts\",\n\t\"directories\": {\n\t\t\"lib\": \"src\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\",\n\t\t\"Suneet Tipirneni <suneettipirneni@icloud.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/core\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"@discordjs/rest\": \"workspace:^\",\n\t\t\"@discordjs/util\": \"workspace:^\",\n\t\t\"@discordjs/ws\": \"workspace:^\",\n\t\t\"@sapphire/snowflake\": \"^3.5.5\",\n\t\t\"@vladfrangu/async_event_emitter\": \"^2.4.7\",\n\t\t\"discord-api-types\": \"^0.38.41\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@discordjs/api-extractor\": \"workspace:^\",\n\t\t\"@discordjs/scripts\": \"workspace:^\",\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@types/node\": \"^22.19.11\",\n\t\t\"@vitest/coverage-v8\": \"^4.0.18\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"esbuild-plugin-version-injector\": \"^1.2.1\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vitest\": \"^4.0.18\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/core/scripts/check-routes.mts",
    "content": "import { Routes } from 'discord-api-types/v10';\nimport { glob, readFile } from 'node:fs/promises';\n\nconst usedRoutes = new Set<string>();\n\nconst ignoredRoutes = new Set([\n\t// Deprecated\n\t'channelPins',\n\t'channelPin',\n\t'guilds',\n\t'guildCurrentMemberNickname',\n\t'guildMFA',\n\t'nitroStickerPacks',\n]);\n\nconst cwd = new URL('../src/api/', import.meta.url);\n\nfor await (const file of glob('**/*.ts', { cwd })) {\n\tconst content = await readFile(new URL(file, cwd), 'utf-8');\n\n\tconst routes = content.matchAll(/Routes\\.([\\w\\d_]+)/g);\n\tfor (const route of routes) {\n\t\tusedRoutes.add(route[1]!);\n\t}\n}\n\nconst unusedRoutes = Object.keys(Routes).filter((route) => !usedRoutes.has(route) && !ignoredRoutes.has(route));\n\nif (unusedRoutes.length > 0) {\n\tconsole.warn('The following routes are not implemented:');\n\tfor (const route of unusedRoutes) {\n\t\tconsole.warn(` - ${route}`);\n\t}\n} else {\n\tconsole.log('No missing routes.');\n}\n"
  },
  {
    "path": "packages/core/scripts/find-returns-not-return-type.mts",
    "content": "import { glob, readFile } from 'node:fs/promises';\n\nconst cwd = new URL('../src/api/', import.meta.url);\nconst results: string[] = [];\n\nfor await (const file of glob('**/*.ts', { cwd })) {\n\tconst content = await readFile(new URL(file, cwd), { encoding: 'utf-8' });\n\n\tconst matches = content.matchAll(/as Promise<(?<returnType>\\w+)>/g);\n\n\tfor (const match of matches) {\n\t\tconst returnType = match.groups!.returnType!;\n\n\t\tif (!returnType.startsWith('REST') || !returnType.includes('Result')) {\n\t\t\tresults.push(`in file core/src/api/${file}: ${returnType}`);\n\t\t}\n\t}\n}\n\nif (results.length > 0) {\n\tconsole.warn('Found return types that are not REST return types:');\n\n\tfor (const result of results) {\n\t\tconsole.warn(`  - ${result}`);\n\t}\n} else {\n\tconsole.log('No return types that are not REST return types found');\n}\n"
  },
  {
    "path": "packages/core/src/Gateway.ts",
    "content": "import type { Awaitable } from '@discordjs/util';\nimport type { ManagerShardEventsMap, WebSocketShardEvents } from '@discordjs/ws';\nimport type { GatewaySendPayload } from 'discord-api-types/v10';\n\n/**\n * Gateway-like structure that can be used to interact with an actual WebSocket connection.\n * You can provide a custom implementation, useful for running a message broker between your app and your gateway,\n * or you can simply use the {@link @discordjs/ws#(WebSocketManager:class)}.\n */\nexport interface Gateway {\n\tgetShardCount(): Awaitable<number>;\n\ton(\n\t\tevent: WebSocketShardEvents.Dispatch,\n\t\tlistener: (...params: ManagerShardEventsMap[WebSocketShardEvents.Dispatch]) => Awaitable<void>,\n\t): this;\n\tsend(shardId: number, payload: GatewaySendPayload): Awaitable<void>;\n}\n"
  },
  {
    "path": "packages/core/src/api/applicationCommands.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport { makeURLSearchParams, type RequestData, type REST } from '@discordjs/rest';\nimport {\n\tRoutes,\n\ttype RESTGetAPIApplicationCommandPermissionsResult,\n\ttype RESTGetAPIApplicationCommandResult,\n\ttype RESTGetAPIApplicationCommandsQuery,\n\ttype RESTGetAPIApplicationCommandsResult,\n\ttype RESTGetAPIApplicationGuildCommandResult,\n\ttype RESTGetAPIApplicationGuildCommandsQuery,\n\ttype RESTGetAPIApplicationGuildCommandsResult,\n\ttype RESTGetAPIGuildApplicationCommandsPermissionsResult,\n\ttype RESTPatchAPIApplicationCommandJSONBody,\n\ttype RESTPatchAPIApplicationCommandResult,\n\ttype RESTPatchAPIApplicationGuildCommandJSONBody,\n\ttype RESTPatchAPIApplicationGuildCommandResult,\n\ttype RESTPostAPIApplicationCommandsJSONBody,\n\ttype RESTPostAPIApplicationCommandsResult,\n\ttype RESTPostAPIApplicationGuildCommandsJSONBody,\n\ttype RESTPostAPIApplicationGuildCommandsResult,\n\ttype RESTPutAPIApplicationCommandPermissionsJSONBody,\n\ttype RESTPutAPIApplicationCommandPermissionsResult,\n\ttype RESTPutAPIApplicationCommandsJSONBody,\n\ttype RESTPutAPIApplicationCommandsResult,\n\ttype RESTPutAPIApplicationGuildCommandsJSONBody,\n\ttype RESTPutAPIApplicationGuildCommandsResult,\n\ttype Snowflake,\n} from 'discord-api-types/v10';\n\nexport class ApplicationCommandsAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Fetches all global commands for a application\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#get-global-application-commands}\n\t * @param applicationId - The application id to fetch commands for\n\t * @param query - The query options for fetching commands\n\t * @param options - The options for fetching commands\n\t */\n\tpublic async getGlobalCommands(\n\t\tapplicationId: Snowflake,\n\t\tquery: RESTGetAPIApplicationCommandsQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.applicationCommands(applicationId), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIApplicationCommandsResult>;\n\t}\n\n\t/**\n\t * Creates a new global command\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#create-global-application-command}\n\t * @param applicationId - The application id to create the command for\n\t * @param body - The data for creating the command\n\t * @param options - The options for creating the command\n\t */\n\tpublic async createGlobalCommand(\n\t\tapplicationId: Snowflake,\n\t\tbody: RESTPostAPIApplicationCommandsJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.applicationCommands(applicationId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIApplicationCommandsResult>;\n\t}\n\n\t/**\n\t * Fetches a global command\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#get-global-application-command}\n\t * @param applicationId - The application id to fetch the command from\n\t * @param commandId - The command id to fetch\n\t * @param options - The options for fetching the command\n\t */\n\tpublic async getGlobalCommand(\n\t\tapplicationId: Snowflake,\n\t\tcommandId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.applicationCommand(applicationId, commandId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIApplicationCommandResult>;\n\t}\n\n\t/**\n\t * Edits a global command\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#edit-global-application-command}\n\t * @param applicationId - The application id of the command\n\t * @param commandId - The id of the command to edit\n\t * @param body - The data for editing the command\n\t * @param options - The options for editing the command\n\t */\n\tpublic async editGlobalCommand(\n\t\tapplicationId: Snowflake,\n\t\tcommandId: Snowflake,\n\t\tbody: RESTPatchAPIApplicationCommandJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.applicationCommand(applicationId, commandId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIApplicationCommandResult>;\n\t}\n\n\t/**\n\t * Deletes a global command\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#delete-global-application-command}\n\t * @param applicationId - The application id of the command\n\t * @param commandId - The id of the command to delete\n\t * @param options - The options for deleting a command\n\t */\n\tpublic async deleteGlobalCommand(\n\t\tapplicationId: Snowflake,\n\t\tcommandId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.applicationCommand(applicationId, commandId), { auth, signal });\n\t}\n\n\t/**\n\t * Overwrites global commands\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#bulk-overwrite-global-application-commands}\n\t * @param applicationId - The application id to overwrite commands for\n\t * @param body - The data for overwriting commands\n\t * @param options - The options for overwriting commands\n\t */\n\tpublic async bulkOverwriteGlobalCommands(\n\t\tapplicationId: Snowflake,\n\t\tbody: RESTPutAPIApplicationCommandsJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.put(Routes.applicationCommands(applicationId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPutAPIApplicationCommandsResult>;\n\t}\n\n\t/**\n\t * Fetches all commands for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#get-guild-application-commands}\n\t * @param applicationId - The application id to fetch commands for\n\t * @param guildId - The guild id to fetch commands for\n\t * @param query - The data for fetching commands\n\t * @param options - The options for fetching commands\n\t */\n\tpublic async getGuildCommands(\n\t\tapplicationId: Snowflake,\n\t\tguildId: Snowflake,\n\t\tquery: RESTGetAPIApplicationGuildCommandsQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.applicationGuildCommands(applicationId, guildId), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIApplicationGuildCommandsResult>;\n\t}\n\n\t/**\n\t * Creates a new command for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#create-guild-application-command}\n\t * @param applicationId - The application id to create the command for\n\t * @param guildId - The guild id to create the command for\n\t * @param body - The data for creating the command\n\t * @param options - The options for creating the command\n\t */\n\tpublic async createGuildCommand(\n\t\tapplicationId: Snowflake,\n\t\tguildId: Snowflake,\n\t\tbody: RESTPostAPIApplicationGuildCommandsJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.applicationGuildCommands(applicationId, guildId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIApplicationGuildCommandsResult>;\n\t}\n\n\t/**\n\t * Fetches a guild command\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#get-guild-application-command}\n\t * @param applicationId - The application id to fetch the command from\n\t * @param guildId - The guild id to fetch the command from\n\t * @param commandId - The command id to fetch\n\t * @param options - The options for fetching the command\n\t */\n\tpublic async getGuildCommand(\n\t\tapplicationId: Snowflake,\n\t\tguildId: Snowflake,\n\t\tcommandId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.applicationGuildCommand(applicationId, guildId, commandId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIApplicationGuildCommandResult>;\n\t}\n\n\t/**\n\t * Edits a guild command\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#edit-guild-application-command}\n\t * @param applicationId - The application id of the command\n\t * @param guildId - The guild id of the command\n\t * @param commandId - The command id to edit\n\t * @param body - The data for editing the command\n\t * @param options - The options for editing the command\n\t */\n\tpublic async editGuildCommand(\n\t\tapplicationId: Snowflake,\n\t\tguildId: Snowflake,\n\t\tcommandId: Snowflake,\n\t\tbody: RESTPatchAPIApplicationGuildCommandJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.applicationGuildCommand(applicationId, guildId, commandId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIApplicationGuildCommandResult>;\n\t}\n\n\t/**\n\t * Deletes a guild command\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#delete-guild-application-command}\n\t * @param applicationId - The application id of the command\n\t * @param guildId - The guild id of the command\n\t * @param commandId - The id of the command to delete\n\t * @param options - The options for deleting the command\n\t */\n\tpublic async deleteGuildCommand(\n\t\tapplicationId: Snowflake,\n\t\tguildId: Snowflake,\n\t\tcommandId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.applicationGuildCommand(applicationId, guildId, commandId), { auth, signal });\n\t}\n\n\t/**\n\t * Bulk overwrites guild commands\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#bulk-overwrite-guild-application-commands}\n\t * @param applicationId - The application id to overwrite commands for\n\t * @param guildId - The guild id to overwrite commands for\n\t * @param body - The data for overwriting commands\n\t * @param options - The options for overwriting the commands\n\t */\n\tpublic async bulkOverwriteGuildCommands(\n\t\tapplicationId: Snowflake,\n\t\tguildId: Snowflake,\n\t\tbody: RESTPutAPIApplicationGuildCommandsJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.put(Routes.applicationGuildCommands(applicationId, guildId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPutAPIApplicationGuildCommandsResult>;\n\t}\n\n\t/**\n\t * Fetches the permissions for a guild command\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#get-guild-application-command-permissions}\n\t * @param applicationId - The application id to get the permissions for\n\t * @param guildId - The guild id of the command\n\t * @param commandId - The command id to get the permissions for\n\t * @param options - The option for fetching the command\n\t */\n\tpublic async getGuildCommandPermissions(\n\t\tapplicationId: Snowflake,\n\t\tguildId: Snowflake,\n\t\tcommandId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.applicationCommandPermissions(applicationId, guildId, commandId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIApplicationCommandPermissionsResult>;\n\t}\n\n\t/**\n\t * Fetches all permissions for all commands in a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#get-application-command-permissions}\n\t * @param applicationId - The application id to get the permissions for\n\t * @param guildId - The guild id to get the permissions for\n\t * @param options - The options for fetching permissions\n\t */\n\tpublic async getGuildCommandsPermissions(\n\t\tapplicationId: Snowflake,\n\t\tguildId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildApplicationCommandsPermissions(applicationId, guildId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildApplicationCommandsPermissionsResult>;\n\t}\n\n\t/**\n\t * Edits the permissions for a guild command\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/application-commands#edit-application-command-permissions}\n\t * @param userToken - The token of the user to edit permissions on behalf of\n\t * @param applicationId - The application id to edit the permissions for\n\t * @param guildId - The guild id to edit the permissions for\n\t * @param commandId - The id of the command to edit the permissions for\n\t * @param body - The data for editing the permissions\n\t * @param options - The options for editing the permissions\n\t */\n\tpublic async editGuildCommandPermissions(\n\t\tuserToken: string,\n\t\tapplicationId: Snowflake,\n\t\tguildId: Snowflake,\n\t\tcommandId: Snowflake,\n\t\tbody: RESTPutAPIApplicationCommandPermissionsJSONBody,\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\treturn this.rest.put(Routes.applicationCommandPermissions(applicationId, guildId, commandId), {\n\t\t\theaders: { Authorization: `Bearer ${userToken.replace('Bearer ', '')}` },\n\t\t\tauth: false,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPutAPIApplicationCommandPermissionsResult>;\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/applications.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport type { RequestData, REST } from '@discordjs/rest';\nimport {\n\tRoutes,\n\ttype RESTGetAPIApplicationEmojiResult,\n\ttype RESTGetAPIApplicationEmojisResult,\n\ttype RESTGetCurrentApplicationResult,\n\ttype RESTPatchAPIApplicationEmojiJSONBody,\n\ttype RESTPatchAPIApplicationEmojiResult,\n\ttype RESTPatchCurrentApplicationJSONBody,\n\ttype RESTPatchCurrentApplicationResult,\n\ttype RESTPostAPIApplicationEmojiJSONBody,\n\ttype RESTPostAPIApplicationEmojiResult,\n\ttype Snowflake,\n} from 'discord-api-types/v10';\n\nexport class ApplicationsAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Fetches the application associated with the requesting bot user.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/application#get-current-application}\n\t * @param options - The options for fetching the application\n\t */\n\tpublic async getCurrent({ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.currentApplication(), { auth, signal }) as Promise<RESTGetCurrentApplicationResult>;\n\t}\n\n\t/**\n\t * Edits properties of the application associated with the requesting bot user.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/application#edit-current-application}\n\t * @param body - The new application data\n\t * @param options - The options for editing the application\n\t */\n\tpublic async editCurrent(\n\t\tbody: RESTPatchCurrentApplicationJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.currentApplication(), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchCurrentApplicationResult>;\n\t}\n\n\t/**\n\t * Fetches all emojis of an application\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/emoji#list-application-emojis}\n\t * @param applicationId - The id of the application to fetch the emojis of\n\t * @param options - The options for fetching the emojis\n\t */\n\tpublic async getEmojis(applicationId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.applicationEmojis(applicationId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIApplicationEmojisResult>;\n\t}\n\n\t/**\n\t * Fetches an emoji of an application\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/emoji#get-application-emoji}\n\t * @param applicationId - The id of the application to fetch the emoji of\n\t * @param emojiId - The id of the emoji to fetch\n\t * @param options - The options for fetching the emoji\n\t */\n\tpublic async getEmoji(\n\t\tapplicationId: Snowflake,\n\t\temojiId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.applicationEmoji(applicationId, emojiId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIApplicationEmojiResult>;\n\t}\n\n\t/**\n\t * Creates a new emoji of an application\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/emoji#create-application-emoji}\n\t * @param applicationId - The id of the application to create the emoji of\n\t * @param body - The data for creating the emoji\n\t * @param options - The options for creating the emoji\n\t */\n\tpublic async createEmoji(\n\t\tapplicationId: Snowflake,\n\t\tbody: RESTPostAPIApplicationEmojiJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.applicationEmojis(applicationId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIApplicationEmojiResult>;\n\t}\n\n\t/**\n\t * Edits an emoji of an application\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/emoji#modify-application-emoji}\n\t * @param applicationId - The id of the application to edit the emoji of\n\t * @param emojiId - The id of the emoji to edit\n\t * @param body - The data for editing the emoji\n\t * @param options - The options for editing the emoji\n\t */\n\tpublic async editEmoji(\n\t\tapplicationId: Snowflake,\n\t\temojiId: Snowflake,\n\t\tbody: RESTPatchAPIApplicationEmojiJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.applicationEmoji(applicationId, emojiId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIApplicationEmojiResult>;\n\t}\n\n\t/**\n\t * Deletes an emoji of an application\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/emoji#delete-application-emoji}\n\t * @param applicationId - The id of the application to delete the emoji of\n\t * @param emojiId - The id of the emoji to delete\n\t * @param options - The options for deleting the emoji\n\t */\n\tpublic async deleteEmoji(\n\t\tapplicationId: Snowflake,\n\t\temojiId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.applicationEmoji(applicationId, emojiId), { auth, signal });\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/channel.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport { makeURLSearchParams, type RawFile, type RequestData, type REST } from '@discordjs/rest';\nimport {\n\tRoutes,\n\ttype RESTDeleteAPIChannelResult,\n\ttype RESTGetAPIChannelInvitesResult,\n\ttype RESTGetAPIChannelMessageReactionUsersQuery,\n\ttype RESTGetAPIChannelMessageReactionUsersResult,\n\ttype RESTGetAPIChannelMessageResult,\n\ttype RESTGetAPIChannelMessagesPinsQuery,\n\ttype RESTGetAPIChannelMessagesPinsResult,\n\ttype RESTGetAPIChannelMessagesQuery,\n\ttype RESTGetAPIChannelMessagesResult,\n\ttype RESTGetAPIChannelResult,\n\ttype RESTGetAPIChannelThreadsArchivedQuery,\n\ttype RESTGetAPIChannelUsersThreadsArchivedResult,\n\ttype RESTGetAPIChannelWebhooksResult,\n\ttype RESTPatchAPIChannelJSONBody,\n\ttype RESTPatchAPIChannelMessageJSONBody,\n\ttype RESTPatchAPIChannelMessageResult,\n\ttype RESTPatchAPIChannelResult,\n\ttype RESTPostAPIChannelFollowersResult,\n\ttype RESTPostAPIChannelInviteJSONBody,\n\ttype RESTPostAPIChannelInviteResult,\n\ttype RESTPostAPIChannelMessageCrosspostResult,\n\ttype RESTPostAPIChannelMessageJSONBody,\n\ttype RESTPostAPIChannelMessageResult,\n\ttype RESTPostAPIChannelThreadsJSONBody,\n\ttype RESTPostAPIChannelThreadsResult,\n\ttype RESTPostAPIChannelWebhookJSONBody,\n\ttype RESTPostAPIChannelWebhookResult,\n\ttype RESTPostAPIGuildForumThreadsJSONBody,\n\ttype RESTPostAPISendSoundboardSoundResult,\n\ttype RESTPostAPISoundboardSendSoundJSONBody,\n\ttype RESTPutAPIChannelPermissionJSONBody,\n\ttype RESTPutAPIChannelRecipientJSONBody,\n\ttype Snowflake,\n} from 'discord-api-types/v10';\n\nexport interface StartForumThreadOptions extends RESTPostAPIGuildForumThreadsJSONBody {\n\tmessage: RESTPostAPIGuildForumThreadsJSONBody['message'] & { files?: RawFile[] };\n}\n\nexport interface CreateMessageOptions extends RESTPostAPIChannelMessageJSONBody {\n\tfiles?: RawFile[];\n}\n\nexport interface EditMessageOptions extends RESTPatchAPIChannelMessageJSONBody {\n\tfiles?: RawFile[];\n}\n\nexport class ChannelsAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Sends a message in a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#create-message}\n\t * @param channelId - The id of the channel to send the message in\n\t * @param body - The data for sending the message\n\t * @param options - The options for sending the message\n\t */\n\tpublic async createMessage(\n\t\tchannelId: Snowflake,\n\t\t{ files, ...body }: CreateMessageOptions,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.channelMessages(channelId), {\n\t\t\tauth,\n\t\t\tfiles,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIChannelMessageResult>;\n\t}\n\n\t/**\n\t * Edits a message\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#edit-message}\n\t * @param channelId - The id of the channel the message is in\n\t * @param messageId - The id of the message to edit\n\t * @param body - The data for editing the message\n\t * @param options - The options for editing the message\n\t */\n\tpublic async editMessage(\n\t\tchannelId: Snowflake,\n\t\tmessageId: Snowflake,\n\t\t{ files, ...body }: EditMessageOptions,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.channelMessage(channelId, messageId), {\n\t\t\tauth,\n\t\t\tfiles,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIChannelMessageResult>;\n\t}\n\n\t/**\n\t * Fetches the reactions for a message\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#get-reactions}\n\t * @param channelId - The id of the channel the message is in\n\t * @param messageId - The id of the message to get the reactions for\n\t * @param emoji - The emoji to get the reactions for. URL encoding happens internally\n\t * @param query - The query options for fetching the reactions\n\t * @param options - The options for fetching the message reactions\n\t * @example\n\t * ```ts\n\t * // Unicode.\n\t * await api.channels.getMessageReactions('1234567890', '1234567890', '👍');\n\t *\n\t * // Custom emoji.\n\t * await api.channels.getMessageReactions('1234567890', '1234567890', 'emoji_name:1234567890');\n\t * ```\n\t */\n\tpublic async getMessageReactions(\n\t\tchannelId: Snowflake,\n\t\tmessageId: Snowflake,\n\t\temoji: string,\n\t\tquery: RESTGetAPIChannelMessageReactionUsersQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.channelMessageReaction(channelId, messageId, encodeURIComponent(emoji)), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIChannelMessageReactionUsersResult>;\n\t}\n\n\t/**\n\t * Deletes a reaction for the current user\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#delete-own-reaction}\n\t * @param channelId - The id of the channel the message is in\n\t * @param messageId - The id of the message to delete the reaction for\n\t * @param emoji - The emoji to delete the reaction for. URL encoding happens internally\n\t * @param options - The options for deleting the reaction\n\t * @example\n\t * ```ts\n\t * // Unicode.\n\t * await api.channels.deleteOwnMessageReaction('1234567890', '1234567890', '👍');\n\t *\n\t * // Custom emoji.\n\t * await api.channels.deleteOwnMessageReaction('1234567890', '1234567890', 'emoji_name:1234567890');\n\t * ```\n\t */\n\tpublic async deleteOwnMessageReaction(\n\t\tchannelId: Snowflake,\n\t\tmessageId: Snowflake,\n\t\temoji: string,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.channelMessageOwnReaction(channelId, messageId, encodeURIComponent(emoji)), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t});\n\t}\n\n\t/**\n\t * Deletes a reaction for a user\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#delete-user-reaction}\n\t * @param channelId - The id of the channel the message is in\n\t * @param messageId - The id of the message to delete the reaction for\n\t * @param emoji - The emoji to delete the reaction for. URL encoding happens internally\n\t * @param userId - The id of the user to delete the reaction for\n\t * @param options - The options for deleting the reaction\n\t * @example\n\t * ```ts\n\t * // Unicode.\n\t * await api.channels.deleteUserMessageReaction('1234567890', '1234567890', '👍', '1234567890');\n\t *\n\t * // Custom emoji.\n\t * await api.channels.deleteUserMessageReaction('1234567890', '1234567890', 'emoji_name:1234567890', '1234567890');\n\t * ```\n\t */\n\tpublic async deleteUserMessageReaction(\n\t\tchannelId: Snowflake,\n\t\tmessageId: Snowflake,\n\t\temoji: string,\n\t\tuserId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.channelMessageUserReaction(channelId, messageId, encodeURIComponent(emoji), userId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t});\n\t}\n\n\t/**\n\t * Deletes all reactions for a message\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#delete-all-reactions}\n\t * @param channelId - The id of the channel the message is in\n\t * @param messageId - The id of the message to delete the reactions for\n\t * @param options - The options for deleting the reactions\n\t */\n\tpublic async deleteAllMessageReactions(\n\t\tchannelId: Snowflake,\n\t\tmessageId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.channelMessageAllReactions(channelId, messageId), { auth, signal });\n\t}\n\n\t/**\n\t * Deletes all reactions of an emoji for a message\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#delete-all-reactions-for-emoji}\n\t * @param channelId - The id of the channel the message is in\n\t * @param messageId - The id of the message to delete the reactions for\n\t * @param emoji - The emoji to delete the reactions for. URL encoding happens internally\n\t * @param options - The options for deleting the reactions\n\t * @example\n\t * ```ts\n\t * // Unicode.\n\t * await api.channels.deleteAllMessageReactionsForEmoji('1234567890', '1234567890', '👍');\n\t *\n\t * // Custom emoji.\n\t * await api.channels.deleteAllMessageReactionsForEmoji('1234567890', '1234567890', 'emoji_name:1234567890');\n\t * ```\n\t */\n\tpublic async deleteAllMessageReactionsForEmoji(\n\t\tchannelId: Snowflake,\n\t\tmessageId: Snowflake,\n\t\temoji: string,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.channelMessageReaction(channelId, messageId, encodeURIComponent(emoji)), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t});\n\t}\n\n\t/**\n\t * Adds a reaction to a message\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#create-reaction}\n\t * @param channelId - The id of the channel the message is in\n\t * @param messageId - The id of the message to add the reaction to\n\t * @param emoji - The emoji to add the reaction with. URL encoding happens internally\n\t * @param options - The options for adding the reaction\n\t * @example\n\t * ```ts\n\t * // Unicode.\n\t * await api.channels.addMessageReaction('1234567890', '1234567890', '👍');\n\t *\n\t * // Custom emoji.\n\t * await api.channels.addMessageReaction('1234567890', '1234567890', 'emoji_name:1234567890');\n\t * ```\n\t */\n\tpublic async addMessageReaction(\n\t\tchannelId: Snowflake,\n\t\tmessageId: Snowflake,\n\t\temoji: string,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.put(Routes.channelMessageOwnReaction(channelId, messageId, encodeURIComponent(emoji)), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t});\n\t}\n\n\t/**\n\t * Fetches a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#get-channel}\n\t * @param channelId - The id of the channel\n\t * @param options - The options for fetching the channel\n\t */\n\tpublic async get(channelId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.channel(channelId), { auth, signal }) as Promise<RESTGetAPIChannelResult>;\n\t}\n\n\t/**\n\t * Edits a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#modify-channel}\n\t * @param channelId - The id of the channel to edit\n\t * @param body - The new channel data\n\t * @param options - The options for editing the channel\n\t */\n\tpublic async edit(\n\t\tchannelId: Snowflake,\n\t\tbody: RESTPatchAPIChannelJSONBody,\n\t\t{ auth, signal, reason }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.channel(channelId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIChannelResult>;\n\t}\n\n\t/**\n\t * Deletes a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#deleteclose-channel}\n\t * @param channelId - The id of the channel to delete\n\t * @param options - The options for deleting the channel\n\t */\n\tpublic async delete(\n\t\tchannelId: Snowflake,\n\t\t{ auth, signal, reason }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.delete(Routes.channel(channelId), { auth, signal, reason }) as Promise<RESTDeleteAPIChannelResult>;\n\t}\n\n\t/**\n\t * Fetches the messages of a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#get-channel-messages}\n\t * @param channelId - The id of the channel to fetch messages from\n\t * @param query - The query options for fetching messages\n\t * @param options - The options for fetching the messages\n\t */\n\tpublic async getMessages(\n\t\tchannelId: Snowflake,\n\t\tquery: RESTGetAPIChannelMessagesQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.channelMessages(channelId), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIChannelMessagesResult>;\n\t}\n\n\t/**\n\t * Shows a typing indicator in a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#trigger-typing-indicator}\n\t * @param channelId - The id of the channel to show the typing indicator in\n\t * @param options - The options for showing the typing indicator\n\t */\n\tpublic async showTyping(channelId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\tawait this.rest.post(Routes.channelTyping(channelId), { auth, signal });\n\t}\n\n\t/**\n\t * Fetches pinned messages of a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#get-channel-pins}\n\t * @param channelId - The id of the channel to fetch pinned messages from\n\t * @param query - The query options for fetching pinned messages\n\t * @param options - The options for fetching pinned messages\n\t */\n\tpublic async getPins(\n\t\tchannelId: Snowflake,\n\t\tquery: RESTGetAPIChannelMessagesPinsQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.channelMessagesPins(channelId), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIChannelMessagesPinsResult>;\n\t}\n\n\t/**\n\t * Pins a message in a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#pin-message}\n\t * @param channelId - The id of the channel to pin the message in\n\t * @param messageId - The id of the message to pin\n\t * @param options - The options for pinning the message\n\t */\n\tpublic async pinMessage(\n\t\tchannelId: Snowflake,\n\t\tmessageId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.put(Routes.channelMessagesPin(channelId, messageId), { auth, reason, signal });\n\t}\n\n\t/**\n\t * Deletes a message\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#delete-message}\n\t * @param channelId - The id of the channel the message is in\n\t * @param messageId - The id of the message to delete\n\t * @param options - The options for deleting the message\n\t */\n\tpublic async deleteMessage(\n\t\tchannelId: Snowflake,\n\t\tmessageId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.channelMessage(channelId, messageId), { auth, reason, signal });\n\t}\n\n\t/**\n\t * Bulk deletes messages\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#bulk-delete-messages}\n\t * @param channelId - The id of the channel the messages are in\n\t * @param messageIds - The ids of the messages to delete\n\t * @param options - The options for deleting the messages\n\t */\n\tpublic async bulkDeleteMessages(\n\t\tchannelId: Snowflake,\n\t\tmessageIds: Snowflake[],\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t): Promise<void> {\n\t\tawait this.rest.post(Routes.channelBulkDelete(channelId), { auth, reason, body: { messages: messageIds }, signal });\n\t}\n\n\t/**\n\t * Fetches a message\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#get-channel-message}\n\t * @param channelId - The id of the channel the message is in\n\t * @param messageId - The id of the message to fetch\n\t * @param options - The options for fetching the message\n\t */\n\tpublic async getMessage(\n\t\tchannelId: Snowflake,\n\t\tmessageId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.channelMessage(channelId, messageId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIChannelMessageResult>;\n\t}\n\n\t/**\n\t * Crossposts a message\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#crosspost-message}\n\t * @param channelId - The id of the channel the message is in\n\t * @param messageId - The id of the message to crosspost\n\t * @param options - The options for crossposting the message\n\t */\n\tpublic async crosspostMessage(\n\t\tchannelId: Snowflake,\n\t\tmessageId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.channelMessageCrosspost(channelId, messageId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIChannelMessageCrosspostResult>;\n\t}\n\n\t/**\n\t * Unpins a message in a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/message#unpin-message}\n\t * @param channelId - The id of the channel to unpin the message in\n\t * @param messageId - The id of the message to unpin\n\t * @param options - The options for unpinning the message\n\t */\n\tpublic async unpinMessage(\n\t\tchannelId: Snowflake,\n\t\tmessageId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.channelMessagesPin(channelId, messageId), { auth, reason, signal });\n\t}\n\n\t/**\n\t * Follows an announcement channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#follow-announcement-channel}\n\t * @param channelId - The id of the announcement channel to follow\n\t * @param webhookChannelId - The id of the webhook channel to follow the announcements in\n\t * @param options - The options for following the announcement channel\n\t */\n\tpublic async followAnnouncements(\n\t\tchannelId: Snowflake,\n\t\twebhookChannelId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.channelFollowers(channelId), {\n\t\t\tauth,\n\t\t\tbody: { webhook_channel_id: webhookChannelId },\n\t\t\treason,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIChannelFollowersResult>;\n\t}\n\n\t/**\n\t * Creates a new invite for a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#create-channel-invite}\n\t * @param channelId - The id of the channel to create an invite for\n\t * @param body - The data for creating the invite\n\t * @param options - The options for creating the invite\n\t */\n\tpublic async createInvite(\n\t\tchannelId: Snowflake,\n\t\tbody: RESTPostAPIChannelInviteJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.channelInvites(channelId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIChannelInviteResult>;\n\t}\n\n\t/**\n\t * Fetches the invites of a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#get-channel-invites}\n\t * @param channelId - The id of the channel to fetch invites from\n\t * @param options - The options for fetching the invites\n\t */\n\tpublic async getInvites(channelId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.channelInvites(channelId), { auth, signal }) as Promise<RESTGetAPIChannelInvitesResult>;\n\t}\n\n\t/**\n\t * Creates a new thread\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#start-thread-from-message}\n\t * @see {@link https://discord.com/developers/docs/resources/channel#start-thread-without-message}\n\t * @param channelId - The id of the channel to start the thread in\n\t * @param body - The data for starting the thread\n\t * @param messageId - The id of the message to start the thread from\n\t * @param options - The options for starting the thread\n\t */\n\tpublic async createThread(\n\t\tchannelId: Snowflake,\n\t\tbody: RESTPostAPIChannelThreadsJSONBody,\n\t\tmessageId?: Snowflake,\n\t\t{ auth, signal, reason }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.threads(channelId, messageId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t\treason,\n\t\t}) as Promise<RESTPostAPIChannelThreadsResult>;\n\t}\n\n\t/**\n\t * Creates a new forum post\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#start-thread-in-forum-or-media-channel}\n\t * @param channelId - The id of the forum channel to start the thread in\n\t * @param body - The data for starting the thread\n\t * @param options - The options for starting the thread\n\t */\n\tpublic async createForumThread(\n\t\tchannelId: Snowflake,\n\t\t{ message, ...optionsBody }: StartForumThreadOptions,\n\t\t{ auth, signal, reason }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tconst { files, ...messageBody } = message;\n\n\t\tconst body = {\n\t\t\t...optionsBody,\n\t\t\tmessage: messageBody,\n\t\t};\n\n\t\treturn this.rest.post(Routes.threads(channelId), {\n\t\t\tauth,\n\t\t\tfiles,\n\t\t\tbody,\n\t\t\treason,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIChannelThreadsResult>;\n\t}\n\n\t/**\n\t * Fetches the archived threads of a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#list-public-archived-threads}\n\t * @see {@link https://discord.com/developers/docs/resources/channel#list-private-archived-threads}\n\t * @param channelId - The id of the channel to fetch archived threads from\n\t * @param archivedStatus - The archived status of the threads to fetch\n\t * @param query - The options for fetching archived threads\n\t * @param options - The options for fetching archived threads\n\t */\n\tpublic async getArchivedThreads(\n\t\tchannelId: Snowflake,\n\t\tarchivedStatus: 'private' | 'public',\n\t\tquery: RESTGetAPIChannelThreadsArchivedQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.channelThreads(channelId, archivedStatus), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIChannelUsersThreadsArchivedResult>;\n\t}\n\n\t/**\n\t * Fetches the private joined archived threads of a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#list-joined-private-archived-threads}\n\t * @param channelId - The id of the channel to fetch joined archived threads from\n\t * @param query - The options for fetching joined archived threads\n\t * @param options - The options for fetching joined archived threads\n\t */\n\tpublic async getJoinedPrivateArchivedThreads(\n\t\tchannelId: Snowflake,\n\t\tquery: RESTGetAPIChannelThreadsArchivedQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.channelJoinedArchivedThreads(channelId), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIChannelUsersThreadsArchivedResult>;\n\t}\n\n\t/**\n\t * Creates a new webhook\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#create-webhook}\n\t * @param channelId - The id of the channel to create the webhook in\n\t * @param body - The data for creating the webhook\n\t * @param options - The options for creating the webhook\n\t */\n\tpublic async createWebhook(\n\t\tchannelId: Snowflake,\n\t\tbody: RESTPostAPIChannelWebhookJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.channelWebhooks(channelId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIChannelWebhookResult>;\n\t}\n\n\t/**\n\t * Fetches the webhooks of a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#get-channel-webhooks}\n\t * @param channelId - The id of the channel\n\t * @param options - The options for fetching the webhooks\n\t */\n\tpublic async getWebhooks(channelId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.channelWebhooks(channelId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIChannelWebhooksResult>;\n\t}\n\n\t/**\n\t * Edits the permission overwrite for a user or role in a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#edit-channel-permissions}\n\t * @param channelId - The id of the channel to edit the permission overwrite in\n\t * @param overwriteId - The id of the user or role to edit the permission overwrite for\n\t * @param body - The data for editing the permission overwrite\n\t * @param options - The options for editing the permission overwrite\n\t */\n\tpublic async editPermissionOverwrite(\n\t\tchannelId: Snowflake,\n\t\toverwriteId: Snowflake,\n\t\tbody: RESTPutAPIChannelPermissionJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.put(Routes.channelPermission(channelId, overwriteId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t});\n\t}\n\n\t/**\n\t * Deletes the permission overwrite for a user or role in a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#delete-channel-permission}\n\t * @param channelId - The id of the channel to delete the permission overwrite in\n\t * @param overwriteId - The id of the user or role to delete the permission overwrite for\n\t * @param options - The options for deleting the permission overwrite\n\t */\n\tpublic async deletePermissionOverwrite(\n\t\tchannelId: Snowflake,\n\t\toverwriteId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.channelPermission(channelId, overwriteId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tsignal,\n\t\t});\n\t}\n\n\t/**\n\t * Sends a soundboard sound in a channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/soundboard#send-soundboard-sound}\n\t * @param channelId - The id of the channel to send the soundboard sound in\n\t * @param body - The data for sending the soundboard sound\n\t * @param options - The options for sending the soundboard sound\n\t */\n\tpublic async sendSoundboardSound(\n\t\tchannelId: Snowflake,\n\t\tbody: RESTPostAPISoundboardSendSoundJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.sendSoundboardSound(channelId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPISendSoundboardSoundResult>;\n\t}\n\n\t/**\n\t * Adds a recipient to a group DM channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#group-dm-add-recipient}\n\t * @param channelId - The id of the channel to add the recipient to\n\t * @param userId - The id of the user to add as a recipient\n\t * @param body - The data for adding the recipient\n\t * @param options - The options for adding the recipient\n\t */\n\tpublic async addGroupDMRecipient(\n\t\tchannelId: Snowflake,\n\t\tuserId: Snowflake,\n\t\tbody: RESTPutAPIChannelRecipientJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.put(Routes.channelRecipient(channelId, userId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t});\n\t}\n\n\t/**\n\t * Removes a recipient from a group DM channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#group-dm-remove-recipient}\n\t * @param channelId - The id of the channel to remove the recipient from\n\t * @param userId - The id of the user to remove as a recipient\n\t * @param options - The options for removing the recipient\n\t */\n\tpublic async removeGroupDMRecipient(\n\t\tchannelId: Snowflake,\n\t\tuserId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.channelRecipient(channelId, userId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/gateway.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport type { RequestData, REST } from '@discordjs/rest';\nimport { Routes, type RESTGetAPIGatewayBotResult, type RESTGetAPIGatewayResult } from 'discord-api-types/v10';\n\nexport class GatewayAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Gets gateway information.\n\t *\n\t * @see {@link https://discord.com/developers/docs/events/gateway#get-gateway}\n\t * @param options - The options for fetching the gateway information\n\t */\n\tpublic async get({ signal }: Pick<RequestData, 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.gateway(), {\n\t\t\tauth: false,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGatewayResult>;\n\t}\n\n\t/**\n\t * Gets gateway information with additional metadata.\n\t *\n\t * @see {@link https://discord.com/developers/docs/events/gateway#get-gateway-bot}\n\t * @param options - The options for fetching the gateway information\n\t */\n\tpublic async getBot({ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.gatewayBot(), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGatewayBotResult>;\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/guild.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport { makeURLSearchParams, type REST, type RawFile, type RequestData } from '@discordjs/rest';\nimport {\n\tRoutes,\n\ttype GuildWidgetStyle,\n\ttype RESTGetAPIAuditLogQuery,\n\ttype RESTGetAPIAuditLogResult,\n\ttype RESTGetAPIAutoModerationRuleResult,\n\ttype RESTGetAPIAutoModerationRulesResult,\n\ttype RESTGetAPIGuildBanResult,\n\ttype RESTGetAPIGuildBansQuery,\n\ttype RESTGetAPIGuildBansResult,\n\ttype RESTGetAPIGuildChannelsResult,\n\ttype RESTGetAPIGuildEmojiResult,\n\ttype RESTGetAPIGuildEmojisResult,\n\ttype RESTGetAPIGuildIntegrationsResult,\n\ttype RESTGetAPIGuildInvitesResult,\n\ttype RESTGetAPIGuildMemberResult,\n\ttype RESTGetAPIGuildMembersQuery,\n\ttype RESTGetAPIGuildMembersResult,\n\ttype RESTGetAPIGuildMembersSearchQuery,\n\ttype RESTGetAPIGuildMembersSearchResult,\n\ttype RESTGetAPIGuildOnboardingResult,\n\ttype RESTGetAPIGuildPreviewResult,\n\ttype RESTGetAPIGuildPruneCountQuery,\n\ttype RESTGetAPIGuildPruneCountResult,\n\ttype RESTGetAPIGuildQuery,\n\ttype RESTGetAPIGuildResult,\n\ttype RESTGetAPIGuildRoleMemberCountsResult,\n\ttype RESTGetAPIGuildRoleResult,\n\ttype RESTGetAPIGuildRolesResult,\n\ttype RESTGetAPIGuildScheduledEventQuery,\n\ttype RESTGetAPIGuildScheduledEventResult,\n\ttype RESTGetAPIGuildScheduledEventUsersQuery,\n\ttype RESTGetAPIGuildScheduledEventUsersResult,\n\ttype RESTGetAPIGuildScheduledEventsQuery,\n\ttype RESTGetAPIGuildScheduledEventsResult,\n\ttype RESTGetAPIGuildSoundboardSoundResult,\n\ttype RESTGetAPIGuildSoundboardSoundsResult,\n\ttype RESTGetAPIGuildStickerResult,\n\ttype RESTGetAPIGuildStickersResult,\n\ttype RESTGetAPIGuildTemplatesResult,\n\ttype RESTGetAPIGuildThreadsResult,\n\ttype RESTGetAPIGuildVanityUrlResult,\n\ttype RESTGetAPIGuildVoiceRegionsResult,\n\ttype RESTGetAPIGuildWebhooksResult,\n\ttype RESTGetAPIGuildWelcomeScreenResult,\n\ttype RESTGetAPIGuildWidgetImageResult,\n\ttype RESTGetAPIGuildWidgetJSONResult,\n\ttype RESTGetAPIGuildWidgetSettingsResult,\n\ttype RESTGetAPITemplateResult,\n\ttype RESTPatchAPIAutoModerationRuleJSONBody,\n\ttype RESTPatchAPIAutoModerationRuleResult,\n\ttype RESTPatchAPIGuildChannelPositionsJSONBody,\n\ttype RESTPatchAPIGuildEmojiJSONBody,\n\ttype RESTPatchAPIGuildEmojiResult,\n\ttype RESTPatchAPIGuildJSONBody,\n\ttype RESTPatchAPIGuildMemberJSONBody,\n\ttype RESTPatchAPIGuildMemberResult,\n\ttype RESTPatchAPIGuildResult,\n\ttype RESTPatchAPIGuildRoleJSONBody,\n\ttype RESTPatchAPIGuildRolePositionsJSONBody,\n\ttype RESTPatchAPIGuildRolePositionsResult,\n\ttype RESTPatchAPIGuildRoleResult,\n\ttype RESTPatchAPIGuildScheduledEventJSONBody,\n\ttype RESTPatchAPIGuildScheduledEventResult,\n\ttype RESTPatchAPIGuildSoundboardSoundJSONBody,\n\ttype RESTPatchAPIGuildSoundboardSoundResult,\n\ttype RESTPatchAPIGuildStickerJSONBody,\n\ttype RESTPatchAPIGuildStickerResult,\n\ttype RESTPatchAPIGuildTemplateJSONBody,\n\ttype RESTPatchAPIGuildTemplateResult,\n\ttype RESTPatchAPIGuildWelcomeScreenJSONBody,\n\ttype RESTPatchAPIGuildWelcomeScreenResult,\n\ttype RESTPatchAPIGuildWidgetSettingsJSONBody,\n\ttype RESTPatchAPIGuildWidgetSettingsResult,\n\ttype RESTPostAPIAutoModerationRuleJSONBody,\n\ttype RESTPostAPIAutoModerationRuleResult,\n\ttype RESTPostAPIGuildBulkBanJSONBody,\n\ttype RESTPostAPIGuildBulkBanResult,\n\ttype RESTPostAPIGuildChannelJSONBody,\n\ttype RESTPostAPIGuildChannelResult,\n\ttype RESTPostAPIGuildEmojiJSONBody,\n\ttype RESTPostAPIGuildEmojiResult,\n\ttype RESTPostAPIGuildPruneJSONBody,\n\ttype RESTPostAPIGuildPruneResult,\n\ttype RESTPostAPIGuildRoleJSONBody,\n\ttype RESTPostAPIGuildRoleResult,\n\ttype RESTPostAPIGuildScheduledEventJSONBody,\n\ttype RESTPostAPIGuildScheduledEventResult,\n\ttype RESTPostAPIGuildSoundboardSoundJSONBody,\n\ttype RESTPostAPIGuildSoundboardSoundResult,\n\ttype RESTPostAPIGuildStickerFormDataBody,\n\ttype RESTPostAPIGuildStickerResult,\n\ttype RESTPostAPIGuildTemplatesJSONBody,\n\ttype RESTPostAPIGuildTemplatesResult,\n\ttype RESTPutAPIGuildBanJSONBody,\n\ttype RESTPutAPIGuildIncidentActionsJSONBody,\n\ttype RESTPutAPIGuildIncidentActionsResult,\n\ttype RESTPutAPIGuildMemberJSONBody,\n\ttype RESTPutAPIGuildMemberResult,\n\ttype RESTPutAPIGuildOnboardingJSONBody,\n\ttype RESTPutAPIGuildOnboardingResult,\n\ttype RESTPutAPIGuildTemplateSyncResult,\n\ttype Snowflake,\n} from 'discord-api-types/v10';\n\nexport interface CreateStickerOptions extends Omit<RESTPostAPIGuildStickerFormDataBody, 'file'> {\n\tfile: RawFile;\n}\n\nexport class GuildsAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Fetches a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild}\n\t * @param guildId - The id of the guild\n\t * @param query - The query options for fetching the guild\n\t * @param options - The options for fetching the guild\n\t */\n\tpublic async get(\n\t\tguildId: Snowflake,\n\t\tquery: RESTGetAPIGuildQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guild(guildId), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildResult>;\n\t}\n\n\t/**\n\t * Fetches a guild preview\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-preview}\n\t * @param guildId - The id of the guild to fetch the preview from\n\t * @param options - The options for fetching the guild preview\n\t */\n\tpublic async getPreview(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildPreview(guildId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildPreviewResult>;\n\t}\n\n\t/**\n\t * Edits a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#modify-guild}\n\t * @param guildId - The id of the guild to edit\n\t * @param body - The new guild data\n\t * @param options - The options for editing the guild\n\t */\n\tpublic async edit(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPatchAPIGuildJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.guild(guildId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIGuildResult>;\n\t}\n\n\t/**\n\t * Adds user to the guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#add-guild-member}\n\t * @param guildId - The id of the guild to add the user to\n\t * @param userId - The id of the user to add\n\t * @param body - The data for adding users to the guild\n\t * @param options - The options for adding users to the guild\n\t */\n\tpublic async addMember(\n\t\tguildId: Snowflake,\n\t\tuserId: Snowflake,\n\t\tbody: RESTPutAPIGuildMemberJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.put(Routes.guildMember(guildId, userId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPutAPIGuildMemberResult>;\n\t}\n\n\t/**\n\t * Fetches members of a guild.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#list-guild-members}\n\t * @param guildId - The id of the guild\n\t * @param query - The query for fetching the guild members\n\t * @param options - The options for fetching the guild members\n\t */\n\tpublic async getMembers(\n\t\tguildId: Snowflake,\n\t\tquery: RESTGetAPIGuildMembersQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildMembers(guildId), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildMembersResult>;\n\t}\n\n\t/**\n\t * Fetches a guild's channels\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-channels}\n\t * @param guildId - The id of the guild to fetch the channels from\n\t * @param options - The options for fetching the guild channels\n\t */\n\tpublic async getChannels(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildChannels(guildId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildChannelsResult>;\n\t}\n\n\t/**\n\t * Creates a guild channel\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#create-guild-channel}\n\t * @param guildId - The id of the guild to create the channel in\n\t * @param body - The data to create the new channel\n\t * @param options - The options for creating the guild channel\n\t */\n\tpublic async createChannel(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPostAPIGuildChannelJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.guildChannels(guildId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIGuildChannelResult>;\n\t}\n\n\t/**\n\t * Edits a guild channel's positions\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#modify-guild-channel-positions}\n\t * @param guildId - The id of the guild to edit the channel positions from\n\t * @param body - The data to edit the channel positions with\n\t * @param options - The options for editing the guild channel positions\n\t */\n\tpublic async setChannelPositions(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPatchAPIGuildChannelPositionsJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.patch(Routes.guildChannels(guildId), { auth, reason, body, signal });\n\t}\n\n\t/**\n\t * Fetches the active threads in a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#list-active-guild-threads}\n\t * @param guildId - The id of the guild to fetch the active threads from\n\t * @param options - The options for fetching the active threads\n\t */\n\tpublic async getActiveThreads(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildActiveThreads(guildId), { auth, signal }) as Promise<RESTGetAPIGuildThreadsResult>;\n\t}\n\n\t/**\n\t * Fetches a guild member ban\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-ban}\n\t * @param guildId - The id of the guild to fetch the ban from\n\t * @param userId - The id of the user to fetch the ban\n\t * @param options - The options for fetching the ban\n\t */\n\tpublic async getMemberBan(\n\t\tguildId: Snowflake,\n\t\tuserId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildBan(guildId, userId), { auth, signal }) as Promise<RESTGetAPIGuildBanResult>;\n\t}\n\n\t/**\n\t * Fetches guild member bans\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-bans}\n\t * @param guildId - The id of the guild to fetch the bans from\n\t * @param query - The query options for fetching the bans\n\t * @param options - The options for fetching the bans\n\t */\n\tpublic async getMemberBans(\n\t\tguildId: Snowflake,\n\t\tquery: RESTGetAPIGuildBansQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildBans(guildId), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildBansResult>;\n\t}\n\n\t/**\n\t * Bans a user from a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#create-guild-ban}\n\t * @param guildId - The id of the guild to ban the member in\n\t * @param userId - The id of the user to ban\n\t * @param body - The payload for banning the user\n\t * @param options - The options for banning the user\n\t */\n\tpublic async banUser(\n\t\tguildId: Snowflake,\n\t\tuserId: Snowflake,\n\t\tbody: RESTPutAPIGuildBanJSONBody = {},\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.put(Routes.guildBan(guildId, userId), { auth, reason, body, signal });\n\t}\n\n\t/**\n\t * Unbans a user from a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#remove-guild-ban}\n\t * @param guildId - The id of the guild to unban the member in\n\t * @param userId - The id of the user to unban\n\t * @param options - The options for unbanning the user\n\t */\n\tpublic async unbanUser(\n\t\tguildId: Snowflake,\n\t\tuserId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.guildBan(guildId, userId), { auth, reason, signal });\n\t}\n\n\t/**\n\t * Bulk ban users from a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#bulk-guild-ban}\n\t * @param guildId - The id of the guild to bulk ban users in\n\t * @param body - The data for bulk banning users\n\t * @param options - The options for bulk banning users\n\t */\n\tpublic async bulkBanUsers(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPostAPIGuildBulkBanJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.guildBulkBan(guildId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIGuildBulkBanResult>;\n\t}\n\n\t/**\n\t * Gets all the roles in a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-roles}\n\t * @param guildId - The id of the guild to fetch the roles from\n\t * @param options - The options for fetching the guild roles\n\t */\n\tpublic async getRoles(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildRoles(guildId), { auth, signal }) as Promise<RESTGetAPIGuildRolesResult>;\n\t}\n\n\t/**\n\t * Get a role in a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-role}\n\t * @param guildId - The id of the guild to fetch the role from\n\t * @param roleId - The id of the role to fetch\n\t * @param options - The options for fetching the guild role\n\t */\n\tpublic async getRole(\n\t\tguildId: Snowflake,\n\t\troleId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildRole(guildId, roleId), { auth, signal }) as Promise<RESTGetAPIGuildRoleResult>;\n\t}\n\n\t/**\n\t * Creates a guild role\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#create-guild-role}\n\t * @param guildId - The id of the guild to create the role in\n\t * @param body - The data to create the role with\n\t * @param options - The options for creating the guild role\n\t */\n\tpublic async createRole(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPostAPIGuildRoleJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.guildRoles(guildId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIGuildRoleResult>;\n\t}\n\n\t/**\n\t * Sets role positions in a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#modify-guild-role-positions}\n\t * @param guildId - The id of the guild to set role positions for\n\t * @param body - The data for setting a role position\n\t * @param options - The options for setting role positions\n\t */\n\tpublic async setRolePositions(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPatchAPIGuildRolePositionsJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.guildRoles(guildId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIGuildRolePositionsResult>;\n\t}\n\n\t/**\n\t * Edits a guild role\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#modify-guild-role}\n\t * @param guildId - The id of the guild to edit the role in\n\t * @param roleId - The id of the role to edit\n\t * @param body - data for editing the role\n\t * @param options - The options for editing the guild role\n\t */\n\tpublic async editRole(\n\t\tguildId: Snowflake,\n\t\troleId: Snowflake,\n\t\tbody: RESTPatchAPIGuildRoleJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.guildRole(guildId, roleId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIGuildRoleResult>;\n\t}\n\n\t/**\n\t * Deletes a guild role\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#delete-guild-role}\n\t * @param guildId - The id of the guild to delete the role in\n\t * @param roleId - The id of the role to delete\n\t * @param options - The options for deleting the guild role\n\t */\n\tpublic async deleteRole(\n\t\tguildId: Snowflake,\n\t\troleId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.guildRole(guildId, roleId), { auth, reason, signal });\n\t}\n\n\t/**\n\t * Fetch the number of members that can be pruned from a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-prune-count}\n\t * @param guildId - The id of the guild to fetch the number of pruned members from\n\t * @param query - The query options for fetching the number of pruned members\n\t * @param options - The options for fetching the number of pruned members\n\t */\n\tpublic async getPruneCount(\n\t\tguildId: Snowflake,\n\t\tquery: RESTGetAPIGuildPruneCountQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildPrune(guildId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t}) as Promise<RESTGetAPIGuildPruneCountResult>;\n\t}\n\n\t/**\n\t * Prunes members in a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#begin-guild-prune}\n\t * @param guildId - The id of the guild to prune members in\n\t * @param body - The options for pruning members\n\t * @param options - The options for initiating the prune\n\t */\n\tpublic async beginPrune(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPostAPIGuildPruneJSONBody = {},\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.guildPrune(guildId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\treason,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIGuildPruneResult>;\n\t}\n\n\t/**\n\t * Fetches voice regions for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-voice-regions}\n\t * @param guildId - The id of the guild to fetch the voice regions from\n\t * @param options - The options for fetching the voice regions\n\t */\n\tpublic async getVoiceRegions(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildVoiceRegions(guildId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildVoiceRegionsResult>;\n\t}\n\n\t/**\n\t * Fetches the invites for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-invites}\n\t * @param guildId - The id of the guild to fetch the invites from\n\t * @param options - The options for fetching the invites\n\t */\n\tpublic async getInvites(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildInvites(guildId), { auth, signal }) as Promise<RESTGetAPIGuildInvitesResult>;\n\t}\n\n\t/**\n\t * Fetches the integrations for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-integrations}\n\t * @param guildId - The id of the guild to fetch the integrations from\n\t * @param options - The options for fetching the integrations\n\t */\n\tpublic async getIntegrations(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildIntegrations(guildId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildIntegrationsResult>;\n\t}\n\n\t/**\n\t * Deletes an integration from a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#delete-guild-integration}\n\t * @param guildId - The id of the guild to delete the integration from\n\t * @param integrationId - The id of the integration to delete\n\t * @param options - The options for deleting the integration\n\t */\n\tpublic async deleteIntegration(\n\t\tguildId: Snowflake,\n\t\tintegrationId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.guildIntegration(guildId, integrationId), { auth, reason, signal });\n\t}\n\n\t/**\n\t * Fetches the widget settings for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-widget-settings}\n\t * @param guildId - The id of the guild to fetch the widget settings from\n\t * @param options - The options for fetching the widget settings\n\t */\n\tpublic async getWidgetSettings(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildWidgetSettings(guildId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildWidgetSettingsResult>;\n\t}\n\n\t/**\n\t * Edits the widget settings for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#modify-guild-widget}\n\t * @param guildId - The id of the guild to edit the widget settings from\n\t * @param body - The new widget settings data\n\t * @param options - The options for editing the widget settings\n\t */\n\tpublic async editWidgetSettings(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPatchAPIGuildWidgetSettingsJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.guildWidgetSettings(guildId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIGuildWidgetSettingsResult>;\n\t}\n\n\t/**\n\t * Fetches the widget for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-widget}\n\t * @param guildId - The id of the guild to fetch the widget from\n\t * @param options - The options for fetching the widget\n\t */\n\tpublic async getWidget(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildWidgetJSON(guildId), { auth, signal }) as Promise<RESTGetAPIGuildWidgetJSONResult>;\n\t}\n\n\t/**\n\t * Fetches the vanity url for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-vanity-url}\n\t * @param guildId - The id of the guild to fetch the vanity url from\n\t * @param options - The options for fetching the vanity url\n\t */\n\tpublic async getVanityURL(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildVanityUrl(guildId), { auth, signal }) as Promise<RESTGetAPIGuildVanityUrlResult>;\n\t}\n\n\t/**\n\t * Fetches the widget image for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-widget-image}\n\t * @param guildId - The id of the guild to fetch the widget image from\n\t * @param style - The style of the widget image\n\t * @param options - The options for fetching the widget image\n\t */\n\tpublic async getWidgetImage(\n\t\tguildId: Snowflake,\n\t\tstyle?: GuildWidgetStyle,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildWidgetImage(guildId), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams({ style }),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildWidgetImageResult>;\n\t}\n\n\t/**\n\t * Fetches the welcome screen for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-welcome-screen}\n\t * @param guildId - The id of the guild to fetch the welcome screen from\n\t * @param options - The options for fetching the welcome screen\n\t */\n\tpublic async getWelcomeScreen(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildWelcomeScreen(guildId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildWelcomeScreenResult>;\n\t}\n\n\t/**\n\t * Edits the welcome screen for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#modify-guild-welcome-screen}\n\t * @param guildId - The id of the guild to edit the welcome screen for\n\t * @param body - The new welcome screen data\n\t * @param options - The options for editing the welcome screen\n\t */\n\tpublic async editWelcomeScreen(\n\t\tguildId: Snowflake,\n\t\tbody?: RESTPatchAPIGuildWelcomeScreenJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.guildWelcomeScreen(guildId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIGuildWelcomeScreenResult>;\n\t}\n\n\t/**\n\t * Fetches all emojis for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/emoji#list-guild-emojis}\n\t * @param guildId - The id of the guild to fetch the emojis from\n\t * @param options - The options for fetching the emojis\n\t */\n\tpublic async getEmojis(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildEmojis(guildId), { auth, signal }) as Promise<RESTGetAPIGuildEmojisResult>;\n\t}\n\n\t/**\n\t * Fetches an emoji for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/emoji#get-guild-emoji}\n\t * @param guildId - The id of the guild to fetch the emoji from\n\t * @param emojiId - The id of the emoji to fetch\n\t * @param options - The options for fetching the emoji\n\t */\n\tpublic async getEmoji(\n\t\tguildId: Snowflake,\n\t\temojiId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildEmoji(guildId, emojiId), { auth, signal }) as Promise<RESTGetAPIGuildEmojiResult>;\n\t}\n\n\t/**\n\t * Creates a new emoji for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/emoji#create-guild-emoji}\n\t * @param guildId - The id of the guild to create the emoji from\n\t * @param body - The data for creating the emoji\n\t * @param options - The options for creating the emoji\n\t */\n\tpublic async createEmoji(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPostAPIGuildEmojiJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.guildEmojis(guildId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIGuildEmojiResult>;\n\t}\n\n\t/**\n\t * Edits an emoji for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/emoji#modify-guild-emoji}\n\t * @param guildId - The id of the guild to edit the emoji from\n\t * @param emojiId - The id of the emoji to edit\n\t * @param body - The data for editing the emoji\n\t * @param options - The options for editing the emoji\n\t */\n\tpublic async editEmoji(\n\t\tguildId: Snowflake,\n\t\temojiId: Snowflake,\n\t\tbody: RESTPatchAPIGuildEmojiJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.guildEmoji(guildId, emojiId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIGuildEmojiResult>;\n\t}\n\n\t/**\n\t * Deletes an emoji for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/emoji#delete-guild-emoji}\n\t * @param guildId - The id of the guild to delete the emoji from\n\t * @param emojiId - The id of the emoji to delete\n\t * @param options - The options for deleting the emoji\n\t */\n\tpublic async deleteEmoji(\n\t\tguildId: Snowflake,\n\t\temojiId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.guildEmoji(guildId, emojiId), { auth, reason, signal });\n\t}\n\n\t/**\n\t * Fetches all scheduled events for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#list-scheduled-events-for-guild}\n\t * @param guildId - The id of the guild to fetch the scheduled events from\n\t * @param query - The query options for fetching the scheduled events\n\t * @param options - The options for fetching the scheduled events\n\t */\n\tpublic async getScheduledEvents(\n\t\tguildId: Snowflake,\n\t\tquery: RESTGetAPIGuildScheduledEventsQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildScheduledEvents(guildId), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildScheduledEventsResult>;\n\t}\n\n\t/**\n\t * Creates a new scheduled event for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#create-guild-scheduled-event}\n\t * @param guildId - The id of the guild to create the scheduled event from\n\t * @param body - The data to create the event with\n\t * @param options - The options for creating the scheduled event\n\t */\n\tpublic async createScheduledEvent(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPostAPIGuildScheduledEventJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.guildScheduledEvents(guildId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIGuildScheduledEventResult>;\n\t}\n\n\t/**\n\t * Fetches a scheduled event for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#get-guild-scheduled-event}\n\t * @param guildId - The id of the guild to fetch the scheduled event from\n\t * @param eventId - The id of the scheduled event to fetch\n\t * @param query - The options for fetching the scheduled event\n\t * @param options - The options for fetching the scheduled event\n\t */\n\tpublic async getScheduledEvent(\n\t\tguildId: Snowflake,\n\t\teventId: Snowflake,\n\t\tquery: RESTGetAPIGuildScheduledEventQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildScheduledEvent(guildId, eventId), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildScheduledEventResult>;\n\t}\n\n\t/**\n\t * Edits a scheduled event for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#modify-guild-scheduled-event}\n\t * @param guildId - The id of the guild to edit the scheduled event from\n\t * @param eventId - The id of the scheduled event to edit\n\t * @param body - The new event data\n\t * @param options - The options for editing the scheduled event\n\t */\n\tpublic async editScheduledEvent(\n\t\tguildId: Snowflake,\n\t\teventId: Snowflake,\n\t\tbody: RESTPatchAPIGuildScheduledEventJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.guildScheduledEvent(guildId, eventId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIGuildScheduledEventResult>;\n\t}\n\n\t/**\n\t * Deletes a scheduled event for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#delete-guild-scheduled-event}\n\t * @param guildId - The id of the guild to delete the scheduled event from\n\t * @param eventId - The id of the scheduled event to delete\n\t * @param options - The options for deleting the scheduled event\n\t */\n\tpublic async deleteScheduledEvent(\n\t\tguildId: Snowflake,\n\t\teventId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.guildScheduledEvent(guildId, eventId), { auth, reason, signal });\n\t}\n\n\t/**\n\t * Gets all users that are interested in a scheduled event\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#get-guild-scheduled-event-users}\n\t * @param guildId - The id of the guild to fetch the scheduled event users from\n\t * @param eventId - The id of the scheduled event to fetch the users for\n\t * @param query - The options for fetching the scheduled event users\n\t * @param options - The options for fetching the scheduled event users\n\t */\n\tpublic async getScheduledEventUsers(\n\t\tguildId: Snowflake,\n\t\teventId: Snowflake,\n\t\tquery: RESTGetAPIGuildScheduledEventUsersQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildScheduledEventUsers(guildId, eventId), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildScheduledEventUsersResult>;\n\t}\n\n\t/**\n\t * Fetches all the templates for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild-template#get-guild-templates}\n\t * @param guildId - The id of the guild to fetch the templates from\n\t * @param options - The options for fetching the templates\n\t */\n\tpublic async getTemplates(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildTemplates(guildId), { auth, signal }) as Promise<RESTGetAPIGuildTemplatesResult>;\n\t}\n\n\t/**\n\t * Syncs a template for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild-template#sync-guild-template}\n\t * @param guildId - The id of the guild to sync the template from\n\t * @param templateCode - The code of the template to sync\n\t * @param options - The options for syncing the template\n\t */\n\tpublic async syncTemplate(\n\t\tguildId: Snowflake,\n\t\ttemplateCode: string,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.put(Routes.guildTemplate(guildId, templateCode), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPutAPIGuildTemplateSyncResult>;\n\t}\n\n\t/**\n\t * Edits a template for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild-template#modify-guild-template}\n\t * @param guildId - The id of the guild to edit the template from\n\t * @param templateCode - The code of the template to edit\n\t * @param body - The data for editing the template\n\t * @param options - The options for editing the template\n\t */\n\tpublic async editTemplate(\n\t\tguildId: Snowflake,\n\t\ttemplateCode: string,\n\t\tbody: RESTPatchAPIGuildTemplateJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.guildTemplate(guildId, templateCode), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIGuildTemplateResult>;\n\t}\n\n\t/**\n\t * Deletes a template for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild-template#delete-guild-template}\n\t * @param guildId - The id of the guild to delete the template from\n\t * @param templateCode - The code of the template to delete\n\t * @param options - The options for deleting the template\n\t */\n\tpublic async deleteTemplate(\n\t\tguildId: Snowflake,\n\t\ttemplateCode: string,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.guildTemplate(guildId, templateCode), { auth, signal });\n\t}\n\n\t/**\n\t * Fetches all the stickers for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/sticker#list-guild-stickers}\n\t * @param guildId - The id of the guild to fetch the stickers from\n\t * @param options - The options for fetching the stickers\n\t */\n\tpublic async getStickers(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildStickers(guildId), { auth, signal }) as Promise<RESTGetAPIGuildStickersResult>;\n\t}\n\n\t/**\n\t * Fetches a sticker for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/sticker#get-guild-sticker}\n\t * @param guildId - The id of the guild to fetch the sticker from\n\t * @param stickerId - The id of the sticker to fetch\n\t * @param options - The options for fetching the sticker\n\t */\n\tpublic async getSticker(\n\t\tguildId: Snowflake,\n\t\tstickerId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildSticker(guildId, stickerId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildStickerResult>;\n\t}\n\n\t/**\n\t * Creates a sticker for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/sticker#create-guild-sticker}\n\t * @param guildId - The id of the guild to create the sticker for\n\t * @param body - The data for creating the sticker\n\t * @param options - The options for creating the sticker\n\t */\n\tpublic async createSticker(\n\t\tguildId: Snowflake,\n\t\t{ file, ...body }: CreateStickerOptions,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tconst fileData = { ...file, key: 'file' };\n\n\t\treturn this.rest.post(Routes.guildStickers(guildId), {\n\t\t\tauth,\n\t\t\tappendToFormData: true,\n\t\t\tbody,\n\t\t\tfiles: [fileData],\n\t\t\treason,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIGuildStickerResult>;\n\t}\n\n\t/**\n\t * Edits a sticker for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/sticker#modify-guild-sticker}\n\t * @param guildId - The id of the guild to edit the sticker from\n\t * @param stickerId - The id of the sticker to edit\n\t * @param body - The data for editing the sticker\n\t * @param options - The options for editing the sticker\n\t */\n\tpublic async editSticker(\n\t\tguildId: Snowflake,\n\t\tstickerId: Snowflake,\n\t\tbody: RESTPatchAPIGuildStickerJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.guildSticker(guildId, stickerId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIGuildStickerResult>;\n\t}\n\n\t/**\n\t * Deletes a sticker for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/sticker#delete-guild-sticker}\n\t * @param guildId - The id of the guild to delete the sticker from\n\t * @param stickerId - The id of the sticker to delete\n\t * @param options - The options for deleting the sticker\n\t */\n\tpublic async deleteSticker(\n\t\tguildId: Snowflake,\n\t\tstickerId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.guildSticker(guildId, stickerId), { auth, reason, signal });\n\t}\n\n\t/**\n\t * Fetches the audit logs for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/audit-log#get-guild-audit-log}\n\t * @param guildId - The id of the guild to fetch the audit logs from\n\t * @param query - The query options for fetching the audit logs\n\t * @param options - The options for fetching the audit logs\n\t */\n\tpublic async getAuditLogs(\n\t\tguildId: Snowflake,\n\t\tquery: RESTGetAPIAuditLogQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildAuditLog(guildId), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIAuditLogResult>;\n\t}\n\n\t/**\n\t * Fetches all auto moderation rules for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/auto-moderation#list-auto-moderation-rules-for-guild}\n\t * @param guildId - The id of the guild to fetch the auto moderation rules from\n\t * @param options - The options for fetching the auto moderation rules\n\t */\n\tpublic async getAutoModerationRules(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildAutoModerationRules(guildId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIAutoModerationRulesResult>;\n\t}\n\n\t/**\n\t * Fetches an auto moderation rule for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/auto-moderation#get-auto-moderation-rule}\n\t * @param guildId - The id of the guild to fetch the auto moderation rule from\n\t * @param ruleId - The id of the auto moderation rule to fetch\n\t * @param options - The options for fetching the auto moderation rule\n\t */\n\tpublic async getAutoModerationRule(\n\t\tguildId: Snowflake,\n\t\truleId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildAutoModerationRule(guildId, ruleId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIAutoModerationRuleResult>;\n\t}\n\n\t/**\n\t * Creates a new auto moderation rule for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/auto-moderation#create-auto-moderation-rule}\n\t * @param guildId - The id of the guild to create the auto moderation rule from\n\t * @param body - The data for creating the auto moderation rule\n\t * @param options - The options for creating the auto moderation rule\n\t */\n\tpublic async createAutoModerationRule(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPostAPIAutoModerationRuleJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.guildAutoModerationRules(guildId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIAutoModerationRuleResult>;\n\t}\n\n\t/**\n\t * Edits an auto moderation rule for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/auto-moderation#modify-auto-moderation-rule}\n\t * @param guildId - The id of the guild to edit the auto moderation rule from\n\t * @param ruleId - The id of the auto moderation rule to edit\n\t * @param body - The data for editing the auto moderation rule\n\t * @param options - The options for editing the auto moderation rule\n\t */\n\tpublic async editAutoModerationRule(\n\t\tguildId: Snowflake,\n\t\truleId: Snowflake,\n\t\tbody: RESTPatchAPIAutoModerationRuleJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.guildAutoModerationRule(guildId, ruleId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIAutoModerationRuleResult>;\n\t}\n\n\t/**\n\t * Deletes an auto moderation rule for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/auto-moderation#delete-auto-moderation-rule}\n\t * @param guildId - The id of the guild to delete the auto moderation rule from\n\t * @param ruleId - The id of the auto moderation rule to delete\n\t * @param options - The options for deleting the auto moderation rule\n\t */\n\tpublic async deleteAutoModerationRule(\n\t\tguildId: Snowflake,\n\t\truleId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.guildAutoModerationRule(guildId, ruleId), { auth, reason, signal });\n\t}\n\n\t/**\n\t * Fetches a guild member\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-member}\n\t * @param guildId - The id of the guild\n\t * @param userId - The id of the user\n\t * @param options - The options for fetching the guild member\n\t */\n\tpublic async getMember(\n\t\tguildId: Snowflake,\n\t\tuserId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildMember(guildId, userId), { auth, signal }) as Promise<RESTGetAPIGuildMemberResult>;\n\t}\n\n\t/**\n\t * Searches for guild members\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#search-guild-members}\n\t * @param guildId - The id of the guild to search in\n\t * @param query - The query to search for\n\t * @param options - The options for searching for guild members\n\t */\n\tpublic async searchForMembers(\n\t\tguildId: Snowflake,\n\t\tquery: RESTGetAPIGuildMembersSearchQuery,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildMembersSearch(guildId), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildMembersSearchResult>;\n\t}\n\n\t/**\n\t * Edits a guild member\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#modify-guild-member}\n\t * @param guildId - The id of the guild\n\t * @param userId - The id of the user\n\t * @param body - The data for editing the guild member\n\t * @param options - The options for editing the guild member\n\t */\n\tpublic async editMember(\n\t\tguildId: Snowflake,\n\t\tuserId: Snowflake,\n\t\tbody: RESTPatchAPIGuildMemberJSONBody = {},\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.guildMember(guildId, userId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIGuildMemberResult>;\n\t}\n\n\t/**\n\t * Removes a member from a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#remove-guild-member}\n\t * @param guildId - The id of the guild\n\t * @param userId - The id of the user\n\t * @param options - The options for removing the guild member\n\t */\n\tpublic async removeMember(\n\t\tguildId: Snowflake,\n\t\tuserId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.delete(Routes.guildMember(guildId, userId), { auth, reason, signal });\n\t}\n\n\t/**\n\t * Adds a role to a guild member\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#add-guild-member-role}\n\t * @param guildId - The id of the guild\n\t * @param userId - The id of the user\n\t * @param roleId - The id of the role\n\t * @param options - The options for adding a role to a guild member\n\t */\n\tpublic async addRoleToMember(\n\t\tguildId: Snowflake,\n\t\tuserId: Snowflake,\n\t\troleId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.put(Routes.guildMemberRole(guildId, userId, roleId), { auth, reason, signal });\n\t}\n\n\t/**\n\t * Removes a role from a guild member\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#remove-guild-member-role}\n\t * @param guildId - The id of the guild\n\t * @param userId - The id of the user\n\t * @param roleId - The id of the role\n\t * @param options - The options for removing a role from a guild member\n\t */\n\tpublic async removeRoleFromMember(\n\t\tguildId: Snowflake,\n\t\tuserId: Snowflake,\n\t\troleId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.guildMemberRole(guildId, userId, roleId), { auth, reason, signal });\n\t}\n\n\t/**\n\t * Fetches a guild template\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild-template#get-guild-template}\n\t * @param templateCode - The code of the template\n\t * @param options - The options for fetching the guild template\n\t */\n\tpublic async getTemplate(templateCode: string, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.template(templateCode), { auth, signal }) as Promise<RESTGetAPITemplateResult>;\n\t}\n\n\t/**\n\t * Creates a new template\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild-template#create-guild-template}\n\t * @param guildId - The id of the guild\n\t * @param body - The data for creating the template\n\t * @param options - The options for creating the template\n\t */\n\tpublic async createTemplate(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPostAPIGuildTemplatesJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.guildTemplates(guildId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIGuildTemplatesResult>;\n\t}\n\n\t/**\n\t * Fetches webhooks for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#get-guild-webhooks}\n\t * @param id - The id of the guild\n\t * @param options - The options for fetching the webhooks\n\t */\n\tpublic async getWebhooks(id: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildWebhooks(id), { auth, signal }) as Promise<RESTGetAPIGuildWebhooksResult>;\n\t}\n\n\t/**\n\t * Fetches a guild onboarding\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-onboarding}\n\t * @param guildId - The id of the guild\n\t * @param options - The options for fetching the guild onboarding\n\t */\n\tpublic async getOnboarding(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildOnboarding(guildId), { auth, signal }) as Promise<RESTGetAPIGuildOnboardingResult>;\n\t}\n\n\t/**\n\t * Edits a guild onboarding\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#modify-guild-onboarding}\n\t * @param guildId - The id of the guild\n\t * @param body - The data for editing the guild onboarding\n\t * @param options - The options for editing the guild onboarding\n\t */\n\tpublic async editOnboarding(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPutAPIGuildOnboardingJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.put(Routes.guildOnboarding(guildId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPutAPIGuildOnboardingResult>;\n\t}\n\n\t/**\n\t * Fetches all the soundboard sounds for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/soundboard#list-guild-soundboard-sounds}\n\t * @param guildId - The id of the guild to fetch the soundboard sounds for\n\t * @param options - The options for fetching the soundboard sounds\n\t */\n\tpublic async getSoundboardSounds(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildSoundboardSounds(guildId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildSoundboardSoundsResult>;\n\t}\n\n\t/**\n\t * Fetches a soundboard sound for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/soundboard#get-guild-soundboard-sound}\n\t * @param guildId - The id of the guild to fetch the soundboard sound for\n\t * @param soundId - The id of the soundboard sound to fetch\n\t * @param options - The options for fetching the soundboard sound\n\t */\n\tpublic async getSoundboardSound(\n\t\tguildId: Snowflake,\n\t\tsoundId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildSoundboardSound(guildId, soundId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildSoundboardSoundResult>;\n\t}\n\n\t/**\n\t * Creates a new soundboard sound for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/soundboard#create-guild-soundboard-sound}\n\t * @param guildId - The id of the guild to create the soundboard sound for\n\t * @param body - The data for creating the soundboard sound\n\t * @param options - The options for creating the soundboard sound\n\t */\n\tpublic async createSoundboardSound(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPostAPIGuildSoundboardSoundJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.guildSoundboardSounds(guildId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\treason,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIGuildSoundboardSoundResult>;\n\t}\n\n\t/**\n\t * Edits a soundboard sound for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/soundboard#modify-guild-soundboard-sound}\n\t * @param guildId - The id of the guild to edit the soundboard sound for\n\t * @param soundId - The id of the soundboard sound to edit\n\t * @param body - The data for editing the soundboard sound\n\t * @param options - The options for editing the soundboard sound\n\t */\n\tpublic async editSoundboardSound(\n\t\tguildId: Snowflake,\n\t\tsoundId: Snowflake,\n\t\tbody: RESTPatchAPIGuildSoundboardSoundJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.guildSoundboardSound(guildId, soundId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\treason,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIGuildSoundboardSoundResult>;\n\t}\n\n\t/**\n\t * Deletes a soundboard sound for a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/soundboard#delete-guild-soundboard-sound}\n\t * @param guildId - The id of the guild to delete the soundboard sound for\n\t * @param soundId - The id of the soundboard sound to delete\n\t * @param options - The options for deleting the soundboard sound\n\t */\n\tpublic async deleteSoundboardSound(\n\t\tguildId: Snowflake,\n\t\tsoundId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.guildSoundboardSound(guildId, soundId), { auth, reason, signal });\n\t}\n\n\t/**\n\t * Modifies incident actions for a guild.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#modify-guild-incident-actions}\n\t * @param guildId - The id of the guild\n\t * @param body - The data for modifying guild incident actions\n\t * @param options - The options for modifying guild incident actions\n\t */\n\tpublic async editIncidentActions(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPutAPIGuildIncidentActionsJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.put(Routes.guildIncidentActions(guildId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPutAPIGuildIncidentActionsResult>;\n\t}\n\n\t/**\n\t * Fetches role member counts for a guild.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#get-guild-role-member-counts}\n\t * @param guildId - The id of the guild to fetch role member counts for\n\t * @param options - The options for fetching role member counts\n\t */\n\tpublic async getRoleMemberCounts(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildRoleMemberCounts(guildId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildRoleMemberCountsResult>;\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/index.ts",
    "content": "import type { REST } from '@discordjs/rest';\nimport { ApplicationCommandsAPI } from './applicationCommands.js';\nimport { ApplicationsAPI } from './applications.js';\nimport { ChannelsAPI } from './channel.js';\nimport { GatewayAPI } from './gateway.js';\nimport { GuildsAPI } from './guild.js';\nimport { InteractionsAPI } from './interactions.js';\nimport { InvitesAPI } from './invite.js';\nimport { MonetizationAPI } from './monetization.js';\nimport { OAuth2API } from './oauth2.js';\nimport { PollAPI } from './poll.js';\nimport { RoleConnectionsAPI } from './roleConnections.js';\nimport { SoundboardSoundsAPI } from './soundboardSounds.js';\nimport { StageInstancesAPI } from './stageInstances.js';\nimport { StickersAPI } from './sticker.js';\nimport { ThreadsAPI } from './thread.js';\nimport { UsersAPI } from './user.js';\nimport { VoiceAPI } from './voice.js';\nimport { WebhooksAPI } from './webhook.js';\n\nexport * from './applicationCommands.js';\nexport * from './applications.js';\nexport * from './channel.js';\nexport * from './gateway.js';\nexport * from './guild.js';\nexport * from './interactions.js';\nexport * from './invite.js';\nexport * from './monetization.js';\nexport * from './oauth2.js';\nexport * from './poll.js';\nexport * from './roleConnections.js';\nexport * from './soundboardSounds.js';\nexport * from './stageInstances.js';\nexport * from './sticker.js';\nexport * from './thread.js';\nexport * from './user.js';\nexport * from './voice.js';\nexport * from './webhook.js';\n\nexport class API {\n\tpublic readonly applicationCommands: ApplicationCommandsAPI;\n\n\tpublic readonly applications: ApplicationsAPI;\n\n\tpublic readonly channels: ChannelsAPI;\n\n\tpublic readonly gateway: GatewayAPI;\n\n\tpublic readonly guilds: GuildsAPI;\n\n\tpublic readonly interactions: InteractionsAPI;\n\n\tpublic readonly invites: InvitesAPI;\n\n\tpublic readonly monetization: MonetizationAPI;\n\n\tpublic readonly oauth2: OAuth2API;\n\n\tpublic readonly poll: PollAPI;\n\n\tpublic readonly roleConnections: RoleConnectionsAPI;\n\n\tpublic readonly soundboardSounds: SoundboardSoundsAPI;\n\n\tpublic readonly stageInstances: StageInstancesAPI;\n\n\tpublic readonly stickers: StickersAPI;\n\n\tpublic readonly threads: ThreadsAPI;\n\n\tpublic readonly users: UsersAPI;\n\n\tpublic readonly voice: VoiceAPI;\n\n\tpublic readonly webhooks: WebhooksAPI;\n\n\tpublic constructor(public readonly rest: REST) {\n\t\tthis.applicationCommands = new ApplicationCommandsAPI(rest);\n\t\tthis.applications = new ApplicationsAPI(rest);\n\t\tthis.channels = new ChannelsAPI(rest);\n\t\tthis.gateway = new GatewayAPI(rest);\n\t\tthis.guilds = new GuildsAPI(rest);\n\t\tthis.invites = new InvitesAPI(rest);\n\t\tthis.monetization = new MonetizationAPI(rest);\n\t\tthis.oauth2 = new OAuth2API(rest);\n\t\tthis.poll = new PollAPI(rest);\n\t\tthis.roleConnections = new RoleConnectionsAPI(rest);\n\t\tthis.soundboardSounds = new SoundboardSoundsAPI(rest);\n\t\tthis.stageInstances = new StageInstancesAPI(rest);\n\t\tthis.stickers = new StickersAPI(rest);\n\t\tthis.threads = new ThreadsAPI(rest);\n\t\tthis.users = new UsersAPI(rest);\n\t\tthis.voice = new VoiceAPI(rest);\n\t\tthis.webhooks = new WebhooksAPI(rest);\n\t\tthis.interactions = new InteractionsAPI(rest, this.webhooks);\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/interactions.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport { makeURLSearchParams, type RawFile, type RequestData, type REST } from '@discordjs/rest';\nimport {\n\tInteractionResponseType,\n\tRoutes,\n\ttype APICommandAutocompleteInteractionResponseCallbackData,\n\ttype APIInteractionResponseCallbackData,\n\ttype APIInteractionResponseDeferredChannelMessageWithSource,\n\ttype APIModalInteractionResponseCallbackData,\n\ttype RESTGetAPIWebhookWithTokenMessageResult,\n\ttype RESTPostAPIInteractionCallbackQuery,\n\ttype RESTPostAPIInteractionCallbackWithResponseResult,\n\ttype Snowflake,\n} from 'discord-api-types/v10';\nimport type { WebhooksAPI } from './webhook.js';\n\nexport interface CreateInteractionResponseOptions\n\textends APIInteractionResponseCallbackData, RESTPostAPIInteractionCallbackQuery {\n\tfiles?: RawFile[];\n}\n\nexport type CreateInteractionDeferResponseOptions = APIInteractionResponseDeferredChannelMessageWithSource['data'] &\n\tRESTPostAPIInteractionCallbackQuery;\n\nexport type CreateInteractionFollowUpResponseOptions = APIInteractionResponseCallbackData & { files?: RawFile[] };\nexport type EditInteractionResponseOptions = APIInteractionResponseCallbackData & { files?: RawFile[] };\n\nexport type CreateInteractionUpdateMessageResponseOptions = APIInteractionResponseCallbackData &\n\tRESTPostAPIInteractionCallbackQuery & { files?: RawFile[] };\n\nexport type CreateAutocompleteResponseOptions = APICommandAutocompleteInteractionResponseCallbackData &\n\tRESTPostAPIInteractionCallbackQuery;\n\nexport type CreateModalResponseOptions = APIModalInteractionResponseCallbackData & RESTPostAPIInteractionCallbackQuery;\n\nexport class InteractionsAPI {\n\tpublic constructor(\n\t\tprivate readonly rest: REST,\n\t\tprivate readonly webhooks: WebhooksAPI,\n\t) {}\n\n\t/**\n\t * Replies to an interaction and returns an interaction callback object\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param body - The callback data for replying\n\t * @param options - The options for replying\n\t */\n\tpublic async reply(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tbody: CreateInteractionResponseOptions & { with_response: true },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<RESTPostAPIInteractionCallbackWithResponseResult>;\n\n\t/**\n\t * Replies to an interaction\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param body - The callback data for replying\n\t * @param options - The options for replying\n\t */\n\tpublic async reply(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tbody: CreateInteractionResponseOptions & { with_response?: false },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<undefined>;\n\n\t/**\n\t * Replies to an interaction\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param body - The callback data for replying\n\t * @param options - The options for replying\n\t */\n\tpublic async reply(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tbody: CreateInteractionResponseOptions,\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<RESTPostAPIInteractionCallbackWithResponseResult | undefined>;\n\n\tpublic async reply(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\t{ files, with_response, ...data }: CreateInteractionResponseOptions,\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\tconst response = await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), {\n\t\t\tquery: makeURLSearchParams({ with_response }),\n\t\t\tfiles,\n\t\t\tauth: false,\n\t\t\tbody: {\n\t\t\t\ttype: InteractionResponseType.ChannelMessageWithSource,\n\t\t\t\tdata,\n\t\t\t},\n\t\t\tsignal,\n\t\t});\n\n\t\treturn with_response ? response : undefined;\n\t}\n\n\t/**\n\t * Defers the reply to an interaction and returns an interaction callback object\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param body - The callback data for deferring the reply\n\t * @param options - The options for deferring\n\t */\n\tpublic async defer(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tbody: CreateInteractionDeferResponseOptions & { with_response: true },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<RESTPostAPIInteractionCallbackWithResponseResult>;\n\n\t/**\n\t * Defers the reply to an interaction\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param body - The callback data for deferring the reply\n\t * @param options - The options for deferring\n\t */\n\tpublic async defer(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tbody?: CreateInteractionDeferResponseOptions & { with_response?: false },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<undefined>;\n\n\t/**\n\t * Defers the reply to an interaction\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param body - The callback data for deferring the reply\n\t * @param options - The options for deferring\n\t */\n\tpublic async defer(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tbody?: CreateInteractionDeferResponseOptions,\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<RESTPostAPIInteractionCallbackWithResponseResult | undefined>;\n\n\tpublic async defer(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\t{ with_response, ...data }: CreateInteractionDeferResponseOptions = {},\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\tconst response = await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), {\n\t\t\tquery: makeURLSearchParams({ with_response }),\n\t\t\tauth: false,\n\t\t\tbody: {\n\t\t\t\ttype: InteractionResponseType.DeferredChannelMessageWithSource,\n\t\t\t\tdata,\n\t\t\t},\n\t\t\tsignal,\n\t\t});\n\n\t\treturn with_response ? response : undefined;\n\t}\n\n\t/**\n\t * Defers an update from a message component interaction and returns an interaction callback object\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param body - The callback data for deferring the update\n\t * @param options - The options for deferring\n\t */\n\tpublic async deferMessageUpdate(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tbody: RESTPostAPIInteractionCallbackQuery & { with_response: true },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<RESTPostAPIInteractionCallbackWithResponseResult>;\n\n\t/**\n\t * Defers an update from a message component interaction\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param body - The callback data for deferring the update\n\t * @param options - The options for deferring\n\t */\n\tpublic async deferMessageUpdate(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tbody?: RESTPostAPIInteractionCallbackQuery & { with_response?: false },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<undefined>;\n\n\t/**\n\t * Defers an update from a message component interaction\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param body - The callback data for deferring the update\n\t * @param options - The options for deferring\n\t */\n\tpublic async deferMessageUpdate(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tbody?: RESTPostAPIInteractionCallbackQuery,\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<RESTPostAPIInteractionCallbackWithResponseResult | undefined>;\n\n\tpublic async deferMessageUpdate(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\t{ with_response }: RESTPostAPIInteractionCallbackQuery = {},\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\tconst response = await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), {\n\t\t\tquery: makeURLSearchParams({ with_response }),\n\t\t\tauth: false,\n\t\t\tbody: {\n\t\t\t\ttype: InteractionResponseType.DeferredMessageUpdate,\n\t\t\t},\n\t\t\tsignal,\n\t\t});\n\n\t\treturn with_response ? response : undefined;\n\t}\n\n\t/**\n\t * Reply to a deferred interaction\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-followup-message}\n\t * @param applicationId - The application id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param body - The callback data for replying\n\t * @param options - The options for replying\n\t */\n\tpublic async followUp(\n\t\tapplicationId: Snowflake,\n\t\tinteractionToken: string,\n\t\tbody: CreateInteractionFollowUpResponseOptions,\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\treturn this.webhooks.execute(applicationId, interactionToken, { ...body, wait: true }, { signal });\n\t}\n\n\t/**\n\t * Edits the initial reply to an interaction\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#edit-original-interaction-response}\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#edit-followup-message}\n\t * @param applicationId - The application id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param callbackData - The callback data for editing the reply\n\t * @param messageId - The id of the message to edit. If omitted, the original reply will be edited\n\t * @param options - The options for editing the reply\n\t */\n\tpublic async editReply(\n\t\tapplicationId: Snowflake,\n\t\tinteractionToken: string,\n\t\tcallbackData: EditInteractionResponseOptions,\n\t\tmessageId?: Snowflake | '@original',\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\treturn this.webhooks.editMessage(applicationId, interactionToken, messageId ?? '@original', callbackData, {\n\t\t\tsignal,\n\t\t});\n\t}\n\n\t/**\n\t * Fetches the initial reply to an interaction\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#get-original-interaction-response}\n\t * @param applicationId - The application id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param options - The options for fetching the reply\n\t */\n\tpublic async getOriginalReply(\n\t\tapplicationId: Snowflake,\n\t\tinteractionToken: string,\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\treturn this.webhooks.getMessage(\n\t\t\tapplicationId,\n\t\t\tinteractionToken,\n\t\t\t'@original',\n\t\t\t{},\n\t\t\t{ signal },\n\t\t) as Promise<RESTGetAPIWebhookWithTokenMessageResult>;\n\t}\n\n\t/**\n\t * Deletes the initial reply to an interaction\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#delete-original-interaction-response}\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#delete-followup-message}\n\t * @param applicationId - The application id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param messageId - The id of the message to delete. If omitted, the original reply will be deleted\n\t * @param options - The options for deleting the reply\n\t */\n\tpublic async deleteReply(\n\t\tapplicationId: Snowflake,\n\t\tinteractionToken: string,\n\t\tmessageId?: Snowflake | '@original',\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\tawait this.webhooks.deleteMessage(applicationId, interactionToken, messageId ?? '@original', {}, { signal });\n\t}\n\n\t/**\n\t * Updates the message the component interaction was triggered on and returns an interaction callback object\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param callbackData - The callback data for updating the interaction\n\t * @param options - The options for updating the interaction\n\t */\n\tpublic async updateMessage(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tcallbackData: CreateInteractionUpdateMessageResponseOptions & { with_response: true },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<RESTPostAPIInteractionCallbackWithResponseResult>;\n\n\t/**\n\t * Updates the message the component interaction was triggered on\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param callbackData - The callback data for updating the interaction\n\t * @param options - The options for updating the interaction\n\t */\n\tpublic async updateMessage(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tcallbackData: CreateInteractionUpdateMessageResponseOptions & { with_response?: false },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<undefined>;\n\n\t/**\n\t * Updates the message the component interaction was triggered on\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param callbackData - The callback data for updating the interaction\n\t * @param options - The options for updating the interaction\n\t */\n\tpublic async updateMessage(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tcallbackData: CreateInteractionUpdateMessageResponseOptions,\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<RESTPostAPIInteractionCallbackWithResponseResult | undefined>;\n\n\tpublic async updateMessage(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\t{ files, with_response, ...data }: CreateInteractionUpdateMessageResponseOptions,\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\tconst response = await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), {\n\t\t\tquery: makeURLSearchParams({ with_response }),\n\t\t\tfiles,\n\t\t\tauth: false,\n\t\t\tbody: {\n\t\t\t\ttype: InteractionResponseType.UpdateMessage,\n\t\t\t\tdata,\n\t\t\t},\n\t\t\tsignal,\n\t\t});\n\n\t\treturn with_response ? response : undefined;\n\t}\n\n\t/**\n\t * Sends an autocomplete response to an interaction and returns an interaction callback object\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param callbackData - The callback data for the autocomplete response\n\t * @param options - The options for sending the autocomplete response\n\t */\n\tpublic async createAutocompleteResponse(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tcallbackData: CreateAutocompleteResponseOptions & { with_response: true },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<RESTPostAPIInteractionCallbackWithResponseResult>;\n\n\t/**\n\t * Sends an autocomplete response to an interaction\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param callbackData - The callback data for the autocomplete response\n\t * @param options - The options for sending the autocomplete response\n\t */\n\tpublic async createAutocompleteResponse(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tcallbackData: CreateAutocompleteResponseOptions & { with_response?: false },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<undefined>;\n\n\t/**\n\t * Sends an autocomplete response to an interaction\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param callbackData - The callback data for the autocomplete response\n\t * @param options - The options for sending the autocomplete response\n\t */\n\tpublic async createAutocompleteResponse(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tcallbackData: CreateAutocompleteResponseOptions,\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<RESTPostAPIInteractionCallbackWithResponseResult | undefined>;\n\n\tpublic async createAutocompleteResponse(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\t{ with_response, ...data }: CreateAutocompleteResponseOptions,\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\tconst response = await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), {\n\t\t\tquery: makeURLSearchParams({ with_response }),\n\t\t\tauth: false,\n\t\t\tbody: {\n\t\t\t\ttype: InteractionResponseType.ApplicationCommandAutocompleteResult,\n\t\t\t\tdata,\n\t\t\t},\n\t\t\tsignal,\n\t\t});\n\n\t\treturn with_response ? response : undefined;\n\t}\n\n\t/**\n\t * Sends a modal response to an interaction and returns an interaction callback object\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param callbackData - The modal callback data to send\n\t * @param options - The options for sending the modal\n\t */\n\tpublic async createModal(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tcallbackData: CreateModalResponseOptions & { with_response: true },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<RESTPostAPIInteractionCallbackWithResponseResult>;\n\n\t/**\n\t * Sends a modal response to an interaction\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param callbackData - The modal callback data to send\n\t * @param options - The options for sending the modal\n\t */\n\tpublic async createModal(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tcallbackData: CreateModalResponseOptions & { with_response?: false },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<undefined>;\n\n\t/**\n\t * Sends a modal response to an interaction\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param callbackData - The modal callback data to send\n\t * @param options - The options for sending the modal\n\t */\n\tpublic async createModal(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tcallbackData: CreateModalResponseOptions,\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<RESTPostAPIInteractionCallbackWithResponseResult | undefined>;\n\n\tpublic async createModal(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\t{ with_response, ...data }: CreateModalResponseOptions,\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\tconst response = await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), {\n\t\t\tquery: makeURLSearchParams({ with_response }),\n\t\t\tauth: false,\n\t\t\tbody: {\n\t\t\t\ttype: InteractionResponseType.Modal,\n\t\t\t\tdata,\n\t\t\t},\n\t\t\tsignal,\n\t\t});\n\n\t\treturn with_response ? response : undefined;\n\t}\n\n\t/**\n\t * Launches an activity and returns an interaction callback object\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param body - The callback data for launching the activity\n\t * @param options - The options for launching the activity\n\t */\n\tpublic async launchActivity(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tbody: RESTPostAPIInteractionCallbackQuery & { with_response: true },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<RESTPostAPIInteractionCallbackWithResponseResult>;\n\n\t/**\n\t * Launches an activity\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param body - The callback data for launching the activity\n\t * @param options - The options for launching the activity\n\t */\n\tpublic async launchActivity(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tbody?: RESTPostAPIInteractionCallbackQuery & { with_response?: false },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<undefined>;\n\n\t/**\n\t * Launches an activity\n\t *\n\t * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#create-interaction-response}\n\t * @param interactionId - The id of the interaction\n\t * @param interactionToken - The token of the interaction\n\t * @param body - The callback data for launching the activity\n\t * @param options - The options for launching the activity\n\t */\n\tpublic async launchActivity(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\tbody?: RESTPostAPIInteractionCallbackQuery,\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<RESTPostAPIInteractionCallbackWithResponseResult | undefined>;\n\n\tpublic async launchActivity(\n\t\tinteractionId: Snowflake,\n\t\tinteractionToken: string,\n\t\t{ with_response }: RESTPostAPIInteractionCallbackQuery = {},\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\tconst response = await this.rest.post(Routes.interactionCallback(interactionId, interactionToken), {\n\t\t\tquery: makeURLSearchParams({ with_response }),\n\t\t\tauth: false,\n\t\t\tbody: {\n\t\t\t\ttype: InteractionResponseType.LaunchActivity,\n\t\t\t},\n\t\t\tsignal,\n\t\t});\n\n\t\treturn with_response ? response : undefined;\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/invite.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport { makeURLSearchParams, type RequestData, type REST } from '@discordjs/rest';\nimport { Routes, type RESTGetAPIInviteQuery, type RESTGetAPIInviteResult } from 'discord-api-types/v10';\n\nexport class InvitesAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Fetches an invite\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/invite#get-invite}\n\t * @param code - The invite code\n\t * @param query - The options for fetching the invite\n\t * @param options - The options for fetching the invite\n\t */\n\tpublic async get(\n\t\tcode: string,\n\t\tquery: RESTGetAPIInviteQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.invite(code), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIInviteResult>;\n\t}\n\n\t/**\n\t * Deletes an invite\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/invite#delete-invite}\n\t * @param code - The invite code\n\t * @param options - The options for deleting the invite\n\t */\n\tpublic async delete(code: string, { auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {}) {\n\t\tawait this.rest.delete(Routes.invite(code), { auth, reason, signal });\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/monetization.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport { makeURLSearchParams, type RequestData, type REST } from '@discordjs/rest';\nimport {\n\tRoutes,\n\ttype RESTGetAPIEntitlementsQuery,\n\ttype RESTGetAPIEntitlementResult,\n\ttype RESTGetAPIEntitlementsResult,\n\ttype RESTGetAPISKUsResult,\n\ttype RESTGetAPISKUSubscriptionResult,\n\ttype RESTGetAPISKUSubscriptionsQuery,\n\ttype RESTGetAPISKUSubscriptionsResult,\n\ttype RESTPostAPIEntitlementJSONBody,\n\ttype RESTPostAPIEntitlementResult,\n\ttype Snowflake,\n} from 'discord-api-types/v10';\n\nexport class MonetizationAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Fetches the SKUs for an application.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/sku#list-skus}\n\t * @param applicationId - The application id to fetch SKUs for\n\t * @param options - The options for fetching the SKUs.\n\t */\n\tpublic async getSKUs(applicationId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.skus(applicationId), { auth, signal }) as Promise<RESTGetAPISKUsResult>;\n\t}\n\n\t/**\n\t * Fetches subscriptions for an SKU.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/subscription#list-sku-subscriptions}\n\t * @param skuId - The SKU id to fetch subscriptions for\n\t * @param query - The query options for fetching subscriptions\n\t * @param options - The options for fetching subscriptions\n\t */\n\tpublic async getSKUSubscriptions(\n\t\tskuId: Snowflake,\n\t\tquery: RESTGetAPISKUSubscriptionsQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.skuSubscriptions(skuId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t}) as Promise<RESTGetAPISKUSubscriptionsResult>;\n\t}\n\n\t/**\n\t * Fetches a subscription for an SKU.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/subscription#get-sku-subscription}\n\t * @param skuId - The SKU id to fetch subscription for\n\t * @param subscriptionId - The subscription id to fetch\n\t * @param options - The options for fetching the subscription\n\t */\n\tpublic async getSKUSubscription(\n\t\tskuId: Snowflake,\n\t\tsubscriptionId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.skuSubscription(skuId, subscriptionId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPISKUSubscriptionResult>;\n\t}\n\n\t/**\n\t * Fetches the entitlements for an application.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/entitlement#list-entitlements}\n\t * @param applicationId - The application id to fetch entitlements for\n\t * @param query - The query options for fetching entitlements\n\t * @param options - The options for fetching entitlements\n\t */\n\tpublic async getEntitlements(\n\t\tapplicationId: Snowflake,\n\t\tquery: RESTGetAPIEntitlementsQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.entitlements(applicationId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t}) as Promise<RESTGetAPIEntitlementsResult>;\n\t}\n\n\t/**\n\t * Fetches an entitlement for an application.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/entitlement#get-entitlement}\n\t * @param applicationId - The application id to fetch the entitlement for\n\t * @param entitlementId - The entitlement id to fetch\n\t * @param options - The options for fetching the entitlement\n\t */\n\tpublic async getEntitlement(\n\t\tapplicationId: Snowflake,\n\t\tentitlementId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.entitlement(applicationId, entitlementId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIEntitlementResult>;\n\t}\n\n\t/**\n\t * Creates a test entitlement for an application's SKU.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/entitlement#create-test-entitlement}\n\t * @param applicationId - The application id to create the entitlement for\n\t * @param body - The data for creating the entitlement\n\t * @param options - The options for creating the entitlement\n\t */\n\tpublic async createTestEntitlement(\n\t\tapplicationId: Snowflake,\n\t\tbody: RESTPostAPIEntitlementJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.entitlements(applicationId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIEntitlementResult>;\n\t}\n\n\t/**\n\t * Deletes a test entitlement for an application's SKU.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/entitlement#delete-test-entitlement}\n\t * @param applicationId - The application id to delete the entitlement for\n\t * @param entitlementId - The entitlement id to delete\n\t * @param options - The options for deleting the entitlement\n\t */\n\tpublic async deleteTestEntitlement(\n\t\tapplicationId: Snowflake,\n\t\tentitlementId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.entitlement(applicationId, entitlementId), { auth, signal });\n\t}\n\n\t/**\n\t * Marks a given entitlement for the user as consumed. Only available for One-Time Purchase consumable SKUs.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/entitlement#consume-an-entitlement}\n\t * @param applicationId - The application id to consume the entitlement for\n\t * @param entitlementId - The entitlement id to consume\n\t * @param options - The options for consuming the entitlement\n\t */\n\tpublic async consumeEntitlement(\n\t\tapplicationId: Snowflake,\n\t\tentitlementId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.post(Routes.consumeEntitlement(applicationId, entitlementId), { auth, signal });\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/oauth2.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport { type RequestData, type REST, makeURLSearchParams } from '@discordjs/rest';\nimport {\n\tRoutes,\n\tRouteBases,\n\ttype RESTOAuth2AuthorizationQuery,\n\ttype RESTPostOAuth2RefreshTokenURLEncodedData,\n\ttype RESTPostOAuth2RefreshTokenResult,\n\ttype RESTPostOAuth2ClientCredentialsURLEncodedData,\n\ttype RESTPostOAuth2ClientCredentialsResult,\n\ttype RESTGetAPIOAuth2CurrentAuthorizationResult,\n\ttype RESTGetAPIOAuth2CurrentApplicationResult,\n\ttype RESTPostOAuth2AccessTokenURLEncodedData,\n\ttype RESTPostOAuth2AccessTokenResult,\n\ttype RESTPostOAuth2TokenRevocationQuery,\n\ttype Snowflake,\n} from 'discord-api-types/v10';\n\nexport class OAuth2API {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Creates an OAuth2 authorization URL given the options\n\t *\n\t * @see {@link https://discord.com/developers/docs/topics/oauth2#authorization-code-grant-authorization-url-example}\n\t * @param options - The options for creating the authorization URL\n\t */\n\tpublic generateAuthorizationURL(options: RESTOAuth2AuthorizationQuery) {\n\t\tconst url = new URL(`${RouteBases.api}${Routes.oauth2Authorization()}`);\n\t\turl.search = makeURLSearchParams(options).toString();\n\t\treturn url.toString();\n\t}\n\n\t/**\n\t * Performs an OAuth2 token exchange, giving you an access token\n\t *\n\t * @see {@link https://discord.com/developers/docs/topics/oauth2#authorization-code-grant-access-token-exchange-example}\n\t * @param body - The body of the token exchange request\n\t * @param options - The options for the token exchange request\n\t */\n\tpublic async tokenExchange(\n\t\tbody: RESTPostOAuth2AccessTokenURLEncodedData,\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.oauth2TokenExchange(), {\n\t\t\tbody: makeURLSearchParams<RESTPostOAuth2AccessTokenURLEncodedData>(body),\n\t\t\tpassThroughBody: true,\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tauth: false,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostOAuth2AccessTokenResult>;\n\t}\n\n\t/**\n\t * Refreshes an OAuth2 access token, giving you a new one\n\t *\n\t * @see {@link https://discord.com/developers/docs/topics/oauth2#authorization-code-grant-refresh-token-exchange-example}\n\t * @param body - The options for the refresh token request\n\t * @param options - The options for the refresh token request\n\t */\n\tpublic async refreshToken(\n\t\tbody: RESTPostOAuth2RefreshTokenURLEncodedData,\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.oauth2TokenExchange(), {\n\t\t\tbody: makeURLSearchParams<RESTPostOAuth2RefreshTokenURLEncodedData>(body),\n\t\t\tpassThroughBody: true,\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tauth: false,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostOAuth2RefreshTokenResult>;\n\t}\n\n\t/**\n\t * Fetches the bearer token for the current application\n\t *\n\t * @remarks\n\t * This is primarily used for testing purposes\n\t * @see {@link https://discord.com/developers/docs/topics/oauth2#client-credentials-grant}\n\t * @param body - The options for the client credentials grant request\n\t * @param options - The options for the client credentials grant request\n\t */\n\tpublic async getToken(\n\t\tbody: RESTPostOAuth2ClientCredentialsURLEncodedData,\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.oauth2TokenExchange(), {\n\t\t\tbody: makeURLSearchParams(body),\n\t\t\tpassThroughBody: true,\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tauth: false,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostOAuth2ClientCredentialsResult>;\n\t}\n\n\t/**\n\t * Fetches the current bot's application information\n\t *\n\t * @see {@link https://discord.com/developers/docs/topics/oauth2#get-current-bot-application-information}\n\t * @param options - The options for the current bot application information request\n\t */\n\tpublic async getCurrentBotApplicationInformation({ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.oauth2CurrentApplication(), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIOAuth2CurrentApplicationResult>;\n\t}\n\n\t/**\n\t * Fetches the current authorization information\n\t *\n\t * @see {@link https://discord.com/developers/docs/topics/oauth2#get-current-authorization-information}\n\t * @param options - The options for the current authorization information request\n\t */\n\tpublic async getCurrentAuthorizationInformation({ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.oauth2CurrentAuthorization(), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIOAuth2CurrentAuthorizationResult>;\n\t}\n\n\t/**\n\t * Revokes an OAuth2 token\n\t *\n\t * @see {@link https://discord.com/developers/docs/topics/oauth2#authorization-code-grant-token-revocation-example}\n\t * @param applicationId - The application id\n\t * @param applicationSecret - The application secret\n\t * @param body - The body of the token revocation request\n\t * @param options - The options for the token revocation request\n\t */\n\tpublic async revokeToken(\n\t\tapplicationId: Snowflake,\n\t\tapplicationSecret: string,\n\t\tbody: RESTPostOAuth2TokenRevocationQuery,\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\tawait this.rest.post(Routes.oauth2TokenRevocation(), {\n\t\t\tbody: makeURLSearchParams(body),\n\t\t\tpassThroughBody: true,\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Basic ${btoa(`${applicationId}:${applicationSecret}`)}`,\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tauth: false,\n\t\t\tsignal,\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/poll.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport { makeURLSearchParams, type RequestData, type REST } from '@discordjs/rest';\nimport {\n\tRoutes,\n\ttype RESTGetAPIPollAnswerVotersQuery,\n\ttype RESTGetAPIPollAnswerVotersResult,\n\ttype RESTPostAPIPollExpireResult,\n\ttype Snowflake,\n} from 'discord-api-types/v10';\n\nexport class PollAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Gets the list of users that voted for a specific answer in a poll\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/poll#get-answer-voters}\n\t * @param channelId - The id of the channel containing the message\n\t * @param messageId - The id of the message containing the poll\n\t * @param answerId - The id of the answer to get voters for\n\t * @param query - The query for getting the list of voters\n\t * @param options - The options for getting the list of voters\n\t */\n\tpublic async getAnswerVoters(\n\t\tchannelId: Snowflake,\n\t\tmessageId: Snowflake,\n\t\tanswerId: number,\n\t\tquery: RESTGetAPIPollAnswerVotersQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.pollAnswerVoters(channelId, messageId, answerId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t}) as Promise<RESTGetAPIPollAnswerVotersResult>;\n\t}\n\n\t/**\n\t * Immediately expires (i.e. ends) a poll\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/poll#expire-poll}\n\t * @param channelId - The id of the channel containing the message\n\t * @param messageId - The id of the message containing the poll\n\t * @param options - The options for expiring the poll\n\t */\n\tpublic async expirePoll(\n\t\tchannelId: Snowflake,\n\t\tmessageId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.expirePoll(channelId, messageId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIPollExpireResult>;\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/roleConnections.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport type { RequestData, REST } from '@discordjs/rest';\nimport {\n\tRoutes,\n\ttype RESTGetAPIApplicationRoleConnectionMetadataResult,\n\ttype RESTPutAPIApplicationRoleConnectionMetadataResult,\n\ttype RESTPutAPIApplicationRoleConnectionMetadataJSONBody,\n\ttype Snowflake,\n} from 'discord-api-types/v10';\n\nexport class RoleConnectionsAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Gets the role connection metadata records for the application\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/application-role-connection-metadata#get-application-role-connection-metadata-records}\n\t * @param applicationId - The id of the application to get role connection metadata records for\n\t * @param options - The options for fetching the role connection metadata records\n\t */\n\tpublic async getMetadataRecords(\n\t\tapplicationId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.applicationRoleConnectionMetadata(applicationId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIApplicationRoleConnectionMetadataResult>;\n\t}\n\n\t/**\n\t * Updates the role connection metadata records for the application\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/application-role-connection-metadata#update-application-role-connection-metadata-records}\n\t * @param applicationId - The id of the application to update role connection metadata records for\n\t * @param body - The new role connection metadata records\n\t * @param options - The options for updating the role connection metadata records\n\t */\n\tpublic async updateMetadataRecords(\n\t\tapplicationId: Snowflake,\n\t\tbody: RESTPutAPIApplicationRoleConnectionMetadataJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.put(Routes.applicationRoleConnectionMetadata(applicationId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPutAPIApplicationRoleConnectionMetadataResult>;\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/soundboardSounds.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport type { RequestData, REST } from '@discordjs/rest';\nimport { Routes, type RESTGetAPISoundboardDefaultSoundsResult } from 'discord-api-types/v10';\n\nexport class SoundboardSoundsAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Fetches all the soundboard default sounds.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/soundboard#list-default-soundboard-sounds}\n\t * @param options - The options for fetching the soundboard default sounds.\n\t */\n\tpublic async getSoundboardDefaultSounds({ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.soundboardDefaultSounds(), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPISoundboardDefaultSoundsResult>;\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/stageInstances.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport type { RequestData, REST } from '@discordjs/rest';\nimport {\n\ttype Snowflake,\n\ttype RESTGetAPIStageInstanceResult,\n\ttype RESTPatchAPIStageInstanceJSONBody,\n\ttype RESTPatchAPIStageInstanceResult,\n\ttype RESTPostAPIStageInstanceJSONBody,\n\ttype RESTPostAPIStageInstanceResult,\n\tRoutes,\n} from 'discord-api-types/v10';\n\nexport class StageInstancesAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Creates a new stage instance\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/stage-instance#create-stage-instance}\n\t * @param body - The data for creating the new stage instance\n\t * @param options - The options for creating the new stage instance\n\t */\n\tpublic async create(\n\t\tbody: RESTPostAPIStageInstanceJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.stageInstances(), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\treason,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIStageInstanceResult>;\n\t}\n\n\t/**\n\t * Fetches a stage instance\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/stage-instance#get-stage-instance}\n\t * @param channelId - The id of the channel\n\t * @param options - The options for fetching the stage instance\n\t */\n\tpublic async get(channelId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.stageInstance(channelId), { auth, signal }) as Promise<RESTGetAPIStageInstanceResult>;\n\t}\n\n\t/**\n\t * Edits a stage instance\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/stage-instance#modify-stage-instance}\n\t * @param channelId - The id of the channel\n\t * @param body - The new stage instance data\n\t * @param options - The options for editing the stage instance\n\t */\n\tpublic async edit(\n\t\tchannelId: Snowflake,\n\t\tbody: RESTPatchAPIStageInstanceJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.stageInstance(channelId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\treason,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIStageInstanceResult>;\n\t}\n\n\t/**\n\t * Deletes a stage instance\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/stage-instance#delete-stage-instance}\n\t * @param channelId - The id of the channel\n\t * @param options - The options for deleting the stage instance\n\t */\n\tpublic async delete(\n\t\tchannelId: Snowflake,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.stageInstance(channelId), { auth, reason, signal });\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/sticker.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport type { RequestData, REST } from '@discordjs/rest';\nimport {\n\tRoutes,\n\ttype RESTGetAPIStickerPackResult,\n\ttype RESTGetAPIStickerResult,\n\ttype RESTGetStickerPacksResult,\n\ttype Snowflake,\n} from 'discord-api-types/v10';\n\nexport class StickersAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Fetches a sticker pack\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/sticker#get-sticker-pack}\n\t * @param packId - The id of the sticker pack\n\t * @param options - The options for fetching the sticker pack\n\t */\n\tpublic async getStickerPack(packId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.stickerPack(packId), { auth, signal }) as Promise<RESTGetAPIStickerPackResult>;\n\t}\n\n\t/**\n\t * Fetches all of the sticker packs\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/sticker#list-sticker-packs}\n\t * @param options - The options for fetching the sticker packs\n\t */\n\tpublic async getStickers({ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.stickerPacks(), { auth, signal }) as Promise<RESTGetStickerPacksResult>;\n\t}\n\n\t/**\n\t * Fetches a sticker\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/sticker#get-sticker}\n\t * @param stickerId - The id of the sticker\n\t * @param options - The options for fetching the sticker\n\t */\n\tpublic async get(stickerId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.sticker(stickerId), { auth, signal }) as Promise<RESTGetAPIStickerResult>;\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/thread.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport { makeURLSearchParams, type RequestData, type REST } from '@discordjs/rest';\nimport {\n\tRoutes,\n\ttype RESTGetAPIChannelThreadMemberQuery,\n\ttype RESTGetAPIChannelThreadMemberResult,\n\ttype RESTGetAPIChannelThreadMembersResult,\n\ttype Snowflake,\n} from 'discord-api-types/v10';\n\nexport class ThreadsAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Adds the current user to a thread\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#join-thread}\n\t * @param threadId - The id of the thread to join\n\t * @param options - The options for joining the thread\n\t */\n\tpublic async join(threadId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\tawait this.rest.put(Routes.threadMembers(threadId, '@me'), { auth, signal });\n\t}\n\n\t/**\n\t * Adds a member to a thread\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#add-thread-member}\n\t * @param threadId - The id of the thread to add the member to\n\t * @param userId - The id of the user to add to the thread\n\t * @param options - The options for adding the member to the thread\n\t */\n\tpublic async addMember(\n\t\tthreadId: Snowflake,\n\t\tuserId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.put(Routes.threadMembers(threadId, userId), { auth, signal });\n\t}\n\n\t/**\n\t * Removes the current user from a thread\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#leave-thread}\n\t * @param threadId - The id of the thread to leave\n\t * @param options - The options for leaving the thread\n\t */\n\tpublic async leave(threadId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\tawait this.rest.delete(Routes.threadMembers(threadId, '@me'), { auth, signal });\n\t}\n\n\t/**\n\t * Removes a member from a thread\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#remove-thread-member}\n\t * @param threadId - The id of the thread to remove the member from\n\t * @param userId - The id of the user to remove from the thread\n\t * @param options - The options for removing the member from the thread\n\t */\n\tpublic async removeMember(\n\t\tthreadId: Snowflake,\n\t\tuserId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.threadMembers(threadId, userId), { auth, signal });\n\t}\n\n\t/**\n\t * Fetches a member of a thread\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#get-thread-member}\n\t * @param threadId - The id of the thread to fetch the member from\n\t * @param userId - The id of the user\n\t * @param query - The query for fetching the member\n\t * @param options - The options for fetching the member\n\t */\n\tpublic async getMember(\n\t\tthreadId: Snowflake,\n\t\tuserId: Snowflake,\n\t\tquery: RESTGetAPIChannelThreadMemberQuery & { with_member: true },\n\t\toptions?: Pick<RequestData, 'auth' | 'signal'>,\n\t): Promise<Required<Pick<RESTGetAPIChannelThreadMemberResult, 'member'>> & RESTGetAPIChannelThreadMemberResult>;\n\n\t/**\n\t * Fetches a member of a thread\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#get-thread-member}\n\t * @param threadId - The id of the thread to fetch the member from\n\t * @param userId - The id of the user\n\t * @param query - The query for fetching the member\n\t * @param options - The options for fetching the member\n\t */\n\tpublic async getMember(\n\t\tthreadId: Snowflake,\n\t\tuserId: Snowflake,\n\t\tquery?: RESTGetAPIChannelThreadMemberQuery,\n\t\toptions?: Pick<RequestData, 'auth' | 'signal'>,\n\t): Promise<RESTGetAPIChannelThreadMemberResult>;\n\n\tpublic async getMember(\n\t\tthreadId: Snowflake,\n\t\tuserId: Snowflake,\n\t\tquery: RESTGetAPIChannelThreadMemberQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.threadMembers(threadId, userId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t});\n\t}\n\n\t/**\n\t * Fetches all members of a thread\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/channel#list-thread-members}\n\t * @param threadId - The id of the thread to fetch the members from\n\t * @param options - The options for fetching the members\n\t */\n\tpublic async getAllMembers(threadId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.threadMembers(threadId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIChannelThreadMembersResult>;\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/user.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport { makeURLSearchParams, type RequestData, type REST } from '@discordjs/rest';\nimport {\n\tRoutes,\n\ttype RESTGetAPICurrentUserApplicationRoleConnectionResult,\n\ttype RESTGetAPICurrentUserConnectionsResult,\n\ttype RESTGetAPICurrentUserGuildsQuery,\n\ttype RESTGetAPICurrentUserGuildsResult,\n\ttype RESTGetAPICurrentUserResult,\n\ttype RESTGetAPIUserResult,\n\ttype RESTGetCurrentUserGuildMemberResult,\n\ttype RESTPatchAPICurrentGuildMemberJSONBody,\n\ttype RESTPatchAPICurrentUserJSONBody,\n\ttype RESTPatchAPICurrentUserResult,\n\ttype RESTPatchAPIGuildMemberResult,\n\ttype RESTPostAPICurrentUserCreateDMChannelResult,\n\ttype RESTPutAPICurrentUserApplicationRoleConnectionJSONBody,\n\ttype RESTPutAPICurrentUserApplicationRoleConnectionResult,\n\ttype Snowflake,\n} from 'discord-api-types/v10';\n\nexport class UsersAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Fetches a user by their id\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/user#get-user}\n\t * @param userId - The id of the user to fetch\n\t * @param options - The options for fetching the user\n\t */\n\tpublic async get(userId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.user(userId), { auth, signal }) as Promise<RESTGetAPIUserResult>;\n\t}\n\n\t/**\n\t * Returns the user object of the requester's account\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/user#get-current-user}\n\t * @param options - The options for fetching the current user\n\t */\n\tpublic async getCurrent({ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.user('@me'), { auth, signal }) as Promise<RESTGetAPICurrentUserResult>;\n\t}\n\n\t/**\n\t * Returns a list of partial guild objects the current user is a member of\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/user#get-current-user-guilds}\n\t * @param query - The query options for fetching the current user's guilds\n\t * @param options - The options for fetching the guilds\n\t */\n\tpublic async getGuilds(\n\t\tquery: RESTGetAPICurrentUserGuildsQuery = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.userGuilds(), {\n\t\t\tauth,\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPICurrentUserGuildsResult>;\n\t}\n\n\t/**\n\t * Leaves the guild with the given id\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/user#leave-guild}\n\t * @param guildId - The id of the guild\n\t * @param options - The options for leaving the guild\n\t */\n\tpublic async leaveGuild(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\tawait this.rest.delete(Routes.userGuild(guildId), { auth, signal });\n\t}\n\n\t/**\n\t * Edits the current user\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/user#modify-current-user}\n\t * @param body - The new data for the current user\n\t * @param options - The options for editing the user\n\t */\n\tpublic async edit(\n\t\tbody: RESTPatchAPICurrentUserJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.user('@me'), { auth, body, signal }) as Promise<RESTPatchAPICurrentUserResult>;\n\t}\n\n\t/**\n\t * Fetches the guild member for the current user\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/user#get-current-user-guild-member}\n\t * @param guildId - The id of the guild\n\t * @param options - The options for fetching the guild member\n\t */\n\tpublic async getGuildMember(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.userGuildMember(guildId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetCurrentUserGuildMemberResult>;\n\t}\n\n\t/**\n\t * Edits the guild member for the current user\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/guild#modify-current-member}\n\t * @param guildId - The id of the guild\n\t * @param body - The new data for the guild member\n\t * @param options - The options for editing the guild member\n\t */\n\tpublic async editCurrentGuildMember(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPatchAPICurrentGuildMemberJSONBody = {},\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.guildMember(guildId, '@me'), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIGuildMemberResult>;\n\t}\n\n\t/**\n\t * Opens a new DM channel with a user\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/user#create-dm}\n\t * @param userId - The id of the user to open a DM channel with\n\t * @param options - The options for opening the DM\n\t */\n\tpublic async createDM(userId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.post(Routes.userChannels(), {\n\t\t\tauth,\n\t\t\tbody: { recipient_id: userId },\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPICurrentUserCreateDMChannelResult>;\n\t}\n\n\t/**\n\t * Gets the current user's connections\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/user#get-user-connections}\n\t * @param options - The options for fetching the user's connections\n\t */\n\tpublic async getConnections({ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.userConnections(), { auth, signal }) as Promise<RESTGetAPICurrentUserConnectionsResult>;\n\t}\n\n\t/**\n\t * Gets the current user's active application role connection\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/user#get-user-application-role-connection}\n\t * @param applicationId - The id of the application\n\t * @param options - The options for fetching the role connections\n\t */\n\tpublic async getApplicationRoleConnection(\n\t\tapplicationId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.userApplicationRoleConnection(applicationId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPICurrentUserApplicationRoleConnectionResult>;\n\t}\n\n\t/**\n\t * Updates the current user's application role connection\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/user#update-user-application-role-connection}\n\t * @param applicationId - The id of the application\n\t * @param body - The data for updating the application role connection\n\t * @param options - The options for updating the application role connection\n\t */\n\tpublic async updateApplicationRoleConnection(\n\t\tapplicationId: Snowflake,\n\t\tbody: RESTPutAPICurrentUserApplicationRoleConnectionJSONBody,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.put(Routes.userApplicationRoleConnection(applicationId), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPutAPICurrentUserApplicationRoleConnectionResult>;\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/voice.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport type { RequestData, REST } from '@discordjs/rest';\nimport {\n\tRoutes,\n\ttype Snowflake,\n\ttype RESTGetAPIVoiceRegionsResult,\n\ttype RESTGetAPIGuildVoiceStateUserResult,\n\ttype RESTGetAPIGuildVoiceStateCurrentMemberResult,\n\ttype RESTPatchAPIGuildVoiceStateUserJSONBody,\n\ttype RESTPatchAPIGuildVoiceStateCurrentMemberResult,\n\ttype RESTPatchAPIGuildVoiceStateCurrentMemberJSONBody,\n\ttype RESTPatchAPIGuildVoiceStateUserResult,\n} from 'discord-api-types/v10';\n\nexport class VoiceAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Fetches all voice regions\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/voice#list-voice-regions}\n\t * @param options - The options for fetching the voice regions\n\t */\n\tpublic async getVoiceRegions({ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.voiceRegions(), { auth, signal }) as Promise<RESTGetAPIVoiceRegionsResult>;\n\t}\n\n\t/**\n\t * Fetches voice state of a user by their id\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/voice#get-user-voice-state}\n\t * @param options - The options for fetching user voice state\n\t */\n\tpublic async getUserVoiceState(\n\t\tguildId: Snowflake,\n\t\tuserId: Snowflake,\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.guildVoiceState(guildId, userId), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildVoiceStateUserResult>;\n\t}\n\n\t/**\n\t * Fetches the current user's voice state\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/voice#get-current-user-voice-state}\n\t * @param options - The options for fetching user voice state\n\t */\n\tpublic async getVoiceState(guildId: Snowflake, { auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {}) {\n\t\treturn this.rest.get(Routes.guildVoiceState(guildId, '@me'), {\n\t\t\tauth,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIGuildVoiceStateCurrentMemberResult>;\n\t}\n\n\t/**\n\t * Edits a user's voice state in a guild\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/voice#modify-user-voice-state}\n\t * @param guildId - The id of the guild to edit the current user's voice state in\n\t * @param userId - The id of the user to edit the voice state for\n\t * @param body - The data for editing the voice state\n\t * @param options - The options for editing the voice state\n\t */\n\tpublic async editUserVoiceState(\n\t\tguildId: Snowflake,\n\t\tuserId: Snowflake,\n\t\tbody: RESTPatchAPIGuildVoiceStateUserJSONBody,\n\t\t{ auth, reason, signal }: Pick<RequestData, 'auth' | 'reason' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.guildVoiceState(guildId, userId), {\n\t\t\tauth,\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIGuildVoiceStateUserResult>;\n\t}\n\n\t/**\n\t * Edits the voice state for the current user\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/voice#modify-current-user-voice-state}\n\t * @param guildId - The id of the guild\n\t * @param body - The data for editing the voice state\n\t * @param options - The options for editing the voice state\n\t */\n\tpublic async editVoiceState(\n\t\tguildId: Snowflake,\n\t\tbody: RESTPatchAPIGuildVoiceStateCurrentMemberJSONBody = {},\n\t\t{ auth, signal }: Pick<RequestData, 'auth' | 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.guildVoiceState(guildId, '@me'), {\n\t\t\tauth,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPatchAPIGuildVoiceStateCurrentMemberResult>;\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/api/webhook.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport { makeURLSearchParams, type RequestData, type RawFile, type REST } from '@discordjs/rest';\nimport {\n\tRoutes,\n\ttype RESTGetAPIWebhookWithTokenMessageQuery,\n\ttype RESTGetAPIWebhookWithTokenMessageResult,\n\ttype RESTGetAPIWebhookResult,\n\ttype RESTPatchAPIWebhookJSONBody,\n\ttype RESTPatchAPIWebhookResult,\n\ttype RESTPatchAPIWebhookWithTokenMessageJSONBody,\n\ttype RESTPatchAPIWebhookWithTokenMessageQuery,\n\ttype RESTPatchAPIWebhookWithTokenMessageResult,\n\ttype RESTPostAPIWebhookWithTokenGitHubQuery,\n\ttype RESTPostAPIWebhookWithTokenJSONBody,\n\ttype RESTPostAPIWebhookWithTokenQuery,\n\ttype RESTPostAPIWebhookWithTokenSlackQuery,\n\ttype RESTPostAPIWebhookWithTokenWaitResult,\n\ttype Snowflake,\n} from 'discord-api-types/v10';\n\nexport type CreateWebhookMessageOptions = RESTPostAPIWebhookWithTokenJSONBody &\n\tRESTPostAPIWebhookWithTokenQuery & { files?: RawFile[] };\n\nexport type EditWebhookMessageOptions = RESTPatchAPIWebhookWithTokenMessageJSONBody &\n\tRESTPatchAPIWebhookWithTokenMessageQuery & {\n\t\tfiles?: RawFile[];\n\t};\n\nexport class WebhooksAPI {\n\tpublic constructor(private readonly rest: REST) {}\n\n\t/**\n\t * Fetches a webhook\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#get-webhook}\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#get-webhook-with-token}\n\t * @param id - The id of the webhook\n\t * @param options - The options for fetching the webhook\n\t */\n\tpublic async get(\n\t\tid: Snowflake,\n\t\t{ token, signal }: Pick<RequestData, 'signal'> & { token?: string | undefined } = {},\n\t) {\n\t\treturn this.rest.get(Routes.webhook(id, token), {\n\t\t\tsignal,\n\t\t\tauth: !token,\n\t\t}) as Promise<RESTGetAPIWebhookResult>;\n\t}\n\n\t/**\n\t * Edits a webhook\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#modify-webhook}\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#modify-webhook-with-token}\n\t * @param id - The id of the webhook to edit\n\t * @param body - The new webhook data\n\t * @param options - The options for editing the webhook\n\t */\n\tpublic async edit(\n\t\tid: Snowflake,\n\t\tbody: RESTPatchAPIWebhookJSONBody,\n\t\t{ token, reason, signal }: Pick<RequestData, 'reason' | 'signal'> & { token?: string | undefined } = {},\n\t) {\n\t\treturn this.rest.patch(Routes.webhook(id, token), {\n\t\t\treason,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t\tauth: !token,\n\t\t}) as Promise<RESTPatchAPIWebhookResult>;\n\t}\n\n\t/**\n\t * Deletes a webhook\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#delete-webhook}\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#delete-webhook-with-token}\n\t * @param id - The id of the webhook to delete\n\t * @param options - The options for deleting the webhook\n\t */\n\tpublic async delete(\n\t\tid: Snowflake,\n\t\t{ token, reason, signal }: Pick<RequestData, 'reason' | 'signal'> & { token?: string | undefined } = {},\n\t) {\n\t\tawait this.rest.delete(Routes.webhook(id, token), {\n\t\t\treason,\n\t\t\tsignal,\n\t\t\tauth: !token,\n\t\t});\n\t}\n\n\t/**\n\t * Executes a webhook and returns the created message\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#execute-webhook}\n\t * @param id - The id of the webhook\n\t * @param token - The token of the webhook\n\t * @param body - The data for executing the webhook\n\t * @param options - The options for executing the webhook\n\t */\n\tpublic async execute(\n\t\tid: Snowflake,\n\t\ttoken: string,\n\t\tbody: CreateWebhookMessageOptions & { wait: true },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<RESTPostAPIWebhookWithTokenWaitResult>;\n\n\t/**\n\t * Executes a webhook\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#execute-webhook}\n\t * @param id - The id of the webhook\n\t * @param token - The token of the webhook\n\t * @param body - The data for executing the webhook\n\t * @param options - The options for executing the webhook\n\t */\n\tpublic async execute(\n\t\tid: Snowflake,\n\t\ttoken: string,\n\t\tbody: CreateWebhookMessageOptions & { wait?: false },\n\t\toptions?: Pick<RequestData, 'signal'>,\n\t): Promise<void>;\n\n\t/**\n\t * Executes a webhook\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#execute-webhook}\n\t * @param id - The id of the webhook\n\t * @param token - The token of the webhook\n\t * @param body - The data for executing the webhook\n\t * @param options - The options for executing the webhook\n\t */\n\tpublic async execute(\n\t\tid: Snowflake,\n\t\ttoken: string,\n\t\t{ wait, thread_id, with_components, files, ...body }: CreateWebhookMessageOptions,\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\treturn this.rest.post(Routes.webhook(id, token), {\n\t\t\tquery: makeURLSearchParams({ wait, thread_id, with_components }),\n\t\t\tfiles,\n\t\t\tbody,\n\t\t\tauth: false,\n\t\t\tsignal,\n\t\t}) as Promise<RESTPostAPIWebhookWithTokenWaitResult | void>;\n\t}\n\n\t/**\n\t * Executes a slack webhook\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook}\n\t * @param id - The id of the webhook\n\t * @param token - The token of the webhook\n\t * @param body - The data for executing the webhook\n\t * @param query - The query options for executing the webhook\n\t * @param options - The options for executing the webhook\n\t */\n\tpublic async executeSlack(\n\t\tid: Snowflake,\n\t\ttoken: string,\n\t\tbody: unknown,\n\t\tquery: RESTPostAPIWebhookWithTokenSlackQuery = {},\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\tawait this.rest.post(Routes.webhookPlatform(id, token, 'slack'), {\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tbody,\n\t\t\tauth: false,\n\t\t\tsignal,\n\t\t});\n\t}\n\n\t/**\n\t * Executes a github webhook\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#execute-githubcompatible-webhook}\n\t * @param id - The id of the webhook\n\t * @param token - The token of the webhook\n\t * @param body - The data for executing the webhook\n\t * @param query - The options for executing the webhook\n\t * @param options - The options for executing the webhook\n\t */\n\tpublic async executeGitHub(\n\t\tid: Snowflake,\n\t\ttoken: string,\n\t\tbody: unknown,\n\t\tquery: RESTPostAPIWebhookWithTokenGitHubQuery = {},\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\tawait this.rest.post(Routes.webhookPlatform(id, token, 'github'), {\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tbody,\n\t\t\tsignal,\n\t\t\tauth: false,\n\t\t});\n\t}\n\n\t/**\n\t * Fetches an associated message from a webhook\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#get-webhook-message}\n\t * @param id - The id of the webhook\n\t * @param token - The token of the webhook\n\t * @param messageId - The id of the message to fetch\n\t * @param query - The query options for fetching the message\n\t * @param options - The options for fetching the message\n\t */\n\tpublic async getMessage(\n\t\tid: Snowflake,\n\t\ttoken: string,\n\t\tmessageId: Snowflake,\n\t\tquery: RESTGetAPIWebhookWithTokenMessageQuery = {},\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\treturn this.rest.get(Routes.webhookMessage(id, token, messageId), {\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tauth: false,\n\t\t\tsignal,\n\t\t}) as Promise<RESTGetAPIWebhookWithTokenMessageResult>;\n\t}\n\n\t/**\n\t * Edits an associated message from a webhook\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#edit-webhook-message}\n\t * @param id - The id of the webhook\n\t * @param token - The token of the webhook\n\t * @param messageId - The id of the message to edit\n\t * @param body - The data for editing the message\n\t * @param options - The options for editing the message\n\t */\n\tpublic async editMessage(\n\t\tid: Snowflake,\n\t\ttoken: string,\n\t\tmessageId: Snowflake,\n\t\t{ thread_id, with_components, files, ...body }: EditWebhookMessageOptions,\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\treturn this.rest.patch(Routes.webhookMessage(id, token, messageId), {\n\t\t\tquery: makeURLSearchParams({ thread_id, with_components }),\n\t\t\tauth: false,\n\t\t\tbody,\n\t\t\tsignal,\n\t\t\tfiles,\n\t\t}) as Promise<RESTPatchAPIWebhookWithTokenMessageResult>;\n\t}\n\n\t/**\n\t * Deletes an associated message from a webhook\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#delete-webhook-message}\n\t * @param id - The id of the webhook\n\t * @param token - The token of the webhook\n\t * @param messageId - The id of the message to delete\n\t * @param query - The options for deleting the message\n\t * @param options - The options for deleting the message\n\t */\n\tpublic async deleteMessage(\n\t\tid: Snowflake,\n\t\ttoken: string,\n\t\tmessageId: Snowflake,\n\t\tquery: { thread_id?: Snowflake } = {},\n\t\t{ signal }: Pick<RequestData, 'signal'> = {},\n\t) {\n\t\tawait this.rest.delete(Routes.webhookMessage(id, token, messageId), {\n\t\t\tquery: makeURLSearchParams(query),\n\t\t\tauth: false,\n\t\t\tsignal,\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/client.ts",
    "content": "import type { REST } from '@discordjs/rest';\nimport { calculateShardId, GatewayRateLimitError } from '@discordjs/util';\nimport { WebSocketShardEvents } from '@discordjs/ws';\nimport { DiscordSnowflake } from '@sapphire/snowflake';\nimport { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';\nimport {\n\tGatewayDispatchEvents,\n\tGatewayOpcodes,\n\ttype GatewayApplicationCommandPermissionsUpdateDispatchData,\n\ttype GatewayAutoModerationActionExecutionDispatchData,\n\ttype GatewayAutoModerationRuleCreateDispatchData,\n\ttype GatewayAutoModerationRuleDeleteDispatchData,\n\ttype GatewayAutoModerationRuleUpdateDispatchData,\n\ttype GatewayChannelCreateDispatchData,\n\ttype GatewayChannelDeleteDispatchData,\n\ttype GatewayChannelPinsUpdateDispatchData,\n\ttype GatewayChannelUpdateDispatchData,\n\ttype GatewayEntitlementCreateDispatchData,\n\ttype GatewayEntitlementDeleteDispatchData,\n\ttype GatewayEntitlementUpdateDispatchData,\n\ttype GatewayGuildAuditLogEntryCreateDispatchData,\n\ttype GatewayGuildBanAddDispatchData,\n\ttype GatewayGuildBanRemoveDispatchData,\n\ttype GatewayGuildCreateDispatchData,\n\ttype GatewayGuildDeleteDispatchData,\n\ttype GatewayGuildEmojisUpdateDispatchData,\n\ttype GatewayGuildIntegrationsUpdateDispatchData,\n\ttype GatewayGuildMemberAddDispatchData,\n\ttype GatewayGuildMemberRemoveDispatchData,\n\ttype GatewayGuildMemberUpdateDispatchData,\n\ttype GatewayGuildMembersChunkDispatchData,\n\ttype GatewayGuildRoleCreateDispatchData,\n\ttype GatewayGuildRoleDeleteDispatchData,\n\ttype GatewayGuildRoleUpdateDispatchData,\n\ttype GatewayGuildScheduledEventCreateDispatchData,\n\ttype GatewayGuildScheduledEventDeleteDispatchData,\n\ttype GatewayGuildScheduledEventUpdateDispatchData,\n\ttype GatewayGuildScheduledEventUserAddDispatchData,\n\ttype GatewayGuildScheduledEventUserRemoveDispatchData,\n\ttype GatewayGuildSoundboardSoundCreateDispatch,\n\ttype GatewayGuildSoundboardSoundDeleteDispatch,\n\ttype GatewayGuildSoundboardSoundUpdateDispatch,\n\ttype GatewayGuildSoundboardSoundsUpdateDispatch,\n\ttype GatewayGuildStickersUpdateDispatchData,\n\ttype GatewayGuildUpdateDispatchData,\n\ttype GatewayIntegrationCreateDispatchData,\n\ttype GatewayIntegrationDeleteDispatchData,\n\ttype GatewayIntegrationUpdateDispatchData,\n\ttype GatewayInteractionCreateDispatchData,\n\ttype GatewayInviteCreateDispatchData,\n\ttype GatewayInviteDeleteDispatchData,\n\ttype GatewayMessageCreateDispatchData,\n\ttype GatewayMessageDeleteBulkDispatchData,\n\ttype GatewayMessageDeleteDispatchData,\n\ttype GatewayMessagePollVoteDispatchData,\n\ttype GatewayMessageReactionAddDispatchData,\n\ttype GatewayMessageReactionRemoveAllDispatchData,\n\ttype GatewayMessageReactionRemoveDispatchData,\n\ttype GatewayMessageReactionRemoveEmojiDispatchData,\n\ttype GatewayMessageUpdateDispatchData,\n\ttype GatewayPresenceUpdateData,\n\ttype GatewayPresenceUpdateDispatchData,\n\ttype GatewayRateLimitedDispatchData,\n\ttype GatewayReadyDispatchData,\n\ttype GatewayRequestGuildMembersData,\n\ttype GatewayStageInstanceCreateDispatchData,\n\ttype GatewayStageInstanceDeleteDispatchData,\n\ttype GatewayStageInstanceUpdateDispatchData,\n\ttype GatewaySubscriptionCreateDispatchData,\n\ttype GatewaySubscriptionDeleteDispatchData,\n\ttype GatewaySubscriptionUpdateDispatchData,\n\ttype GatewayThreadCreateDispatchData,\n\ttype GatewayThreadDeleteDispatchData,\n\ttype GatewayThreadListSyncDispatchData,\n\ttype GatewayThreadMemberUpdateDispatchData,\n\ttype GatewayThreadMembersUpdateDispatchData,\n\ttype GatewayThreadUpdateDispatchData,\n\ttype GatewayTypingStartDispatchData,\n\ttype GatewayUserUpdateDispatchData,\n\ttype GatewayVoiceServerUpdateDispatchData,\n\ttype GatewayVoiceStateUpdateData,\n\ttype GatewayVoiceStateUpdateDispatchData,\n\ttype GatewayWebhooksUpdateDispatchData,\n\ttype GatewayRequestSoundboardSoundsData,\n\ttype GatewaySoundboardSoundsDispatchData,\n} from 'discord-api-types/v10';\nimport type { Gateway } from './Gateway.js';\nimport { API } from './api/index.js';\n\nexport interface IntrinsicProps {\n\t/**\n\t * The REST API\n\t */\n\tapi: API;\n\t/**\n\t * The id of the shard that emitted the event\n\t */\n\tshardId: number;\n}\n\nexport interface ToEventProps<Data> extends IntrinsicProps {\n\tdata: Data;\n}\n\nexport interface MappedEvents {\n\t[GatewayDispatchEvents.ApplicationCommandPermissionsUpdate]: [\n\t\tToEventProps<GatewayApplicationCommandPermissionsUpdateDispatchData>,\n\t];\n\t[GatewayDispatchEvents.AutoModerationActionExecution]: [\n\t\tToEventProps<GatewayAutoModerationActionExecutionDispatchData>,\n\t];\n\t[GatewayDispatchEvents.AutoModerationRuleCreate]: [ToEventProps<GatewayAutoModerationRuleCreateDispatchData>];\n\t[GatewayDispatchEvents.AutoModerationRuleDelete]: [ToEventProps<GatewayAutoModerationRuleDeleteDispatchData>];\n\t[GatewayDispatchEvents.AutoModerationRuleUpdate]: [ToEventProps<GatewayAutoModerationRuleUpdateDispatchData>];\n\t[GatewayDispatchEvents.ChannelCreate]: [ToEventProps<GatewayChannelCreateDispatchData>];\n\t[GatewayDispatchEvents.ChannelDelete]: [ToEventProps<GatewayChannelDeleteDispatchData>];\n\t[GatewayDispatchEvents.ChannelPinsUpdate]: [ToEventProps<GatewayChannelPinsUpdateDispatchData>];\n\t[GatewayDispatchEvents.ChannelUpdate]: [ToEventProps<GatewayChannelUpdateDispatchData>];\n\t[GatewayDispatchEvents.EntitlementCreate]: [ToEventProps<GatewayEntitlementCreateDispatchData>];\n\t[GatewayDispatchEvents.EntitlementDelete]: [ToEventProps<GatewayEntitlementDeleteDispatchData>];\n\t[GatewayDispatchEvents.EntitlementUpdate]: [ToEventProps<GatewayEntitlementUpdateDispatchData>];\n\t[GatewayDispatchEvents.GuildAuditLogEntryCreate]: [ToEventProps<GatewayGuildAuditLogEntryCreateDispatchData>];\n\t[GatewayDispatchEvents.GuildBanAdd]: [ToEventProps<GatewayGuildBanAddDispatchData>];\n\t[GatewayDispatchEvents.GuildBanRemove]: [ToEventProps<GatewayGuildBanRemoveDispatchData>];\n\t[GatewayDispatchEvents.GuildCreate]: [ToEventProps<GatewayGuildCreateDispatchData>];\n\t[GatewayDispatchEvents.GuildDelete]: [ToEventProps<GatewayGuildDeleteDispatchData>];\n\t[GatewayDispatchEvents.GuildEmojisUpdate]: [ToEventProps<GatewayGuildEmojisUpdateDispatchData>];\n\t[GatewayDispatchEvents.GuildIntegrationsUpdate]: [ToEventProps<GatewayGuildIntegrationsUpdateDispatchData>];\n\t[GatewayDispatchEvents.GuildMemberAdd]: [ToEventProps<GatewayGuildMemberAddDispatchData>];\n\t[GatewayDispatchEvents.GuildMemberRemove]: [ToEventProps<GatewayGuildMemberRemoveDispatchData>];\n\t[GatewayDispatchEvents.GuildMemberUpdate]: [ToEventProps<GatewayGuildMemberUpdateDispatchData>];\n\t[GatewayDispatchEvents.GuildMembersChunk]: [ToEventProps<GatewayGuildMembersChunkDispatchData>];\n\t[GatewayDispatchEvents.GuildRoleCreate]: [ToEventProps<GatewayGuildRoleCreateDispatchData>];\n\t[GatewayDispatchEvents.GuildRoleDelete]: [ToEventProps<GatewayGuildRoleDeleteDispatchData>];\n\t[GatewayDispatchEvents.GuildRoleUpdate]: [ToEventProps<GatewayGuildRoleUpdateDispatchData>];\n\t[GatewayDispatchEvents.GuildScheduledEventCreate]: [ToEventProps<GatewayGuildScheduledEventCreateDispatchData>];\n\t[GatewayDispatchEvents.GuildScheduledEventDelete]: [ToEventProps<GatewayGuildScheduledEventDeleteDispatchData>];\n\t[GatewayDispatchEvents.GuildScheduledEventUpdate]: [ToEventProps<GatewayGuildScheduledEventUpdateDispatchData>];\n\t[GatewayDispatchEvents.GuildScheduledEventUserAdd]: [ToEventProps<GatewayGuildScheduledEventUserAddDispatchData>];\n\t[GatewayDispatchEvents.GuildScheduledEventUserRemove]: [\n\t\tToEventProps<GatewayGuildScheduledEventUserRemoveDispatchData>,\n\t];\n\t[GatewayDispatchEvents.GuildSoundboardSoundCreate]: [ToEventProps<GatewayGuildSoundboardSoundCreateDispatch>];\n\t[GatewayDispatchEvents.GuildSoundboardSoundDelete]: [ToEventProps<GatewayGuildSoundboardSoundDeleteDispatch>];\n\t[GatewayDispatchEvents.GuildSoundboardSoundUpdate]: [ToEventProps<GatewayGuildSoundboardSoundUpdateDispatch>];\n\t[GatewayDispatchEvents.GuildSoundboardSoundsUpdate]: [ToEventProps<GatewayGuildSoundboardSoundsUpdateDispatch>];\n\t[GatewayDispatchEvents.SoundboardSounds]: [ToEventProps<GatewaySoundboardSoundsDispatchData>];\n\t[GatewayDispatchEvents.GuildStickersUpdate]: [ToEventProps<GatewayGuildStickersUpdateDispatchData>];\n\t[GatewayDispatchEvents.GuildUpdate]: [ToEventProps<GatewayGuildUpdateDispatchData>];\n\t[GatewayDispatchEvents.IntegrationCreate]: [ToEventProps<GatewayIntegrationCreateDispatchData>];\n\t[GatewayDispatchEvents.IntegrationDelete]: [ToEventProps<GatewayIntegrationDeleteDispatchData>];\n\t[GatewayDispatchEvents.IntegrationUpdate]: [ToEventProps<GatewayIntegrationUpdateDispatchData>];\n\t[GatewayDispatchEvents.InteractionCreate]: [ToEventProps<GatewayInteractionCreateDispatchData>];\n\t[GatewayDispatchEvents.InviteCreate]: [ToEventProps<GatewayInviteCreateDispatchData>];\n\t[GatewayDispatchEvents.InviteDelete]: [ToEventProps<GatewayInviteDeleteDispatchData>];\n\t[GatewayDispatchEvents.MessageCreate]: [ToEventProps<GatewayMessageCreateDispatchData>];\n\t[GatewayDispatchEvents.MessageDelete]: [ToEventProps<GatewayMessageDeleteDispatchData>];\n\t[GatewayDispatchEvents.MessageDeleteBulk]: [ToEventProps<GatewayMessageDeleteBulkDispatchData>];\n\t[GatewayDispatchEvents.MessagePollVoteAdd]: [ToEventProps<GatewayMessagePollVoteDispatchData>];\n\t[GatewayDispatchEvents.MessagePollVoteRemove]: [ToEventProps<GatewayMessagePollVoteDispatchData>];\n\t[GatewayDispatchEvents.MessageReactionAdd]: [ToEventProps<GatewayMessageReactionAddDispatchData>];\n\t[GatewayDispatchEvents.MessageReactionRemove]: [ToEventProps<GatewayMessageReactionRemoveDispatchData>];\n\t[GatewayDispatchEvents.MessageReactionRemoveAll]: [ToEventProps<GatewayMessageReactionRemoveAllDispatchData>];\n\t[GatewayDispatchEvents.MessageReactionRemoveEmoji]: [ToEventProps<GatewayMessageReactionRemoveEmojiDispatchData>];\n\t[GatewayDispatchEvents.MessageUpdate]: [ToEventProps<GatewayMessageUpdateDispatchData>];\n\t[GatewayDispatchEvents.PresenceUpdate]: [ToEventProps<GatewayPresenceUpdateDispatchData>];\n\t[GatewayDispatchEvents.RateLimited]: [ToEventProps<GatewayRateLimitedDispatchData>];\n\t[GatewayDispatchEvents.Ready]: [ToEventProps<GatewayReadyDispatchData>];\n\t[GatewayDispatchEvents.Resumed]: [ToEventProps<never>];\n\t[GatewayDispatchEvents.StageInstanceCreate]: [ToEventProps<GatewayStageInstanceCreateDispatchData>];\n\t[GatewayDispatchEvents.StageInstanceDelete]: [ToEventProps<GatewayStageInstanceDeleteDispatchData>];\n\t[GatewayDispatchEvents.StageInstanceUpdate]: [ToEventProps<GatewayStageInstanceUpdateDispatchData>];\n\t[GatewayDispatchEvents.SubscriptionCreate]: [ToEventProps<GatewaySubscriptionCreateDispatchData>];\n\t[GatewayDispatchEvents.SubscriptionDelete]: [ToEventProps<GatewaySubscriptionDeleteDispatchData>];\n\t[GatewayDispatchEvents.SubscriptionUpdate]: [ToEventProps<GatewaySubscriptionUpdateDispatchData>];\n\t[GatewayDispatchEvents.ThreadCreate]: [ToEventProps<GatewayThreadCreateDispatchData>];\n\t[GatewayDispatchEvents.ThreadDelete]: [ToEventProps<GatewayThreadDeleteDispatchData>];\n\t[GatewayDispatchEvents.ThreadListSync]: [ToEventProps<GatewayThreadListSyncDispatchData>];\n\t[GatewayDispatchEvents.ThreadMemberUpdate]: [ToEventProps<GatewayThreadMemberUpdateDispatchData>];\n\t[GatewayDispatchEvents.ThreadMembersUpdate]: [ToEventProps<GatewayThreadMembersUpdateDispatchData>];\n\t[GatewayDispatchEvents.ThreadUpdate]: [ToEventProps<GatewayThreadUpdateDispatchData>];\n\t[GatewayDispatchEvents.TypingStart]: [ToEventProps<GatewayTypingStartDispatchData>];\n\t[GatewayDispatchEvents.UserUpdate]: [ToEventProps<GatewayUserUpdateDispatchData>];\n\t[GatewayDispatchEvents.VoiceServerUpdate]: [ToEventProps<GatewayVoiceServerUpdateDispatchData>];\n\t[GatewayDispatchEvents.VoiceStateUpdate]: [ToEventProps<GatewayVoiceStateUpdateDispatchData>];\n\t[GatewayDispatchEvents.WebhooksUpdate]: [ToEventProps<GatewayWebhooksUpdateDispatchData>];\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface ManagerShardEventsMap extends MappedEvents {}\n\nexport interface ClientOptions {\n\tgateway: Gateway;\n\trest: REST;\n}\n\nexport interface RequestGuildMembersResult {\n\tmembers: GatewayGuildMembersChunkDispatchData['members'];\n\tnonce: NonNullable<GatewayGuildMembersChunkDispatchData['nonce']>;\n\tnotFound: NonNullable<GatewayGuildMembersChunkDispatchData['not_found']>;\n\tpresences: NonNullable<GatewayGuildMembersChunkDispatchData['presences']>;\n}\n\nfunction createTimer(controller: AbortController, timeout: number) {\n\treturn setTimeout(() => controller.abort(), timeout);\n}\n\nexport class Client extends AsyncEventEmitter<MappedEvents> {\n\tpublic readonly rest: REST;\n\n\tpublic readonly gateway: Gateway;\n\n\tpublic readonly api: API;\n\n\tpublic constructor(options: ClientOptions) {\n\t\tsuper();\n\t\tthis.rest = options.rest;\n\t\tthis.gateway = options.gateway;\n\t\tthis.api = new API(this.rest);\n\n\t\tthis.gateway.on(WebSocketShardEvents.Dispatch, (dispatch, shardId) => {\n\t\t\tthis.emit(dispatch.t, this.toEventProps(dispatch.d, shardId));\n\t\t});\n\t}\n\n\t/**\n\t * Requests guild members from the gateway and returns an async iterator that yields the data from each guild members chunk event.\n\t *\n\t * @see {@link https://discord.com/developers/docs/topics/gateway-events#request-guild-members}\n\t * @param options - The options for the request\n\t * @param timeout - The timeout for waiting for each guild members chunk event\n\t * @example\n\t * Requesting all members from a guild\n\t * ```ts\n\t * for await (const { members } of client.requestGuildMembersIterator({ guild_id: '1234567890', query: '', limit: 0 })) {\n\t * \tconsole.log(members);\n\t * }\n\t * ```\n\t */\n\tpublic async *requestGuildMembersIterator(options: GatewayRequestGuildMembersData, timeout = 10_000) {\n\t\tconst shardId = calculateShardId(options.guild_id, await this.gateway.getShardCount());\n\t\tconst nonce = options.nonce ?? DiscordSnowflake.generate().toString();\n\n\t\tconst controller = new AbortController();\n\n\t\tlet timer: NodeJS.Timeout | undefined = createTimer(controller, timeout);\n\n\t\tconst onRatelimit = ({ data }: ToEventProps<GatewayRateLimitedDispatchData>) => {\n\t\t\t// We could verify meta.guild_id === options.guild_id as well, but really, the nonce check is enough\n\t\t\tif (data.meta.nonce === nonce) {\n\t\t\t\tcontroller.abort(new GatewayRateLimitError(data, options));\n\t\t\t}\n\t\t};\n\n\t\tconst cleanup = () => {\n\t\t\tif (timer) {\n\t\t\t\tclearTimeout(timer);\n\t\t\t}\n\n\t\t\tthis.off(GatewayDispatchEvents.RateLimited, onRatelimit);\n\t\t};\n\n\t\tthis.on(GatewayDispatchEvents.RateLimited, onRatelimit);\n\t\tawait this.gateway.send(shardId, {\n\t\t\top: GatewayOpcodes.RequestGuildMembers,\n\t\t\t// eslint-disable-next-line id-length\n\t\t\td: {\n\t\t\t\t...options,\n\t\t\t\tnonce,\n\t\t\t},\n\t\t});\n\n\t\ttry {\n\t\t\tconst iterator = AsyncEventEmitter.on(this, GatewayDispatchEvents.GuildMembersChunk, {\n\t\t\t\tsignal: controller.signal,\n\t\t\t});\n\n\t\t\tfor await (const [{ data }] of iterator) {\n\t\t\t\tif (data.nonce !== nonce) continue;\n\n\t\t\t\tclearTimeout(timer);\n\t\t\t\ttimer = undefined;\n\n\t\t\t\tyield {\n\t\t\t\t\tmembers: data.members,\n\t\t\t\t\tnonce,\n\t\t\t\t\tnotFound: data.not_found ?? null,\n\t\t\t\t\tpresences: data.presences ?? null,\n\t\t\t\t\tchunkIndex: data.chunk_index,\n\t\t\t\t\tchunkCount: data.chunk_count,\n\t\t\t\t};\n\n\t\t\t\tif (data.chunk_index >= data.chunk_count - 1) break;\n\n\t\t\t\t// eslint-disable-next-line require-atomic-updates\n\t\t\t\ttimer = createTimer(controller, timeout);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.name === 'AbortError') {\n\t\t\t\tif (error.cause instanceof GatewayRateLimitError) {\n\t\t\t\t\tthrow error.cause;\n\t\t\t\t}\n\n\t\t\t\tthrow new Error('Request timed out');\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tcleanup();\n\t\t}\n\t}\n\n\t/**\n\t * Requests guild members from the gateway.\n\t *\n\t * @see {@link https://discord.com/developers/docs/topics/gateway-events#request-guild-members}\n\t * @param options - The options for the request\n\t * @param timeout - The timeout for waiting for each guild members chunk event\n\t * @example\n\t * Requesting specific members from a guild\n\t * ```ts\n\t * const { members } = await client.requestGuildMembers({ guild_id: '1234567890', user_ids: ['9876543210'] });\n\t * ```\n\t */\n\tpublic async requestGuildMembers(options: GatewayRequestGuildMembersData, timeout = 10_000) {\n\t\tconst members: RequestGuildMembersResult['members'] = [];\n\t\tconst notFound: RequestGuildMembersResult['notFound'] = [];\n\t\tconst presences: RequestGuildMembersResult['presences'] = [];\n\t\tconst nonce = options.nonce ?? DiscordSnowflake.generate().toString();\n\n\t\tfor await (const data of this.requestGuildMembersIterator({ ...options, nonce }, timeout)) {\n\t\t\tmembers.push(...data.members);\n\t\t\tif (data.presences) presences.push(...data.presences);\n\t\t\tif (data.notFound) notFound.push(...data.notFound);\n\t\t}\n\n\t\treturn { members, nonce, notFound, presences };\n\t}\n\n\t/**\n\t * Requests soundboard sounds from the gateway and returns an async iterator that yields the data from each soundboard sounds event.\n\t *\n\t * @see {@link https://discord.com/developers/docs/topics/gateway-events#request-soundboard-sounds}\n\t * @param options - The options for the request\n\t * @param timeout - The timeout for waiting for each soundboard sounds\n\t * @example\n\t * Requesting soundboard sounds for specific guilds\n\t * ```ts\n\t * for await (const { guildId, soundboardSounds } of this.requestSoundboardSoundsIterator({\n\t *\tguild_ids: ['1234567890', '9876543210'],\n\t * })) {\n\t *\tconsole.log(`Soundboard sounds for guild ${guildId}:`, soundboardSounds);\n\t * }\n\t * ```\n\t */\n\tpublic async *requestSoundboardSoundsIterator(options: GatewayRequestSoundboardSoundsData, timeout = 10_000) {\n\t\tconst shardCount = await this.gateway.getShardCount();\n\t\tconst shardIds = Map.groupBy(options.guild_ids, (guildId) => calculateShardId(guildId, shardCount));\n\n\t\tconst controller = new AbortController();\n\n\t\tlet timer: NodeJS.Timeout | undefined = createTimer(controller, timeout);\n\n\t\tfor (const [shardId, guildIds] of shardIds) {\n\t\t\tawait this.gateway.send(shardId, {\n\t\t\t\top: GatewayOpcodes.RequestSoundboardSounds,\n\t\t\t\t// eslint-disable-next-line id-length\n\t\t\t\td: {\n\t\t\t\t\t...options,\n\t\t\t\t\tguild_ids: guildIds,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\ttry {\n\t\t\tconst iterator = AsyncEventEmitter.on(this, GatewayDispatchEvents.SoundboardSounds, {\n\t\t\t\tsignal: controller.signal,\n\t\t\t});\n\n\t\t\tconst guildIds = new Set(options.guild_ids);\n\n\t\t\tfor await (const [{ data }] of iterator) {\n\t\t\t\tif (!guildIds.has(data.guild_id)) continue;\n\n\t\t\t\tclearTimeout(timer);\n\t\t\t\ttimer = undefined;\n\n\t\t\t\tyield {\n\t\t\t\t\tguildId: data.guild_id,\n\t\t\t\t\tsoundboardSounds: data.soundboard_sounds,\n\t\t\t\t};\n\n\t\t\t\tguildIds.delete(data.guild_id);\n\n\t\t\t\tif (guildIds.size === 0) break;\n\n\t\t\t\ttimer = createTimer(controller, timeout);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.name === 'AbortError') {\n\t\t\t\tthrow new Error('Request timed out');\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tif (timer) {\n\t\t\t\tclearTimeout(timer);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Requests soundboard sounds from the gateway.\n\t *\n\t * @see {@link https://discord.com/developers/docs/topics/gateway-events#request-soundboard-sounds}\n\t * @param options - The options for the request\n\t * @param timeout - The timeout for waiting for each soundboard sounds event\n\t * @example\n\t * Requesting soundboard sounds for specific guilds\n\t * ```ts\n\t * const soundboardSounds = await client.requestSoundboardSounds({ guild_ids: ['1234567890', '9876543210'], });\n\t *\n\t * console.log(soundboardSounds.get('1234567890'));\n\t * ```\n\t */\n\tpublic async requestSoundboardSounds(options: GatewayRequestSoundboardSoundsData, timeout = 10_000) {\n\t\tconst soundboardSounds = new Map<\n\t\t\tGatewaySoundboardSoundsDispatchData['guild_id'],\n\t\t\tGatewaySoundboardSoundsDispatchData['soundboard_sounds']\n\t\t>();\n\n\t\tfor await (const data of this.requestSoundboardSoundsIterator(options, timeout)) {\n\t\t\tsoundboardSounds.set(data.guildId, data.soundboardSounds);\n\t\t}\n\n\t\treturn soundboardSounds;\n\t}\n\n\t/**\n\t * Updates the voice state of the bot user\n\t *\n\t * @see {@link https://discord.com/developers/docs/topics/gateway-events#update-voice-state}\n\t * @param options - The options for updating the voice state\n\t */\n\tpublic async updateVoiceState(options: GatewayVoiceStateUpdateData) {\n\t\tconst shardId = calculateShardId(options.guild_id, await this.gateway.getShardCount());\n\n\t\tawait this.gateway.send(shardId, {\n\t\t\top: GatewayOpcodes.VoiceStateUpdate,\n\t\t\t// eslint-disable-next-line id-length\n\t\t\td: options,\n\t\t});\n\t}\n\n\t/**\n\t * Updates the presence of the bot user\n\t *\n\t * @param shardId - The id of the shard to update the presence in\n\t * @param options - The options for updating the presence\n\t */\n\tpublic async updatePresence(shardId: number, options: GatewayPresenceUpdateData) {\n\t\tawait this.gateway.send(shardId, {\n\t\t\top: GatewayOpcodes.PresenceUpdate,\n\t\t\t// eslint-disable-next-line id-length\n\t\t\td: options,\n\t\t});\n\t}\n\n\tprivate toEventProps<ObjectType>(obj: ObjectType, shardId: number): ToEventProps<ObjectType> {\n\t\treturn {\n\t\t\tapi: this.api,\n\t\t\tshardId,\n\t\t\tdata: obj,\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/http-only/index.ts",
    "content": "export * from '../api/index.js';\nexport * from '../util/index.js';\n\nexport * from 'discord-api-types/v10';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/core#readme | @discordjs/core} version\n * that you are currently using.\n */\n// This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild\nexport const version = '[VI]{{inject}}[/VI]' as string;\n"
  },
  {
    "path": "packages/core/src/index.ts",
    "content": "export * from './api/index.js';\nexport * from './client.js';\nexport type * from './Gateway.js';\nexport * from './util/index.js';\n\nexport * from 'discord-api-types/v10';\n\nexport { GatewayRateLimitError } from '@discordjs/util';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/core#readme | @discordjs/core} version\n * that you are currently using.\n */\n// This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild\nexport const version = '[VI]{{inject}}[/VI]' as string;\n"
  },
  {
    "path": "packages/core/src/util/files.ts",
    "content": "import type { RawFile } from '@discordjs/rest';\nimport type { APIInteractionResponseCallbackData } from 'discord-api-types/v10';\n\nexport interface DescriptiveRawFile extends RawFile {\n\tdescription?: string;\n}\n\n/**\n * A utility function to create a form data payload given an array of file buffers\n *\n * @param files - The files to create a form data payload for\n * @param options - The additional options for the form data payload\n */\nexport function withFiles(files: DescriptiveRawFile[], options: APIInteractionResponseCallbackData) {\n\tconst body = {\n\t\t...options,\n\t\tattachments: files.map((file, index) => ({\n\t\t\tid: index.toString(),\n\t\t\tdescription: file.description,\n\t\t})),\n\t};\n\n\tconst outputFiles = files.map((file, index) => ({\n\t\tname: file.name ?? index.toString(),\n\t\tdata: file.data,\n\t}));\n\n\treturn { body, files: outputFiles };\n}\n"
  },
  {
    "path": "packages/core/src/util/index.ts",
    "content": "export * from './files.js';\n"
  },
  {
    "path": "packages/core/tsconfig.docs.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.docs.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist-docs\"\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/core/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/core/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/core/tsconfig.test.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"noEmit\": true,\n\t\t\"skipLibCheck\": true\n\t},\n\t\"include\": [\"__tests__/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/core/tsup.config.ts",
    "content": "import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector';\nimport { createTsupConfig } from '../../tsup.config.js';\n\nexport default [\n\tcreateTsupConfig({\n\t\tesbuildPlugins: [esbuildPluginVersionInjector()],\n\t}),\n\tcreateTsupConfig({\n\t\tentry: {\n\t\t\t'http-only': 'src/http-only/index.ts',\n\t\t},\n\t\tesbuildPlugins: [esbuildPluginVersionInjector()],\n\t}),\n];\n"
  },
  {
    "path": "packages/create-discord-bot/.cliff-jumperrc.json",
    "content": "{\n\t\"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n\t\"name\": \"create-discord-bot\",\n\t\"packagePath\": \"packages/create-discord-bot\",\n\t\"tagTemplate\": \"{{name}}@{{new-version}}\",\n\t\"identifierBase\": false,\n\t\"monoRepo\": true\n}\n"
  },
  {
    "path": "packages/create-discord-bot/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n!template/**/.env\n\n# Dist\ndist\n\n# Miscellaneous\n.tmp\n"
  },
  {
    "path": "packages/create-discord-bot/.lintstagedrc.cjs",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/create-discord-bot/.prettierignore",
    "content": "# Autogenerated\nCHANGELOG.md\n.turbo\ndist/\ndocs/**/*\n!docs/index.yml\n!docs/README.md\ncoverage/\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/create-discord-bot/.prettierrc.cjs",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/create-discord-bot/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n# [create-discord-bot@4.1.0](https://github.com/discordjs/discord.js/compare/create-discord-bot@4.0.0...create-discord-bot@4.1.0) - (2025-10-24)\n\n## Bug Fixes\n\n- **guide:** Miscellaneous fixes (#11147) ([a97ac82](https://github.com/discordjs/discord.js/commit/a97ac82619f0a807a7b816afa0140ba9161aa50d)) by @Jiralite\n\n## Documentation\n\n- Replace Discord API with Discord Developers (#10968) ([3a060f7](https://github.com/discordjs/discord.js/commit/3a060f74945da78535440890be0a5df8bd0ee36b)) by @Jiralite\n\n## Features\n\n- Bump discord.js in create-discord-bot/app (#11048) ([4b6060d](https://github.com/discordjs/discord.js/commit/4b6060dcd8fc7b3f065fd51fb0fa1a576ee4fca7)) by @vladfrangu\n\n## Refactor\n\n- Update deno template and loader logic (#11060) ([8ca279e](https://github.com/discordjs/discord.js/commit/8ca279e0c3764f4f059c5d3f895b2c76678859e1)) by @almeidx\n- **create-discord-bot:** Replace deps with built-in apis (#10971) ([ee3ca6f](https://github.com/discordjs/discord.js/commit/ee3ca6f7c629b169a976edf66b54b0dfe5c3a486)) by @SuperchupuDev\n\n### New Contributors\n\n* @didinele made their first contribution in #11152\n* @Jiralite made their first contribution in #11147\n* @almeidx made their first contribution in #11133\n* @vladfrangu made their first contribution in #11048\n* @SuperchupuDev made their first contribution in #10971\n\n# [create-discord-bot@4.0.0](https://github.com/discordjs/discord.js/compare/create-discord-bot@1.0.0...create-discord-bot@4.0.0) - (2025-06-21)\n\n## Bug Fixes\n\n- Structure imports on windows (#10835) ([5c0b714](https://github.com/discordjs/discord.js/commit/5c0b714557ce86d793145445ff5f103b6962ec11)) by @almeidx\n- **create-discord-bot:** Register command files in subdirectories (#10775) ([79b79b6](https://github.com/discordjs/discord.js/commit/79b79b6a44967d9ed1e449b49a851b417afb263b)) by @schrodienieur\n\n## Documentation\n\n- Guide setup (#10862) ([2184085](https://github.com/discordjs/discord.js/commit/2184085fdaf00c982130212eb27ab878df2c3e1e)) by @iCrawl\n- Fix close tags (#10756) ([5c49b6d](https://github.com/discordjs/discord.js/commit/5c49b6d9af9b0e69c4792ef4be831607675d418c)) by @Jiralite\n\n## Refactor\n\n- Remove `registerEvents` function (#10877) ([2c21de6](https://github.com/discordjs/discord.js/commit/2c21de68f3bd1faa52e14cc70aebc322cf4bdd56)) by @sdanialraza\n- **constants:** Update guide URL (#10803) ([eabcc52](https://github.com/discordjs/discord.js/commit/eabcc52594c2237666bbbbbc89c66d5e34ef29bb)) by @Jiralite\n\n## Build\n\n- Bump Node.js to 22.12.0 (#10726) ([3db8ce7](https://github.com/discordjs/discord.js/commit/3db8ce70a2d20bd2def70a2c839b015bc24195eb)) by @Jiralite\n  - **BREAKING CHANGE:** Node.js 22.12.0 or above is required.\n- Bumps the version of create-discord-bot and create-discord-app to `4.0.0` for consistency\n\n### New Contributors\n\n* @schrodienieur made their first contribution in #10775\n* @nsgpriyanshu made their first contribution in #10428\n\n# [create-discord-bot@1.0.0](https://github.com/discordjs/discord.js/compare/create-discord-bot@0.3.1...create-discord-bot@1.0.0) - (2025-01-01)\n\n## Features\n\n- Upgrade create-discord-bot dependencies (#10673) ([a111cdd](https://github.com/discordjs/discord.js/commit/a111cddcea13afa24cde7fc39f60a62abec539cf)) by @Jiralite\n\n### New Contributors\n\n* @Jiralite made their first contribution in #10673\n* @almeidx made their first contribution in #10671\n* @ckohen made their first contribution in #10471\n\n# [create-discord-bot@0.3.1](https://github.com/discordjs/discord.js/compare/create-discord-bot@0.3.0...create-discord-bot@0.3.1) - (2024-09-01)\n\n## Bug Fixes\n\n- Failed build in node and bad lints (#10444) ([00accf7](https://github.com/discordjs/discord.js/commit/00accf74708b4ce8a032907005ae81460b79a988))\n\n# [create-discord-bot@0.3.0](https://github.com/discordjs/discord.js/compare/create-discord-bot@0.2.3...create-discord-bot@0.3.0) - (2024-05-04)\n\n## Bug Fixes\n\n- **Bun:** Fix typo for Bun template (#9987) ([ce0be39](https://github.com/discordjs/discord.js/commit/ce0be392d818b13ba5a081811519b559202cdba8))\n\n## Features\n\n- Local and preview detection ([79fbda3](https://github.com/discordjs/discord.js/commit/79fbda3aac6d4f0f8bfb193e797d09cbe331d315))\n\n## Refactor\n\n- Docs (#10126) ([18cce83](https://github.com/discordjs/discord.js/commit/18cce83d80598c430218775c53441b6b2ecdc776))\n- Improve structure validation with zod (#10103) ([1d56544](https://github.com/discordjs/discord.js/commit/1d565443b0edc46d785f1993d743f683f19bcbb4))\n\n# [create-discord-bot@0.2.3](https://github.com/discordjs/discord.js/compare/create-discord-bot/0.2.2...create-discord-bot/0.2.3) - (2023-11-12)\n\n## Bug Fixes\n\n- Import picocolors as default (#9949) ([8a6045f](https://github.com/discordjs/discord.js/commit/8a6045f6003971dbf64c8576f08631751b982ae4))\n\n## Features\n\n- Bump package versions ([e8bd354](https://github.com/discordjs/discord.js/commit/e8bd35405239616b12cb5f09eb983f5251298aca))\n\n# [create-discord-bot@0.2.2](https://github.com/discordjs/discord.js/compare/create-discord-bot@0.2.1...create-discord-bot@0.2.2) - (2023-11-12)\n\n## Bug Fixes\n\n- Update module to `NodeNext` in tsconfig.json (#9875) ([f586283](https://github.com/discordjs/discord.js/commit/f58628385cf9df2afc5f543141ed76fbba74aa22))\n\n## Documentation\n\n- **create-discord-bot:** Support bun in create-discord-bot (#9798) ([7157748](https://github.com/discordjs/discord.js/commit/7157748fe3a69265896adf0450cd3f37acbcf97b))\n\n## Features\n\n- Add `no-install` option (#9604) ([8325fa6](https://github.com/discordjs/discord.js/commit/8325fa65409c157da3448da40669c92c636b3f14))\n- **create-discord-bot:** Bun/deno templates (#9795) ([dd5e745](https://github.com/discordjs/discord.js/commit/dd5e7453e89ae918b94de1c13ce53c7cfd373721))\n\n# [create-discord-bot@0.2.1](https://github.com/discordjs/discord.js/compare/create-discord-bot@0.2.0...create-discord-bot@0.2.1) - (2023-08-17)\n\n## Bug Fixes\n\n- **create-discord-bot:** Add shebang in main file (#9747) ([99194fc](https://github.com/discordjs/discord.js/commit/99194fc2703988693264ef4a7c2d7bb040c39fa8))\n\n# [create-discord-bot@0.2.0](https://github.com/discordjs/discord.js/compare/create-discord-bot@0.1.0...create-discord-bot@0.2.0) - (2023-07-31)\n\n## Bug Fixes\n\n- Resolve imports for Windows (#9546) ([b6162bc](https://github.com/discordjs/discord.js/commit/b6162bc5b582089a9405d29f6825d9748180f66a))\n- Non-existing data property (#9544) ([5b8d535](https://github.com/discordjs/discord.js/commit/5b8d535fd633ff25dd801f35e13b4cb169cc42ac))\n- **create-discord-bot:** Fix start script (#9542) ([8482e3c](https://github.com/discordjs/discord.js/commit/8482e3c95dd5ca086805e756afdcf787e3fea1f9))\n\n## Documentation\n\n- Add Cloudflare sponsorship in `create-discord-bot` readme (#9540) ([12482b7](https://github.com/discordjs/discord.js/commit/12482b70ed4bfadf26720f9b2ed9d7bf7ccc39b8))\n\n## Features\n\n- **create-discord-bot:** Throw error if the directory is a file (#9719) ([351a18b](https://github.com/discordjs/discord.js/commit/351a18bc35da7765d281e419b646ef734a315bdf))\n- **create-discord-bot:** Add prompts, command handler and deployment script (#9570) ([84f1b18](https://github.com/discordjs/discord.js/commit/84f1b1890de5add805bef1a030b0ade3c6aca213))\n- Check for empty directory (#9539) ([64324a8](https://github.com/discordjs/discord.js/commit/64324a8be13dc2b766636a1042ae13d3d52a5c79))\n- **create-discord-bot:** Inherit stdio when installing deps (#9543) ([c4a3120](https://github.com/discordjs/discord.js/commit/c4a3120354ea3930e010ba011216e42311e29cdb))\n\n# [create-discord-bot@0.1.0](https://github.com/discordjs/discord.js/tree/create-discord-bot@0.1.0) - (2023-05-07)\n\n## Features\n\n- Create-discord-bot (#9420) ([f83a8a5](https://github.com/discordjs/discord.js/commit/f83a8a58c99532131848f9d89cec58ae5cd5d138))\n"
  },
  {
    "path": "packages/create-discord-bot/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2023 Noel Buechler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/create-discord-bot/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/commits/main/packages/create-discord-bot\"><img alt=\"Last commit.\" src=\"https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fcreate-discord-bot\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## About\n\nIt's easy to create a simple Discord bot to begin your journey with the Discord API.\n\n```sh\nnpm create discord-bot ./your/chosen/directory\nyarn create discord-bot ./your/chosen/directory\npnpm create discord-bot ./your/chosen/directory\nbun create discord-bot ./your/chosen/directory\n```\n\n## Links\n\n- [Guide] ([source][guide-source])\n  - Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested.  \nSee [the contribution guide][contributing] if you'd like to submit a pull request.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js server][discord].\n\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/create-discord-bot\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/create-discord-bot/api-extractor.json",
    "content": "{\n\t\"extends\": \"../../api-extractor.json\",\n\t\"docModel\": {\n\t\t\"projectFolderUrl\": \"https://github.com/discordjs/discord.js/tree/main/packages/create-discord-bot\"\n\t}\n}\n"
  },
  {
    "path": "packages/create-discord-bot/bin/index.ts",
    "content": "#!/usr/bin/env node\n\nimport process from 'node:process';\nimport { styleText } from 'node:util';\nimport { Option, program } from 'commander';\nimport prompts from 'prompts';\nimport validateProjectName from 'validate-npm-package-name';\nimport packageJSON from '../package.json' with { type: 'json' };\nimport { createDiscordBot } from '../src/create-discord-bot.js';\nimport { resolvePackageManager } from '../src/helpers/packageManager.js';\nimport { DEFAULT_PROJECT_NAME, PACKAGE_MANAGERS } from '../src/util/constants.js';\n\nlet projectDirectory = '';\n\nconst handleSigTerm = () => process.exit(0);\n\nprocess.on('SIGINT', handleSigTerm);\nprocess.on('SIGTERM', handleSigTerm);\n\n// https://github.com/vercel/next.js/blob/canary/packages/create-next-app/index.ts#L24-L32\nconst onPromptState = (state: any) => {\n\tif (state.aborted) {\n\t\t// If we don't re-enable the terminal cursor before exiting\n\t\t// the program, the cursor will remain hidden\n\t\tprocess.stdout.write('\\u001B[?25h');\n\t\tprocess.stdout.write('\\n');\n\t\tprocess.exit(1);\n\t}\n};\n\nprogram\n\t.name(packageJSON.name)\n\t.version(packageJSON.version)\n\t.description('Create a basic discord.js bot.')\n\t.argument('[directory]', 'What is the name of the directory you want to create this project in?')\n\t.usage(`${styleText('green', '<directory>')}`)\n\t.action((directory) => {\n\t\tprojectDirectory = directory;\n\t})\n\t.option('--typescript', 'Whether to use the TypeScript template.')\n\t.option('--javascript', 'Whether to use the JavaScript template.')\n\t.option('--no-install', 'Whether to not automatically install the packages.')\n\t.addOption(\n\t\tnew Option('--package-manager <packageManager>', 'The package manager to use.')\n\t\t\t.choices(PACKAGE_MANAGERS)\n\t\t\t.default(resolvePackageManager()),\n\t)\n\t.allowUnknownOption()\n\t.parse();\n\n// eslint-disable-next-line prefer-const\nlet { typescript, javascript, packageManager, install: installPackages } = program.opts();\n\nif (!projectDirectory) {\n\tprojectDirectory = (\n\t\tawait prompts({\n\t\t\tonState: onPromptState,\n\t\t\ttype: 'text',\n\t\t\tname: 'directory',\n\t\t\tinitial: DEFAULT_PROJECT_NAME,\n\t\t\tmessage: 'What is the name of the directory you want to create this project in?',\n\t\t\tvalidate: (directory) => {\n\t\t\t\t// We'll use the directory name as the project name. Check npm name validity.\n\t\t\t\tconst validationResult = validateProjectName(directory);\n\n\t\t\t\tif (!validationResult.validForNewPackages) {\n\t\t\t\t\tconst errors = [];\n\n\t\t\t\t\tfor (const error of [...(validationResult.errors ?? []), ...(validationResult.warnings ?? [])]) {\n\t\t\t\t\t\terrors.push(styleText('red', `- ${error}`));\n\t\t\t\t\t}\n\n\t\t\t\t\treturn styleText(\n\t\t\t\t\t\t'red',\n\t\t\t\t\t\t`Cannot create a project named ${styleText(\n\t\t\t\t\t\t\t'yellow',\n\t\t\t\t\t\t\t`\"${directory}\"`,\n\t\t\t\t\t\t)} due to npm naming restrictions.\\n\\nErrors:\\n${errors.join('\\n')}\\n\\n${styleText(\n\t\t\t\t\t\t\t'red',\n\t\t\t\t\t\t\t'\\nSee https://docs.npmjs.com/cli/configuring-npm/package-json for more details.',\n\t\t\t\t\t\t)}}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t},\n\t\t})\n\t).directory;\n}\n\nconst deno = packageManager === 'deno';\nif (!deno && typescript === undefined && javascript === undefined) {\n\tconst { useTypescript } = await prompts({\n\t\tonState: onPromptState,\n\t\ttype: 'toggle',\n\t\tname: 'useTypescript',\n\t\tmessage: 'Do you want to use TypeScript?',\n\t\tinitial: true,\n\t\tactive: 'Yes',\n\t\tinactive: 'No',\n\t});\n\n\ttypescript = useTypescript;\n}\n\nawait createDiscordBot({\n\ttypescript,\n\tdirectory: projectDirectory,\n\tpackageManager,\n\tinstallPackages,\n});\n"
  },
  {
    "path": "packages/create-discord-bot/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t\t{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length %}\\\n\t\\n### New Contributors\\n\n\t{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\\\n\t\t* @{{ contributor.username }} made their first contribution in #{{ contributor.pr_number }}\n\t{% endfor %}\\\n{% endif %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"create-discord-bot@[0-9]*\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/create-discord-bot/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"create-discord-bot\",\n\t\"version\": \"4.1.0\",\n\t\"description\": \"A simple way to create a startup Discord bot.\",\n\t\"scripts\": {\n\t\t\"build\": \"tsc --noEmit && tsup\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src\",\n\t\t\"prepack\": \"pnpm run build && pnpm run lint\",\n\t\t\"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/create-discord-bot/*'\",\n\t\t\"release\": \"cliff-jumper\",\n\t\t\"rename-to-app\": \"node scripts/rename-to-app.mjs\"\n\t},\n\t\"type\": \"module\",\n\t\"bin\": \"./dist/index.js\",\n\t\"directories\": {\n\t\t\"bin\": \"bin\",\n\t\t\"lib\": \"src\"\n\t},\n\t\"files\": [\n\t\t\"dist\",\n\t\t\"template\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\",\n\t\t\"Jiralite <me@jiralite.dev>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"discord\",\n\t\t\"discord-api\",\n\t\t\"discord.js\",\n\t\t\"create-bot\",\n\t\t\"init-bot\",\n\t\t\"init-discord\",\n\t\t\"boilerplate\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"git+https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/create-discord-bot\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"commander\": \"^14.0.3\",\n\t\t\"prompts\": \"^2.4.2\",\n\t\t\"validate-npm-package-name\": \"^7.0.2\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@discordjs/api-extractor\": \"workspace:^\",\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@types/node\": \"^22.19.11\",\n\t\t\"@types/prompts\": \"^2.4.9\",\n\t\t\"@types/validate-npm-package-name\": \"^4.0.2\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"terser\": \"^5.46.0\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"typescript\": \"~5.9.3\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/create-discord-bot/scripts/rename-to-app.mjs",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nconst pkgJsonPath = new URL('../package.json', import.meta.url);\nconst pkgJson = JSON.parse(await readFile(pkgJsonPath, 'utf8'));\n\npkgJson.name = 'create-discord-app';\n\nawait writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, '\\t') + '\\n');\n\nconst readmePath = new URL('../README.md', import.meta.url);\nconst readme = await readFile(readmePath, 'utf8');\n\nawait writeFile(readmePath, readme.replaceAll('create discord-bot', 'create discord-app'));\n"
  },
  {
    "path": "packages/create-discord-bot/src/create-discord-bot.ts",
    "content": "import type { ExecException } from 'node:child_process';\nimport { cp, mkdir, stat, readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport process from 'node:process';\nimport { styleText } from 'node:util';\nimport type { PackageManager } from './helpers/packageManager.js';\nimport { install } from './helpers/packageManager.js';\nimport { GUIDE_URL } from './util/constants.js';\nimport { isFolderEmpty } from './util/isFolderEmpty.js';\n\ninterface Options {\n\tdirectory: string;\n\tinstallPackages: boolean;\n\tpackageManager: PackageManager;\n\ttypescript?: boolean;\n}\n\nexport async function createDiscordBot({ directory, installPackages, typescript, packageManager }: Options) {\n\tconst root = path.resolve(directory);\n\tconst directoryName = path.basename(root);\n\n\tconsole.log();\n\n\tconst directoryStats = await stat(root).catch(async (error) => {\n\t\t// Create a new directory if the specified one does not exist.\n\t\tif (error.code === 'ENOENT') {\n\t\t\tawait mkdir(root, { recursive: true });\n\t\t\treturn stat(root);\n\t\t}\n\n\t\tthrow error;\n\t});\n\n\t// If the directory is actually a file or if it's not empty, throw an error.\n\tif (!directoryStats.isDirectory() || !isFolderEmpty(root, directoryName)) {\n\t\tconsole.error(\n\t\t\tstyleText(\n\t\t\t\t'red',\n\t\t\t\t`The directory ${styleText('yellow', `\"${directoryName}\"`)} is either not a directory or is not empty.`,\n\t\t\t),\n\t\t);\n\t\tconsole.error(styleText('red', `Please specify an empty directory.`));\n\t\tprocess.exit(1);\n\t}\n\n\tconsole.log(`Creating ${directoryName} in ${styleText('green', root)}.`);\n\n\tconst deno = packageManager === 'deno';\n\tconst bun = packageManager === 'bun';\n\n\tconst lang = typescript ? 'TypeScript' : 'JavaScript';\n\tconst templateBasePath = deno ? 'Deno' : bun ? `Bun/${lang}` : lang;\n\n\tawait cp(new URL(`../template/${templateBasePath}`, import.meta.url), root, {\n\t\trecursive: true,\n\t});\n\n\tprocess.chdir(root);\n\n\tconst newVSCodeSettings = await readFile('./.vscode/settings.json', { encoding: 'utf8' });\n\tawait writeFile(\n\t\t'./.vscode/settings.json',\n\t\tnewVSCodeSettings.replace(\n\t\t\t/\"npm\\.packageManager\":\\s*\"[^\"]+\"/,\n\t\t\t`\"npm.packageManager\": \"${deno || bun ? 'auto' : packageManager}\"`,\n\t\t),\n\t);\n\n\tif (!deno) {\n\t\tconst newPackageJSON = await readFile('./package.json', { encoding: 'utf8' });\n\t\tawait writeFile('./package.json', newPackageJSON.replace(/\"name\":\\s*\"[^\"]+\"/, `\"name\": \"${directoryName}\"`));\n\t}\n\n\tif (installPackages) {\n\t\ttry {\n\t\t\tinstall(packageManager);\n\t\t} catch (error) {\n\t\t\tconsole.log();\n\t\t\tconst err = error as ExecException;\n\t\t\tif (err.signal === 'SIGINT') {\n\t\t\t\tconsole.log(styleText('red', 'Installation aborted.'));\n\t\t\t} else {\n\t\t\t\tconsole.error(styleText('red', 'Installation failed.'));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t}\n\t}\n\n\tconsole.log();\n\tconsole.log(styleText('green', 'All done! Be sure to read through the discord.js guide for help on your journey.'));\n\tconsole.log(`Link: ${styleText('cyan', GUIDE_URL)}`);\n}\n"
  },
  {
    "path": "packages/create-discord-bot/src/helpers/packageManager.ts",
    "content": "import { execSync } from 'node:child_process';\nimport process from 'node:process';\nimport { styleText } from 'node:util';\nimport { DEFAULT_PACKAGE_MANAGER, type PACKAGE_MANAGERS } from '../util/constants.js';\n\n/**\n * A union of supported package managers.\n */\nexport type PackageManager = (typeof PACKAGE_MANAGERS)[number];\n\n/**\n * Resolves the package manager from `npm_config_user_agent`.\n */\nexport function resolvePackageManager(): PackageManager {\n\tconst npmConfigUserAgent = process.env.npm_config_user_agent;\n\n\t// @ts-expect-error: We're not using Deno's types, so its global is not declared\n\tif (typeof Deno !== 'undefined') {\n\t\treturn 'deno';\n\t}\n\n\tif (process.versions.bun) {\n\t\treturn 'bun';\n\t}\n\n\t// If this is not present, return the default package manager.\n\tif (!npmConfigUserAgent) {\n\t\treturn DEFAULT_PACKAGE_MANAGER;\n\t}\n\n\tif (npmConfigUserAgent.startsWith('npm')) {\n\t\treturn 'npm';\n\t}\n\n\tif (npmConfigUserAgent.startsWith('yarn')) {\n\t\treturn 'yarn';\n\t}\n\n\tif (npmConfigUserAgent.startsWith('pnpm')) {\n\t\treturn 'pnpm';\n\t}\n\n\tif (npmConfigUserAgent.startsWith('bun')) {\n\t\treturn 'bun';\n\t}\n\n\tconsole.error(\n\t\tstyleText(\n\t\t\t'yellow',\n\t\t\t`Detected an unsupported package manager (${npmConfigUserAgent}). Falling back to ${DEFAULT_PACKAGE_MANAGER}.`,\n\t\t),\n\t);\n\n\t// Fallback to the default package manager.\n\treturn DEFAULT_PACKAGE_MANAGER;\n}\n\n/**\n * Installs with a provided package manager.\n *\n * @param packageManager - The package manager to use\n */\nexport function install(packageManager: PackageManager) {\n\tlet installCommand: string[] | string = `${packageManager} install`;\n\n\tconsole.log(`Installing dependencies with ${packageManager}...`);\n\n\t// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check\n\tswitch (packageManager) {\n\t\tcase 'yarn':\n\t\t\tconsole.log();\n\t\t\tinstallCommand = [\n\t\t\t\t`${packageManager} set version stable`,\n\t\t\t\t`${packageManager} config set nodeLinker node-modules`,\n\t\t\t\t`${packageManager} config set logFilters --json '[{ \"code\": \"YN0002\", \"level\": \"discard\" }, { \"code\": \"YN0013\", \"level\": \"discard\" }, { \"code\": \"YN0032\", \"level\": \"discard\" }, { \"code\": \"YN0060\", \"level\": \"discard\" }]'`,\n\t\t\t\t`${packageManager} plugin import interactive-tools`,\n\t\t\t\t`${packageManager} plugin import workspace-tools`,\n\t\t\t\tinstallCommand,\n\t\t\t];\n\t\t\tbreak;\n\t\tcase 'deno':\n\t\t\tinstallCommand = `${packageManager} cache --reload src/index.ts`;\n\t\t\tbreak;\n\t\tcase 'pnpm':\n\t\tcase 'bun':\n\t\t\tconsole.log();\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\n\tconst env = {\n\t\t...process.env,\n\t\tADBLOCK: '1',\n\t\tNODE_ENV: 'development',\n\t\tDISABLE_OPENCOLLECTIVE: '1',\n\t};\n\n\tif (Array.isArray(installCommand)) {\n\t\tfor (const [index, command] of installCommand.entries()) {\n\t\t\tif (index === installCommand.length - 1) {\n\t\t\t\texecSync(command, {\n\t\t\t\t\tstdio: 'inherit',\n\t\t\t\t\tenv,\n\t\t\t\t});\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\texecSync(command, {\n\t\t\t\tstdio: 'ignore',\n\t\t\t\tenv,\n\t\t\t});\n\t\t}\n\n\t\treturn;\n\t}\n\n\texecSync(installCommand, {\n\t\tstdio: 'inherit',\n\t\tenv,\n\t});\n}\n"
  },
  {
    "path": "packages/create-discord-bot/src/util/constants.ts",
    "content": "/**\n * The default package manager.\n */\nexport const DEFAULT_PACKAGE_MANAGER = 'npm' as const;\n\n/**\n * The default project name.\n */\nexport const DEFAULT_PROJECT_NAME = 'my-bot' as const;\n\n/**\n * The supported package managers.\n */\nexport const PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun', 'deno'] as const;\n\n/**\n * The URL to the guide.\n */\nexport const GUIDE_URL = 'https://discordjs.guide' as const;\n"
  },
  {
    "path": "packages/create-discord-bot/src/util/isFolderEmpty.ts",
    "content": "/**\n * @license MIT\n *\n * Copyright (c) 2025 Vercel, Inc.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation\n * files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy,\n * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE\n * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * Source: https://github.com/vercel/next.js/blob/7fb2aa908216fb3a910c7fa6d24524412b5af6e5/packages/create-next-app/helpers/is-folder-empty.ts\n */\nimport { lstatSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { styleText } from 'node:util';\n\nexport function isFolderEmpty(root: string, name: string): boolean {\n\tconst validFiles = [\n\t\t'.DS_Store',\n\t\t'.git',\n\t\t'.gitattributes',\n\t\t'.gitignore',\n\t\t'.gitlab-ci.yml',\n\t\t'.hg',\n\t\t'.hgcheck',\n\t\t'.hgignore',\n\t\t'.idea',\n\t\t'.npmignore',\n\t\t'.travis.yml',\n\t\t'LICENSE',\n\t\t'Thumbs.db',\n\t\t'docs',\n\t\t'mkdocs.yml',\n\t\t'npm-debug.log',\n\t\t'yarn-debug.log',\n\t\t'yarn-error.log',\n\t\t'yarnrc.yml',\n\t\t'.yarn',\n\t];\n\n\tconst conflicts = readdirSync(root).filter(\n\t\t(file) =>\n\t\t\t!validFiles.includes(file) &&\n\t\t\t// Support IntelliJ IDEA-based editors\n\t\t\t!file.endsWith('.iml'),\n\t);\n\n\tif (conflicts.length > 0) {\n\t\tconsole.log(`The directory ${styleText('green', name)} contains files that could conflict:`);\n\t\tconsole.log();\n\t\tfor (const file of conflicts) {\n\t\t\ttry {\n\t\t\t\tconst stats = lstatSync(join(root, file));\n\t\t\t\tif (stats.isDirectory()) {\n\t\t\t\t\tconsole.log(`  ${styleText('blue', file)}/`);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log(`  ${file}`);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tconsole.log(`  ${file}`);\n\t\t\t}\n\t\t}\n\n\t\tconsole.log();\n\t\tconsole.log('Either try using a new directory name, or remove the files listed above.');\n\t\tconsole.log();\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/JavaScript/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional stylelint cache\n.stylelintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variable files\n.env\n.env.*\n!.env.example\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n.output\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n.temp\n.cache\n\n# Sveltekit cache directory\n.svelte-kit/\n\n# vitepress build output\n**/.vitepress/dist\n\n# vitepress cache directory\n**/.vitepress/cache\n\n# Docusaurus cache and generated files\n.docusaurus\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# Firebase cache directory\n.firebase/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# yarn v3\n.pnp.*\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n\n# Vite files\nvite.config.js.timestamp-*\nvite.config.ts.timestamp-*\n.vite/\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/JavaScript/.prettierrc.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/prettierrc.json\",\n\t\"printWidth\": 120,\n\t\"useTabs\": true,\n\t\"singleQuote\": true,\n\t\"quoteProps\": \"as-needed\",\n\t\"trailingComma\": \"all\",\n\t\"endOfLine\": \"lf\"\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/JavaScript/.vscode/extensions.json",
    "content": "{\n\t\"recommendations\": [\n\t\t\"esbenp.prettier-vscode\",\n\t\t\"dbaeumer.vscode-eslint\",\n\t\t\"codezombiech.gitignore\",\n\t\t\"christian-kohler.npm-intellisense\",\n\t\t\"christian-kohler.path-intellisense\",\n\t\t\"oven.bun-vscode\"\n\t]\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/JavaScript/.vscode/settings.json",
    "content": "{\n\t\"eslint.validate\": [\"javascript\", \"javascriptreact\", \"typescript\", \"typescriptreact\"],\n\t\"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n\t\"editor.formatOnSave\": true,\n\t\"editor.codeActionsOnSave\": {\n\t\t\"source.fixAll\": \"explicit\",\n\t\t\"source.organizeImports\": \"never\"\n\t},\n\t\"editor.trimAutoWhitespace\": false,\n\t\"files.insertFinalNewline\": true,\n\t\"files.eol\": \"\\n\",\n\t\"npm.packageManager\": \"bun\"\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/JavaScript/eslint.config.js",
    "content": "import common from 'eslint-config-neon/common';\nimport node from 'eslint-config-neon/node';\nimport prettier from 'eslint-config-neon/prettier';\n\nconst config = [\n\t{\n\t\tignores: [],\n\t},\n\t...common,\n\t...node,\n\t...prettier,\n\t{\n\t\tlanguageOptions: {\n\t\t\tglobals: {\n\t\t\t\tBun: 'readonly',\n\t\t\t},\n\t\t},\n\t\trules: {\n\t\t\t'no-restricted-globals': 0,\n\t\t\t'n/prefer-global/buffer': [2, 'never'],\n\t\t\t'n/prefer-global/console': [2, 'always'],\n\t\t\t'n/prefer-global/process': [2, 'never'],\n\t\t\t'n/prefer-global/text-decoder': [2, 'always'],\n\t\t\t'n/prefer-global/text-encoder': [2, 'always'],\n\t\t\t'n/prefer-global/url-search-params': [2, 'always'],\n\t\t\t'n/prefer-global/url': [2, 'always'],\n\t\t\t'jsdoc/check-tag-names': 0,\n\t\t\t'jsdoc/no-undefined-types': 0,\n\t\t\t'jsdoc/valid-types': 0,\n\t\t},\n\t},\n];\n\nexport default config;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/JavaScript/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/template-bun-javascript\",\n\t\"version\": \"0.1.0\",\n\t\"private\": true,\n\t\"type\": \"module\",\n\t\"scripts\": {\n\t\t\"lint\": \"prettier --check . && eslint --ext .js,.mjs,.cjs --format=pretty src\",\n\t\t\"deploy\": \"bun --env-file=.env src/util/deploy.js\",\n\t\t\"format\": \"prettier --write . && eslint --ext .js,.mjs,.cjs --fix --format=pretty src\",\n\t\t\"start\": \"bun --env-file=.env src/index.js\"\n\t},\n\t\"dependencies\": {\n\t\t\"@discordjs/core\": \"^2.4.0\",\n\t\t\"discord.js\": \"^14.25.1\"\n\t},\n\t\"devDependencies\": {\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"zod\": \"^4.3.6\"\n\t}\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/JavaScript/src/commands/index.js",
    "content": "import { z } from 'zod';\n\n/**\n * Defines the structure of a command.\n *\n * @typedef {object} Command\n * @property {import('discord.js').RESTPostAPIApplicationCommandsJSONBody} data The data for the command\n * @property {(interaction: import('discord.js').CommandInteraction) => Promise<void> | void} execute The function to execute when the command is called\n */\n\n/**\n * Defines the schema for a command\n */\nexport const schema = z.object({\n\tdata: z.record(z.string(), z.any()),\n\texecute: z.function(),\n});\n\n/**\n * Defines the predicate to check if an object is a valid Command type.\n *\n * @type {import('../util/loaders.js').StructurePredicate<Command>}\n * @returns {structure is Command}\n */\nexport const predicate = (structure) => schema.safeParse(structure).success;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/JavaScript/src/commands/ping.js",
    "content": "/** @type {import('./index.js').Command} */\nexport default {\n\tdata: {\n\t\tname: 'ping',\n\t\tdescription: 'Ping!',\n\t},\n\tasync execute(interaction) {\n\t\tawait interaction.reply('Pong!');\n\t},\n};\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/JavaScript/src/commands/utility/user.js",
    "content": "/** @type {import('../index.js').Command} */\nexport default {\n\tdata: {\n\t\tname: 'user',\n\t\tdescription: 'Provides information about the user.',\n\t},\n\tasync execute(interaction) {\n\t\tawait interaction.reply(`This command was run by ${interaction.user.username}.`);\n\t},\n};\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/JavaScript/src/events/index.js",
    "content": "import { z } from 'zod';\n\n/**\n * Defines the structure of an event.\n *\n * @template {keyof import('discord.js').ClientEvents} [EventName=keyof import('discord.js').ClientEvents]\n * @typedef {object} Event\n * @property {(...parameters: import('discord.js').ClientEvents[EventName]) => Promise<void> | void} execute The function to execute the command\n * @property {EventName} name The name of the event to listen to\n * @property {boolean} [once] Whether or not the event should only be listened to once\n */\n\n/**\n * Defines the schema for an event.\n *\n */\nexport const schema = z.object({\n\tname: z.string(),\n\tonce: z.boolean().optional().default(false),\n\texecute: z.function(),\n});\n\n/**\n * Defines the predicate to check if an object is a valid Event type.\n *\n * @type {import('../util/loaders.js').StructurePredicate<Event>}\n * @returns {structure is Event}\n */\nexport const predicate = (structure) => schema.safeParse(structure).success;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/JavaScript/src/events/interactionCreate.js",
    "content": "import { Events } from 'discord.js';\nimport { loadCommands } from '../util/loaders.js';\n\nconst commands = await loadCommands(new URL('../commands/', import.meta.url));\n\n/** @type {import('../events/index.js').Event<Events.InteractionCreate>} */\nexport default {\n\tname: Events.InteractionCreate,\n\tasync execute(interaction) {\n\t\tif (interaction.isCommand()) {\n\t\t\tconst command = commands.get(interaction.commandName);\n\n\t\t\tif (!command) {\n\t\t\t\tthrow new Error(`Command '${interaction.commandName}' not found.`);\n\t\t\t}\n\n\t\t\tawait command.execute(interaction);\n\t\t}\n\t},\n};\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/JavaScript/src/events/ready.js",
    "content": "import { Events } from 'discord.js';\n\n/** @type {import('./index.js').Event<Events.ClientReady>} */\nexport default {\n\tname: Events.ClientReady,\n\tonce: true,\n\tasync execute(client) {\n\t\tconsole.log(`Ready! Logged in as ${client.user.tag}`);\n\t},\n};\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/JavaScript/src/index.js",
    "content": "import { Client, GatewayIntentBits } from 'discord.js';\nimport { loadEvents } from './util/loaders.js';\n\n// Initialize the client\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\n// Load the events and commands\nconst events = await loadEvents(new URL('events/', import.meta.url));\n\n// Register the event handlers\nfor (const event of events) {\n\tclient[event.once ? 'once' : 'on'](event.name, async (...args) => {\n\t\ttry {\n\t\t\tawait event.execute(...args);\n\t\t} catch (error) {\n\t\t\tconsole.error(`Error executing event ${String(event.name)}:`, error);\n\t\t}\n\t});\n}\n\n// Login to the client\nvoid client.login(Bun.env.DISCORD_TOKEN);\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/JavaScript/src/util/deploy.js",
    "content": "import { API } from '@discordjs/core/http-only';\nimport { REST } from 'discord.js';\nimport { loadCommands } from './loaders.js';\n\nconst commands = await loadCommands(new URL('../commands/', import.meta.url));\nconst commandData = [...commands.values()].map((command) => command.data);\n\nconst rest = new REST({ version: '10' }).setToken(Bun.env.DISCORD_TOKEN);\nconst api = new API(rest);\n\nconst result = await api.applicationCommands.bulkOverwriteGlobalCommands(Bun.env.APPLICATION_ID, commandData);\n\nconsole.log(`Successfully registered ${result.length} commands.`);\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/JavaScript/src/util/loaders.js",
    "content": "import { stat } from 'node:fs/promises';\nimport { basename, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { Glob } from 'bun';\nimport { predicate as commandPredicate } from '../commands/index.js';\nimport { predicate as eventPredicate } from '../events/index.js';\n\n/**\n * A predicate to check if the structure is valid.\n *\n * @template Structure\n * @typedef {(structure: unknown) => structure is Structure} StructurePredicate\n */\n\n/**\n * Loads all the structures in the provided directory.\n *\n * @template Structure\n * @param {import('node:fs').PathLike} dir - The directory to load the structures from\n * @param {StructurePredicate<Structure>} predicate - The predicate to check if the structure is valid\n * @param {boolean} recursive - Whether to recursively load the structures in the directory\n * @returns {Promise<Structure[]>}\n */\nexport async function loadStructures(dir, predicate, recursive = true) {\n\t// Get the stats of the directory\n\tconst statDir = await stat(dir);\n\n\t// If the provided directory path is not a directory, throw an error\n\tif (!statDir.isDirectory()) {\n\t\tthrow new Error(`The directory '${dir}' is not a directory.`);\n\t}\n\n\t// Create an empty array to store the structures\n\t/** @type {Structure[]} */\n\tconst structures = [];\n\n\t// Create a glob pattern to match the .js files\n\tconst basePath = dir instanceof URL ? fileURLToPath(dir) : dir.toString();\n\tconst pattern = resolve(basePath, recursive ? '**/*.js' : '*.js');\n\tconst glob = new Glob(pattern);\n\n\t// Loop through all the matching files in the directory\n\tfor await (const file of glob.scan('.')) {\n\t\t// If the file is index.js, skip the file\n\t\tif (basename(file) === 'index.js') {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Import the structure dynamically from the file\n\t\tconst { default: structure } = await import(file);\n\n\t\t// If the default export is a valid structure, add it\n\t\tif (predicate(structure)) {\n\t\t\tstructures.push(structure);\n\t\t}\n\t}\n\n\treturn structures;\n}\n\n/**\n * @param {import('node:fs').PathLike} dir\n * @param {boolean} [recursive]\n * @returns {Promise<Map<string, import('../commands/index.js').Command>>}\n */\nexport async function loadCommands(dir, recursive = true) {\n\treturn (await loadStructures(dir, commandPredicate, recursive)).reduce(\n\t\t(acc, cur) => acc.set(cur.data.name, cur),\n\t\tnew Map(),\n\t);\n}\n\n/**\n * @param {import('node:fs').PathLike} dir\n * @param {boolean} [recursive]\n * @returns {Promise<import('../events/index.js').Event[]>}\n */\nexport async function loadEvents(dir, recursive = true) {\n\treturn loadStructures(dir, eventPredicate, recursive);\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional stylelint cache\n.stylelintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variable files\n.env\n.env.*\n!.env.example\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n.output\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n.temp\n.cache\n\n# Sveltekit cache directory\n.svelte-kit/\n\n# vitepress build output\n**/.vitepress/dist\n\n# vitepress cache directory\n**/.vitepress/cache\n\n# Docusaurus cache and generated files\n.docusaurus\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# Firebase cache directory\n.firebase/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# yarn v3\n.pnp.*\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n\n# Vite files\nvite.config.js.timestamp-*\nvite.config.ts.timestamp-*\n.vite/\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/.prettierrc.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/prettierrc.json\",\n\t\"printWidth\": 120,\n\t\"useTabs\": true,\n\t\"singleQuote\": true,\n\t\"quoteProps\": \"as-needed\",\n\t\"trailingComma\": \"all\",\n\t\"endOfLine\": \"lf\"\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/.vscode/extensions.json",
    "content": "{\n\t\"recommendations\": [\n\t\t\"esbenp.prettier-vscode\",\n\t\t\"dbaeumer.vscode-eslint\",\n\t\t\"codezombiech.gitignore\",\n\t\t\"christian-kohler.npm-intellisense\",\n\t\t\"christian-kohler.path-intellisense\",\n\t\t\"oven.bun-vscode\"\n\t]\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/.vscode/settings.json",
    "content": "{\n\t\"eslint.validate\": [\"javascript\", \"javascriptreact\", \"typescript\", \"typescriptreact\"],\n\t\"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n\t\"editor.formatOnSave\": true,\n\t\"editor.codeActionsOnSave\": {\n\t\t\"source.fixAll\": \"explicit\",\n\t\t\"source.organizeImports\": \"never\"\n\t},\n\t\"editor.trimAutoWhitespace\": false,\n\t\"files.insertFinalNewline\": true,\n\t\"files.eol\": \"\\n\",\n\t\"npm.packageManager\": \"bun\"\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/eslint.config.js",
    "content": "import common from 'eslint-config-neon/common';\nimport node from 'eslint-config-neon/node';\nimport prettier from 'eslint-config-neon/prettier';\nimport typescript from 'eslint-config-neon/typescript';\n\nconst config = [\n\t{\n\t\tignores: [],\n\t},\n\t...common,\n\t...node,\n\t...typescript,\n\t...prettier,\n\t{\n\t\tlanguageOptions: {\n\t\t\tparserOptions: {\n\t\t\t\tproject: ['./tsconfig.eslint.json'],\n\t\t\t},\n\t\t},\n\t\trules: {\n\t\t\t'no-restricted-globals': 0,\n\t\t\t'n/prefer-global/buffer': [2, 'never'],\n\t\t\t'n/prefer-global/console': [2, 'always'],\n\t\t\t'n/prefer-global/process': [2, 'never'],\n\t\t\t'n/prefer-global/text-decoder': [2, 'always'],\n\t\t\t'n/prefer-global/text-encoder': [2, 'always'],\n\t\t\t'n/prefer-global/url-search-params': [2, 'always'],\n\t\t\t'n/prefer-global/url': [2, 'always'],\n\t\t\t'import/extensions': 0,\n\t\t},\n\t},\n];\n\nexport default config;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/template-bun-typescript\",\n\t\"version\": \"0.1.0\",\n\t\"private\": true,\n\t\"type\": \"module\",\n\t\"scripts\": {\n\t\t\"lint\": \"tsc && prettier --check . && eslint --ext .ts --format=pretty src\",\n\t\t\"deploy\": \"bun --env-file=.env src/util/deploy.ts\",\n\t\t\"format\": \"prettier --write . && eslint --ext .ts --fix --format=pretty src\",\n\t\t\"start\": \"bun --env-file=.env src/index.ts\"\n\t},\n\t\"dependencies\": {\n\t\t\"@discordjs/core\": \"^2.4.0\",\n\t\t\"discord.js\": \"^14.25.1\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@sapphire/ts-config\": \"^5.0.3\",\n\t\t\"@types/bun\": \"^1.3.9\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"zod\": \"^4.3.6\"\n\t}\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/src/commands/index.ts",
    "content": "import type { RESTPostAPIApplicationCommandsJSONBody, CommandInteraction } from 'discord.js';\nimport { z } from 'zod';\nimport type { StructurePredicate } from '../util/loaders.ts';\n\n/**\n * Defines the structure of a command\n */\nexport type Command = {\n\t/**\n\t * The data for the command\n\t */\n\tdata: RESTPostAPIApplicationCommandsJSONBody;\n\t/**\n\t * The function to execute when the command is called\n\t *\n\t * @param interaction - The interaction of the command\n\t */\n\texecute(interaction: CommandInteraction): Promise<void> | void;\n};\n\n/**\n * Defines the schema for a command\n */\nexport const schema = z.object({\n\tdata: z.record(z.string(), z.any()),\n\texecute: z.function(),\n});\n\n/**\n * Defines the predicate to check if an object is a valid Command type.\n */\nexport const predicate: StructurePredicate<Command> = (structure: unknown): structure is Command =>\n\tschema.safeParse(structure).success;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/src/commands/ping.ts",
    "content": "import type { Command } from './index.ts';\n\nexport default {\n\tdata: {\n\t\tname: 'ping',\n\t\tdescription: 'Ping!',\n\t},\n\tasync execute(interaction) {\n\t\tawait interaction.reply('Pong!');\n\t},\n} satisfies Command;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/src/commands/utility/user.ts",
    "content": "import type { Command } from '../index.ts';\n\nexport default {\n\tdata: {\n\t\tname: 'user',\n\t\tdescription: 'Provides information about the user.',\n\t},\n\tasync execute(interaction) {\n\t\tawait interaction.reply(`This command was run by ${interaction.user.username}.`);\n\t},\n} satisfies Command;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/src/events/index.ts",
    "content": "import type { ClientEvents } from 'discord.js';\nimport { z } from 'zod';\nimport type { StructurePredicate } from '../util/loaders.ts';\n\n/**\n * Defines the structure of an event.\n */\nexport type Event<EventName extends keyof ClientEvents = keyof ClientEvents> = {\n\t/**\n\t * The function to execute when the event is emitted.\n\t *\n\t * @param parameters - The parameters of the event\n\t */\n\texecute(...parameters: ClientEvents[EventName]): Promise<void> | void;\n\t/**\n\t * The name of the event to listen to\n\t */\n\tname: EventName;\n\t/**\n\t * Whether or not the event should only be listened to once\n\t *\n\t * @defaultValue `false`\n\t */\n\tonce?: boolean;\n};\n\n/**\n * Defines the schema for an event.\n */\nexport const schema = z.object({\n\tname: z.string(),\n\tonce: z.boolean().optional().default(false),\n\texecute: z.function(),\n});\n\n/**\n * Defines the predicate to check if an object is a valid Event type.\n */\nexport const predicate: StructurePredicate<Event> = (structure: unknown): structure is Event =>\n\tschema.safeParse(structure).success;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/src/events/interactionCreate.ts",
    "content": "import { Events } from 'discord.js';\nimport { loadCommands } from '../util/loaders.ts';\nimport type { Event } from './index.ts';\n\nconst commands = await loadCommands(new URL('../commands/', import.meta.url));\n\nexport default {\n\tname: Events.InteractionCreate,\n\tasync execute(interaction) {\n\t\tif (interaction.isCommand()) {\n\t\t\tconst command = commands.get(interaction.commandName);\n\n\t\t\tif (!command) {\n\t\t\t\tthrow new Error(`Command '${interaction.commandName}' not found.`);\n\t\t\t}\n\n\t\t\tawait command.execute(interaction);\n\t\t}\n\t},\n} satisfies Event<Events.InteractionCreate>;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/src/events/ready.ts",
    "content": "import { Events } from 'discord.js';\nimport type { Event } from './index.ts';\n\nexport default {\n\tname: Events.ClientReady,\n\tonce: true,\n\tasync execute(client) {\n\t\tconsole.log(`Ready! Logged in as ${client.user.tag}`);\n\t},\n} satisfies Event<Events.ClientReady>;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/src/index.ts",
    "content": "import { Client, GatewayIntentBits } from 'discord.js';\nimport { loadEvents } from './util/loaders.ts';\n\n// Initialize the client\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\n// Load the events and commands\nconst events = await loadEvents(new URL('events/', import.meta.url));\n\n// Register the event handlers\nfor (const event of events) {\n\tclient[event.once ? 'once' : 'on'](event.name, async (...args) => {\n\t\ttry {\n\t\t\tawait event.execute(...args);\n\t\t} catch (error) {\n\t\t\tconsole.error(`Error executing event ${String(event.name)}:`, error);\n\t\t}\n\t});\n}\n\n// Login to the client\nvoid client.login(Bun.env.DISCORD_TOKEN);\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/src/util/deploy.ts",
    "content": "import { API } from '@discordjs/core/http-only';\nimport { REST } from 'discord.js';\nimport { loadCommands } from './loaders.ts';\n\nconst commands = await loadCommands(new URL('../commands/', import.meta.url));\nconst commandData = [...commands.values()].map((command) => command.data);\n\nconst rest = new REST({ version: '10' }).setToken(Bun.env.DISCORD_TOKEN!);\nconst api = new API(rest);\n\nconst result = await api.applicationCommands.bulkOverwriteGlobalCommands(Bun.env.APPLICATION_ID!, commandData);\n\nconsole.log(`Successfully registered ${result.length} commands.`);\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/src/util/loaders.ts",
    "content": "import type { PathLike } from 'node:fs';\nimport { stat } from 'node:fs/promises';\nimport { basename, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { Glob } from 'bun';\nimport { predicate as commandPredicate, type Command } from '../commands/index.ts';\nimport { predicate as eventPredicate, type Event } from '../events/index.ts';\n\n/**\n * A predicate to check if the structure is valid\n */\nexport type StructurePredicate<Structure> = (structure: unknown) => structure is Structure;\n\n/**\n * Loads all the structures in the provided directory\n *\n * @param dir - The directory to load the structures from\n * @param predicate - The predicate to check if the structure is valid\n * @param recursive - Whether to recursively load the structures in the directory\n * @returns\n */\nexport async function loadStructures<Structure>(\n\tdir: PathLike,\n\tpredicate: StructurePredicate<Structure>,\n\trecursive = true,\n): Promise<Structure[]> {\n\t// Get the stats of the directory\n\tconst statDir = await stat(dir);\n\n\t// If the provided directory path is not a directory, throw an error\n\tif (!statDir.isDirectory()) {\n\t\tthrow new Error(`The directory '${dir}' is not a directory.`);\n\t}\n\n\t// Create an empty array to store the structures\n\tconst structures: Structure[] = [];\n\n\t// Create a glob pattern to match the .ts files\n\tconst basePath = dir instanceof URL ? fileURLToPath(dir) : dir.toString();\n\tconst pattern = resolve(basePath, recursive ? '**/*.ts' : '*.ts');\n\tconst glob = new Glob(pattern);\n\n\t// Loop through all the matching files in the directory\n\tfor await (const file of glob.scan('.')) {\n\t\t// If the file is index.ts, skip the file\n\t\tif (basename(file) === 'index.ts') {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Import the structure dynamically from the file\n\t\tconst { default: structure } = await import(file);\n\n\t\t// If the default export is a valid structure, add it\n\t\tif (predicate(structure)) {\n\t\t\tstructures.push(structure);\n\t\t}\n\t}\n\n\treturn structures;\n}\n\nexport async function loadCommands(dir: PathLike, recursive = true): Promise<Map<string, Command>> {\n\treturn (await loadStructures(dir, commandPredicate, recursive)).reduce(\n\t\t(acc, cur) => acc.set(cur.data.name, cur),\n\t\tnew Map<string, Command>(),\n\t);\n}\n\nexport async function loadEvents(dir: PathLike, recursive = true): Promise<Event[]> {\n\treturn loadStructures(dir, eventPredicate, recursive);\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\"*.ts\", \"*.tsx\", \"*.js\", \"*.cjs\", \"*.mjs\", \"src\", \"bin\"]\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Bun/TypeScript/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": [\"@sapphire/ts-config\", \"@sapphire/ts-config/extra-strict\"],\n\t\"compilerOptions\": {\n\t\t\"allowImportingTsExtensions\": true,\n\t\t\"declaration\": false,\n\t\t\"declarationMap\": false,\n\t\t\"incremental\": false,\n\t\t\"module\": \"ESNext\",\n\t\t\"moduleResolution\": \"Bundler\",\n\t\t\"noEmit\": true,\n\t\t\"target\": \"ESNext\",\n\t\t\"skipLibCheck\": true\n\t}\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Deno/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional stylelint cache\n.stylelintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variable files\n.env\n.env.*\n!.env.example\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n.output\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n.temp\n.cache\n\n# Sveltekit cache directory\n.svelte-kit/\n\n# vitepress build output\n**/.vitepress/dist\n\n# vitepress cache directory\n**/.vitepress/cache\n\n# Docusaurus cache and generated files\n.docusaurus\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# Firebase cache directory\n.firebase/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# yarn v3\n.pnp.*\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n\n# Vite files\nvite.config.js.timestamp-*\nvite.config.ts.timestamp-*\n.vite/\n"
  },
  {
    "path": "packages/create-discord-bot/template/Deno/.vscode/extensions.json",
    "content": "{\n\t\"recommendations\": [\"denoland.vscode-deno\"]\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Deno/.vscode/settings.json",
    "content": "{\n\t\"editor.defaultFormatter\": \"denoland.vscode-deno\",\n\t\"editor.formatOnSave\": true,\n\t\"editor.codeActionsOnSave\": {\n\t\t\"source.fixAll\": \"always\",\n\t\t\"source.organizeImports\": \"always\"\n\t},\n\t\"editor.trimAutoWhitespace\": false,\n\t\"files.insertFinalNewline\": true,\n\t\"files.eol\": \"\\n\",\n\t\"deno.enable\": true\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Deno/deno.jsonc",
    "content": "{\n\t\"$schema\": \"https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json\",\n\t\"tasks\": {\n\t\t\"lint\": \"deno lint\",\n\t\t\"deploy\": \"deno run --env-file --allow-read --allow-env --allow-net src/util/deploy.ts\",\n\t\t\"format\": \"deno fmt\",\n\t\t\"fmt\": \"deno fmt\",\n\t\t\"start\": \"deno run --env-file --allow-read --allow-env --allow-net src/index.ts\",\n\t},\n\t\"fmt\": {\n\t\t\"useTabs\": true,\n\t\t\"lineWidth\": 120,\n\t\t\"singleQuote\": true,\n\t},\n\t\"lint\": {\n\t\t\"rules\": {\n\t\t\t\"tags\": [\"recommended\"],\n\t\t\t\"exclude\": [\"require-await\", \"no-await-in-sync-fn\"],\n\t\t},\n\t},\n\t\"imports\": {\n\t\t\"@discordjs/core\": \"npm:@discordjs/core@^2.3.0\",\n\t\t\"discord.js\": \"npm:discord.js@^14.24.2\",\n\t\t\"zod\": \"npm:zod@^4.1.12\",\n\t},\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/Deno/src/commands/index.ts",
    "content": "import type { CommandInteraction, RESTPostAPIApplicationCommandsJSONBody } from 'discord.js';\nimport { z } from 'zod';\nimport type { StructurePredicate } from '../util/loaders.ts';\n\n/**\n * Defines the structure of a command\n */\nexport type Command = {\n\t/**\n\t * The data for the command\n\t */\n\tdata: RESTPostAPIApplicationCommandsJSONBody;\n\t/**\n\t * The function to execute when the command is called\n\t *\n\t * @param interaction - The interaction of the command\n\t */\n\texecute(interaction: CommandInteraction): Promise<void> | void;\n};\n\n/**\n * Defines the schema for a command\n */\nexport const schema = z.object({\n\tdata: z.record(z.string(), z.any()),\n\texecute: z.function(),\n});\n\n/**\n * Defines the predicate to check if an object is a valid Command type.\n */\nexport const predicate: StructurePredicate<Command> = (structure): structure is Command =>\n\tschema.safeParse(structure).success;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Deno/src/commands/ping.ts",
    "content": "import type { Command } from './index.ts';\n\nexport default {\n\tdata: {\n\t\tname: 'ping',\n\t\tdescription: 'Ping!',\n\t},\n\tasync execute(interaction) {\n\t\tawait interaction.reply('Pong!');\n\t},\n} satisfies Command;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Deno/src/commands/utility/user.ts",
    "content": "import type { Command } from '../index.ts';\n\nexport default {\n\tdata: {\n\t\tname: 'user',\n\t\tdescription: 'Provides information about the user.',\n\t},\n\tasync execute(interaction) {\n\t\tawait interaction.reply(`This command was run by ${interaction.user.username}.`);\n\t},\n} satisfies Command;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Deno/src/events/index.ts",
    "content": "import type { ClientEvents } from 'discord.js';\nimport { z } from 'zod';\nimport type { StructurePredicate } from '../util/loaders.ts';\n\n/**\n * Defines the structure of an event.\n */\nexport type Event<EventName extends keyof ClientEvents = keyof ClientEvents> = {\n\t/**\n\t * The function to execute when the event is emitted.\n\t *\n\t * @param parameters - The parameters of the event\n\t */\n\texecute(...parameters: ClientEvents[EventName]): Promise<void> | void;\n\t/**\n\t * The name of the event to listen to\n\t */\n\tname: EventName;\n\t/**\n\t * Whether or not the event should only be listened to once\n\t *\n\t * @defaultValue `false`\n\t */\n\tonce?: boolean;\n};\n\n/**\n * Defines the schema for an event.\n */\nexport const schema = z.object({\n\tname: z.string(),\n\tonce: z.boolean().optional().default(false),\n\texecute: z.function(),\n});\n\n/**\n * Defines the predicate to check if an object is a valid Event type.\n */\nexport const predicate: StructurePredicate<Event> = (structure: unknown): structure is Event =>\n\tschema.safeParse(structure).success;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Deno/src/events/interactionCreate.ts",
    "content": "import { Events } from 'discord.js';\nimport type { Event } from './index.ts';\nimport { loadCommands } from '../util/loaders.ts';\n\nconst commands = await loadCommands(new URL('../commands/', import.meta.url));\n\nexport default {\n\tname: Events.InteractionCreate,\n\tasync execute(interaction) {\n\t\tif (interaction.isCommand()) {\n\t\t\tconst command = commands.get(interaction.commandName);\n\n\t\t\tif (!command) {\n\t\t\t\tthrow new Error(`Command '${interaction.commandName}' not found.`);\n\t\t\t}\n\n\t\t\tawait command.execute(interaction);\n\t\t}\n\t},\n} satisfies Event<Events.InteractionCreate>;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Deno/src/events/ready.ts",
    "content": "import { Events } from 'discord.js';\nimport type { Event } from './index.ts';\n\nexport default {\n\tname: Events.ClientReady,\n\tonce: true,\n\tasync execute(client) {\n\t\tconsole.log(`Ready! Logged in as ${client.user.tag}`);\n\t},\n} satisfies Event<Events.ClientReady>;\n"
  },
  {
    "path": "packages/create-discord-bot/template/Deno/src/index.ts",
    "content": "import { Client, GatewayIntentBits } from 'discord.js';\nimport { loadEvents } from './util/loaders.ts';\n\n// Initialize the client\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\n// Load the events and commands\nconst events = await loadEvents(new URL('events/', import.meta.url));\n\n// Register the event handlers\nfor (const event of events) {\n\tclient[event.once ? 'once' : 'on'](event.name, async (...args) => {\n\t\ttry {\n\t\t\tawait event.execute(...args);\n\t\t} catch (error) {\n\t\t\tconsole.error(`Error executing event ${String(event.name)}:`, error);\n\t\t}\n\t});\n}\n\n// Login to the client\nvoid client.login(Deno.env.get('DISCORD_TOKEN'));\n"
  },
  {
    "path": "packages/create-discord-bot/template/Deno/src/util/deploy.ts",
    "content": "import { API } from '@discordjs/core/http-only';\nimport { REST } from 'discord.js';\nimport { loadCommands } from './loaders.ts';\n\nconst commands = await loadCommands(new URL('../commands/', import.meta.url));\nconst commandData = [...commands.values()].map((command) => command.data);\n\nconst rest = new REST({ version: '10' }).setToken(Deno.env.get('DISCORD_TOKEN')!);\nconst api = new API(rest);\n\nconst result = await api.applicationCommands.bulkOverwriteGlobalCommands(Deno.env.get('APPLICATION_ID')!, commandData);\n\nconsole.log(`Successfully registered ${result.length} commands.`);\n"
  },
  {
    "path": "packages/create-discord-bot/template/Deno/src/util/loaders.ts",
    "content": "import type { PathLike } from 'node:fs';\nimport { glob, stat } from 'node:fs/promises';\nimport { basename, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { Command } from '../commands/index.ts';\nimport { predicate as commandPredicate } from '../commands/index.ts';\nimport type { Event } from '../events/index.ts';\nimport { predicate as eventPredicate } from '../events/index.ts';\n\n/**\n * A predicate to check if the structure is valid\n */\nexport type StructurePredicate<Structure> = (structure: unknown) => structure is Structure;\n\n/**\n * Loads all the structures in the provided directory\n *\n * @param dir - The directory to load the structures from\n * @param predicate - The predicate to check if the structure is valid\n * @param recursive - Whether to recursively load the structures in the directory\n * @returns\n */\nexport async function loadStructures<Structure>(\n\tdir: PathLike,\n\tpredicate: StructurePredicate<Structure>,\n\trecursive = true,\n): Promise<Structure[]> {\n\t// Get the stats of the directory\n\tconst statDir = await stat(dir);\n\n\t// If the provided directory path is not a directory, throw an error\n\tif (!statDir.isDirectory()) {\n\t\tthrow new Error(`The directory '${dir}' is not a directory.`);\n\t}\n\n\t// Create an empty array to store the structures\n\tconst structures: Structure[] = [];\n\n\t// Create a glob pattern to match the .ts files\n\tconst basePath = dir instanceof URL ? fileURLToPath(dir) : dir.toString();\n\tconst pattern = resolve(basePath, recursive ? '**/*.ts' : '*.ts');\n\n\t// Loop through all the matching files in the directory\n\tfor await (const file of glob(pattern)) {\n\t\t// If the file is index.ts, skip the file\n\t\tif (basename(file) === 'index.ts') {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Import the structure dynamically from the file\n\t\tconst { default: structure } = await import(file);\n\n\t\t// If the default export is a valid structure, add it\n\t\tif (predicate(structure)) {\n\t\t\tstructures.push(structure);\n\t\t}\n\t}\n\n\treturn structures;\n}\n\nexport async function loadCommands(dir: PathLike, recursive = true): Promise<Map<string, Command>> {\n\treturn (await loadStructures(dir, commandPredicate, recursive)).reduce(\n\t\t(acc, cur) => acc.set(cur.data.name, cur),\n\t\tnew Map<string, Command>(),\n\t);\n}\n\nexport async function loadEvents(dir: PathLike, recursive = true): Promise<Event[]> {\n\treturn loadStructures(dir, eventPredicate, recursive);\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional stylelint cache\n.stylelintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variable files\n.env\n.env.*\n!.env.example\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n.output\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n.temp\n.cache\n\n# Sveltekit cache directory\n.svelte-kit/\n\n# vitepress build output\n**/.vitepress/dist\n\n# vitepress cache directory\n**/.vitepress/cache\n\n# Docusaurus cache and generated files\n.docusaurus\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# Firebase cache directory\n.firebase/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# yarn v3\n.pnp.*\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n\n# Vite files\nvite.config.js.timestamp-*\nvite.config.ts.timestamp-*\n.vite/\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/.prettierignore",
    "content": "pnpm-lock.yaml\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/.prettierrc.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/prettierrc.json\",\n\t\"printWidth\": 120,\n\t\"useTabs\": true,\n\t\"singleQuote\": true,\n\t\"quoteProps\": \"as-needed\",\n\t\"trailingComma\": \"all\",\n\t\"endOfLine\": \"lf\"\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/.vscode/extensions.json",
    "content": "{\n\t\"recommendations\": [\n\t\t\"esbenp.prettier-vscode\",\n\t\t\"dbaeumer.vscode-eslint\",\n\t\t\"codezombiech.gitignore\",\n\t\t\"christian-kohler.npm-intellisense\",\n\t\t\"christian-kohler.path-intellisense\"\n\t]\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/.vscode/settings.json",
    "content": "{\n\t\"eslint.validate\": [\"javascript\", \"javascriptreact\", \"typescript\", \"typescriptreact\"],\n\t\"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n\t\"editor.formatOnSave\": true,\n\t\"editor.codeActionsOnSave\": {\n\t\t\"source.fixAll\": true,\n\t\t\"source.organizeImports\": false\n\t},\n\t\"editor.trimAutoWhitespace\": false,\n\t\"files.insertFinalNewline\": true,\n\t\"files.eol\": \"\\n\",\n\t\"npm.packageManager\": \"[REPLACE_PACKAGE_MANAGER]\"\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/eslint.config.js",
    "content": "import common from 'eslint-config-neon/common';\nimport node from 'eslint-config-neon/node';\nimport prettier from 'eslint-config-neon/prettier';\n\nconst config = [\n\t{\n\t\tignores: [],\n\t},\n\t...common,\n\t...node,\n\t...prettier,\n\t{\n\t\trules: {\n\t\t\t'no-restricted-globals': 0,\n\t\t\t'n/prefer-global/buffer': [2, 'never'],\n\t\t\t'n/prefer-global/console': [2, 'always'],\n\t\t\t'n/prefer-global/process': [2, 'never'],\n\t\t\t'n/prefer-global/text-decoder': [2, 'always'],\n\t\t\t'n/prefer-global/text-encoder': [2, 'always'],\n\t\t\t'n/prefer-global/url-search-params': [2, 'always'],\n\t\t\t'n/prefer-global/url': [2, 'always'],\n\t\t\t'jsdoc/check-tag-names': 0,\n\t\t\t'jsdoc/no-undefined-types': 0,\n\t\t\t'jsdoc/valid-types': 0,\n\t\t},\n\t},\n];\n\nexport default config;\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/template-javascript\",\n\t\"version\": \"0.1.0\",\n\t\"private\": true,\n\t\"type\": \"module\",\n\t\"scripts\": {\n\t\t\"lint\": \"prettier --check . && eslint --ext .js,.mjs,.cjs --format=pretty src\",\n\t\t\"format\": \"prettier --write . && eslint --ext .js,.mjs,.cjs --fix --format=pretty src\",\n\t\t\"start\": \"node --env-file=.env src/index.js\",\n\t\t\"deploy\": \"node --env-file=.env src/util/deploy.js\"\n\t},\n\t\"dependencies\": {\n\t\t\"@discordjs/core\": \"^2.4.0\",\n\t\t\"discord.js\": \"^14.25.1\"\n\t},\n\t\"devDependencies\": {\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"zod\": \"^4.3.6\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t}\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/src/commands/index.js",
    "content": "import { z } from 'zod';\n\n/**\n * Defines the structure of a command.\n *\n * @typedef {object} Command\n * @property {import('discord.js').RESTPostAPIApplicationCommandsJSONBody} data The data for the command\n * @property {(interaction: import('discord.js').CommandInteraction) => Promise<void> | void} execute The function to execute when the command is called\n */\n\n/**\n * Defines the schema for a command\n */\nexport const schema = z.object({\n\tdata: z.record(z.string(), z.any()),\n\texecute: z.function(),\n});\n\n/**\n * Defines the predicate to check if an object is a valid Command type.\n *\n * @type {import('../util/loaders.js').StructurePredicate<Command>}\n * @returns {structure is Command}\n */\nexport const predicate = (structure) => schema.safeParse(structure).success;\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/src/commands/ping.js",
    "content": "/** @type {import('./index.js').Command} */\nexport default {\n\tdata: {\n\t\tname: 'ping',\n\t\tdescription: 'Ping!',\n\t},\n\tasync execute(interaction) {\n\t\tawait interaction.reply('Pong!');\n\t},\n};\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/src/commands/utility/user.js",
    "content": "/** @type {import('../index.js').Command} */\nexport default {\n\tdata: {\n\t\tname: 'user',\n\t\tdescription: 'Provides information about the user.',\n\t},\n\tasync execute(interaction) {\n\t\tawait interaction.reply(`This command was run by ${interaction.user.username}.`);\n\t},\n};\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/src/events/index.js",
    "content": "import { z } from 'zod';\n\n/**\n * Defines the structure of an event.\n *\n * @template {keyof import('discord.js').ClientEvents} [EventName=keyof import('discord.js').ClientEvents]\n * @typedef {object} Event\n * @property {(...parameters: import('discord.js').ClientEvents[EventName]) => Promise<void> | void} execute The function to execute the command\n * @property {EventName} name The name of the event to listen to\n * @property {boolean} [once] Whether or not the event should only be listened to once\n */\n\n/**\n * Defines the schema for an event.\n *\n */\nexport const schema = z.object({\n\tname: z.string(),\n\tonce: z.boolean().optional().default(false),\n\texecute: z.function(),\n});\n\n/**\n * Defines the predicate to check if an object is a valid Event type.\n *\n * @type {import('../util/loaders.js').StructurePredicate<Event>}\n * @returns {structure is Event}\n */\nexport const predicate = (structure) => schema.safeParse(structure).success;\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/src/events/interactionCreate.js",
    "content": "import { Events } from 'discord.js';\nimport { loadCommands } from '../util/loaders.js';\n\nconst commands = await loadCommands(new URL('../commands/', import.meta.url));\n\n/** @type {import('../events/index.js').Event<Events.InteractionCreate>} */\nexport default {\n\tname: Events.InteractionCreate,\n\tasync execute(interaction) {\n\t\tif (interaction.isCommand()) {\n\t\t\tconst command = commands.get(interaction.commandName);\n\n\t\t\tif (!command) {\n\t\t\t\tthrow new Error(`Command '${interaction.commandName}' not found.`);\n\t\t\t}\n\n\t\t\tawait command.execute(interaction);\n\t\t}\n\t},\n};\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/src/events/ready.js",
    "content": "import { Events } from 'discord.js';\n\n/** @type {import('./index.js').Event<Events.ClientReady>} */\nexport default {\n\tname: Events.ClientReady,\n\tonce: true,\n\tasync execute(client) {\n\t\tconsole.log(`Ready! Logged in as ${client.user.tag}`);\n\t},\n};\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/src/index.js",
    "content": "import process from 'node:process';\nimport { Client, GatewayIntentBits } from 'discord.js';\nimport { loadEvents } from './util/loaders.js';\n\n// Initialize the client\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\n// Load the events and commands\nconst events = await loadEvents(new URL('events/', import.meta.url));\n\n// Register the event handlers\nfor (const event of events) {\n\tclient[event.once ? 'once' : 'on'](event.name, async (...args) => {\n\t\ttry {\n\t\t\tawait event.execute(...args);\n\t\t} catch (error) {\n\t\t\tconsole.error(`Error executing event ${String(event.name)}:`, error);\n\t\t}\n\t});\n}\n\n// Login to the client\nvoid client.login(process.env.DISCORD_TOKEN);\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/src/util/deploy.js",
    "content": "import process from 'node:process';\nimport { API } from '@discordjs/core/http-only';\nimport { REST } from 'discord.js';\nimport { loadCommands } from './loaders.js';\n\nconst commands = await loadCommands(new URL('../commands/', import.meta.url));\nconst commandData = [...commands.values()].map((command) => command.data);\n\nconst rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);\nconst api = new API(rest);\n\nconst result = await api.applicationCommands.bulkOverwriteGlobalCommands(process.env.APPLICATION_ID, commandData);\n\nconsole.log(`Successfully registered ${result.length} commands.`);\n"
  },
  {
    "path": "packages/create-discord-bot/template/JavaScript/src/util/loaders.js",
    "content": "import { glob, stat } from 'node:fs/promises';\nimport { basename, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { predicate as commandPredicate } from '../commands/index.js';\nimport { predicate as eventPredicate } from '../events/index.js';\n\n/**\n * A predicate to check if the structure is valid.\n *\n * @template Structure\n * @typedef {(structure: unknown) => structure is Structure} StructurePredicate\n */\n\n/**\n * Loads all the structures in the provided directory.\n *\n * @template Structure\n * @param {import('node:fs').PathLike} dir - The directory to load the structures from\n * @param {StructurePredicate<Structure>} predicate - The predicate to check if the structure is valid\n * @param {boolean} recursive - Whether to recursively load the structures in the directory\n * @returns {Promise<Structure[]>}\n */\nexport async function loadStructures(dir, predicate, recursive = true) {\n\t// Get the stats of the directory\n\tconst statDir = await stat(dir);\n\n\t// If the provided directory path is not a directory, throw an error\n\tif (!statDir.isDirectory()) {\n\t\tthrow new Error(`The directory '${dir}' is not a directory.`);\n\t}\n\n\t// Create an empty array to store the structures\n\t/** @type {Structure[]} */\n\tconst structures = [];\n\n\t// Create a glob pattern to match the .js files\n\tconst basePath = dir instanceof URL ? fileURLToPath(dir) : dir.toString();\n\tconst pattern = resolve(basePath, recursive ? '**/*.js' : '*.js');\n\n\t// Loop through all the matching files in the directory\n\tfor await (const file of glob(pattern)) {\n\t\t// If the file is index.js, skip the file\n\t\tif (basename(file) === 'index.js') {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Import the structure dynamically from the file\n\t\tconst { default: structure } = await import(file);\n\n\t\t// If the default export is a valid structure, add it\n\t\tif (predicate(structure)) {\n\t\t\tstructures.push(structure);\n\t\t}\n\t}\n\n\treturn structures;\n}\n\n/**\n * @param {import('node:fs').PathLike} dir\n * @param {boolean} [recursive]\n * @returns {Promise<Map<string, import('../commands/index.js').Command>>}\n */\nexport async function loadCommands(dir, recursive = true) {\n\treturn (await loadStructures(dir, commandPredicate, recursive)).reduce(\n\t\t(acc, cur) => acc.set(cur.data.name, cur),\n\t\tnew Map(),\n\t);\n}\n\n/**\n * @param {import('node:fs').PathLike} dir\n * @param {boolean} [recursive]\n * @returns {Promise<import('../events/index.js').Event[]>}\n */\nexport async function loadEvents(dir, recursive = true) {\n\treturn loadStructures(dir, eventPredicate, recursive);\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional stylelint cache\n.stylelintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variable files\n.env\n.env.*\n!.env.example\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n.output\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n.temp\n.cache\n\n# Sveltekit cache directory\n.svelte-kit/\n\n# vitepress build output\n**/.vitepress/dist\n\n# vitepress cache directory\n**/.vitepress/cache\n\n# Docusaurus cache and generated files\n.docusaurus\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# Firebase cache directory\n.firebase/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# yarn v3\n.pnp.*\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n\n# Vite files\nvite.config.js.timestamp-*\nvite.config.ts.timestamp-*\n.vite/\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/.prettierignore",
    "content": "pnpm-lock.yaml\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/.prettierrc.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/prettierrc.json\",\n\t\"printWidth\": 120,\n\t\"useTabs\": true,\n\t\"singleQuote\": true,\n\t\"quoteProps\": \"as-needed\",\n\t\"trailingComma\": \"all\",\n\t\"endOfLine\": \"lf\"\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/.vscode/extensions.json",
    "content": "{\n\t\"recommendations\": [\n\t\t\"esbenp.prettier-vscode\",\n\t\t\"dbaeumer.vscode-eslint\",\n\t\t\"codezombiech.gitignore\",\n\t\t\"christian-kohler.npm-intellisense\",\n\t\t\"christian-kohler.path-intellisense\"\n\t]\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/.vscode/settings.json",
    "content": "{\n\t\"eslint.validate\": [\"javascript\", \"javascriptreact\", \"typescript\", \"typescriptreact\"],\n\t\"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n\t\"editor.formatOnSave\": true,\n\t\"editor.codeActionsOnSave\": {\n\t\t\"source.fixAll\": \"explicit\",\n\t\t\"source.organizeImports\": \"never\"\n\t},\n\t\"editor.trimAutoWhitespace\": false,\n\t\"files.insertFinalNewline\": true,\n\t\"files.eol\": \"\\n\",\n\t\"npm.packageManager\": \"[REPLACE_PACKAGE_MANAGER]\"\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/eslint.config.js",
    "content": "import common from 'eslint-config-neon/common';\nimport node from 'eslint-config-neon/node';\nimport prettier from 'eslint-config-neon/prettier';\nimport typescript from 'eslint-config-neon/typescript';\n\nconst config = [\n\t{\n\t\tignores: [],\n\t},\n\t...common,\n\t...node,\n\t...typescript,\n\t...prettier,\n\t{\n\t\tlanguageOptions: {\n\t\t\tparserOptions: {\n\t\t\t\tproject: ['./tsconfig.eslint.json'],\n\t\t\t},\n\t\t},\n\t\trules: {\n\t\t\t'no-restricted-globals': 0,\n\t\t\t'n/prefer-global/buffer': [2, 'never'],\n\t\t\t'n/prefer-global/console': [2, 'always'],\n\t\t\t'n/prefer-global/process': [2, 'never'],\n\t\t\t'n/prefer-global/text-decoder': [2, 'always'],\n\t\t\t'n/prefer-global/text-encoder': [2, 'always'],\n\t\t\t'n/prefer-global/url-search-params': [2, 'always'],\n\t\t\t'n/prefer-global/url': [2, 'always'],\n\t\t\t'import/extensions': 0,\n\t\t},\n\t},\n];\n\nexport default config;\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/template-typescript\",\n\t\"version\": \"0.1.0\",\n\t\"private\": true,\n\t\"type\": \"module\",\n\t\"scripts\": {\n\t\t\"build\": \"tsc\",\n\t\t\"lint\": \"prettier --check . && eslint --ext .ts --format=pretty src\",\n\t\t\"deploy\": \"node --env-file=.env src/util/deploy.ts\",\n\t\t\"format\": \"prettier --write . && eslint --ext .ts --fix --format=pretty src\",\n\t\t\"start\": \"node --env-file=.env src/index.ts\"\n\t},\n\t\"dependencies\": {\n\t\t\"@discordjs/core\": \"^2.4.0\",\n\t\t\"discord.js\": \"^14.25.1\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@sapphire/ts-config\": \"^5.0.3\",\n\t\t\"@types/node\": \"^22.19.11\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"zod\": \"^4.3.6\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t}\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/src/commands/index.ts",
    "content": "import type { RESTPostAPIApplicationCommandsJSONBody, CommandInteraction } from 'discord.js';\nimport { z } from 'zod';\nimport type { StructurePredicate } from '../util/loaders.ts';\n\n/**\n * Defines the structure of a command\n */\nexport type Command = {\n\t/**\n\t * The data for the command\n\t */\n\tdata: RESTPostAPIApplicationCommandsJSONBody;\n\t/**\n\t * The function to execute when the command is called\n\t *\n\t * @param interaction - The interaction of the command\n\t */\n\texecute(interaction: CommandInteraction): Promise<void> | void;\n};\n\n/**\n * Defines the schema for a command\n */\nexport const schema = z.object({\n\tdata: z.record(z.string(), z.any()),\n\texecute: z.function(),\n});\n\n/**\n * Defines the predicate to check if an object is a valid Command type.\n */\nexport const predicate: StructurePredicate<Command> = (structure: unknown): structure is Command =>\n\tschema.safeParse(structure).success;\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/src/commands/ping.ts",
    "content": "import type { Command } from './index.ts';\n\nexport default {\n\tdata: {\n\t\tname: 'ping',\n\t\tdescription: 'Ping!',\n\t},\n\tasync execute(interaction) {\n\t\tawait interaction.reply('Pong!');\n\t},\n} satisfies Command;\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/src/commands/utility/user.ts",
    "content": "import type { Command } from '../index.ts';\n\nexport default {\n\tdata: {\n\t\tname: 'user',\n\t\tdescription: 'Provides information about the user.',\n\t},\n\tasync execute(interaction) {\n\t\tawait interaction.reply(`This command was run by ${interaction.user.username}.`);\n\t},\n} satisfies Command;\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/src/events/index.ts",
    "content": "import type { ClientEvents } from 'discord.js';\nimport { z } from 'zod';\nimport type { StructurePredicate } from '../util/loaders.ts';\n\n/**\n * Defines the structure of an event.\n */\nexport type Event<EventName extends keyof ClientEvents = keyof ClientEvents> = {\n\t/**\n\t * The function to execute when the event is emitted.\n\t *\n\t * @param parameters - The parameters of the event\n\t */\n\texecute(...parameters: ClientEvents[EventName]): Promise<void> | void;\n\t/**\n\t * The name of the event to listen to\n\t */\n\tname: EventName;\n\t/**\n\t * Whether or not the event should only be listened to once\n\t *\n\t * @defaultValue `false`\n\t */\n\tonce?: boolean;\n};\n\n/**\n * Defines the schema for an event.\n */\nexport const schema = z.object({\n\tname: z.string(),\n\tonce: z.boolean().optional().default(false),\n\texecute: z.function(),\n});\n\n/**\n * Defines the predicate to check if an object is a valid Event type.\n */\nexport const predicate: StructurePredicate<Event> = (structure: unknown): structure is Event =>\n\tschema.safeParse(structure).success;\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/src/events/interactionCreate.ts",
    "content": "import { Events } from 'discord.js';\nimport { loadCommands } from '../util/loaders.ts';\nimport type { Event } from './index.ts';\n\nconst commands = await loadCommands(new URL('../commands/', import.meta.url));\n\nexport default {\n\tname: Events.InteractionCreate,\n\tasync execute(interaction) {\n\t\tif (interaction.isCommand()) {\n\t\t\tconst command = commands.get(interaction.commandName);\n\n\t\t\tif (!command) {\n\t\t\t\tthrow new Error(`Command '${interaction.commandName}' not found.`);\n\t\t\t}\n\n\t\t\tawait command.execute(interaction);\n\t\t}\n\t},\n} satisfies Event<Events.InteractionCreate>;\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/src/events/ready.ts",
    "content": "import { Events } from 'discord.js';\nimport type { Event } from './index.ts';\n\nexport default {\n\tname: Events.ClientReady,\n\tonce: true,\n\tasync execute(client) {\n\t\tconsole.log(`Ready! Logged in as ${client.user.tag}`);\n\t},\n} satisfies Event<Events.ClientReady>;\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/src/index.ts",
    "content": "import process from 'node:process';\nimport { Client, GatewayIntentBits } from 'discord.js';\nimport { loadEvents } from './util/loaders.ts';\n\n// Initialize the client\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\n// Load the events and commands\nconst events = await loadEvents(new URL('events/', import.meta.url));\n\n// Register the event handlers\nfor (const event of events) {\n\tclient[event.once ? 'once' : 'on'](event.name, async (...args) => {\n\t\ttry {\n\t\t\tawait event.execute(...args);\n\t\t} catch (error) {\n\t\t\tconsole.error(`Error executing event ${String(event.name)}:`, error);\n\t\t}\n\t});\n}\n\n// Login to the client\nvoid client.login(process.env.DISCORD_TOKEN);\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/src/util/deploy.ts",
    "content": "import process from 'node:process';\nimport { API } from '@discordjs/core/http-only';\nimport { REST } from 'discord.js';\nimport { loadCommands } from './loaders.ts';\n\nconst commands = await loadCommands(new URL('../commands/', import.meta.url));\nconst commandData = [...commands.values()].map((command) => command.data);\n\nconst rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN!);\nconst api = new API(rest);\n\nconst result = await api.applicationCommands.bulkOverwriteGlobalCommands(process.env.APPLICATION_ID!, commandData);\n\nconsole.log(`Successfully registered ${result.length} commands.`);\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/src/util/loaders.ts",
    "content": "import type { PathLike } from 'node:fs';\nimport { glob, stat } from 'node:fs/promises';\nimport { basename, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { predicate as commandPredicate, type Command } from '../commands/index.ts';\nimport { predicate as eventPredicate, type Event } from '../events/index.ts';\n\n/**\n * A predicate to check if the structure is valid\n */\nexport type StructurePredicate<Structure> = (structure: unknown) => structure is Structure;\n\n/**\n * Loads all the structures in the provided directory\n *\n * @param dir - The directory to load the structures from\n * @param predicate - The predicate to check if the structure is valid\n * @param recursive - Whether to recursively load the structures in the directory\n * @returns\n */\nexport async function loadStructures<Structure>(\n\tdir: PathLike,\n\tpredicate: StructurePredicate<Structure>,\n\trecursive = true,\n): Promise<Structure[]> {\n\t// Get the stats of the directory\n\tconst statDir = await stat(dir);\n\n\t// If the provided directory path is not a directory, throw an error\n\tif (!statDir.isDirectory()) {\n\t\tthrow new Error(`The directory '${dir}' is not a directory.`);\n\t}\n\n\t// Create an empty array to store the structures\n\tconst structures: Structure[] = [];\n\n\t// Create a glob pattern to match the .ts files\n\tconst basePath = dir instanceof URL ? fileURLToPath(dir) : dir.toString();\n\tconst pattern = resolve(basePath, recursive ? '**/*.ts' : '*.ts');\n\n\t// Loop through all the matching files in the directory\n\tfor await (const file of glob(pattern)) {\n\t\t// If the file is index.ts, skip the file\n\t\tif (basename(file) === 'index.ts') {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Import the structure dynamically from the file\n\t\tconst { default: structure } = await import(file);\n\n\t\t// If the default export is a valid structure, add it\n\t\tif (predicate(structure)) {\n\t\t\tstructures.push(structure);\n\t\t}\n\t}\n\n\treturn structures;\n}\n\nexport async function loadCommands(dir: PathLike, recursive = true): Promise<Map<string, Command>> {\n\treturn (await loadStructures(dir, commandPredicate, recursive)).reduce(\n\t\t(acc, cur) => acc.set(cur.data.name, cur),\n\t\tnew Map<string, Command>(),\n\t);\n}\n\nexport async function loadEvents(dir: PathLike, recursive = true): Promise<Event[]> {\n\treturn loadStructures(dir, eventPredicate, recursive);\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\"*.ts\", \"*.tsx\", \"*.js\", \"*.cjs\", \"*.mjs\", \"src\", \"bin\"]\n}\n"
  },
  {
    "path": "packages/create-discord-bot/template/TypeScript/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": [\"@sapphire/ts-config\", \"@sapphire/ts-config/extra-strict\"],\n\t\"compilerOptions\": {\n\t\t\"allowImportingTsExtensions\": true,\n\t\t\"erasableSyntaxOnly\": true,\n\t\t\"declaration\": false,\n\t\t\"declarationMap\": false,\n\t\t\"incremental\": false,\n\t\t\"module\": \"ESNext\",\n\t\t\"moduleResolution\": \"Bundler\",\n\t\t\"noEmit\": true,\n\t\t\"target\": \"ESNext\",\n\t\t\"skipLibCheck\": true\n\t}\n}\n"
  },
  {
    "path": "packages/create-discord-bot/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\", \"template\"]\n}\n"
  },
  {
    "path": "packages/create-discord-bot/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/create-discord-bot/tsup.config.ts",
    "content": "import { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tentry: ['bin/index.ts'],\n\tdts: false,\n\tformat: 'esm',\n\tminify: 'terser',\n\tsourcemap: false,\n});\n"
  },
  {
    "path": "packages/discord.js/.cliff-jumperrc.json",
    "content": "{\n  \"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n  \"name\": \"discord.js\",\n  \"packagePath\": \"packages/discord.js\",\n  \"tagTemplate\": \"{{new-version}}\",\n  \"identifierBase\": false\n}\n"
  },
  {
    "path": "packages/discord.js/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\ntest/auth.json\ntest/auth.js\n\n# Docs\ndocs/**/*\n!docs/index.json\n!docs/logo.svg\n!docs/README.md\n\n# Miscellaneous\n.turbo\n.tmp\n\n# Generated files\ntypings/index.d.mts\n"
  },
  {
    "path": "packages/discord.js/.lintstagedrc.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/lintstagedrc.schema.json\",\n  \"*\": \"prettier --ignore-unknown --write\",\n  \"{src/**,typings/**,scripts/**}.{mjs,js,ts}\": \"cross-env eslint --fix --format=pretty\"\n}\n"
  },
  {
    "path": "packages/discord.js/.prettierignore",
    "content": ".turbo\ndocs/docs.json\nCHANGELOG.md\n"
  },
  {
    "path": "packages/discord.js/.prettierrc.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/prettierrc.json\",\n  \"singleQuote\": true,\n  \"printWidth\": 120,\n  \"trailingComma\": \"all\",\n  \"endOfLine\": \"lf\",\n  \"arrowParens\": \"avoid\"\n}\n"
  },
  {
    "path": "packages/discord.js/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n# [14.16.3](https://github.com/discordjs/discord.js/compare/14.16.2...14.16.3) - (2024-09-29)\n\n## Bug Fixes\n\n- **BaseInteraction:** Add missing props (#10517) ([6c77fee](https://github.com/discordjs/discord.js/commit/6c77fee41b1aabc243bff623debd157a4c7fad6a)) by @monbrey\n- `GuildChannel#guildId` not being patched to `undefined` (#10505) ([2adee06](https://github.com/discordjs/discord.js/commit/2adee06b6e92b7854ebb1c2bfd04940aab68dd10)) by @Qjuh\n\n## Typings\n\n- **MessageEditOptions:** Omit `poll` (#10509) ([665bf14](https://github.com/discordjs/discord.js/commit/665bf1486aec62e9528f5f7b5a6910ae6b5a6c9c)) by @TAEMBO\n\n# [14.16.2](https://github.com/discordjs/discord.js/compare/14.16.1...14.16.2) - (2024-09-12)\n\n## Bug Fixes\n\n- **ApplicationCommand:** Incorrect comparison in equals method (#10497) ([3c74aa2](https://github.com/discordjs/discord.js/commit/3c74aa204909323ff6d05991438bee2c583e838b)) by @monbrey\n- Type guard for sendable text-based channels (#10482) ([dea6840](https://github.com/discordjs/discord.js/commit/dea68400a38edb90b8b4242d64be14968943130d)) by @vladfrangu\n\n## Documentation\n\n- Update discord documentation links (#10484) ([799fa54](https://github.com/discordjs/discord.js/commit/799fa54fa4434144855be2f7a0bbac6ff8ce9d0b)) by @sdanialraza\n- **Message:** Mark `interaction` as deprecated (#10481) ([c13f18e](https://github.com/discordjs/discord.js/commit/c13f18e90eb6eb315397c095e948993856428757)) by @sdanialraza\n- **ApplicationEmojiManager:** Fix fetch example (#10480) ([4594896](https://github.com/discordjs/discord.js/commit/4594896b5404c6a34e07544951c59ff8f3657184)) by @sdanialraza\n\n## Typings\n\n- Export GroupDM helper type (#10478) ([aff772c](https://github.com/discordjs/discord.js/commit/aff772c7aa3b3de58780a94588d1f3576a434f32)) by @Qjuh\n\n# [14.16.1](https://github.com/discordjs/discord.js/compare/14.16.0...14.16.1) - (2024-09-02)\n\n## Bug Fixes\n\n- **Message:** Reacting returning undefined (#10475) ([9257a09](https://github.com/discordjs/discord.js/commit/9257a09abbf80558ed2d5d209a2f6bd2a4b3d799)) by @vladfrangu\n- **Transformers:** Pass client to recursive call (#10474) ([4810f7c](https://github.com/discordjs/discord.js/commit/4810f7c8637dacf77d0442bd84e0d579e1f1d3bd)) by @SpaceEEC\n\n# [14.16.0](https://github.com/discordjs/discord.js/compare/14.15.3...14.16.0) - (2024-09-01)\n\n## Bug Fixes\n\n- Message reaction crash (#10469) ([13dc779](https://github.com/discordjs/discord.js/commit/13dc779029acbea295e208cc0c058f0e6ec0e9aa))\n- **MessagePayload:** Crash when resolving body (#10454) ([dd795da](https://github.com/discordjs/discord.js/commit/dd795da790ac4107bc9d8d55aa7bc119367ee8c6))\n- **Shard:** Add env, execArgv, and argv for worker-based shards (#10429) ([b0f8df0](https://github.com/discordjs/discord.js/commit/b0f8df0f6c7d2a89838132c886294428ddf090d9))\n- **GuildAuditLogsEntry:** Correct mapped `AuditLogChange` objects (#10438) ([45f7e1a](https://github.com/discordjs/discord.js/commit/45f7e1a2e85da760f548765b768bd1b378bdedb9))\n- **GuildMemberManager:** Fix data type check for `add()` method (#10338) ([ab8bf0f](https://github.com/discordjs/discord.js/commit/ab8bf0f4d2a50cd85cf8b2aa1d4e2ea93872807b))\n- Consistent debug log spacing (#10349) ([38c699b](https://github.com/discordjs/discord.js/commit/38c699bc8a2ca40f37f70c93e08067e00f12ee81))\n\n## Documentation\n\n- Correct documentation for BaseInteraction#inCachedGuild (#10456) ([bddf018](https://github.com/discordjs/discord.js/commit/bddf018f266f7050d64f414aa60dd01b1568a1ef))\n- Lowercase \"image\" URL (#10386) ([785ec8f](https://github.com/discordjs/discord.js/commit/785ec8fd757da1d8cf7963e3cec231a6d5fe4a24))\n- Update rule trigger types (#9708) ([757bed0](https://github.com/discordjs/discord.js/commit/757bed0b1f345a8963bc4eb680bed4462531fb49))\n\n## Features\n\n- User-installable apps (#10227) ([fc0b6f7](https://github.com/discordjs/discord.js/commit/fc0b6f7f8ebd94a4a05fac0c76e49b23752a8e65))\n- Super reactions (#9336) ([a5afc40](https://github.com/discordjs/discord.js/commit/a5afc406b965b39a9cc90ef9e0e7a4b460c4e04c))\n- Use get sticker pack endpoint (#10445) ([1b1ae2f](https://github.com/discordjs/discord.js/commit/1b1ae2f0cb339170e4c0692eb43fbc966fd64030))\n- **VoiceState:** Add methods for fetching voice state (#10442) ([9907ff9](https://github.com/discordjs/discord.js/commit/9907ff915e7c72e7e980d68bf005763a3aacad1c))\n- Application emojis (#10399) ([5d92525](https://github.com/discordjs/discord.js/commit/5d92525596a0193fe65626119bb040c2eb9e945a))\n- **Attachment:** Add `title` (#10423) ([c63bde9](https://github.com/discordjs/discord.js/commit/c63bde9479359a863be4ffa4916d683a88eb46f1))\n- Add support for Automated Message nonce handling (#10381) ([2ca187b](https://github.com/discordjs/discord.js/commit/2ca187bd34a8cf2ac4ac7f2bdaecd0506c5b40bd))\n- **GuildAuditLogsEntry:** Onboarding events (#9726) ([3654efe](https://github.com/discordjs/discord.js/commit/3654efede26e28f572313cc9f3556ae59db61ba3))\n- Premium buttons (#10353) ([4f59b74](https://github.com/discordjs/discord.js/commit/4f59b740d01b9ff2213949708a36e17da32b89c3))\n- **Message:** Add `call` (#10283) ([6803121](https://github.com/discordjs/discord.js/commit/68031210f52f25dff80558e0a12d1eceb785b47b))\n- **Invite:** Add `type` (#10280) ([17d4c78](https://github.com/discordjs/discord.js/commit/17d4c78fdecff62f616546e69ef9d8ddaea3986c))\n- **User:** Add `avatarDecorationData` (#9888) ([3b5c600](https://github.com/discordjs/discord.js/commit/3b5c600b9e3f8d40ed48f02e3c9acec7433f1cc3))\n\n## Refactor\n\n- Use get guild role endpoint (#10443) ([bba0e72](https://github.com/discordjs/discord.js/commit/bba0e72e2283630b9f84b77d53525397036c6b31))\n- **actions:** Safer getChannel calls (#10434) ([87776bb](https://github.com/discordjs/discord.js/commit/87776bb0e8de0e04043ff61fdaf5e71cfbb69aef))\n- **GuildChannelManager:** Remove redundant edit code (#10370) ([9461045](https://github.com/discordjs/discord.js/commit/9461045e5a8b832778e7e8637f540ee51e6d1eef))\n\n## Typings\n\n- Use `ThreadChannel` and `AnyThreadChannel` consistently (#10181) ([1f7d1f8](https://github.com/discordjs/discord.js/commit/1f7d1f8094da8d9ee797b72711a4453b29589f8b))\n- **Client:** `EventEmitter` static method overrides (#10360) ([9b707f2](https://github.com/discordjs/discord.js/commit/9b707f2b832a57d5768757fad09cf8982f64d03b))\n- Fix wrong auto moderation target type (#10391) ([bbef68d](https://github.com/discordjs/discord.js/commit/bbef68d27116a2e0aa8c545a2043c46774c97887))\n- **ApplicationCommandManager:** `Snowflake` fetch (#10366) ([b8397b2](https://github.com/discordjs/discord.js/commit/b8397b24e5a3b27639a5a0bf495c2c47b7954dad))\n\n# [14.15.3](https://github.com/discordjs/discord.js/compare/14.15.2...14.15.3) - (2024-06-02)\n\n## Bug Fixes\n\n- **Message:** Properly compare `attachments` and `embeds` (#10282) ([a468ae8](https://github.com/discordjs/discord.js/commit/a468ae8bb5a9de9cb34d40493c59693e84c2812a))\n- Throw error on no message id for `Message#fetchReference()` (#10295) ([638b896](https://github.com/discordjs/discord.js/commit/638b896efaf0a01b477f91c17170214ad96b1602))\n- **ThreadChannel:** Invalid owner fetch option (#10292) ([27d0659](https://github.com/discordjs/discord.js/commit/27d0659a45c44f0c5986688d16f28e75e99abcc1))\n- **Action:** Ensure all properties on `getChannel()` are passed (#10278) ([92c1a51](https://github.com/discordjs/discord.js/commit/92c1a511dc0d9b552b797ef25c7aed2eb36b4386))\n- **docs:** Some link tags didn't resolve correctly (#10269) ([914cc4b](https://github.com/discordjs/discord.js/commit/914cc4ba5441cde5aa6dc8ec6406a283855d6828))\n- **actions:** Handle missing poll object (#10266) ([7816ec2](https://github.com/discordjs/discord.js/commit/7816ec2e6b28daf400eaa9cb050fb72908e6f7c6))\n\n## Refactor\n\n- **GuildChannelManager:** Improve addFollower errors (#10277) ([555961b](https://github.com/discordjs/discord.js/commit/555961b3b8da8759349cd0e88f89f98d2e8a6363))\n\n## Typings\n\n- Forum starter messages do not support polls (#10276) ([35207b0](https://github.com/discordjs/discord.js/commit/35207b0b31929558eee69f4bd53a6f9adadb0362))\n- Add `defaultValues` to respective select menu components data (#10265) ([c2432d5](https://github.com/discordjs/discord.js/commit/c2432d5704e4e178c044bc0d02f2dabe51450d19))\n\n# [14.15.2](https://github.com/discordjs/discord.js/compare/14.15.1...14.15.2) - (2024-05-05)\n\n## Bug Fixes\n\n- **PollAnswer:** FetchVoters route changed to MessageManager (#10251) ([30d79e8](https://github.com/discordjs/discord.js/commit/30d79e85fb8502aee5c63fe7effd9029e347d266))\n\n# [14.15.1](https://github.com/discordjs/discord.js/compare/14.15.0...14.15.1) - (2024-05-04)\n\n## Bug Fixes\n\n- **MessageManager:** Poll methods don't need a channel id (#10249) ([0474a43](https://github.com/discordjs/discord.js/commit/0474a4375146b57b35074dadbaa83274416f899e))\n\n# [14.15.0](https://github.com/discordjs/discord.js/compare/14.14.1...14.15.0) - (2024-05-04)\n\n## Bug Fixes\n\n- **Message:** Not crosspostable if has a poll (#10246) ([a6b9f1b](https://github.com/discordjs/discord.js/commit/a6b9f1b37e60a9cd6689cec9d9d062a01d179165))\n- **actions:** Always emit message create for own messages (#10211) ([798f28c](https://github.com/discordjs/discord.js/commit/798f28cb9b25f9f1760be1300465869772f43978))\n- **Embed:** Address `equals` method issue (#10152) ([ddc927f](https://github.com/discordjs/discord.js/commit/ddc927fabdc4d79a00a89652fb7d6310a40e6397))\n- **types:** Export `ReadonlyCollection` (#10184) ([6cc5fa2](https://github.com/discordjs/discord.js/commit/6cc5fa28e6dc540a48c9e6f734ffb3832b78b3df))\n- Anchor link for events ([0efd1be](https://github.com/discordjs/discord.js/commit/0efd1bea46fa2fc8bcd3dcfd0ac5cd608a0a7df0))\n- **resolveColor:** Address case for numbers (#10115) ([3755e66](https://github.com/discordjs/discord.js/commit/3755e66d411efd6ed210d5070a0257c742c336d6))\n- Invert deletable message types list (#10093) ([42bc5d2](https://github.com/discordjs/discord.js/commit/42bc5d2c744d59a63ba2cccff2099092556da49e))\n- **BaseClient:** Fall back to `userAgentAppendix` (#10113) ([b16647e](https://github.com/discordjs/discord.js/commit/b16647e6cc6c1d0ee13ac5ce3bf31fd743355eb3))\n- **InteractionResponses:** Check if ephemeral message flag is used (#10021) ([62e31cb](https://github.com/discordjs/discord.js/commit/62e31cb9ee4b21b15fcce45b2cdfab970bb89824))\n- Replace internal calls to Emoji#url (#10025) ([941642a](https://github.com/discordjs/discord.js/commit/941642ad2ff31017cfe0419fda55f1f2a1f12286))\n- Export \"ESM\" types when discord.js is imported in ESM land (#10009) ([e412a22](https://github.com/discordjs/discord.js/commit/e412a22ceb92f142fbeddb6b9330e046bec92c69))\n- **website:** Discord-api-types links, URL links and some minor doc issues (#9990) ([57c414b](https://github.com/discordjs/discord.js/commit/57c414be21157a83a5dfe0f720b0f8d495e28538))\n- **website:** Cross package deprecated links (#9981) ([802ec63](https://github.com/discordjs/discord.js/commit/802ec63a4872430577431a2b8fbff87d504f81e4))\n- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))\n- **website:** Misc improvements (#9940) ([b79351b](https://github.com/discordjs/discord.js/commit/b79351ba99d71b1c0e9263539634cd2532ee7b60))\n\n## Documentation\n\n- Remove unused `Locale` typedef (#10191) ([f1f2683](https://github.com/discordjs/discord.js/commit/f1f2683dc7179a84f9efe0217381fe0a9f61283e))\n- **ActionRow:** Fix deprecated message (#10130) ([f67da74](https://github.com/discordjs/discord.js/commit/f67da74a5aca929aa71d5b1ff040cef17eda7c62))\n- **ApplicationCommandPermissionsManager:** Remove incorrect comment (#10123) ([e9d6547](https://github.com/discordjs/discord.js/commit/e9d654772d1edb55e3aed69e7778e84c204b38e7))\n- Split docs.api.json into multiple json files ([597340f](https://github.com/discordjs/discord.js/commit/597340f288437c35da8c703d9b621274de60d880))\n- Convert comment into private remark (#10097) ([bfc7bb5](https://github.com/discordjs/discord.js/commit/bfc7bb55641c60d4d67e57c27c9d1e63b6f30c9b))\n- **BaseInteraction:** Correct return type of `member` (#10096) ([f48787e](https://github.com/discordjs/discord.js/commit/f48787eef183ff3ae24cf353c191f3c672c8de73))\n- **ThreadMember:** Fix docblock async return type (#10058) ([4824ac1](https://github.com/discordjs/discord.js/commit/4824ac154d89e5168754d46c5a55f3493c5ae14f))\n- **CategoryCreateChannelOptions:** Update reference (#10031) ([8ace6fa](https://github.com/discordjs/discord.js/commit/8ace6face82315d7e6453f49ca121663e36bcb1e))\n- **resolvePartialEmoji:** Add `@internal` to all overloads (#10033) ([e245a39](https://github.com/discordjs/discord.js/commit/e245a390e7b8c665e5dcd1dbfeb0265af91db4e7))\n- **PermissionOverwriteManager:** `PermissionsFlagsBit` typo (#10004) ([b992019](https://github.com/discordjs/discord.js/commit/b992019a78d4e35024fe9bb5536ec352672a2de9))\n- Fix links in @deprecated tags (#9976) ([9868772](https://github.com/discordjs/discord.js/commit/9868772b6418d521650c3690dd5f5172e2a36d00))\n\n## Features\n\n- **MessageManager:** Poll methods (#10239) ([6cf094c](https://github.com/discordjs/discord.js/commit/6cf094c28214c24fd70045e848c48bfb33eaf47a))\n- Consumable entitlements (#10235) ([9978870](https://github.com/discordjs/discord.js/commit/997887069a00b732e62ba7bdceed714e3ede1079))\n- Polls (#10185) ([a1aeaeb](https://github.com/discordjs/discord.js/commit/a1aeaeb9d804b126dd525b6090c6f2ff9591cb9c))\n- **ClientUser:** Add support for setting bot banner (#10176) ([de14c92](https://github.com/discordjs/discord.js/commit/de14c92c1158d3e5d7d87d29d2fe9d99eb407df5))\n- **GuildBanManager:** Add `bulkCreate()` method (#10182) ([b6bdd57](https://github.com/discordjs/discord.js/commit/b6bdd578b9c26158ce5552993e649e92c52f1024))\n- Local and preview detection ([79fbda3](https://github.com/discordjs/discord.js/commit/79fbda3aac6d4f0f8bfb193e797d09cbe331d315))\n- **MessageCreateOptions:** Add `enforceNonce` (#10129) ([992aa67](https://github.com/discordjs/discord.js/commit/992aa67841720bedb41829076580f22bbbdfbab6))\n- Add support for `using` keyword on discord.js `Client` and `WebSocketManager` (#10063) ([543d617](https://github.com/discordjs/discord.js/commit/543d61737e0709b9d88029d01156d48cfcaf3bcc))\n- **Webhook:** Allow setting `appliedTags` on `send()` (#10027) ([33674be](https://github.com/discordjs/discord.js/commit/33674be85ef705e35307a66ffdfa232059386ca6))\n- Premium application subscriptions (#9907) ([c4fcee3](https://github.com/discordjs/discord.js/commit/c4fcee3ef6021c440f162a5764d5d9465f06dc9b))\n- **website:** Show union members of type aliases (#10001) ([a44ada6](https://github.com/discordjs/discord.js/commit/a44ada661f14504b56102e081b1c7108f4d9b06e))\n\n## Performance\n\n- **Presence:** Prefer boolean client status comparison before activity checks (#10213) ([4ad2858](https://github.com/discordjs/discord.js/commit/4ad285804bfd72b157139dde61c3fd8ac2544322))\n\n## Refactor\n\n- **ThreadChannel:** Use single thread member endpoint (#10136) ([f500ad6](https://github.com/discordjs/discord.js/commit/f500ad6e2ee7e3cd75371bce37fc3908c19d6466))\n- Docs (#10126) ([18cce83](https://github.com/discordjs/discord.js/commit/18cce83d80598c430218775c53441b6b2ecdc776))\n- Remove usage of mixin on error classes (#10128) ([f48cb2a](https://github.com/discordjs/discord.js/commit/f48cb2a357b754ac1748d67dd71be93f9795e038))\n- **resolveColor:** Prioritise number type check (#10116) ([d4472f8](https://github.com/discordjs/discord.js/commit/d4472f85a57a13a9ddd90b877cca977d18be5dee))\n- **Messages:** Improve `ColorConvert` error (#10108) ([fc1f8ae](https://github.com/discordjs/discord.js/commit/fc1f8ae3748354cb2fc847bbc3e631d1adb7b2e6))\n- **formatters:** Add support for object and name param in `formatEmoji()` (#10076) ([7b8e0de](https://github.com/discordjs/discord.js/commit/7b8e0debebb944184b5817edd76cb0ac7e870993))\n- Document relevant types as `@internal` (#9974) ([2b8ac35](https://github.com/discordjs/discord.js/commit/2b8ac35e56f1684f696bda9bcd5f772eefb39fdc))\n- **ThreadMemberManager:** #remove accepts UserResolvable (#10000) ([179af38](https://github.com/discordjs/discord.js/commit/179af387d06fd38c40d7a51b73bb73b41b298c2a))\n\n## Typings\n\n- Add `Poll` to `Message` (#10245) ([cb961f5](https://github.com/discordjs/discord.js/commit/cb961f5be3369cc2fc7c65e84e3cea534c3fa683))\n- Generic for Webhook type (#10188) ([980a2b7](https://github.com/discordjs/discord.js/commit/980a2b71c7b2b27bcea58b6e9d98f16d5b509006))\n- Fix duplicate props in merged interfaces (#10160) ([a1010c6](https://github.com/discordjs/discord.js/commit/a1010c61f5978093d1a9ff087679a2d7ddff5b03))\n- Update accessibility modifiers on constructors (#10147) ([efa3cac](https://github.com/discordjs/discord.js/commit/efa3cac6f223d8781b1ebab857f1da6a25c3e6b4))\n- **Builder.from:** Fix wrong types (#10071) ([bfbd62e](https://github.com/discordjs/discord.js/commit/bfbd62e3e00ab47013f6f4a7a63c29074452de54))\n- Use readonly array / collection types for user input (#10045) ([bcd4c2c](https://github.com/discordjs/discord.js/commit/bcd4c2cb23a1121b06e00e0a39c364c7b1de6e8a))\n- **InteractionReplyOptions:** Allow setting `MessageFlags.SuppressNotifications` (#9199) ([c89c343](https://github.com/discordjs/discord.js/commit/c89c343b0a6f74fc760ae6a2dab42cc07fef6b39))\n- Replace Mixins with interface merging (#10094) ([54106db](https://github.com/discordjs/discord.js/commit/54106dbd8175881840654a1936988e05b5f60c1e))\n- **DirectoryChannel:** Ensure directory channels cannot contain user mentions when stringified (#10043) ([db56324](https://github.com/discordjs/discord.js/commit/db56324624b4eca706b487f425df990a2e44a369))\n- Change Awaitable<void> to void (#10017) ([1acc9ab](https://github.com/discordjs/discord.js/commit/1acc9abae2c3c6aafac464bd7a85be994b55737f))\n- Omit unnecessary methods from <ContextMenuCommandInteraction>.options (#10003) ([17a6f5d](https://github.com/discordjs/discord.js/commit/17a6f5d3c971bf8d47dfed37c96e064ae74535e3))\n- **InteractionWebhook:** Add `client` (#9997) ([30f6a5f](https://github.com/discordjs/discord.js/commit/30f6a5fc5666e2131270a5b358fca2a6948f0d57))\n\n# [14.14.1](https://github.com/discordjs/discord.js/compare/14.14.0...14.14.1) - (2023-11-12)\n\n## Bug Fixes\n\n- **Emoji:** `id` set as `undefined` edge case (#9953) ([cc07a28](https://github.com/discordjs/discord.js/commit/cc07a28f125be63a7f1132a5a07d317c160f9a89))\n- **BaseClient:** Default in objects properly (#9952) ([f93abf7](https://github.com/discordjs/discord.js/commit/f93abf7e35ab6793aa530ceadc279d8c80b7aebf))\n\n## Documentation\n\n- Use preferred nullable syntax (`?T` over `T | null`) (#9946) ([1e4ef35](https://github.com/discordjs/discord.js/commit/1e4ef35436cd134db70c1c3152e33342baf9d6b6))\n\n## Refactor\n\n- Use formatters (#9956) ([40726db](https://github.com/discordjs/discord.js/commit/40726db722c7851f4096cda29667ea4ee89da98b))\n\n## Typings\n\n- Use wrapper utilities (#9945) ([4bc1dae](https://github.com/discordjs/discord.js/commit/4bc1dae36f01649127774c40b14e778d65cf25c5))\n\n# [14.14.0](https://github.com/discordjs/discord.js/compare/14.13.0...14.14.0) - (2023-11-12)\n\n## Bug Fixes\n\n- **Client:** Ensure destroyed connections are not ready (#9942) ([b5e23ec](https://github.com/discordjs/discord.js/commit/b5e23ec2ecdfed1bb558e62adc3ac0b843ef64ca))\n- **Webhook:** Do not call `client.deleteWebhook` in `delete` (#9786) ([31d914e](https://github.com/discordjs/discord.js/commit/31d914e44b77ffd0d4511b5159e6869c04e8b1ec))\n- **GuildManager#fetch:** Inject shard id (#9921) ([85753a9](https://github.com/discordjs/discord.js/commit/85753a9d6fe569a3bc25dcdce2d6320fa61b8976))\n- Prevent 'undefined' debug message on intentional shard closure (#9846) ([0e0b85b](https://github.com/discordjs/discord.js/commit/0e0b85b76669237e3368e9ccef5278f47f7812d8))\n- **Role:** Calculate position correctly when rawPositions are equal (#9871) ([0529b2a](https://github.com/discordjs/discord.js/commit/0529b2af95a80478f52b906fa3f217cb47a3621b))\n- **GuildScheduledEvent:** Use `if...else` pattern and handle partials (#9802) ([32d614c](https://github.com/discordjs/discord.js/commit/32d614ccd389622e2969d59582f80d07a35eb39c))\n\n## Documentation\n\n- **Message:** Remove duplicated word 'of' in description (#9923) ([85a78f9](https://github.com/discordjs/discord.js/commit/85a78f96d4df637099bf650b41b3580e3891905c))\n- **GuildMember:** Clarify display color (#9891) ([e38d03f](https://github.com/discordjs/discord.js/commit/e38d03fbe7168f5f85c40c01be4df5b5e6ea4fc8))\n- Remove duplicate `APIEmoji` (#9880) ([8cfadb6](https://github.com/discordjs/discord.js/commit/8cfadb6953b86fbdb3ef3c94d14653c519c9ce17))\n- Consolidate API types (#9881) ([44a3cbf](https://github.com/discordjs/discord.js/commit/44a3cbf39e66b59f6bdec6568887374eeb5fe1f5))\n- Remove `FileOptions` (#9855) ([eaabcdf](https://github.com/discordjs/discord.js/commit/eaabcdfda651e7bad5b6e818b869e631a07e8a41))\n- **DiscordjsErrorCodes:** Deprecate unused properties (#9790) ([4588e07](https://github.com/discordjs/discord.js/commit/4588e075c3d0cd437b4057dbd2dde18639e98ae9))\n- **ApplicationCommandManager:** Id parameter can take options (#9664) ([ed14135](https://github.com/discordjs/discord.js/commit/ed1413584416149306b831bdcb88291b5d2a2612))\n- **Attachment:** Add MIME types link to `contentType` (#9824) ([85b2498](https://github.com/discordjs/discord.js/commit/85b24988a51dff74ffe0ab8186bad3a8370bfd5d))\n- Fix \"its\" typo (#9825) ([c50809e](https://github.com/discordjs/discord.js/commit/c50809e20648cacea99f5450e8073d960ff8aa39))\n- **GuildMember:** Clarify timeout parameter wording (#9800) ([8d97e2d](https://github.com/discordjs/discord.js/commit/8d97e2d2c551fcb1eb57a9550a5984135cdf2e67))\n- **create-discord-bot:** Support bun in create-discord-bot (#9798) ([7157748](https://github.com/discordjs/discord.js/commit/7157748fe3a69265896adf0450cd3f37acbcf97b))\n\n## Features\n\n- Default select menu values (#9867) ([4ff3ea4](https://github.com/discordjs/discord.js/commit/4ff3ea4a1bcb708973fbbbc84aaede1f7643e630))\n- Mainlib docs on new website (#9930) ([da455bc](https://github.com/discordjs/discord.js/commit/da455bceead521b10c32097b092fccc7a137471f))\n- **cleanContent:** Add slash commands and emojis (#9809) ([c2349d4](https://github.com/discordjs/discord.js/commit/c2349d4be45a2b2cfff7eaf2f227c69917fec77f))\n- **Emoji:** Add `imageURL()` (#9788) ([b6c762c](https://github.com/discordjs/discord.js/commit/b6c762cb843b21f57d2d0e1e79a16b3d565001a4))\n- Onboarding mode and edit method (#9647) ([7671a83](https://github.com/discordjs/discord.js/commit/7671a836f4b080a0c0d42bbbacc6ddd1df7c0ba8))\n- Support new application properties and patch endpoint (#9709) ([1fe7247](https://github.com/discordjs/discord.js/commit/1fe72475286775cdfc68dad251ed662db7375ad1))\n- **BaseChannel:** Add `isThreadOnly()` (#9847) ([699b232](https://github.com/discordjs/discord.js/commit/699b2329224ebffb483de75aac88255a7ee1e36e))\n- **StageInstanceManager:** Add `guildScheduledEvent` to `create()` (#8885) ([931c3ed](https://github.com/discordjs/discord.js/commit/931c3ed593d842e21568e039ed21855a53de4f2c))\n- Support `default_thread_rate_limit_per_user` in channel creation (#9273) ([1e5c14b](https://github.com/discordjs/discord.js/commit/1e5c14b74110fc1cae5e0bc605d30531e7ee7c4b))\n- Add media channels (#9662) ([571aedd](https://github.com/discordjs/discord.js/commit/571aedd58aeb5ac677f2a94a4a2851c4378a70b0))\n- Support widget image URL (#9782) ([b6a2441](https://github.com/discordjs/discord.js/commit/b6a244181971546b4b269ca96ec8b7235cd3015f))\n- **GuildAuditLogsEntry:** Expose extra integrationType in relevant log types (#9796) ([3109798](https://github.com/discordjs/discord.js/commit/310979808eb3a517ccf0f16d66a08c5cbf25ae0d))\n- Add support for teams update (#9805) ([c66636d](https://github.com/discordjs/discord.js/commit/c66636da11851e3b8c5a3136c2f95b10b2f8b2cc))\n- **Presence:** Expose sync_id in Activity (#9766) ([485dd71](https://github.com/discordjs/discord.js/commit/485dd718c57802ce620ec832cef8a708c711251a))\n\n## Refactor\n\n- **utils:** Remove `mergeDefault` (#9938) ([5b0aa92](https://github.com/discordjs/discord.js/commit/5b0aa92c8106aeaaefb473a926f57b1eae4bd9e4))\n- Use proper variable names in callbacks (#9840) ([11f6955](https://github.com/discordjs/discord.js/commit/11f6955ed9dfd4483c9c4dd6ac2ef4b020feb7f0))\n- **GuildAuditLogsEntry:** Abstract reduce logic into a new function (#9845) ([19ea0ba](https://github.com/discordjs/discord.js/commit/19ea0baa00e9b8671896ae857f4cdb2cdb6d69af))\n- Stickers are free (no more \"premium\" packs) (#9791) ([e02a59b](https://github.com/discordjs/discord.js/commit/e02a59bbb6f57c6935230d120867519c1e84d10a))\n\n## Typings\n\n- **Partials:** Add toString() method to supported Partials (#9835) ([7422d9f](https://github.com/discordjs/discord.js/commit/7422d9f172019fd5fbe93051512929506b122f93))\n- **MessageEditOptions:** Correct `attachments` type (#9874) ([2aa3250](https://github.com/discordjs/discord.js/commit/2aa325058464741d57114b538ce358ea4de3bcd2))\n- **UserContextMenuCommandInteraction:** Nullify `targetMember` (#9844) ([3c043d8](https://github.com/discordjs/discord.js/commit/3c043d83a93333d803f675cfe31feb62fe1999b1))\n- Don't include dom types (#9831) ([9dbc954](https://github.com/discordjs/discord.js/commit/9dbc9542c4ad91e75df509bc1e1de25515a88cfe))\n- **Client:** Fix isReady narrowing (#9828) ([6404c01](https://github.com/discordjs/discord.js/commit/6404c013e75c1d3baa1f1b15695315b76bb7acd6))\n\n# [14.13.0](https://github.com/discordjs/discord.js/compare/14.12.1...14.13.0) - (2023-08-17)\n\n## Bug Fixes\n\n- **Action:** Do not add the client user as a recipient (#9774) ([24fbb11](https://github.com/discordjs/discord.js/commit/24fbb11ba2f7e8f8f604752159d2053f2cee16ec))\n- **DMChannel:** Correct partial typo (#9773) ([c1ff545](https://github.com/discordjs/discord.js/commit/c1ff545bf1c018875f5a9ceb828c9f84ed391920))\n- **CachedManager:** Allow overriding constructor for makeCache (#9763) ([346fa57](https://github.com/discordjs/discord.js/commit/346fa57f95a99d5b4e1169bb85706c4c25bf71d0))\n- **types:** Fixed CachedManager constructor arguments in type (#9761) ([b3c85d3](https://github.com/discordjs/discord.js/commit/b3c85d34a6ced8a8e2cd15a6e3879fb2dd5121d0))\n- **Action:** Do not set `undefined` values (#9755) ([d8e3755](https://github.com/discordjs/discord.js/commit/d8e37551ceefe9f82566e3f45edc69bb7f9d1463))\n\n## Documentation\n\n- **EmbedBuilder:** `@readonly` length (#9778) ([8f572a6](https://github.com/discordjs/discord.js/commit/8f572a6badd45b916d3a46dd489653d2d6efb2a8))\n- **WebhookEditOptions:** Add all of the types (#9776) ([d5be424](https://github.com/discordjs/discord.js/commit/d5be4242c6a6f90b90af54e27071ecc0f5422944))\n- Update Node.js requirement to 16.11.0 (#9764) ([188877c](https://github.com/discordjs/discord.js/commit/188877c50af70f0d5cffb246620fa277435c6ce6))\n\n## Features\n\n- **Client:** Add deleteWebhook method (#9777) ([d90ba8d](https://github.com/discordjs/discord.js/commit/d90ba8dce8de630db14b77764ec35201998c7ce7))\n- **ClientPresence:** Allow setting activity state (#9743) ([9ed1b59](https://github.com/discordjs/discord.js/commit/9ed1b59df6acb6356d5950b43d04885d5e692887))\n- **ClientApplication:** Approximate guild count and new `GET` route (#9713) ([632a9b4](https://github.com/discordjs/discord.js/commit/632a9b4965cd24ffffdf0f88f1a9eedeb6b284f7))\n- **Role:** Add `flags` (#9694) ([3b18e5b](https://github.com/discordjs/discord.js/commit/3b18e5b08dc3ec2aba37d3e6a55e42ce8af7dbab))\n- **Attachment:** Add `flags` (#9686) ([692f0fc](https://github.com/discordjs/discord.js/commit/692f0fc96d9f92161b64fb83f02b71d43d2d7c9c))\n- Add `Client#webhooksUpdate` (#9732) ([0de071d](https://github.com/discordjs/discord.js/commit/0de071d0a5524ba1fbb8cab5d7e74567103f7129))\n\n## Typings\n\n- **GuildInvitableChannelResolvable:** Allow forum channels (#9775) ([727dc09](https://github.com/discordjs/discord.js/commit/727dc094d52a5b169e46917b64308ab87a7144b1))\n- Make activity name required (#9765) ([0a9a3ed](https://github.com/discordjs/discord.js/commit/0a9a3ede292b92235a103b6776477a707da4d84b))\n- **BaseButtonComponentData:** Narrow component type (#9735) ([a30d46c](https://github.com/discordjs/discord.js/commit/a30d46c5f5909eee86704bbb9e34fb7bb09b2c27))\n\n# [14.12.1](https://github.com/discordjs/discord.js/compare/14.12.0...14.12.1) - (2023-08-01)\n\n## Bug Fixes\n\n- **BaseClient:** Fix destroy method (#9742) ([1af7e5a](https://github.com/discordjs/discord.js/commit/1af7e5a0bb4eca35221cb342c1c53dc18263c789))\n\n# [14.12.0](https://github.com/discordjs/discord.js/compare/14.11.0...14.12.0) - (2023-07-31)\n\n## Bug Fixes\n\n- **ChannelUpdate:** Check against unknown channels (#9697) ([7fb91c5](https://github.com/discordjs/discord.js/commit/7fb91c57f72b74395d67f2207246033c703f1f19))\n- **Action:** Use existing recipients if available (#9653) ([719e54a](https://github.com/discordjs/discord.js/commit/719e54a921f74890519f066a9f56e52fdcfacf07))\n- Everyone role members (#9685) ([0803eb5](https://github.com/discordjs/discord.js/commit/0803eb562bdc7644fa611a0a87dea3e8b0d4c7af))\n- `awaitMessageComponent` with `MessageComponentInteraction`s (#8598) ([b61e4fb](https://github.com/discordjs/discord.js/commit/b61e4fb0dcb9e5d43a7626c5a4760f5801e06fae))\n- **ThreadManager:** Fix internal crash upon conditionally resolving thread members (#9648) ([a6dbe16](https://github.com/discordjs/discord.js/commit/a6dbe163dd3df12ad98465b1dfc040b8eff8805e))\n- **User:** Check global name in equals (#9631) ([8f3bd38](https://github.com/discordjs/discord.js/commit/8f3bd3807233fca2a057948406bdc8aef008b6cb))\n- **WebSocketManager:** Await WebSocket destroy (#9519) ([75308f2](https://github.com/discordjs/discord.js/commit/75308f266933454301b10ee8e1d940d782fdb637))\n- **Client:** Safe call for possibly null WebSocket (#9600) ([24a6149](https://github.com/discordjs/discord.js/commit/24a61495b9bf07887dd535a05ffbec2895faa888))\n- **ThreadManager:** Ensure `fetchActive()` only returns active threads in a channel (#9568) ([53aa24d](https://github.com/discordjs/discord.js/commit/53aa24d41809382c1af57bd1871107c8359e4a15))\n- **LimitedCollection:** Allow items to be stored if keepOverLimit is true when maxSize is 0 (#9534) ([9345d1b](https://github.com/discordjs/discord.js/commit/9345d1b1ac4f7b1f66b919602dff995782151407))\n- **AutocompleteInteraction:** Prevent snake casing of locales (#9565) ([7196fe3](https://github.com/discordjs/discord.js/commit/7196fe36e8089dde7bcaf0db4dd09cf524125e0c))\n\n## Documentation\n\n- Change `Channel` to `BaseChannel` (#9718) ([e5effb6](https://github.com/discordjs/discord.js/commit/e5effb6f6a3e547006eb9bc054cc168844a157f2))\n- **BaseChannel:** Remove `APIChannel` (#9717) ([125405f](https://github.com/discordjs/discord.js/commit/125405f1cf11433c69ff1ae9d6b8f7e713fc37c0))\n- **BuildersSelectMenuOption:** Update link (#9690) ([ede9f4e](https://github.com/discordjs/discord.js/commit/ede9f4e5e203bcfb8820ae7ec3418482735ff9c1))\n- **ClientOptions:** Change default value of sweepers in docs (#9591) ([911e6ef](https://github.com/discordjs/discord.js/commit/911e6eff75f5d05e837d5dfaacf557d6594df16a))\n- **Client:** Correct invite gateway permission checks (#9597) ([e1b6eee](https://github.com/discordjs/discord.js/commit/e1b6eeed0e2e18f9900bc945c9f82d2d05f28a78))\n- Fix broken links to new documentation (#9563) ([d01e8aa](https://github.com/discordjs/discord.js/commit/d01e8aa8af00f5caacffe98caef3ead02e80a9bf))\n\n## Features\n\n- Add ws option support for \"buildIdentifyThrottler\" (#9728) ([6307f81](https://github.com/discordjs/discord.js/commit/6307f813854ed9dc76d2c4351bd69dd0490d0928))\n- **Client:** Add `guildAvailable` event (#9692) ([3c85fb2](https://github.com/discordjs/discord.js/commit/3c85fb21e62b30e75a7200b704e242c3a0adeda1))\n- User avatar decorations (#8914) ([8d97017](https://github.com/discordjs/discord.js/commit/8d9701745840e23854e8f0b057d21cb10e7d1d54))\n- Add silent option to ShardingManager (#9506) ([df40dcd](https://github.com/discordjs/discord.js/commit/df40dcdb850c398642ebc5cd6e4c48034280f464))\n- **EmbedBuilder:** Add `.length` (#8682) ([53c17e0](https://github.com/discordjs/discord.js/commit/53c17e00c0668c3d1497142dde7384c058c46c64))\n- Guild onboarding (#9120) ([dc73c93](https://github.com/discordjs/discord.js/commit/dc73c938ff9d04a0d7d57630faeb8e81ea343006))\n- Add resume event in shard (#9650) ([a73d54e](https://github.com/discordjs/discord.js/commit/a73d54e43a01719f683e8fd21714e85ffe737add))\n- **presence:** Re-introduce image resolving for other platforms (#9637) ([73c2f8a](https://github.com/discordjs/discord.js/commit/73c2f8aa17aac51b05382444148cb1f60081ee03))\n- Add message to send resume event to shard (#9626) ([a873ec1](https://github.com/discordjs/discord.js/commit/a873ec1e8511829ba95e85bbc9a4074e40c76086))\n- Support new username system (#9512) ([1ab60f9](https://github.com/discordjs/discord.js/commit/1ab60f9da4d6b7ea144fa05b97b029a4bfaeede2))\n- **GuildAuditLogsEntry#extra:** Add missing `channel` property (#9518) ([2272321](https://github.com/discordjs/discord.js/commit/227232112d1cd9f211e177996b7cdee2940f471e))\n\n## Performance\n\n- **Channel:** Linear speed position getter (#9497) ([09b0382](https://github.com/discordjs/discord.js/commit/09b0382c458ed0f3df5b8fa778c504b3e658ac49))\n- **Role:** Improve `members` getter (#9529) ([37181ab](https://github.com/discordjs/discord.js/commit/37181ab2322e48e17ff0d1040bcc510dc7c34e93))\n\n## Refactor\n\n- **User:** Remove deprecation warning from tag (#9660) ([cf8012c](https://github.com/discordjs/discord.js/commit/cf8012c20022aff184d7bce0ad436c136e428d9c))\n- **GuildMember:** Make `_roles` property non-enumerable (#9387) ([46167a7](https://github.com/discordjs/discord.js/commit/46167a79d7d0cac5599459a31c33b2bbcf6e06da))\n- **rest:** Switch api to fetch-like and provide strategies (#9416) ([cdaa0a3](https://github.com/discordjs/discord.js/commit/cdaa0a36f586459f1e5ede868c4250c7da90455c))\n  - **BREAKING CHANGE:** NodeJS v18+ is required when using node due to the use of global `fetch`\n  - **BREAKING CHANGE:** The raw method of REST now returns a web compatible `Respone` object.\n  - **BREAKING CHANGE:** The `parseResponse` utility method has been updated to operate on a web compatible `Response` object.\n  - **BREAKING CHANGE:** Many underlying internals have changed, some of which were exported.\n  - **BREAKING CHANGE:** `DefaultRestOptions` used to contain a default `agent`, which is now set to `null` instead.\n\n## Typings\n\n- **MessageManager:** Allow comparison of messages again (#9612) ([a48d0ef](https://github.com/discordjs/discord.js/commit/a48d0efb09613eac6bf3c1bd996f58f5fff7667c))\n- **AutoModerationActionExecution:** Add forum channels as a possible type in `channel()` (#9623) ([d64330a](https://github.com/discordjs/discord.js/commit/d64330a1570b3a2047ef959a6bce268372c70e99))\n- **ModalSubmitFields:** Components is an array (#9406) ([1cab79f](https://github.com/discordjs/discord.js/commit/1cab79f6fde6f367141c9f7ed91bcb70ed2e5c17))\n- Use `readonly` arrays and `const` type parameters in places (#9641) ([cd69868](https://github.com/discordjs/discord.js/commit/cd6986854f4c2d143d2cd9b81d096738480dfa63))\n- **BaseInteraction:** `appPermissions` not `null` in guilds (#9601) ([6c2242f](https://github.com/discordjs/discord.js/commit/6c2242f4f970b1c75c243f74ae64f30ecbf8ba0d))\n\n# [14.11.0](https://github.com/discordjs/discord.js/compare/14.10.2...14.11.0) - (2023-05-06)\n\n## Bug Fixes\n\n- **WebSocketManager:** Properly emit shard error events (#9521) ([e627468](https://github.com/discordjs/discord.js/commit/e6274681fd10b0d75e1d3b448c94b50ec6810367))\n- **WebSocketManager:** Emit raw ws events again (#9502) ([c429763](https://github.com/discordjs/discord.js/commit/c429763be8e94f0f0cbc630e8bb1d415d46f1465))\n\n## Documentation\n\n- **Client:** Update Sapphire's snowflake utility links (#9501) ([1b7981e](https://github.com/discordjs/discord.js/commit/1b7981e4696b8ae74ceffa876fc0a9be7d0b9f93))\n\n## Features\n\n- **Guild:** Safety alerts channel and mention raid protection (#8959) ([6b2c3fb](https://github.com/discordjs/discord.js/commit/6b2c3fb9d0571de808e990cf064f73240ab93451))\n\n## Performance\n\n- **Role:** Linear speed position getter (#9493) ([8e9a2b4](https://github.com/discordjs/discord.js/commit/8e9a2b4630f78bb9e45345ec2a16812bfac70a20))\n\n## Refactor\n\n- **GuildChannel:** Simplify constructor (#9499) ([f2ad076](https://github.com/discordjs/discord.js/commit/f2ad0762c521422ab64e5b10344a6fd67961031b))\n\n## Typings\n\n- **StringSelectMenuComponentData:** `options` is required (#9515) ([d7b18f0](https://github.com/discordjs/discord.js/commit/d7b18f0681d4147ff192c98108c035d6d0f96cce))\n\n# [14.10.2](https://github.com/discordjs/discord.js/compare/14.10.1...14.10.2) - (2023-05-01)\n\n## Bug Fixes\n\n- Correct `isJSONEncodable()` import (#9495) ([201b002](https://github.com/discordjs/discord.js/commit/201b002ad405b845ace5f708077c1f157bb4126d))\n- **Client:** `generateInvite()` scope validation (#9492) ([b327f49](https://github.com/discordjs/discord.js/commit/b327f4925ff557e0aa8273d7f017aa616226ca06))\n\n# [14.10.1](https://github.com/discordjs/discord.js/compare/14.10.0...14.10.1) - (2023-05-01)\n\n## Bug Fixes\n\n- **Client:** Spelling of InvalidScopesWithPermissions ([ac9bf3a](https://github.com/discordjs/discord.js/commit/ac9bf3ac06ec78dbaca2ce4a82cceb0d82484211))\n\n## Refactor\n\n- **ShardClientUtil:** Logic de-duplication (#9491) ([a9f2bff](https://github.com/discordjs/discord.js/commit/a9f2bff82a18c6a3afdee99e5830e1d7b4da65dc))\n\n# [14.10.0](https://github.com/discordjs/discord.js/compare/14.9.0...14.10.0) - (2023-05-01)\n\n## Bug Fixes\n\n- **ShardClientUtil:** Fix client event names (#9474) ([ad217cc](https://github.com/discordjs/discord.js/commit/ad217cc7604dda6a33df73db82799fd5bb4e85a9))\n- **BaseClient:** Prevent user agent mutation (#9425) ([217e5d8](https://github.com/discordjs/discord.js/commit/217e5d81005a2506c96335f7fb96fa21d7dbb04c))\n- **BitField:** Use only enum names in iterating (#9357) ([40d07fb](https://github.com/discordjs/discord.js/commit/40d07fbbbd51d62793d9ea541f41f157b5dad224))\n- Use new permission name (#9274) ([d2d27ce](https://github.com/discordjs/discord.js/commit/d2d27ce7346bc37b34938c84bd3b106a4fa51f53))\n- **Message#editable:** Fix permissions check in locked threads (#9319) ([d4c1fec](https://github.com/discordjs/discord.js/commit/d4c1fecbe264bc52a70aaf0ec303d35e2f15bbcd))\n- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2))\n\n## Documentation\n\n- **AutoModerationRule:** Update docs (#9464) ([1b15d31](https://github.com/discordjs/discord.js/commit/1b15d31b5ae1b1739716fab00b18083c1d7d389a))\n- **APITypes:** Document role & user select menu components (#9435) ([c6ca5a8](https://github.com/discordjs/discord.js/commit/c6ca5a83e7b72613f95c2145606a1330f64ae894))\n- **BaseMessageOptions:** Fix embeds and components (#9437) ([5c52bb9](https://github.com/discordjs/discord.js/commit/5c52bb95906250518a8813820d543f43dd7abdf9))\n- **InteractionResponses:** ShowModal docs change (#9434) ([7d34100](https://github.com/discordjs/discord.js/commit/7d341000d44b762a2fe0434a6b518f7d63539d34))\n- Use ESM code in examples (#9427) ([ce287f2](https://github.com/discordjs/discord.js/commit/ce287f21d1540da7f17cac8a57dc33a67f391ef3))\n- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9))\n- **Options:** Fix links and invalid syntax (#9322) ([86e5f5a](https://github.com/discordjs/discord.js/commit/86e5f5a119c6d2588b988a33236d358ded357847))\n- Cleanup MessageCreateOptions and MessageReplyOptions (#9283) ([300059c](https://github.com/discordjs/discord.js/commit/300059cb266e6cca42c30ee7f997c48ab2cc565e))\n- **Events:** Document auto moderation events (#9342) ([79bcdfa](https://github.com/discordjs/discord.js/commit/79bcdfa767e7e842164e1174b6f4834ed731d329))\n- Add `SnowflakeUtil` (#9371) ([8ffcf77](https://github.com/discordjs/discord.js/commit/8ffcf77840b62590fcb4731380d28b22d0b98741))\n- Use stable tag (#9343) ([c0f2dd7](https://github.com/discordjs/discord.js/commit/c0f2dd713151a29c98e1eebad66721a208be1fc0))\n- Remove `JSONEncondable` (#9344) ([b2eec5f](https://github.com/discordjs/discord.js/commit/b2eec5f9fcf37ebb3b7f87a67a6ee3160c182183))\n\n## Features\n\n- **Attachment:** Voice messages (#9392) ([3e01f91](https://github.com/discordjs/discord.js/commit/3e01f91bbba2cbacacc6c921ed664752f679960b))\n- **BaseInteraction:** Support new channel payload (#9337) ([29389e3](https://github.com/discordjs/discord.js/commit/29389e39f479b832e54c7cb3ddd363aebe99674f))\n- **RoleTagData:** Add guildConnections (#9366) ([2dddbe1](https://github.com/discordjs/discord.js/commit/2dddbe1f321f2e2722dba4a28f7d18384cf50353))\n\n## Performance\n\n- **RoleManager:** Dont call Role#position getter twice per role (#9352) ([bfee6c8](https://github.com/discordjs/discord.js/commit/bfee6c8d889502ea39ad919dd9b1e6253a2af571))\n\n## Refactor\n\n- **WebSocketManager:** Use /ws package internally (#9099) ([a9e0de4](https://github.com/discordjs/discord.js/commit/a9e0de4288ea39a6a089b8379dcd44ac0053dac7))\n- Remove `fromInteraction` in internal channel creation (#9335) ([794abe8](https://github.com/discordjs/discord.js/commit/794abe8450bae000cd0544922cdf53e7b3e4c59c))\n\n## Typings\n\n- **AutoModerationActionMetadataOptions:** Make channel property optional (#9460) ([d26df5f](https://github.com/discordjs/discord.js/commit/d26df5fabaf227fb9d10ba5cc1ab326de55aadbc))\n- **CategoryChannel:** Ensure `parent` and `parentId` are `null` (#9327) ([8218ffc](https://github.com/discordjs/discord.js/commit/8218ffc78d23234b32c05a97fde2f4bea64d7aa6))\n- **GuildTextBasedChannel:** Remove unnecessary exclusion of forum channels (#9326) ([7ff3d52](https://github.com/discordjs/discord.js/commit/7ff3d528d942a0daa990194915ff8328dec99149))\n\n# [14.9.0](https://github.com/discordjs/discord.js/compare/14.8.0...14.9.0) - (2023-04-01)\n\n## Bug Fixes\n\n- Add support for new guild feature `GUILD_WEB_PAGE_VANITY_URL` (#9219) ([de1aac6](https://github.com/discordjs/discord.js/commit/de1aac674acb3830124646fcd52cdd98cdb71ba5))\n- Resolving string bitfield (#9262) ([7987565](https://github.com/discordjs/discord.js/commit/79875658cf4a8daa25210c2c620c73a710ca22de))\n- **AutocompleteInteraction:** Send `name_localizations` correctly (#9238) ([1864d37](https://github.com/discordjs/discord.js/commit/1864d37d36e53d127e74b6969a5f542193bfc3c7))\n- Keep symbols in actions manager (#9293) ([984bd55](https://github.com/discordjs/discord.js/commit/984bd55b437507e7ebfdf09ac944c8eba0340d27))\n- **scripts:** Accessing tsComment ([d8d5f31](https://github.com/discordjs/discord.js/commit/d8d5f31d3927fd1de62f1fa3a1a6e454243ad87b))\n- **ClientUser:** No mutation on edit (#9259) ([abd6ae9](https://github.com/discordjs/discord.js/commit/abd6ae9fc8ea03722e8b36e29c3fdc1c2cfc93e8))\n- **Message#editable:** Update editable check in threads locked (#9216) ([22e880a](https://github.com/discordjs/discord.js/commit/22e880aaa0d8c644fc8d16a524d17f4f53a056f6))\n- **ThreadManager:** Add `members` and conditionally include `hasMore` (#9164) ([e9a8eb3](https://github.com/discordjs/discord.js/commit/e9a8eb323f3a554dc8f9dab361cd1bac7b88e1cc))\n- **ThreadManager:** Respect `cache` and `force` in fetching (#9239) ([cc57563](https://github.com/discordjs/discord.js/commit/cc57563e73d78a0d71d1444d1ee8215a26a81fa8))\n- **TextBasedChannelTypes:** Add `GuildStageVoice` (#9232) ([51edba7](https://github.com/discordjs/discord.js/commit/51edba78bc4d4cb44b4dd2b79e4bbc515dc46f5b))\n\n## Documentation\n\n- Describe private properties (#8879) ([2792e48](https://github.com/discordjs/discord.js/commit/2792e48119f1cf5fa7d5e6b63369457b0719d4e4))\n- Differ `User#send` (#9251) ([384b4d1](https://github.com/discordjs/discord.js/commit/384b4d10e8642f0f280ea1651f33cd378c341333))\n- Fix compare position example (#9272) ([d16114c](https://github.com/discordjs/discord.js/commit/d16114c52646ca92c53f9b44a0dd10af98dbddcd))\n- **Role:** Fix example for `comparePositionTo()` (#9270) ([bc641fa](https://github.com/discordjs/discord.js/commit/bc641fa9360b851642bc51839cef6bd5600d71f7))\n- Add more examples (#9252) ([bf507ab](https://github.com/discordjs/discord.js/commit/bf507ab2659d95e2991e83293b3834f21283ff33))\n- **FetchArchivedThreadOptions:** `before` respects `archive_timestamp`, not creation timestamp (#9240) ([178c8dc](https://github.com/discordjs/discord.js/commit/178c8dcfeea1c4a6a32835baea389f25feefbac7))\n- Update `APISelectMenuComponent` (#9235) ([56cf138](https://github.com/discordjs/discord.js/commit/56cf138e029e7884a4e7efb606055687ca67b4ac))\n\n## Features\n\n- **Guild:** Add `max_stage_video_channel_users` (#8422) ([34bc36a](https://github.com/discordjs/discord.js/commit/34bc36ac4b04ad033d0dcc3d2701fcf2e682743c))\n- **website:** Render syntax and mdx on the server (#9086) ([ee5169e](https://github.com/discordjs/discord.js/commit/ee5169e0aadd7bbfcd752aae614ec0f69602b68b))\n- Add GuildBasedTextChannelTypes (#9234) ([5f93dcc](https://github.com/discordjs/discord.js/commit/5f93dcce466286f0fdead8faf4131e98d1c9db55))\n\n## Refactor\n\n- Call `GuildBanManager#create()` directly (#9263) ([f340f3b](https://github.com/discordjs/discord.js/commit/f340f3b1fd719e8f7cf6fa28a41835bc16039fc7))\n- **FetchThreadsOptions:** Remove `active` (#9241) ([519e163](https://github.com/discordjs/discord.js/commit/519e163f8aa3b55420f86d2d60c2584b3a2eb327))\n\n# [14.8.0](https://github.com/discordjs/discord.js/compare/14.7.1...14.8.0) - (2023-03-12)\n\n## Bug Fixes\n\n- **snowflake:** Snowflakes length (#9144) ([955e8fe](https://github.com/discordjs/discord.js/commit/955e8fe312c42ad4937cc1994d1d81e517c413c8))\n- **Actions:** Inject built data by using a symbol (#9203) ([a63ac88](https://github.com/discordjs/discord.js/commit/a63ac88fcca5b61209892a6e560e35d58f5adc3b))\n- **Message#deletable:** Add check for deletable message types (#9168) ([e78b8ad](https://github.com/discordjs/discord.js/commit/e78b8ad3fb6692cba2c565b508254c723f185f0c))\n- **Message:** `bulkDeletable` permissions should be retrieved later for DMs (#9146) ([a9495bd](https://github.com/discordjs/discord.js/commit/a9495bd8f014c8021a214b83ffc531a2af5defef))\n- **AutoModerationActionExecution:** Transform `action` (#9111) ([9156a28](https://github.com/discordjs/discord.js/commit/9156a2889cd0946dfd0b30a5f8365abfbc377b3d))\n- **MessageReaction:** `toJSON()` infinite recursion (#9070) ([f268e1d](https://github.com/discordjs/discord.js/commit/f268e1d9798744e169ae87089ea2e1f214364d95))\n- **ThreadChannel:** Insert starter message from threads created in forum channels (#9100) ([0b76ab4](https://github.com/discordjs/discord.js/commit/0b76ab4c403dd646c71482856ab993b263b7c474))\n- **ApplicationRoleConnectionMetadata:** Export the class correctly (#9076) ([071516c](https://github.com/discordjs/discord.js/commit/071516c35239bd4e1cae572c855d86b335c8536d))\n- Don't auth for interaction `showModal()` (#9046) ([b803a9a](https://github.com/discordjs/discord.js/commit/b803a9a899aaa75a3ea2bc6623c6afb28f495e8c))\n- **WebSocketShard:** Zombie connection fix (#8989) ([876b181](https://github.com/discordjs/discord.js/commit/876b1813128ec702d3ef1e7b0074a4613e88c332))\n- Keep other properties in triggerMetadata (#8977) ([d8dd197](https://github.com/discordjs/discord.js/commit/d8dd197a936dfffc05f9e5bc3184ec9022c56b51))\n- **escapeX:** Emojis with underlines (#8945) ([07b597d](https://github.com/discordjs/discord.js/commit/07b597df16b9412c23ec2387d54564e4d1bcf7ed))\n- **WebSocketShard:** Either start close timeout or emit destroyed but never both (#8956) ([43ce2a5](https://github.com/discordjs/discord.js/commit/43ce2a572eb8977b6994680171ac0c5f9bda1703))\n- **DMChannel:** `recipientId` edge case (#8950) ([7ce9909](https://github.com/discordjs/discord.js/commit/7ce990954e2f73d7a996df0afa42ab287cb12514))\n- Return only boolean for `disabled` (#8965) ([6614603](https://github.com/discordjs/discord.js/commit/66146033268a4db1279b2eaee4bd418f326c0d4b))\n- Export missing `escapeX()` functions (#8944) ([25c27ea](https://github.com/discordjs/discord.js/commit/25c27eac1417e75c9b601b17cf177b1f47b699a9))\n- **WebSocketShard:** Only cleanup the connection if a connection still exists (#8946) ([5eab5fc](https://github.com/discordjs/discord.js/commit/5eab5fc06ca6be36ecf1557f2ad29a670d4d5ae7))\n- Add `@discordjs/formatters` to dependency list (#8939) ([18b3a19](https://github.com/discordjs/discord.js/commit/18b3a19810a6436fa8bb4b490ec5137eaecbd465))\n- **resolveColor:** Invalid colors (#8933) ([c76e170](https://github.com/discordjs/discord.js/commit/c76e17078602914c3e1d227a3acc98eaa99c18d4))\n- **WebSocketShard:** Clear listeners on reconnect (#8927) ([aa8c57d](https://github.com/discordjs/discord.js/commit/aa8c57dab60104549e28451abf35c0387595d67e))\n- Re-export formatters (#8909) ([b14604a](https://github.com/discordjs/discord.js/commit/b14604abdecca575b1fca693c1593e3585bcca8c))\n\n## Documentation\n\n- **MessageManager:** Add clarification to fetch messages (#9222) ([f5ec1ca](https://github.com/discordjs/discord.js/commit/f5ec1cada5ebf0ca4093bdfc81aaf56900c794ef))\n- Make interactionResponse as optional (#9179) ([664cccb](https://github.com/discordjs/discord.js/commit/664cccb2706db33635aa2556954de57f93b3d3db))\n- Fix typos (#9127) ([1ba1f23](https://github.com/discordjs/discord.js/commit/1ba1f238f04221ec890fc921678909b5b7d92c26))\n- **chatInputApplicationCommandMention:** Parameters are not nullable (#9091) ([6f78e82](https://github.com/discordjs/discord.js/commit/6f78e8285b3ce762de010e68d49b377a47dc5a63))\n- No `@type` description and reveal info block (#9097) ([405f940](https://github.com/discordjs/discord.js/commit/405f9400e8e3ffea9f3847ab5abb431a34538a96))\n- **ThreadEditOptions:** Move info tag back to `invitable` (#9020) ([f3fe3ce](https://github.com/discordjs/discord.js/commit/f3fe3ced622676b406a62b43f085aedde7a621aa))\n- Fix a typo in the MentionableSelectMenuInteraction link (#9000) ([6d7a143](https://github.com/discordjs/discord.js/commit/6d7a143667f33ef2ea45d8016ac4738237707881))\n- **ApplicationRoleConnectionMetadata:** Add documentation (#8976) ([2e22b31](https://github.com/discordjs/discord.js/commit/2e22b31892d9b858fcb24fa580b486b4154e823f))\n- Fix malformed overridden documentation (#8954) ([0b8b114](https://github.com/discordjs/discord.js/commit/0b8b114761f961a2bf8e5aae342ed711b154a89e))\n- **GuildForumThreadManager:** Fix `sticker` type (#8940) ([dd62be0](https://github.com/discordjs/discord.js/commit/dd62be077d3e4fbd73a0c10ca344d93d3d19fa38))\n- Fix deprecated links (#8907) ([976b234](https://github.com/discordjs/discord.js/commit/976b234e9dc9999e5dee47b58c85afbc1cd494c2))\n- **UserFlagsBitField:** Make `.Flags` static (#8902) ([c48ff5e](https://github.com/discordjs/discord.js/commit/c48ff5e4205899e3b6cd35812ca857236bef6864))\n\n## Features\n\n- **Collector:** Add lastCollectedTimestamp (#9044) ([4458a13](https://github.com/discordjs/discord.js/commit/4458a13925164762b519ded1037ae8775d879f71))\n- **StageChannel:** Add messages (#9134) ([ffdb197](https://github.com/discordjs/discord.js/commit/ffdb197f988657100e2a9ff0ca17b759339a1dda))\n- **AutoModerationActionExecution:** Add `channel`, `user` and `member` getters (#9142) ([095bd77](https://github.com/discordjs/discord.js/commit/095bd77515aa31bb0e95a350b4355980fea9268d))\n- **AutoModeration:** Support `custom_message` (#9171) ([c1000b8](https://github.com/discordjs/discord.js/commit/c1000b86ed6d5413afcd6ee7e80505e5a845430b))\n- **ThreadMemberManager:** Support pagination fetching (#9035) ([765d5a3](https://github.com/discordjs/discord.js/commit/765d5a3b2d5529c3a2a4b29512f6932264443ed1))\n- **InteractionResponse:** Add new methods (#9132) ([dc9924f](https://github.com/discordjs/discord.js/commit/dc9924fb5f24c8dac963d6b86ba279a89545e73b))\n- **GuildMember:** Add `flags` (#9087) ([76b2116](https://github.com/discordjs/discord.js/commit/76b21162aca7cd4897826437da3063524e1e7553))\n- **Client:** `guildAuditLogEntryCreate` event (#9058) ([9439107](https://github.com/discordjs/discord.js/commit/9439107a1d6a9b77b5f991973d96bc6100da4753))\n- Add role subscription data (#9025) ([1ba22f4](https://github.com/discordjs/discord.js/commit/1ba22f4c9e4173f8866339d3eadb2939d4b32034))\n- **Sticker:** Add support for gif stickers (#9038) ([6a9875d](https://github.com/discordjs/discord.js/commit/6a9875da054a875a4711394547d47439bbe66fb6))\n- **GuildAuditLogs:** Support `after` (#9011) ([0076589](https://github.com/discordjs/discord.js/commit/0076589ccc93e09d77a448874d1ceff5d0e91aa2))\n- Add role subscriptions (#8915) ([3407e1e](https://github.com/discordjs/discord.js/commit/3407e1eea3c8d5629465553f342ac30ceae27a47))\n- Add `not_found` to guild member chunk data (#8975) ([be294ea](https://github.com/discordjs/discord.js/commit/be294eaf9901ea139ce485deeec9178959ffa91f))\n- **ClientApplication:** Add role connections (#8855) ([22e2bbb](https://github.com/discordjs/discord.js/commit/22e2bbb0d24e3f30516f262308d5786f2f666713))\n- **CommandInteractionOptionResolver:** Add `channelTypes` option to `getChannel` (#8934) ([429dbcc](https://github.com/discordjs/discord.js/commit/429dbccc85cabd9986b2e8bf443bf384e4ddc61a))\n- **ForumChannel:** Add `defaultForumLayout` (#8895) ([cbafd47](https://github.com/discordjs/discord.js/commit/cbafd479b331633ed97f7b1a22ef03c6a2f4cf31))\n- Add support for nsfw commands (#7976) ([7a51344](https://github.com/discordjs/discord.js/commit/7a5134459c5f06864bf74631d83b96d9c21b72d8))\n- **InteractionResponse:** CreatedTimestamp (#8917) ([627511d](https://github.com/discordjs/discord.js/commit/627511d6522f772b84c25e6a3f6da06b06bb912e))\n- **Guild:** Add disableInvites method (#8801) ([45faa19](https://github.com/discordjs/discord.js/commit/45faa199820e7c4ccdb2997c7e3b353f566d2312))\n\n## Refactor\n\n- Compare with `undefined` directly (#9191) ([869153c](https://github.com/discordjs/discord.js/commit/869153c3fdf155783e7c0ecebd3627b087c3a026))\n- **GuildMemberManager:** Tidy up fetching guild members (#8972) ([4e0e125](https://github.com/discordjs/discord.js/commit/4e0e1250399aa12c340ac92a86ec2c05704fe2bb))\n- **BitField:** Reverse iterator/toArray responsibilities (#9118) ([f70df91](https://github.com/discordjs/discord.js/commit/f70df910ed12e397066d0bdb27343af21ead4d92))\n- Moved the escapeX functions from discord.js to @discord.js/formatters (#8957) ([13ce78a](https://github.com/discordjs/discord.js/commit/13ce78af6e3aedc793f53a099a6a615df44311f7))\n- Use `deprecate()` directly (#9026) ([1c871b5](https://github.com/discordjs/discord.js/commit/1c871b5b576dddef12c5afacecf416dbd6243dea))\n- **Guild:** Destructure object in guild editing (#8971) ([d3e9f2a](https://github.com/discordjs/discord.js/commit/d3e9f2a355a1f5272d62a507eb6ecd8808904fff))\n- **GuildManager:** Better handling of creation code (#8974) ([d7a09f6](https://github.com/discordjs/discord.js/commit/d7a09f6fcee30c31b4418166bf7bf9e894841f87))\n- **sharding:** Use switch statement (#8928) ([6540914](https://github.com/discordjs/discord.js/commit/6540914b4a7f244f5e40fe2a3b7e73986763d81b))\n- Use consistent naming for options (#8901) ([a7b55c1](https://github.com/discordjs/discord.js/commit/a7b55c1460cf63fb482f7d05657120eec96bee82))\n- **CommandInteractionOptionResolver:** Loosen mentionable checks (#8910) ([1b151db](https://github.com/discordjs/discord.js/commit/1b151db59c4340417f8a28a88064f45336ac8c78))\n\n## Styling\n\n- Run prettier (#9041) ([2798ba1](https://github.com/discordjs/discord.js/commit/2798ba1eb3d734f0cf2eeccd2e16cfba6804873b))\n\n## Typings\n\n- Allow sending messages with `SuppressNotifications` flag (#9177) ([71a427f](https://github.com/discordjs/discord.js/commit/71a427f6322be76fe2d1cb265de09f171b1b354a))\n- Remove `EscapeMarkdownOptions` (#9153) ([fd0246c](https://github.com/discordjs/discord.js/commit/fd0246ca4c75e60d8e117d9ac5af7067c7a63277))\n- **Attachment:** Make `attachment` private (#8982) ([da23cd5](https://github.com/discordjs/discord.js/commit/da23cd5d69de4856d075f00738f75c68c555ae5b))\n- Fix type of Attachment#name (#9101) ([4e0a89f](https://github.com/discordjs/discord.js/commit/4e0a89f58f43f362bfde80d8319dce767c62850f))\n- Allow builders to set channel types in discord.js (#8990) ([7dec892](https://github.com/discordjs/discord.js/commit/7dec892218f7b470a5f8e78732a524a53da24d26))\n- Swap message reaction and emoji identifier types (#8969) ([ad49845](https://github.com/discordjs/discord.js/commit/ad4984526020f2baeefaeeebbded66c6848c4b85))\n- **widget:** Add missing `name` (#8978) ([898b5ac](https://github.com/discordjs/discord.js/commit/898b5ac416cbbb415b125bb27221d0901fdd180e))\n- Use StringSelectMenuOptionBuilder (#8949) ([bec51de](https://github.com/discordjs/discord.js/commit/bec51de1038c35c6edaaa13934781758fe1951de))\n- Fix actions type in automod (#8962) ([5915f39](https://github.com/discordjs/discord.js/commit/5915f39810b712c05a46fa21ab4e12b4cfa3c25a))\n- Subcommand group `options` is required (#8966) ([5dc5e90](https://github.com/discordjs/discord.js/commit/5dc5e902688fc563087cd5061dcb59dd68fd4eda))\n- Add generic to `ActionRowBuilder.from()` (#8414) ([153352a](https://github.com/discordjs/discord.js/commit/153352ad7a1ccb4a9461523cf2597d81df93b69c))\n\n# [14.7.1](https://github.com/discordjs/discord.js/compare/14.7.0...14.7.1) - (2022-12-01)\n\n## Bug Fixes\n\n- Prevent crash on no select menu option (#8881) ([11d195d](https://github.com/discordjs/discord.js/commit/11d195d04ff57d51adb0f0d3a0a7342f9e34aba0))\n\n# [14.7.0](https://github.com/discordjs/discord.js/compare/14.6.0...14.7.0) - (2022-11-28)\n\n## Bug Fixes\n\n- **MessageMentions:** Add `InGuild` generic (#8828) ([f982803](https://github.com/discordjs/discord.js/commit/f9828034cd21e6f702762a46923e0f42115596f6))\n- **Activity:** Fix equals() not checking for differing emoji (#8841) ([7e06f68](https://github.com/discordjs/discord.js/commit/7e06f68185423ba7cb310220b213f445b6571e29))\n- Fixed react/astro/guide/discord.js build, updated dependencies, fix crawlvatar (#8861) ([d0c8256](https://github.com/discordjs/discord.js/commit/d0c82561b8a1765a1daa362ca903f3ffb3fa33ee))\n- **escapeMarkdown:** Fix double escaping (#8798) ([d6873b7](https://github.com/discordjs/discord.js/commit/d6873b7159352479475b3a0daa215bddbdd3a79b))\n- **Transfomers:** Call `.toJSON` in `toSnakeCase` (#8790) ([017f9b1](https://github.com/discordjs/discord.js/commit/017f9b1ed4014dc1db0b78c1a77e463b4403de5d))\n- Censor token in debug output (#8764) ([53d8e87](https://github.com/discordjs/discord.js/commit/53d8e87d7f3a329608250656950bd0a200adb1c7))\n- Pin @types/node version ([9d8179c](https://github.com/discordjs/discord.js/commit/9d8179c6a78e1c7f9976f852804055964d5385d4))\n\n## Documentation\n\n- Describe InteractionEditReplyOptions (#8840) ([cb77fd0](https://github.com/discordjs/discord.js/commit/cb77fd02d083438de2aff6f0769baf7d1797bc65))\n- **AutoModerationRuleManager:** Describe cache (#8848) ([d275480](https://github.com/discordjs/discord.js/commit/d2754802cc3479e6288cdbfcd48c76bf57e09a07))\n- Fix message action row components (#8819) ([65bc0ad](https://github.com/discordjs/discord.js/commit/65bc0adbf4d7870d33b92585ca18f964f24bc84e))\n- Specify `ActionRowBuilder` for `components` (#8834) ([8ed5c1b](https://github.com/discordjs/discord.js/commit/8ed5c1beb622f71ce0bd89e4cbeff50e464da8fe))\n- Add `@extends` for select menu classes (#8824) ([09f65b7](https://github.com/discordjs/discord.js/commit/09f65b724b0d2f36bbe89b83570c0d18093b5126))\n- Make WebSocketShard.lastPingTimestamp public (#8768) ([68c9cb3](https://github.com/discordjs/discord.js/commit/68c9cb37bc3df6326b720291827ea477e421faf2))\n- **MessageReplyOptions:** Remove duplicate stickers field (#8766) ([6e348ff](https://github.com/discordjs/discord.js/commit/6e348ffd1d8db8d8ad2da7823460814695e01a43))\n\n## Features\n\n- **Webhook:** Add `channel` property (#8812) ([decbce4](https://github.com/discordjs/discord.js/commit/decbce401062af75f633e6acacc88207b115a719))\n- Auto Moderation (#7938) ([fd4ba5e](https://github.com/discordjs/discord.js/commit/fd4ba5eaba66898699127fc0d5f0ab52c18e3db0))\n- **SelectMenuInteractions:** Add `values` property (#8805) ([b2fabd1](https://github.com/discordjs/discord.js/commit/b2fabd130a76ea54cfbfa1b871ef8659513c2c7a))\n- **ThreadChannel:** Add a helper for pin and unpin (#8786) ([e74aa7f](https://github.com/discordjs/discord.js/commit/e74aa7f6b0fe04e3473fc4a62a73a7db87307685))\n- Add `Message#bulkDeletable` (#8760) ([ff85481](https://github.com/discordjs/discord.js/commit/ff85481d3e7cd6f7c5e38edbe43b27b104e82fba))\n- New select menus (#8793) ([5152abf](https://github.com/discordjs/discord.js/commit/5152abf7285581abf7689e9050fdc56c4abb1e2b))\n- **InteractionResponses:** Add message parameter (#8773) ([8b400ca](https://github.com/discordjs/discord.js/commit/8b400ca975c6bad00060b9c67068f42bd53524ba))\n- Support resume urls (#8784) ([88cd9d9](https://github.com/discordjs/discord.js/commit/88cd9d906074eb79e85df0ef49287f11133d2e0d))\n- Allow deletion of ephemeral messages (#8774) ([fc10774](https://github.com/discordjs/discord.js/commit/fc107744618857bf28c2167f204253baf690ede8))\n- **GuildChannelManager:** Add `.addFollower()` method (#8567) ([caeb1cb](https://github.com/discordjs/discord.js/commit/caeb1cbfdb2f2f007252c4d7e9f47a575c24bcb5))\n\n## Refactor\n\n- **Embed:** Use `embedLength` function from builders (#8735) ([cb3826c](https://github.com/discordjs/discord.js/commit/cb3826ce6dbcd3cf7ab639af6cdfcea80336aa1d))\n\n# [14.6.0](https://github.com/discordjs/discord.js/compare/14.5.0...14.6.0) - (2022-10-10)\n\n## Bug Fixes\n\n- **ClientOptions:** Make `ClientOptions#intents` returns an IntentsBitField (#8617) ([4c2955a](https://github.com/discordjs/discord.js/commit/4c2955a5de6779c29c09e63ba9ad2b235904f842))\n- Correctly construct a builder (#8727) ([e548e6a](https://github.com/discordjs/discord.js/commit/e548e6a10b7e1720f5e8f3c859b0b64d5134a012))\n- **Components:** Error with unknown components (#8724) ([6fd331d](https://github.com/discordjs/discord.js/commit/6fd331dd528e78fd023c908bd58af3faa9ed6c65))\n- **Client:** Don't auth for webhook fetches with token (#8709) ([01d75c8](https://github.com/discordjs/discord.js/commit/01d75c8b8b14f33c95a4da83a8494db848beeb8c))\n- Re-export util (#8699) ([a306219](https://github.com/discordjs/discord.js/commit/a306219673335584accd2ff77ab34d2812ef6c5d))\n- Throw discord.js errors correctly (#8697) ([ace974f](https://github.com/discordjs/discord.js/commit/ace974fc1fdbc5bcaa0d7f6f6d17de185c9f9cbf))\n\n## Documentation\n\n- **Utils:** Remove `private` from `parseEmoji` (#8718) ([a31e605](https://github.com/discordjs/discord.js/commit/a31e605e09064a300e31a3c91466b613654ba98e))\n- Update UserContextMenuCommandInteraction documentation (#8717) ([7556db2](https://github.com/discordjs/discord.js/commit/7556db243d9480949835668fcb5724fdd5d70e08))\n- Fix `AwaitMessageComponentOptions` typedef (#8696) ([9effd82](https://github.com/discordjs/discord.js/commit/9effd82abe82ba71ae627673da21ba07e1ede23e))\n\n## Features\n\n- **Util:** Escape more markdown characters (#8701) ([7b8966b](https://github.com/discordjs/discord.js/commit/7b8966bca156db79933403289741893a6e10ccd5))\n- **GuildChannelManager:** Allow creating channels with a default auto archive duration (#8693) ([628759b](https://github.com/discordjs/discord.js/commit/628759bcff8b0d4c77926cee2b8c18d8fdb4c260))\n- Add `@discordjs/util` (#8591) ([b2ec865](https://github.com/discordjs/discord.js/commit/b2ec865765bf94181473864a627fb63ea8173fd3))\n- **ForumChannel:** Add `defaultSortOrder` (#8633) ([883f6e9](https://github.com/discordjs/discord.js/commit/883f6e9202a559c986f4b15fccb422b5aea7bea8))\n\n## Refactor\n\n- Rename Error to DiscordjsError internally (#8706) ([aec44a0](https://github.com/discordjs/discord.js/commit/aec44a0c93f620b22242f35e626d817e831fc8cb))\n\n## Typings\n\n- Fix events augmentation (#8681) ([ac83ada](https://github.com/discordjs/discord.js/commit/ac83ada306ec153c13260d2bd53e4d704884b68a))\n- **Message:** Remove `& this` from `#inGuild` typeguard (#8704) ([c0f7a1a](https://github.com/discordjs/discord.js/commit/c0f7a1a89a4cf62edc7065bd200b2ce4018e0a27))\n- **ModalBuilder:** Fix constructor typings (#8690) ([2ea2a85](https://github.com/discordjs/discord.js/commit/2ea2a85e6335d57f44689f9b6e284129104de8fc))\n\n# [14.5.0](https://github.com/discordjs/discord.js/compare/14.4.0...14.5.0) - (2022-09-25)\n\n## Bug Fixes\n\n- **ThreadChannel:** Add forum channel to parent (#8664) ([0126d9b](https://github.com/discordjs/discord.js/commit/0126d9b810a156c4bf1b8b93f2121f3319855bac))\n- **GuildChannelManager:** Allow creating webhooks on forums (#8661) ([16fcdc3](https://github.com/discordjs/discord.js/commit/16fcdc36877d1a65ce9995c9fe3502aa268c9388))\n- **ForumChannel:** Implement missing properties and methods (#8662) ([8622939](https://github.com/discordjs/discord.js/commit/862293922924f453f69b0b0f8efe87ddebbd387d))\n- RepliableInteraction respect cached generic (#8667) ([578bc95](https://github.com/discordjs/discord.js/commit/578bc951bdcdc21ec5aee86e7a47a17e8c867dfc))\n- **ThreadChannel:** Allow editing flags (#8671) ([1244854](https://github.com/discordjs/discord.js/commit/1244854e1365d7e4a8d01703a7ec13610ed100c7))\n- **GuildChannelManager:** Typo in `flags` property name when editing (#8669) ([fc8ed81](https://github.com/discordjs/discord.js/commit/fc8ed816e643754a938211a17b41a2cec95df265))\n\n## Documentation\n\n- Fix duplicate typedefs (#8677) ([d79aa2d](https://github.com/discordjs/discord.js/commit/d79aa2d0d0b186bd28cbfc82f3d6ecf3deb41c50))\n- **ForumChannel:** Add `@implements` (#8678) ([8ca407e](https://github.com/discordjs/discord.js/commit/8ca407e089c3050b61a51a52b9100e4613ad1666))\n\n## Features\n\n- **GuildChannelManager:** Allow editing `flags` (#8637) ([abb7226](https://github.com/discordjs/discord.js/commit/abb7226af3445f5b724815bb2f7a121a52a563b5))\n\n## Refactor\n\n- **GuildBanManager:** Add deprecation warning for `deleteMessageDays` (#8659) ([e993122](https://github.com/discordjs/discord.js/commit/e9931229ae62a120ae0761ee2a2c10ea0cb1a6fb))\n\n## Typings\n\n- **GuildChannelManager:** Handle forum channel overload (#8660) ([1486bc9](https://github.com/discordjs/discord.js/commit/1486bc9336369d229972df5e28b9428365b92bff))\n- **Caches:** Allow `GuildForumThreadManager` and `GuildTextThreadManager` (#8665) ([2487e3b](https://github.com/discordjs/discord.js/commit/2487e3bf76260a4a2fbf375e0b01a43f347922a3))\n\n# [14.4.0](https://github.com/discordjs/discord.js/compare/14.3.0...14.4.0) - (2022-09-21)\n\n## Bug Fixes\n\n- Correct applied tags type (#8641) ([f6f15d8](https://github.com/discordjs/discord.js/commit/f6f15d8e877d4ffbe908a093e64809ef9015e0ff))\n- **ThreadChannel:** Make `fetchStarterMessage()` work in forum posts (#8638) ([a7f816e](https://github.com/discordjs/discord.js/commit/a7f816eeb7fa1e193cf0901efbdcaf629f72465f))\n- Update `messageCount`/`totalMessageSent` on message events (#8635) ([145eb2f](https://github.com/discordjs/discord.js/commit/145eb2fc5db5ca739aa9782d5ec5210f81a6aeeb))\n- Footer / sidebar / deprecation alert ([ba3e0ed](https://github.com/discordjs/discord.js/commit/ba3e0ed348258fe8e51eefb4aa7379a1230616a9))\n\n## Documentation\n\n- Correctly overwrite `setRTCRegion` method (#8642) ([f049734](https://github.com/discordjs/discord.js/commit/f0497343f1193635b260b9e2085cac7b43991f74))\n- **GuildTextThreadManager:** Document correct `@extend` (#8639) ([802b239](https://github.com/discordjs/discord.js/commit/802b2394b08151faab6810695fd5c8f27ce84d58))\n- Fix regexps incorrectly being called global (#8624) ([fc9653f](https://github.com/discordjs/discord.js/commit/fc9653f5aea4013da15fb8de0a4452400eaa7739))\n- Update misleading `Client#guildMemberAvailable` event description (#8626) ([22ac6b4](https://github.com/discordjs/discord.js/commit/22ac6b4660db6b02f62b9851e9e3bcfe5fb506b5))\n- **Options:** Update DefaultMakeCacheSettings (#8585) ([3252332](https://github.com/discordjs/discord.js/commit/32523325c6610e95fe3ffcc31d005b3418c6bc68))\n- Change name (#8604) ([dd5a089](https://github.com/discordjs/discord.js/commit/dd5a08944c258a847fc4377f1d5e953264ab47d0))\n\n## Features\n\n- **Widget:** Allow forum channels (#8645) ([b106956](https://github.com/discordjs/discord.js/commit/b1069563086fc616fe21abb789f28f69e57c8851))\n- **WelcomeChannel:** Add forum channel as a type (#8643) ([6f1f465](https://github.com/discordjs/discord.js/commit/6f1f465a77e362e20ec50067be0e634d35946ba5))\n- Allow forum channels in webhook update event (#8646) ([5048a3d](https://github.com/discordjs/discord.js/commit/5048a3d17ace22336e74451d30b513b3db42a26f))\n- Add support for guild forums (#7791) ([8a8d519](https://github.com/discordjs/discord.js/commit/8a8d519c9c4c082370fc6935b56dafb525b873df))\n- **GuildBanManager#create:** Add `deleteMessageSeconds` (#8326) ([03fb5b0](https://github.com/discordjs/discord.js/commit/03fb5b0a2f45275dec7885175ad691a1d9c449c4))\n- Add typeguard to BaseInteraction#isRepliable (#8565) ([55c3ee2](https://github.com/discordjs/discord.js/commit/55c3ee20ae700e78d18a3c4c04b6a7426cffc060))\n- **Integration:** Add `scopes` (#8483) ([8b3d006](https://github.com/discordjs/discord.js/commit/8b3d0061180cfd5d9ba8beae3e8d623b5ce43ea4))\n- Add `chatInputApplicationCommandMention` formatter (#8546) ([d08a57c](https://github.com/discordjs/discord.js/commit/d08a57cadd9d69a734077cc1902d931ab10336db))\n\n## Refactor\n\n- Replace usage of deprecated `ChannelType`s (#8625) ([669c3cd](https://github.com/discordjs/discord.js/commit/669c3cd2566eac68ef38ab522dd6378ba761e8b3))\n- Split message send/edit types/documentation (#8590) ([8e1afae](https://github.com/discordjs/discord.js/commit/8e1afaebdb686033555ca58e53f34bb97f7369c8))\n- Website components (#8600) ([c334157](https://github.com/discordjs/discord.js/commit/c3341570d983aea9ecc419979d5a01de658c9d67))\n\n## Typings\n\n- Narrow channel type in thread managers (#8640) ([14bbc91](https://github.com/discordjs/discord.js/commit/14bbc9150a748e7ac1660c2375c7f065fcc55a6c))\n- **interactions:** Pass `Cached` type to return type of methods (#8619) ([053da5b](https://github.com/discordjs/discord.js/commit/053da5bc91d5cfa8d842b13b0b05083d2f7f086d))\n- Ensure events possess `Client<true>` (#8612) ([a9f003a](https://github.com/discordjs/discord.js/commit/a9f003ac9b56d31166cbf353d02140dad0b2517e))\n- **GuildChannelManager:** Correct `fetch` return type (#8549) ([1d4cdee](https://github.com/discordjs/discord.js/commit/1d4cdee321ab25bb0f109d55a000582825dd79f9))\n- **ThreadChannel:** `fetchStarterMessage` must return a `Message<true>` (#8560) ([b9c62ac](https://github.com/discordjs/discord.js/commit/b9c62ac0f0f534c33f9913135095f8b3d98ec05e))\n- **webhook:** Avatar can be null (#8541) ([f77612a](https://github.com/discordjs/discord.js/commit/f77612a55e9c593a21bc27e58c9fbd03d85787e3))\n\n# [14.3.0](https://github.com/discordjs/discord.js/compare/14.2.0...14.3.0) - (2022-08-22)\n\n## Bug Fixes\n\n- **GuildMemberManager:** `add()` method throws an error (#8539) ([3bef901](https://github.com/discordjs/discord.js/commit/3bef9018c0be3c5dc51d03b796d08b925dc4e1b9))\n- **Guild:** Widget channel types and fixes (#8530) ([23a0b6c](https://github.com/discordjs/discord.js/commit/23a0b6ccf27410963bd4f5c53d9ee2ce019e90a8))\n- **Embed:** Reference video in video (#8473) ([c97977a](https://github.com/discordjs/discord.js/commit/c97977a3e806bd5d8682bc7fb22ebec1a8ceecdc))\n\n## Documentation\n\n- **GuildAuditLogsEntry:** Correct `action` wording (#8499) ([7d25072](https://github.com/discordjs/discord.js/commit/7d2507279cc9d1397c7d61e7c7b856ff4bc17c86))\n\n## Features\n\n- **GuildMemberManager:** AddRole and removeRole (#8510) ([cda3f00](https://github.com/discordjs/discord.js/commit/cda3f005b1546fdb8410e9550526956f840857fc))\n- Deprecate `ActionRow.from()` (#8504) ([f9c25dd](https://github.com/discordjs/discord.js/commit/f9c25ddcfe68f089e13f1090c3df4bd7cd74d2b7))\n- **WebSocketShard:** Support new resume url (#8480) ([bc06cc6](https://github.com/discordjs/discord.js/commit/bc06cc638d2f57ab5c600e8cdb6afc8eb2180166))\n\n## Refactor\n\n- **GuildAuditLogsEntry:** Remove `guild` from application command permission update extra (#8520) ([2b8074d](https://github.com/discordjs/discord.js/commit/2b8074dd12f2f1e957caffb57e5fd4d7be88dc25))\n\n## Typings\n\n- Inference of guild in `MessageManager` (#8538) ([6bb1474](https://github.com/discordjs/discord.js/commit/6bb1474d2001b76773954c959b2c2687e1df0136))\n- Allow choice's value type to be strictly inferred (#8529) ([b3f7c32](https://github.com/discordjs/discord.js/commit/b3f7c32f7f91f12766178f5e17585856e81d9a87))\n- **GuildAuditLogs:** Allow fetching to return all possible values (#8522) ([0dba8ad](https://github.com/discordjs/discord.js/commit/0dba8adbd2e6efd634bd3eb31df09467ba8a8a0d))\n- Correct `EventEmitter.on (static)` return type (#8524) ([16bbc8a](https://github.com/discordjs/discord.js/commit/16bbc8aa208a8a16c22be24696f57d5f7a5faf2b))\n- **GuildAuditLogs:** Remove static `Entry` (#8521) ([7a3d18d](https://github.com/discordjs/discord.js/commit/7a3d18dd6d1fe27393d00019b9ecd35c98b95ee7))\n- Disallow some channel types from webhook creation (#8531) ([4882b17](https://github.com/discordjs/discord.js/commit/4882b17a77484f801faa19fb971f2e6abd88e59f))\n- Implement max/min values for autocomplete (#8498) ([812f7f1](https://github.com/discordjs/discord.js/commit/812f7f1ea86fc953aa796875cbc7ccc434203d77))\n- **ModalMessageModalSubmitInteraction:** ChannelId is not nullable (#8496) ([c31a5cf](https://github.com/discordjs/discord.js/commit/c31a5cfcc82706667768eac77b5f99ba69cf3c91))\n- Change type of ApplicationCommandSubCommand.options (#8476) ([ebaf158](https://github.com/discordjs/discord.js/commit/ebaf158006d3c7db3b8c695e7c027b8af11999ba))\n\n# [14.2.0](https://github.com/discordjs/discord.js/compare/14.1.2...14.2.0) - (2022-08-10)\n\n## Bug Fixes\n\n- **ThreadChannel:** Handle possibly `null` parent (#8466) ([afa27b1](https://github.com/discordjs/discord.js/commit/afa27b15c5b92bc8d55b8285834d8e03f6692d06))\n- Remove DM channels from `Client#messageDeleteBulk`'s types (#8460) ([6c6fe74](https://github.com/discordjs/discord.js/commit/6c6fe74dd84859c5319efa999404e8168f189710))\n- **Transformers:** Do not transform `Date` objects (#8463) ([0e2a095](https://github.com/discordjs/discord.js/commit/0e2a09571c8e5ee61153b04e45334a226a1b4534))\n- **ModalSubmitInteraction:** Allow deferUpdate (#8455) ([0fab869](https://github.com/discordjs/discord.js/commit/0fab869e5179dca7ddec75b5519615278e51ad82))\n- **Guild:** Unable to fetch templates (#8420) ([aac8acc](https://github.com/discordjs/discord.js/commit/aac8acc22be7d7af99933ef099eca7deda43cb40))\n- **MessageMentions:** Infinite loop in `parsedUsers` getter (#8430) ([b8a3136](https://github.com/discordjs/discord.js/commit/b8a31360a220e3d796f5381bd215d30a379ecb7c))\n- **DataResolver:** Make `Buffer` from string (#8416) ([e72b986](https://github.com/discordjs/discord.js/commit/e72b986939e2958547c0e54d6d27472c8d111609))\n\n## Documentation\n\n- Change registration example to use global commands (#8454) ([64a4041](https://github.com/discordjs/discord.js/commit/64a4041a05e9514334a9f9e1f38a1ea18bb676d5))\n- **Colors:** Provide enum descriptions (#8437) ([6ef4754](https://github.com/discordjs/discord.js/commit/6ef4754d40c5ec65715fc1e00e643c52fe0a6209))\n- **AttachmentBuilder:** Fix #8407 (#8421) ([5b053cf](https://github.com/discordjs/discord.js/commit/5b053cf82ec2f2b717a490485af052dc956fe3c9))\n\n## Features\n\n- **Guild:** Add `max_video_channel_users` (#8423) ([3a96ce7](https://github.com/discordjs/discord.js/commit/3a96ce7970947f6268c21a1323d986aac8cb736d))\n\n## Typings\n\n- **Message:** Correct `bulkDelete` return type (#8465) ([c5b96a1](https://github.com/discordjs/discord.js/commit/c5b96a185cb8ba836b7cd10526c14059866f218f))\n- Fix missing types for mentionable options (#8443) ([452e94f](https://github.com/discordjs/discord.js/commit/452e94fd3ecc12de9e3408982c5c7fd931bae634))\n- **ApplicationCommandOption:** Add `ApplicationCommandBooleanOption` (#8434) ([38275fc](https://github.com/discordjs/discord.js/commit/38275fc53d633ce77ed2b142aff788dcbd4fad8c))\n\n# [14.1.2](https://github.com/discordjs/discord.js/compare/14.1.1...14.1.2) - (2022-07-30)\n\n## Bug Fixes\n\n- **errors:** Error codes (#8398) ([480c85c](https://github.com/discordjs/discord.js/commit/480c85c9c3d129204b3399ed726a4e570e0b2852))\n\n## Documentation\n\n- **Embed:** Ensure height and width are numbers (#8396) ([fca3dad](https://github.com/discordjs/discord.js/commit/fca3dada2a565eecfc7e5275cc9317df1d261871))\n\n# [14.1.0](https://github.com/discordjs/discord.js/compare/14.0.3...14.1.0) - (2022-07-29)\n\n## Bug Fixes\n\n- **MessageMentions:** `ignoreRepliedUser` option in `has()` (#8202) ([b4e2c0c](https://github.com/discordjs/discord.js/commit/b4e2c0c4d5538b945f9d597c6410a6f84b315084))\n- **GuildChannelManager:** Allow unsetting rtcRegion (#8359) ([a7d49e5](https://github.com/discordjs/discord.js/commit/a7d49e56fc7c34d2e4548d9e5bf0aec45273506e))\n- **ThreadChannel:** Omit webhook fetching (#8351) ([3839958](https://github.com/discordjs/discord.js/commit/3839958e3f682c715f1017da05436d2fe34900fd))\n- **GuildAuditLogsEntry:** Replace OverwriteType with AuditLogOptionsType (#8345) ([58c1b51](https://github.com/discordjs/discord.js/commit/58c1b51c5ceab137ad9851919b338419eeeab69e))\n- **ShardClientUtil#_respond:** Construct global error (#8348) ([8e520f9](https://github.com/discordjs/discord.js/commit/8e520f946a5b9f93a939290facf4ccca2c05ff21))\n- **Presence:** Do not return NaN for activity timestamp (#8340) ([df42fdf](https://github.com/discordjs/discord.js/commit/df42fdfc421f1190f0a2267a66efd3c921ec2348))\n- **Client:** Omit private properties from toJSON (#8337) ([830c670](https://github.com/discordjs/discord.js/commit/830c670c61dcb17d8ab2a894a3203c68917d27e0))\n- **ApplicationCommandManager:** Allow passing 0n to defaultMemberPermissions (#8311) ([1fb7b30](https://github.com/discordjs/discord.js/commit/1fb7b30963cfe7ea4c05b1f3b42171c879c46a1d))\n\n## Documentation\n\n- **InteractionResponses:** Add `showModal()` return type (#8376) ([0b61dbf](https://github.com/discordjs/discord.js/commit/0b61dbf720e844322b066e30080c3537ab3d8174))\n- **WebhookClient:** Document working options (#8375) ([ba6797e](https://github.com/discordjs/discord.js/commit/ba6797e74209161b64c412de1b6f307cb28736b8))\n- **Message:** Document gateway intent for content (#8364) ([2130aae](https://github.com/discordjs/discord.js/commit/2130aae3210a8eaf91c5ccae5463940d49052c7d))\n- Use info blocks for requirements (#8361) ([80b9738](https://github.com/discordjs/discord.js/commit/80b9738957ebf5b6eb7c9858cec0fb1c897d0a1f))\n- **WebhookClient:** Make constructor a union (#8370) ([e9920a9](https://github.com/discordjs/discord.js/commit/e9920a9c98ffb78bd7d0ae00d486476367296646))\n- Update docs and examples to PascalCase links (#8305) ([34ba9d1](https://github.com/discordjs/discord.js/commit/34ba9d1c4c80eff7e6ac199a40232d07491432cc))\n\n## Features\n\n- Add channel & message URL formatters (#8371) ([a7deb8f](https://github.com/discordjs/discord.js/commit/a7deb8f89830ead6185c5fb46a49688b6d209ed1))\n- Restore missing typeguards (#8328) ([77ed407](https://github.com/discordjs/discord.js/commit/77ed407f6aadb68e729470c5269e9b526cb1b3f0))\n- **GuildMember:** Add dmChannel getter (#8281) ([4fc2c60](https://github.com/discordjs/discord.js/commit/4fc2c60a3bb43671b4b0202ae75eab42aba163ff))\n\n## Refactor\n\n- Deprecate `Formatter` class (#8373) ([7fd9ed8](https://github.com/discordjs/discord.js/commit/7fd9ed8f13d17ce7e98e34f7454d9047054d8467))\n- **PermissionOverwriteManager:** Use `OverwriteType` (#8374) ([6d24805](https://github.com/discordjs/discord.js/commit/6d248051cfd431e9cb1c65cb98f56aa0a6556407))\n\n## Typings\n\n- **GuildAuditLogsEntryExtraField:** Use `AuditLogOptionsType` (#8349) ([200ab91](https://github.com/discordjs/discord.js/commit/200ab91f527d8a5706d277b89a975096f75d141a))\n\n# [14.0.3](https://github.com/discordjs/discord.js/compare/14.0.2...14.0.3) - (2022-07-19)\n\n## Bug Fixes\n\n- **Components:** Support emoji id strings (#8310) ([660e212](https://github.com/discordjs/discord.js/commit/660e212e83df026c684ee2cda7fb4e98870f342e))\n\n# [14.0.2](https://github.com/discordjs/discord.js/compare/14.0.1...14.0.2) - (2022-07-18)\n\n## Bug Fixes\n\n- **DataResolver#resolveImage:** Adjust to updated resolveFile (#8308) ([3a7e93d](https://github.com/discordjs/discord.js/commit/3a7e93df576172c797f1d8bd6483234bb6af2d00))\n\n# [14.0.0](https://github.com/discordjs/discord.js/compare/9.3.1...14.0.0) - (2022-07-17)\n\n## Bug Fixes\n\n- **GuildMemberManager:** Allow setting own nickname (#8066) ([52a9e21](https://github.com/discordjs/discord.js/commit/52a9e213c2dc13ee52ee0234593fdce392f43890))\n- **PermissionOverwriteManager:** Mutates user (#8283) ([3bf30b1](https://github.com/discordjs/discord.js/commit/3bf30b1e6d2d6f583f7069a1e24e7842d59fab2f))\n- **GuildChannelManager:** Access `resolveId` correctly (#8296) ([3648f6d](https://github.com/discordjs/discord.js/commit/3648f6d567cd834c301de913ce19f786a265240d))\n- **GuildChannelManager:** Edit lockPermissions (#8269) ([7876548](https://github.com/discordjs/discord.js/commit/787654816d2b6a5168d199d32cdaeb4ef6d270b9))\n- **`SelectMenuBuilder`:** Properly accept `SelectMenuOptionBuilder`s (#8174) ([31d5930](https://github.com/discordjs/discord.js/commit/31d593046466438c55f5784b0f2098e233c5edc4))\n- Remove global flag on regular expressions (#8177) ([cdd9214](https://github.com/discordjs/discord.js/commit/cdd9214212892e30b3eaa161837c37516c5bcaa0))\n- **MessagePayload:** Guard against `repliedUser` property (#8211) ([fa010b5](https://github.com/discordjs/discord.js/commit/fa010b516254c4ab2762278817f31bf289f0ab6a))\n- **ApplicationCommandManager:** Explicitly allow passing builders to methods (#8209) ([50d55bd](https://github.com/discordjs/discord.js/commit/50d55bd6b819307c86701f4808c087f359c6ccff))\n- **GuildMemberRemove:** Remove member's presence (#8181) ([11b1739](https://github.com/discordjs/discord.js/commit/11b173931968c548f8504649ae7090865892e62d))\n- Edit() data can be partial and `defaultMemberPermissions` can be `null` (#8163) ([0ffbef5](https://github.com/discordjs/discord.js/commit/0ffbef506a97a0bf22cb134fc007c2aec29cbffc))\n- **WebSocketShard:** Keep an error handler on connections (#8150) ([c34c02a](https://github.com/discordjs/discord.js/commit/c34c02ab8d119bf16d8d14d125a9b650b4bb18f4))\n- **DJSError:** Error code validation (#8149) ([31f6582](https://github.com/discordjs/discord.js/commit/31f658247fe0e1047897edab629643d140e77e07))\n- **vcs:** Nsfw property (#8132) ([2eeaad6](https://github.com/discordjs/discord.js/commit/2eeaad6f27fdf8868364fa95ed20755ee09bda87))\n- **WebSocketManager:** Correct error name (#8138) ([db2b033](https://github.com/discordjs/discord.js/commit/db2b0333d912fe83381db2ffe16829d7d03d6c2e))\n- **WebSocketShard:** Disconnected casing (#8117) ([23e183a](https://github.com/discordjs/discord.js/commit/23e183a9ac7aaa3bca2bc4eb8634d1738ec34a26))\n- **webhooks:** Revert webhook caching (and returning Message) (#8038) ([d54bf5d](https://github.com/discordjs/discord.js/commit/d54bf5d286f4057db130901591b192fd4d1668c1))\n- **ApplicationCommand:** Remove `autocomplete` check at the top level and correctly check for `dmPermission` (#8100) ([0a44b05](https://github.com/discordjs/discord.js/commit/0a44b05db83948857afbe18471e7a867da47177a))\n- **ApplicationCommand:** Fix default member permissions assignment (#8067) ([96053ba](https://github.com/discordjs/discord.js/commit/96053babe1bd65ebe1fc6a261f5eb052906afdb9))\n- **scripts:** Read directory and rerun (#8065) ([f527dea](https://github.com/discordjs/discord.js/commit/f527dea36ead194aaae1bf5da1e953df59d692fd))\n- Select menu options to accept both rest and array (#8032) ([fbe67e1](https://github.com/discordjs/discord.js/commit/fbe67e102502b4b49690cbf8ff891ead2232ecf3))\n- **CommandInteractionOptionResolver:** Handle autocompletion interactions (#8058) ([d8077c6](https://github.com/discordjs/discord.js/commit/d8077c6839dc8ceb57d3c3a86bf9746be2a91ada))\n- **scripts:** Add quotes around blob arguments (#8054) ([598f61b](https://github.com/discordjs/discord.js/commit/598f61b992fab1b3fdcab8ff960366f7af0b37ea))\n- **Message:** Force fetching (#8047) ([f2b267c](https://github.com/discordjs/discord.js/commit/f2b267c079dd8aa7277910471f3db2f88af6efb2))\n- **Attachment:** Do not destructure `data` (#8041) ([1afae90](https://github.com/discordjs/discord.js/commit/1afae909d72e648cf48d63d7de2708737a78c126))\n- **DirectoryChannel:** Type `name` and handle `url` (#8023) ([86d8fbc](https://github.com/discordjs/discord.js/commit/86d8fbc023e3925e8f86799d6ebf2d423f7bf2ec))\n- Readd `isThread` type guard (#8019) ([f8ed71b](https://github.com/discordjs/discord.js/commit/f8ed71bfca6e47e3d44ad063e23804354bd23604))\n- Add static method `from` in builders (#7990) ([ad36c0b](https://github.com/discordjs/discord.js/commit/ad36c0be7744ea4214ccf345fe80a5a1a9e89101))\n- Typings (#7965) ([7a1095b](https://github.com/discordjs/discord.js/commit/7a1095b66be3c5d81185e026281e2908c10c1695))\n- **GuildAuditLogs:** Cache guild scheduled events (#7951) ([2f03f9a](https://github.com/discordjs/discord.js/commit/2f03f9ad3f63abee5b5c46d02f1afa8885e8977c))\n- Make sure action row builders create djs builders (#7945) ([adf461b](https://github.com/discordjs/discord.js/commit/adf461baf49be754c7a10c61faf1ef3df333413a))\n- **TextBasedChannel#bulkDelete:** Return deleted message (#7943) ([191510b](https://github.com/discordjs/discord.js/commit/191510b7f87903e4bd93b891649cb290fd50c47e))\n- Remove trailing invites on channel deletion (#7932) ([5e9b757](https://github.com/discordjs/discord.js/commit/5e9b757a3733e6526770eb60a15072612294eb21))\n- **DataResolver:** Fix check for readable streams (#7928) ([28172ca](https://github.com/discordjs/discord.js/commit/28172ca7b57357436d3252ec01ec17dad865d87f))\n- **AuditLog:** Default changes to empty array (#7880) ([19eaed6](https://github.com/discordjs/discord.js/commit/19eaed63905367ef4604366b8839023384524d1f))\n- **Util:** Flatten ignoring certain fields (#7773) ([df64d3e](https://github.com/discordjs/discord.js/commit/df64d3ea382c07e66bc7cc8877ee430206c31d63))\n- Possibly missing (#7829) ([6239d83](https://github.com/discordjs/discord.js/commit/6239d83c4d5f0a396678410d7fef35e39ed29009))\n- `endReason` not being properly set in base Collector (#7833) ([0c18dab](https://github.com/discordjs/discord.js/commit/0c18dab1280205b8855d17d075b7421860d59c14))\n- **SelectMenuBuilder:** Options array (#7826) ([3617093](https://github.com/discordjs/discord.js/commit/361709332bdc871822c2b9919f14fd090d68666a))\n- **Activity:** Platform type (#7805) ([4ac91c6](https://github.com/discordjs/discord.js/commit/4ac91c61d08111ae4d49d1e64caf94e6e49832c8))\n- **ApplicationCommand:** Equal nameLocalizations and descriptionLocalizations (#7802) ([4972bd8](https://github.com/discordjs/discord.js/commit/4972bd87c17cbc6a94c9608ba2ab39c475f9921f))\n- **InteractionResponses:** Use optional chaining on nullable property (#7812) ([c5fb548](https://github.com/discordjs/discord.js/commit/c5fb54852906898ffb19282dd60168dfc6fb2eba))\n- **MessageManager:** Allow caching option of an unspecified limit (#7763) ([1b2d8de](https://github.com/discordjs/discord.js/commit/1b2d8decb638faeae8184119c5cedfcdaf9485e3))\n- **builders:** Add constructor default param (#7788) ([c286650](https://github.com/discordjs/discord.js/commit/c2866504a3824005fe756556fec4b349898b7d22))\n- **MessagePayload:** ResolveBody check body instead of data (#7738) ([3db20ab](https://github.com/discordjs/discord.js/commit/3db20abdd2d502a1ed457842181b164dc6390ba1))\n- **ActionRow:** ToJSON should include components (#7739) ([ebb4dfa](https://github.com/discordjs/discord.js/commit/ebb4dfa262adb2086c83db487002bb2e1ed5ab88))\n- Prevent `NaN` for nullable timestamps (#7750) ([8625d81](https://github.com/discordjs/discord.js/commit/8625d817145eb642aeb0da05184352f438586986))\n- **InteractionCreateAction:** Ensure text-based channel for caching messages (#7755) ([25fdb38](https://github.com/discordjs/discord.js/commit/25fdb3894d33dc395a376a3d962a063eb5735253))\n- Pass `force` correctly (#7721) ([402514f](https://github.com/discordjs/discord.js/commit/402514ff323ccf1f8c95d295f044cf0bb5547c2e))\n- Support reason in setRTCRegion helpers (#7723) ([905a6a1](https://github.com/discordjs/discord.js/commit/905a6a11663f9469ada67f8310a969453ffc5b2a))\n- **GuildMemberManager:** Return type can be null (#7680) ([74bf7d5](https://github.com/discordjs/discord.js/commit/74bf7d57ab959eb820ab1c213ac86ab1ea660398))\n- **gateway:** Use version 10 (#7689) ([8880de0](https://github.com/discordjs/discord.js/commit/8880de0cecdf273fd6df23988e4cb77774a75390))\n- Audit log static reference (#7703) ([85e531f](https://github.com/discordjs/discord.js/commit/85e531f22d7a8f8ad043647ce445726ae0df26c0))\n- Handle possibly missing property (#7641) ([0c32332](https://github.com/discordjs/discord.js/commit/0c32332a5aacbbb6c415da75c166d09cfdb34bbd))\n- **util:** Allow `escapeInlineCode` to escape double backtics (#7638) ([d5369a5](https://github.com/discordjs/discord.js/commit/d5369a56e3fcf50513f3bc582552c2838b04d199))\n- **GuildEditData:** Some fields can be null (#7632) ([4d2b559](https://github.com/discordjs/discord.js/commit/4d2b55955d1a3ff05c3047599232becdc3f2c445))\n- TOKEN_INVALID error not thrown at login with invalid token (#7630) ([cd79bef](https://github.com/discordjs/discord.js/commit/cd79bef2547594f4d0c744faa8fa67fb9fd61526))\n- **GuildScheduledEvent:** Handle missing `image` (#7625) ([c684ac5](https://github.com/discordjs/discord.js/commit/c684ac55e1d225740e67ab7bd5643de1b35f4594))\n- **guild:** Throw if ownerId falsey (#7575) ([98177aa](https://github.com/discordjs/discord.js/commit/98177aa38d3d6516d4c5354d6c7edea925dc881d))\n- Remove Modal export (#7654) ([87a6b84](https://github.com/discordjs/discord.js/commit/87a6b8445bfbf3981cd39813fe961dfa1c7f2bce))\n- **Embed:** Fix incorrect destructuring import (#7615) ([cbdb408](https://github.com/discordjs/discord.js/commit/cbdb408dffd1c7f2193c15989528a3de5fd9f13a))\n- **ThreadMembersUpdate:** Only emit added & removed thread members (#7539) ([c12d61a](https://github.com/discordjs/discord.js/commit/c12d61a3421afcdc41f77c0fddde4efbb257fa69))\n- **Util:** EscapeInlineCode properly (#7587) ([851f380](https://github.com/discordjs/discord.js/commit/851f380eb10d23ffd08e8b845aed4039abbcd03b))\n- **GuildStickerManager:** Correctly access guild ID (#7605) ([4b08d9b](https://github.com/discordjs/discord.js/commit/4b08d9b376bda7a7f4bb3fb8c555d25cca648de4))\n- **MessageManager:** Pin route (#7610) ([cb566c8](https://github.com/discordjs/discord.js/commit/cb566c8b6abff489a944db7952e5c5a48e0c98b0))\n- Handle partial data for `Typing#user` (#7542) ([c6cb5e9](https://github.com/discordjs/discord.js/commit/c6cb5e9ebbf46d81404119a6aa11bb8ebb17d5a4))\n- **guild:** Fix typo accessing user instead of users (#7537) ([8203c5d](https://github.com/discordjs/discord.js/commit/8203c5d843f2431c0f49023282f1bf73d85881d1))\n- **test:** `MessageActionRow` to `ActionRow` (#7523) ([d1d1b07](https://github.com/discordjs/discord.js/commit/d1d1b076bebf7cb706b2436a40d87c6efaed1e1d))\n- **MessagePayload:** Don't set reply flags to target flags (#7514) ([4f30652](https://github.com/discordjs/discord.js/commit/4f306521d829fef21ebd70557b37f8199b82572b))\n- **invite:** Add back channelId property (#7501) ([78aa36f](https://github.com/discordjs/discord.js/commit/78aa36f9f5913b86c82376ecdf20653b15340bbe))\n- Properly serialize `undefined` values (#7497) ([8dbd345](https://github.com/discordjs/discord.js/commit/8dbd34544cbeb499282f01dda9d35ed9bca93591))\n- Allow unsafe embeds to be serialized (#7494) ([942ea1a](https://github.com/discordjs/discord.js/commit/942ea1acbfb49289ccb3a1882b5a2da0a7d0bccf))\n- Attachment types (#7478) ([395a68f](https://github.com/discordjs/discord.js/commit/395a68ff49c622d5136d6b775beaf8e88a2d8610))\n- Use case converter for json component serialization (#7464) ([2d45544](https://github.com/discordjs/discord.js/commit/2d4554440ed9329a5876a9c674c3eb2de0f2f917))\n- **GuildAuditLogs:** Typings and consistency (#7445) ([c1b27f8](https://github.com/discordjs/discord.js/commit/c1b27f8eed8ea04a48bc106453892bddcdc6b73e))\n- **dataresolver:** Ensure fetched file is convert to a buffer (#7457) ([9311fa7](https://github.com/discordjs/discord.js/commit/9311fa7b42b2b5a74e411aa263daa4fbfc270645))\n- **messagepayload:** ResolveFile property names (#7458) ([a8106f7](https://github.com/discordjs/discord.js/commit/a8106f7c586f0ecac76e7f72c53b0da215a6fbf1))\n- **ci:** Ci error (#7454) ([0af9bc8](https://github.com/discordjs/discord.js/commit/0af9bc841ffe1a297d308500d696bad4b85abda9))\n- **threads:** Require being sendable to be unarchivable (#7406) ([861f0e2](https://github.com/discordjs/discord.js/commit/861f0e2134662ab64a11d313130aff58b413d495))\n- **guildmember:** Check if member has administrator permission (#7384) ([81d8b54](https://github.com/discordjs/discord.js/commit/81d8b54ff6b98b0e7ee2c57eaee6bc0b707e135a))\n- **guild:** Remove `maximumPresences` default value (#7440) ([55b388a](https://github.com/discordjs/discord.js/commit/55b388a763dc7223e88b62ae928fe85fe8b8fe58))\n- **guildchannelmanager:** Edit always sets parent to null (#7446) ([b97aedd](https://github.com/discordjs/discord.js/commit/b97aedd8e15f9358960cb59403f3a8ea24b87141))\n- **guildmember:** Make `pending` nullable (#7401) ([fe11ff5](https://github.com/discordjs/discord.js/commit/fe11ff5f6e85571a981e90eba5b9f3bda7a2cd04))\n- **clientpresence:** Fix used opcodes (#7415) ([a921ec7](https://github.com/discordjs/discord.js/commit/a921ec7dc525c58d40b4678e66270f9238abed31))\n- Correctly export UnsafeSelectMenuComponent from builders (#7421) ([aadfbda](https://github.com/discordjs/discord.js/commit/aadfbda586d57a7b775ad26c201f0dc34618180b))\n- MessageReaction.me being false when it shouldn't (#7378) ([04502ce](https://github.com/discordjs/discord.js/commit/04502ce702da53c4b00bf391d0fd936746851381))\n- Fix some typos (#7393) ([92a04f4](https://github.com/discordjs/discord.js/commit/92a04f4d98f6c6760214034cc8f5a1eaa78893c7))\n- **messagementions:** Fix `has` method (#7292) ([3a5ab2c](https://github.com/discordjs/discord.js/commit/3a5ab2c4e54de4e67ab6e323d7eac86482da7382))\n- **guildmembermanager:** Use rest in edit (#7356) ([00ce1c5](https://github.com/discordjs/discord.js/commit/00ce1c56ac224691a8691a3525cb14ae002319c6))\n- **typings:** Mark `RESTOptions` as Partial in `ClientOptions` (#7349) ([e1ecc1a](https://github.com/discordjs/discord.js/commit/e1ecc1a80a9358cdbafbe8542c40b9de8cad467e))\n- **Webhook:** Use correct method name (#7348) ([11e5e5a](https://github.com/discordjs/discord.js/commit/11e5e5ac5b70138f56332eb3e61a42443670b0de))\n- **thread:** Don't assign directly to getters (#7346) ([2db0cdd](https://github.com/discordjs/discord.js/commit/2db0cdd357c3a02decb4fd4168db87888efba283))\n- Missed enums and typings from #7290 (#7331) ([47633f0](https://github.com/discordjs/discord.js/commit/47633f0fd2435d6d8c694d8d37b26039a7b3797a))\n- **guildchannelmanager:** Remove reverse enum lookup (#7304) ([857bba4](https://github.com/discordjs/discord.js/commit/857bba448029f3f070c67fb40b59a3a2a2e5c6f4))\n- Import `clear{Timeout,Interval}` from `node:timers` (#7269) ([8ddd44e](https://github.com/discordjs/discord.js/commit/8ddd44ed85b32c86243efe0ec35b283eaaa8212c))\n- **ApplicationCommand:** Use new ApplicationCommandOptionType enums (#7257) ([06f5210](https://github.com/discordjs/discord.js/commit/06f5210f58bbba6102173033a9f1e6fb004fdf5d))\n- Use enums from discord-api-types (#7258) ([f284a46](https://github.com/discordjs/discord.js/commit/f284a4641fd68de9190bda97ec1eab0981149630))\n- **exports:** Export ApplicationCommandType properly (#7256) ([f753882](https://github.com/discordjs/discord.js/commit/f75388259262bf6b4a64375b97800bd72378f3bc))\n- **Shard:** EventEmitter listener warning (#7240) ([ff3a8b8](https://github.com/discordjs/discord.js/commit/ff3a8b83234d3826fc49c5a8c3cb52ef9f281ffd))\n- **timestamps:** Account for timestamps of 0 when creating Dates (#7226) ([a8509c9](https://github.com/discordjs/discord.js/commit/a8509c91ca0147393b407221405b6b917677961a))\n- **MessageEmbed:** CreatedAt field can be zero (#7218) ([37cad54](https://github.com/discordjs/discord.js/commit/37cad54dbdade39607397b8ad697eca94f1b7197))\n- **BaseClient:** Do not append default options if provided is not an object (#6453) ([b92a7d7](https://github.com/discordjs/discord.js/commit/b92a7d72332c35b607db54aa6aca24b8e10e00ad))\n- Snowflakeutil import (#7219) ([962f4bf](https://github.com/discordjs/discord.js/commit/962f4bf88211dbfb5ad0295a9467dede1e2688ee))\n- **Role:** Remove unused process (#7215) ([63034b4](https://github.com/discordjs/discord.js/commit/63034b44c9849087e391684d9b6c0c6ae9a21113))\n- **WebhookClient:** Updated webhook url regex (#6804) ([1c615d1](https://github.com/discordjs/discord.js/commit/1c615d1bb2606d5f19e55076d4ecab95c619518e))\n- **Sweepers:** Add sweepStickers function (#7213) ([95f8375](https://github.com/discordjs/discord.js/commit/95f8375d425f58f501f32ead03f7927e6596f8e6))\n- **InteractionCreate:** Use ChatInputCommandInteraction instead (#7210) ([49dada3](https://github.com/discordjs/discord.js/commit/49dada35f92470d3e4426362510847b93dd42d1a))\n- **Structues:** Rename old module's name (#7207) ([fbef454](https://github.com/discordjs/discord.js/commit/fbef45489457a2198357dc4dd303740d79036784))\n- **WebSocket:** Remove application command handler (#7202) ([033151c](https://github.com/discordjs/discord.js/commit/033151cf92fe43536b8a4c0f4d7d9ed75a2095c5))\n- **User:** `bannerURL()` should not throw when not present (#6789) ([3872acf](https://github.com/discordjs/discord.js/commit/3872acfeb8390f6f7202d69cf1f7f8616a7b0b34))\n- **VoiceState:** Ensure `suppress` & `streaming` have proper fallback values (#6377) ([a0d5f13](https://github.com/discordjs/discord.js/commit/a0d5f13dd9b27c44f5183a2a9af4c4fdecb312c0))\n- **sweepers:** Provide default for object param (#7182) ([ae2f013](https://github.com/discordjs/discord.js/commit/ae2f013653c8a9f9ffb12ae8fcdb1bb604b39236))\n\n## Deprecation\n\n- **Caching:** Clean up deprecated cache sweeping (#7118) ([12ffa06](https://github.com/discordjs/discord.js/commit/12ffa069aa8b247e945fef16a543f41c2c391bf1))\n\n## Documentation\n\n- Align webhook method return types with implementation (#8253) ([5aeed99](https://github.com/discordjs/discord.js/commit/5aeed9935058241648507d7f651679226a89dbb3))\n- Remove `@private` constructor documentation (#8255) ([452dec5](https://github.com/discordjs/discord.js/commit/452dec57ca422f5e7424a0f0e78c3e152717f413))\n- **ApplicationCommand:** Add `min_length` and `max_length` to ApplicationCommandOptionData (#8239) ([43f62bb](https://github.com/discordjs/discord.js/commit/43f62bb6678ec332795c8cfbe0c01854b95aa61e))\n- **MessageInteraction#commandName:** Updated description (#8212) ([ab238a9](https://github.com/discordjs/discord.js/commit/ab238a9046e0201dbd4755fa41fa69c44b186912))\n- Add missing `@extends` (#8205) ([e0c8282](https://github.com/discordjs/discord.js/commit/e0c82824905dcebf62c2d1afcc5e5590a5594838))\n- **Constants:** Fix SweeperKeys type (#8157) ([af04992](https://github.com/discordjs/discord.js/commit/af04992ed3c2617fda686c2bc7338dcada283dc6))\n- **Channels:** Internally document channel creation (#8154) ([5e5853a](https://github.com/discordjs/discord.js/commit/5e5853a4e885c47e3dde519761dd59a5ec0e06fc))\n- Update threads to use `ThreadAutoArchiveDuration` (#8153) ([ee36d60](https://github.com/discordjs/discord.js/commit/ee36d60dc6714c83569a20716fa8ca8e1bd7de4f))\n- **APITypes:** Remove duplicate type definition (#8144) ([a061233](https://github.com/discordjs/discord.js/commit/a0612335101c7ce2a07d95da4b79f0d4a2b1a6a0))\n- Document missing type definitions (#8130) ([203bc4a](https://github.com/discordjs/discord.js/commit/203bc4a2cf0c2d90a003093318aa0741605610f5))\n- **InteractionResponse:** Fix return (#8141) ([f1ac17c](https://github.com/discordjs/discord.js/commit/f1ac17c961cf95d99e205133605d10d8be5bd737))\n- **PermissionsBitField:** Fix `@name` of bitfield (#8115) ([3a77ce0](https://github.com/discordjs/discord.js/commit/3a77ce0b18c60a0b21ba088590ff89f2ace94087))\n- `TextBasedChannel` -> `TextBasedChannels` typos (#8110) ([db663a5](https://github.com/discordjs/discord.js/commit/db663a55c2ed2faf61e217009158da50dfcf274f))\n- Remove `number`s from enums (#8098) ([0a138da](https://github.com/discordjs/discord.js/commit/0a138dab95a86512f08ac3be356f77f38f2ea880))\n- **GuildAuditLogs:** Fix and reimplement type definitions (#8108) ([4155136](https://github.com/discordjs/discord.js/commit/415513696c7b7e139d1b958e480bf0c7e4d14111))\n- **WebSocketOptions:** Add `version` to docs and typings (#8050) ([386c41f](https://github.com/discordjs/discord.js/commit/386c41f24fb3c9d06967d9c1881a57645c3a71f2))\n- **BaseGuildTextChannel:** Update `setType()`'s parameter type (#8088) ([9c0f190](https://github.com/discordjs/discord.js/commit/9c0f190de1f743d9bd597ffd656503c672db71c1))\n- Update outdated examples (#8081) ([51eadf3](https://github.com/discordjs/discord.js/commit/51eadf37371a6138847efdb4b5b81ee132001cf0))\n- **ThreadMemberManager:** Require `member` in `FetchThreadMemberOptions` (#8079) ([552ec72](https://github.com/discordjs/discord.js/commit/552ec72542ec3b2b3ebf35c9fd84ab502dd746cf))\n- **AutocompleteInteraction:** Change useless log in responds example  (#8077) ([ac7bf69](https://github.com/discordjs/discord.js/commit/ac7bf692bfce8204e278205dde811515a51f154b))\n- Description and missing `@typedef` fixes (#8087) ([a2eebf6](https://github.com/discordjs/discord.js/commit/a2eebf6c66f3e4c96ece9d2ae2a1133c84257f42))\n- Ignore docs of unexported functions (#8051) ([94bdcac](https://github.com/discordjs/discord.js/commit/94bdcaca62414a77d4ee0b8b79752a2be937320b))\n- **ClientOptions:** Fix closeTimeout default (#8049) ([b2eea1c](https://github.com/discordjs/discord.js/commit/b2eea1c900ba73d4b98b72f5c196f51e27d3ab8f))\n- **DirectoryChannel:** Extend `Channel` (#8022) ([f3f34f0](https://github.com/discordjs/discord.js/commit/f3f34f07b3b396015b130b8e9d938a3eec688fc3))\n- **Attachment:** Remove constructor doc (#8009) ([0a7953e](https://github.com/discordjs/discord.js/commit/0a7953e46310c77483d277539b47f1a7ab051fd9))\n- **VoiceChannel:** Annotate that it is implementing TextBasedChannel (#8007) ([5987dbe](https://github.com/discordjs/discord.js/commit/5987dbe5cff6991ae6905b0387411fa042d3e9b7))\n- Add missing discord-api-types external types (#8001) ([546d486](https://github.com/discordjs/discord.js/commit/546d48655f36ed9a6c6c5ce3c2eabcca1a86a945))\n- **InteractionResponses:** Replace outdated Embed example for reply (#7875) ([d308c66](https://github.com/discordjs/discord.js/commit/d308c66eeca6bdc3471637ae3aaaaa0a2f5c9989))\n- Require parameter (#7838) ([f4ccc67](https://github.com/discordjs/discord.js/commit/f4ccc6772c15e32489ca22fb2c3e803b85d4dbf9))\n- **ApplicationCommand:** Fix and improve localization docs (#7804) ([61a44c5](https://github.com/discordjs/discord.js/commit/61a44c509c40abaf7ffb95b10942889cbbf155ac))\n- **ApplicationCommand:** Fix ApplicationCommandOptionChoice (#7794) ([f1d0084](https://github.com/discordjs/discord.js/commit/f1d0084da26b0111ca029c789ad9e8e6c2882b4d))\n- Add back static properties and methods (#7706) ([520f471](https://github.com/discordjs/discord.js/commit/520f471ac56cbc01402b79197333a8a34c4ac5c9))\n- **InteractionCollector:** Document channel option type (#7551) ([e787cd5](https://github.com/discordjs/discord.js/commit/e787cd5fa5d013319347392ee4f799a677f6f512))\n- Correctly type getters (#7500) ([ffecf08](https://github.com/discordjs/discord.js/commit/ffecf084956f954cf10e1b844e00326e443a86f2))\n- ApplicationCommandData typedef (#7389) ([d32db88](https://github.com/discordjs/discord.js/commit/d32db8833e1058fb36f2e83af79d5353a9f2f693))\n- **channel:** Fix `isDMBased` docs (#7411) ([f2a7a9f](https://github.com/discordjs/discord.js/commit/f2a7a9f1b30af272a6a8d81825d09f84e749cc24))\n- **messageattachment:** Fix `contentType` docs (#7413) ([2800e07](https://github.com/discordjs/discord.js/commit/2800e07e5974e07b9f8ce043722b9b99a5bcc80d))\n- Add supported option types for autocomplete (#7368) ([8bb3751](https://github.com/discordjs/discord.js/commit/8bb37513400d646d784d59875d6b6a6ec10160cd))\n- Add external builder docs links (#7390) ([0b866c9](https://github.com/discordjs/discord.js/commit/0b866c9fb284971113e288e52327d4506db28011))\n- Add EnumResolvers (#7353) ([72767a1](https://github.com/discordjs/discord.js/commit/72767a1059526bdf617e80d5a9e5da1fbd2936d3))\n- **locales:** Update Discord API docs link (#7266) ([b640272](https://github.com/discordjs/discord.js/commit/b6402723c31bed3c49f8b8cde873b65b9f373fd7))\n- **StageInstance:** Deprecate discoverableDisabled (#7179) ([bd33ebb](https://github.com/discordjs/discord.js/commit/bd33ebb507eab36bc2219103dbd1e0217b9f38c0))\n- **shardingmanager:** Fix type of `execArgv` option (#7284) ([e65da44](https://github.com/discordjs/discord.js/commit/e65da44d9c564d1ffcb0f4df2bcdaf0ce0636f35))\n- **interaction:** Add locale list link (#7261) ([37ec0bd](https://github.com/discordjs/discord.js/commit/37ec0bda6df75fb1dc69b7a1eafbb8ea19e68457))\n- Fix a typo and use milliseconds instead of ms (#7251) ([0dd56af](https://github.com/discordjs/discord.js/commit/0dd56afe1cdf16f1e7d9afe1f8c29c31d1833a25))\n- Fix command interaction docs (#7212) ([137ea24](https://github.com/discordjs/discord.js/commit/137ea249df3aa6b8375ecb42aa456a6fdb811f19))\n- **TextBasedChannel:** Fixed syntax error in examples (#7163) ([b454740](https://github.com/discordjs/discord.js/commit/b454740ae87b6c3c13536181965519c7277e5840))\n- **TextBasedChannel:** Fix #createMessageComponentCollector description (#7168) ([d4e6e03](https://github.com/discordjs/discord.js/commit/d4e6e0370857dff00185d59faf8aaac12b343a7a))\n- Fixes the examples for kick and ban (#7170) ([db669b8](https://github.com/discordjs/discord.js/commit/db669b897132ec458d50ca6c1e3afa761e98ffc3))\n- **RoleManager:** Fix incorrect example (#7174) ([f79ea67](https://github.com/discordjs/discord.js/commit/f79ea67d3a9ba134a9acef0a443bd089c4e173a6))\n\n## Features\n\n- **builder:** Add max min length in string option (#8214) ([96c8d21](https://github.com/discordjs/discord.js/commit/96c8d21f95eb366c46ae23505ba9054f44821b25))\n- **applicationCommand:** Add max min length in string option (#8215) ([94ee60d](https://github.com/discordjs/discord.js/commit/94ee60d3d438f6657bdef51471528769af09624c))\n- Add website documentation early mvp (#8183) ([d95197c](https://github.com/discordjs/discord.js/commit/d95197cc78593df4d0a8d1cc492b0e41b4ab58b8))\n- **BaseInteraction:** Add support for `app_permissions` (#8194) ([002d6a5](https://github.com/discordjs/discord.js/commit/002d6a5aede3d1c0e08bd58eeef38a3b9202f525))\n- **util:** ParseWebhookURL (#8166) ([c4653f9](https://github.com/discordjs/discord.js/commit/c4653f97b1529eb0b99fccdba67c37eb4f467ff9))\n- **AutocompleteInteraction:** Add `commandGuildId` (#8086) ([10a6c42](https://github.com/discordjs/discord.js/commit/10a6c4287dd45a30290814e50fa29a086f85da02))\n- **guild:** Add support for setting MFA level (#8024) ([c5176be](https://github.com/discordjs/discord.js/commit/c5176be14b697ff506eb973c4119644eab544304))\n- **vcs:** Add missing property and methods (#8002) ([0415300](https://github.com/discordjs/discord.js/commit/0415300243877ddbcb501c0a26b1ff65618a1da7))\n- **docgen:** Update typedoc ([b3346f4](https://github.com/discordjs/discord.js/commit/b3346f4b9b3d4f96443506643d4631dc1c6d7b21))\n- Website (#8043) ([127931d](https://github.com/discordjs/discord.js/commit/127931d1df7a2a5c27923c2f2151dbf3824e50cc))\n- Docgen package (#8029) ([8b979c0](https://github.com/discordjs/discord.js/commit/8b979c0245c42fd824d8e98745ee869f5360fc86))\n- Backport handle zombie connection (#7626) ([e1176fa](https://github.com/discordjs/discord.js/commit/e1176faa27898d4f127c293c099201cb294e10ee))\n- **CommandInteraction:** Add 'commandGuildId' (#8018) ([aa59a40](https://github.com/discordjs/discord.js/commit/aa59a409b36c7ef7018d1785d2dba4da17b57864))\n- Allow builders to accept rest params and arrays (#7874) ([ad75be9](https://github.com/discordjs/discord.js/commit/ad75be9a9cf90c8624495df99b75177e6c24022f))\n- **MessageReaction:** Add react method (#7810) ([a328778](https://github.com/discordjs/discord.js/commit/a3287782b57c28b94c390c24e7d5f2d8c303301f))\n- **Collector:** Add `ignore` event (#7644) ([5244fe3](https://github.com/discordjs/discord.js/commit/5244fe3c1cd400985b00e95d8e5ec73823cf4f25))\n- **GuildMemberManager:** Add `GuildMemberManager#fetchMe()` (#7526) ([349766d](https://github.com/discordjs/discord.js/commit/349766dd6925e2d5e5597cc78c73e46f17c56eab))\n- **guildChannelManager:** Add `videoQualityMode` option for `create()` (#7980) ([cdd2ba0](https://github.com/discordjs/discord.js/commit/cdd2ba036ab1559783eb067786c52aff61807557))\n- **EnumResolvers:** Remove Enumresolvers (#7876) ([76694c1](https://github.com/discordjs/discord.js/commit/76694c1497de1b083a792fd1fda20f0eace50c48))\n- Move `me` to `GuildMemberManager` manager (#7669) ([aed687b](https://github.com/discordjs/discord.js/commit/aed687b09f87862eb2f33fb9f95b2cbd0b770585))\n- **rest:** Use undici (#7747) ([d1ec8c3](https://github.com/discordjs/discord.js/commit/d1ec8c37ffb7fe3b63eaa8c382f22ca1fb348c9b))\n- **VoiceChannel:** Add support for text in voice (#6921) ([4ba0f56](https://github.com/discordjs/discord.js/commit/4ba0f56b6af64bac30eea807fb3e9f3c41c3c83c))\n- **SelectMenu:** Allow emojis in options and option constructors (#7797) ([f22245e](https://github.com/discordjs/discord.js/commit/f22245e9d072ac4ef63b0ae0d84d5ba94608ce22))\n- Allow `createMessageComponentCollector` without using `fetchReply` (#7623) ([a58556a](https://github.com/discordjs/discord.js/commit/a58556adc02b2b9239c8f277a4387c743c9d6f04))\n- Add guild directory support (#6788) ([b01f414](https://github.com/discordjs/discord.js/commit/b01f4147d4f3bca021bc269c9f06463f06e3db53))\n- **GuildBanManager:** Support pagination results (#7734) ([fc2a8bb](https://github.com/discordjs/discord.js/commit/fc2a8bb6750919ecd6ee7c872df05f4b677ff5d3))\n- **CommandInteraction:** Add support for localized slash commands (#7684) ([01a423d](https://github.com/discordjs/discord.js/commit/01a423d110cfcddb3d794fcc32579a1547dd472d))\n- Allow emoji strings to be passed through constructors (#7718) ([0faac04](https://github.com/discordjs/discord.js/commit/0faac04b69f1dda3dc860cd584af100e36a40917))\n- **StageInstanceManager:** Add `sendStartNotification` option to create (#7730) ([29f8807](https://github.com/discordjs/discord.js/commit/29f88079559cc02ccfef7a7c16458d481e573fb5))\n- Add `makeURLSearchParams` utility function (#7744) ([8eaec11](https://github.com/discordjs/discord.js/commit/8eaec114a98026024c21545988860c123948c55d))\n- **modal:** Add `awaitModalSubmit` (#7751) ([3037fca](https://github.com/discordjs/discord.js/commit/3037fca196a0f9238d53bb51394daf737bbf3742))\n- **Actions:** Add parent structure to events parameters (#7577) ([3f3e432](https://github.com/discordjs/discord.js/commit/3f3e4327c86da86734c19a96e97115bd505b4532))\n- Export `UnsafeModalBuilder` and `UnsafeTextInputBuilder` (#7628) ([6fec252](https://github.com/discordjs/discord.js/commit/6fec25239dfed46a30826d38dc97f3680f24ec65))\n- **VoiceChannel:** Support `video_quality_mode` (#7722) ([3b3dabf](https://github.com/discordjs/discord.js/commit/3b3dabf3da2e2f24b81967d68b581d7f7452273f))\n- Add API v10 support (#7477) ([72577c4](https://github.com/discordjs/discord.js/commit/72577c4bfd02524a27afb6ff4aebba9301a690d3))\n- **embed:** Remove Embed.setColor (#7662) ([9b0d8cb](https://github.com/discordjs/discord.js/commit/9b0d8cb2d8f7b55753de584eb3a3f347f87596c2))\n- **StageInstance:** Add support for associated guild event (#7576) ([3dff31f](https://github.com/discordjs/discord.js/commit/3dff31f63fe4afdcc818193d737e1917f1ac8105))\n- **VoiceState:** Add edit method (#7569) ([b162f27](https://github.com/discordjs/discord.js/commit/b162f27e46524bfc64515969d753c6e8f30e6c40))\n- **ModalSubmitInteraction:** Add boolean properties (#7596) ([8907390](https://github.com/discordjs/discord.js/commit/89073903a253d9408839573502c72cae93fe70b6))\n- Add Modals and Text Inputs (#7023) ([ed92015](https://github.com/discordjs/discord.js/commit/ed920156344233241a21b0c0b99736a3a855c23c))\n- **discord.js:** Partial transition to undici (#7482) ([5158332](https://github.com/discordjs/discord.js/commit/51583320d3b0f6452cd96bad1021f2a57e4cc6f6))\n- **message:** Add `reason` on pin and unpin (#7520) ([00728f7](https://github.com/discordjs/discord.js/commit/00728f72b36123b607502624b4b02a02ee524d4a))\n- Re-export AuditLogEvent enum (#7528) ([6a2fa70](https://github.com/discordjs/discord.js/commit/6a2fa70b8e79a460be38916eeb605976ad6fe68b))\n- **options:** Add support for custom JSON transformers (#7476) ([dee27db](https://github.com/discordjs/discord.js/commit/dee27db35af379b0835f9fd5cc19563f7bf3dfc0))\n- Add CategoryChannelChildManager (#7320) ([5cf5071](https://github.com/discordjs/discord.js/commit/5cf5071061760c2f9c1e36d7648aef544b03323a))\n  - **Co-authored-by:** Antonio Román <kyradiscord@gmail.com>\n- Attachment application command option type (#7200) ([0034396](https://github.com/discordjs/discord.js/commit/003439671d359dcfe481446ef12b90bd71c57835))\n- **builders:** Add attachment command option type (#7203) ([ae0f35f](https://github.com/discordjs/discord.js/commit/ae0f35f51d68dfa5a7dc43d161ef9365171debdb))\n- **scheduledevents:** Add image option (#7436) ([fbc71ef](https://github.com/discordjs/discord.js/commit/fbc71ef6b668c4b1e2b065d9b65541d9303db0a0))\n- Add methods to managers (#7300) ([dd751ae](https://github.com/discordjs/discord.js/commit/dd751ae19da196cc2f90ccd35c7d8e99878daaf9))\n- **channel:** Add .url getter (#7402) ([f59d630](https://github.com/discordjs/discord.js/commit/f59d6305cb0cd0d154a909f18be76407c4d452d3))\n- **components:** Add unsafe message component builders (#7387) ([6b6222b](https://github.com/discordjs/discord.js/commit/6b6222bf513d1ee8cd98fba0ad313def560b864f))\n- **thread:** Add `newlyCreated` to `threadCreate` event (#7386) ([51beda5](https://github.com/discordjs/discord.js/commit/51beda56f74e44ed013b5d25044b8d5fd1978b29))\n- **channel:** Add isDMBased typeguard (#7362) ([388f535](https://github.com/discordjs/discord.js/commit/388f53550cca7ded7350a050fda03c36e4c1fdf7))\n- **`Interaction`:** Add `.commandType` property to `CommandInteraction` and `AutocompleteInteraction` (#7357) ([567db60](https://github.com/discordjs/discord.js/commit/567db60475c8704661b2e788c9905ef364d6c00c))\n- **scheduledevent:** Add support for event cover images (#7337) ([355f579](https://github.com/discordjs/discord.js/commit/355f579771771a28a293c327a38574c8918d18f8))\n- **enumResolvers:** Strengthen typings (#7344) ([9a566e8](https://github.com/discordjs/discord.js/commit/9a566e8068f28fce87c07861ef1d2877c6ae105f))\n- Allow setting message flags when sending (#7312) ([706db92](https://github.com/discordjs/discord.js/commit/706db9228a91ef42e49d2ec749eac153b9ef75d0))\n- **minor:** Add application_id to Webhook (#7317) ([5ccdb0a](https://github.com/discordjs/discord.js/commit/5ccdb0ab266e4f74c331386ac2d6dd32bc225c62))\n- **threadchannel:** Add `createdTimestamp` field (#7306) ([9a16234](https://github.com/discordjs/discord.js/commit/9a1623425ae2d69f5c16f0096af4951ff5096e80))\n- **GuildPreview:** Add stickers (#7152) ([cf25de9](https://github.com/discordjs/discord.js/commit/cf25de9373df98b3c1cd0ca0a092d9dc8172929d))\n- Enum resolvers & internal enum string removal (#7290) ([213acd7](https://github.com/discordjs/discord.js/commit/213acd799738b888d550cdf3f08906764f8288e0))\n- **guildemojimanager:** Add `delete` and `edit` methods (#7286) ([9181a31](https://github.com/discordjs/discord.js/commit/9181a31e0ba330502052c94da544bb15c8b66f11))\n- **interaction:** Add `isRepliable` type guard (#7259) ([da05a88](https://github.com/discordjs/discord.js/commit/da05a8856b11cc1bf0df424c88a1cf9573e5b654))\n- **Channel:** Improve typeguards (#6957) ([37a22e0](https://github.com/discordjs/discord.js/commit/37a22e04c27724c2a65b05c701e3000ba3653ba1))\n- Add Locales to Interactions (#7131) ([9052e32](https://github.com/discordjs/discord.js/commit/9052e321d1c9c8841962d4e8dc5d9e060b104438))\n- **Permissions:** Remove deprecated thread-related permissions (#6755) ([ab3ff5a](https://github.com/discordjs/discord.js/commit/ab3ff5a262caf7d6225b8d6b54ab2c6b6613c0d0))\n- **VoiceRegion:** Remove the unsent vip field (#6759) ([caaef53](https://github.com/discordjs/discord.js/commit/caaef53dd97ecac9f714072ddba5ae9a99ab1027))\n- **richpresenceassets:** Add YouTube and custom image support (#7184) ([d06d70c](https://github.com/discordjs/discord.js/commit/d06d70ccf26c04c1122fac8430922588a489f95e))\n- **Collector:** Yield all collected values (#7073) ([2b480cb](https://github.com/discordjs/discord.js/commit/2b480cb14e6f52855efcb372da7fb455c15b13b1))\n\n## Refactor\n\n- **Util:** Rename `fetchRecommendedShards` (#8298) ([cafde77](https://github.com/discordjs/discord.js/commit/cafde77d73452d729ba8e2cb1cac3f14235b889b))\n- **Embed:** Add all the types (#8254) ([64f8140](https://github.com/discordjs/discord.js/commit/64f814066cc4adebaca47eb8d7a2040a8df399ae))\n- **rest:** Add content-type(s) to uploads (#8290) ([103a358](https://github.com/discordjs/discord.js/commit/103a3584c95a7b7f57fa62d47b86520d5ec32303))\n- Make `GuildAuditLogsEntry.action` return an `AuditLogEvent` (#8256) ([f0b68d5](https://github.com/discordjs/discord.js/commit/f0b68d57368d7ac3db97925df68c11a945ccd84c))\n- **builder:** Remove `unsafe*Builder`s (#8074) ([a4d1862](https://github.com/discordjs/discord.js/commit/a4d18629828234f43f03d1bd4851d4b727c6903b))\n- Make `ShardEvents` the events of `Shard` (#8185) ([c5750d5](https://github.com/discordjs/discord.js/commit/c5750d59f529ab48a5bc88a73a1c449ef6ddbffd))\n- **Util:** Make single `replace` call in `cleanContent` (#8210) ([6b20645](https://github.com/discordjs/discord.js/commit/6b206457400ce31d566b02a0c135042afb540853))\n- **ApplicationCommandManager:** Use `makeURLSearchParams` (#8196) ([cb3dca4](https://github.com/discordjs/discord.js/commit/cb3dca4ae029724421f3d04a784ace0ae2de75e2))\n- Use `Base` prefix for channel and interaction base classes (#8099) ([e24970e](https://github.com/discordjs/discord.js/commit/e24970e3c3d24f71ba711e59666cd8a49a33e33b))\n- **Constants:** Remove leftover code (#8156) ([cd17aad](https://github.com/discordjs/discord.js/commit/cd17aad720430d23af51c364caeb8b22bf6cb6b5))\n- Errors (#8068) ([e68effa](https://github.com/discordjs/discord.js/commit/e68effa822f064a324ed5b92e797c9fc3ce5e211))\n- **ClientOptions:** Remove `$` prefix from `ws.properties` keys (#8094) ([90a98fe](https://github.com/discordjs/discord.js/commit/90a98fee16b7d1d06768461f4e85127c0edf8419))\n- Use `GuildFeature` enum (#8101) ([e5ec1c4](https://github.com/discordjs/discord.js/commit/e5ec1c4dbc3fa54b2c43d1fec24932d7363e17cb))\n- **util:** Make utility functions top level (#8052) ([e53d162](https://github.com/discordjs/discord.js/commit/e53d1621986035b0c92a1782f6e013d408480e00))\n- **ApplicationCommand:** Permissions v2 (#7857) ([c7391db](https://github.com/discordjs/discord.js/commit/c7391db11b3efd4b1a6904affb26887ad06d6db4))\n- ***:** Include name/reason/etc fields into options/data params (#8026) ([9c8b310](https://github.com/discordjs/discord.js/commit/9c8b3102ce00d1f2c1255c150fb3030f8b6dd026))\n- **ThreadMemberManager:** Consistent thread member fetching (#8021) ([da9107c](https://github.com/discordjs/discord.js/commit/da9107c007536952107bd92943b6c714538d5aeb))\n- **interactions:** Remove redundant interaction typeguards (#8027) ([f57d676](https://github.com/discordjs/discord.js/commit/f57d6768ad24f6e37dc598f9c93709449d3bc4dd))\n- Move all the config files to root (#8033) ([769ea0b](https://github.com/discordjs/discord.js/commit/769ea0bfe78c4f1d413c6b397c604ffe91e39c6a))\n- **channel:** Remove redundant channel type guards (#8012) ([70c733b](https://github.com/discordjs/discord.js/commit/70c733bb9a5bde0f79e6bea0bdc416458bda4c06))\n- Always return `Message` instances in interactions (#7917) ([9720e55](https://github.com/discordjs/discord.js/commit/9720e555340431c3b3ad7bd670ad0ac7eee8865f))\n- **attachment:** Don't return attachment builders from API (#7852) ([dfadcbc](https://github.com/discordjs/discord.js/commit/dfadcbc2fd50be64c8a0c1cae3be10f83678c5ee))\n- Clean up modal submissions (#7994) ([643dab3](https://github.com/discordjs/discord.js/commit/643dab3b1b5305d002fcefed62755bbe11fc3267))\n- **ThreadChannel:** Remove `MAX` helper from threads (#7846) ([dfd9eb2](https://github.com/discordjs/discord.js/commit/dfd9eb20b2d3e0e7db26744b1f15134ac6eda139))\n- **Activity:** Remove undocumented properties (#7844) ([5ba7740](https://github.com/discordjs/discord.js/commit/5ba7740fcfefda1eeba81ace4e6351eac02522a4))\n- **MessageAttachment:** Use `Attachment` instead (#7691) ([ab4c608](https://github.com/discordjs/discord.js/commit/ab4c608b97ff319935e1a7f23564622bfd7ddd57))\n- **Util:** Remove splitting (#7780) ([54e5629](https://github.com/discordjs/discord.js/commit/54e56299865a6746744544ba25d5540a1166d27c))\n- Tidy up builders and components (#7711) ([96a0d83](https://github.com/discordjs/discord.js/commit/96a0d83a1366703ecae40b5e0d5171be9123d079))\n- Remove nickname parsing (#7736) ([78a3afc](https://github.com/discordjs/discord.js/commit/78a3afcd7fdac358e06764cc0d675e1215c785f3))\n- Remove store channels (#7634) ([aedddb8](https://github.com/discordjs/discord.js/commit/aedddb875e740e1f1bd77f06ce1b361fd3b7bc36))\n- **IntegrationApplication:** Remove `summary` (#7729) ([eb6b472](https://github.com/discordjs/discord.js/commit/eb6b472f72488cad7e96befccc00270cf6dc01b8))\n- **GuildAuditLogs:** Remove build (#7704) ([cedd053](https://github.com/discordjs/discord.js/commit/cedd0536baa1301984daf89dfda4e63a7be595a2))\n- **InteractionCollector:** Simplify constructor logic (#7667) ([07b23a9](https://github.com/discordjs/discord.js/commit/07b23a99c7088a7c740f23051f3f755f091519b0))\n- Remove undocumented checks (#7637) ([9a6e691](https://github.com/discordjs/discord.js/commit/9a6e691eaa6c3d133098b2734414590cb838de2e))\n- Allow builders to accept emoji strings (#7616) ([fb9a9c2](https://github.com/discordjs/discord.js/commit/fb9a9c221121ee1c7986f9c775b77b9691a0ae15))\n- Use `static` fields (#7701) ([e805777](https://github.com/discordjs/discord.js/commit/e805777a7a81d1dc7a2edd9741ecb04e685a3886))\n- **EmbedBuilder:** Allow hex strings in setColor (#7673) ([f472975](https://github.com/discordjs/discord.js/commit/f4729759f600372455f062c75859f084e23a5d78))\n- Don't return builders from API data (#7584) ([549716e](https://github.com/discordjs/discord.js/commit/549716e4fcec89ca81216a6d22aa8e623175e37a))\n- **embed:** Allow hex strings in `setColor()` (#7593) ([79d6c04](https://github.com/discordjs/discord.js/commit/79d6c0489c3d563fdd05de63c4fcf93a6deefce1))\n- **InteractionResponses:** Use ClientOptions.jsonTransformer (#7599) ([fac55bc](https://github.com/discordjs/discord.js/commit/fac55bcfd1e8b76aae1273415f74fa6de7aca66d))\n- Deprecate invite stage instance (#7437) ([d2bc9d4](https://github.com/discordjs/discord.js/commit/d2bc9d444f42a70a3c4cc4c68eb107bcaebec509))\n- **guild:** Move `premiumSubscriptionCount` to `AnonymousGuild` (#7451) ([6d3da22](https://github.com/discordjs/discord.js/commit/6d3da226d3c003d137639e719394a807330e4844))\n- **actions:** Use optional chaining (#7460) ([d1bb362](https://github.com/discordjs/discord.js/commit/d1bb36256f2f86022884e6ee9e05b0536cb6384d))\n- **guildbanmanager:** Rename days option to deleteMessageDays (#7447) ([0dfdb2c](https://github.com/discordjs/discord.js/commit/0dfdb2cf11e236e67dd34277108973b5b79790a8))\n- Make public builder props getters (#7422) ([e8252ed](https://github.com/discordjs/discord.js/commit/e8252ed3b981a4b7e4013f12efadd2f5d9318d3e))\n- Remove redundant API defaults (#7449) ([532846b](https://github.com/discordjs/discord.js/commit/532846b1f8260d85022a022d093553310052afc9))\n- Allow discord.js builders to accept camelCase (#7424) ([94bf727](https://github.com/discordjs/discord.js/commit/94bf727cc3a2f11c88e95cdb151b235f775cd1ca))\n- Replace `WSCodes`, `WSEvents`, and `InviteScopes` with `discord-api-types` equivalent (#7409) ([cc25455](https://github.com/discordjs/discord.js/commit/cc25455d2c75177e3eddc880b7fd53cb122387c4))\n- Make constants enums top level and `PascalCase` (#7379) ([d8184f9](https://github.com/discordjs/discord.js/commit/d8184f94dd08daab37195f52828e06af5ed1c1e0))\n- **`Bitfield`:** Use discord-api-types enums instead (#7313) ([fbb1d03](https://github.com/discordjs/discord.js/commit/fbb1d0328bcd517027ad2eedb8753d17489ed851))\n- Use `@discordjs/rest` (#7298) ([ec0fba1](https://github.com/discordjs/discord.js/commit/ec0fba1ed0d3c5b1bb18171ece6fe5ee42d48497))\n- Switch to /builders `Embed` (#7067) ([d2d3a80](https://github.com/discordjs/discord.js/commit/d2d3a80c556a104099a1ddb1b24f1b921c553257))\n- Remove transformPermissions (#7303) ([b4ed8fd](https://github.com/discordjs/discord.js/commit/b4ed8fd3ed953085cd908b2845d4384c8555d3a2))\n- Remove VoiceChannel#editable (#7291) ([164589c](https://github.com/discordjs/discord.js/commit/164589c5516a847457444d11098981d557b6778b))\n- Remove boolean option for `Webhook#fetchMessage` (#7293) ([347ff80](https://github.com/discordjs/discord.js/commit/347ff80bbc9bc5243b7f68ba5d745782eadeba21))\n- **subcommandgroup:** Required default to false (#7217) ([6112767](https://github.com/discordjs/discord.js/commit/6112767128a664f32205425f52ba52220d57834f))\n- **invite:** Make `channel` and `inviter` getters (#7278) ([18b0ed4](https://github.com/discordjs/discord.js/commit/18b0ed4cbe8285637a971c7c99ee49d18060a403))\n- Remove required from getMember (#7188) ([c90e47f](https://github.com/discordjs/discord.js/commit/c90e47f90403e5b1b3499b213dcdf2704fd96b66))\n- Remove djs components and use /builders components instead (#7252) ([101d7c5](https://github.com/discordjs/discord.js/commit/101d7c5ffa03edcf8cb8a0647b77d5c9a38e4bdd))\n- Default *URL methods to animated hash (#7149) ([7c07976](https://github.com/discordjs/discord.js/commit/7c07976018728154be0ce0314d3e8dfe8eb9ed5b))\n- Use setPosition inside edit (#7263) ([0b23b7f](https://github.com/discordjs/discord.js/commit/0b23b7f0394a20596c8d85b82870c3f35ea6b0e0))\n- Don't disable import order lint (#7262) ([0a5d5f3](https://github.com/discordjs/discord.js/commit/0a5d5f38c0b1a249fa2efe16f3b601c90622a4d5))\n- Remove discord.js enums and use discord-api-types enums instead (#7077) ([aa6d1c7](https://github.com/discordjs/discord.js/commit/aa6d1c74de01dd9a8f020c43fb2c193c4729df8d))\n- **application:** Remove fetchAssets (#7250) ([1479e40](https://github.com/discordjs/discord.js/commit/1479e40bcecc4c28ecb9f05fa4fbbdfe3bd387e1))\n- PresenceUpdate and demuxProbe (#7248) ([1745973](https://github.com/discordjs/discord.js/commit/174597302408f13c5bb685e2fb02ae2137cb481d))\n- **embeds:** Don't create new embed instances when unnecessary (#7227) ([822dc67](https://github.com/discordjs/discord.js/commit/822dc678da626de7b4fb22a747cd3cd2e8376732))\n- **GuildMember:** Throw better errors on #kickable and #bannable (#7137) ([4fd127e](https://github.com/discordjs/discord.js/commit/4fd127e79edfa1851f8a10242838f9d7aa68c8c3))\n- **SnowflakeUtil:** Switch to `@sapphire/snowflake` (#7079) ([e082dfb](https://github.com/discordjs/discord.js/commit/e082dfb1584926e4c05face5966d16e4a2921bc5))\n- **InteractionCreate:** Remove interaction event (#6326) ([ae876d9](https://github.com/discordjs/discord.js/commit/ae876d962453ccf843f8e6f70666a98a3173bb75))\n- **MessageCreate:** Remove message event (#6324) ([171e917](https://github.com/discordjs/discord.js/commit/171e917fb96b6bf39a6ad70e83be646f72fe451e))\n- **integration:** Turn undefined into null and consistency (#7209) ([13eb782](https://github.com/discordjs/discord.js/commit/13eb78256da901e6c3c405f546f36617ef5e8239))\n- Remove `deleted` field (#7092) ([cee7fd1](https://github.com/discordjs/discord.js/commit/cee7fd181c464e44eabf20b511d12589f2453722))\n- **Dates:** Save timestamps everywhere and use Date.parse (#7108) ([55e21f5](https://github.com/discordjs/discord.js/commit/55e21f53663a91863c63b6d9f3a8c35564664061))\n- **RoleManager:** Remove `comparePositions()` (#7201) ([fbbac27](https://github.com/discordjs/discord.js/commit/fbbac279789427b2c36869dc47b65fb08431e14d))\n- Better Command Terminology (#7197) ([b7856e7](https://github.com/discordjs/discord.js/commit/b7856e7809ff6fa21fe00286f885808535624f7c))\n- **Actions:** Remove deleted maps (#7076) ([5022b14](https://github.com/discordjs/discord.js/commit/5022b14da09e9b421f947e9bc385a0574cbf07d1))\n- **Client:** Remove applicationCommand events (#6492) ([6085b4f](https://github.com/discordjs/discord.js/commit/6085b4f72723d4ff82f7fea504241d14c94af21e))\n- Remove `Util.removeMentions()` (#6530) ([0c24cc8](https://github.com/discordjs/discord.js/commit/0c24cc8ec0d818315cc8f8bcf74fce060847ac79))\n- **Constants:** Change APPLICATION_COMMAND -> CHAT_INPUT_COMMAND (#7018) ([75616a3](https://github.com/discordjs/discord.js/commit/75616a305f9af33013486b13a872a39212101ce7))\n- **Guild:** Remove deprecated setXPositions methods (#6897) ([43e5e3c](https://github.com/discordjs/discord.js/commit/43e5e3c339a96fa895267d4538eee1d5e5843d05))\n- **UserFlags:** Update flag names (#6938) ([b246fc4](https://github.com/discordjs/discord.js/commit/b246fc4101b8e4957ffd1af8e2e4986a020ca211))\n\n## Styling\n\n- Cleanup tests and tsup configs ([6b8ef20](https://github.com/discordjs/discord.js/commit/6b8ef20cb3af5b5cfd176dd0aa0a1a1e98551629))\n\n## Typings\n\n- **GuildFeature:** Allow feature strings to be passed (#8264) ([b7d4e55](https://github.com/discordjs/discord.js/commit/b7d4e55419207d4e25f5c40cab221c7c04a617bf))\n- **CategoryChannelChildManager:** Fix Holds type (#8288) ([33a7a5c](https://github.com/discordjs/discord.js/commit/33a7a5cbdc00d2a5034dc1ec91fec5da7042f9d0))\n- Remove `MemberMention` (#8292) ([bf65b37](https://github.com/discordjs/discord.js/commit/bf65b37d1a9ea8417e26ad4afacea1eb45a0ff5a))\n- **GuildMemberManager:** Fix placement for `fetchMe()` (#8258) ([7525615](https://github.com/discordjs/discord.js/commit/75256153a9923d94ca709a37aaccc48dfb43c153))\n- Convert `Events` to an enum (#8246) ([feb3bdd](https://github.com/discordjs/discord.js/commit/feb3bdda0a3c3da80378c8cbcafca2968551eef9))\n- **GuildMemberManager:** Non-void return of `edit()` (#8186) ([c7a205f](https://github.com/discordjs/discord.js/commit/c7a205f7b992eea43af13a4638e2a03db7bc0d8a))\n- Add missing shard types (#8180) ([27d8deb](https://github.com/discordjs/discord.js/commit/27d8deb4716a87704370a95103b16fa1b763de18))\n- Implement `GuildChannelEditOptions` (#8184) ([b83e0c0](https://github.com/discordjs/discord.js/commit/b83e0c0caffc2b767aa1ba4412580970a6901899))\n- **Status:** Add missing members (#8179) ([8421f92](https://github.com/discordjs/discord.js/commit/8421f9203bd2d85ef8e64c3fb9a991c74223a75d))\n- **GuildScheduledEvent#scheduledStartAt:** Should be nullish (#8111) ([65dc8d6](https://github.com/discordjs/discord.js/commit/65dc8d677ee81469c0eeb4ecdd83fe2f68cc8982))\n- Fix modal builder constructor data type (#8143) ([7279f9c](https://github.com/discordjs/discord.js/commit/7279f9c31b14bc1e78c63b7298e80e37ca5dfe0c))\n- Use `ThreadAutoArchiveDuration` from discord-api-types (#8145) ([a3799f9](https://github.com/discordjs/discord.js/commit/a3799f9ebb027904830457119708d550e2009200))\n- **Shard#reconnecting:** Fix event name (#8118) ([95e6d6e](https://github.com/discordjs/discord.js/commit/95e6d6ede03c4fb92a8d8027a085e84b043fd895))\n- **ApplicationCommand:** Fix typo in setDMPermission (#8097) ([4df491c](https://github.com/discordjs/discord.js/commit/4df491ce8578a1b01ee8412a4df8137a302e7202))\n- Fix `setType()` parameter and `ChannelData.type` (#8089) ([b4e28a8](https://github.com/discordjs/discord.js/commit/b4e28a8ff6bf165c54a8726d3bc3a3cc0c1e469b))\n- Fix `ApplicationCommandPermissionsUpdate` event typings (#8071) ([9964454](https://github.com/discordjs/discord.js/commit/9964454c2944a0523399481a5f609144486e549b))\n- **AutocompleteOption:** Fix and improve types (#8069) ([476b7d5](https://github.com/discordjs/discord.js/commit/476b7d519c719152ea04e207f6dd09bb23e733db))\n- **ThreadMemberManager:** Fix return type of fetching members with no arguments (#8060) ([2392a6f](https://github.com/discordjs/discord.js/commit/2392a6f5de2efcf6b326173d26295c928b94adb6))\n- Remove isAutocomplete typeguard from typings (#8063) ([c0f079d](https://github.com/discordjs/discord.js/commit/c0f079d2325a636c83ac676c525bfa89ce308b3c))\n- **AttachmentBuilder:** Fix data type (#8016) ([7fa698d](https://github.com/discordjs/discord.js/commit/7fa698d23e548987762c4c66c96c510d9ea56eb4))\n- **modal:** Fix `showModal()` typings (#8014) ([0ccc243](https://github.com/discordjs/discord.js/commit/0ccc243c8ffbf852660c899cc2ad47bd5ebb65cb))\n- Fix some attachment related typings (#8013) ([6aa6232](https://github.com/discordjs/discord.js/commit/6aa623240ee94b117c7e69c1d09b50923a8f7a4c))\n- **AttachmentBuilder:** Remove name parameter from constructor (#8008) ([6266b0c](https://github.com/discordjs/discord.js/commit/6266b0c1e323f9522010f90f34ce6f17fcb6e769))\n- Add types to `EventEmitter` static methods (#7986) ([d60c464](https://github.com/discordjs/discord.js/commit/d60c464e618e4159d2656e7832798909832f33cd))\n- Nullify `guildScheduledEventUpdate`'s old parameter (#7955) ([fdeac9d](https://github.com/discordjs/discord.js/commit/fdeac9d9fba06c532eca296ddd8479047bc732bf))\n- Make `CacheType` generic more accurate for return values (#7868) ([e07b910](https://github.com/discordjs/discord.js/commit/e07b910e684bc3cf71fb93417951ad42351bace4))\n- **guildScheduledEvent:** Mark `entityMetadata` as nullable (#7908) ([64bdf53](https://github.com/discordjs/discord.js/commit/64bdf53116945ffb51764bb8ec539d530aefcfb1))\n- **discord.js:** Export missing enums (#7864) ([5eeef3f](https://github.com/discordjs/discord.js/commit/5eeef3f708eb900ec994d837fb4cd414a4f4b437))\n- Fix return type of `toString()` on channels (#7836) ([ece6289](https://github.com/discordjs/discord.js/commit/ece628986c7eb1a66f46076d8f8518c9ff00aaf3))\n- **Message#activity:** Make `partyId` optional and use enum for `type` (#7845) ([bfeaf85](https://github.com/discordjs/discord.js/commit/bfeaf856f76eb7cb756ac55aac13636ccdb345b6))\n- Cleanup *Data type definitions (#7716) ([585169f](https://github.com/discordjs/discord.js/commit/585169f2f097ffb1940d17f549e4290aa55acde2))\n- Fix BooleanCache never resolving to true (#7809) ([440ac24](https://github.com/discordjs/discord.js/commit/440ac243ca1d6f8cd04603e63e3f2f6ea1722ee8))\n- **CommandInteraction:** Add awaitModalSubmit (#7811) ([a6d9ce5](https://github.com/discordjs/discord.js/commit/a6d9ce57c6cae90d0afc60010cad44fdc2c2d06c))\n- **ThreadChannel:** Fix autoArchiveDuration types (#7816) ([0857476](https://github.com/discordjs/discord.js/commit/08574763eb665b5a43ccfb826929f1e3f0d1c3a7))\n- Add missing typing (#7781) ([f094e33](https://github.com/discordjs/discord.js/commit/f094e338617a1a3c9f48a325e4b8e9b5a405aa91))\n- **VoiceChannel:** Nullify property (#7793) ([446eb39](https://github.com/discordjs/discord.js/commit/446eb390ce58b7e7f60e297b25f53773a55f7fb9))\n- **ModalSubmitInteraction:** Message (#7705) ([b577bcc](https://github.com/discordjs/discord.js/commit/b577bcc1df5c6424fef9984e19a5f11c77371cf3))\n- **Embed:** Add missing getters and add video to EmbedData (#7728) ([fd1dc72](https://github.com/discordjs/discord.js/commit/fd1dc72c0a77dbe18753d8db22972dfa5fe4ab36))\n- **ModalSubmitInteraction:** Fix `components` type (#7732) ([6f4e97b](https://github.com/discordjs/discord.js/commit/6f4e97bfafe4a058f6ec85d321676401d701ee55))\n- **interactionCollector:** Filter should have a collected argument (#7753) ([e4f2705](https://github.com/discordjs/discord.js/commit/e4f27051ca921d299c302b600a8c2917e9356ef6))\n- Fix regressions (#7649) ([5748dbe](https://github.com/discordjs/discord.js/commit/5748dbe08783beb80c526de38ccd105eb0e82664))\n- **Constants:** Add `NonSystemMessageTypes` (#7678) ([9afc030](https://github.com/discordjs/discord.js/commit/9afc03054e4c8973702d6c18e618643f76382dd9))\n- Fix auto archive duration type (#7688) ([8e3b2d7](https://github.com/discordjs/discord.js/commit/8e3b2d7abd38136534969cf77c6a748ee3a20355))\n- **InteractionResponseFields:** Add webhook (#7597) ([daf2829](https://github.com/discordjs/discord.js/commit/daf2829cb58d1a44cb1f1ece21e428d1a23e99c9))\n- **Embed:** Add forgotten `footer` type (#7665) ([8fb9816](https://github.com/discordjs/discord.js/commit/8fb98165a9d098ab316475d6baacb015783eb638))\n- **ColorResolvable:** Simplify string types (#7643) ([2297c2b](https://github.com/discordjs/discord.js/commit/2297c2b9479ace16f5f7155479605a4ac2718e3d))\n- Allow component classes in action row data (#7614) ([230c0c4](https://github.com/discordjs/discord.js/commit/230c0c4cb137882ff7bab783a4aeaa83ae941de5))\n- **ActionRow:** Allow components to be passed to constructors (#7531) ([e71c76c](https://github.com/discordjs/discord.js/commit/e71c76c7f795837dbcc3576e507bd286640b4296))\n- **showModal:** Align types with the documentation (#7600) ([0d7e4ed](https://github.com/discordjs/discord.js/commit/0d7e4edd969513692c061c107be4bbe7e4b54321))\n- Modals type and doc fixes (#7608) ([93854a8](https://github.com/discordjs/discord.js/commit/93854a8013d07234cb849bfcbfa99f74a4c3cdb4))\n- **InteractionResponseFields:** Add boolean properties (#7565) ([53defb8](https://github.com/discordjs/discord.js/commit/53defb82e36108468e35077b887ee28b811891ab))\n- Allow raw components for reply and message options (#7573) ([2d4971b](https://github.com/discordjs/discord.js/commit/2d4971b032a01c05b55c93d6475e61b0d25d69d3))\n- Fix component *Data types (#7536) ([a8321d8](https://github.com/discordjs/discord.js/commit/a8321d8026df2e6a09d867939986bf77f894f3a8))\n- Use discord-api-types `Locale` (#7541) ([8346003](https://github.com/discordjs/discord.js/commit/83460037be840ba623f3b02a3e6f218943f9d2b7))\n- **anychannel:** Add PartialGroupDMChannel (#7472) ([cf66930](https://github.com/discordjs/discord.js/commit/cf669301c7be8eaecf91d7f764eccc67d7a5b4c6))\n- Remove `ApplicationCommandInteractionOptionResolver` (#7491) ([71f4fa8](https://github.com/discordjs/discord.js/commit/71f4fa82ed6206d6843345a5394119f2a728aa35))\n- **embed:** Fix timestamp allowed types (#7470) ([7959a68](https://github.com/discordjs/discord.js/commit/7959a68d8ec600af248f5506f39871cae7eeeb04))\n- Remove duplicate rate limit for thread creation (#7465) ([2d2de1d](https://github.com/discordjs/discord.js/commit/2d2de1d3fd15a098d69e09710e9a7a3352234fef))\n- Correct types for InteractionCollector guild and channel (#7452) ([6ce906a](https://github.com/discordjs/discord.js/commit/6ce906a02fcb051cb6df3e9f453ba9f53db03bd0))\n- Fix `GuildAuditLogsTypes` keys & typos (#7423) ([3d8c776](https://github.com/discordjs/discord.js/commit/3d8c77600be51a86a99b526078bb1b1fcb9a0811))\n- Remove duplicate `GuildChannelOverwriteOptions` interface (#7428) ([83458ff](https://github.com/discordjs/discord.js/commit/83458ff7c782b8efdaaac931d2dee1764dad25bf))\n- Use `GuildFeature` enum from `discord-api-types` (#7397) ([a7b80b9](https://github.com/discordjs/discord.js/commit/a7b80b9d9bf4902bd85b592986771eadf7a765dc))\n- Fix *BitField.Flags properties (#7363) ([e6a26d2](https://github.com/discordjs/discord.js/commit/e6a26d25b3cf8dfcc8aa8997b021f1774f3b754b))\n- Fix MessageMentions channel types (#7316) ([c05b388](https://github.com/discordjs/discord.js/commit/c05b38873bb3c37c6e4ebcb6b6373a8858cc03de))\n- Fix channel create overloads (#7294) ([1c6c944](https://github.com/discordjs/discord.js/commit/1c6c9449ad68601c6c98748d73be8114401d38ef))\n- Fix regressions and inconsistencies (#7260) ([26a9dc3](https://github.com/discordjs/discord.js/commit/26a9dc32062cd071917bbe7264050315b4d6dd3c))\n- **interaction:** Remove renamed typeguards (#7220) ([68b9564](https://github.com/discordjs/discord.js/commit/68b9564f1821726377a1e929a3ca1fc65b4ad598))\n- AssertType -> expectType ([3f36746](https://github.com/discordjs/discord.js/commit/3f36746561a40cd61a7cd2e054b7ef80d58fc707))\n- Fix cache types resolving to `never` (#7164) ([c978dbb](https://github.com/discordjs/discord.js/commit/c978dbb6233bcd85408caf0bca7619c9c5d508f0))\n"
  },
  {
    "path": "packages/discord.js/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2021 Noel Buechler\n   Copyright 2015 Amish Shah\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/discord.js/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/discord.js\"><img src=\"https://img.shields.io/npm/v/discord.js.svg?maxAge=3600\" alt=\"npm version\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/discord.js\"><img src=\"https://img.shields.io/npm/dt/discord.js.svg?maxAge=3600\" alt=\"npm downloads\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Tests status\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/commits/main/packages/discord.js\"><img alt=\"Last commit.\" src=\"https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fdiscord.js\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t\t<a href=\"https://codecov.io/gh/discordjs/discord.js\"><img src=\"https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2\" alt=\"Code coverage\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## About\n\ndiscord.js is a powerful [Node.js](https://nodejs.org) module that allows you to easily interact with the\n[Discord API](https://discord.com/developers/docs/intro).\n\n- Object-oriented\n- Predictable abstractions\n- Performant\n- 100% coverage of the Discord API\n\n## Installation\n\n**Node.js 22.12.0 or newer is required.**\n\n```sh\nnpm install discord.js\nyarn add discord.js\npnpm add discord.js\nbun add discord.js\n```\n\n### Optional packages\n\n- [zlib-sync](https://www.npmjs.com/package/zlib-sync) for WebSocket data compression and inflation (`npm install zlib-sync`)\n- [bufferutil](https://www.npmjs.com/package/bufferutil) for a much faster WebSocket connection (`npm install bufferutil`)\n- [@discordjs/voice](https://www.npmjs.com/package/@discordjs/voice) for interacting with the Discord Voice API (`npm install @discordjs/voice`)\n\n## Example usage\n\nInstall discord.js:\n\n```sh\nnpm install discord.js\nyarn add discord.js\npnpm add discord.js\nbun add discord.js\n```\n\nThese examples use [ES modules](https://nodejs.org/api/esm.html#enabling).\n\nRegister a slash command against the Discord API:\n\n```js\nimport { REST, Routes } from 'discord.js';\n\nconst commands = [\n  {\n    name: 'ping',\n    description: 'Replies with Pong!',\n  },\n];\n\nconst rest = new REST({ version: '10' }).setToken(TOKEN);\n\ntry {\n  console.log('Started refreshing application (/) commands.');\n\n  await rest.put(Routes.applicationCommands(CLIENT_ID), { body: commands });\n\n  console.log('Successfully reloaded application (/) commands.');\n} catch (error) {\n  console.error(error);\n}\n```\n\nAfterwards we can create a quite simple example bot:\n\n```js\nimport { Client, Events, GatewayIntentBits } from 'discord.js';\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds] });\n\nclient.on(Events.ClientReady, readyClient => {\n  console.log(`Logged in as ${readyClient.user.tag}!`);\n});\n\nclient.on(Events.InteractionCreate, async interaction => {\n  if (!interaction.isChatInputCommand()) return;\n\n  if (interaction.commandName === 'ping') {\n    await interaction.reply('Pong!');\n  }\n});\n\nclient.login(TOKEN);\n```\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Documentation][documentation]\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [npm][npm]\n- [Related libraries][related-libs]\n\n### Extensions\n\n- [RPC][rpc] ([source][rpc-source])\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the\n[documentation][documentation].  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs/packages/discord.js/stable\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/discord.js\n[npm]: https://www.npmjs.com/package/discord.js\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[rpc]: https://www.npmjs.com/package/discord-rpc\n[rpc-source]: https://github.com/discordjs/RPC\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/discord.js/api-extractor.json",
    "content": "{\n  \"extends\": \"../../api-extractor.json\",\n  \"mainEntryPointFilePath\": \"<projectFolder>/typings/index.d.ts\",\n  \"bundledPackages\": [\n    \"discord-api-types\",\n    \"@discordjs/builders\",\n    \"@discordjs/collection\",\n    \"@discordjs/formatters\",\n    \"@discordjs/rest\",\n    \"@discordjs/util\",\n    \"@discordjs/ws\"\n  ],\n  \"docModel\": {\n    \"projectFolderUrl\": \"https://github.com/discordjs/discord.js/tree/main/packages/discord.js\"\n  }\n}\n"
  },
  {
    "path": "packages/discord.js/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t\t{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length %}\\\n\t\\n### New Contributors\\n\n\t{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\\\n\t\t* @{{ contributor.username }} made their first contribution in #{{ contributor.pr_number }}\n\t{% endfor %}\\\n{% endif %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^typings\", group = \"Typings\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"^[0-9]+\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/discord.js/docs/README.md",
    "content": "## [View the documentation here.](https://discord.js.org/docs/packages/discord.js/main)\n"
  },
  {
    "path": "packages/discord.js/docs/index.json",
    "content": "[{ \"name\": \"General\", \"files\": [{ \"name\": \"Welcome\", \"id\": \"welcome\", \"path\": \"../../README.md\" }] }]\n"
  },
  {
    "path": "packages/discord.js/package.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/package.json\",\n  \"name\": \"discord.js\",\n  \"version\": \"14.16.3\",\n  \"description\": \"A powerful library for interacting with the Discord API\",\n  \"scripts\": {\n    \"test\": \"pnpm run docs:test && pnpm run test:typescript\",\n    \"test:typescript\": \"tsc --noEmit && tsd\",\n    \"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty scripts src typings\",\n    \"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty scripts src typings\",\n    \"fmt\": \"pnpm run format\",\n    \"docs\": \"docgen -i \\\"./src/*.js\\\" \\\"./src/**/*.js\\\" -c ./docs/index.json -r ../../ -o ./docs/docs.json && pnpm run docs:new\",\n    \"docs:test\": \"docgen -i \\\"./src/*.js\\\" \\\"./src/**/*.js\\\" -c ./docs/index.json -r ../../\",\n    \"docs:new\": \"api-extractor run --local --minify && generate-split-documentation\",\n    \"prepack\": \"pnpm run lint && pnpm run test && node ./scripts/esmDts.mjs\",\n    \"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/discord.js/*'\",\n    \"release\": \"cliff-jumper\"\n  },\n  \"main\": \"./src/index.js\",\n  \"types\": \"./typings/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"import\": {\n        \"types\": \"./typings/index.d.mts\",\n        \"default\": \"./src/index.js\"\n      },\n      \"require\": {\n        \"types\": \"./typings/index.d.ts\",\n        \"default\": \"./src/index.js\"\n      }\n    }\n  },\n  \"directories\": {\n    \"lib\": \"src\",\n    \"test\": \"test\"\n  },\n  \"files\": [\n    \"src\",\n    \"typings/*.d.ts\",\n    \"typings/*.d.mts\"\n  ],\n  \"contributors\": [\n    \"Crawl <icrawltogo@gmail.com>\",\n    \"Amish Shah <amishshah.2k@gmail.com>\",\n    \"Vlad Frangu <me@vladfrangu.dev>\",\n    \"SpaceEEC <spaceeec@yahoo.com>\",\n    \"Aura Román <kyradiscord@gmail.com>\"\n  ],\n  \"license\": \"Apache-2.0\",\n  \"keywords\": [\n    \"discord\",\n    \"api\",\n    \"bot\",\n    \"client\",\n    \"node\",\n    \"discordapp\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/discordjs/discord.js.git\",\n    \"directory\": \"packages/discord.js\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/discordjs/discord.js/issues\"\n  },\n  \"homepage\": \"https://discord.js.org\",\n  \"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n  \"dependencies\": {\n    \"@discordjs/collection\": \"workspace:^\",\n    \"@discordjs/formatters\": \"workspace:^\",\n    \"@discordjs/rest\": \"workspace:^\",\n    \"@discordjs/util\": \"workspace:^\",\n    \"@discordjs/ws\": \"workspace:^\",\n    \"@sapphire/snowflake\": \"3.5.5\",\n    \"@vladfrangu/async_event_emitter\": \"^2.4.7\",\n    \"discord-api-types\": \"^0.38.41\",\n    \"fast-deep-equal\": \"3.1.3\",\n    \"lodash.snakecase\": \"4.1.1\",\n    \"magic-bytes.js\": \"^1.13.0\",\n    \"tslib\": \"^2.8.1\",\n    \"undici\": \"7.22.0\"\n  },\n  \"devDependencies\": {\n    \"@discordjs/api-extractor\": \"workspace:^\",\n    \"@discordjs/builders\": \"workspace:^\",\n    \"@discordjs/docgen\": \"workspace:^\",\n    \"@discordjs/scripts\": \"workspace:^\",\n    \"@favware/cliff-jumper\": \"^6.0.0\",\n    \"@types/node\": \"^22.19.11\",\n    \"cross-env\": \"^10.1.0\",\n    \"eslint\": \"^9.39.2\",\n    \"eslint-config-neon\": \"^0.3.2\",\n    \"eslint-formatter-compact\": \"^9.0.1\",\n    \"eslint-formatter-pretty\": \"^7.0.0\",\n    \"prettier\": \"^3.8.1\",\n    \"tsd\": \"^0.33.0\",\n    \"turbo\": \"^2.8.10\",\n    \"typescript\": \"~5.9.3\"\n  },\n  \"engines\": {\n    \"node\": \">=22.12.0\"\n  },\n  \"publishConfig\": {\n    \"provenance\": true\n  }\n}\n"
  },
  {
    "path": "packages/discord.js/scripts/esmDts.mjs",
    "content": "import { cp } from 'node:fs/promises';\n\nconst rawIndexDTS = new URL('../typings/index.d.ts', import.meta.url);\nconst rawIndexMTS = new URL('../typings/index.d.mts', import.meta.url);\n\nawait cp(rawIndexDTS, rawIndexMTS);\n"
  },
  {
    "path": "packages/discord.js/scripts/generateRequires.mjs",
    "content": "import { readdir, writeFile } from 'node:fs/promises';\n\nasync function writeWebsocketHandlerImports() {\n  const lines = [\"'use strict';\\n\", 'const PacketHandlers = Object.fromEntries(['];\n\n  const handlersDirectory = new URL('../src/client/websocket/handlers', import.meta.url);\n\n  for (const file of (await readdir(handlersDirectory)).sort()) {\n    if (file === 'index.js') continue;\n\n    lines.push(`  ['${file.slice(0, -3)}', require('./${file}')],`);\n  }\n\n  lines.push(']);\\n\\nexports.PacketHandlers = PacketHandlers;\\n');\n\n  const outputFile = new URL('../src/client/websocket/handlers/index.js', import.meta.url);\n\n  await writeFile(outputFile, lines.join('\\n'));\n}\n\nasync function writeClientActionImports() {\n  const lines = [\n    \"'use strict';\\n\",\n    'class ActionsManager {',\n    '  // These symbols represent fully built data that we inject at times when calling actions manually.',\n    '  // Action#getUser, for example, will return the injected data (which is assumed to be a built structure)',\n    '  // instead of trying to make it from provided data',\n    \"  injectedUser = Symbol('djs.actions.injectedUser');\\n\",\n    \"  injectedChannel = Symbol('djs.actions.injectedChannel');\\n\",\n    \"  injectedMessage = Symbol('djs.actions.injectedMessage');\\n\",\n    '  constructor(client) {',\n    '    this.client = client;\\n',\n  ];\n\n  const actionsDirectory = new URL('../src/client/actions', import.meta.url);\n  for (const file of (await readdir(actionsDirectory)).sort()) {\n    if (file === 'Action.js' || file === 'ActionsManager.js') continue;\n\n    const actionName = file.slice(0, -3);\n\n    lines.push(`    this.${actionName} = this.load(require('./${file}').${actionName}Action);`);\n  }\n\n  lines.push('  }\\n');\n  lines.push('  load(Action) {');\n  lines.push('    return new Action(this.client);');\n  lines.push('  }');\n  lines.push('}\\n');\n  lines.push('exports.ActionsManager = ActionsManager;\\n');\n\n  const outputFile = new URL('../src/client/actions/ActionsManager.js', import.meta.url);\n\n  await writeFile(outputFile, lines.join('\\n'));\n}\n\nwriteWebsocketHandlerImports();\nwriteClientActionImports();\n"
  },
  {
    "path": "packages/discord.js/src/client/Client.js",
    "content": "'use strict';\n\nconst process = require('node:process');\nconst { clearTimeout, setImmediate, setTimeout } = require('node:timers');\nconst { Collection } = require('@discordjs/collection');\nconst { REST, RESTEvents, makeURLSearchParams } = require('@discordjs/rest');\nconst { WebSocketManager, WebSocketShardEvents, WebSocketShardStatus } = require('@discordjs/ws');\nconst { AsyncEventEmitter } = require('@vladfrangu/async_event_emitter');\nconst { GatewayDispatchEvents, GatewayIntentBits, OAuth2Scopes, Routes } = require('discord-api-types/v10');\nconst { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { ChannelManager } = require('../managers/ChannelManager.js');\nconst { GuildManager } = require('../managers/GuildManager.js');\nconst { UserManager } = require('../managers/UserManager.js');\nconst { ShardClientUtil } = require('../sharding/ShardClientUtil.js');\nconst { ClientPresence } = require('../structures/ClientPresence.js');\nconst { GuildPreview } = require('../structures/GuildPreview.js');\nconst { GuildTemplate } = require('../structures/GuildTemplate.js');\nconst { SoundboardSound } = require('../structures/SoundboardSound.js');\nconst { Sticker } = require('../structures/Sticker.js');\nconst { StickerPack } = require('../structures/StickerPack.js');\nconst { VoiceRegion } = require('../structures/VoiceRegion.js');\nconst { Webhook } = require('../structures/Webhook.js');\nconst { Widget } = require('../structures/Widget.js');\nconst { resolveInviteCode, resolveGuildTemplateCode } = require('../util/DataResolver.js');\nconst { Events } = require('../util/Events.js');\nconst { IntentsBitField } = require('../util/IntentsBitField.js');\nconst { createInvite } = require('../util/Invites.js');\nconst { Options } = require('../util/Options.js');\nconst { PermissionsBitField } = require('../util/PermissionsBitField.js');\nconst { Status } = require('../util/Status.js');\nconst { Sweepers } = require('../util/Sweepers.js');\nconst { flatten } = require('../util/Util.js');\nconst { ActionsManager } = require('./actions/ActionsManager.js');\nconst { ClientVoiceManager } = require('./voice/ClientVoiceManager.js');\nconst { PacketHandlers } = require('./websocket/handlers/index.js');\n\nconst WaitingForGuildEvents = [GatewayDispatchEvents.GuildCreate, GatewayDispatchEvents.GuildDelete];\nconst BeforeReadyWhitelist = [\n  GatewayDispatchEvents.Ready,\n  GatewayDispatchEvents.Resumed,\n  GatewayDispatchEvents.GuildCreate,\n  GatewayDispatchEvents.GuildDelete,\n  GatewayDispatchEvents.GuildMembersChunk,\n  GatewayDispatchEvents.GuildMemberAdd,\n  GatewayDispatchEvents.GuildMemberRemove,\n];\n\n/**\n * The main hub for interacting with the Discord API, and the starting point for any bot.\n *\n * @extends {AsyncEventEmitter}\n */\nclass Client extends AsyncEventEmitter {\n  /**\n   * @param {ClientOptions} options Options for the client\n   */\n  constructor(options) {\n    super();\n\n    if (typeof options !== 'object' || options === null) {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true);\n    }\n\n    const defaultOptions = Options.createDefault();\n    /**\n     * The options the client was instantiated with\n     *\n     * @type {ClientOptions}\n     */\n    this.options = {\n      ...defaultOptions,\n      ...options,\n      presence: {\n        ...defaultOptions.presence,\n        ...options.presence,\n      },\n      sweepers: {\n        ...defaultOptions.sweepers,\n        ...options.sweepers,\n      },\n      ws: {\n        ...defaultOptions.ws,\n        ...options.ws,\n      },\n      rest: {\n        ...defaultOptions.rest,\n        ...options.rest,\n        userAgentAppendix: options.rest?.userAgentAppendix\n          ? `${Options.userAgentAppendix} ${options.rest.userAgentAppendix}`\n          : Options.userAgentAppendix,\n      },\n    };\n\n    /**\n     * The REST manager of the client\n     *\n     * @type {REST}\n     */\n    this.rest = new REST(this.options.rest);\n\n    this.rest.on(RESTEvents.Debug, message => this.emit(Events.Debug, message));\n\n    const data = require('node:worker_threads').workerData ?? process.env;\n\n    if (this.options.ws.shardIds === defaultOptions.ws.shardIds && 'SHARDS' in data) {\n      const shards = JSON.parse(data.SHARDS);\n      this.options.ws.shardIds = Array.isArray(shards) ? shards : [shards];\n    }\n\n    if (this.options.ws.shardCount === defaultOptions.ws.shardCount && 'SHARD_COUNT' in data) {\n      this.options.ws.shardCount = Number(data.SHARD_COUNT);\n    }\n\n    /**\n     * The presence of the Client\n     *\n     * @private\n     * @type {ClientPresence}\n     */\n    this.presence = new ClientPresence(this, this.options.ws.initialPresence ?? this.options.presence);\n\n    this._validateOptions();\n\n    /**\n     * The current status of this Client\n     *\n     * @type {Status}\n     * @private\n     */\n    this.status = Status.Idle;\n\n    /**\n     * A set of guild ids this Client expects to receive\n     *\n     * @name Client#expectedGuilds\n     * @type {Set<string>}\n     * @private\n     */\n    Object.defineProperty(this, 'expectedGuilds', { value: new Set(), writable: true });\n\n    /**\n     * The ready timeout\n     *\n     * @name Client#readyTimeout\n     * @type {?NodeJS.Timeout}\n     * @private\n     */\n    Object.defineProperty(this, 'readyTimeout', { value: null, writable: true });\n\n    /**\n     * The action manager of the client\n     *\n     * @type {ActionsManager}\n     * @private\n     */\n    this.actions = new ActionsManager(this);\n\n    /**\n     * The user manager of this client\n     *\n     * @type {UserManager}\n     */\n    this.users = new UserManager(this);\n\n    /**\n     * A manager of all the guilds the client is currently handling -\n     * as long as sharding isn't being used, this will be *every* guild the bot is a member of\n     *\n     * @type {GuildManager}\n     */\n    this.guilds = new GuildManager(this);\n\n    /**\n     * All of the {@link BaseChannel}s that the client is currently handling -\n     * as long as sharding isn't being used, this will be *every* channel in *every* guild the bot\n     * is a member of. Note that DM channels will not be initially cached, and thus not be present\n     * in the Manager without their explicit fetching or use.\n     *\n     * @type {ChannelManager}\n     */\n    this.channels = new ChannelManager(this);\n\n    /**\n     * The sweeping functions and their intervals used to periodically sweep caches\n     *\n     * @type {Sweepers}\n     */\n    this.sweepers = new Sweepers(this, this.options.sweepers);\n\n    Object.defineProperty(this, 'token', { writable: true });\n    if (!this.token && 'DISCORD_TOKEN' in process.env) {\n      /**\n       * Authorization token for the logged in bot.\n       * If present, this defaults to `process.env.DISCORD_TOKEN` when instantiating the client\n       * <warn>This should be kept private at all times.</warn>\n       *\n       * @type {?string}\n       */\n      this.token = process.env.DISCORD_TOKEN;\n    } else if (this.options.ws.token) {\n      this.token = this.options.ws.token;\n    } else {\n      this.token = null;\n    }\n\n    const wsOptions = {\n      ...this.options.ws,\n      intents: this.options.intents.bitfield,\n      fetchGatewayInformation: () => this.rest.get(Routes.gatewayBot()),\n      // Explicitly nulled to always be set using `setToken` in `login`\n      token: null,\n    };\n\n    /**\n     * The WebSocket manager of the client\n     *\n     * @type {WebSocketManager}\n     */\n    this.ws = new WebSocketManager(wsOptions);\n\n    /**\n     * Shard helpers for the client (only if the process was spawned from a {@link ShardingManager})\n     *\n     * @type {?ShardClientUtil}\n     */\n    this.shard = process.env.SHARDING_MANAGER\n      ? ShardClientUtil.singleton(this, process.env.SHARDING_MANAGER_MODE)\n      : null;\n\n    /**\n     * The voice manager of the client\n     *\n     * @type {ClientVoiceManager}\n     */\n    this.voice = new ClientVoiceManager(this);\n\n    /**\n     * User that the client is logged in as\n     *\n     * @type {?ClientUser}\n     */\n    this.user = null;\n\n    /**\n     * The application of this bot\n     *\n     * @type {?ClientApplication}\n     */\n    this.application = null;\n\n    /**\n     * The latencies of the WebSocketShard connections\n     *\n     * @type {Collection<number, number>}\n     */\n    this.pings = new Collection();\n\n    /**\n     * The last time a ping was sent (a timestamp) for each WebSocketShard connection\n     *\n     * @type {Collection<number, number>}\n     */\n    this.lastPingTimestamps = new Collection();\n\n    /**\n     * Timestamp of the time the client was last {@link Status.Ready} at\n     *\n     * @type {?number}\n     */\n    this.readyTimestamp = null;\n\n    /**\n     * An array of queued events before this Client became ready\n     *\n     * @type {Object[]}\n     * @private\n     * @name Client#incomingPacketQueue\n     */\n    Object.defineProperty(this, 'incomingPacketQueue', { value: [] });\n\n    this._attachEvents();\n  }\n\n  /**\n   * Time at which the client was last regarded as being in the {@link Status.Ready} state\n   * (each time the client disconnects and successfully reconnects, this will be overwritten)\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get readyAt() {\n    return this.readyTimestamp && new Date(this.readyTimestamp);\n  }\n\n  /**\n   * How long it has been since the client last entered the {@link Status.Ready} state in milliseconds\n   *\n   * @type {?number}\n   * @readonly\n   */\n  get uptime() {\n    return this.readyTimestamp && Date.now() - this.readyTimestamp;\n  }\n\n  /**\n   * Logs the client in, establishing a WebSocket connection to Discord.\n   *\n   * @param {string} [token=this.token] Token of the account to log in with\n   * @returns {Promise<string>} Token of the account used\n   * @example\n   * client.login('my token');\n   */\n  async login(token = this.token) {\n    if (!token || typeof token !== 'string') throw new DiscordjsError(ErrorCodes.TokenInvalid);\n    this.token = token.replace(/^bot\\s*/i, '');\n\n    this.rest.setToken(this.token);\n\n    this.emit(Events.Debug, `Provided token: ${this._censoredToken}`);\n    this.emit(Events.Debug, 'Preparing to connect to the gateway...');\n\n    this.ws.setToken(this.token);\n\n    try {\n      await this.ws.connect();\n      return this.token;\n    } catch (error) {\n      await this.destroy();\n      throw error;\n    }\n  }\n\n  /**\n   * Checks if the client can be marked as ready\n   *\n   * @private\n   */\n  async _checkReady() {\n    // Step 0. Clear the ready timeout, if it exists\n    if (this.readyTimeout) {\n      clearTimeout(this.readyTimeout);\n      this.readyTimeout = null;\n    }\n\n    // Step 1. If we don't have any other guilds pending, we are ready\n    if (\n      !this.expectedGuilds.size &&\n      (await this.ws.fetchStatus()).every(status => status === WebSocketShardStatus.Ready)\n    ) {\n      this.emit(Events.Debug, 'Client received all its guilds. Marking as fully ready.');\n\n      this._triggerClientReady();\n      return;\n    }\n\n    const hasGuildsIntent = this.options.intents.has(GatewayIntentBits.Guilds);\n    // Step 2. Create a timeout that will mark the client as ready if there are still unavailable guilds\n    // * The timeout is 15 seconds by default\n    // * This can be optionally changed in the client options via the `waitGuildTimeout` option\n    // * a timeout time of zero will skip this timeout, which potentially could cause the Client to miss guilds.\n\n    this.readyTimeout = setTimeout(\n      () => {\n        this.emit(\n          Events.Debug,\n          `${\n            hasGuildsIntent\n              ? `Client did not receive any guild packets in ${this.options.waitGuildTimeout} ms.`\n              : 'Client will not receive anymore guild packets.'\n          }\\nUnavailable guild count: ${this.expectedGuilds.size}`,\n        );\n\n        this.readyTimeout = null;\n\n        this._triggerClientReady();\n      },\n      hasGuildsIntent ? this.options.waitGuildTimeout : 0,\n    ).unref();\n  }\n\n  /**\n   * Attaches event handlers to the WebSocketShardManager from `@discordjs/ws`.\n   *\n   * @private\n   */\n  _attachEvents() {\n    this.ws.on(WebSocketShardEvents.Debug, (message, shardId) =>\n      this.emit(Events.Debug, `[WS => ${typeof shardId === 'number' ? `Shard ${shardId}` : 'Manager'}] ${message}`),\n    );\n    this.ws.on(WebSocketShardEvents.Dispatch, this._handlePacket.bind(this));\n\n    this.ws.on(WebSocketShardEvents.HeartbeatComplete, ({ heartbeatAt, latency }, shardId) => {\n      this.emit(Events.Debug, `[WS => Shard ${shardId}] Heartbeat acknowledged, latency of ${latency}ms.`);\n      this.lastPingTimestamps.set(shardId, heartbeatAt);\n      this.pings.set(shardId, latency);\n    });\n  }\n\n  /**\n   * Processes a packet and queues it if this WebSocketManager is not ready.\n   *\n   * @param {GatewayDispatchPayload} packet The packet to be handled\n   * @param {number} shardId The shardId that received this packet\n   * @private\n   */\n  async _handlePacket(packet, shardId) {\n    if (this.status !== Status.Ready && !BeforeReadyWhitelist.includes(packet.t)) {\n      this.incomingPacketQueue.push({ packet, shardId });\n    } else {\n      if (this.incomingPacketQueue.length) {\n        const item = this.incomingPacketQueue.shift();\n        setImmediate(async () => {\n          await this._handlePacket(item.packet, item.shardId);\n        }).unref();\n      }\n\n      if (PacketHandlers[packet.t]) {\n        PacketHandlers[packet.t](this, packet, shardId);\n      }\n\n      if (packet.t === GatewayDispatchEvents.Ready) {\n        await this._checkReady();\n      } else if (this.status === Status.WaitingForGuilds && WaitingForGuildEvents.includes(packet.t)) {\n        this.expectedGuilds.delete(packet.d.id);\n        await this._checkReady();\n      }\n    }\n  }\n\n  /**\n   * Broadcasts a packet to every shard of this client handles.\n   *\n   * @param {Object} packet The packet to send\n   * @private\n   */\n  async _broadcast(packet) {\n    const shardIds = await this.ws.getShardIds();\n    return Promise.all(shardIds.map(shardId => this.ws.send(shardId, packet)));\n  }\n\n  /**\n   * Causes the client to be marked as ready and emits the ready event.\n   *\n   * @private\n   */\n  _triggerClientReady() {\n    this.status = Status.Ready;\n\n    this.readyTimestamp = Date.now();\n\n    /**\n     * Emitted when the client becomes ready to start working.\n     *\n     * @event Client#clientReady\n     * @param {Client} client The client\n     */\n    this.emit(Events.ClientReady, this);\n  }\n\n  /**\n   * Returns whether the client has logged in, indicative of being able to access\n   * properties such as `user` and `application`.\n   *\n   * @returns {boolean}\n   */\n  isReady() {\n    return this.status === Status.Ready;\n  }\n\n  /**\n   * The average ping of all WebSocketShards\n   *\n   * @type {?number}\n   * @readonly\n   */\n  get ping() {\n    return this.pings.size ? this.pings.reduce((a, b) => a + b, 0) / this.pings.size : null;\n  }\n\n  /**\n   * Options used for deleting a webhook.\n   *\n   * @typedef {Object} WebhookDeleteOptions\n   * @property {string} [token] Token of the webhook\n   * @property {string} [reason] The reason for deleting the webhook\n   */\n\n  /**\n   * Deletes a webhook.\n   *\n   * @param {Snowflake} id The webhook's id\n   * @param {WebhookDeleteOptions} [options] Options for deleting the webhook\n   * @returns {Promise<void>}\n   */\n  async deleteWebhook(id, { token, reason } = {}) {\n    await this.rest.delete(Routes.webhook(id, token), { auth: !token, reason });\n  }\n\n  /**\n   * Increments max listeners by one, if they are not zero.\n   *\n   * @private\n   */\n  incrementMaxListeners() {\n    const maxListeners = this.getMaxListeners();\n    if (maxListeners !== 0) {\n      this.setMaxListeners(maxListeners + 1);\n    }\n  }\n\n  /**\n   * Decrements max listeners by one, if they are not zero.\n   *\n   * @private\n   */\n  decrementMaxListeners() {\n    const maxListeners = this.getMaxListeners();\n    if (maxListeners !== 0) {\n      this.setMaxListeners(maxListeners - 1);\n    }\n  }\n\n  /**\n   * Destroys all assets used by the client.\n   *\n   * @returns {Promise<void>}\n   */\n  async destroy() {\n    this.rest.clearHashSweeper();\n    this.rest.clearHandlerSweeper();\n\n    this.sweepers.destroy();\n    await this.ws.destroy();\n    this.token = null;\n    this.rest.setToken(null);\n  }\n\n  /**\n   * Options used when fetching an invite from Discord.\n   *\n   * @typedef {Object} ClientFetchInviteOptions\n   * @property {boolean} [withCounts] Whether to include approximate member counts\n   * @property {Snowflake} [guildScheduledEventId] The id of the guild scheduled event to include with\n   * the invite\n   */\n\n  /**\n   * Obtains an invite from Discord.\n   *\n   * @param {InviteResolvable} invite Invite code or URL\n   * @param {ClientFetchInviteOptions} [options] Options for fetching the invite\n   * @returns {Promise<Invite>}\n   * @example\n   * client.fetchInvite('https://discord.gg/djs')\n   *   .then(invite => console.log(`Obtained invite with code: ${invite.code}`))\n   *   .catch(console.error);\n   */\n  async fetchInvite(invite, { withCounts, guildScheduledEventId } = {}) {\n    const code = resolveInviteCode(invite);\n\n    const query = makeURLSearchParams({\n      with_counts: withCounts,\n      guild_scheduled_event_id: guildScheduledEventId,\n    });\n\n    const data = await this.rest.get(Routes.invite(code), { query });\n    return createInvite(this, data);\n  }\n\n  /**\n   * Obtains a template from Discord.\n   *\n   * @param {GuildTemplateResolvable} template Template code or URL\n   * @returns {Promise<GuildTemplate>}\n   * @example\n   * client.fetchGuildTemplate('https://discord.new/FKvmczH2HyUf')\n   *   .then(template => console.log(`Obtained template with code: ${template.code}`))\n   *   .catch(console.error);\n   */\n  async fetchGuildTemplate(template) {\n    const code = resolveGuildTemplateCode(template);\n    const data = await this.rest.get(Routes.template(code));\n    return new GuildTemplate(this, data);\n  }\n\n  /**\n   * Obtains a webhook from Discord.\n   *\n   * @param {Snowflake} id The webhook's id\n   * @param {string} [token] Token for the webhook\n   * @returns {Promise<Webhook>}\n   * @example\n   * client.fetchWebhook('id', 'token')\n   *   .then(webhook => console.log(`Obtained webhook with name: ${webhook.name}`))\n   *   .catch(console.error);\n   */\n  async fetchWebhook(id, token) {\n    const data = await this.rest.get(Routes.webhook(id, token), { auth: token === undefined });\n    return new Webhook(this, { token, ...data });\n  }\n\n  /**\n   * Obtains the available voice regions from Discord.\n   *\n   * @returns {Promise<Collection<string, VoiceRegion>>}\n   * @example\n   * client.fetchVoiceRegions()\n   *   .then(regions => console.log(`Available regions are: ${regions.map(region => region.name).join(', ')}`))\n   *   .catch(console.error);\n   */\n  async fetchVoiceRegions() {\n    const apiRegions = await this.rest.get(Routes.voiceRegions());\n    const regions = new Collection();\n    for (const region of apiRegions) regions.set(region.id, new VoiceRegion(region));\n    return regions;\n  }\n\n  /**\n   * Obtains a sticker from Discord.\n   *\n   * @param {Snowflake} id The sticker's id\n   * @returns {Promise<Sticker>}\n   * @example\n   * client.fetchSticker('id')\n   *   .then(sticker => console.log(`Obtained sticker with name: ${sticker.name}`))\n   *   .catch(console.error);\n   */\n  async fetchSticker(id) {\n    const data = await this.rest.get(Routes.sticker(id));\n    return new Sticker(this, data);\n  }\n\n  /**\n   * Options for fetching sticker packs.\n   *\n   * @typedef {Object} StickerPackFetchOptions\n   * @property {Snowflake} [packId] The id of the sticker pack to fetch\n   */\n\n  /**\n   * Obtains the list of available sticker packs.\n   *\n   * @param {StickerPackFetchOptions} [options={}] Options for fetching sticker packs\n   * @returns {Promise<Collection<Snowflake, StickerPack>|StickerPack>}\n   * A collection of sticker packs, or a single sticker pack if a packId was provided\n   * @example\n   * client.fetchStickerPacks()\n   *   .then(packs => console.log(`Available sticker packs are: ${packs.map(pack => pack.name).join(', ')}`))\n   *   .catch(console.error);\n   * @example\n   * client.fetchStickerPacks({ packId: '751604115435421716' })\n   *   .then(pack => console.log(`Sticker pack name: ${pack.name}`))\n   *   .catch(console.error);\n   */\n  async fetchStickerPacks({ packId } = {}) {\n    if (packId) {\n      const innerData = await this.rest.get(Routes.stickerPack(packId));\n      return new StickerPack(this, innerData);\n    }\n\n    const data = await this.rest.get(Routes.stickerPacks());\n    return new Collection(data.sticker_packs.map(stickerPack => [stickerPack.id, new StickerPack(this, stickerPack)]));\n  }\n\n  /**\n   * Obtains the list of default soundboard sounds.\n   *\n   * @returns {Promise<Collection<string, SoundboardSound>>}\n   * @example\n   * client.fetchDefaultSoundboardSounds()\n   *  .then(sounds => console.log(`Available soundboard sounds are: ${sounds.map(sound => sound.name).join(', ')}`))\n   *  .catch(console.error);\n   */\n  async fetchDefaultSoundboardSounds() {\n    const data = await this.rest.get(Routes.soundboardDefaultSounds());\n    return new Collection(data.map(sound => [sound.sound_id, new SoundboardSound(this, sound)]));\n  }\n\n  /**\n   * Obtains a guild preview from Discord, available for all guilds the bot is in and all Discoverable guilds.\n   *\n   * @param {GuildResolvable} guild The guild to fetch the preview for\n   * @returns {Promise<GuildPreview>}\n   */\n  async fetchGuildPreview(guild) {\n    const id = this.guilds.resolveId(guild);\n    if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'guild', 'GuildResolvable');\n    const data = await this.rest.get(Routes.guildPreview(id));\n    return new GuildPreview(this, data);\n  }\n\n  /**\n   * Obtains the widget data of a guild from Discord, available for guilds with the widget enabled.\n   *\n   * @param {GuildResolvable} guild The guild to fetch the widget data for\n   * @returns {Promise<Widget>}\n   */\n  async fetchGuildWidget(guild) {\n    const id = this.guilds.resolveId(guild);\n    if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'guild', 'GuildResolvable');\n    const data = await this.rest.get(Routes.guildWidgetJSON(id));\n    return new Widget(this, data);\n  }\n\n  /**\n   * Options for {@link Client#generateInvite}.\n   *\n   * @typedef {Object} InviteGenerationOptions\n   * @property {OAuth2Scopes[]} scopes Scopes that should be requested\n   * @property {PermissionResolvable} [permissions] Permissions to request\n   * @property {GuildResolvable} [guild] Guild to preselect\n   * @property {boolean} [disableGuildSelect] Whether to disable the guild selection\n   */\n\n  /**\n   * Generates a link that can be used to invite the bot to a guild.\n   *\n   * @param {InviteGenerationOptions} [options={}] Options for the invite\n   * @returns {string}\n   * @example\n   * const link = client.generateInvite({\n   *   scopes: [OAuth2Scopes.ApplicationsCommands],\n   * });\n   * console.log(`Generated application invite link: ${link}`);\n   * @example\n   * const link = client.generateInvite({\n   *   permissions: [\n   *     PermissionFlagsBits.SendMessages,\n   *     PermissionFlagsBits.ManageGuild,\n   *     PermissionFlagsBits.MentionEveryone,\n   *   ],\n   *   scopes: [OAuth2Scopes.Bot],\n   * });\n   * console.log(`Generated bot invite link: ${link}`);\n   */\n  generateInvite(options = {}) {\n    if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true);\n    if (!this.application) throw new DiscordjsError(ErrorCodes.ClientNotReady, 'generate an invite link');\n\n    const { scopes } = options;\n    if (scopes === undefined) {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidMissingScopes);\n    }\n\n    if (!Array.isArray(scopes)) {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'scopes', 'Array of Invite Scopes', true);\n    }\n\n    if (!scopes.some(scope => [OAuth2Scopes.Bot, OAuth2Scopes.ApplicationsCommands].includes(scope))) {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidMissingScopes);\n    }\n\n    if (!scopes.includes(OAuth2Scopes.Bot) && options.permissions) {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidScopesWithPermissions);\n    }\n\n    const validScopes = Object.values(OAuth2Scopes);\n    const invalidScope = scopes.find(scope => !validScopes.includes(scope));\n    if (invalidScope) {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array', 'scopes', invalidScope);\n    }\n\n    const query = makeURLSearchParams({\n      client_id: this.application.id,\n      scope: scopes.join(' '),\n      disable_guild_select: options.disableGuildSelect,\n    });\n\n    if (options.permissions) {\n      const permissions = PermissionsBitField.resolve(options.permissions);\n      if (permissions) query.set('permissions', permissions.toString());\n    }\n\n    if (options.guild) {\n      const guildId = this.guilds.resolveId(options.guild);\n      if (!guildId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options.guild', 'GuildResolvable');\n      query.set('guild_id', guildId);\n    }\n\n    return `${this.options.rest.api}${Routes.oauth2Authorization()}?${query}`;\n  }\n\n  toJSON() {\n    return flatten(this, { actions: false, presence: false });\n  }\n\n  /**\n   * Partially censored client token for debug logging purposes.\n   *\n   * @type {?string}\n   * @readonly\n   * @private\n   */\n  get _censoredToken() {\n    if (!this.token) return null;\n\n    return this.token\n      .split('.')\n      .map((val, index) => (index > 1 ? val.replaceAll(/./g, '*') : val))\n      .join('.');\n  }\n\n  /**\n   * Calls {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/eval} on a script\n   * with the client as `this`.\n   *\n   * @param {string} script Script to eval\n   * @returns {*}\n   * @private\n   */\n  _eval(script) {\n    // eslint-disable-next-line no-eval\n    return eval(script);\n  }\n\n  /**\n   * Validates the client options.\n   *\n   * @param {ClientOptions} [options=this.options] Options to validate\n   * @private\n   */\n  _validateOptions(options = this.options) {\n    if (options.intents === undefined && options.ws?.intents === undefined) {\n      throw new DiscordjsTypeError(ErrorCodes.ClientMissingIntents);\n    } else {\n      options.intents = new IntentsBitField(options.intents ?? options.ws.intents).freeze();\n    }\n\n    if (typeof options.sweepers !== 'object' || options.sweepers === null) {\n      throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'sweepers', 'an object');\n    }\n\n    if (!Array.isArray(options.partials)) {\n      throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'partials', 'an Array');\n    }\n\n    if (typeof options.waitGuildTimeout !== 'number' || Number.isNaN(options.waitGuildTimeout)) {\n      throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'waitGuildTimeout', 'a number');\n    }\n\n    if (typeof options.failIfNotExists !== 'boolean') {\n      throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'failIfNotExists', 'a boolean');\n    }\n\n    if (typeof options.enforceNonce !== 'boolean') {\n      throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'enforceNonce', 'a boolean');\n    }\n\n    if (\n      (typeof options.allowedMentions !== 'object' && options.allowedMentions !== undefined) ||\n      options.allowedMentions === null\n    ) {\n      throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'allowedMentions', 'an object');\n    }\n\n    if (typeof options.ws !== 'object' || options.ws === null) {\n      throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'ws', 'an object');\n    }\n\n    if (\n      (typeof options.presence !== 'object' || options.presence === null) &&\n      options.ws.initialPresence === undefined\n    ) {\n      throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'presence', 'an object');\n    } else {\n      options.ws.initialPresence = options.ws.initialPresence ?? this.presence._parse(this.options.presence);\n    }\n\n    if (typeof options.rest !== 'object' || options.rest === null) {\n      throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'rest', 'an object');\n    }\n\n    if (typeof options.jsonTransformer !== 'function') {\n      throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'jsonTransformer', 'a function');\n    }\n  }\n\n  async [Symbol.asyncDispose]() {\n    await this.destroy();\n  }\n}\n\nexports.Client = Client;\n\n/**\n * @class SnowflakeUtil\n * @classdesc This class is an alias for {@link https://www.npmjs.com/package/@sapphire/snowflake @sapphire/snowflake}'s\n * `DiscordSnowflake` class.\n *\n * Check their documentation\n * {@link https://www.sapphirejs.dev/docs/Documentation/api-utilities/classes/sapphire_snowflake.Snowflake here}\n * ({@link https://www.sapphirejs.dev/docs/Guide/utilities/snowflake guide})\n * to see what you can do.\n * @hideconstructor\n */\n\n/**\n * A {@link https://docs.x.com/resources/fundamentals/x-ids Twitter snowflake},\n * except the epoch is 2015-01-01T00:00:00.000Z.\n *\n * If we have a snowflake '266241948824764416' we can represent it as binary:\n * ```\n * 64                                          22     17     12          0\n *  000000111011000111100001101001000101000000  00001  00000  000000000000\n *  number of milliseconds since Discord epoch  worker  pid    increment\n * ```\n *\n * @typedef {string} Snowflake\n */\n\n/**\n * Emitted for general debugging information.\n *\n * @event Client#debug\n * @param {string} info The debug information\n */\n\n/**\n * Emitted for general warnings.\n *\n * @event Client#warn\n * @param {string} info The warning\n */\n\n/**\n * @external Collection\n * @see {@link https://discord.js.org/docs/packages/collection/stable/Collection:Class}\n */\n\n/**\n * @external REST\n * @see {@link https://discord.js.org/docs/packages/rest/stable/REST:Class}\n */\n\n/**\n * @external ImageURLOptions\n * @see {@link https://discord.js.org/docs/packages/rest/stable/ImageURLOptions:Interface}\n */\n\n/**\n * @external EmojiURLOptions\n * @see {@link https://discord.js.org/docs/packages/rest/stable/EmojiURLOptions:TypeAlias}\n */\n\n/**\n * @external BaseImageURLOptions\n * @see {@link https://discord.js.org/docs/packages/rest/stable/BaseImageURLOptions:Interface}\n */\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/Action.js",
    "content": "'use strict';\n\nconst { Poll } = require('../../structures/Poll.js');\nconst { PollAnswer } = require('../../structures/PollAnswer.js');\nconst { Partials } = require('../../util/Partials.js');\n\n/*\n\nABOUT ACTIONS\n\nActions are similar to WebSocket Packet Handlers, but since introducing\nthe REST API methods, in order to prevent rewriting code to handle data,\n\"actions\" have been introduced. They're basically what Packet Handlers\nused to be but they're strictly for manipulating data and making sure\nthat WebSocket events don't clash with REST methods.\n\n*/\n\nclass Action {\n  constructor(client) {\n    this.client = client;\n  }\n\n  handle(data) {\n    return data;\n  }\n\n  getPayload(data, manager, id, partialType, cache) {\n    return this.client.options.partials.includes(partialType) ? manager._add(data, cache) : manager.cache.get(id);\n  }\n\n  getChannel(data) {\n    const payloadData = {};\n    const id = data.channel_id ?? data.id;\n\n    if (!('recipients' in data)) {\n      // Try to resolve the recipient, but do not add the client user.\n      const recipient = data.author ?? data.user ?? { id: data.user_id };\n      if (recipient.id !== this.client.user.id) payloadData.recipients = [recipient];\n    }\n\n    if (id !== undefined) payloadData.id = id;\n\n    return (\n      data[this.client.actions.injectedChannel] ??\n      this.getPayload({ ...data, ...payloadData }, this.client.channels, id, Partials.Channel)\n    );\n  }\n\n  getMessage(data, channel, cache) {\n    const id = data.message_id ?? data.id;\n    return (\n      data[this.client.actions.injectedMessage] ??\n      this.getPayload(\n        {\n          id,\n          channel_id: channel.id,\n          guild_id: data.guild_id ?? channel.guild?.id,\n        },\n        channel.messages,\n        id,\n        Partials.Message,\n        cache,\n      )\n    );\n  }\n\n  getPoll(data, message, channel) {\n    const includePollPartial = this.client.options.partials.includes(Partials.Poll);\n    const includePollAnswerPartial = this.client.options.partials.includes(Partials.PollAnswer);\n    if (message.partial && (!includePollPartial || !includePollAnswerPartial)) return null;\n\n    if (!message.poll && includePollPartial) {\n      message.poll = new Poll(this.client, data, message, channel);\n    }\n\n    if (message.poll && !message.poll.answers.has(data.answer_id) && includePollAnswerPartial) {\n      const pollAnswer = new PollAnswer(this.client, data, message.poll);\n      message.poll.answers.set(data.answer_id, pollAnswer);\n    }\n\n    return message.poll;\n  }\n\n  getReaction(data, message, user) {\n    const id = data.emoji.id ?? decodeURIComponent(data.emoji.name);\n    return this.getPayload(\n      {\n        emoji: data.emoji,\n        count: message.partial ? null : 0,\n        me: user?.id === this.client.user.id,\n      },\n      message.reactions,\n      id,\n      Partials.Reaction,\n    );\n  }\n\n  getMember(data, guild) {\n    return this.getPayload(data, guild.members, data.user.id, Partials.GuildMember);\n  }\n\n  getUser(data) {\n    const id = data.user_id;\n    return data[this.client.actions.injectedUser] ?? this.getPayload({ id }, this.client.users, id, Partials.User);\n  }\n\n  getUserFromMember(data) {\n    if (data.guild_id && data.member?.user) {\n      const guild = this.client.guilds.cache.get(data.guild_id);\n      if (guild) {\n        return guild.members._add(data.member).user;\n      } else {\n        return this.client.users._add(data.member.user);\n      }\n    }\n\n    return this.getUser(data);\n  }\n\n  getScheduledEvent(data, guild) {\n    const id = data.guild_scheduled_event_id ?? data.id;\n    return this.getPayload(\n      { id, guild_id: data.guild_id ?? guild.id },\n      guild.scheduledEvents,\n      id,\n      Partials.GuildScheduledEvent,\n    );\n  }\n\n  getThreadMember(id, manager) {\n    return this.getPayload({ user_id: id }, manager, id, Partials.ThreadMember, false);\n  }\n\n  getSoundboardSound(data, guild) {\n    return this.getPayload(data, guild.soundboardSounds, data.sound_id, Partials.SoundboardSound);\n  }\n\n  spreadInjectedData(data) {\n    return Object.fromEntries(Object.getOwnPropertySymbols(data).map(symbol => [symbol, data[symbol]]));\n  }\n}\n\nexports.Action = Action;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/ActionsManager.js",
    "content": "'use strict';\n\nclass ActionsManager {\n  // These symbols represent fully built data that we inject at times when calling actions manually.\n  // Action#getUser, for example, will return the injected data (which is assumed to be a built structure)\n  // instead of trying to make it from provided data\n  injectedUser = Symbol('djs.actions.injectedUser');\n\n  injectedChannel = Symbol('djs.actions.injectedChannel');\n\n  injectedMessage = Symbol('djs.actions.injectedMessage');\n\n  constructor(client) {\n    this.client = client;\n\n    this.ChannelCreate = this.load(require('./ChannelCreate.js').ChannelCreateAction);\n    this.ChannelDelete = this.load(require('./ChannelDelete.js').ChannelDeleteAction);\n    this.ChannelUpdate = this.load(require('./ChannelUpdate.js').ChannelUpdateAction);\n    this.GuildChannelsPositionUpdate = this.load(\n      require('./GuildChannelsPositionUpdate.js').GuildChannelsPositionUpdateAction,\n    );\n    this.GuildEmojiCreate = this.load(require('./GuildEmojiCreate.js').GuildEmojiCreateAction);\n    this.GuildEmojiDelete = this.load(require('./GuildEmojiDelete.js').GuildEmojiDeleteAction);\n    this.GuildEmojiUpdate = this.load(require('./GuildEmojiUpdate.js').GuildEmojiUpdateAction);\n    this.GuildEmojisUpdate = this.load(require('./GuildEmojisUpdate.js').GuildEmojisUpdateAction);\n    this.GuildMemberRemove = this.load(require('./GuildMemberRemove.js').GuildMemberRemoveAction);\n    this.GuildMemberUpdate = this.load(require('./GuildMemberUpdate.js').GuildMemberUpdateAction);\n    this.GuildRoleCreate = this.load(require('./GuildRoleCreate.js').GuildRoleCreateAction);\n    this.GuildRoleDelete = this.load(require('./GuildRoleDelete.js').GuildRoleDeleteAction);\n    this.GuildRolesPositionUpdate = this.load(require('./GuildRolesPositionUpdate.js').GuildRolesPositionUpdateAction);\n    this.GuildScheduledEventDelete = this.load(\n      require('./GuildScheduledEventDelete.js').GuildScheduledEventDeleteAction,\n    );\n    this.GuildScheduledEventUserAdd = this.load(\n      require('./GuildScheduledEventUserAdd.js').GuildScheduledEventUserAddAction,\n    );\n    this.GuildScheduledEventUserRemove = this.load(\n      require('./GuildScheduledEventUserRemove.js').GuildScheduledEventUserRemoveAction,\n    );\n    this.GuildSoundboardSoundDelete = this.load(\n      require('./GuildSoundboardSoundDelete.js').GuildSoundboardSoundDeleteAction,\n    );\n    this.GuildStickerCreate = this.load(require('./GuildStickerCreate.js').GuildStickerCreateAction);\n    this.GuildStickerDelete = this.load(require('./GuildStickerDelete.js').GuildStickerDeleteAction);\n    this.GuildStickerUpdate = this.load(require('./GuildStickerUpdate.js').GuildStickerUpdateAction);\n    this.GuildStickersUpdate = this.load(require('./GuildStickersUpdate.js').GuildStickersUpdateAction);\n    this.GuildUpdate = this.load(require('./GuildUpdate.js').GuildUpdateAction);\n    this.InteractionCreate = this.load(require('./InteractionCreate.js').InteractionCreateAction);\n    this.MessageCreate = this.load(require('./MessageCreate.js').MessageCreateAction);\n    this.MessageDelete = this.load(require('./MessageDelete.js').MessageDeleteAction);\n    this.MessageDeleteBulk = this.load(require('./MessageDeleteBulk.js').MessageDeleteBulkAction);\n    this.MessagePollVoteAdd = this.load(require('./MessagePollVoteAdd.js').MessagePollVoteAddAction);\n    this.MessagePollVoteRemove = this.load(require('./MessagePollVoteRemove.js').MessagePollVoteRemoveAction);\n    this.MessageReactionAdd = this.load(require('./MessageReactionAdd.js').MessageReactionAddAction);\n    this.MessageReactionRemove = this.load(require('./MessageReactionRemove.js').MessageReactionRemoveAction);\n    this.MessageReactionRemoveAll = this.load(require('./MessageReactionRemoveAll.js').MessageReactionRemoveAllAction);\n    this.MessageReactionRemoveEmoji = this.load(\n      require('./MessageReactionRemoveEmoji.js').MessageReactionRemoveEmojiAction,\n    );\n    this.MessageUpdate = this.load(require('./MessageUpdate.js').MessageUpdateAction);\n    this.StageInstanceCreate = this.load(require('./StageInstanceCreate.js').StageInstanceCreateAction);\n    this.StageInstanceDelete = this.load(require('./StageInstanceDelete.js').StageInstanceDeleteAction);\n    this.StageInstanceUpdate = this.load(require('./StageInstanceUpdate.js').StageInstanceUpdateAction);\n    this.ThreadCreate = this.load(require('./ThreadCreate.js').ThreadCreateAction);\n    this.ThreadMembersUpdate = this.load(require('./ThreadMembersUpdate.js').ThreadMembersUpdateAction);\n    this.TypingStart = this.load(require('./TypingStart.js').TypingStartAction);\n    this.UserUpdate = this.load(require('./UserUpdate.js').UserUpdateAction);\n  }\n\n  load(Action) {\n    return new Action(this.client);\n  }\n}\n\nexports.ActionsManager = ActionsManager;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/ChannelCreate.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass ChannelCreateAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const existing = client.channels.cache.has(data.id);\n    const channel = client.channels._add(data);\n    if (!existing && channel) {\n      /**\n       * Emitted whenever a guild channel is created.\n       *\n       * @event Client#channelCreate\n       * @param {GuildChannel} channel The channel that was created\n       */\n      client.emit(Events.ChannelCreate, channel);\n    }\n\n    return { channel };\n  }\n}\n\nexports.ChannelCreateAction = ChannelCreateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/ChannelDelete.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass ChannelDeleteAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const channel = client.channels.cache.get(data.id);\n\n    if (channel) {\n      client.channels._remove(channel.id);\n      /**\n       * Emitted whenever a channel is deleted.\n       *\n       * @event Client#channelDelete\n       * @param {DMChannel|GuildChannel} channel The channel that was deleted\n       */\n      client.emit(Events.ChannelDelete, channel);\n    }\n  }\n}\n\nexports.ChannelDeleteAction = ChannelDeleteAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/ChannelUpdate.js",
    "content": "'use strict';\n\nconst { createChannel } = require('../../util/Channels.js');\nconst { Action } = require('./Action.js');\n\nclass ChannelUpdateAction extends Action {\n  handle(data) {\n    const client = this.client;\n    let channel = client.channels.cache.get(data.id);\n\n    if (channel) {\n      const old = channel._update(data);\n\n      if (channel.type !== data.type) {\n        const newChannel = createChannel(this.client, data, channel.guild);\n\n        if (!newChannel) {\n          this.client.channels.cache.delete(channel.id);\n          return {};\n        }\n\n        if (channel.isTextBased() && newChannel.isTextBased()) {\n          for (const [id, message] of channel.messages.cache) newChannel.messages.cache.set(id, message);\n        }\n\n        channel = newChannel;\n        this.client.channels.cache.set(channel.id, channel);\n      }\n\n      return {\n        old,\n        updated: channel,\n      };\n    } else {\n      client.channels._add(data);\n    }\n\n    return {};\n  }\n}\n\nexports.ChannelUpdateAction = ChannelUpdateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildChannelsPositionUpdate.js",
    "content": "'use strict';\n\nconst { Action } = require('./Action.js');\n\nclass GuildChannelsPositionUpdateAction extends Action {\n  handle(data) {\n    const client = this.client;\n\n    const guild = client.guilds.cache.get(data.guild_id);\n    if (guild) {\n      for (const partialChannel of data.channels) {\n        const channel = guild.channels.cache.get(partialChannel.id);\n        if (channel) channel.rawPosition = partialChannel.position;\n      }\n    }\n\n    return { guild };\n  }\n}\n\nexports.GuildChannelsPositionUpdateAction = GuildChannelsPositionUpdateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildEmojiCreate.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass GuildEmojiCreateAction extends Action {\n  handle(guild, createdEmoji) {\n    const already = guild.emojis.cache.has(createdEmoji.id);\n    const emoji = guild.emojis._add(createdEmoji);\n    /**\n     * Emitted whenever a custom emoji is created in a guild.\n     *\n     * @event Client#emojiCreate\n     * @param {GuildEmoji} emoji The emoji that was created\n     */\n    if (!already) this.client.emit(Events.GuildEmojiCreate, emoji);\n    return { emoji };\n  }\n}\n\nexports.GuildEmojiCreateAction = GuildEmojiCreateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildEmojiDelete.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass GuildEmojiDeleteAction extends Action {\n  handle(emoji) {\n    emoji.guild.emojis.cache.delete(emoji.id);\n    /**\n     * Emitted whenever a custom emoji is deleted in a guild.\n     *\n     * @event Client#emojiDelete\n     * @param {GuildEmoji} emoji The emoji that was deleted\n     */\n    this.client.emit(Events.GuildEmojiDelete, emoji);\n    return { emoji };\n  }\n}\n\nexports.GuildEmojiDeleteAction = GuildEmojiDeleteAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildEmojiUpdate.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass GuildEmojiUpdateAction extends Action {\n  handle(current, data) {\n    const old = current._update(data);\n    /**\n     * Emitted whenever a custom emoji is updated in a guild.\n     *\n     * @event Client#emojiUpdate\n     * @param {GuildEmoji} oldEmoji The old emoji\n     * @param {GuildEmoji} newEmoji The new emoji\n     */\n    this.client.emit(Events.GuildEmojiUpdate, old, current);\n    return { emoji: current };\n  }\n}\n\nexports.GuildEmojiUpdateAction = GuildEmojiUpdateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildEmojisUpdate.js",
    "content": "'use strict';\n\nconst { Action } = require('./Action.js');\n\nclass GuildEmojisUpdateAction extends Action {\n  handle(data) {\n    const guild = this.client.guilds.cache.get(data.guild_id);\n    if (!guild?.emojis) return;\n\n    const deletions = new Map(guild.emojis.cache);\n\n    for (const emoji of data.emojis) {\n      // Determine type of emoji event\n      const cachedEmoji = guild.emojis.cache.get(emoji.id);\n      if (cachedEmoji) {\n        deletions.delete(emoji.id);\n        if (!cachedEmoji.equals(emoji)) {\n          // Emoji updated\n          this.client.actions.GuildEmojiUpdate.handle(cachedEmoji, emoji);\n        }\n      } else {\n        // Emoji added\n        this.client.actions.GuildEmojiCreate.handle(guild, emoji);\n      }\n    }\n\n    for (const emoji of deletions.values()) {\n      // Emoji deleted\n      this.client.actions.GuildEmojiDelete.handle(emoji);\n    }\n  }\n}\n\nexports.GuildEmojisUpdateAction = GuildEmojisUpdateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildMemberRemove.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass GuildMemberRemoveAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const guild = client.guilds.cache.get(data.guild_id);\n    let member = null;\n    if (guild) {\n      member = this.getMember({ user: data.user }, guild);\n      guild.memberCount--;\n      if (member) {\n        guild.members.cache.delete(member.id);\n        /**\n         * Emitted whenever a member leaves a guild, or is kicked.\n         *\n         * @event Client#guildMemberRemove\n         * @param {GuildMember} member The member that has left/been kicked from the guild\n         */\n        client.emit(Events.GuildMemberRemove, member);\n      }\n\n      guild.presences.cache.delete(data.user.id);\n      guild.voiceStates.cache.delete(data.user.id);\n    }\n\n    return { guild, member };\n  }\n}\n\nexports.GuildMemberRemoveAction = GuildMemberRemoveAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildMemberUpdate.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass GuildMemberUpdateAction extends Action {\n  handle(data) {\n    const { client } = this;\n    if (data.user.username) {\n      const user = client.users.cache.get(data.user.id);\n      if (!user) {\n        client.users._add(data.user);\n      } else if (!user._equals(data.user)) {\n        client.actions.UserUpdate.handle(data.user);\n      }\n    }\n\n    const guild = client.guilds.cache.get(data.guild_id);\n    if (guild) {\n      const member = this.getMember({ user: data.user }, guild);\n      if (member) {\n        const old = member._update(data);\n        /**\n         * Emitted whenever a guild member changes - i.e. new role, removed role, nickname.\n         *\n         * @event Client#guildMemberUpdate\n         * @param {GuildMember} oldMember The member before the update\n         * @param {GuildMember} newMember The member after the update\n         */\n        if (!member.equals(old)) client.emit(Events.GuildMemberUpdate, old, member);\n      } else {\n        const newMember = guild.members._add(data);\n        /**\n         * Emitted whenever a member becomes available.\n         *\n         * @event Client#guildMemberAvailable\n         * @param {GuildMember} member The member that became available\n         */\n        this.client.emit(Events.GuildMemberAvailable, newMember);\n      }\n    }\n  }\n}\n\nexports.GuildMemberUpdateAction = GuildMemberUpdateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildRoleCreate.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass GuildRoleCreateAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const guild = client.guilds.cache.get(data.guild_id);\n    let role;\n    if (guild) {\n      const already = guild.roles.cache.has(data.role.id);\n      role = guild.roles._add(data.role);\n      /**\n       * Emitted whenever a role is created.\n       *\n       * @event Client#roleCreate\n       * @param {Role} role The role that was created\n       */\n      if (!already) client.emit(Events.GuildRoleCreate, role);\n    }\n\n    return { role };\n  }\n}\n\nexports.GuildRoleCreateAction = GuildRoleCreateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildRoleDelete.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass GuildRoleDeleteAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const guild = client.guilds.cache.get(data.guild_id);\n    let role;\n\n    if (guild) {\n      role = guild.roles.cache.get(data.role_id);\n      if (role) {\n        guild.roles.cache.delete(data.role_id);\n        /**\n         * Emitted whenever a guild role is deleted.\n         *\n         * @event Client#roleDelete\n         * @param {Role} role The role that was deleted\n         */\n        client.emit(Events.GuildRoleDelete, role);\n      }\n    }\n\n    return { role };\n  }\n}\n\nexports.GuildRoleDeleteAction = GuildRoleDeleteAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildRolesPositionUpdate.js",
    "content": "'use strict';\n\nconst { Action } = require('./Action.js');\n\nclass GuildRolesPositionUpdateAction extends Action {\n  handle(data) {\n    const client = this.client;\n\n    const guild = client.guilds.cache.get(data.guild_id);\n    if (guild) {\n      for (const partialRole of data.roles) {\n        const role = guild.roles.cache.get(partialRole.id);\n        if (role) role.rawPosition = partialRole.position;\n      }\n    }\n\n    return { guild };\n  }\n}\n\nexports.GuildRolesPositionUpdateAction = GuildRolesPositionUpdateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildScheduledEventDelete.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass GuildScheduledEventDeleteAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const guild = client.guilds.cache.get(data.guild_id);\n\n    if (guild) {\n      const guildScheduledEvent = this.getScheduledEvent(data, guild);\n      if (guildScheduledEvent) {\n        guild.scheduledEvents.cache.delete(guildScheduledEvent.id);\n\n        /**\n         * Emitted whenever a guild scheduled event is deleted.\n         *\n         * @event Client#guildScheduledEventDelete\n         * @param {GuildScheduledEvent} guildScheduledEvent The deleted guild scheduled event\n         */\n        client.emit(Events.GuildScheduledEventDelete, guildScheduledEvent);\n\n        return { guildScheduledEvent };\n      }\n    }\n\n    return {};\n  }\n}\n\nexports.GuildScheduledEventDeleteAction = GuildScheduledEventDeleteAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildScheduledEventUserAdd.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass GuildScheduledEventUserAddAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const guild = client.guilds.cache.get(data.guild_id);\n\n    if (guild) {\n      const guildScheduledEvent = this.getScheduledEvent(data, guild);\n      const user = this.getUser(data);\n\n      if (guildScheduledEvent && user) {\n        /**\n         * Emitted whenever a user subscribes to a guild scheduled event\n         *\n         * @event Client#guildScheduledEventUserAdd\n         * @param {GuildScheduledEvent} guildScheduledEvent The guild scheduled event\n         * @param {User} user The user who subscribed\n         */\n        client.emit(Events.GuildScheduledEventUserAdd, guildScheduledEvent, user);\n\n        return { guildScheduledEvent, user };\n      }\n    }\n\n    return {};\n  }\n}\n\nexports.GuildScheduledEventUserAddAction = GuildScheduledEventUserAddAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildScheduledEventUserRemove.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass GuildScheduledEventUserRemoveAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const guild = client.guilds.cache.get(data.guild_id);\n\n    if (guild) {\n      const guildScheduledEvent = this.getScheduledEvent(data, guild);\n      const user = this.getUser(data);\n\n      if (guildScheduledEvent && user) {\n        /**\n         * Emitted whenever a user unsubscribes from a guild scheduled event\n         *\n         * @event Client#guildScheduledEventUserRemove\n         * @param {GuildScheduledEvent} guildScheduledEvent The guild scheduled event\n         * @param {User} user The user who unsubscribed\n         */\n        client.emit(Events.GuildScheduledEventUserRemove, guildScheduledEvent, user);\n\n        return { guildScheduledEvent, user };\n      }\n    }\n\n    return {};\n  }\n}\n\nexports.GuildScheduledEventUserRemoveAction = GuildScheduledEventUserRemoveAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildSoundboardSoundDelete.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass GuildSoundboardSoundDeleteAction extends Action {\n  handle(data) {\n    const guild = this.client.guilds.cache.get(data.guild_id);\n\n    if (!guild) return {};\n\n    const soundboardSound = this.getSoundboardSound(data, guild);\n\n    if (soundboardSound) {\n      guild.soundboardSounds.cache.delete(soundboardSound.soundId);\n\n      /**\n       * Emitted whenever a soundboard sound is deleted in a guild.\n       *\n       * @event Client#guildSoundboardSoundDelete\n       * @param {SoundboardSound} soundboardSound The soundboard sound that was deleted\n       */\n      this.client.emit(Events.GuildSoundboardSoundDelete, soundboardSound);\n    }\n\n    return { soundboardSound };\n  }\n}\n\nexports.GuildSoundboardSoundDeleteAction = GuildSoundboardSoundDeleteAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildStickerCreate.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass GuildStickerCreateAction extends Action {\n  handle(guild, createdSticker) {\n    const already = guild.stickers.cache.has(createdSticker.id);\n    const sticker = guild.stickers._add(createdSticker);\n    /**\n     * Emitted whenever a custom sticker is created in a guild.\n     *\n     * @event Client#stickerCreate\n     * @param {Sticker} sticker The sticker that was created\n     */\n    if (!already) this.client.emit(Events.GuildStickerCreate, sticker);\n    return { sticker };\n  }\n}\n\nexports.GuildStickerCreateAction = GuildStickerCreateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildStickerDelete.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass GuildStickerDeleteAction extends Action {\n  handle(sticker) {\n    sticker.guild.stickers.cache.delete(sticker.id);\n    /**\n     * Emitted whenever a custom sticker is deleted in a guild.\n     *\n     * @event Client#stickerDelete\n     * @param {Sticker} sticker The sticker that was deleted\n     */\n    this.client.emit(Events.GuildStickerDelete, sticker);\n    return { sticker };\n  }\n}\n\nexports.GuildStickerDeleteAction = GuildStickerDeleteAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildStickerUpdate.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass GuildStickerUpdateAction extends Action {\n  handle(current, data) {\n    const old = current._update(data);\n    /**\n     * Emitted whenever a custom sticker is updated in a guild.\n     *\n     * @event Client#stickerUpdate\n     * @param {Sticker} oldSticker The old sticker\n     * @param {Sticker} newSticker The new sticker\n     */\n    this.client.emit(Events.GuildStickerUpdate, old, current);\n    return { sticker: current };\n  }\n}\n\nexports.GuildStickerUpdateAction = GuildStickerUpdateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildStickersUpdate.js",
    "content": "'use strict';\n\nconst { Action } = require('./Action.js');\n\nclass GuildStickersUpdateAction extends Action {\n  handle(data) {\n    const guild = this.client.guilds.cache.get(data.guild_id);\n    if (!guild?.stickers) return;\n\n    const deletions = new Map(guild.stickers.cache);\n\n    for (const sticker of data.stickers) {\n      // Determine type of sticker event\n      const cachedSticker = guild.stickers.cache.get(sticker.id);\n      if (cachedSticker) {\n        deletions.delete(sticker.id);\n        if (!cachedSticker.equals(sticker)) {\n          // Sticker updated\n          this.client.actions.GuildStickerUpdate.handle(cachedSticker, sticker);\n        }\n      } else {\n        // Sticker added\n        this.client.actions.GuildStickerCreate.handle(guild, sticker);\n      }\n    }\n\n    for (const sticker of deletions.values()) {\n      // Sticker deleted\n      this.client.actions.GuildStickerDelete.handle(sticker);\n    }\n  }\n}\n\nexports.GuildStickersUpdateAction = GuildStickersUpdateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/GuildUpdate.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass GuildUpdateAction extends Action {\n  handle(data) {\n    const client = this.client;\n\n    const guild = client.guilds.cache.get(data.id);\n    if (guild) {\n      const old = guild._update(data);\n      /**\n       * Emitted whenever a guild is updated - e.g. name change.\n       *\n       * @event Client#guildUpdate\n       * @param {Guild} oldGuild The guild before the update\n       * @param {Guild} newGuild The guild after the update\n       */\n      client.emit(Events.GuildUpdate, old, guild);\n      return {\n        old,\n        updated: guild,\n      };\n    }\n\n    return {\n      old: null,\n      updated: null,\n    };\n  }\n}\n\nexports.GuildUpdateAction = GuildUpdateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/InteractionCreate.js",
    "content": "'use strict';\n\nconst { InteractionType, ComponentType, ApplicationCommandType } = require('discord-api-types/v10');\nconst { AutocompleteInteraction } = require('../../structures/AutocompleteInteraction.js');\nconst { ButtonInteraction } = require('../../structures/ButtonInteraction.js');\nconst { ChannelSelectMenuInteraction } = require('../../structures/ChannelSelectMenuInteraction.js');\nconst { ChatInputCommandInteraction } = require('../../structures/ChatInputCommandInteraction.js');\nconst { MentionableSelectMenuInteraction } = require('../../structures/MentionableSelectMenuInteraction.js');\nconst { MessageContextMenuCommandInteraction } = require('../../structures/MessageContextMenuCommandInteraction.js');\nconst { ModalSubmitInteraction } = require('../../structures/ModalSubmitInteraction.js');\nconst { PrimaryEntryPointCommandInteraction } = require('../../structures/PrimaryEntryPointCommandInteraction.js');\nconst { RoleSelectMenuInteraction } = require('../../structures/RoleSelectMenuInteraction.js');\nconst { StringSelectMenuInteraction } = require('../../structures/StringSelectMenuInteraction.js');\nconst { UserContextMenuCommandInteraction } = require('../../structures/UserContextMenuCommandInteraction.js');\nconst { UserSelectMenuInteraction } = require('../../structures/UserSelectMenuInteraction.js');\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass InteractionCreateAction extends Action {\n  handle(data) {\n    const client = this.client;\n\n    // Resolve and cache partial channels for Interaction#channel getter\n    const channel = data.channel && this.getChannel(data.channel);\n\n    // Do not emit this for interactions that cache messages that are non-text-based.\n    let InteractionClass;\n\n    switch (data.type) {\n      case InteractionType.ApplicationCommand:\n        switch (data.data.type) {\n          case ApplicationCommandType.ChatInput:\n            InteractionClass = ChatInputCommandInteraction;\n            break;\n          case ApplicationCommandType.User:\n            InteractionClass = UserContextMenuCommandInteraction;\n            break;\n          case ApplicationCommandType.Message:\n            if (channel && !channel.isTextBased()) return;\n            InteractionClass = MessageContextMenuCommandInteraction;\n            break;\n          case ApplicationCommandType.PrimaryEntryPoint:\n            InteractionClass = PrimaryEntryPointCommandInteraction;\n            break;\n          default:\n            client.emit(\n              Events.Debug,\n              `[INTERACTION] Received application command interaction with unknown type: ${data.data.type}`,\n            );\n            return;\n        }\n\n        break;\n      case InteractionType.MessageComponent:\n        if (channel && !channel.isTextBased()) return;\n\n        switch (data.data.component_type) {\n          case ComponentType.Button:\n            InteractionClass = ButtonInteraction;\n            break;\n          case ComponentType.StringSelect:\n            InteractionClass = StringSelectMenuInteraction;\n            break;\n          case ComponentType.UserSelect:\n            InteractionClass = UserSelectMenuInteraction;\n            break;\n          case ComponentType.RoleSelect:\n            InteractionClass = RoleSelectMenuInteraction;\n            break;\n          case ComponentType.MentionableSelect:\n            InteractionClass = MentionableSelectMenuInteraction;\n            break;\n          case ComponentType.ChannelSelect:\n            InteractionClass = ChannelSelectMenuInteraction;\n            break;\n          default:\n            client.emit(\n              Events.Debug,\n              `[INTERACTION] Received component interaction with unknown type: ${data.data.component_type}`,\n            );\n            return;\n        }\n\n        break;\n      case InteractionType.ApplicationCommandAutocomplete:\n        InteractionClass = AutocompleteInteraction;\n        break;\n      case InteractionType.ModalSubmit:\n        InteractionClass = ModalSubmitInteraction;\n        break;\n      default:\n        client.emit(Events.Debug, `[INTERACTION] Received interaction with unknown type: ${data.type}`);\n        return;\n    }\n\n    const interaction = new InteractionClass(client, data);\n\n    /**\n     * Emitted when an interaction is created.\n     *\n     * @event Client#interactionCreate\n     * @param {BaseInteraction} interaction The interaction which was created\n     */\n    client.emit(Events.InteractionCreate, interaction);\n  }\n}\n\nexports.InteractionCreateAction = InteractionCreateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/MessageCreate.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass MessageCreateAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const channel = this.getChannel({\n      id: data.channel_id,\n      author: data.author,\n      ...('guild_id' in data && { guild_id: data.guild_id }),\n    });\n    if (channel) {\n      if (!channel.isTextBased()) return {};\n\n      if (channel.isThread()) {\n        channel.messageCount++;\n        channel.totalMessageSent++;\n      }\n\n      const existing = channel.messages.cache.get(data.id);\n      if (existing && existing.author?.id !== this.client.user.id) return { message: existing };\n      const message = existing ?? channel.messages._add(data);\n      channel.lastMessageId = data.id;\n\n      /**\n       * Emitted whenever a message is created.\n       *\n       * @event Client#messageCreate\n       * @param {Message} message The created message\n       */\n      client.emit(Events.MessageCreate, message);\n\n      return { message };\n    }\n\n    return {};\n  }\n}\n\nexports.MessageCreateAction = MessageCreateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/MessageDelete.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass MessageDeleteAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });\n    let message;\n    if (channel) {\n      if (!channel.isTextBased()) return {};\n\n      if (channel.isThread()) channel.messageCount--;\n\n      message = this.getMessage(data, channel);\n      if (message) {\n        channel.messages.cache.delete(message.id);\n        /**\n         * Emitted whenever a message is deleted.\n         *\n         * @event Client#messageDelete\n         * @param {Message} message The deleted message\n         */\n        client.emit(Events.MessageDelete, message);\n      }\n    }\n\n    return { message };\n  }\n}\n\nexports.MessageDeleteAction = MessageDeleteAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/MessageDeleteBulk.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass MessageDeleteBulkAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const channel = client.channels.cache.get(data.channel_id);\n\n    if (channel) {\n      if (!channel.isTextBased()) return {};\n\n      if (channel.isThread()) channel.messageCount -= data.ids.length;\n\n      const ids = data.ids;\n      const messages = new Collection();\n      for (const id of ids) {\n        const message = this.getMessage(\n          {\n            id,\n            guild_id: data.guild_id,\n          },\n          channel,\n          false,\n        );\n        if (message) {\n          messages.set(message.id, message);\n          channel.messages.cache.delete(id);\n        }\n      }\n\n      /**\n       * Emitted whenever messages are deleted in bulk.\n       *\n       * @event Client#messageDeleteBulk\n       * @param {Collection<Snowflake, Message>} messages The deleted messages, mapped by their id\n       * @param {GuildTextBasedChannel} channel The channel that the messages were deleted in\n       */\n      if (messages.size > 0) client.emit(Events.MessageBulkDelete, messages, channel);\n      return { messages };\n    }\n\n    return {};\n  }\n}\n\nexports.MessageDeleteBulkAction = MessageDeleteBulkAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/MessagePollVoteAdd.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass MessagePollVoteAddAction extends Action {\n  handle(data) {\n    const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });\n    if (!channel?.isTextBased()) return false;\n\n    const message = this.getMessage(data, channel);\n    if (!message) return false;\n\n    const poll = this.getPoll(data, message, channel);\n    if (!poll) return false;\n\n    const answer = poll.answers.get(data.answer_id);\n    if (!answer) return false;\n\n    const user = this.getUser(data);\n\n    if (user) {\n      answer.voters._add(user);\n    }\n\n    answer.voteCount++;\n\n    /**\n     * Emitted whenever a user votes in a poll.\n     *\n     * @event Client#messagePollVoteAdd\n     * @param {PollAnswer} pollAnswer The answer that was voted on\n     * @param {Snowflake} userId The id of the user that voted\n     */\n    this.client.emit(Events.MessagePollVoteAdd, answer, data.user_id);\n\n    return { poll };\n  }\n}\n\nexports.MessagePollVoteAddAction = MessagePollVoteAddAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/MessagePollVoteRemove.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass MessagePollVoteRemoveAction extends Action {\n  handle(data) {\n    const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });\n    if (!channel?.isTextBased()) return false;\n\n    const message = this.getMessage(data, channel);\n    if (!message) return false;\n\n    const poll = this.getPoll(data, message, channel);\n    if (!poll) return false;\n\n    const answer = poll.answers.get(data.answer_id);\n    if (!answer) return false;\n\n    answer.voters.cache.delete(data.user_id);\n\n    if (answer.voteCount > 0) {\n      answer.voteCount--;\n    }\n\n    /**\n     * Emitted whenever a user removes their vote in a poll.\n     *\n     * @event Client#messagePollVoteRemove\n     * @param {PollAnswer} pollAnswer The answer where the vote was removed\n     * @param {Snowflake} userId The id of the user that removed their vote\n     */\n    this.client.emit(Events.MessagePollVoteRemove, answer, data.user_id);\n\n    return { poll };\n  }\n}\n\nexports.MessagePollVoteRemoveAction = MessagePollVoteRemoveAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/MessageReactionAdd.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Partials } = require('../../util/Partials.js');\nconst { Action } = require('./Action.js');\n\n/*\n{ user_id: 'id',\n     message_id: 'id',\n     emoji: { name: '�', id: null },\n     channel_id: 'id',\n     burst: boolean\n     // If originating from a guild\n     guild_id: 'id',\n     member: { ..., user: { ... } } }\n*/\n\nclass MessageReactionAddAction extends Action {\n  handle(data, fromStructure = false) {\n    if (!data.emoji) return false;\n\n    const user = this.getUserFromMember(data);\n    if (!user) return false;\n\n    // Verify channel\n    const channel = this.getChannel({\n      id: data.channel_id,\n      ...('guild_id' in data && { guild_id: data.guild_id }),\n      user_id: data.user_id,\n      ...this.spreadInjectedData(data),\n    });\n\n    if (!channel?.isTextBased()) return false;\n\n    // Verify message\n    const message = this.getMessage(data, channel);\n    if (!message) return false;\n\n    // Verify reaction\n    const includePartial = this.client.options.partials.includes(Partials.Reaction);\n    if (message.partial && !includePartial) return false;\n    const reaction = message.reactions._add({\n      emoji: data.emoji,\n      count: message.partial ? null : 0,\n      me: user.id === this.client.user.id,\n      burst_colors: data.burst_colors,\n    });\n    if (!reaction) return false;\n    reaction._add(user, data.burst);\n    if (fromStructure) return { message, reaction, user };\n    /**\n     * Provides additional information about altered reaction\n     *\n     * @typedef {Object} MessageReactionEventDetails\n     * @property {ReactionType} type The type of the reaction\n     * @property {boolean} burst Determines whether a super reaction was used\n     */\n    /**\n     * Emitted whenever a reaction is added to a cached message.\n     *\n     * @event Client#messageReactionAdd\n     * @param {MessageReaction} messageReaction The reaction object\n     * @param {User} user The user that applied the guild or reaction emoji\n     * @param {MessageReactionEventDetails} details Details of adding the reaction\n     */\n    this.client.emit(Events.MessageReactionAdd, reaction, user, { type: data.type, burst: data.burst });\n\n    return { message, reaction, user };\n  }\n}\n\nexports.MessageReactionAddAction = MessageReactionAddAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/MessageReactionRemove.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\n/*\n{ user_id: 'id',\n     message_id: 'id',\n     emoji: { name: '�', id: null },\n     channel_id: 'id',\n     guild_id: 'id' }\n*/\n\nclass MessageReactionRemoveAction extends Action {\n  handle(data) {\n    if (!data.emoji) return false;\n\n    const user = this.getUser(data);\n    if (!user) return false;\n\n    // Verify channel\n    const channel = this.getChannel({\n      id: data.channel_id,\n      ...('guild_id' in data && { guild_id: data.guild_id }),\n      user_id: data.user_id,\n    });\n    if (!channel?.isTextBased()) return false;\n\n    // Verify message\n    const message = this.getMessage(data, channel);\n    if (!message) return false;\n\n    // Verify reaction\n    const reaction = this.getReaction(data, message, user);\n    if (!reaction) return false;\n    reaction._remove(user, data.burst);\n    /**\n     * Emitted whenever a reaction is removed from a cached message.\n     *\n     * @event Client#messageReactionRemove\n     * @param {MessageReaction} messageReaction The reaction object\n     * @param {User} user The user whose emoji or reaction emoji was removed\n     * @param {MessageReactionEventDetails} details Details of removing the reaction\n     */\n    this.client.emit(Events.MessageReactionRemove, reaction, user, { type: data.type, burst: data.burst });\n\n    return { message, reaction, user };\n  }\n}\n\nexports.MessageReactionRemoveAction = MessageReactionRemoveAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/MessageReactionRemoveAll.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass MessageReactionRemoveAllAction extends Action {\n  handle(data) {\n    // Verify channel\n    const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });\n    if (!channel?.isTextBased()) return false;\n\n    // Verify message\n    const message = this.getMessage(data, channel);\n    if (!message) return false;\n\n    // Copy removed reactions to emit for the event.\n    const removed = message.reactions.cache.clone();\n\n    message.reactions.cache.clear();\n    this.client.emit(Events.MessageReactionRemoveAll, message, removed);\n\n    return { message };\n  }\n}\n\n/**\n * Emitted whenever all reactions are removed from a cached message.\n *\n * @event Client#messageReactionRemoveAll\n * @param {Message} message The message the reactions were removed from\n * @param {Collection<string|Snowflake, MessageReaction>} reactions The cached message reactions that were removed.\n */\n\nexports.MessageReactionRemoveAllAction = MessageReactionRemoveAllAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/MessageReactionRemoveEmoji.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass MessageReactionRemoveEmojiAction extends Action {\n  handle(data) {\n    const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });\n    if (!channel?.isTextBased()) return false;\n\n    const message = this.getMessage(data, channel);\n    if (!message) return false;\n\n    const reaction = this.getReaction(data, message);\n    if (!reaction) return false;\n    if (!message.partial) message.reactions.cache.delete(reaction.emoji.id ?? reaction.emoji.name);\n\n    /**\n     * Emitted when a bot removes an emoji reaction from a cached message.\n     *\n     * @event Client#messageReactionRemoveEmoji\n     * @param {MessageReaction} reaction The reaction that was removed\n     */\n    this.client.emit(Events.MessageReactionRemoveEmoji, reaction);\n    return { reaction };\n  }\n}\n\nexports.MessageReactionRemoveEmojiAction = MessageReactionRemoveEmojiAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/MessageUpdate.js",
    "content": "'use strict';\n\nconst { Action } = require('./Action.js');\n\nclass MessageUpdateAction extends Action {\n  handle(data) {\n    const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });\n    if (channel) {\n      if (!channel.isTextBased()) return {};\n\n      const { id, channel_id, guild_id, author, timestamp, type } = data;\n      const message = this.getMessage({ id, channel_id, guild_id, author, timestamp, type }, channel);\n      if (message) {\n        const old = message._update(data);\n        return {\n          old,\n          updated: message,\n        };\n      }\n    }\n\n    return {};\n  }\n}\n\nexports.MessageUpdateAction = MessageUpdateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/StageInstanceCreate.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass StageInstanceCreateAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });\n\n    if (channel) {\n      const stageInstance = channel.guild.stageInstances._add(data);\n\n      /**\n       * Emitted whenever a stage instance is created.\n       *\n       * @event Client#stageInstanceCreate\n       * @param {StageInstance} stageInstance The created stage instance\n       */\n      client.emit(Events.StageInstanceCreate, stageInstance);\n\n      return { stageInstance };\n    }\n\n    return {};\n  }\n}\n\nexports.StageInstanceCreateAction = StageInstanceCreateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/StageInstanceDelete.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass StageInstanceDeleteAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });\n\n    if (channel) {\n      const stageInstance = channel.guild.stageInstances._add(data);\n      if (stageInstance) {\n        channel.guild.stageInstances.cache.delete(stageInstance.id);\n\n        /**\n         * Emitted whenever a stage instance is deleted.\n         *\n         * @event Client#stageInstanceDelete\n         * @param {StageInstance} stageInstance The deleted stage instance\n         */\n        client.emit(Events.StageInstanceDelete, stageInstance);\n\n        return { stageInstance };\n      }\n    }\n\n    return {};\n  }\n}\n\nexports.StageInstanceDeleteAction = StageInstanceDeleteAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/StageInstanceUpdate.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass StageInstanceUpdateAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const channel = this.getChannel({ id: data.channel_id, guild_id: data.guild_id });\n\n    if (channel) {\n      const oldStageInstance = channel.guild.stageInstances.cache.get(data.id)?._clone() ?? null;\n      const newStageInstance = channel.guild.stageInstances._add(data);\n\n      /**\n       * Emitted whenever a stage instance gets updated - e.g. change in topic or privacy level\n       *\n       * @event Client#stageInstanceUpdate\n       * @param {?StageInstance} oldStageInstance The stage instance before the update\n       * @param {StageInstance} newStageInstance The stage instance after the update\n       */\n      client.emit(Events.StageInstanceUpdate, oldStageInstance, newStageInstance);\n\n      return { oldStageInstance, newStageInstance };\n    }\n\n    return {};\n  }\n}\n\nexports.StageInstanceUpdateAction = StageInstanceUpdateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/ThreadCreate.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass ThreadCreateAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const existing = client.channels.cache.has(data.id);\n    const thread = client.channels._add(data);\n    if (!existing && thread) {\n      /**\n       * Emitted whenever a thread is created or when the client user is added to a thread.\n       *\n       * @event Client#threadCreate\n       * @param {ThreadChannel} thread The thread that was created\n       * @param {boolean} newlyCreated Whether the thread was newly created\n       */\n      client.emit(Events.ThreadCreate, thread, data.newly_created ?? false);\n    }\n\n    return { thread };\n  }\n}\n\nexports.ThreadCreateAction = ThreadCreateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/ThreadMembersUpdate.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass ThreadMembersUpdateAction extends Action {\n  handle(data) {\n    const client = this.client;\n    const thread = client.channels.cache.get(data.id);\n    if (thread) {\n      thread.memberCount = data.member_count;\n      const addedMembers = new Collection();\n      const removedMembers = new Collection();\n\n      data.added_members?.reduce(\n        (_addedMembers, addedMember) => _addedMembers.set(addedMember.user_id, thread.members._add(addedMember)),\n        addedMembers,\n      );\n\n      data.removed_member_ids?.reduce((removedMembersIds, removedMembersId) => {\n        const threadMember = this.getThreadMember(removedMembersId, thread.members);\n        if (threadMember) removedMembersIds.set(threadMember.id, threadMember);\n        thread.members.cache.delete(removedMembersId);\n        return removedMembersIds;\n      }, removedMembers);\n\n      if (addedMembers.size === 0 && removedMembers.size === 0) {\n        // Uncached thread member(s) left.\n        return {};\n      }\n\n      /**\n       * Emitted whenever members are added or removed from a thread.\n       * <info>This event requires the {@link GatewayIntentBits.GuildMembers} privileged gateway intent.</info>\n       *\n       * @event Client#threadMembersUpdate\n       * @param {Collection<Snowflake, ThreadMember>} addedMembers The members that were added\n       * @param {Collection<Snowflake, ThreadMember>} removedMembers The members that were removed\n       * @param {ThreadChannel} thread The thread where members got updated\n       */\n      client.emit(Events.ThreadMembersUpdate, addedMembers, removedMembers, thread);\n    }\n\n    return {};\n  }\n}\n\nexports.ThreadMembersUpdateAction = ThreadMembersUpdateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/TypingStart.js",
    "content": "'use strict';\n\nconst { Typing } = require('../../structures/Typing.js');\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass TypingStartAction extends Action {\n  handle(data) {\n    const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });\n    if (!channel) return;\n\n    if (!channel.isTextBased()) {\n      this.client.emit(Events.Warn, `Discord sent a typing packet to a ${channel.type} channel ${channel.id}`);\n      return;\n    }\n\n    const user = this.getUserFromMember(data);\n    if (user) {\n      /**\n       * Emitted whenever a user starts typing in a channel.\n       *\n       * @event Client#typingStart\n       * @param {Typing} typing The typing state\n       */\n      this.client.emit(Events.TypingStart, new Typing(channel, user, data));\n    }\n  }\n}\n\nexports.TypingStartAction = TypingStartAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/actions/UserUpdate.js",
    "content": "'use strict';\n\nconst { Events } = require('../../util/Events.js');\nconst { Action } = require('./Action.js');\n\nclass UserUpdateAction extends Action {\n  handle(data) {\n    const client = this.client;\n\n    const newUser = data.id === client.user.id ? client.user : client.users.cache.get(data.id);\n    const oldUser = newUser._update(data);\n\n    if (!oldUser.equals(newUser)) {\n      /**\n       * Emitted whenever a user's details (e.g. username) are changed.\n       * Triggered by the Discord gateway events {@link Events.UserUpdate},\n       * {@link Events.GuildMemberUpdate}, and {@link Events.PresenceUpdate}.\n       *\n       * @event Client#userUpdate\n       * @param {User} oldUser The user before the update\n       * @param {User} newUser The user after the update\n       */\n      client.emit(Events.UserUpdate, oldUser, newUser);\n      return {\n        old: oldUser,\n        updated: newUser,\n      };\n    }\n\n    return {\n      old: null,\n      updated: null,\n    };\n  }\n}\n\nexports.UserUpdateAction = UserUpdateAction;\n"
  },
  {
    "path": "packages/discord.js/src/client/voice/ClientVoiceManager.js",
    "content": "'use strict';\n\nconst { WebSocketShardEvents, CloseCodes } = require('@discordjs/ws');\n\n/**\n * Manages voice connections for the client\n */\nclass ClientVoiceManager {\n  constructor(client) {\n    /**\n     * The client that instantiated this voice manager\n     *\n     * @type {Client}\n     * @readonly\n     * @name ClientVoiceManager#client\n     */\n    Object.defineProperty(this, 'client', { value: client });\n\n    /**\n     * Maps guild ids to voice adapters created for use with `@discordjs/voice`.\n     *\n     * @type {Map<Snowflake, Object>}\n     */\n    this.adapters = new Map();\n\n    client.ws.on(WebSocketShardEvents.Closed, (code, shardId) => {\n      if (code === CloseCodes.Normal) {\n        for (const [guildId, adapter] of this.adapters.entries()) {\n          if (client.guilds.cache.get(guildId)?.shardId === shardId) {\n            adapter.destroy();\n          }\n        }\n      }\n    });\n  }\n\n  onVoiceServer(payload) {\n    this.adapters.get(payload.guild_id)?.onVoiceServerUpdate(payload);\n  }\n\n  onVoiceStateUpdate(payload) {\n    if (payload.guild_id && payload.session_id && payload.user_id === this.client.user?.id) {\n      this.adapters.get(payload.guild_id)?.onVoiceStateUpdate(payload);\n    }\n  }\n}\n\nexports.ClientVoiceManager = ClientVoiceManager;\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/APPLICATION_COMMAND_PERMISSIONS_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  /**\n   * Represents the properties of an application command permissions update\n   *\n   * @typedef {Object} ApplicationCommandPermissionsUpdateData\n   * @property {ApplicationCommandPermissions[]} permissions The permissions for the command\n   * @property {Snowflake} id The id of the command\n   * @property {Snowflake} guildId The id of the guild\n   * @property {Snowflake} applicationId The id of the application\n   */\n\n  /**\n   * Emitted whenever permissions for an application command in a guild were updated.\n   * <warn>This includes permission updates for other applications in addition to the logged in client,\n   * check `data.applicationId` to verify which application the update is for</warn>\n   *\n   * @event Client#applicationCommandPermissionsUpdate\n   * @param {ApplicationCommandPermissionsUpdateData} data The updated permissions\n   */\n  client.emit(Events.ApplicationCommandPermissionsUpdate, {\n    permissions: data.permissions,\n    id: data.id,\n    guildId: data.guild_id,\n    applicationId: data.application_id,\n  });\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/AUTO_MODERATION_ACTION_EXECUTION.js",
    "content": "'use strict';\n\nconst { AutoModerationActionExecution } = require('../../../structures/AutoModerationActionExecution.js');\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n\n  /**\n   * Emitted whenever an auto moderation rule is triggered.\n   * <info>This event requires the {@link PermissionFlagsBits.ManageGuild} permission.</info>\n   *\n   * @event Client#autoModerationActionExecution\n   * @param {AutoModerationActionExecution} autoModerationActionExecution The data of the execution\n   */\n  client.emit(Events.AutoModerationActionExecution, new AutoModerationActionExecution(data, guild));\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/AUTO_MODERATION_RULE_CREATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n\n  const autoModerationRule = guild.autoModerationRules._add(data);\n\n  /**\n   * Emitted whenever an auto moderation rule is created.\n   * <info>This event requires the {@link PermissionFlagsBits.ManageGuild} permission.</info>\n   *\n   * @event Client#autoModerationRuleCreate\n   * @param {AutoModerationRule} autoModerationRule The created auto moderation rule\n   */\n  client.emit(Events.AutoModerationRuleCreate, autoModerationRule);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/AUTO_MODERATION_RULE_DELETE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n\n  const autoModerationRule = guild.autoModerationRules.cache.get(data.id);\n  if (!autoModerationRule) return;\n\n  guild.autoModerationRules.cache.delete(autoModerationRule.id);\n\n  /**\n   * Emitted whenever an auto moderation rule is deleted.\n   * <info>This event requires the {@link PermissionFlagsBits.ManageGuild} permission.</info>\n   *\n   * @event Client#autoModerationRuleDelete\n   * @param {AutoModerationRule} autoModerationRule The deleted auto moderation rule\n   */\n  client.emit(Events.AutoModerationRuleDelete, autoModerationRule);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/AUTO_MODERATION_RULE_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n\n  const oldAutoModerationRule = guild.autoModerationRules.cache.get(data.id)?._clone() ?? null;\n  const newAutoModerationRule = guild.autoModerationRules._add(data);\n\n  /**\n   * Emitted whenever an auto moderation rule gets updated.\n   * <info>This event requires the {@link PermissionFlagsBits.ManageGuild} permission.</info>\n   *\n   * @event Client#autoModerationRuleUpdate\n   * @param {?AutoModerationRule} oldAutoModerationRule The auto moderation rule before the update\n   * @param {AutoModerationRule} newAutoModerationRule The auto moderation rule after the update\n   */\n  client.emit(Events.AutoModerationRuleUpdate, oldAutoModerationRule, newAutoModerationRule);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/CHANNEL_CREATE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.ChannelCreate.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/CHANNEL_DELETE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.ChannelDelete.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/CHANNEL_PINS_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const channel = client.channels.cache.get(data.channel_id);\n  const time = data.last_pin_timestamp ? Date.parse(data.last_pin_timestamp) : null;\n\n  if (channel) {\n    // Discord sends null for last_pin_timestamp if the last pinned message was removed\n    channel.lastPinTimestamp = time;\n\n    /**\n     * Emitted whenever the pins of a channel are updated. Due to the nature of the WebSocket event,\n     * not much information can be provided easily here - you need to manually check the pins yourself.\n     *\n     * @event Client#channelPinsUpdate\n     * @param {TextBasedChannels} channel The channel that the pins update occurred in\n     * @param {Date} time The time of the pins update\n     */\n    client.emit(Events.ChannelPinsUpdate, channel, time);\n  }\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/CHANNEL_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, packet) => {\n  const { old, updated } = client.actions.ChannelUpdate.handle(packet.d);\n  if (old && updated) {\n    /**\n     * Emitted whenever a channel is updated - e.g. name change, topic change, channel type change.\n     *\n     * @event Client#channelUpdate\n     * @param {DMChannel|GuildChannel} oldChannel The channel before the update\n     * @param {DMChannel|GuildChannel} newChannel The channel after the update\n     */\n    client.emit(Events.ChannelUpdate, old, updated);\n  }\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/ENTITLEMENT_CREATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const entitlement = client.application.entitlements._add(data);\n\n  /**\n   * Emitted whenever an entitlement is created.\n   *\n   * @event Client#entitlementCreate\n   * @param {Entitlement} entitlement The entitlement that was created\n   */\n  client.emit(Events.EntitlementCreate, entitlement);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/ENTITLEMENT_DELETE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const entitlement = client.application.entitlements._add(data, false);\n\n  client.application.entitlements.cache.delete(entitlement.id);\n\n  /**\n   * Emitted whenever an entitlement is deleted.\n   * <warn>Entitlements are not deleted when they expire.\n   * This is only triggered when Discord issues a refund or deletes the entitlement manually.</warn>\n   *\n   * @event Client#entitlementDelete\n   * @param {Entitlement} entitlement The entitlement that was deleted\n   */\n  client.emit(Events.EntitlementDelete, entitlement);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/ENTITLEMENT_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const oldEntitlement = client.application.entitlements.cache.get(data.id)?._clone() ?? null;\n  const newEntitlement = client.application.entitlements._add(data);\n\n  /**\n   * Emitted whenever an entitlement is updated - i.e. when a user's subscription renews.\n   *\n   * @event Client#entitlementUpdate\n   * @param {?Entitlement} oldEntitlement The entitlement before the update\n   * @param {Entitlement} newEntitlement The entitlement after the update\n   */\n  client.emit(Events.EntitlementUpdate, oldEntitlement, newEntitlement);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_AUDIT_LOG_ENTRY_CREATE.js",
    "content": "'use strict';\n\nconst { GuildAuditLogsEntry } = require('../../../structures/GuildAuditLogsEntry.js');\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n\n  const auditLogEntry = new GuildAuditLogsEntry(guild, data);\n\n  /**\n   * Emitted whenever a guild audit log entry is created.\n   *\n   * @event Client#guildAuditLogEntryCreate\n   * @param {GuildAuditLogsEntry} auditLogEntry The entry that was created\n   * @param {Guild} guild The guild where the entry was created\n   */\n  client.emit(Events.GuildAuditLogEntryCreate, auditLogEntry, guild);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_BAN_ADD.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n\n  /**\n   * Emitted whenever a member is banned from a guild.\n   *\n   * @event Client#guildBanAdd\n   * @param {GuildBan} ban The ban that occurred\n   */\n  client.emit(Events.GuildBanAdd, guild.bans._add(data));\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_BAN_REMOVE.js",
    "content": "'use strict';\n\nconst { GuildBan } = require('../../../structures/GuildBan.js');\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n\n  const ban = guild.bans.cache.get(data.user.id) ?? new GuildBan(client, data, guild);\n\n  guild.bans.cache.delete(ban.user.id);\n\n  /**\n   * Emitted whenever a member is unbanned from a guild.\n   *\n   * @event Client#guildBanRemove\n   * @param {GuildBan} ban The ban that was removed\n   */\n  client.emit(Events.GuildBanRemove, ban);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_CREATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\nconst { Status } = require('../../../util/Status.js');\n\nmodule.exports = (client, { d: data }, shardId) => {\n  let guild = client.guilds.cache.get(data.id);\n  if (guild) {\n    if (!guild.available && !data.unavailable) {\n      // A newly available guild\n      guild._patch(data);\n\n      /**\n       * Emitted whenever a guild becomes available.\n       *\n       * @event Client#guildAvailable\n       * @param {Guild} guild The guild that became available\n       */\n      client.emit(Events.GuildAvailable, guild);\n    }\n  } else {\n    // A new guild\n    data.shardId = shardId;\n    guild = client.guilds._add(data);\n    if (client.status === Status.Ready) {\n      /**\n       * Emitted whenever the client joins a guild.\n       *\n       * @event Client#guildCreate\n       * @param {Guild} guild The created guild\n       */\n      client.emit(Events.GuildCreate, guild);\n    }\n  }\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_DELETE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.id);\n  if (!guild) return;\n\n  if (data.unavailable) {\n    guild.available = false;\n\n    /**\n     * Emitted whenever a guild becomes unavailable, likely due to a server outage.\n     *\n     * @event Client#guildUnavailable\n     * @param {Guild} guild The guild that has become unavailable\n     */\n    client.emit(Events.GuildUnavailable, guild);\n\n    // Stops the GuildDelete packet thinking a guild was actually deleted,\n    // handles emitting of event itself\n    return;\n  }\n\n  for (const channel of guild.channels.cache.values()) client.channels._remove(channel.id);\n  client.voice.adapters.get(data.id)?.destroy();\n\n  client.guilds.cache.delete(guild.id);\n\n  /**\n   * Emitted whenever a guild kicks the client or the guild is deleted/left.\n   *\n   * @event Client#guildDelete\n   * @param {Guild} guild The guild that was deleted\n   */\n  client.emit(Events.GuildDelete, guild);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_EMOJIS_UPDATE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.GuildEmojisUpdate.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_INTEGRATIONS_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n\n  /**\n   * Emitted whenever a guild integration is updated\n   *\n   * @event Client#guildIntegrationsUpdate\n   * @param {Guild} guild The guild whose integrations were updated\n   */\n  client.emit(Events.GuildIntegrationsUpdate, guild);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n  const members = new Collection();\n\n  for (const member of data.members) members.set(member.user.id, guild.members._add(member));\n  if (data.presences) {\n    for (const presence of data.presences) guild.presences._add(Object.assign(presence, { guild }));\n  }\n\n  /**\n   * Represents the properties of a guild members chunk\n   *\n   * @typedef {Object} GuildMembersChunk\n   * @property {number} index Index of the received chunk\n   * @property {number} count Number of chunks the client should receive\n   * @property {Array<*>} notFound An array of whatever could not be found\n   * when using {@link GatewayOpcodes.RequestGuildMembers}\n   * @property {?string} nonce Nonce for this chunk\n   */\n\n  /**\n   * Emitted whenever a chunk of guild members is received (all members come from the same guild).\n   *\n   * @event Client#guildMembersChunk\n   * @param {Collection<Snowflake, GuildMember>} members The members in the chunk\n   * @param {Guild} guild The guild related to the member chunk\n   * @param {GuildMembersChunk} chunk Properties of the received chunk\n   */\n  client.emit(Events.GuildMembersChunk, members, guild, {\n    index: data.chunk_index,\n    count: data.chunk_count,\n    notFound: data.not_found,\n    nonce: data.nonce,\n  });\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_MEMBER_ADD.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (guild) {\n    guild.memberCount++;\n    const member = guild.members._add(data);\n    /**\n     * Emitted whenever a user joins a guild.\n     *\n     * @event Client#guildMemberAdd\n     * @param {GuildMember} member The member that has joined a guild\n     */\n    client.emit(Events.GuildMemberAdd, member);\n  }\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_MEMBER_REMOVE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.GuildMemberRemove.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_MEMBER_UPDATE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.GuildMemberUpdate.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_ROLE_CREATE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.GuildRoleCreate.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_ROLE_DELETE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.GuildRoleDelete.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_ROLE_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n\n  const role = guild.roles.cache.get(data.role.id);\n  if (!role) return;\n\n  const old = role._update(data.role);\n\n  /**\n   * Emitted whenever a guild role is updated.\n   *\n   * @event Client#roleUpdate\n   * @param {Role} oldRole The role before the update\n   * @param {Role} newRole The role after the update\n   */\n  client.emit(Events.GuildRoleUpdate, old, role);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_CREATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n\n  const guildScheduledEvent = guild.scheduledEvents._add(data);\n\n  /**\n   * Emitted whenever a guild scheduled event is created.\n   *\n   * @event Client#guildScheduledEventCreate\n   * @param {GuildScheduledEvent} guildScheduledEvent The created guild scheduled event\n   */\n  client.emit(Events.GuildScheduledEventCreate, guildScheduledEvent);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_DELETE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.GuildScheduledEventDelete.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n\n  const oldGuildScheduledEvent = guild.scheduledEvents.cache.get(data.id)?._clone() ?? null;\n  const newGuildScheduledEvent = guild.scheduledEvents._add(data);\n\n  /**\n   * Emitted whenever a guild scheduled event gets updated.\n   *\n   * @event Client#guildScheduledEventUpdate\n   * @param {?GuildScheduledEvent} oldGuildScheduledEvent The guild scheduled event object before the update\n   * @param {GuildScheduledEvent} newGuildScheduledEvent The guild scheduled event object after the update\n   */\n  client.emit(Events.GuildScheduledEventUpdate, oldGuildScheduledEvent, newGuildScheduledEvent);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_ADD.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.GuildScheduledEventUserAdd.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_REMOVE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.GuildScheduledEventUserRemove.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUNDS_UPDATE.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n\n  if (!guild) return;\n\n  const soundboardSounds = new Collection();\n\n  for (const soundboardSound of data.soundboard_sounds) {\n    soundboardSounds.set(soundboardSound.sound_id, guild.soundboardSounds._add(soundboardSound));\n  }\n\n  /**\n   * Emitted whenever multiple guild soundboard sounds are updated.\n   *\n   * @event Client#guildSoundboardSoundsUpdate\n   * @param {Collection<Snowflake, SoundboardSound>} soundboardSounds The updated soundboard sounds\n   * @param {Guild} guild The guild that the soundboard sounds are from\n   */\n  client.emit(Events.GuildSoundboardSoundsUpdate, soundboardSounds, guild);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_CREATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n\n  if (!guild) return;\n\n  const soundboardSound = guild.soundboardSounds._add(data);\n\n  /**\n   * Emitted whenever a guild soundboard sound is created.\n   *\n   * @event Client#guildSoundboardSoundCreate\n   * @param {SoundboardSound} soundboardSound The created guild soundboard sound\n   */\n  client.emit(Events.GuildSoundboardSoundCreate, soundboardSound);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_DELETE.js",
    "content": "'use strict';\n\nmodule.exports = (client, { d: data }) => {\n  client.actions.GuildSoundboardSoundDelete.handle(data);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n\n  if (!guild) return;\n\n  const oldGuildSoundboardSound = guild.soundboardSounds.cache.get(data.sound_id)?._clone() ?? null;\n  const newGuildSoundboardSound = guild.soundboardSounds._add(data);\n\n  /**\n   * Emitted whenever a guild soundboard sound is updated.\n   *\n   * @event Client#guildSoundboardSoundUpdate\n   * @param {?SoundboardSound} oldGuildSoundboardSound The guild soundboard sound before the update\n   * @param {SoundboardSound} newGuildSoundboardSound The guild soundboard sound after the update\n   */\n  client.emit(Events.GuildSoundboardSoundUpdate, oldGuildSoundboardSound, newGuildSoundboardSound);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_STICKERS_UPDATE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.GuildStickersUpdate.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/GUILD_UPDATE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.GuildUpdate.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/INTERACTION_CREATE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.InteractionCreate.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/INVITE_CREATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const channel = client.channels.cache.get(data.channel_id);\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!channel) return;\n\n  const inviteData = Object.assign(data, { channel, guild });\n  const invite = guild.invites._add(inviteData);\n\n  /**\n   * Emitted when an invite is created.\n   * <info>This event requires the {@link PermissionFlagsBits.ManageChannels} permission for the channel.</info>\n   *\n   * @event Client#inviteCreate\n   * @param {GuildInvite} invite The invite that was created\n   */\n  client.emit(Events.InviteCreate, invite);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/INVITE_DELETE.js",
    "content": "'use strict';\n\nconst { GuildInvite } = require('../../../structures/GuildInvite.js');\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const channel = client.channels.cache.get(data.channel_id);\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!channel) return;\n\n  const inviteData = Object.assign(data, { channel, guild });\n  const invite = new GuildInvite(client, inviteData);\n\n  guild.invites.cache.delete(invite.code);\n\n  /**\n   * Emitted when an invite is deleted.\n   * <info>This event requires the {@link PermissionFlagsBits.ManageChannels} permission for the channel.</info>\n   *\n   * @event Client#inviteDelete\n   * @param {GuildInvite} invite The invite that was deleted\n   */\n  client.emit(Events.InviteDelete, invite);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/MESSAGE_CREATE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.MessageCreate.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/MESSAGE_DELETE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.MessageDelete.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/MESSAGE_DELETE_BULK.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.MessageDeleteBulk.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/MESSAGE_POLL_VOTE_ADD.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.MessagePollVoteAdd.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/MESSAGE_POLL_VOTE_REMOVE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.MessagePollVoteRemove.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_ADD.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.MessageReactionAdd.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.MessageReactionRemove.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_ALL.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.MessageReactionRemoveAll.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_EMOJI.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.MessageReactionRemoveEmoji.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/MESSAGE_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, packet) => {\n  const { old, updated } = client.actions.MessageUpdate.handle(packet.d);\n  if (old && updated) {\n    /**\n     * Emitted whenever a message is updated - e.g. embed or content change.\n     *\n     * @event Client#messageUpdate\n     * @param {Message} oldMessage The message before the update\n     * @param {Message} newMessage The message after the update\n     */\n    client.emit(Events.MessageUpdate, old, updated);\n  }\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/PRESENCE_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\nconst { Partials } = require('../../../util/Partials.js');\n\nmodule.exports = (client, { d: data }) => {\n  let user = client.users.cache.get(data.user.id);\n  if (!user && ('username' in data.user || client.options.partials.includes(Partials.User))) {\n    user = client.users._add(data.user);\n  }\n\n  if (!user) return;\n\n  if (data.user.username && !user._equals(data.user)) client.actions.UserUpdate.handle(data.user);\n\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n\n  const oldPresence = guild.presences.cache.get(user.id)?._clone() ?? null;\n\n  let member = guild.members.cache.get(user.id);\n  if (!member && data.status !== 'offline') {\n    member = guild.members._add({\n      user,\n      deaf: false,\n      mute: false,\n    });\n\n    client.emit(Events.GuildMemberAvailable, member);\n  }\n\n  const newPresence = guild.presences._add(Object.assign(data, { guild }));\n  if (client.listenerCount(Events.PresenceUpdate) > 0 && !newPresence.equals(oldPresence)) {\n    /**\n     * Emitted whenever a guild member's presence (e.g. status, activity) is changed.\n     *\n     * @event Client#presenceUpdate\n     * @param {?Presence} oldPresence The presence before the update, if one at all\n     * @param {Presence} newPresence The presence after the update\n     */\n    client.emit(Events.PresenceUpdate, oldPresence, newPresence);\n  }\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/RATE_LIMITED.js",
    "content": "'use strict';\n\nconst process = require('node:process');\nconst { GatewayOpcodes } = require('discord-api-types/v10');\n\nconst emittedFor = new Set();\n\nmodule.exports = (client, { d: data }) => {\n  switch (data.opcode) {\n    case GatewayOpcodes.RequestGuildMembers: {\n      break;\n    }\n\n    default: {\n      if (!emittedFor.has(data.opcode)) {\n        process.emitWarning(\n          `Hit a gateway rate limit on opcode ${data.opcode} (${GatewayOpcodes[data.opcode]}). If the discord.js version you're using is up-to-date, please open an issue on GitHub.`,\n        );\n\n        emittedFor.add(data.opcode);\n      }\n    }\n  }\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/READY.js",
    "content": "'use strict';\n\nconst { ClientApplication } = require('../../../structures/ClientApplication.js');\nconst { Status } = require('../../../util/Status.js');\n\nlet ClientUser;\n\nmodule.exports = (client, { d: data }, shardId) => {\n  if (client.user) {\n    client.user._patch(data.user);\n  } else {\n    ClientUser ??= require('../../../structures/ClientUser.js').ClientUser;\n    client.user = new ClientUser(client, data.user);\n    client.users.cache.set(client.user.id, client.user);\n  }\n\n  for (const guild of data.guilds) {\n    client.expectedGuilds.add(guild.id);\n    guild.shardId = shardId;\n    client.guilds._add(guild);\n  }\n\n  if (client.application) {\n    client.application._patch(data.application);\n  } else {\n    client.application = new ClientApplication(client, data.application);\n  }\n\n  client.status = Status.WaitingForGuilds;\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/SOUNDBOARD_SOUNDS.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n\n  if (!guild) return;\n\n  const soundboardSounds = new Collection();\n\n  for (const soundboardSound of data.soundboard_sounds) {\n    soundboardSounds.set(soundboardSound.sound_id, guild.soundboardSounds._add(soundboardSound));\n  }\n\n  /**\n   * Emitted whenever soundboard sounds are received (all soundboard sounds come from the same guild).\n   *\n   * @event Client#soundboardSounds\n   * @param {Collection<Snowflake, SoundboardSound>} soundboardSounds The sounds received\n   * @param {Guild} guild The guild that the soundboard sounds are from\n   */\n  client.emit(Events.SoundboardSounds, soundboardSounds, guild);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/STAGE_INSTANCE_CREATE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.StageInstanceCreate.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/STAGE_INSTANCE_DELETE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.StageInstanceDelete.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/STAGE_INSTANCE_UPDATE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.StageInstanceUpdate.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/SUBSCRIPTION_CREATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const subscription = client.application.subscriptions._add(data);\n\n  /**\n   * Emitted whenever a subscription is created.\n   *\n   * @event Client#subscriptionCreate\n   * @param {Subscription} subscription The subscription that was created\n   */\n  client.emit(Events.SubscriptionCreate, subscription);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/SUBSCRIPTION_DELETE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const subscription = client.application.subscriptions._add(data, false);\n\n  client.application.subscriptions.cache.delete(subscription.id);\n\n  /**\n   * Emitted whenever a subscription is deleted.\n   *\n   * @event Client#subscriptionDelete\n   * @param {Subscription} subscription The subscription that was deleted\n   */\n  client.emit(Events.SubscriptionDelete, subscription);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/SUBSCRIPTION_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const oldSubscription = client.application.subscriptions.cache.get(data.id)?._clone() ?? null;\n  const newSubscription = client.application.subscriptions._add(data);\n\n  /**\n   * Emitted whenever a subscription is updated - i.e. when a user's subscription renews.\n   *\n   * @event Client#subscriptionUpdate\n   * @param {?Subscription} oldSubscription The subscription before the update\n   * @param {Subscription} newSubscription The subscription after the update\n   */\n  client.emit(Events.SubscriptionUpdate, oldSubscription, newSubscription);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/THREAD_CREATE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.ThreadCreate.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/THREAD_DELETE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const thread = client.channels.cache.get(data.id);\n  if (!thread) return;\n\n  client.channels._remove(thread.id);\n\n  /**\n   * Emitted whenever a thread is deleted.\n   *\n   * @event Client#threadDelete\n   * @param {ThreadChannel} thread The thread that was deleted\n   */\n  client.emit(Events.ThreadDelete, thread);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/THREAD_LIST_SYNC.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n\n  if (data.channel_ids) {\n    for (const id of data.channel_ids) {\n      const channel = client.channels.cache.get(id);\n      if (channel) removeStaleThreads(client, channel);\n    }\n  } else {\n    for (const channel of guild.channels.cache.values()) {\n      removeStaleThreads(client, channel);\n    }\n  }\n\n  const syncedThreads = data.threads.reduce((coll, rawThread) => {\n    const thread = client.channels._add(rawThread);\n    return coll.set(thread.id, thread);\n  }, new Collection());\n\n  for (const rawMember of Object.values(data.members)) {\n    // Discord sends the thread id as id in this object\n    const thread = client.channels.cache.get(rawMember.id);\n    if (thread) {\n      thread.members._add(rawMember);\n    }\n  }\n\n  /**\n   * Emitted whenever the client user gains access to a text or announcement channel that contains threads\n   *\n   * @event Client#threadListSync\n   * @param {Collection<Snowflake, ThreadChannel>} threads The threads that were synced\n   * @param {Guild} guild The guild that the threads were synced in\n   */\n  client.emit(Events.ThreadListSync, syncedThreads, guild);\n};\n\nfunction removeStaleThreads(client, channel) {\n  if (!channel.threads) return;\n\n  for (const thread of channel.threads.cache.values()) {\n    if (!thread.archived) {\n      client.channels._remove(thread.id);\n    }\n  }\n}\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/THREAD_MEMBERS_UPDATE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.ThreadMembersUpdate.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/THREAD_MEMBER_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  // Discord sends the thread id as id in this object\n  const thread = client.channels.cache.get(data.id);\n  if (!thread) return;\n\n  const member = thread.members.cache.get(data.user_id);\n  if (!member) {\n    thread.members._add(data);\n    return;\n  }\n\n  const old = member._update(data);\n\n  /**\n   * Emitted whenever the client user's thread member is updated.\n   *\n   * @event Client#threadMemberUpdate\n   * @param {ThreadMember} oldMember The member before the update\n   * @param {ThreadMember} newMember The member after the update\n   */\n  client.emit(Events.ThreadMemberUpdate, old, member);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/THREAD_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, packet) => {\n  const { old, updated } = client.actions.ChannelUpdate.handle(packet.d);\n  if (old && updated) {\n    /**\n     * Emitted whenever a thread is updated - e.g. name change, archive state change, locked state change.\n     *\n     * @event Client#threadUpdate\n     * @param {ThreadChannel} oldThread The thread before the update\n     * @param {ThreadChannel} newThread The thread after the update\n     */\n    client.emit(Events.ThreadUpdate, old, updated);\n  }\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/TYPING_START.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.TypingStart.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/USER_UPDATE.js",
    "content": "'use strict';\n\nmodule.exports = (client, packet) => {\n  client.actions.UserUpdate.handle(packet.d);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js",
    "content": "'use strict';\n\nconst { VoiceChannelEffect } = require('../../../structures/VoiceChannelEffect.js');\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n\n  /**\n   * Emitted when someone sends an effect, such as an emoji reaction, in a voice channel the client is connected to.\n   *\n   * @event Client#voiceChannelEffectSend\n   * @param {VoiceChannelEffect} voiceChannelEffect The sent voice channel effect\n   */\n  client.emit(Events.VoiceChannelEffectSend, new VoiceChannelEffect(data, guild));\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/VOICE_SERVER_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  client.emit(\n    Events.Debug,\n    `[VOICE] received voice server: ${JSON.stringify({ ...data, token: '*'.repeat(data.token.length) })}`,\n  );\n\n  client.voice.onVoiceServer(data);\n\n  /**\n   * Represents the properties of a voice server update\n   *\n   * @typedef {Object} VoiceServerUpdateData\n   * @property {Snowflake} guildId The id of the guild this voice server update is for\n   * @property {?string} endpoint The voice server host\n   * @property {string} token The voice connection token\n   */\n\n  /**\n   * Emitted whenever a voice server is updated.\n   *\n   * @event Client#voiceServerUpdate\n   * @param {VoiceServerUpdateData} data The voice server update data\n   */\n  client.emit(Events.VoiceServerUpdate, {\n    guildId: data.guild_id,\n    endpoint: data.endpoint,\n    token: data.token,\n  });\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/VOICE_STATE_UPDATE.js",
    "content": "'use strict';\n\nconst { VoiceState } = require('../../../structures/VoiceState.js');\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const guild = client.guilds.cache.get(data.guild_id);\n  if (!guild) return;\n\n  // Update the state\n  const oldState =\n    guild.voiceStates.cache.get(data.user_id)?._clone() ?? new VoiceState(guild, { user_id: data.user_id });\n\n  const newState = guild.voiceStates._add(data);\n\n  // Get the member\n  let member = guild.members.cache.get(data.user_id);\n  if (member && data.member) {\n    member._patch(data.member);\n  } else if (data.member?.user && data.member.joined_at) {\n    member = guild.members._add(data.member);\n  }\n\n  // Emit event\n  if (member?.user.id === client.user.id) {\n    client.emit(Events.Debug, `[VOICE] received voice state update: ${JSON.stringify(data)}`);\n    client.voice.onVoiceStateUpdate(data);\n  }\n\n  /**\n   * Emitted whenever a member changes voice state - e.g. joins/leaves a channel, mutes/unmutes.\n   *\n   * @event Client#voiceStateUpdate\n   * @param {VoiceState} oldState The voice state before the update\n   * @param {VoiceState} newState The voice state after the update\n   */\n  client.emit(Events.VoiceStateUpdate, oldState, newState);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/WEBHOOKS_UPDATE.js",
    "content": "'use strict';\n\nconst { Events } = require('../../../util/Events.js');\n\nmodule.exports = (client, { d: data }) => {\n  const channel = client.channels.cache.get(data.channel_id);\n  if (!channel) return;\n\n  /**\n   * Emitted whenever a channel has its webhooks changed.\n   *\n   * @event Client#webhooksUpdate\n   * @param {TextChannel|AnnouncementChannel|VoiceChannel|StageChannel|ForumChannel|MediaChannel} channel\n   * The channel that had a webhook update\n   */\n  client.emit(Events.WebhooksUpdate, channel);\n};\n"
  },
  {
    "path": "packages/discord.js/src/client/websocket/handlers/index.js",
    "content": "'use strict';\n\nconst PacketHandlers = Object.fromEntries([\n  ['APPLICATION_COMMAND_PERMISSIONS_UPDATE', require('./APPLICATION_COMMAND_PERMISSIONS_UPDATE.js')],\n  ['AUTO_MODERATION_ACTION_EXECUTION', require('./AUTO_MODERATION_ACTION_EXECUTION.js')],\n  ['AUTO_MODERATION_RULE_CREATE', require('./AUTO_MODERATION_RULE_CREATE.js')],\n  ['AUTO_MODERATION_RULE_DELETE', require('./AUTO_MODERATION_RULE_DELETE.js')],\n  ['AUTO_MODERATION_RULE_UPDATE', require('./AUTO_MODERATION_RULE_UPDATE.js')],\n  ['CHANNEL_CREATE', require('./CHANNEL_CREATE.js')],\n  ['CHANNEL_DELETE', require('./CHANNEL_DELETE.js')],\n  ['CHANNEL_PINS_UPDATE', require('./CHANNEL_PINS_UPDATE.js')],\n  ['CHANNEL_UPDATE', require('./CHANNEL_UPDATE.js')],\n  ['ENTITLEMENT_CREATE', require('./ENTITLEMENT_CREATE.js')],\n  ['ENTITLEMENT_DELETE', require('./ENTITLEMENT_DELETE.js')],\n  ['ENTITLEMENT_UPDATE', require('./ENTITLEMENT_UPDATE.js')],\n  ['GUILD_AUDIT_LOG_ENTRY_CREATE', require('./GUILD_AUDIT_LOG_ENTRY_CREATE.js')],\n  ['GUILD_BAN_ADD', require('./GUILD_BAN_ADD.js')],\n  ['GUILD_BAN_REMOVE', require('./GUILD_BAN_REMOVE.js')],\n  ['GUILD_CREATE', require('./GUILD_CREATE.js')],\n  ['GUILD_DELETE', require('./GUILD_DELETE.js')],\n  ['GUILD_EMOJIS_UPDATE', require('./GUILD_EMOJIS_UPDATE.js')],\n  ['GUILD_INTEGRATIONS_UPDATE', require('./GUILD_INTEGRATIONS_UPDATE.js')],\n  ['GUILD_MEMBERS_CHUNK', require('./GUILD_MEMBERS_CHUNK.js')],\n  ['GUILD_MEMBER_ADD', require('./GUILD_MEMBER_ADD.js')],\n  ['GUILD_MEMBER_REMOVE', require('./GUILD_MEMBER_REMOVE.js')],\n  ['GUILD_MEMBER_UPDATE', require('./GUILD_MEMBER_UPDATE.js')],\n  ['GUILD_ROLE_CREATE', require('./GUILD_ROLE_CREATE.js')],\n  ['GUILD_ROLE_DELETE', require('./GUILD_ROLE_DELETE.js')],\n  ['GUILD_ROLE_UPDATE', require('./GUILD_ROLE_UPDATE.js')],\n  ['GUILD_SCHEDULED_EVENT_CREATE', require('./GUILD_SCHEDULED_EVENT_CREATE.js')],\n  ['GUILD_SCHEDULED_EVENT_DELETE', require('./GUILD_SCHEDULED_EVENT_DELETE.js')],\n  ['GUILD_SCHEDULED_EVENT_UPDATE', require('./GUILD_SCHEDULED_EVENT_UPDATE.js')],\n  ['GUILD_SCHEDULED_EVENT_USER_ADD', require('./GUILD_SCHEDULED_EVENT_USER_ADD.js')],\n  ['GUILD_SCHEDULED_EVENT_USER_REMOVE', require('./GUILD_SCHEDULED_EVENT_USER_REMOVE.js')],\n  ['GUILD_SOUNDBOARD_SOUNDS_UPDATE', require('./GUILD_SOUNDBOARD_SOUNDS_UPDATE.js')],\n  ['GUILD_SOUNDBOARD_SOUND_CREATE', require('./GUILD_SOUNDBOARD_SOUND_CREATE.js')],\n  ['GUILD_SOUNDBOARD_SOUND_DELETE', require('./GUILD_SOUNDBOARD_SOUND_DELETE.js')],\n  ['GUILD_SOUNDBOARD_SOUND_UPDATE', require('./GUILD_SOUNDBOARD_SOUND_UPDATE.js')],\n  ['GUILD_STICKERS_UPDATE', require('./GUILD_STICKERS_UPDATE.js')],\n  ['GUILD_UPDATE', require('./GUILD_UPDATE.js')],\n  ['INTERACTION_CREATE', require('./INTERACTION_CREATE.js')],\n  ['INVITE_CREATE', require('./INVITE_CREATE.js')],\n  ['INVITE_DELETE', require('./INVITE_DELETE.js')],\n  ['MESSAGE_CREATE', require('./MESSAGE_CREATE.js')],\n  ['MESSAGE_DELETE', require('./MESSAGE_DELETE.js')],\n  ['MESSAGE_DELETE_BULK', require('./MESSAGE_DELETE_BULK.js')],\n  ['MESSAGE_POLL_VOTE_ADD', require('./MESSAGE_POLL_VOTE_ADD.js')],\n  ['MESSAGE_POLL_VOTE_REMOVE', require('./MESSAGE_POLL_VOTE_REMOVE.js')],\n  ['MESSAGE_REACTION_ADD', require('./MESSAGE_REACTION_ADD.js')],\n  ['MESSAGE_REACTION_REMOVE', require('./MESSAGE_REACTION_REMOVE.js')],\n  ['MESSAGE_REACTION_REMOVE_ALL', require('./MESSAGE_REACTION_REMOVE_ALL.js')],\n  ['MESSAGE_REACTION_REMOVE_EMOJI', require('./MESSAGE_REACTION_REMOVE_EMOJI.js')],\n  ['MESSAGE_UPDATE', require('./MESSAGE_UPDATE.js')],\n  ['PRESENCE_UPDATE', require('./PRESENCE_UPDATE.js')],\n  ['RATE_LIMITED', require('./RATE_LIMITED.js')],\n  ['READY', require('./READY.js')],\n  ['SOUNDBOARD_SOUNDS', require('./SOUNDBOARD_SOUNDS.js')],\n  ['STAGE_INSTANCE_CREATE', require('./STAGE_INSTANCE_CREATE.js')],\n  ['STAGE_INSTANCE_DELETE', require('./STAGE_INSTANCE_DELETE.js')],\n  ['STAGE_INSTANCE_UPDATE', require('./STAGE_INSTANCE_UPDATE.js')],\n  ['SUBSCRIPTION_CREATE', require('./SUBSCRIPTION_CREATE.js')],\n  ['SUBSCRIPTION_DELETE', require('./SUBSCRIPTION_DELETE.js')],\n  ['SUBSCRIPTION_UPDATE', require('./SUBSCRIPTION_UPDATE.js')],\n  ['THREAD_CREATE', require('./THREAD_CREATE.js')],\n  ['THREAD_DELETE', require('./THREAD_DELETE.js')],\n  ['THREAD_LIST_SYNC', require('./THREAD_LIST_SYNC.js')],\n  ['THREAD_MEMBERS_UPDATE', require('./THREAD_MEMBERS_UPDATE.js')],\n  ['THREAD_MEMBER_UPDATE', require('./THREAD_MEMBER_UPDATE.js')],\n  ['THREAD_UPDATE', require('./THREAD_UPDATE.js')],\n  ['TYPING_START', require('./TYPING_START.js')],\n  ['USER_UPDATE', require('./USER_UPDATE.js')],\n  ['VOICE_CHANNEL_EFFECT_SEND', require('./VOICE_CHANNEL_EFFECT_SEND.js')],\n  ['VOICE_SERVER_UPDATE', require('./VOICE_SERVER_UPDATE.js')],\n  ['VOICE_STATE_UPDATE', require('./VOICE_STATE_UPDATE.js')],\n  ['WEBHOOKS_UPDATE', require('./WEBHOOKS_UPDATE.js')],\n]);\n\nexports.PacketHandlers = PacketHandlers;\n"
  },
  {
    "path": "packages/discord.js/src/errors/DJSError.js",
    "content": "'use strict';\n\n// Heavily inspired by node's `internal/errors` module\nconst { ErrorCodes } = require('./ErrorCodes.js');\nconst { Messages } = require('./Messages.js');\n\n/**\n * Extend an error of some sort into a DiscordjsError.\n *\n * @param {Error} Base Base error to extend\n * @returns {DiscordjsError}\n * @ignore\n */\nfunction makeDiscordjsError(Base) {\n  return class extends Base {\n    static {\n      Object.defineProperty(this, 'name', { value: `Discordjs${Base.name}` });\n    }\n\n    constructor(code, ...args) {\n      super(message(code, args));\n      this.code = code;\n      Error.captureStackTrace(this, this.constructor);\n    }\n\n    get name() {\n      return `${this.constructor.name} [${this.code}]`;\n    }\n  };\n}\n\n/**\n * Format the message for an error.\n *\n * @param {string} code The error code\n * @param {Array<*>} args Arguments to pass for util format or as function args\n * @returns {string} Formatted string\n * @ignore\n */\nfunction message(code, args) {\n  if (!(code in ErrorCodes)) throw new Error('Error code must be a valid DiscordjsErrorCodes');\n  const msg = Messages[code];\n  if (!msg) throw new Error(`No message associated with error code: ${code}.`);\n  if (typeof msg === 'function') return msg(...args);\n  if (!args?.length) return msg;\n  args.unshift(msg);\n  return String(...args);\n}\n\nexports.DiscordjsError = makeDiscordjsError(Error);\nexports.DiscordjsTypeError = makeDiscordjsError(TypeError);\nexports.DiscordjsRangeError = makeDiscordjsError(RangeError);\n"
  },
  {
    "path": "packages/discord.js/src/errors/ErrorCodes.js",
    "content": "/* eslint-disable jsdoc/tag-lines, jsdoc/require-property-description */\n'use strict';\n\n/**\n * @typedef {Object} DiscordjsErrorCodes\n * @property {'ClientInvalidOption'} ClientInvalidOption\n * @property {'ClientInvalidProvidedShards'} ClientInvalidProvidedShards\n * @property {'ClientMissingIntents'} ClientMissingIntents\n * @property {'ClientNotReady'} ClientNotReady\n *\n * @property {'TokenInvalid'} TokenInvalid\n * @property {'TokenMissing'} TokenMissing\n * @property {'ApplicationCommandPermissionsTokenMissing'} ApplicationCommandPermissionsTokenMissing\n *\n * @property {'BitFieldInvalid'} BitFieldInvalid\n *\n * @property {'ShardingNoShards'} ShardingNoShards\n * @property {'ShardingInProcess'} ShardingInProcess\n * @property {'ShardingInvalidEvalBroadcast'} ShardingInvalidEvalBroadcast\n * @property {'ShardingShardNotFound'} ShardingShardNotFound\n * @property {'ShardingAlreadySpawned'} ShardingAlreadySpawned\n * @property {'ShardingProcessExists'} ShardingProcessExists\n * @property {'ShardingWorkerExists'} ShardingWorkerExists\n * @property {'ShardingReadyTimeout'} ShardingReadyTimeout\n * @property {'ShardingReadyDisconnected'} ShardingReadyDisconnected\n * @property {'ShardingReadyDied'} ShardingReadyDied\n * @property {'ShardingNoChildExists'} ShardingNoChildExists\n * @property {'ShardingShardMiscalculation'} ShardingShardMiscalculation\n *\n * @property {'ColorRange'} ColorRange\n * @property {'ColorConvert'} ColorConvert\n *\n * @property {'InviteOptionsMissingChannel'} InviteOptionsMissingChannel\n *\n * @property {'InteractionCollectorError'} InteractionCollectorError\n *\n * @property {'FileNotFound'} FileNotFound\n *\n * @property {'UserNoDMChannel'} UserNoDMChannel\n *\n * @property {'VoiceNotStageChannel'} VoiceNotStageChannel\n *\n * @property {'VoiceStateNotOwn'} VoiceStateNotOwn\n * @property {'VoiceStateInvalidType'} VoiceStateInvalidType\n *\n * @property {'ReqResourceType'} ReqResourceType\n *\n * @property {'MessageBulkDeleteType'} MessageBulkDeleteType\n * @property {'MessageContentType'} MessageContentType\n * @property {'MessageNonceRequired'} MessageNonceRequired\n * @property {'MessageNonceType'} MessageNonceType\n *\n * @property {'BanResolveId'} BanResolveId\n * @property {'FetchBanResolveId'} FetchBanResolveId\n *\n * @property {'PruneDaysType'} PruneDaysType\n *\n * @property {'GuildChannelResolve'} GuildChannelResolve\n * @property {'GuildVoiceChannelResolve'} GuildVoiceChannelResolve\n * @property {'GuildChannelOrphan'} GuildChannelOrphan\n * @property {'GuildChannelUnowned'} GuildChannelUnowned\n * @property {'GuildMembersTimeout'} GuildMembersTimeout\n * @property {'GuildSoundboardSoundsTimeout'} GuildSoundboardSoundsTimeout\n * @property {'GuildUncachedMe'} GuildUncachedMe\n * @property {'ChannelNotCached'} ChannelNotCached\n * @property {'StageChannelResolve'} StageChannelResolve\n * @property {'GuildScheduledEventResolve'} GuildScheduledEventResolve\n * @property {'FetchOwnerId'} FetchOwnerId\n *\n * @property {'InvalidType'} InvalidType\n * @property {'InvalidElement'} InvalidElement\n *\n * @property {'MessageThreadParent'} MessageThreadParent\n * @property {'MessageExistingThread'} MessageExistingThread\n * @property {'ThreadInvitableType'} ThreadInvitableType\n * @property {'NotAThreadOfParent'} NotAThreadOfParent\n *\n * @property {'WebhookMessage'} WebhookMessage\n * @property {'WebhookTokenUnavailable'} WebhookTokenUnavailable\n * @property {'WebhookApplication'} WebhookApplication\n *\n * @property {'MessageReferenceMissing'} MessageReferenceMissing\n *\n * @property {'EmojiType'} EmojiType\n * @property {'EmojiManaged'} EmojiManaged\n * @property {'MissingGuildExpressionsPermission'} MissingGuildExpressionsPermission\n *\n * @property {'NotGuildSoundboardSound'} NotGuildSoundboardSound\n * @property {'NotGuildSticker'} NotGuildSticker\n *\n * @property {'ReactionResolveUser'} ReactionResolveUser\n *\n * @property {'InviteResolveCode'} InviteResolveCode\n * @property {'InviteNotFound'} InviteNotFound\n *\n * @property {'DeleteGroupDMChannel'} DeleteGroupDMChannel\n * @property {'FetchGroupDMChannel'} FetchGroupDMChannel\n *\n * @property {'MemberFetchNonceLength'} MemberFetchNonceLength\n *\n * @property {'GlobalCommandPermissions'} GlobalCommandPermissions\n * @property {'GuildUncachedEntityResolve'} GuildUncachedEntityResolve\n *\n * @property {'InteractionAlreadyReplied'} InteractionAlreadyReplied\n * @property {'InteractionNotReplied'} InteractionNotReplied\n *\n * @property {'CommandInteractionOptionNotFound'} CommandInteractionOptionNotFound\n * @property {'CommandInteractionOptionType'} CommandInteractionOptionType\n * @property {'CommandInteractionOptionEmpty'} CommandInteractionOptionEmpty\n * @property {'CommandInteractionOptionNoSubcommand'} CommandInteractionOptionNoSubcommand\n * @property {'CommandInteractionOptionNoSubcommandGroup'} CommandInteractionOptionNoSubcommandGroup\n * @property {'CommandInteractionOptionInvalidChannelType'} CommandInteractionOptionInvalidChannelType\n * @property {'AutocompleteInteractionOptionNoFocusedOption'} AutocompleteInteractionOptionNoFocusedOption\n *\n * @property {'ModalSubmitInteractionComponentNotFound'} ModalSubmitInteractionComponentNotFound\n * @property {'ModalSubmitInteractionComponentType'} ModalSubmitInteractionComponentType\n * @property {'ModalSubmitInteractionComponentEmpty'} ModalSubmitInteractionComponentEmpty\n * @property {'ModalSubmitInteractionComponentInvalidChannelType'} ModalSubmitInteractionComponentInvalidChannelType\n *\n * @property {'InvalidMissingScopes'} InvalidMissingScopes\n * @property {'InvalidScopesWithPermissions'} InvalidScopesWithPermissions\n *\n * @property {'NotImplemented'} NotImplemented\n *\n * @property {'GuildForumMessageRequired'} GuildForumMessageRequired\n *\n * @property {'SweepFilterReturn'} SweepFilterReturn\n *\n * @property {'EntitlementCreateInvalidOwner'} EntitlementCreateInvalidOwner\n *\n * @property {'BulkBanUsersOptionEmpty'} BulkBanUsersOptionEmpty\n *\n * @property {'PollAlreadyExpired'} PollAlreadyExpired\n *\n * @property {'PermissionOverwritesTypeMandatory'} PermissionOverwritesTypeMandatory\n * @property {'PermissionOverwritesTypeMismatch'} PermissionOverwritesTypeMismatch\n */\n\nconst keys = [\n  'ClientInvalidOption',\n  'ClientInvalidProvidedShards',\n  'ClientMissingIntents',\n  'ClientNotReady',\n\n  'TokenInvalid',\n  'TokenMissing',\n  'ApplicationCommandPermissionsTokenMissing',\n\n  'BitFieldInvalid',\n\n  'ShardingNoShards',\n  'ShardingInProcess',\n  'ShardingInvalidEvalBroadcast',\n  'ShardingShardNotFound',\n  'ShardingAlreadySpawned',\n  'ShardingProcessExists',\n  'ShardingWorkerExists',\n  'ShardingReadyTimeout',\n  'ShardingReadyDisconnected',\n  'ShardingReadyDied',\n  'ShardingNoChildExists',\n  'ShardingShardMiscalculation',\n\n  'ColorRange',\n  'ColorConvert',\n\n  'InviteOptionsMissingChannel',\n\n  'InteractionCollectorError',\n\n  'FileNotFound',\n\n  'UserNoDMChannel',\n\n  'VoiceNotStageChannel',\n\n  'VoiceStateNotOwn',\n  'VoiceStateInvalidType',\n\n  'ReqResourceType',\n\n  'MessageBulkDeleteType',\n  'MessageContentType',\n  'MessageNonceRequired',\n  'MessageNonceType',\n\n  'BanResolveId',\n  'FetchBanResolveId',\n\n  'PruneDaysType',\n\n  'GuildChannelResolve',\n  'GuildVoiceChannelResolve',\n  'GuildChannelOrphan',\n  'GuildChannelUnowned',\n  'GuildMembersTimeout',\n  'GuildSoundboardSoundsTimeout',\n  'GuildUncachedMe',\n  'ChannelNotCached',\n  'StageChannelResolve',\n  'GuildScheduledEventResolve',\n  'FetchOwnerId',\n\n  'InvalidType',\n  'InvalidElement',\n\n  'MessageThreadParent',\n  'MessageExistingThread',\n  'ThreadInvitableType',\n  'NotAThreadOfParent',\n\n  'WebhookMessage',\n  'WebhookTokenUnavailable',\n  'WebhookApplication',\n\n  'MessageReferenceMissing',\n\n  'EmojiType',\n  'EmojiManaged',\n  'MissingGuildExpressionsPermission',\n\n  'NotGuildSoundboardSound',\n  'NotGuildSticker',\n\n  'ReactionResolveUser',\n\n  'InviteResolveCode',\n  'InviteNotFound',\n\n  'DeleteGroupDMChannel',\n  'FetchGroupDMChannel',\n\n  'MemberFetchNonceLength',\n\n  'GlobalCommandPermissions',\n  'GuildUncachedEntityResolve',\n\n  'InteractionAlreadyReplied',\n  'InteractionNotReplied',\n\n  'CommandInteractionOptionNotFound',\n  'CommandInteractionOptionType',\n  'CommandInteractionOptionEmpty',\n  'CommandInteractionOptionNoSubcommand',\n  'CommandInteractionOptionNoSubcommandGroup',\n  'CommandInteractionOptionInvalidChannelType',\n  'AutocompleteInteractionOptionNoFocusedOption',\n\n  'ModalSubmitInteractionComponentNotFound',\n  'ModalSubmitInteractionComponentType',\n  'ModalSubmitInteractionComponentEmpty',\n  'ModalSubmitInteractionComponentInvalidChannelType',\n\n  'InvalidMissingScopes',\n  'InvalidScopesWithPermissions',\n\n  'NotImplemented',\n\n  'SweepFilterReturn',\n\n  'GuildForumMessageRequired',\n\n  'EntitlementCreateInvalidOwner',\n\n  'BulkBanUsersOptionEmpty',\n\n  'PollAlreadyExpired',\n\n  'PermissionOverwritesTypeMandatory',\n  'PermissionOverwritesTypeMismatch',\n];\n\n// JSDoc for IntelliSense purposes\n/**\n * @type {DiscordjsErrorCodes}\n * @ignore\n */\nconst ErrorCodes = Object.fromEntries(keys.map(key => [key, key]));\n\nexports.ErrorCodes = ErrorCodes;\n"
  },
  {
    "path": "packages/discord.js/src/errors/Messages.js",
    "content": "'use strict';\n\nconst { ErrorCodes } = require('./ErrorCodes.js');\n\nconst Messages = {\n  [ErrorCodes.ClientInvalidOption]: (prop, must) => `The ${prop} option must be ${must}`,\n  [ErrorCodes.ClientInvalidProvidedShards]: 'None of the provided shards were valid.',\n  [ErrorCodes.ClientMissingIntents]: 'Valid intents must be provided for the Client.',\n  [ErrorCodes.ClientNotReady]: action => `The client needs to be logged in to ${action}.`,\n\n  [ErrorCodes.TokenInvalid]: 'An invalid token was provided.',\n  [ErrorCodes.TokenMissing]: 'Request to use token, but token was unavailable to the client.',\n  [ErrorCodes.ApplicationCommandPermissionsTokenMissing]:\n    'Editing application command permissions requires an OAuth2 bearer token, but none was provided.',\n\n  [ErrorCodes.BitFieldInvalid]: bit => `Invalid bitfield flag or number: ${bit}.`,\n\n  [ErrorCodes.ShardingNoShards]: 'No shards have been spawned.',\n  [ErrorCodes.ShardingInProcess]: 'Shards are still being spawned.',\n  [ErrorCodes.ShardingInvalidEvalBroadcast]: 'Script to evaluate must be a function',\n  [ErrorCodes.ShardingShardNotFound]: id => `Shard ${id} could not be found.`,\n  [ErrorCodes.ShardingAlreadySpawned]: count => `Already spawned ${count} shards.`,\n  [ErrorCodes.ShardingProcessExists]: id => `Shard ${id} already has an active process.`,\n  [ErrorCodes.ShardingWorkerExists]: id => `Shard ${id} already has an active worker.`,\n  [ErrorCodes.ShardingReadyTimeout]: id => `Shard ${id}'s Client took too long to become ready.`,\n  [ErrorCodes.ShardingReadyDisconnected]: id => `Shard ${id}'s Client disconnected before becoming ready.`,\n  [ErrorCodes.ShardingReadyDied]: id => `Shard ${id}'s process exited before its Client became ready.`,\n  [ErrorCodes.ShardingNoChildExists]: id => `Shard ${id} has no active process or worker.`,\n  [ErrorCodes.ShardingShardMiscalculation]: (shard, guild, count) =>\n    `Calculated invalid shard ${shard} for guild ${guild} with ${count} shards.`,\n\n  [ErrorCodes.ColorRange]: 'Color must be within the range 0 - 16777215 (0xFFFFFF).',\n  [ErrorCodes.ColorConvert]: color => `Unable to convert \"${color}\" to a number.`,\n\n  [ErrorCodes.InviteOptionsMissingChannel]:\n    'A valid guild channel must be provided when GuildScheduledEvent is EXTERNAL.',\n\n  [ErrorCodes.InteractionCollectorError]: reason =>\n    `Collector received no interactions before ending with reason: ${reason}`,\n\n  [ErrorCodes.FileNotFound]: file => `File could not be found: ${file}`,\n\n  [ErrorCodes.UserNoDMChannel]: 'No DM Channel exists!',\n\n  [ErrorCodes.VoiceNotStageChannel]: 'You are only allowed to do this in stage channels.',\n\n  [ErrorCodes.VoiceStateNotOwn]:\n    'You cannot self-deafen/mute/request to speak on VoiceStates that do not belong to the ClientUser.',\n  [ErrorCodes.VoiceStateInvalidType]: name => `${name} must be a boolean.`,\n\n  [ErrorCodes.ReqResourceType]: 'The resource must be a string, Buffer or a valid file stream.',\n\n  [ErrorCodes.MessageBulkDeleteType]: 'The messages must be an Array, Collection, or number.',\n  [ErrorCodes.MessageContentType]: 'Message content must be a string.',\n  [ErrorCodes.MessageNonceRequired]: 'Message nonce is required when enforceNonce is true.',\n  [ErrorCodes.MessageNonceType]: 'Message nonce must be an integer or a string.',\n\n  [ErrorCodes.BanResolveId]: (ban = false) => `Couldn't resolve the user id to ${ban ? 'ban' : 'unban'}.`,\n  [ErrorCodes.FetchBanResolveId]: \"Couldn't resolve the user id to fetch the ban.\",\n\n  [ErrorCodes.PruneDaysType]: 'Days must be a number',\n\n  [ErrorCodes.GuildChannelResolve]: 'Could not resolve channel to a guild channel.',\n  [ErrorCodes.GuildVoiceChannelResolve]: 'Could not resolve channel to a guild voice channel.',\n  [ErrorCodes.GuildChannelOrphan]: 'Could not find a parent to this guild channel.',\n  [ErrorCodes.GuildChannelUnowned]: \"The fetched channel does not belong to this manager's guild.\",\n  [ErrorCodes.GuildMembersTimeout]: \"Members didn't arrive in time.\",\n  [ErrorCodes.GuildSoundboardSoundsTimeout]: \"Soundboard sounds didn't arrive in time.\",\n  [ErrorCodes.GuildUncachedMe]: 'The client user as a member of this guild is uncached.',\n  [ErrorCodes.ChannelNotCached]: 'Could not find the channel where this message came from in the cache!',\n  [ErrorCodes.StageChannelResolve]: 'Could not resolve channel to a stage channel.',\n  [ErrorCodes.GuildScheduledEventResolve]: 'Could not resolve the guild scheduled event.',\n  [ErrorCodes.FetchOwnerId]: type => `Couldn't resolve the ${type} ownerId to fetch the ${type} member.`,\n\n  [ErrorCodes.InvalidType]: (name, expected, an = false) => `Supplied ${name} is not a${an ? 'n' : ''} ${expected}.`,\n  [ErrorCodes.InvalidElement]: (type, name, elem) => `Supplied ${type} ${name} includes an invalid element: ${elem}`,\n\n  [ErrorCodes.MessageThreadParent]: 'The message was not sent in a guild text or announcement channel',\n  [ErrorCodes.MessageExistingThread]: 'The message already has a thread',\n  [ErrorCodes.ThreadInvitableType]: type => `Invitable cannot be edited on ${type}`,\n  [ErrorCodes.NotAThreadOfParent]: 'Provided ThreadChannelResolvable is not a thread of the parent channel.',\n\n  [ErrorCodes.WebhookMessage]: 'The message was not sent by a webhook.',\n  [ErrorCodes.WebhookTokenUnavailable]: 'This action requires a webhook token, but none is available.',\n  [ErrorCodes.WebhookApplication]: 'This message webhook belongs to an application and cannot be fetched.',\n\n  [ErrorCodes.MessageReferenceMissing]: 'The message does not reference another message',\n\n  [ErrorCodes.EmojiType]: 'Emoji must be a string or GuildEmoji/ReactionEmoji',\n  [ErrorCodes.EmojiManaged]: 'Emoji is managed and has no Author.',\n  [ErrorCodes.MissingGuildExpressionsPermission]: guild =>\n    `Client must have Create Guild Expressions or Manage Guild Expressions permission in guild ${guild} to see emoji authors.`,\n\n  [ErrorCodes.NotGuildSoundboardSound]: action =>\n    `Soundboard sound is a default (non-guild) soundboard sound and can't be ${action}.`,\n  [ErrorCodes.NotGuildSticker]: 'Sticker is a standard (non-guild) sticker and has no author.',\n\n  [ErrorCodes.ReactionResolveUser]: \"Couldn't resolve the user id to remove from the reaction.\",\n\n  [ErrorCodes.InviteResolveCode]: 'Could not resolve the code to fetch the invite.',\n  [ErrorCodes.InviteNotFound]: 'Could not find the requested invite.',\n\n  [ErrorCodes.DeleteGroupDMChannel]: \"Bots don't have access to Group DM Channels and cannot delete them\",\n  [ErrorCodes.FetchGroupDMChannel]: \"Bots don't have access to Group DM Channels and cannot fetch them\",\n\n  [ErrorCodes.MemberFetchNonceLength]: 'Nonce length must not exceed 32 characters.',\n\n  [ErrorCodes.GlobalCommandPermissions]:\n    'Permissions for global commands may only be fetched or modified by providing a GuildResolvable ' +\n    \"or from a guild's application command manager.\",\n  [ErrorCodes.GuildUncachedEntityResolve]: type =>\n    `Cannot resolve ${type} from an arbitrary guild, provide an id instead`,\n\n  [ErrorCodes.InteractionAlreadyReplied]: 'The reply to this interaction has already been sent or deferred.',\n  [ErrorCodes.InteractionNotReplied]: 'The reply to this interaction has not been sent or deferred.',\n\n  [ErrorCodes.CommandInteractionOptionNotFound]: name => `Required option \"${name}\" not found.`,\n  [ErrorCodes.CommandInteractionOptionType]: (name, type, expected) =>\n    `Option \"${name}\" is of type: ${type}; expected ${expected}.`,\n  [ErrorCodes.CommandInteractionOptionEmpty]: (name, type) =>\n    `Required option \"${name}\" is of type: ${type}; expected a non-empty value.`,\n  [ErrorCodes.CommandInteractionOptionNoSubcommand]: 'No subcommand specified for interaction.',\n  [ErrorCodes.CommandInteractionOptionNoSubcommandGroup]: 'No subcommand group specified for interaction.',\n  [ErrorCodes.CommandInteractionOptionInvalidChannelType]: (name, type, expected) =>\n    `The type of channel of the option \"${name}\" is: ${type}; expected ${expected}.`,\n  [ErrorCodes.AutocompleteInteractionOptionNoFocusedOption]: 'No focused option for autocomplete interaction.',\n\n  [ErrorCodes.ModalSubmitInteractionComponentNotFound]: customId =>\n    `Required component with custom id \"${customId}\" not found.`,\n  [ErrorCodes.ModalSubmitInteractionComponentType]: (customId, type, expected) =>\n    `Component with custom id \"${customId}\" is of type: ${type}; expected ${expected}.`,\n  [ErrorCodes.ModalSubmitInteractionComponentEmpty]: (customId, type) =>\n    `Required component with custom id \"${customId}\" is of type: ${type}; expected a non-empty value.`,\n  [ErrorCodes.ModalSubmitInteractionComponentInvalidChannelType]: (customId, type, expected) =>\n    `The type of channel of the component with custom id \"${customId}\" is: ${type}; expected ${expected}.`,\n\n  [ErrorCodes.InvalidMissingScopes]: 'At least one valid scope must be provided for the invite',\n  [ErrorCodes.InvalidScopesWithPermissions]: 'Permissions cannot be set without the bot scope.',\n\n  [ErrorCodes.NotImplemented]: (what, name) => `Method ${what} not implemented on ${name}.`,\n\n  [ErrorCodes.SweepFilterReturn]: 'The return value of the sweepFilter function was not false or a Function',\n\n  [ErrorCodes.GuildForumMessageRequired]: 'You must provide a message to create a guild forum thread',\n\n  [ErrorCodes.EntitlementCreateInvalidOwner]:\n    'You must provide either a guild or a user to create an entitlement, but not both',\n\n  [ErrorCodes.BulkBanUsersOptionEmpty]: 'Option \"users\" array or collection is empty',\n\n  [ErrorCodes.PollAlreadyExpired]: 'This poll has already expired.',\n\n  [ErrorCodes.PermissionOverwritesTypeMandatory]: '\"overwrite.type\" is mandatory if \"overwrite.id\" is a Snowflake',\n  [ErrorCodes.PermissionOverwritesTypeMismatch]: expected =>\n    `\"overwrite.id\" is a ${expected.toLowerCase()} object, ` +\n    `but \"overwrite.type\" is defined and not equal to OverwriteType.${expected}`,\n};\n\nexports.Messages = Messages;\n"
  },
  {
    "path": "packages/discord.js/src/errors/index.js",
    "content": "'use strict';\n\nexports.DiscordjsError = require('./DJSError.js').DiscordjsError;\nexports.DiscordjsTypeError = require('./DJSError.js').DiscordjsTypeError;\nexports.DiscordjsRangeError = require('./DJSError.js').DiscordjsRangeError;\nexports.ErrorCodes = require('./ErrorCodes.js').ErrorCodes;\nexports.Messages = require('./Messages.js').Messages;\n"
  },
  {
    "path": "packages/discord.js/src/index.js",
    "content": "'use strict';\n\nconst { __exportStar } = require('tslib');\n\n// \"Root\" classes (starting points)\nexports.Client = require('./client/Client.js').Client;\nexports.Shard = require('./sharding/Shard.js').Shard;\nexports.ShardClientUtil = require('./sharding/ShardClientUtil.js').ShardClientUtil;\nexports.ShardingManager = require('./sharding/ShardingManager.js').ShardingManager;\n\n// Errors\nexports.DiscordjsError = require('./errors/DJSError.js').DiscordjsError;\nexports.DiscordjsTypeError = require('./errors/DJSError.js').DiscordjsTypeError;\nexports.DiscordjsRangeError = require('./errors/DJSError.js').DiscordjsRangeError;\nexports.DiscordjsErrorCodes = require('./errors/ErrorCodes.js').ErrorCodes;\n\n// Utilities\nexports.ActivityFlagsBitField = require('./util/ActivityFlagsBitField.js').ActivityFlagsBitField;\nexports.ApplicationFlagsBitField = require('./util/ApplicationFlagsBitField.js').ApplicationFlagsBitField;\nexports.AttachmentFlagsBitField = require('./util/AttachmentFlagsBitField.js').AttachmentFlagsBitField;\nexports.BaseManager = require('./managers/BaseManager.js').BaseManager;\nexports.BitField = require('./util/BitField.js').BitField;\nexports.ChannelFlagsBitField = require('./util/ChannelFlagsBitField.js').ChannelFlagsBitField;\nexports.Collection = require('@discordjs/collection').Collection;\nexports.Colors = require('./util/Colors.js').Colors;\nexports.Constants = require('./util/Constants.js');\nexports.Events = require('./util/Events.js').Events;\nexports.GuildMemberFlagsBitField = require('./util/GuildMemberFlagsBitField.js').GuildMemberFlagsBitField;\nexports.IntentsBitField = require('./util/IntentsBitField.js').IntentsBitField;\nexports.InviteFlagsBitField = require('./util/InviteFlagsBitField.js').InviteFlagsBitField;\nexports.LimitedCollection = require('./util/LimitedCollection.js').LimitedCollection;\nexports.MessageFlagsBitField = require('./util/MessageFlagsBitField.js').MessageFlagsBitField;\nexports.Options = require('./util/Options.js').Options;\nexports.Partials = require('./util/Partials.js').Partials;\nexports.PermissionsBitField = require('./util/PermissionsBitField.js').PermissionsBitField;\nexports.RoleFlagsBitField = require('./util/RoleFlagsBitField.js').RoleFlagsBitField;\nexports.ShardEvents = require('./util/ShardEvents.js').ShardEvents;\nexports.SKUFlagsBitField = require('./util/SKUFlagsBitField.js').SKUFlagsBitField;\nexports.SnowflakeUtil = require('@sapphire/snowflake').DiscordSnowflake;\nexports.Status = require('./util/Status.js').Status;\nexports.Sweepers = require('./util/Sweepers.js').Sweepers;\nexports.SystemChannelFlagsBitField = require('./util/SystemChannelFlagsBitField.js').SystemChannelFlagsBitField;\nexports.ThreadMemberFlagsBitField = require('./util/ThreadMemberFlagsBitField.js').ThreadMemberFlagsBitField;\nexports.UserFlagsBitField = require('./util/UserFlagsBitField.js').UserFlagsBitField;\n\n__exportStar(require('./util/DataResolver.js'), exports);\n\nexports.cleanCodeBlockContent = require('./util/Util.js').cleanCodeBlockContent;\nexports.cleanContent = require('./util/Util.js').cleanContent;\nexports.discordSort = require('./util/Util.js').discordSort;\nexports.fetchRecommendedShardCount = require('./util/Util.js').fetchRecommendedShardCount;\nexports.flatten = require('./util/Util.js').flatten;\nexports.parseEmoji = require('./util/Util.js').parseEmoji;\nexports.parseWebhookURL = require('./util/Util.js').parseWebhookURL;\nexports.resolveColor = require('./util/Util.js').resolveColor;\nexports.resolveSKUId = require('./util/Util.js').resolveSKUId;\nexports.verifyString = require('./util/Util.js').verifyString;\n\nexports.version = require('../package.json').version;\n\n// Managers\nexports.ApplicationCommandManager = require('./managers/ApplicationCommandManager.js').ApplicationCommandManager;\nexports.ApplicationCommandPermissionsManager =\n  require('./managers/ApplicationCommandPermissionsManager.js').ApplicationCommandPermissionsManager;\nexports.ApplicationEmojiManager = require('./managers/ApplicationEmojiManager.js').ApplicationEmojiManager;\nexports.AutoModerationRuleManager = require('./managers/AutoModerationRuleManager.js').AutoModerationRuleManager;\nexports.CachedManager = require('./managers/CachedManager.js').CachedManager;\nexports.ChannelManager = require('./managers/ChannelManager.js').ChannelManager;\nexports.ClientVoiceManager = require('./client/voice/ClientVoiceManager.js').ClientVoiceManager;\nexports.DataManager = require('./managers/DataManager.js').DataManager;\nexports.DMMessageManager = require('./managers/DMMessageManager.js').DMMessageManager;\nexports.EntitlementManager = require('./managers/EntitlementManager.js').EntitlementManager;\nexports.GuildApplicationCommandManager =\n  require('./managers/GuildApplicationCommandManager.js').GuildApplicationCommandManager;\nexports.GuildBanManager = require('./managers/GuildBanManager.js').GuildBanManager;\nexports.GuildChannelManager = require('./managers/GuildChannelManager.js').GuildChannelManager;\nexports.GuildEmojiManager = require('./managers/GuildEmojiManager.js').GuildEmojiManager;\nexports.GuildEmojiRoleManager = require('./managers/GuildEmojiRoleManager.js').GuildEmojiRoleManager;\nexports.GuildForumThreadManager = require('./managers/GuildForumThreadManager.js').GuildForumThreadManager;\nexports.GuildInviteManager = require('./managers/GuildInviteManager.js').GuildInviteManager;\nexports.GuildManager = require('./managers/GuildManager.js').GuildManager;\nexports.GuildMemberManager = require('./managers/GuildMemberManager.js').GuildMemberManager;\nexports.GuildMemberRoleManager = require('./managers/GuildMemberRoleManager.js').GuildMemberRoleManager;\nexports.GuildMessageManager = require('./managers/GuildMessageManager.js').GuildMessageManager;\nexports.GuildScheduledEventManager = require('./managers/GuildScheduledEventManager.js').GuildScheduledEventManager;\nexports.GuildSoundboardSoundManager = require('./managers/GuildSoundboardSoundManager.js').GuildSoundboardSoundManager;\nexports.GuildStickerManager = require('./managers/GuildStickerManager.js').GuildStickerManager;\nexports.GuildTextThreadManager = require('./managers/GuildTextThreadManager.js').GuildTextThreadManager;\nexports.MessageManager = require('./managers/MessageManager.js').MessageManager;\nexports.PermissionOverwriteManager = require('./managers/PermissionOverwriteManager.js').PermissionOverwriteManager;\nexports.PollAnswerVoterManager = require('./managers/PollAnswerVoterManager.js').PollAnswerVoterManager;\nexports.PresenceManager = require('./managers/PresenceManager.js').PresenceManager;\nexports.ReactionManager = require('./managers/ReactionManager.js').ReactionManager;\nexports.ReactionUserManager = require('./managers/ReactionUserManager.js').ReactionUserManager;\nexports.RoleManager = require('./managers/RoleManager.js').RoleManager;\nexports.StageInstanceManager = require('./managers/StageInstanceManager.js').StageInstanceManager;\nexports.SubscriptionManager = require('./managers/SubscriptionManager.js').SubscriptionManager;\nexports.ThreadManager = require('./managers/ThreadManager.js').ThreadManager;\nexports.ThreadMemberManager = require('./managers/ThreadMemberManager.js').ThreadMemberManager;\nexports.UserManager = require('./managers/UserManager.js').UserManager;\nexports.VoiceStateManager = require('./managers/VoiceStateManager.js').VoiceStateManager;\n\n// Structures\nexports.ActionRow = require('./structures/ActionRow.js').ActionRow;\nexports.Activity = require('./structures/Presence.js').Activity;\nexports.AnnouncementChannel = require('./structures/AnnouncementChannel.js').AnnouncementChannel;\nexports.AnonymousGuild = require('./structures/AnonymousGuild.js').AnonymousGuild;\nexports.AuthorizingIntegrationOwners =\n  require('./structures/AuthorizingIntegrationOwners.js').AuthorizingIntegrationOwners;\nexports.Application = require('./structures/interfaces/Application.js').Application;\nexports.ApplicationCommand = require('./structures/ApplicationCommand.js').ApplicationCommand;\nexports.ApplicationEmoji = require('./structures/ApplicationEmoji.js').ApplicationEmoji;\nexports.ApplicationRoleConnectionMetadata =\n  require('./structures/ApplicationRoleConnectionMetadata.js').ApplicationRoleConnectionMetadata;\nexports.Attachment = require('./structures/Attachment.js').Attachment;\nexports.AutocompleteInteraction = require('./structures/AutocompleteInteraction.js').AutocompleteInteraction;\nexports.AutoModerationActionExecution =\n  require('./structures/AutoModerationActionExecution.js').AutoModerationActionExecution;\nexports.AutoModerationRule = require('./structures/AutoModerationRule.js').AutoModerationRule;\nexports.Base = require('./structures/Base.js').Base;\nexports.BaseChannel = require('./structures/BaseChannel.js').BaseChannel;\nexports.BaseGuild = require('./structures/BaseGuild.js').BaseGuild;\nexports.BaseGuildEmoji = require('./structures/BaseGuildEmoji.js').BaseGuildEmoji;\nexports.BaseGuildTextChannel = require('./structures/BaseGuildTextChannel.js').BaseGuildTextChannel;\nexports.BaseGuildVoiceChannel = require('./structures/BaseGuildVoiceChannel.js').BaseGuildVoiceChannel;\nexports.BaseInteraction = require('./structures/BaseInteraction.js').BaseInteraction;\nexports.BaseInvite = require('./structures/BaseInvite.js').BaseInvite;\nexports.BaseSelectMenuComponent = require('./structures/BaseSelectMenuComponent.js').BaseSelectMenuComponent;\nexports.ButtonComponent = require('./structures/ButtonComponent.js').ButtonComponent;\nexports.ButtonInteraction = require('./structures/ButtonInteraction.js').ButtonInteraction;\nexports.CategoryChannel = require('./structures/CategoryChannel.js').CategoryChannel;\nexports.ChannelSelectMenuComponent = require('./structures/ChannelSelectMenuComponent.js').ChannelSelectMenuComponent;\nexports.ChannelSelectMenuInteraction =\n  require('./structures/ChannelSelectMenuInteraction.js').ChannelSelectMenuInteraction;\nexports.ChatInputCommandInteraction =\n  require('./structures/ChatInputCommandInteraction.js').ChatInputCommandInteraction;\nexports.ClientApplication = require('./structures/ClientApplication.js').ClientApplication;\nexports.ClientPresence = require('./structures/ClientPresence.js').ClientPresence;\nexports.ClientUser = require('./structures/ClientUser.js').ClientUser;\nexports.Collector = require('./structures/interfaces/Collector.js').Collector;\nexports.CommandInteraction = require('./structures/CommandInteraction.js').CommandInteraction;\nexports.CommandInteractionOptionResolver =\n  require('./structures/CommandInteractionOptionResolver.js').CommandInteractionOptionResolver;\nexports.Component = require('./structures/Component.js').Component;\nexports.ContainerComponent = require('./structures/ContainerComponent.js').ContainerComponent;\nexports.ContextMenuCommandInteraction =\n  require('./structures/ContextMenuCommandInteraction.js').ContextMenuCommandInteraction;\nexports.DirectoryChannel = require('./structures/DirectoryChannel.js').DirectoryChannel;\nexports.DMChannel = require('./structures/DMChannel.js').DMChannel;\nexports.Embed = require('./structures/Embed.js').Embed;\nexports.Emoji = require('./structures/Emoji.js').Emoji;\nexports.Entitlement = require('./structures/Entitlement.js').Entitlement;\nexports.FileComponent = require('./structures/FileComponent.js').FileComponent;\nexports.ForumChannel = require('./structures/ForumChannel.js').ForumChannel;\nexports.GroupDMInvite = require('./structures/GroupDMInvite.js').GroupDMInvite;\nexports.Guild = require('./structures/Guild.js').Guild;\nexports.GuildAuditLogs = require('./structures/GuildAuditLogs.js').GuildAuditLogs;\nexports.GuildAuditLogsEntry = require('./structures/GuildAuditLogsEntry.js').GuildAuditLogsEntry;\nexports.GuildBan = require('./structures/GuildBan.js').GuildBan;\nexports.GuildChannel = require('./structures/GuildChannel.js').GuildChannel;\nexports.GuildEmoji = require('./structures/GuildEmoji.js').GuildEmoji;\nexports.GuildInvite = require('./structures/GuildInvite.js').GuildInvite;\nexports.GuildMember = require('./structures/GuildMember.js').GuildMember;\nexports.GuildOnboarding = require('./structures/GuildOnboarding.js').GuildOnboarding;\nexports.GuildOnboardingPrompt = require('./structures/GuildOnboardingPrompt.js').GuildOnboardingPrompt;\nexports.GuildOnboardingPromptOption =\n  require('./structures/GuildOnboardingPromptOption.js').GuildOnboardingPromptOption;\nexports.GuildPreview = require('./structures/GuildPreview.js').GuildPreview;\nexports.GuildPreviewEmoji = require('./structures/GuildPreviewEmoji.js').GuildPreviewEmoji;\nexports.GuildScheduledEvent = require('./structures/GuildScheduledEvent.js').GuildScheduledEvent;\nexports.GuildTemplate = require('./structures/GuildTemplate.js').GuildTemplate;\nexports.Integration = require('./structures/Integration.js').Integration;\nexports.IntegrationApplication = require('./structures/IntegrationApplication.js').IntegrationApplication;\nexports.InteractionCallback = require('./structures/InteractionCallback.js').InteractionCallback;\nexports.InteractionCallbackResource =\n  require('./structures/InteractionCallbackResource.js').InteractionCallbackResource;\nexports.InteractionCallbackResponse =\n  require('./structures/InteractionCallbackResponse.js').InteractionCallbackResponse;\nexports.InteractionCollector = require('./structures/InteractionCollector.js').InteractionCollector;\nexports.InteractionWebhook = require('./structures/InteractionWebhook.js').InteractionWebhook;\nexports.InviteGuild = require('./structures/InviteGuild.js').InviteGuild;\nexports.LabelComponent = require('./structures/LabelComponent.js').LabelComponent;\nexports.MediaChannel = require('./structures/MediaChannel.js').MediaChannel;\nexports.MediaGalleryComponent = require('./structures/MediaGalleryComponent.js').MediaGalleryComponent;\nexports.MediaGalleryItem = require('./structures/MediaGalleryItem.js').MediaGalleryItem;\nexports.MentionableSelectMenuComponent =\n  require('./structures/MentionableSelectMenuComponent.js').MentionableSelectMenuComponent;\nexports.MentionableSelectMenuInteraction =\n  require('./structures/MentionableSelectMenuInteraction.js').MentionableSelectMenuInteraction;\nexports.MentionableSelectMenuInteraction =\n  require('./structures/MentionableSelectMenuInteraction.js').MentionableSelectMenuInteraction;\nexports.Message = require('./structures/Message.js').Message;\nexports.MessageCollector = require('./structures/MessageCollector.js').MessageCollector;\nexports.MessageComponentInteraction =\n  require('./structures/MessageComponentInteraction.js').MessageComponentInteraction;\nexports.MessageContextMenuCommandInteraction =\n  require('./structures/MessageContextMenuCommandInteraction.js').MessageContextMenuCommandInteraction;\nexports.MessageMentions = require('./structures/MessageMentions.js').MessageMentions;\nexports.MessagePayload = require('./structures/MessagePayload.js').MessagePayload;\nexports.MessageReaction = require('./structures/MessageReaction.js').MessageReaction;\nexports.ModalComponentResolver = require('./structures/ModalComponentResolver.js').ModalComponentResolver;\nexports.ModalSubmitInteraction = require('./structures/ModalSubmitInteraction.js').ModalSubmitInteraction;\nexports.OAuth2Guild = require('./structures/OAuth2Guild.js').OAuth2Guild;\nexports.PartialGroupDMChannel = require('./structures/PartialGroupDMChannel.js').PartialGroupDMChannel;\nexports.PermissionOverwrites = require('./structures/PermissionOverwrites.js').PermissionOverwrites;\nexports.Poll = require('./structures/Poll.js').Poll;\nexports.PollAnswer = require('./structures/PollAnswer.js').PollAnswer;\nexports.PrimaryEntryPointCommandInteraction =\n  require('./structures/PrimaryEntryPointCommandInteraction.js').PrimaryEntryPointCommandInteraction;\nexports.Presence = require('./structures/Presence.js').Presence;\nexports.ReactionCollector = require('./structures/ReactionCollector.js').ReactionCollector;\nexports.ReactionEmoji = require('./structures/ReactionEmoji.js').ReactionEmoji;\nexports.RichPresenceAssets = require('./structures/Presence.js').RichPresenceAssets;\nexports.Role = require('./structures/Role.js').Role;\nexports.RoleSelectMenuComponent = require('./structures/RoleSelectMenuComponent.js').RoleSelectMenuComponent;\nexports.RoleSelectMenuInteraction = require('./structures/RoleSelectMenuInteraction.js').RoleSelectMenuInteraction;\nexports.SectionComponent = require('./structures/SectionComponent.js').SectionComponent;\nexports.SeparatorComponent = require('./structures/SeparatorComponent.js').SeparatorComponent;\nexports.SKU = require('./structures/SKU.js').SKU;\nexports.SoundboardSound = require('./structures/SoundboardSound.js').SoundboardSound;\nexports.StageChannel = require('./structures/StageChannel.js').StageChannel;\nexports.StageInstance = require('./structures/StageInstance.js').StageInstance;\nexports.Sticker = require('./structures/Sticker.js').Sticker;\nexports.StickerPack = require('./structures/StickerPack.js').StickerPack;\nexports.StringSelectMenuComponent = require('./structures/StringSelectMenuComponent.js').StringSelectMenuComponent;\nexports.StringSelectMenuInteraction =\n  require('./structures/StringSelectMenuInteraction.js').StringSelectMenuInteraction;\nexports.Subscription = require('./structures/Subscription.js').Subscription;\nexports.Team = require('./structures/Team.js').Team;\nexports.TeamMember = require('./structures/TeamMember.js').TeamMember;\nexports.TextChannel = require('./structures/TextChannel.js').TextChannel;\nexports.TextDisplayComponent = require('./structures/TextDisplayComponent.js').TextDisplayComponent;\nexports.TextInputComponent = require('./structures/TextInputComponent.js').TextInputComponent;\nexports.ThreadChannel = require('./structures/ThreadChannel.js').ThreadChannel;\nexports.ThreadMember = require('./structures/ThreadMember.js').ThreadMember;\nexports.ThreadOnlyChannel = require('./structures/ThreadOnlyChannel.js').ThreadOnlyChannel;\nexports.ThumbnailComponent = require('./structures/ThumbnailComponent.js').ThumbnailComponent;\nexports.Typing = require('./structures/Typing.js').Typing;\nexports.UnfurledMediaItem = require('./structures/UnfurledMediaItem.js').UnfurledMediaItem;\nexports.User = require('./structures/User.js').User;\nexports.UserContextMenuCommandInteraction =\n  require('./structures/UserContextMenuCommandInteraction.js').UserContextMenuCommandInteraction;\nexports.UserSelectMenuComponent = require('./structures/UserSelectMenuComponent.js').UserSelectMenuComponent;\nexports.UserSelectMenuInteraction = require('./structures/UserSelectMenuInteraction.js').UserSelectMenuInteraction;\nexports.VoiceChannel = require('./structures/VoiceChannel.js').VoiceChannel;\nexports.VoiceChannelEffect = require('./structures/VoiceChannelEffect.js').VoiceChannelEffect;\nexports.VoiceRegion = require('./structures/VoiceRegion.js').VoiceRegion;\nexports.VoiceState = require('./structures/VoiceState.js').VoiceState;\nexports.Webhook = require('./structures/Webhook.js').Webhook;\nexports.WelcomeChannel = require('./structures/WelcomeChannel.js').WelcomeChannel;\nexports.WelcomeScreen = require('./structures/WelcomeScreen.js').WelcomeScreen;\nexports.Widget = require('./structures/Widget.js').Widget;\nexports.WidgetMember = require('./structures/WidgetMember.js').WidgetMember;\n\n// External\n__exportStar(require('discord-api-types/v10'), exports);\n__exportStar(require('@discordjs/rest'), exports);\n__exportStar(require('@discordjs/util'), exports);\n__exportStar(require('@discordjs/ws'), exports);\n"
  },
  {
    "path": "packages/discord.js/src/managers/ApplicationCommandManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { isJSONEncodable } = require('@discordjs/util');\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { ApplicationCommand } = require('../structures/ApplicationCommand.js');\nconst { PermissionsBitField } = require('../util/PermissionsBitField.js');\nconst { ApplicationCommandPermissionsManager } = require('./ApplicationCommandPermissionsManager.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for application commands and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass ApplicationCommandManager extends CachedManager {\n  constructor(client, iterable) {\n    super(client, ApplicationCommand, iterable);\n\n    /**\n     * The manager for permissions of arbitrary commands on arbitrary guilds\n     *\n     * @type {ApplicationCommandPermissionsManager}\n     */\n    this.permissions = new ApplicationCommandPermissionsManager(this);\n  }\n\n  /**\n   * The cache of this manager\n   *\n   * @type {Collection<Snowflake, ApplicationCommand>}\n   * @name ApplicationCommandManager#cache\n   */\n\n  _add(data, cache, guildId) {\n    return super._add(data, cache, { extras: [this.guild, guildId] });\n  }\n\n  /**\n   * The APIRouter path to the commands\n   *\n   * @param {Object} [options] The options\n   * @param {Snowflake} [options.id] The application command's id\n   * @param {Snowflake} [options.guildId] The guild's id to use in the path,\n   * ignored when using a {@link GuildApplicationCommandManager}\n   * @returns {string}\n   * @private\n   */\n  commandPath({ id, guildId } = {}) {\n    if (this.guild ?? guildId) {\n      if (id) {\n        return Routes.applicationGuildCommand(this.client.application.id, this.guild?.id ?? guildId, id);\n      }\n\n      return Routes.applicationGuildCommands(this.client.application.id, this.guild?.id ?? guildId);\n    }\n\n    if (id) {\n      return Routes.applicationCommand(this.client.application.id, id);\n    }\n\n    return Routes.applicationCommands(this.client.application.id);\n  }\n\n  /**\n   * Data that resolves to give an ApplicationCommand object. This can be:\n   * - An ApplicationCommand object\n   * - A Snowflake\n   *\n   * @typedef {ApplicationCommand|Snowflake} ApplicationCommandResolvable\n   */\n\n  /**\n   * Data that resolves to the data of an ApplicationCommand\n   *\n   * @typedef {ApplicationCommandData|APIApplicationCommand} ApplicationCommandDataResolvable\n   */\n\n  /**\n   * Options used to fetch data from Discord\n   *\n   * @typedef {Object} BaseFetchOptions\n   * @property {boolean} [cache=true] Whether to cache the fetched data if it wasn't already\n   * @property {boolean} [force=false] Whether to skip the cache check and request the API\n   */\n\n  /**\n   * Options used to fetch Application Commands from Discord\n   *\n   * @typedef {BaseFetchOptions} FetchApplicationCommandOptions\n   * @property {Snowflake} [id] The command's id to fetch\n   * @property {Snowflake} [guildId] The guild's id to fetch commands for, for when the guild is not cached\n   * @property {Locale} [locale] The locale to use when fetching this command\n   * @property {boolean} [withLocalizations] Whether to fetch all localization data\n   */\n\n  /**\n   * Obtains one or multiple application commands from Discord, or the cache if it's already available.\n   *\n   * @param {Snowflake|FetchApplicationCommandOptions} [options] Options for fetching application command(s)\n   * @returns {Promise<ApplicationCommand|Collection<Snowflake, ApplicationCommand>>}\n   * @example\n   * // Fetch a single command\n   * client.application.commands.fetch('123456789012345678')\n   *   .then(command => console.log(`Fetched command ${command.name}`))\n   *   .catch(console.error);\n   * @example\n   * // Fetch all commands\n   * client.application.commands.fetch()\n   *   .then(commands => console.log(`Fetched ${commands.size} commands`))\n   *   .catch(console.error);\n   * @example\n   * // Fetch all commands in a guild\n   * guild.commands.fetch()\n   *   .then(commands => console.log(`Fetched ${commands.size} commands`))\n   *   .catch(console.error);\n   * @example\n   * // Fetch a single command without checking cache\n   * guild.commands.fetch({ id: '123456789012345678', force: true })\n   *   .then(command => console.log(`Fetched command ${command.name}`))\n   *   .catch(console.error)\n   */\n  async fetch(options) {\n    if (!options) return this._fetchMany();\n\n    if (typeof options === 'string') return this._fetchSingle({ id: options });\n\n    const { cache, force, guildId, id, locale, withLocalizations } = options;\n\n    if (id) return this._fetchSingle({ cache, force, guildId, id });\n\n    return this._fetchMany({ cache, guildId, locale, withLocalizations });\n  }\n\n  async _fetchSingle({ cache, force = false, guildId, id }) {\n    if (!force) {\n      const existing = this.cache.get(id);\n      if (existing) return existing;\n    }\n\n    const command = await this.client.rest.get(this.commandPath({ id, guildId }));\n    return this._add(command, cache);\n  }\n\n  async _fetchMany({ cache, guildId, locale, withLocalizations } = {}) {\n    const data = await this.client.rest.get(this.commandPath({ guildId }), {\n      headers: {\n        'X-Discord-Locale': locale,\n      },\n      query: makeURLSearchParams({ with_localizations: withLocalizations }),\n    });\n\n    return data.reduce((coll, command) => coll.set(command.id, this._add(command, cache, guildId)), new Collection());\n  }\n\n  /**\n   * Creates an application command.\n   *\n   * @param {ApplicationCommandDataResolvable} command The command\n   * @param {Snowflake} [guildId] The guild's id to create this command in,\n   * ignored when using a {@link GuildApplicationCommandManager}\n   * @returns {Promise<ApplicationCommand>}\n   * @example\n   * // Create a new command\n   * client.application.commands.create({\n   *   name: 'test',\n   *   description: 'A test command',\n   * })\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async create(command, guildId) {\n    const data = await this.client.rest.post(this.commandPath({ guildId }), {\n      body: this.constructor.transformCommand(command),\n    });\n    return this._add(data, true, guildId);\n  }\n\n  /**\n   * Sets all the commands for this application or guild.\n   *\n   * @param {ApplicationCommandDataResolvable[]} commands The commands\n   * @param {Snowflake} [guildId] The guild's id to create the commands in,\n   * ignored when using a {@link GuildApplicationCommandManager}\n   * @returns {Promise<Collection<Snowflake, ApplicationCommand>>}\n   * @example\n   * // Set all commands to just this one\n   * client.application.commands.set([\n   *   {\n   *     name: 'test',\n   *     description: 'A test command',\n   *   },\n   * ])\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Remove all commands\n   * guild.commands.set([])\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async set(commands, guildId) {\n    const data = await this.client.rest.put(this.commandPath({ guildId }), {\n      body: commands.map(command => this.constructor.transformCommand(command)),\n    });\n    return data.reduce(\n      (collection, command) => collection.set(command.id, this._add(command, true, guildId)),\n      new Collection(),\n    );\n  }\n\n  /**\n   * Edits an application command.\n   *\n   * @param {ApplicationCommandResolvable} command The command to edit\n   * @param {Partial<ApplicationCommandDataResolvable>} data The data to update the command with\n   * @param {Snowflake} [guildId] The guild's id where the command registered,\n   * ignored when using a {@link GuildApplicationCommandManager}\n   * @returns {Promise<ApplicationCommand>}\n   * @example\n   * // Edit an existing command\n   * client.application.commands.edit('123456789012345678', {\n   *   description: 'New description',\n   * })\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async edit(command, data, guildId) {\n    const id = this.resolveId(command);\n    if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'command', 'ApplicationCommandResolvable');\n\n    const patched = await this.client.rest.patch(this.commandPath({ id, guildId }), {\n      body: this.constructor.transformCommand(data),\n    });\n    return this._add(patched, true, guildId);\n  }\n\n  /**\n   * Deletes an application command.\n   *\n   * @param {ApplicationCommandResolvable} command The command to delete\n   * @param {Snowflake} [guildId] The guild's id where the command is registered,\n   * ignored when using a {@link GuildApplicationCommandManager}\n   * @returns {Promise<?ApplicationCommand>}\n   * @example\n   * // Delete a command\n   * guild.commands.delete('123456789012345678')\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async delete(command, guildId) {\n    const id = this.resolveId(command);\n    if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'command', 'ApplicationCommandResolvable');\n\n    await this.client.rest.delete(this.commandPath({ id, guildId }));\n\n    const cached = this.cache.get(id);\n    this.cache.delete(id);\n    return cached ?? null;\n  }\n\n  /**\n   * Transforms an {@link ApplicationCommandData} object into something that can be used with the API.\n   *\n   * @param {ApplicationCommandDataResolvable} command The command to transform\n   * @returns {APIApplicationCommand}\n   * @private\n   */\n  static transformCommand(command) {\n    if (isJSONEncodable(command)) return command.toJSON();\n\n    let default_member_permissions;\n\n    if ('default_member_permissions' in command) {\n      default_member_permissions = command.default_member_permissions\n        ? new PermissionsBitField(BigInt(command.default_member_permissions)).bitfield.toString()\n        : command.default_member_permissions;\n    }\n\n    if ('defaultMemberPermissions' in command) {\n      default_member_permissions =\n        command.defaultMemberPermissions === null\n          ? command.defaultMemberPermissions\n          : new PermissionsBitField(command.defaultMemberPermissions).bitfield.toString();\n    }\n\n    return {\n      name: command.name,\n      name_localizations: command.nameLocalizations ?? command.name_localizations,\n      description: command.description,\n      nsfw: command.nsfw,\n      description_localizations: command.descriptionLocalizations ?? command.description_localizations,\n      type: command.type,\n      options: command.options?.map(option => ApplicationCommand.transformOption(option)),\n      default_member_permissions,\n      integration_types: command.integrationTypes ?? command.integration_types,\n      contexts: command.contexts,\n      handler: command.handler,\n    };\n  }\n}\n\nexports.ApplicationCommandManager = ApplicationCommandManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/ApplicationCommandPermissionsManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { ApplicationCommandPermissionType, RESTJSONErrorCodes, Routes } = require('discord-api-types/v10');\nconst { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { BaseManager } = require('./BaseManager.js');\n\n/**\n * Manages API methods for permissions of Application Commands.\n *\n * @extends {BaseManager}\n */\nclass ApplicationCommandPermissionsManager extends BaseManager {\n  constructor(manager) {\n    super(manager.client);\n\n    /**\n     * The manager or command that this manager belongs to\n     *\n     * @type {ApplicationCommandManager|ApplicationCommand}\n     * @private\n     */\n    this.manager = manager;\n\n    /**\n     * The guild that this manager acts on\n     *\n     * @type {?Guild}\n     */\n    this.guild = manager.guild ?? null;\n\n    /**\n     * The id of the guild that this manager acts on\n     *\n     * @type {?Snowflake}\n     */\n    this.guildId = manager.guildId ?? manager.guild?.id ?? null;\n\n    /**\n     * The id of the command this manager acts on\n     *\n     * @type {?Snowflake}\n     */\n    this.commandId = manager.id ?? null;\n  }\n\n  /**\n   * The APIRouter path to the commands\n   *\n   * @param {Snowflake} guildId The guild's id to use in the path,\n   * @param {Snowflake} [commandId] The application command's id\n   * @returns {string}\n   * @private\n   */\n  permissionsPath(guildId, commandId) {\n    if (commandId) {\n      return Routes.applicationCommandPermissions(this.client.application.id, guildId, commandId);\n    }\n\n    return Routes.guildApplicationCommandsPermissions(this.client.application.id, guildId);\n  }\n\n  /**\n   * The object returned when fetching permissions for an application command.\n   *\n   * @typedef {Object} ApplicationCommandPermissions\n   * @property {Snowflake} id The role, user, or channel's id. Can also be a\n   * {@link https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permissions-constants permission constant}.\n   * @property {ApplicationCommandPermissionType} type Whether this permission is for a role or a user\n   * @property {boolean} permission Whether the role or user has the permission to use this command\n   */\n\n  /**\n   * Options for managing permissions for one or more Application Commands\n   * <warn>When passing these options to a manager where `guildId` is `null`,\n   * `guild` is a required parameter</warn>\n   *\n   * @typedef {Object} BaseApplicationCommandPermissionsOptions\n   * @property {GuildResolvable} [guild] The guild to modify / check permissions for\n   * <warn>Ignored when the manager has a non-null `guildId` property</warn>\n   * @property {ApplicationCommandResolvable} [command] The command to modify / check permissions for\n   * <warn>Ignored when the manager has a non-null `commandId` property</warn>\n   */\n\n  /**\n   * Fetches the permissions for one or multiple commands. Providing the client's id as the \"command id\" will fetch\n   * _only_ the guild level permissions\n   *\n   * @param {BaseApplicationCommandPermissionsOptions} [options] Options used to fetch permissions\n   * @returns {Promise<ApplicationCommandPermissions[]|Collection<Snowflake, ApplicationCommandPermissions[]>>}\n   * @example\n   * // Fetch permissions for one command\n   * guild.commands.permissions.fetch({ command: '123456789012345678' })\n   *   .then(perms => console.log(`Fetched ${perms.length} overwrites`))\n   *   .catch(console.error);\n   * @example\n   * // Fetch permissions for all commands in a guild\n   * client.application.commands.permissions.fetch({ guild: '123456789012345678' })\n   *   .then(perms => console.log(`Fetched permissions for ${perms.size} commands`))\n   *   .catch(console.error);\n   * @example\n   * // Fetch guild level permissions\n   * guild.commands.permissions.fetch({ command: client.user.id })\n   *   .then(perms => console.log(`Fetched ${perms.length} guild level permissions`))\n   *   .catch(console.error);\n   */\n  async fetch({ guild, command } = {}) {\n    const { guildId, commandId } = this._validateOptions(guild, command);\n    if (commandId) {\n      const innerData = await this.client.rest.get(this.permissionsPath(guildId, commandId));\n      return innerData.permissions;\n    }\n\n    const data = await this.client.rest.get(this.permissionsPath(guildId));\n    return data.reduce((coll, perm) => coll.set(perm.id, perm.permissions), new Collection());\n  }\n\n  /**\n   * Options used to set permissions for one or more Application Commands in a guild\n   * <warn>Omitting the `command` parameter edits the guild wide permissions\n   * when the manager's `commandId` is `null`</warn>\n   *\n   * @typedef {BaseApplicationCommandPermissionsOptions} ApplicationCommandPermissionsEditOptions\n   * @property {ApplicationCommandPermissions[]} permissions The new permissions for the guild or overwrite\n   * @property {string} token The bearer token to use that authorizes the permission edit\n   */\n\n  /**\n   * Sets the permissions for the guild or a command overwrite.\n   *\n   * @param {ApplicationCommandPermissionsEditOptions} options Options used to set permissions\n   * @returns {Promise<ApplicationCommandPermissions[]|Collection<Snowflake, ApplicationCommandPermissions[]>>}\n   * @example\n   * // Set a permission overwrite for a command\n   * client.application.commands.permissions.set({\n   *  guild: '892455839386304532',\n   *  command: '123456789012345678',\n   *  token: 'TotallyRealToken',\n   *  permissions: [\n   *    {\n   *      id: '876543210987654321',\n   *      type: ApplicationCommandPermissionType.User,\n   *      permission: false,\n   *    },\n   * ]})\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Set the permissions used for the guild (commands without overwrites)\n   * guild.commands.permissions.set({ token: 'TotallyRealToken', permissions: [\n   *   {\n   *     id: '123456789012345678',\n   *     permissions: [{\n   *       id: '876543210987654321',\n   *       type: ApplicationCommandPermissionType.User,\n   *       permission: false,\n   *     }],\n   *   },\n   * ]})\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async set({ guild, command, permissions, token } = {}) {\n    if (!token) {\n      throw new DiscordjsError(ErrorCodes.ApplicationCommandPermissionsTokenMissing);\n    }\n\n    const options = this._validateOptions(guild, command);\n    let { commandId } = options;\n\n    if (!Array.isArray(permissions)) {\n      throw new DiscordjsTypeError(\n        ErrorCodes.InvalidType,\n        'permissions',\n        'Array of ApplicationCommandPermissions',\n        true,\n      );\n    }\n\n    commandId ??= this.client.user.id;\n\n    const data = await this.client.rest.put(this.permissionsPath(options.guildId, commandId), {\n      body: { permissions },\n      auth: false,\n      headers: { Authorization: `Bearer ${token}` },\n    });\n    return data.permissions;\n  }\n\n  /**\n   * Add permissions to a command.\n   *\n   * @param {ApplicationCommandPermissionsEditOptions} options Options used to add permissions\n   * @returns {Promise<ApplicationCommandPermissions[]>}\n   * @example\n   * // Add a rule to block a role from using a command\n   * guild.commands.permissions.add({ command: '123456789012345678', token: 'TotallyRealToken', permissions: [\n   *   {\n   *     id: '876543211234567890',\n   *     type: ApplicationCommandPermissionType.Role,\n   *     permission: false\n   *   },\n   * ]})\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async add({ guild, command, permissions, token } = {}) {\n    if (!token) {\n      throw new DiscordjsError(ErrorCodes.ApplicationCommandPermissionsTokenMissing);\n    }\n\n    const options = this._validateOptions(guild, command);\n    let { commandId } = options;\n    commandId ??= this.client.user.id;\n\n    if (!Array.isArray(permissions)) {\n      throw new DiscordjsTypeError(\n        ErrorCodes.InvalidType,\n        'permissions',\n        'Array of ApplicationCommandPermissions',\n        true,\n      );\n    }\n\n    let existingPermissions = [];\n    try {\n      existingPermissions = await this.fetch({ guild: options.guildId, command: commandId });\n    } catch (error) {\n      if (error.code !== RESTJSONErrorCodes.UnknownApplicationCommandPermissions) throw error;\n    }\n\n    const newPermissions = permissions.slice();\n    for (const existingPermission of existingPermissions) {\n      if (!newPermissions.some(newPermission => newPermission.id === existingPermission.id)) {\n        newPermissions.push(existingPermission);\n      }\n    }\n\n    return this.set({ guild: options.guildId, command: commandId, permissions: newPermissions, token });\n  }\n\n  /**\n   * A static snowflake that identifies the everyone role for application command permissions.\n   * It is the same as the guild id\n   *\n   * @typedef {Snowflake} RolePermissionConstant\n   */\n\n  /**\n   * A static snowflake that identifies the \"all channels\" entity for application command permissions.\n   * It will be the result of the calculation `guildId - 1`\n   *\n   * @typedef {Snowflake} ChannelPermissionConstant\n   */\n\n  /**\n   * Options used to remove permissions from a command\n   * <warn>Omitting the `command` parameter removes from the guild wide permissions\n   * when the managers `commandId` is `null`</warn>\n   * <warn>At least one of `users`, `roles`, and `channels` is required</warn>\n   *\n   * @typedef {BaseApplicationCommandPermissionsOptions} RemoveApplicationCommandPermissionsOptions\n   * @property {string} token The bearer token to use that authorizes the permission removal\n   * @property {UserResolvable[]} [users] The user(s) to remove\n   * @property {Array<RoleResolvable|RolePermissionConstant>} [roles] The role(s) to remove\n   * @property {Array<GuildChannelResolvable|ChannelPermissionConstant>} [channels] The channel(s) to remove\n   */\n\n  /**\n   * Remove permissions from a command.\n   *\n   * @param {RemoveApplicationCommandPermissionsOptions} options Options used to remove permissions\n   * @returns {Promise<ApplicationCommandPermissions[]>}\n   * @example\n   * // Remove a user permission from this command\n   * guild.commands.permissions.remove({\n   *  command: '123456789012345678', users: '876543210123456789', token: 'TotallyRealToken',\n   * })\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Remove multiple roles from this command\n   * guild.commands.permissions.remove({\n   *   command: '123456789012345678', roles: ['876543210123456789', '765432101234567890'], token: 'TotallyRealToken',\n   * })\n   *    .then(console.log)\n   *    .catch(console.error);\n   */\n  async remove({ guild, command, users, roles, channels, token } = {}) {\n    if (!token) {\n      throw new DiscordjsError(ErrorCodes.ApplicationCommandPermissionsTokenMissing);\n    }\n\n    const options = this._validateOptions(guild, command);\n    let { commandId } = options;\n    commandId ??= this.client.user.id;\n\n    if (!users && !roles && !channels) {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'users OR roles OR channels', 'Array or Resolvable', true);\n    }\n\n    const resolvedUserIds = [];\n    if (Array.isArray(users)) {\n      for (const user of users) {\n        const userId = this.client.users.resolveId(user);\n        if (!userId) throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array', 'users', user);\n        resolvedUserIds.push(userId);\n      }\n    }\n\n    const resolvedRoleIds = [];\n    if (Array.isArray(roles)) {\n      for (const role of roles) {\n        if (typeof role === 'string') {\n          resolvedRoleIds.push(role);\n          continue;\n        }\n\n        if (!this.guild) throw new DiscordjsError(ErrorCodes.GuildUncachedEntityResolve, 'roles');\n        const roleId = this.guild.roles.resolveId(role);\n        if (!roleId) throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array', 'users', role);\n        resolvedRoleIds.push(roleId);\n      }\n    }\n\n    const resolvedChannelIds = [];\n    if (Array.isArray(channels)) {\n      for (const channel of channels) {\n        if (typeof channel === 'string') {\n          resolvedChannelIds.push(channel);\n          continue;\n        }\n\n        if (!this.guild) throw new DiscordjsError(ErrorCodes.GuildUncachedEntityResolve, 'channels');\n        const channelId = this.guild.channels.resolveId(channel);\n        if (!channelId) throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array', 'channels', channel);\n        resolvedChannelIds.push(channelId);\n      }\n    }\n\n    let existing = [];\n    try {\n      existing = await this.fetch({ guild: options.guildId, command: commandId });\n    } catch (error) {\n      if (error.code !== RESTJSONErrorCodes.UnknownApplicationCommandPermissions) throw error;\n    }\n\n    const permissions = existing.filter(perm => {\n      switch (perm.type) {\n        case ApplicationCommandPermissionType.Role:\n          return !resolvedRoleIds.includes(perm.id);\n        case ApplicationCommandPermissionType.User:\n          return !resolvedUserIds.includes(perm.id);\n        case ApplicationCommandPermissionType.Channel:\n          return !resolvedChannelIds.includes(perm.id);\n        default:\n          return true;\n      }\n    });\n\n    return this.set({ guild: options.guildId, command: commandId, permissions, token });\n  }\n\n  /**\n   * Options used to check the existence of permissions on a command\n   * <warn>The `command` parameter is not optional when the managers `commandId` is `null`</warn>\n   *\n   * @typedef {BaseApplicationCommandPermissionsOptions} HasApplicationCommandPermissionsOptions\n   * @property {ApplicationCommandPermissionIdResolvable} permissionId The entity to check if a permission exists for\n   * on this command.\n   * @property {ApplicationCommandPermissionType} [permissionType] Check for a specific type of permission\n   */\n\n  /**\n   * Check whether a permission exists for a user, role, or channel\n   *\n   * @param {HasApplicationCommandPermissionsOptions} options Options used to check permissions\n   * @returns {Promise<boolean>}\n   * @example\n   * guild.commands.permissions.has({ command: '123456789012345678', permissionId: '876543210123456789' })\n   *  .then(console.log)\n   *  .catch(console.error);\n   */\n  async has({ guild, command, permissionId, permissionType }) {\n    const { guildId, commandId } = this._validateOptions(guild, command);\n    if (!commandId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'command', 'ApplicationCommandResolvable');\n\n    if (!permissionId) {\n      throw new DiscordjsTypeError(\n        ErrorCodes.InvalidType,\n        'permissionId',\n        'UserResolvable, RoleResolvable, ChannelResolvable, or Permission Constant',\n      );\n    }\n\n    let resolvedId = permissionId;\n    if (typeof permissionId !== 'string') {\n      resolvedId = this.client.users.resolveId(permissionId);\n      if (!resolvedId) {\n        if (!this.guild) throw new DiscordjsError(ErrorCodes.GuildUncachedEntityResolve, 'roles');\n        resolvedId = this.guild.roles.resolveId(permissionId);\n      }\n\n      resolvedId ??= this.guild.channels.resolveId(permissionId);\n\n      if (!resolvedId) {\n        throw new DiscordjsTypeError(\n          ErrorCodes.InvalidType,\n          'permissionId',\n          'UserResolvable, RoleResolvable, ChannelResolvable, or Permission Constant',\n        );\n      }\n    }\n\n    let existing = [];\n    try {\n      existing = await this.fetch({ guild: guildId, command: commandId });\n    } catch (error) {\n      if (error.code !== RESTJSONErrorCodes.UnknownApplicationCommandPermissions) throw error;\n    }\n\n    // Check permission type if provided for the single edge case where a channel id is the same as the everyone role id\n    return existing.some(perm => perm.id === resolvedId && (permissionType ?? perm.type) === perm.type);\n  }\n\n  _validateOptions(guild, command) {\n    const guildId = this.guildId ?? this.client.guilds.resolveId(guild);\n    if (!guildId) throw new DiscordjsError(ErrorCodes.GlobalCommandPermissions);\n    let commandId = this.commandId;\n    if (command && !commandId) {\n      commandId = this.manager.resolveId?.(command);\n      if (!commandId && this.guild) {\n        commandId = this.guild.commands.resolveId(command);\n      }\n\n      commandId ??= this.client.application?.commands.resolveId(command);\n      if (!commandId) {\n        throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'command', 'ApplicationCommandResolvable', true);\n      }\n    }\n\n    return { guildId, commandId };\n  }\n}\n\nexports.ApplicationCommandPermissionsManager = ApplicationCommandPermissionsManager;\n\n/**\n * Data that resolves to an id used for an application command permission\n *\n * @typedef {UserResolvable|RoleResolvable|GuildChannelResolvable|RolePermissionConstant|ChannelPermissionConstant} ApplicationCommandPermissionIdResolvable\n */\n"
  },
  {
    "path": "packages/discord.js/src/managers/ApplicationEmojiManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { ApplicationEmoji } = require('../structures/ApplicationEmoji.js');\nconst { resolveImage } = require('../util/DataResolver.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for ApplicationEmojis and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass ApplicationEmojiManager extends CachedManager {\n  constructor(application, iterable) {\n    super(application.client, ApplicationEmoji, iterable);\n\n    /**\n     * The application this manager belongs to\n     *\n     * @type {ClientApplication}\n     */\n    this.application = application;\n  }\n\n  _add(data, cache) {\n    return super._add(data, cache, { extras: [this.application] });\n  }\n\n  /**\n   * Options used for creating an emoji of the application\n   *\n   * @typedef {Object} ApplicationEmojiCreateOptions\n   * @property {BufferResolvable|Base64Resolvable} attachment The image for the emoji\n   * @property {string} name The name for the emoji\n   */\n\n  /**\n   * Creates a new custom emoji of the application.\n   *\n   * @param {ApplicationEmojiCreateOptions} options Options for creating the emoji\n   * @returns {Promise<Emoji>} The created emoji\n   * @example\n   * // Create a new emoji from a URL\n   * application.emojis.create({ attachment: 'https://i.imgur.com/w3duR07.png', name: 'rip' })\n   *   .then(emoji => console.log(`Created new emoji with name ${emoji.name}!`))\n   *   .catch(console.error);\n   * @example\n   * // Create a new emoji from a file on your computer\n   * application.emojis.create({ attachment: './memes/banana.png', name: 'banana' })\n   *   .then(emoji => console.log(`Created new emoji with name ${emoji.name}!`))\n   *   .catch(console.error);\n   */\n  async create({ attachment, name }) {\n    const image = await resolveImage(attachment);\n    if (!image) throw new DiscordjsTypeError(ErrorCodes.ReqResourceType);\n\n    const body = { image, name };\n\n    const emoji = await this.client.rest.post(Routes.applicationEmojis(this.application.id), { body });\n    return this._add(emoji);\n  }\n\n  /**\n   * Obtains one or more emojis from Discord, or the emoji cache if they're already available.\n   *\n   * @param {Snowflake} [id] The emoji's id\n   * @param {BaseFetchOptions} [options] Additional options for this fetch\n   * @returns {Promise<ApplicationEmoji|Collection<Snowflake, ApplicationEmoji>>}\n   * @example\n   * // Fetch all emojis from the application\n   * application.emojis.fetch()\n   *   .then(emojis => console.log(`There are ${emojis.size} emojis.`))\n   *   .catch(console.error);\n   * @example\n   * // Fetch a single emoji\n   * application.emojis.fetch('222078108977594368')\n   *   .then(emoji => console.log(`The emoji name is: ${emoji.name}`))\n   *   .catch(console.error);\n   */\n  async fetch(id, { cache = true, force = false } = {}) {\n    if (id) {\n      if (!force) {\n        const existing = this.cache.get(id);\n        if (existing) return existing;\n      }\n\n      const emoji = await this.client.rest.get(Routes.applicationEmoji(this.application.id, id));\n      return this._add(emoji, cache);\n    }\n\n    const { items: data } = await this.client.rest.get(Routes.applicationEmojis(this.application.id));\n    const emojis = new Collection();\n    for (const emoji of data) emojis.set(emoji.id, this._add(emoji, cache));\n    return emojis;\n  }\n\n  /**\n   * Deletes an emoji.\n   *\n   * @param {EmojiResolvable} emoji The Emoji resolvable to delete\n   * @returns {Promise<void>}\n   */\n  async delete(emoji) {\n    const id = this.resolveId(emoji);\n    if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'emoji', 'EmojiResolvable', true);\n    await this.client.rest.delete(Routes.applicationEmoji(this.application.id, id));\n  }\n\n  /**\n   * Edits an emoji.\n   *\n   * @param {EmojiResolvable} emoji The Emoji resolvable to edit\n   * @param {ApplicationEmojiEditOptions} options The options to provide\n   * @returns {Promise<ApplicationEmoji>}\n   */\n  async edit(emoji, options) {\n    const id = this.resolveId(emoji);\n    if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'emoji', 'EmojiResolvable', true);\n\n    const newData = await this.client.rest.patch(Routes.applicationEmoji(this.application.id, id), {\n      body: {\n        name: options.name,\n      },\n    });\n    const existing = this.cache.get(id);\n    if (existing) {\n      existing._patch(newData);\n      return existing;\n    }\n\n    return this._add(newData);\n  }\n\n  /**\n   * Fetches the author for this emoji\n   *\n   * @param {EmojiResolvable} emoji The emoji to fetch the author of\n   * @returns {Promise<User>}\n   */\n  async fetchAuthor(emoji) {\n    const id = this.resolveId(emoji);\n    if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'emoji', 'EmojiResolvable', true);\n\n    const data = await this.client.rest.get(Routes.applicationEmoji(this.application.id, id));\n\n    return this._add(data).author;\n  }\n}\n\nexports.ApplicationEmojiManager = ApplicationEmojiManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/AutoModerationRuleManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Routes } = require('discord-api-types/v10');\nconst { AutoModerationRule } = require('../structures/AutoModerationRule.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for auto moderation rules and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass AutoModerationRuleManager extends CachedManager {\n  constructor(guild, iterable) {\n    super(guild.client, AutoModerationRule, iterable);\n\n    /**\n     * The guild this manager belongs to.\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n  }\n\n  /**\n   * The cache of this manager\n   *\n   * @type {Collection<Snowflake, AutoModerationRule>}\n   * @name AutoModerationRuleManager#cache\n   */\n\n  /**\n   * Resolves an {@link AutoModerationRuleResolvable} to an {@link AutoModerationRule} object.\n   *\n   * @method resolve\n   * @memberof AutoModerationRuleManager\n   * @instance\n   * @param {AutoModerationRuleResolvable} autoModerationRule The AutoModerationRule resolvable to resolve\n   * @returns {?AutoModerationRule}\n   */\n\n  /**\n   * Resolves an {@link AutoModerationRuleResolvable} to a {@link AutoModerationRule} id.\n   *\n   * @method resolveId\n   * @memberof AutoModerationRuleManager\n   * @instance\n   * @param {AutoModerationRuleResolvable} autoModerationRule The AutoModerationRule resolvable to resolve\n   * @returns {?Snowflake}\n   */\n\n  _add(data, cache) {\n    return super._add(data, cache, { extras: [this.guild] });\n  }\n\n  /**\n   * Options used to set the trigger metadata of an auto moderation rule.\n   *\n   * @typedef {Object} AutoModerationTriggerMetadataOptions\n   * @property {string[]} [keywordFilter] The substrings that will be searched for in the content\n   * @property {string[]} [regexPatterns] The regular expression patterns which will be matched against the content\n   * <info>Only Rust-flavored regular expressions are supported.</info>\n   * @property {AutoModerationRuleKeywordPresetType[]} [presets]\n   * The internally pre-defined wordsets which will be searched for in the content\n   * @property {string[]} [allowList] The substrings that will be exempt from triggering\n   * {@link AutoModerationRuleTriggerType.Keyword},\n   * {@link AutoModerationRuleTriggerType.KeywordPreset},\n   * and {@link AutoModerationRuleTriggerType.MemberProfile}\n   * @property {?number} [mentionTotalLimit] The total number of role & user mentions allowed per message\n   * @property {boolean} [mentionRaidProtectionEnabled] Whether to automatically detect mention raids\n   */\n\n  /**\n   * Options used to set the actions of an auto moderation rule.\n   *\n   * @typedef {Object} AutoModerationActionOptions\n   * @property {AutoModerationActionType} type The type of this auto moderation rule action\n   * @property {AutoModerationActionMetadataOptions} [metadata] Additional metadata needed during execution\n   * <info>This property is required if using a `type` of\n   * {@link AutoModerationActionType.SendAlertMessage} or {@link AutoModerationActionType.Timeout}.</info>\n   */\n\n  /**\n   * Options used to set the metadata of an auto moderation rule action.\n   *\n   * @typedef {Object} AutoModerationActionMetadataOptions\n   * @property {GuildTextChannelResolvable|ThreadChannel} [channel] The channel to which content will be logged\n   * @property {number} [durationSeconds] The timeout duration in seconds\n   * @property {string} [customMessage] The custom message that is shown whenever a message is blocked\n   */\n\n  /**\n   * Options used to create an auto moderation rule.\n   *\n   * @typedef {Object} AutoModerationRuleCreateOptions\n   * @property {string} name The name of the auto moderation rule\n   * @property {AutoModerationRuleEventType} eventType The event type of the auto moderation rule\n   * @property {AutoModerationRuleTriggerType} triggerType The trigger type of the auto moderation rule\n   * @property {AutoModerationTriggerMetadataOptions} [triggerMetadata] The trigger metadata of the auto moderation rule\n   * <info>This property is required if using a `triggerType` of\n   * {@link AutoModerationRuleTriggerType.Keyword},\n   * {@link AutoModerationRuleTriggerType.KeywordPreset},\n   * {@link AutoModerationRuleTriggerType.MentionSpam},\n   * or {@link AutoModerationRuleTriggerType.MemberProfile}.</info>\n   * @property {AutoModerationActionOptions[]} actions\n   * The actions that will execute when the auto moderation rule is triggered\n   * @property {boolean} [enabled] Whether the auto moderation rule should be enabled\n   * @property {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles]\n   * The roles that should not be affected by the auto moderation rule\n   * @property {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels]\n   * The channels that should not be affected by the auto moderation rule\n   * @property {string} [reason] The reason for creating the auto moderation rule\n   */\n\n  /**\n   * Creates a new auto moderation rule.\n   *\n   * @param {AutoModerationRuleCreateOptions} options Options for creating the auto moderation rule\n   * @returns {Promise<AutoModerationRule>}\n   */\n  async create({\n    name,\n    eventType,\n    triggerType,\n    triggerMetadata,\n    actions,\n    enabled,\n    exemptRoles,\n    exemptChannels,\n    reason,\n  }) {\n    const data = await this.client.rest.post(Routes.guildAutoModerationRules(this.guild.id), {\n      body: {\n        name,\n        event_type: eventType,\n        trigger_type: triggerType,\n        trigger_metadata: triggerMetadata && {\n          keyword_filter: triggerMetadata.keywordFilter,\n          regex_patterns: triggerMetadata.regexPatterns,\n          presets: triggerMetadata.presets,\n          allow_list: triggerMetadata.allowList,\n          mention_total_limit: triggerMetadata.mentionTotalLimit,\n          mention_raid_protection_enabled: triggerMetadata.mentionRaidProtectionEnabled,\n        },\n        actions: actions.map(action => ({\n          type: action.type,\n          metadata: {\n            duration_seconds: action.metadata?.durationSeconds,\n            channel_id: action.metadata?.channel && this.guild.channels.resolveId(action.metadata.channel),\n            custom_message: action.metadata?.customMessage,\n          },\n        })),\n        enabled,\n        exempt_roles: exemptRoles?.map(exemptRole => this.guild.roles.resolveId(exemptRole)),\n        exempt_channels: exemptChannels?.map(exemptChannel => this.guild.channels.resolveId(exemptChannel)),\n      },\n      reason,\n    });\n\n    return this._add(data);\n  }\n\n  /**\n   * Options used to edit an auto moderation rule.\n   *\n   * @typedef {Object} AutoModerationRuleEditOptions\n   * @property {string} [name] The name of the auto moderation rule\n   * @property {AutoModerationRuleEventType} [eventType] The event type of the auto moderation rule\n   * @property {AutoModerationTriggerMetadataOptions} [triggerMetadata] The trigger metadata of the auto moderation rule\n   * @property {AutoModerationActionOptions[]} [actions]\n   * The actions that will execute when the auto moderation rule is triggered\n   * @property {boolean} [enabled] Whether the auto moderation rule should be enabled\n   * @property {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles]\n   * The roles that should not be affected by the auto moderation rule\n   * @property {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels]\n   * The channels that should not be affected by the auto moderation rule\n   * @property {string} [reason] The reason for creating the auto moderation rule\n   */\n\n  /**\n   * Edits an auto moderation rule.\n   *\n   * @param {AutoModerationRuleResolvable} autoModerationRule The auto moderation rule to edit\n   * @param {AutoModerationRuleEditOptions} options Options for editing the auto moderation rule\n   * @returns {Promise<AutoModerationRule>}\n   */\n  async edit(\n    autoModerationRule,\n    { name, eventType, triggerMetadata, actions, enabled, exemptRoles, exemptChannels, reason },\n  ) {\n    const autoModerationRuleId = this.resolveId(autoModerationRule);\n\n    const data = await this.client.rest.patch(Routes.guildAutoModerationRule(this.guild.id, autoModerationRuleId), {\n      body: {\n        name,\n        event_type: eventType,\n        trigger_metadata: triggerMetadata && {\n          keyword_filter: triggerMetadata.keywordFilter,\n          regex_patterns: triggerMetadata.regexPatterns,\n          presets: triggerMetadata.presets,\n          allow_list: triggerMetadata.allowList,\n          mention_total_limit: triggerMetadata.mentionTotalLimit,\n          mention_raid_protection_enabled: triggerMetadata.mentionRaidProtectionEnabled,\n        },\n        actions: actions?.map(action => ({\n          type: action.type,\n          metadata: {\n            duration_seconds: action.metadata?.durationSeconds,\n            channel_id: action.metadata?.channel && this.guild.channels.resolveId(action.metadata.channel),\n            custom_message: action.metadata?.customMessage,\n          },\n        })),\n        enabled,\n        exempt_roles: exemptRoles?.map(exemptRole => this.guild.roles.resolveId(exemptRole)),\n        exempt_channels: exemptChannels?.map(exemptChannel => this.guild.channels.resolveId(exemptChannel)),\n      },\n      reason,\n    });\n\n    return this._add(data);\n  }\n\n  /**\n   * Data that can be resolved to give an AutoModerationRule object. This can be:\n   * - An AutoModerationRule\n   * - A Snowflake\n   *\n   * @typedef {AutoModerationRule|Snowflake} AutoModerationRuleResolvable\n   */\n\n  /**\n   * Options used to fetch a single auto moderation rule from a guild.\n   *\n   * @typedef {BaseFetchOptions} FetchAutoModerationRuleOptions\n   * @property {AutoModerationRuleResolvable} autoModerationRule The auto moderation rule to fetch\n   */\n\n  /**\n   * Options used to fetch all auto moderation rules from a guild.\n   *\n   * @typedef {Object} FetchAutoModerationRulesOptions\n   * @property {boolean} [cache] Whether to cache the fetched auto moderation rules\n   */\n\n  /**\n   * Fetches auto moderation rules from Discord.\n   *\n   * @param {AutoModerationRuleResolvable|FetchAutoModerationRuleOptions|FetchAutoModerationRulesOptions} [options]\n   * Options for fetching auto moderation rule(s)\n   * @returns {Promise<AutoModerationRule|Collection<Snowflake, AutoModerationRule>>}\n   * @example\n   * // Fetch all auto moderation rules from a guild without caching\n   * guild.autoModerationRules.fetch({ cache: false })\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Fetch a single auto moderation rule\n   * guild.autoModerationRules.fetch('979083472868098119')\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Fetch a single auto moderation rule without checking cache and without caching\n   * guild.autoModerationRules.fetch({ autoModerationRule: '979083472868098119', cache: false, force: true })\n   *   .then(console.log)\n   *   .catch(console.error)\n   */\n  async fetch(options) {\n    if (!options) return this._fetchMany();\n    const { autoModerationRule, cache, force } = options;\n    const resolvedAutoModerationRule = this.resolveId(autoModerationRule ?? options);\n    if (resolvedAutoModerationRule) {\n      return this._fetchSingle({ autoModerationRule: resolvedAutoModerationRule, cache, force });\n    }\n\n    return this._fetchMany(options);\n  }\n\n  async _fetchSingle({ autoModerationRule, cache, force = false }) {\n    if (!force) {\n      const existing = this.cache.get(autoModerationRule);\n      if (existing) return existing;\n    }\n\n    const data = await this.client.rest.get(Routes.guildAutoModerationRule(this.guild.id, autoModerationRule));\n    return this._add(data, cache);\n  }\n\n  async _fetchMany(options = {}) {\n    const data = await this.client.rest.get(Routes.guildAutoModerationRules(this.guild.id));\n\n    return data.reduce(\n      (col, autoModerationRule) => col.set(autoModerationRule.id, this._add(autoModerationRule, options.cache)),\n      new Collection(),\n    );\n  }\n\n  /**\n   * Deletes an auto moderation rule.\n   *\n   * @param {AutoModerationRuleResolvable} autoModerationRule The auto moderation rule to delete\n   * @param {string} [reason] The reason for deleting the auto moderation rule\n   * @returns {Promise<void>}\n   */\n  async delete(autoModerationRule, reason) {\n    const autoModerationRuleId = this.resolveId(autoModerationRule);\n    await this.client.rest.delete(Routes.guildAutoModerationRule(this.guild.id, autoModerationRuleId), { reason });\n  }\n}\n\nexports.AutoModerationRuleManager = AutoModerationRuleManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/BaseManager.js",
    "content": "'use strict';\n\n/**\n * Manages the API methods of a data model.\n *\n * @abstract\n */\nclass BaseManager {\n  constructor(client) {\n    /**\n     * The client that instantiated this Manager\n     *\n     * @name BaseManager#client\n     * @type {Client}\n     * @readonly\n     */\n    Object.defineProperty(this, 'client', { value: client });\n  }\n}\n\nexports.BaseManager = BaseManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/CachedManager.js",
    "content": "'use strict';\n\nconst { MakeCacheOverrideSymbol } = require('../util/Symbols.js');\nconst { DataManager } = require('./DataManager.js');\n\n/**\n * Manages the API methods of a data model with a mutable cache of instances.\n *\n * @extends {DataManager}\n * @abstract\n */\nclass CachedManager extends DataManager {\n  constructor(client, holds, iterable) {\n    super(client, holds);\n\n    /**\n     * The private cache of items for this manager.\n     *\n     * @type {Collection}\n     * @private\n     * @readonly\n     * @name CachedManager#_cache\n     */\n    Object.defineProperty(this, '_cache', {\n      value: this.client.options.makeCache({\n        holds: this.holds,\n        manager: this.constructor,\n        managerType: this.constructor[MakeCacheOverrideSymbol] ?? this.constructor,\n      }),\n    });\n\n    if (iterable) {\n      for (const item of iterable) {\n        this._add(item);\n      }\n    }\n  }\n\n  /**\n   * The cache of items for this manager.\n   *\n   * @type {Collection}\n   * @abstract\n   */\n  get cache() {\n    return this._cache;\n  }\n\n  _add(data, cache = true, { id, extras = [] } = {}) {\n    const existing = this.cache.get(id ?? data.id);\n    if (existing) {\n      if (cache) {\n        existing._patch(data);\n        return existing;\n      }\n\n      const clone = existing._clone();\n      clone._patch(data);\n      return clone;\n    }\n\n    const entry = this.holds ? new this.holds(this.client, data, ...extras) : data;\n    if (cache) this.cache.set(id ?? entry.id, entry);\n    return entry;\n  }\n}\n\nexports.CachedManager = CachedManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/CategoryChannelChildManager.js",
    "content": "'use strict';\n\nconst { GuildChannel } = require('../structures/GuildChannel.js');\nconst { DataManager } = require('./DataManager.js');\n\n/**\n * Manages API methods for CategoryChannels' children.\n *\n * @extends {DataManager}\n */\nclass CategoryChannelChildManager extends DataManager {\n  constructor(channel) {\n    super(channel.client, GuildChannel);\n    /**\n     * The category channel this manager belongs to\n     *\n     * @type {CategoryChannel}\n     */\n    this.channel = channel;\n  }\n\n  /**\n   * The channels that are a part of this category\n   *\n   * @type {Collection<Snowflake, GuildChannel>}\n   * @readonly\n   */\n  get cache() {\n    return this.guild.channels.cache.filter(channel => channel.parentId === this.channel.id);\n  }\n\n  /**\n   * The guild this manager belongs to\n   *\n   * @type {Guild}\n   * @readonly\n   */\n  get guild() {\n    return this.channel.guild;\n  }\n\n  /**\n   * Options for creating a channel using {@link CategoryChannelChildManager#create}.\n   *\n   * @typedef {Object} CategoryCreateChannelOptions\n   * @property {string} name The name for the new channel\n   * @property {ChannelType} [type=ChannelType.GuildText] The type of the new channel.\n   * @property {string} [topic] The topic for the new channel\n   * @property {boolean} [nsfw] Whether the new channel is NSFW\n   * @property {number} [bitrate] Bitrate of the new channel in bits (only voice)\n   * @property {number} [userLimit] Maximum amount of users allowed in the new channel (only voice)\n   * @property {OverwriteResolvable[]|Collection<Snowflake, OverwriteResolvable>} [permissionOverwrites]\n   * Permission overwrites of the new channel\n   * @property {number} [position] Position of the new channel\n   * @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the new channel in seconds\n   * @property {string} [rtcRegion] The specific region of the new channel.\n   * @property {VideoQualityMode} [videoQualityMode] The camera video quality mode of the voice channel\n   * @property {number} [defaultThreadRateLimitPerUser] The initial rate limit per user (slowmode)\n   * to set on newly created threads in a channel.\n   * @property {GuildForumTagData[]} [availableTags] The tags that can be used in this channel (forum only).\n   * @property {DefaultReactionEmoji} [defaultReactionEmoji]\n   * The emoji to show in the add reaction button on a thread in a guild forum channel.\n   * @property {ThreadAutoArchiveDuration} [defaultAutoArchiveDuration]\n   * The default auto archive duration for all new threads in this channel\n   * @property {SortOrderType} [defaultSortOrder] The default sort order mode used to order posts (forum only).\n   * @property {ForumLayoutType} [defaultForumLayout] The default layout used to display posts (forum only).\n   * @property {string} [reason] Reason for creating the new channel\n   */\n\n  /**\n   * Creates a new channel within this category.\n   * <info>You cannot create a channel of type {@link ChannelType.GuildCategory} inside a CategoryChannel.</info>\n   *\n   * @param {CategoryCreateChannelOptions} options Options for creating the new channel\n   * @returns {Promise<GuildChannel>}\n   */\n  async create(options) {\n    return this.guild.channels.create({\n      ...options,\n      parent: this.channel.id,\n    });\n  }\n}\n\nexports.CategoryChannelChildManager = CategoryChannelChildManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/ChannelManager.js",
    "content": "'use strict';\n\nconst process = require('node:process');\nconst { lazy, isFileBodyEncodable, isJSONEncodable } = require('@discordjs/util');\nconst { Routes } = require('discord-api-types/v10');\nconst { BaseChannel } = require('../structures/BaseChannel.js');\nconst { MessagePayload } = require('../structures/MessagePayload.js');\nconst { createChannel } = require('../util/Channels.js');\nconst { ThreadChannelTypes } = require('../util/Constants.js');\nconst { Events } = require('../util/Events.js');\nconst { CachedManager } = require('./CachedManager.js');\n\nconst getMessage = lazy(() => require('../structures/Message.js').Message);\n\nlet cacheWarningEmitted = false;\n\n/**\n * A manager of channels belonging to a client\n *\n * @extends {CachedManager}\n */\nclass ChannelManager extends CachedManager {\n  constructor(client, iterable) {\n    super(client, BaseChannel, iterable);\n    const defaultCaching =\n      this._cache.constructor.name === 'Collection' ||\n      this._cache.maxSize === undefined ||\n      this._cache.maxSize === Infinity;\n    if (!cacheWarningEmitted && !defaultCaching) {\n      cacheWarningEmitted = true;\n      process.emitWarning(\n        `Overriding the cache handling for ${this.constructor.name} is unsupported and breaks functionality.`,\n        'UnsupportedCacheOverwriteWarning',\n      );\n    }\n  }\n\n  /**\n   * The cache of Channels\n   *\n   * @type {Collection<Snowflake, BaseChannel>}\n   * @name ChannelManager#cache\n   */\n\n  _add(data, guild, { cache = true, allowUnknownGuild = false } = {}) {\n    const existing = this.cache.get(data.id);\n    if (existing) {\n      if (cache) existing._patch(data);\n      guild?.channels?._add(existing);\n      if (ThreadChannelTypes.includes(existing.type)) {\n        existing.parent?.threads?._add(existing);\n      }\n\n      return existing;\n    }\n\n    const channel = createChannel(this.client, data, guild, { allowUnknownGuild });\n\n    if (!channel) {\n      this.client.emit(Events.Debug, `Failed to find guild, or unknown type for channel ${data.id} ${data.type}`);\n      return null;\n    }\n\n    if (cache && !allowUnknownGuild) this.cache.set(channel.id, channel);\n\n    return channel;\n  }\n\n  _remove(id) {\n    const channel = this.cache.get(id);\n    channel?.guild?.channels.cache.delete(id);\n\n    for (const [code, invite] of channel?.guild?.invites.cache ?? []) {\n      if (invite.channelId === id) channel.guild.invites.cache.delete(code);\n    }\n\n    channel?.parent?.threads?.cache.delete(id);\n    this.cache.delete(id);\n\n    if (channel?.threads) {\n      for (const threadId of channel.threads.cache.keys()) {\n        this.cache.delete(threadId);\n        channel.guild?.channels.cache.delete(threadId);\n      }\n    }\n  }\n\n  /**\n   * Data that can be resolved to give a Channel object. This can be:\n   * - A Channel object\n   * - A Snowflake\n   *\n   * @typedef {BaseChannel|Snowflake} ChannelResolvable\n   */\n\n  /**\n   * Resolves a ChannelResolvable to a Channel object.\n   *\n   * @method resolve\n   * @memberof ChannelManager\n   * @instance\n   * @param {ChannelResolvable} channel The channel resolvable to resolve\n   * @returns {?BaseChannel}\n   */\n\n  /**\n   * Resolves a ChannelResolvable to a channel id string.\n   *\n   * @method resolveId\n   * @memberof ChannelManager\n   * @instance\n   * @param {ChannelResolvable} channel The channel resolvable to resolve\n   * @returns {?Snowflake}\n   */\n\n  /**\n   * Options for fetching a channel from Discord\n   *\n   * @typedef {BaseFetchOptions} FetchChannelOptions\n   * @property {boolean} [allowUnknownGuild=false] Allows the channel to be returned even if the guild is not in cache,\n   * it will not be cached. <warn>Many of the properties and methods on the returned channel will throw errors</warn>\n   */\n\n  /**\n   * Obtains a channel from Discord, or the channel cache if it's already available.\n   *\n   * @param {Snowflake} id The channel's id\n   * @param {FetchChannelOptions} [options] Additional options for this fetch\n   * @returns {Promise<?BaseChannel>}\n   * @example\n   * // Fetch a channel by its id\n   * client.channels.fetch('222109930545610754')\n   *   .then(channel => console.log(channel.name))\n   *   .catch(console.error);\n   */\n  async fetch(id, { allowUnknownGuild = false, cache = true, force = false } = {}) {\n    if (!force) {\n      const existing = this.cache.get(id);\n      if (existing && !existing.partial) return existing;\n    }\n\n    const data = await this.client.rest.get(Routes.channel(id));\n    return this._add(data, null, { cache, allowUnknownGuild });\n  }\n\n  /**\n   * Creates a message in a channel.\n   *\n   * @param {TextChannelResolvable} channel The channel to send the message to\n   * @param {string|MessagePayload|MessageCreateOptions|JSONEncodable<RESTPostAPIChannelMessageJSONBody>|FileBodyEncodable<RESTPostAPIChannelMessageJSONBody>} options The options to provide\n   * @returns {Promise<Message>}\n   * @example\n   * // Send a basic message\n   * client.channels.createMessage(channel, 'hello!')\n   *   .then(message => console.log(`Sent message: ${message.content}`))\n   *   .catch(console.error);\n   * @example\n   * // Send a remote file\n   * client.channels.createMessage(channel, {\n   *   files: ['https://github.com/discordjs.png']\n   * })\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Send a local file\n   * client.channels.createMessage(channel, {\n   *   files: [{\n   *     attachment: 'entire/path/to/file.jpg',\n   *     name: 'file.jpg',\n   *     description: 'A description of the file'\n   *   }]\n   * })\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async createMessage(channel, options) {\n    let payload;\n\n    if (options instanceof MessagePayload) {\n      payload = await options.resolveBody().resolveFiles();\n    } else if (isFileBodyEncodable(options)) {\n      payload = options.toFileBody();\n    } else if (isJSONEncodable(options)) {\n      payload = { body: options.toJSON() };\n    } else {\n      payload = await MessagePayload.create(this, options).resolveBody().resolveFiles();\n    }\n\n    const resolvedChannelId = this.resolveId(channel);\n    const resolvedChannel = this.resolve(channel);\n    const data = await this.client.rest.post(Routes.channelMessages(resolvedChannelId), payload);\n\n    return resolvedChannel?.messages._add(data) ?? new (getMessage())(this.client, data);\n  }\n}\n\nexports.ChannelManager = ChannelManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/DMMessageManager.js",
    "content": "'use strict';\n\nconst { MessageManager } = require('./MessageManager.js');\n\n/**\n * Manages API methods for messages in direct message channels and holds their cache.\n *\n * @extends {MessageManager}\n */\nclass DMMessageManager extends MessageManager {\n  /**\n   * The channel that the messages belong to\n   *\n   * @name DMMessageManager#channel\n   * @type {DMChannel}\n   */\n}\n\nexports.DMMessageManager = DMMessageManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/DataManager.js",
    "content": "'use strict';\n\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { BaseManager } = require('./BaseManager.js');\n\n/**\n * Manages the API methods of a data model along with a collection of instances.\n *\n * @extends {BaseManager}\n * @abstract\n */\nclass DataManager extends BaseManager {\n  constructor(client, holds) {\n    super(client);\n\n    /**\n     * The data structure belonging to this manager.\n     *\n     * @name DataManager#holds\n     * @type {Function}\n     * @private\n     * @readonly\n     */\n    Object.defineProperty(this, 'holds', { value: holds });\n  }\n\n  /**\n   * The cache of items for this manager.\n   *\n   * @type {Collection}\n   * @abstract\n   */\n  get cache() {\n    throw new DiscordjsError(ErrorCodes.NotImplemented, 'get cache', this.constructor.name);\n  }\n\n  /**\n   * Resolves a data entry to a data Object.\n   *\n   * @param {string | Object} idOrInstance The id or instance of something in this Manager\n   * @returns {?Object} An instance from this Manager\n   */\n  resolve(idOrInstance) {\n    if (idOrInstance instanceof this.holds) return idOrInstance;\n    if (typeof idOrInstance === 'string') return this.cache.get(idOrInstance) ?? null;\n    return null;\n  }\n\n  /**\n   * Resolves a data entry to an instance id.\n   *\n   * @param {string | Object} idOrInstance The id or instance of something in this Manager\n   * @returns {?Snowflake}\n   */\n  resolveId(idOrInstance) {\n    if (idOrInstance instanceof this.holds) return idOrInstance.id;\n    if (typeof idOrInstance === 'string') return idOrInstance;\n    return null;\n  }\n\n  valueOf() {\n    return this.cache;\n  }\n}\n\nexports.DataManager = DataManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/EntitlementManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { Routes, EntitlementOwnerType } = require('discord-api-types/v10');\nconst { ErrorCodes, DiscordjsTypeError } = require('../errors/index.js');\nconst { Entitlement } = require('../structures/Entitlement.js');\nconst { resolveSKUId } = require('../util/Util.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for entitlements and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass EntitlementManager extends CachedManager {\n  constructor(client, iterable) {\n    super(client, Entitlement, iterable);\n  }\n\n  /**\n   * The cache of this manager\n   *\n   * @type {Collection<Snowflake, Entitlement>}\n   * @name EntitlementManager#cache\n   */\n\n  /**\n   * Data that resolves to give an Entitlement object. This can be:\n   * - An Entitlement object\n   * - A Snowflake\n   *\n   * @typedef {Entitlement|Snowflake} EntitlementResolvable\n   */\n\n  /**\n   * Data that resolves to give a SKU object. This can be:\n   * - A SKU object\n   * - A Snowflake\n   *\n   * @typedef {SKU|Snowflake} SKUResolvable\n   */\n\n  /**\n   * Options used to fetch an entitlement\n   *\n   * @typedef {BaseFetchOptions} FetchEntitlementOptions\n   * @property {EntitlementResolvable} entitlement The entitlement to fetch\n   */\n\n  /**\n   * Options used to fetch entitlements\n   *\n   * @typedef {Object} FetchEntitlementsOptions\n   * @property {number} [limit] The maximum number of entitlements to fetch\n   * @property {GuildResolvable} [guild] The guild to fetch entitlements for\n   * @property {UserResolvable} [user] The user to fetch entitlements for\n   * @property {SKUResolvable[]} [skus] The SKUs to fetch entitlements for\n   * @property {boolean} [excludeEnded] Whether to exclude ended entitlements\n   * @property {boolean} [excludeDeleted] Whether to exclude deleted entitlements\n   * @property {boolean} [cache=true] Whether to cache the fetched entitlements\n   * @property {Snowflake} [before] Consider only entitlements before this entitlement id\n   * @property {Snowflake} [after] Consider only entitlements after this entitlement id\n   * <warn>If both `before` and `after` are provided, only `before` is respected</warn>\n   */\n\n  /**\n   * Fetches entitlements for this application\n   *\n   * @param {EntitlementResolvable|FetchEntitlementOptions|FetchEntitlementsOptions} [options]\n   * Options for fetching the entitlements\n   * @returns {Promise<Entitlement|Collection<Snowflake, Entitlement>>}\n   */\n  async fetch(options) {\n    if (!options) return this._fetchMany(options);\n    const { entitlement, cache, force } = options;\n    const resolvedEntitlement = this.resolveId(entitlement ?? options);\n\n    if (resolvedEntitlement) {\n      return this._fetchSingle({ entitlement: resolvedEntitlement, cache, force });\n    }\n\n    return this._fetchMany(options);\n  }\n\n  async _fetchSingle({ entitlement, cache, force = false }) {\n    if (!force) {\n      const existing = this.cache.get(entitlement);\n\n      if (existing) {\n        return existing;\n      }\n    }\n\n    const data = await this.client.rest.get(Routes.entitlement(this.client.application.id, entitlement));\n    return this._add(data, cache);\n  }\n\n  async _fetchMany({ limit, guild, user, skus, excludeEnded, excludeDeleted, cache, before, after } = {}) {\n    const query = makeURLSearchParams({\n      limit,\n      guild_id: guild && this.client.guilds.resolveId(guild),\n      user_id: user && this.client.users.resolveId(user),\n      sku_ids: skus?.map(sku => resolveSKUId(sku)).join(','),\n      exclude_ended: excludeEnded,\n      exclude_deleted: excludeDeleted,\n      before,\n      after,\n    });\n\n    const entitlements = await this.client.rest.get(Routes.entitlements(this.client.application.id), { query });\n\n    return entitlements.reduce(\n      (coll, entitlement) => coll.set(entitlement.id, this._add(entitlement, cache)),\n      new Collection(),\n    );\n  }\n\n  /**\n   * Options used to create a test entitlement\n   * <info>Either `guild` or `user` must be provided, but not both</info>\n   *\n   * @typedef {Object} EntitlementCreateOptions\n   * @property {SKUResolvable} sku The id of the SKU to create the entitlement for\n   * @property {GuildResolvable} [guild] The guild to create the entitlement for\n   * @property {UserResolvable} [user] The user to create the entitlement for\n   */\n\n  /**\n   * Creates a test entitlement\n   *\n   * @param {EntitlementCreateOptions} options Options for creating the test entitlement\n   * @returns {Promise<Entitlement>}\n   */\n  async createTest({ sku, guild, user }) {\n    const skuId = resolveSKUId(sku);\n    if (!skuId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'sku', 'SKUResolvable');\n\n    if ((guild && user) || (!guild && !user)) {\n      throw new DiscordjsTypeError(ErrorCodes.EntitlementCreateInvalidOwner);\n    }\n\n    const resolved = guild ? this.client.guilds.resolveId(guild) : this.client.users.resolveId(user);\n    if (!resolved) {\n      const name = guild ? 'guild' : 'user';\n      const type = guild ? 'GuildResolvable' : 'UserResolvable';\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, name, type);\n    }\n\n    const entitlement = await this.client.rest.post(Routes.entitlements(this.client.application.id), {\n      body: {\n        sku_id: skuId,\n        owner_id: resolved,\n        owner_type: guild ? EntitlementOwnerType.Guild : EntitlementOwnerType.User,\n      },\n    });\n    return new Entitlement(this.client, entitlement);\n  }\n\n  /**\n   * Deletes a test entitlement\n   *\n   * @param {EntitlementResolvable} entitlement The entitlement to delete\n   * @returns {Promise<void>}\n   */\n  async deleteTest(entitlement) {\n    const resolved = this.resolveId(entitlement);\n    if (!resolved) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'entitlement', 'EntitlementResolvable');\n\n    await this.client.rest.delete(Routes.entitlement(this.client.application.id, resolved));\n  }\n\n  /**\n   * Marks an entitlement as consumed\n   * <info>Only available for One-Time Purchase consumable SKUs.</info>\n   *\n   * @param {Snowflake} entitlementId The id of the entitlement to consume\n   * @returns {Promise<void>}\n   */\n  async consume(entitlementId) {\n    await this.client.rest.post(Routes.consumeEntitlement(this.client.application.id, entitlementId));\n  }\n}\n\nexports.EntitlementManager = EntitlementManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/GuildApplicationCommandManager.js",
    "content": "'use strict';\n\nconst { ApplicationCommandManager } = require('./ApplicationCommandManager.js');\nconst { ApplicationCommandPermissionsManager } = require('./ApplicationCommandPermissionsManager.js');\n\n/**\n * An extension for guild-specific application commands.\n *\n * @extends {ApplicationCommandManager}\n */\nclass GuildApplicationCommandManager extends ApplicationCommandManager {\n  constructor(guild, iterable) {\n    super(guild.client, iterable);\n\n    /**\n     * The guild that this manager belongs to\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n\n    /**\n     * The manager for permissions of arbitrary commands on this guild\n     *\n     * @type {ApplicationCommandPermissionsManager}\n     */\n    this.permissions = new ApplicationCommandPermissionsManager(this);\n  }\n}\n\nexports.GuildApplicationCommandManager = GuildApplicationCommandManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/GuildBanManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { GuildBan } = require('../structures/GuildBan.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for guild bans and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass GuildBanManager extends CachedManager {\n  constructor(guild, iterable) {\n    super(guild.client, GuildBan, iterable);\n\n    /**\n     * The guild this Manager belongs to\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n  }\n\n  /**\n   * The cache of this Manager\n   *\n   * @type {Collection<Snowflake, GuildBan>}\n   * @name GuildBanManager#cache\n   */\n\n  _add(data, cache) {\n    return super._add(data, cache, { id: data.user.id, extras: [this.guild] });\n  }\n\n  /**\n   * Data that resolves to give a GuildBan object. This can be:\n   * - A GuildBan object\n   * - A User resolvable\n   *\n   * @typedef {GuildBan|UserResolvable} GuildBanResolvable\n   */\n\n  /**\n   * Resolves a GuildBanResolvable to a GuildBan object.\n   *\n   * @param {GuildBanResolvable} ban The ban that is in the guild\n   * @returns {?GuildBan}\n   */\n  resolve(ban) {\n    return super.resolve(ban) ?? super.resolve(this.client.users.resolveId(ban));\n  }\n\n  /**\n   * Options used to fetch a single ban from a guild.\n   *\n   * @typedef {BaseFetchOptions} FetchBanOptions\n   * @property {UserResolvable} user The ban to fetch\n   */\n\n  /**\n   * Options used to fetch multiple bans from a guild.\n   *\n   * @typedef {Object} FetchBansOptions\n   * @property {number} [limit] The maximum number of bans to return\n   * @property {Snowflake} [before] Consider only bans before this id\n   * @property {Snowflake} [after] Consider only bans after this id\n   * @property {boolean} [cache] Whether to cache the fetched bans\n   */\n\n  /**\n   * Fetches ban(s) from Discord.\n   *\n   * @param {UserResolvable|FetchBanOptions|FetchBansOptions} [options] Options for fetching guild ban(s)\n   * @returns {Promise<GuildBan|Collection<Snowflake, GuildBan>>}\n   * @example\n   * // Fetch multiple bans from a guild\n   * guild.bans.fetch()\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Fetch a maximum of 5 bans from a guild without caching\n   * guild.bans.fetch({ limit: 5, cache: false })\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Fetch a single ban\n   * guild.bans.fetch('351871113346809860')\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Fetch a single ban without checking cache\n   * guild.bans.fetch({ user, force: true })\n   *   .then(console.log)\n   *   .catch(console.error)\n   * @example\n   * // Fetch a single ban without caching\n   * guild.bans.fetch({ user, cache: false })\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async fetch(options) {\n    if (!options) return this._fetchMany();\n    const { user, cache, force, limit, before, after } = options;\n    const resolvedUser = this.client.users.resolveId(user ?? options);\n    if (resolvedUser) return this._fetchSingle({ user: resolvedUser, cache, force });\n\n    if (!before && !after && !limit && cache === undefined) {\n      throw new DiscordjsError(ErrorCodes.FetchBanResolveId);\n    }\n\n    return this._fetchMany(options);\n  }\n\n  async _fetchSingle({ user, cache, force = false }) {\n    if (!force) {\n      const existing = this.cache.get(user);\n      if (existing && !existing.partial) return existing;\n    }\n\n    const data = await this.client.rest.get(Routes.guildBan(this.guild.id, user));\n    return this._add(data, cache);\n  }\n\n  async _fetchMany({ cache, ...apiOptions } = {}) {\n    const data = await this.client.rest.get(Routes.guildBans(this.guild.id), {\n      query: makeURLSearchParams(apiOptions),\n    });\n\n    return data.reduce((col, ban) => col.set(ban.user.id, this._add(ban, cache)), new Collection());\n  }\n\n  /**\n   * Options used to ban a user from a guild.\n   *\n   * @typedef {Object} BanOptions\n   * @property {number} [deleteMessageSeconds] Number of seconds of messages to delete,\n   * must be between 0 and 604800 (7 days), inclusive\n   * @property {string} [reason] The reason for the ban\n   */\n\n  /**\n   * Bans a user from the guild.\n   *\n   * @param {UserResolvable} user The user to ban\n   * @param {BanOptions} [options={}] Options for the ban\n   * @returns {Promise<void>}\n   * @example\n   * // Ban a user by id (or with a user/guild member object)\n   * await guild.bans.create('84484653687267328');\n   */\n  async create(user, options = {}) {\n    if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true);\n    const id = this.client.users.resolveId(user);\n    if (!id) throw new DiscordjsError(ErrorCodes.BanResolveId, true);\n\n    await this.client.rest.put(Routes.guildBan(this.guild.id, id), {\n      body: {\n        delete_message_seconds: options.deleteMessageSeconds,\n      },\n      reason: options.reason,\n    });\n  }\n\n  /**\n   * Unbans a user from the guild.\n   *\n   * @param {UserResolvable} user The user to unban\n   * @param {string} [reason] Reason for unbanning user\n   * @returns {Promise<void>}\n   * @example\n   * // Unban a user by id (or with a user/guild member object)\n   * await guild.bans.remove('84484653687267328');\n   */\n  async remove(user, reason) {\n    const id = this.client.users.resolveId(user);\n    if (!id) throw new DiscordjsError(ErrorCodes.BanResolveId);\n    await this.client.rest.delete(Routes.guildBan(this.guild.id, id), { reason });\n  }\n\n  /**\n   * Result of bulk banning users from a guild.\n   *\n   * @typedef {Object} BulkBanResult\n   * @property {Snowflake[]} bannedUsers IDs of the banned users\n   * @property {Snowflake[]} failedUsers IDs of the users that could not be banned or were already banned\n   */\n\n  /**\n   * Bulk ban users from a guild, and optionally delete previous messages sent by them.\n   *\n   * @param {Collection<Snowflake, UserResolvable>|UserResolvable[]} users The users to ban\n   * @param {BanOptions} [options] The options for bulk banning users\n   * @returns {Promise<BulkBanResult>} Returns an object with `bannedUsers` key containing the IDs of the banned users\n   * and the key `failedUsers` with the IDs that could not be banned or were already banned.\n   * @example\n   * // Bulk ban users by ids (or with user/guild member objects) and delete all their messages from the past 7 days\n   * guild.bans.bulkCreate(['84484653687267328'], { deleteMessageSeconds: 7 * 24 * 60 * 60 })\n   *   .then(result => {\n   *     console.log(`Banned ${result.bannedUsers.length} users, failed to ban ${result.failedUsers.length} users.`)\n   *   })\n   *   .catch(console.error);\n   */\n  async bulkCreate(users, options = {}) {\n    if (!users || !(Array.isArray(users) || users instanceof Collection)) {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'users', 'Array or Collection of UserResolvable', true);\n    }\n\n    if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true);\n\n    const userIds = users.map(user => this.client.users.resolveId(user));\n    if (userIds.length === 0) throw new DiscordjsError(ErrorCodes.BulkBanUsersOptionEmpty);\n\n    const result = await this.client.rest.post(Routes.guildBulkBan(this.guild.id), {\n      body: { delete_message_seconds: options.deleteMessageSeconds, user_ids: userIds },\n      reason: options.reason,\n    });\n    return { bannedUsers: result.banned_users, failedUsers: result.failed_users };\n  }\n}\n\nexports.GuildBanManager = GuildBanManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/GuildChannelManager.js",
    "content": "'use strict';\n\nconst process = require('node:process');\nconst { Collection } = require('@discordjs/collection');\nconst { ChannelType, Routes } = require('discord-api-types/v10');\nconst { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { GuildChannel } = require('../structures/GuildChannel.js');\nconst { PermissionOverwrites } = require('../structures/PermissionOverwrites.js');\nconst { ThreadChannel } = require('../structures/ThreadChannel.js');\nconst { Webhook } = require('../structures/Webhook.js');\nconst { ChannelFlagsBitField } = require('../util/ChannelFlagsBitField.js');\nconst { transformGuildForumTag, transformGuildDefaultReaction } = require('../util/Channels.js');\nconst { ThreadChannelTypes } = require('../util/Constants.js');\nconst { resolveImage } = require('../util/DataResolver.js');\nconst { setPosition } = require('../util/Util.js');\nconst { CachedManager } = require('./CachedManager.js');\nconst { GuildTextThreadManager } = require('./GuildTextThreadManager.js');\n\nlet cacheWarningEmitted = false;\n\n/**\n * Manages API methods for GuildChannels and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass GuildChannelManager extends CachedManager {\n  constructor(guild, iterable) {\n    super(guild.client, GuildChannel, iterable);\n    const defaultCaching =\n      this._cache.constructor.name === 'Collection' ||\n      this._cache.maxSize === undefined ||\n      this._cache.maxSize === Infinity;\n    if (!cacheWarningEmitted && !defaultCaching) {\n      cacheWarningEmitted = true;\n      process.emitWarning(\n        `Overriding the cache handling for ${this.constructor.name} is unsupported and breaks functionality.`,\n        'UnsupportedCacheOverwriteWarning',\n      );\n    }\n\n    /**\n     * The guild this Manager belongs to\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n  }\n\n  /**\n   * The number of channels in this managers cache excluding thread channels\n   * that do not count towards a guild's maximum channels restriction.\n   *\n   * @type {number}\n   * @readonly\n   */\n  get channelCountWithoutThreads() {\n    return this.cache.reduce((acc, channel) => {\n      if (ThreadChannelTypes.includes(channel.type)) return acc;\n      return acc + 1;\n    }, 0);\n  }\n\n  /**\n   * The cache of this Manager\n   *\n   * @type {Collection<Snowflake, GuildChannel|ThreadChannel>}\n   * @name GuildChannelManager#cache\n   */\n\n  _add(channel) {\n    const existing = this.cache.get(channel.id);\n    if (existing) return existing;\n    this.cache.set(channel.id, channel);\n    return channel;\n  }\n\n  /**\n   * Data that can be resolved to give a Guild Channel object. This can be:\n   * - A GuildChannel object\n   * - A ThreadChannel object\n   * - A Snowflake\n   *\n   * @typedef {GuildChannel|ThreadChannel|Snowflake} GuildChannelResolvable\n   */\n\n  /**\n   * Resolves a GuildChannelResolvable to a Channel object.\n   *\n   * @param {GuildChannelResolvable} channel The GuildChannel resolvable to resolve\n   * @returns {?(GuildChannel|ThreadChannel)}\n   */\n  resolve(channel) {\n    if (channel instanceof ThreadChannel) return super.cache.get(channel.id) ?? null;\n    return super.resolve(channel);\n  }\n\n  /**\n   * Resolves a GuildChannelResolvable to a channel id.\n   *\n   * @param {GuildChannelResolvable} channel The GuildChannel resolvable to resolve\n   * @returns {?Snowflake}\n   */\n  resolveId(channel) {\n    if (channel instanceof ThreadChannel) return super.resolveId(channel.id);\n    return super.resolveId(channel);\n  }\n\n  /**\n   * Data that can be resolved to an Announcement Channel object. This can be:\n   * - An Announcement Channel object\n   * - A Snowflake\n   *\n   * @typedef {AnnouncementChannel|Snowflake} AnnouncementChannelResolvable\n   */\n\n  /**\n   * Represents the followed channel data.\n   *\n   * @typedef {Object} FollowedChannelData\n   * @property {Snowflake} channelId Source channel id\n   * @property {Snowflake} webhookId Created webhook id in the target channel\n   */\n\n  /**\n   * Adds the target channel to a channel's followers.\n   *\n   * @param {AnnouncementChannelResolvable} channel The channel to follow\n   * @param {TextChannelResolvable} targetChannel The channel where published announcements will be posted at\n   * @param {string} [reason] Reason for creating the webhook\n   * @returns {Promise<FollowedChannelData>} Returns the data for the followed channel\n   */\n  async addFollower(channel, targetChannel, reason) {\n    const channelId = this.resolveId(channel);\n    if (!channelId) {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'AnnouncementChannelResolvable');\n    }\n\n    const targetChannelId = this.resolveId(targetChannel);\n    if (!targetChannelId) {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'targetChannel', 'TextChannelResolvable');\n    }\n\n    const data = await this.client.rest.post(Routes.channelFollowers(channelId), {\n      body: { webhook_channel_id: targetChannelId },\n      reason,\n    });\n    return { channelId: data.channel_id, webhookId: data.webhook_id };\n  }\n\n  /**\n   * Options used to create a new channel in a guild.\n   *\n   * @typedef {CategoryCreateChannelOptions} GuildChannelCreateOptions\n   * @property {?CategoryChannelResolvable} [parent] Parent of the new channel\n   */\n\n  /**\n   * Creates a new channel in the guild.\n   *\n   * @param {GuildChannelCreateOptions} options Options for creating the new channel\n   * @returns {Promise<GuildChannel>}\n   * @example\n   * // Create a new text channel\n   * guild.channels.create({ name: 'new-general', reason: 'Needed a cool new channel' })\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Create a new channel with permission overwrites\n   * guild.channels.create({\n   *   name: 'new-general',\n   *   type: ChannelType.GuildVoice,\n   *   permissionOverwrites: [\n   *      {\n   *        id: message.author.id,\n   *        deny: [PermissionFlagsBits.ViewChannel],\n   *     },\n   *   ],\n   * })\n   */\n  async create({\n    name,\n    type,\n    topic,\n    nsfw,\n    bitrate,\n    userLimit,\n    parent,\n    permissionOverwrites,\n    position,\n    rateLimitPerUser,\n    rtcRegion,\n    videoQualityMode,\n    defaultThreadRateLimitPerUser,\n    availableTags,\n    defaultReactionEmoji,\n    defaultAutoArchiveDuration,\n    defaultSortOrder,\n    defaultForumLayout,\n    reason,\n  }) {\n    const data = await this.client.rest.post(Routes.guildChannels(this.guild.id), {\n      body: {\n        name,\n        topic,\n        type,\n        nsfw,\n        bitrate,\n        user_limit: userLimit,\n        parent_id: parent && this.client.channels.resolveId(parent),\n        position,\n        permission_overwrites: permissionOverwrites?.map(overwrite =>\n          PermissionOverwrites.resolve(overwrite, this.guild),\n        ),\n        rate_limit_per_user: rateLimitPerUser,\n        rtc_region: rtcRegion,\n        video_quality_mode: videoQualityMode,\n        default_thread_rate_limit_per_user: defaultThreadRateLimitPerUser,\n        available_tags: availableTags?.map(availableTag => transformGuildForumTag(availableTag)),\n        default_reaction_emoji: defaultReactionEmoji && transformGuildDefaultReaction(defaultReactionEmoji),\n        default_auto_archive_duration: defaultAutoArchiveDuration,\n        default_sort_order: defaultSortOrder,\n        default_forum_layout: defaultForumLayout,\n      },\n      reason,\n    });\n    return this.client.actions.ChannelCreate.handle(data).channel;\n  }\n\n  /**\n   * @typedef {ChannelWebhookCreateOptions} WebhookCreateOptions\n   * @property {TextChannel|AnnouncementChannel|VoiceChannel|StageChannel|ForumChannel|MediaChannel|Snowflake} channel\n   * The channel to create the webhook for\n   */\n\n  /**\n   * Creates a webhook for the channel.\n   *\n   * @param {WebhookCreateOptions} options Options for creating the webhook\n   * @returns {Promise<Webhook>} Returns the created Webhook\n   * @example\n   * // Create a webhook for the current channel\n   * guild.channels.createWebhook({\n   *   channel: '222197033908436994',\n   *   name: 'Snek',\n   *   avatar: 'https://i.imgur.com/mI8XcpG.jpg',\n   *   reason: 'Needed a cool new Webhook'\n   * })\n   *   .then(console.log)\n   *   .catch(console.error)\n   */\n  async createWebhook({ channel, name, avatar, reason }) {\n    const channelId = this.resolveId(channel);\n    if (!channelId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');\n\n    const resolvedAvatar = await resolveImage(avatar);\n\n    const data = await this.client.rest.post(Routes.channelWebhooks(channelId), {\n      body: {\n        name,\n        avatar: resolvedAvatar,\n      },\n      reason,\n    });\n\n    return new Webhook(this.client, data);\n  }\n\n  /**\n   * Options used to edit a guild channel.\n   *\n   * @typedef {Object} GuildChannelEditOptions\n   * @property {string} [name] The name of the channel\n   * @property {ChannelType} [type] The type of the channel (only conversion between text and announcement is supported)\n   * @property {number} [position] The position of the channel\n   * @property {?string} [topic] The topic of the text channel\n   * @property {boolean} [nsfw] Whether the channel is NSFW\n   * @property {number} [bitrate] The bitrate of the voice channel\n   * @property {number} [userLimit] The user limit of the voice channel\n   * @property {?CategoryChannelResolvable} [parent] The parent of the channel\n   * @property {boolean} [lockPermissions]\n   * Lock the permissions of the channel to what the parent's permissions are\n   * @property {OverwriteResolvable[]|Collection<Snowflake, OverwriteResolvable>} [permissionOverwrites]\n   * Permission overwrites for the channel\n   * @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the channel in seconds\n   * @property {ThreadAutoArchiveDuration} [defaultAutoArchiveDuration]\n   * The default auto archive duration for all new threads in this channel\n   * @property {?string} [rtcRegion] The RTC region of the channel\n   * @property {?VideoQualityMode} [videoQualityMode] The camera video quality mode of the channel\n   * @property {GuildForumTagData[]} [availableTags] The tags to set as available in a forum channel\n   * @property {?DefaultReactionEmoji} [defaultReactionEmoji] The emoji to set as the default reaction emoji\n   * @property {number} [defaultThreadRateLimitPerUser] The rate limit per user (slowmode) to set on forum posts\n   * @property {ChannelFlagsResolvable} [flags] The flags to set on the channel\n   * @property {?SortOrderType} [defaultSortOrder] The default sort order mode to set on the channel\n   * @property {ForumLayoutType} [defaultForumLayout] The default forum layout to set on the channel\n   * @property {string} [reason] Reason for editing this channel\n   */\n\n  /**\n   * Edits the channel.\n   *\n   * @param {GuildChannelResolvable} channel The channel to edit\n   * @param {GuildChannelEditOptions} options Options for editing the channel\n   * @returns {Promise<GuildChannel>}\n   * @example\n   * // Edit a channel\n   * guild.channels.edit('222197033908436994', { name: 'new-channel' })\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async edit(channel, options) {\n    const resolvedChannel = this.resolve(channel);\n    if (!resolvedChannel) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');\n\n    const parentId = options.parent && this.client.channels.resolveId(options.parent);\n\n    if (options.position !== undefined) {\n      await this.setPosition(resolvedChannel, options.position, { position: options.position, reason: options.reason });\n    }\n\n    let permission_overwrites = options.permissionOverwrites?.map(overwrite =>\n      PermissionOverwrites.resolve(overwrite, this.guild),\n    );\n\n    if (options.lockPermissions) {\n      if (parentId) {\n        const newParent = this.cache.get(parentId);\n        if (newParent?.type === ChannelType.GuildCategory) {\n          permission_overwrites = newParent.permissionOverwrites.cache.map(overwrite =>\n            PermissionOverwrites.resolve(overwrite, this.guild),\n          );\n        }\n      } else if (resolvedChannel.parent) {\n        permission_overwrites = resolvedChannel.parent.permissionOverwrites.cache.map(overwrite =>\n          PermissionOverwrites.resolve(overwrite, this.guild),\n        );\n      }\n    }\n\n    const newData = await this.client.rest.patch(Routes.channel(resolvedChannel.id), {\n      body: {\n        name: options.name,\n        type: options.type,\n        topic: options.topic,\n        nsfw: options.nsfw,\n        bitrate: options.bitrate,\n        user_limit: options.userLimit,\n        rtc_region: options.rtcRegion,\n        video_quality_mode: options.videoQualityMode,\n        parent_id: parentId,\n        lock_permissions: options.lockPermissions,\n        rate_limit_per_user: options.rateLimitPerUser,\n        default_auto_archive_duration: options.defaultAutoArchiveDuration,\n        permission_overwrites,\n        available_tags: options.availableTags?.map(availableTag => transformGuildForumTag(availableTag)),\n        default_reaction_emoji:\n          options.defaultReactionEmoji && transformGuildDefaultReaction(options.defaultReactionEmoji),\n        default_thread_rate_limit_per_user: options.defaultThreadRateLimitPerUser,\n        flags: 'flags' in options ? ChannelFlagsBitField.resolve(options.flags) : undefined,\n        default_sort_order: options.defaultSortOrder,\n        default_forum_layout: options.defaultForumLayout,\n      },\n      reason: options.reason,\n    });\n\n    return this.client.actions.ChannelUpdate.handle(newData).updated;\n  }\n\n  /**\n   * Sets a new position for the guild channel.\n   *\n   * @param {GuildChannelResolvable} channel The channel to set the position for\n   * @param {number} position The new position for the guild channel\n   * @param {SetChannelPositionOptions} options Options for setting position\n   * @returns {Promise<GuildChannel>}\n   * @example\n   * // Set a new channel position\n   * guild.channels.setPosition('222078374472843266', 2)\n   *   .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`))\n   *   .catch(console.error);\n   */\n  async setPosition(channel, position, { relative, reason } = {}) {\n    const resolvedChannel = this.resolve(channel);\n    if (!resolvedChannel) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');\n\n    const updatedChannels = await setPosition(\n      resolvedChannel,\n      position,\n      relative,\n      this.guild._sortedChannels(resolvedChannel),\n      this.client,\n      Routes.guildChannels(this.guild.id),\n      reason,\n    );\n\n    this.client.actions.GuildChannelsPositionUpdate.handle({\n      guild_id: this.guild.id,\n      channels: updatedChannels,\n    });\n\n    return resolvedChannel;\n  }\n\n  /**\n   * Obtains one or more guild channels from Discord, or the channel cache if they're already available.\n   *\n   * @param {Snowflake} [id] The channel's id\n   * @param {BaseFetchOptions} [options] Additional options for this fetch\n   * @returns {Promise<?GuildChannel|ThreadChannel|Collection<Snowflake, ?GuildChannel>>}\n   * @example\n   * // Fetch all channels from the guild (excluding threads)\n   * message.guild.channels.fetch()\n   *   .then(channels => console.log(`There are ${channels.size} channels.`))\n   *   .catch(console.error);\n   * @example\n   * // Fetch a single channel\n   * message.guild.channels.fetch('222197033908436994')\n   *   .then(channel => console.log(`The channel name is: ${channel.name}`))\n   *   .catch(console.error);\n   */\n  async fetch(id, { cache = true, force = false } = {}) {\n    if (id && !force) {\n      const existing = this.cache.get(id);\n      if (existing) return existing;\n    }\n\n    if (id) {\n      const innerData = await this.client.rest.get(Routes.channel(id));\n      // Since this is the guild manager, throw if on a different guild\n      if (this.guild.id !== innerData.guild_id) throw new DiscordjsError(ErrorCodes.GuildChannelUnowned);\n      return this.client.channels._add(innerData, this.guild, { cache });\n    }\n\n    const data = await this.client.rest.get(Routes.guildChannels(this.guild.id));\n    const channels = new Collection();\n    for (const channel of data) channels.set(channel.id, this.client.channels._add(channel, this.guild, { cache }));\n    return channels;\n  }\n\n  /**\n   * Fetches all webhooks for the channel.\n   *\n   * @param {GuildChannelResolvable} channel The channel to fetch webhooks for\n   * @returns {Promise<Collection<Snowflake, Webhook>>}\n   * @example\n   * // Fetch webhooks\n   * guild.channels.fetchWebhooks('769862166131245066')\n   *   .then(hooks => console.log(`This channel has ${hooks.size} hooks`))\n   *   .catch(console.error);\n   */\n  async fetchWebhooks(channel) {\n    const id = this.resolveId(channel);\n    if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');\n    const data = await this.client.rest.get(Routes.channelWebhooks(id));\n    return data.reduce((hooks, hook) => hooks.set(hook.id, new Webhook(this.client, hook)), new Collection());\n  }\n\n  /**\n   * Data that can be resolved to give a Category Channel object. This can be:\n   * - A CategoryChannel object\n   * - A Snowflake\n   *\n   * @typedef {CategoryChannel|Snowflake} CategoryChannelResolvable\n   */\n\n  /**\n   * The data needed for updating a channel's position.\n   *\n   * @typedef {Object} ChannelPosition\n   * @property {GuildChannel|Snowflake} channel Channel to update\n   * @property {number} [position] New position for the channel\n   * @property {CategoryChannelResolvable} [parent] Parent channel for this channel\n   * @property {boolean} [lockPermissions] If the overwrites should be locked to the parents overwrites\n   */\n\n  /**\n   * Batch-updates the guild's channels' positions.\n   * <info>Only one channel's parent can be changed at a time</info>\n   *\n   * @param {ChannelPosition[]} channelPositions Channel positions to update\n   * @returns {Promise<Guild>}\n   * @example\n   * guild.channels.setPositions([{ channel: channelId, position: newChannelIndex }])\n   *   .then(guild => console.log(`Updated channel positions for ${guild}`))\n   *   .catch(console.error);\n   */\n  async setPositions(channelPositions) {\n    const resolvedChannelPositions = channelPositions.map(channelPosition => ({\n      id: this.client.channels.resolveId(channelPosition.channel),\n      position: channelPosition.position,\n      lock_permissions: channelPosition.lockPermissions,\n      parent_id: channelPosition.parent === undefined ? undefined : this.resolveId(channelPosition.parent),\n    }));\n\n    await this.client.rest.patch(Routes.guildChannels(this.guild.id), { body: resolvedChannelPositions });\n\n    return this.client.actions.GuildChannelsPositionUpdate.handle({\n      guild_id: this.guild.id,\n      channels: resolvedChannelPositions,\n    }).guild;\n  }\n\n  /**\n   * Data returned from fetching threads.\n   *\n   * @typedef {Object} FetchedThreads\n   * @property {Collection<Snowflake, ThreadChannel>} threads The threads that were fetched\n   * @property {Collection<Snowflake, ThreadMember>} members The thread members in the received threads\n   */\n\n  /**\n   * Obtains all active thread channels in the guild.\n   *\n   * @param {boolean} [cache=true] Whether to cache the fetched data\n   * @returns {Promise<FetchedThreads>}\n   * @example\n   * // Fetch all threads from the guild\n   * message.guild.channels.fetchActiveThreads()\n   *   .then(fetched => console.log(`There are ${fetched.threads.size} threads.`))\n   *   .catch(console.error);\n   */\n  async fetchActiveThreads(cache = true) {\n    const data = await this.rawFetchGuildActiveThreads();\n    return GuildTextThreadManager._mapThreads(data, this.client, { guild: this.guild, cache });\n  }\n\n  /**\n   * `GET /guilds/{guild.id}/threads/active`\n   *\n   * @private\n   * @returns {Promise<RESTGetAPIGuildThreadsResult>}\n   */\n  async rawFetchGuildActiveThreads() {\n    return this.client.rest.get(Routes.guildActiveThreads(this.guild.id));\n  }\n\n  /**\n   * Deletes the channel.\n   *\n   * @param {GuildChannelResolvable} channel The channel to delete\n   * @param {string} [reason] Reason for deleting this channel\n   * @returns {Promise<void>}\n   * @example\n   * // Delete the channel\n   * guild.channels.delete('858850993013260338', 'making room for new channels')\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async delete(channel, reason) {\n    const id = this.resolveId(channel);\n    if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');\n    await this.client.rest.delete(Routes.channel(id), { reason });\n    this.client.actions.ChannelDelete.handle({ id });\n  }\n}\n\nexports.GuildChannelManager = GuildChannelManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/GuildEmojiManager.js",
    "content": "'use strict';\nconst { Collection } = require('@discordjs/collection');\nconst { Routes, PermissionFlagsBits } = require('discord-api-types/v10');\nconst { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { ApplicationEmoji } = require('../structures/ApplicationEmoji.js');\nconst { GuildEmoji } = require('../structures/GuildEmoji.js');\nconst { ReactionEmoji } = require('../structures/ReactionEmoji.js');\nconst { resolveImage } = require('../util/DataResolver.js');\nconst { parseEmoji } = require('../util/Util.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for GuildEmojis and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass GuildEmojiManager extends CachedManager {\n  constructor(guild, iterable) {\n    super(guild.client, GuildEmoji, iterable);\n\n    /**\n     * The guild this manager belongs to\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n  }\n\n  _add(data, cache) {\n    return super._add(data, cache, { extras: [this.guild] });\n  }\n\n  /**\n   * The cache of GuildEmojis\n   *\n   * @type {Collection<Snowflake, GuildEmoji>}\n   * @name GuildEmojiManager#cache\n   */\n\n  /**\n   * Data that can be resolved into a GuildEmoji object. This can be:\n   * - A Snowflake\n   * - A GuildEmoji object\n   * - A ReactionEmoji object\n   * - An ApplicationEmoji object\n   *\n   * @typedef {Snowflake|GuildEmoji|ReactionEmoji|ApplicationEmoji} EmojiResolvable\n   */\n\n  /**\n   * Resolves an EmojiResolvable to an Emoji object.\n   *\n   * @param {EmojiResolvable} emoji The Emoji resolvable to identify\n   * @returns {?GuildEmoji}\n   */\n  resolve(emoji) {\n    if (emoji instanceof ReactionEmoji) return super.cache.get(emoji.id) ?? null;\n    if (emoji instanceof ApplicationEmoji) return super.cache.get(emoji.id) ?? null;\n    return super.resolve(emoji);\n  }\n\n  /**\n   * Resolves an EmojiResolvable to an Emoji id string.\n   *\n   * @param {EmojiResolvable} emoji The Emoji resolvable to identify\n   * @returns {?Snowflake}\n   */\n  resolveId(emoji) {\n    if (emoji instanceof ReactionEmoji) return emoji.id;\n    if (emoji instanceof ApplicationEmoji) return emoji.id;\n    return super.resolveId(emoji);\n  }\n\n  /**\n   * Data that can be resolved to give an emoji identifier. This can be:\n   * - An EmojiResolvable\n   * - The `<a:name:id>`, `<:name:id>`, `a:name:id` or `name:id` emoji identifier string of an emoji\n   * - The Unicode representation of an emoji\n   *\n   * @typedef {string|EmojiResolvable} EmojiIdentifierResolvable\n   */\n\n  /**\n   * Resolves an EmojiResolvable to an emoji identifier.\n   *\n   * @param {EmojiIdentifierResolvable} emoji The emoji resolvable to resolve\n   * @returns {?string}\n   */\n  resolveIdentifier(emoji) {\n    const emojiResolvable = this.resolve(emoji);\n    if (emojiResolvable) return emojiResolvable.identifier;\n    if (emoji instanceof ReactionEmoji) return emoji.identifier;\n    if (emoji instanceof ApplicationEmoji) return emoji.identifier;\n    if (typeof emoji === 'string') {\n      const res = parseEmoji(emoji);\n      let identifier = emoji;\n      if (res?.name.length) {\n        identifier = `${res.animated ? 'a:' : ''}${res.name}${res.id ? `:${res.id}` : ''}`;\n      }\n\n      if (!identifier.includes('%')) return encodeURIComponent(identifier);\n      return identifier;\n    }\n\n    return null;\n  }\n\n  /**\n   * Options used for creating an emoji in a guild.\n   *\n   * @typedef {Object} GuildEmojiCreateOptions\n   * @property {BufferResolvable|Base64Resolvable} attachment The image for the emoji\n   * @property {string} name The name for the emoji\n   * @property {Collection<Snowflake, Role>|RoleResolvable[]} [roles] The roles to limit the emoji to\n   * @property {string} [reason] The reason for creating the emoji\n   */\n\n  /**\n   * Creates a new custom emoji in the guild.\n   *\n   * @param {GuildEmojiCreateOptions} options Options for creating the emoji\n   * @returns {Promise<Emoji>} The created emoji\n   * @example\n   * // Create a new emoji from a URL\n   * guild.emojis.create({ attachment: 'https://i.imgur.com/w3duR07.png', name: 'rip' })\n   *   .then(emoji => console.log(`Created new emoji with name ${emoji.name}!`))\n   *   .catch(console.error);\n   * @example\n   * // Create a new emoji from a file on your computer\n   * guild.emojis.create({ attachment: './memes/banana.png', name: 'banana' })\n   *   .then(emoji => console.log(`Created new emoji with name ${emoji.name}!`))\n   *   .catch(console.error);\n   */\n  async create({ attachment, name, roles, reason }) {\n    const image = await resolveImage(attachment);\n    if (!image) throw new DiscordjsTypeError(ErrorCodes.ReqResourceType);\n\n    const body = { image, name };\n    if (roles) {\n      if (!Array.isArray(roles) && !(roles instanceof Collection)) {\n        throw new DiscordjsTypeError(\n          ErrorCodes.InvalidType,\n          'options.roles',\n          'Array or Collection of Roles or Snowflakes',\n          true,\n        );\n      }\n\n      body.roles = [];\n      for (const role of roles.values()) {\n        const resolvedRole = this.guild.roles.resolveId(role);\n        if (!resolvedRole) {\n          throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'options.roles', role);\n        }\n\n        body.roles.push(resolvedRole);\n      }\n    }\n\n    const emoji = await this.client.rest.post(Routes.guildEmojis(this.guild.id), { body, reason });\n    return this.client.actions.GuildEmojiCreate.handle(this.guild, emoji).emoji;\n  }\n\n  /**\n   * Obtains one or more emojis from Discord, or the emoji cache if they're already available.\n   *\n   * @param {Snowflake} [id] The emoji's id\n   * @param {BaseFetchOptions} [options] Additional options for this fetch\n   * @returns {Promise<GuildEmoji|Collection<Snowflake, GuildEmoji>>}\n   * @example\n   * // Fetch all emojis from the guild\n   * message.guild.emojis.fetch()\n   *   .then(emojis => console.log(`There are ${emojis.size} emojis.`))\n   *   .catch(console.error);\n   * @example\n   * // Fetch a single emoji\n   * message.guild.emojis.fetch('222078108977594368')\n   *   .then(emoji => console.log(`The emoji name is: ${emoji.name}`))\n   *   .catch(console.error);\n   */\n  async fetch(id, { cache = true, force = false } = {}) {\n    if (id) {\n      if (!force) {\n        const existing = this.cache.get(id);\n        if (existing) return existing;\n      }\n\n      const emoji = await this.client.rest.get(Routes.guildEmoji(this.guild.id, id));\n      return this._add(emoji, cache);\n    }\n\n    const data = await this.client.rest.get(Routes.guildEmojis(this.guild.id));\n    const emojis = new Collection();\n    for (const emoji of data) emojis.set(emoji.id, this._add(emoji, cache));\n    return emojis;\n  }\n\n  /**\n   * Deletes an emoji.\n   *\n   * @param {EmojiResolvable} emoji The Emoji resolvable to delete\n   * @param {string} [reason] Reason for deleting the emoji\n   * @returns {Promise<void>}\n   */\n  async delete(emoji, reason) {\n    const id = this.resolveId(emoji);\n    if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'emoji', 'EmojiResolvable', true);\n    await this.client.rest.delete(Routes.guildEmoji(this.guild.id, id), { reason });\n  }\n\n  /**\n   * Edits an emoji.\n   *\n   * @param {EmojiResolvable} emoji The Emoji resolvable to edit\n   * @param {GuildEmojiEditOptions} options The options to provide\n   * @returns {Promise<GuildEmoji>}\n   */\n  async edit(emoji, options) {\n    const id = this.resolveId(emoji);\n    if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'emoji', 'EmojiResolvable', true);\n    const roles = options.roles?.map(role => this.guild.roles.resolveId(role));\n    const newData = await this.client.rest.patch(Routes.guildEmoji(this.guild.id, id), {\n      body: {\n        name: options.name,\n        roles,\n      },\n      reason: options.reason,\n    });\n    const existing = this.cache.get(id);\n    if (existing) {\n      const clone = existing._clone();\n      clone._patch(newData);\n      return clone;\n    }\n\n    return this._add(newData);\n  }\n\n  /**\n   * Fetches the author for this emoji\n   *\n   * @param {EmojiResolvable} emoji The emoji to fetch the author of\n   * @returns {Promise<User>}\n   */\n  async fetchAuthor(emoji) {\n    const resolvedEmoji = this.resolve(emoji);\n    if (!resolvedEmoji) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'emoji', 'EmojiResolvable', true);\n    if (resolvedEmoji.managed) {\n      throw new DiscordjsError(ErrorCodes.EmojiManaged);\n    }\n\n    const { me } = this.guild.members;\n    if (!me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe);\n    if (!me.permissions.any(PermissionFlagsBits.CreateGuildExpressions | PermissionFlagsBits.ManageGuildExpressions)) {\n      throw new DiscordjsError(ErrorCodes.MissingGuildExpressionsPermission, this.guild);\n    }\n\n    const data = await this.client.rest.get(Routes.guildEmoji(this.guild.id, resolvedEmoji.id));\n    resolvedEmoji._patch(data);\n    return resolvedEmoji.author;\n  }\n}\n\nexports.GuildEmojiManager = GuildEmojiManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/GuildEmojiRoleManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { Role } = require('../structures/Role.js');\nconst { DataManager } = require('./DataManager.js');\n\n/**\n * Manages API methods for roles belonging to emojis and stores their cache.\n *\n * @extends {DataManager}\n */\nclass GuildEmojiRoleManager extends DataManager {\n  constructor(emoji) {\n    super(emoji.client, Role);\n\n    /**\n     * The emoji belonging to this manager\n     *\n     * @type {GuildEmoji}\n     */\n    this.emoji = emoji;\n    /**\n     * The guild belonging to this manager\n     *\n     * @type {Guild}\n     */\n    this.guild = emoji.guild;\n  }\n\n  /**\n   * The cache of roles belonging to this emoji\n   *\n   * @type {Collection<Snowflake, Role>}\n   * @readonly\n   */\n  get cache() {\n    const cache = new Collection();\n    for (const roleId of this.emoji._roles) {\n      const role = this.guild.roles.cache.get(roleId);\n      if (role !== undefined) {\n        cache.set(roleId, role);\n      }\n    }\n\n    return cache;\n  }\n\n  /**\n   * Adds a role (or multiple roles) to the list of roles that can use this emoji.\n   *\n   * @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to add\n   * @returns {Promise<GuildEmoji>}\n   */\n  async add(roleOrRoles) {\n    const roles = Array.isArray(roleOrRoles) || roleOrRoles instanceof Collection ? roleOrRoles : [roleOrRoles];\n\n    const resolvedRoleIds = [];\n    for (const role of roles.values()) {\n      const roleId = this.guild.roles.resolveId(role);\n      if (!roleId) {\n        throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role);\n      }\n\n      resolvedRoleIds.push(roleId);\n    }\n\n    const newRoles = [...new Set(resolvedRoleIds.concat(...this.cache.keys()))];\n    return this.set(newRoles);\n  }\n\n  /**\n   * Removes a role (or multiple roles) from the list of roles that can use this emoji.\n   *\n   * @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to remove\n   * @returns {Promise<GuildEmoji>}\n   */\n  async remove(roleOrRoles) {\n    const roles = Array.isArray(roleOrRoles) || roleOrRoles instanceof Collection ? roleOrRoles : [roleOrRoles];\n\n    const resolvedRoleIds = [];\n    for (const role of roles.values()) {\n      const roleId = this.guild.roles.resolveId(role);\n      if (!roleId) {\n        throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role);\n      }\n\n      resolvedRoleIds.push(roleId);\n    }\n\n    const newRoles = [...this.cache.keys()].filter(id => !resolvedRoleIds.includes(id));\n    return this.set(newRoles);\n  }\n\n  /**\n   * Sets the role(s) that can use this emoji.\n   *\n   * @param {Collection<Snowflake, Role>|RoleResolvable[]} roles The roles or role ids to apply\n   * @returns {Promise<GuildEmoji>}\n   * @example\n   * // Set the emoji's roles to a single role\n   * guildEmoji.roles.set(['391156570408615936'])\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Remove all roles from an emoji\n   * guildEmoji.roles.set([])\n   *    .then(console.log)\n   *    .catch(console.error);\n   */\n  async set(roles) {\n    return this.emoji.edit({ roles });\n  }\n\n  clone() {\n    const clone = new this.constructor(this.emoji);\n    clone._patch([...this.cache.keys()]);\n    return clone;\n  }\n\n  /**\n   * Patches the roles for this manager's cache\n   *\n   * @param {Snowflake[]} roles The new roles\n   * @private\n   */\n  _patch(roles) {\n    this.emoji._roles = roles;\n  }\n\n  valueOf() {\n    return this.cache;\n  }\n}\n\nexports.GuildEmojiRoleManager = GuildEmojiRoleManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/GuildForumThreadManager.js",
    "content": "'use strict';\n\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { MessagePayload } = require('../structures/MessagePayload.js');\nconst { ThreadManager } = require('./ThreadManager.js');\n\n/**\n * Manages API methods for threads in forum channels and stores their cache.\n *\n * @extends {ThreadManager}\n */\nclass GuildForumThreadManager extends ThreadManager {\n  /**\n   * The channel this Manager belongs to\n   *\n   * @name GuildForumThreadManager#channel\n   * @type {ForumChannel}\n   */\n\n  /**\n   * @typedef {BaseMessageOptions} GuildForumThreadMessageCreateOptions\n   * @property {StickerResolvable} [stickers] The stickers to send with the message\n   * @property {BitFieldResolvable} [flags] The flags to send with the message\n   * <info>Only {@link MessageFlags.SuppressEmbeds}, {@link MessageFlags.SuppressNotifications}, and\n   * {@link MessageFlags.IsVoiceMessage} can be set.</info>\n   */\n\n  /**\n   * Options for creating a thread.\n   *\n   * @typedef {StartThreadOptions} GuildForumThreadCreateOptions\n   * @property {GuildForumThreadMessageCreateOptions|MessagePayload} message The message associated with the thread post\n   * @property {Snowflake[]} [appliedTags] The tags to apply to the thread\n   */\n\n  /**\n   * Creates a new thread in the channel.\n   *\n   * @param {GuildForumThreadCreateOptions} [options] Options to create a new thread\n   * @returns {Promise<ThreadChannel>}\n   * @example\n   * // Create a new forum post\n   * forum.threads\n   *   .create({\n   *     name: 'Food Talk',\n   *     autoArchiveDuration: ThreadAutoArchiveDuration.OneHour,\n   *     message: {\n   *      content: 'Discuss your favorite food!',\n   *     },\n   *     reason: 'Needed a separate thread for food',\n   *   })\n   *   .then(threadChannel => console.log(threadChannel))\n   *   .catch(console.error);\n   */\n  async create({\n    name,\n    autoArchiveDuration = this.channel.defaultAutoArchiveDuration,\n    message,\n    reason,\n    rateLimitPerUser,\n    appliedTags,\n  } = {}) {\n    if (!message) {\n      throw new DiscordjsTypeError(ErrorCodes.GuildForumMessageRequired);\n    }\n\n    const { body, files } = await (message instanceof MessagePayload ? message : MessagePayload.create(this, message))\n      .resolveBody()\n      .resolveFiles();\n\n    const data = await this.client.rest.post(Routes.threads(this.channel.id), {\n      body: {\n        name,\n        auto_archive_duration: autoArchiveDuration,\n        rate_limit_per_user: rateLimitPerUser,\n        applied_tags: appliedTags,\n        message: body,\n      },\n      files,\n      reason,\n    });\n\n    return this.client.actions.ThreadCreate.handle(data).thread;\n  }\n}\n\nexports.GuildForumThreadManager = GuildForumThreadManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/GuildInviteManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { GuildInvite } = require('../structures/GuildInvite.js');\nconst { resolveInviteCode } = require('../util/DataResolver.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for GuildInvites and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass GuildInviteManager extends CachedManager {\n  constructor(guild, iterable) {\n    super(guild.client, GuildInvite, iterable);\n\n    /**\n     * The guild this Manager belongs to\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n  }\n\n  /**\n   * The cache of this Manager\n   *\n   * @type {Collection<string, GuildInvite>}\n   * @name GuildInviteManager#cache\n   */\n\n  _add(data, cache) {\n    return super._add(data, cache, { id: data.code, extras: [this.guild] });\n  }\n\n  /**\n   * Data that resolves to give a `GuildInvite`. This can be:\n   *\n   * - An invite code\n   * - An invite URL\n   *\n   * @typedef {string} GuildInviteResolvable\n   */\n\n  /**\n   * A guild channel where an invite may be created on. This can be:\n   * - TextChannel\n   * - VoiceChannel\n   * - AnnouncementChannel\n   * - StageChannel\n   * - ForumChannel\n   * - MediaChannel\n   *\n   * @typedef {TextChannel|VoiceChannel|AnnouncementChannel|StageChannel|ForumChannel|MediaChannel}\n   * GuildInvitableChannel\n   */\n\n  /**\n   * Data that can be resolved to a guild channel where an invite may be created on. This can be:\n   * - GuildInvitableChannel\n   * - Snowflake\n   *\n   * @typedef {GuildInvitableChannel|Snowflake}\n   * GuildInvitableChannelResolvable\n   */\n\n  /**\n   * Resolves an `GuildInviteResolvable` to a `GuildInvite` object.\n   *\n   * @method resolve\n   * @memberof GuildInviteManager\n   * @instance\n   * @param {GuildInviteResolvable} invite The invite resolvable to resolve\n   * @returns {?GuildInvite}\n   */\n\n  /**\n   * Resolves an InviteResolvable to an invite code string.\n   *\n   * @method resolveId\n   * @memberof GuildInviteManager\n   * @instance\n   * @param {InviteResolvable} invite The invite resolvable to resolve\n   * @returns {?string}\n   */\n\n  /**\n   * Options used to fetch a single invite from a guild.\n   *\n   * @typedef {Object} FetchInviteOptions\n   * @property {InviteResolvable} code The invite to fetch\n   * @property {boolean} [cache=true] Whether or not to cache the fetched invite\n   * @property {boolean} [force=false] Whether to skip the cache check and request the API\n   */\n\n  /**\n   * Options used to fetch all invites from a guild.\n   *\n   * @typedef {Object} FetchInvitesOptions\n   * @property {GuildInvitableChannelResolvable} [channelId]\n   * The channel to fetch all invites from\n   * @property {boolean} [cache=true] Whether or not to cache the fetched invites\n   */\n\n  /**\n   * Fetches invite(s) from Discord.\n   *\n   * @param {GuildInviteResolvable|FetchInviteOptions|FetchInvitesOptions} [options]\n   * Options for fetching guild invite(s)\n   * @returns {Promise<GuildInvite|Collection<string, GuildInvite>>}\n   * @example\n   * // Fetch all invites from a guild\n   * guild.invites.fetch()\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Fetch all invites from a guild without caching\n   * guild.invites.fetch({ cache: false })\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Fetch all invites from a channel\n   * guild.invites.fetch({ channelId: '222197033908436994' })\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Fetch a single invite\n   * guild.invites.fetch('bRCvFy9')\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Fetch a single invite without checking cache\n   * guild.invites.fetch({ code: 'bRCvFy9', force: true })\n   *   .then(console.log)\n   *   .catch(console.error)\n   * @example\n   * // Fetch a single invite without caching\n   * guild.invites.fetch({ code: 'bRCvFy9', cache: false })\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async fetch(options) {\n    if (!options) return this._fetchMany();\n    if (typeof options === 'string') {\n      const code = resolveInviteCode(options);\n      if (!code) throw new DiscordjsError(ErrorCodes.InviteResolveCode);\n      return this._fetchSingle({ code, cache: true });\n    }\n\n    if (!options.code) {\n      if (options.channelId) {\n        const id = this.guild.channels.resolveId(options.channelId);\n        if (!id) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);\n        return this._fetchChannelMany(id, options.cache);\n      }\n\n      if ('cache' in options) return this._fetchMany(options.cache);\n      throw new DiscordjsError(ErrorCodes.InviteResolveCode);\n    }\n\n    return this._fetchSingle({\n      ...options,\n      code: resolveInviteCode(options.code),\n    });\n  }\n\n  async _fetchSingle({ code, cache, force = false }) {\n    if (!force) {\n      const existing = this.cache.get(code);\n      if (existing) return existing;\n    }\n\n    const invites = await this._fetchMany(cache);\n    const invite = invites.get(code);\n    if (!invite) throw new DiscordjsError(ErrorCodes.InviteNotFound);\n    return invite;\n  }\n\n  async _fetchMany(cache) {\n    const data = await this.client.rest.get(Routes.guildInvites(this.guild.id));\n    return data.reduce((col, invite) => col.set(invite.code, this._add(invite, cache)), new Collection());\n  }\n\n  async _fetchChannelMany(channelId, cache) {\n    const data = await this.client.rest.get(Routes.channelInvites(channelId));\n    return data.reduce((col, invite) => col.set(invite.code, this._add(invite, cache)), new Collection());\n  }\n\n  /**\n   * Create an invite to the guild from the provided channel.\n   *\n   * @param {GuildInvitableChannelResolvable} channel The options for creating the invite from a channel.\n   * @param {InviteCreateOptions} [options={}] The options for creating the invite from a channel.\n   * @returns {Promise<GuildInvite>}\n   * @example\n   * // Create an invite to a selected channel\n   * guild.invites.create('599942732013764608')\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async create(\n    channel,\n    { temporary, maxAge, maxUses, unique, targetUser, targetApplication, targetType, reason } = {},\n  ) {\n    const id = this.guild.channels.resolveId(channel);\n    if (!id) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);\n\n    const invite = await this.client.rest.post(Routes.channelInvites(id), {\n      body: {\n        temporary,\n        max_age: maxAge,\n        max_uses: maxUses,\n        unique,\n        target_user_id: this.client.users.resolveId(targetUser),\n        target_application_id: targetApplication?.id ?? targetApplication?.applicationId ?? targetApplication,\n        target_type: targetType,\n      },\n      reason,\n    });\n    return new GuildInvite(this.client, invite);\n  }\n\n  /**\n   * Deletes an invite.\n   *\n   * @param {InviteResolvable} invite The invite to delete\n   * @param {string} [reason] Reason for deleting the invite\n   * @returns {Promise<void>}\n   */\n  async delete(invite, reason) {\n    const code = resolveInviteCode(invite);\n\n    await this.client.rest.delete(Routes.invite(code), { reason });\n  }\n}\n\nexports.GuildInviteManager = GuildInviteManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/GuildManager.js",
    "content": "'use strict';\n\nconst process = require('node:process');\nconst { setTimeout, clearTimeout } = require('node:timers');\nconst { Collection } = require('@discordjs/collection');\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { GatewayOpcodes, Routes, RouteBases } = require('discord-api-types/v10');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { ShardClientUtil } = require('../sharding/ShardClientUtil.js');\nconst { Guild } = require('../structures/Guild.js');\nconst { GuildChannel } = require('../structures/GuildChannel.js');\nconst { GuildEmoji } = require('../structures/GuildEmoji.js');\nconst { GuildInvite } = require('../structures/GuildInvite.js');\nconst { GuildMember } = require('../structures/GuildMember.js');\nconst { OAuth2Guild } = require('../structures/OAuth2Guild.js');\nconst { Role } = require('../structures/Role.js');\nconst { Events } = require('../util/Events.js');\nconst { _transformAPIIncidentsData } = require('../util/Transformers.js');\nconst { CachedManager } = require('./CachedManager.js');\n\nlet cacheWarningEmitted = false;\n\n/**\n * Manages API methods for Guilds and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass GuildManager extends CachedManager {\n  constructor(client, iterable) {\n    super(client, Guild, iterable);\n    if (!cacheWarningEmitted && this._cache.constructor.name !== 'Collection') {\n      cacheWarningEmitted = true;\n      process.emitWarning(\n        `Overriding the cache handling for ${this.constructor.name} is unsupported and breaks functionality.`,\n        'UnsupportedCacheOverwriteWarning',\n      );\n    }\n  }\n\n  /**\n   * The cache of this Manager\n   *\n   * @type {Collection<Snowflake, Guild>}\n   * @name GuildManager#cache\n   */\n\n  /**\n   * Data that resolves to give a Guild object. This can be:\n   * - A Guild object\n   * - A GuildChannel object\n   * - A GuildEmoji object\n   * - A Role object\n   * - A Snowflake\n   * - An Invite object\n   *\n   * @typedef {Guild|GuildChannel|GuildMember|GuildEmoji|Role|Snowflake|Invite} GuildResolvable\n   */\n\n  /**\n   * Resolves a {@link GuildResolvable} to a {@link Guild} object.\n   *\n   * @method resolve\n   * @memberof GuildManager\n   * @instance\n   * @param {GuildResolvable} guild The guild resolvable to identify\n   * @returns {?Guild}\n   */\n  resolve(guild) {\n    if (\n      guild instanceof GuildChannel ||\n      guild instanceof GuildMember ||\n      guild instanceof GuildEmoji ||\n      guild instanceof Role ||\n      (guild instanceof GuildInvite && guild.guild)\n    ) {\n      return super.resolve(guild.guild);\n    }\n\n    return super.resolve(guild);\n  }\n\n  /**\n   * Resolves a {@link GuildResolvable} to a {@link Guild} id string.\n   *\n   * @method resolveId\n   * @memberof GuildManager\n   * @instance\n   * @param {GuildResolvable} guild The guild resolvable to identify\n   * @returns {?Snowflake}\n   */\n  resolveId(guild) {\n    if (\n      guild instanceof GuildChannel ||\n      guild instanceof GuildMember ||\n      guild instanceof GuildEmoji ||\n      guild instanceof Role ||\n      (guild instanceof GuildInvite && guild.guild)\n    ) {\n      return super.resolveId(guild.guild.id);\n    }\n\n    return super.resolveId(guild);\n  }\n\n  /**\n   * Options used to fetch a single guild.\n   *\n   * @typedef {BaseFetchOptions} FetchGuildOptions\n   * @property {GuildResolvable} guild The guild to fetch\n   * @property {boolean} [withCounts=true] Whether the approximate member and presence counts should be returned\n   */\n\n  /**\n   * Options used to fetch multiple guilds.\n   *\n   * @typedef {Object} FetchGuildsOptions\n   * @property {Snowflake} [before] Get guilds before this guild id\n   * @property {Snowflake} [after] Get guilds after this guild id\n   * @property {number} [limit] Maximum number of guilds to request (1-200)\n   */\n\n  /**\n   * Obtains one or multiple guilds from Discord, or the guild cache if it's already available.\n   *\n   * @param {GuildResolvable|FetchGuildOptions|FetchGuildsOptions} [options] The guild's id or options\n   * @returns {Promise<Guild|Collection<Snowflake, OAuth2Guild>>}\n   */\n  async fetch(options = {}) {\n    const id = this.resolveId(options) ?? this.resolveId(options.guild);\n\n    if (id) {\n      if (!options.force) {\n        const existing = this.cache.get(id);\n        if (existing) return existing;\n      }\n\n      const innerData = await this.client.rest.get(Routes.guild(id), {\n        query: makeURLSearchParams({ with_counts: options.withCounts ?? true }),\n      });\n      innerData.shardId = ShardClientUtil.shardIdForGuildId(id, await this.client.ws.fetchShardCount());\n      return this._add(innerData, options.cache);\n    }\n\n    const data = await this.client.rest.get(Routes.userGuilds(), { query: makeURLSearchParams(options) });\n    return data.reduce((coll, guild) => coll.set(guild.id, new OAuth2Guild(this.client, guild)), new Collection());\n  }\n\n  /**\n   * @typedef {Object} FetchSoundboardSoundsOptions\n   * @property {Snowflake[]} guildIds The ids of the guilds to fetch soundboard sounds for\n   * @property {number} [time=10_000] The timeout for receipt of the soundboard sounds\n   */\n\n  /**\n   * Fetches soundboard sounds for the specified guilds.\n   *\n   * @param {FetchSoundboardSoundsOptions} options The options for fetching soundboard sounds\n   * @returns {Promise<Collection<Snowflake, Collection<Snowflake, SoundboardSound>>>}\n   * @example\n   * // Fetch soundboard sounds for multiple guilds\n   * const soundboardSounds = await client.guilds.fetchSoundboardSounds({\n   *  guildIds: ['123456789012345678', '987654321098765432'],\n   * })\n   *\n   * console.log(soundboardSounds.get('123456789012345678'));\n   */\n  async fetchSoundboardSounds({ guildIds, time = 10_000 }) {\n    const shardCount = await this.client.ws.getShardCount();\n    const shardIds = Map.groupBy(guildIds, guildId => ShardClientUtil.shardIdForGuildId(guildId, shardCount));\n\n    for (const [shardId, shardGuildIds] of shardIds) {\n      this.client.ws.send(shardId, {\n        op: GatewayOpcodes.RequestSoundboardSounds,\n        // eslint-disable-next-line id-length\n        d: {\n          guild_ids: shardGuildIds,\n        },\n      });\n    }\n\n    return new Promise((resolve, reject) => {\n      const remainingGuildIds = new Set(guildIds);\n\n      const fetchedSoundboardSounds = new Collection();\n\n      const handler = (soundboardSounds, guild) => {\n        // eslint-disable-next-line no-use-before-define\n        timeout.refresh();\n\n        if (!remainingGuildIds.has(guild.id)) return;\n\n        fetchedSoundboardSounds.set(guild.id, soundboardSounds);\n\n        remainingGuildIds.delete(guild.id);\n\n        if (remainingGuildIds.size === 0) {\n          // eslint-disable-next-line no-use-before-define\n          clearTimeout(timeout);\n          this.client.removeListener(Events.SoundboardSounds, handler);\n          this.client.decrementMaxListeners();\n\n          resolve(fetchedSoundboardSounds);\n        }\n      };\n\n      const timeout = setTimeout(() => {\n        this.client.removeListener(Events.SoundboardSounds, handler);\n        this.client.decrementMaxListeners();\n        reject(new DiscordjsError(ErrorCodes.GuildSoundboardSoundsTimeout));\n      }, time).unref();\n\n      this.client.incrementMaxListeners();\n      this.client.on(Events.SoundboardSounds, handler);\n    });\n  }\n\n  /**\n   * Options used to set incident actions. Supplying `null` to any option will disable the action.\n   *\n   * @typedef {Object} IncidentActionsEditOptions\n   * @property {?DateResolvable} [invitesDisabledUntil] When invites should be enabled again\n   * @property {?DateResolvable} [dmsDisabledUntil] When direct messages should be enabled again\n   */\n\n  /**\n   * Sets the incident actions for a guild.\n   *\n   * @param {GuildResolvable} guild The guild\n   * @param {IncidentActionsEditOptions} incidentActions The incident actions to set\n   * @returns {Promise<IncidentActions>}\n   */\n  async setIncidentActions(guild, { invitesDisabledUntil, dmsDisabledUntil }) {\n    const guildId = this.resolveId(guild);\n\n    const data = await this.client.rest.put(Routes.guildIncidentActions(guildId), {\n      body: {\n        invites_disabled_until: invitesDisabledUntil && new Date(invitesDisabledUntil).toISOString(),\n        dms_disabled_until: dmsDisabledUntil && new Date(dmsDisabledUntil).toISOString(),\n      },\n    });\n\n    const parsedData = _transformAPIIncidentsData(data);\n    const resolvedGuild = this.resolve(guild);\n\n    if (resolvedGuild) {\n      resolvedGuild.incidentsData = parsedData;\n    }\n\n    return parsedData;\n  }\n\n  /**\n   * Returns a URL for the PNG widget of a guild.\n   *\n   * @param {GuildResolvable} guild The guild of the widget image\n   * @param {GuildWidgetStyle} [style] The style for the widget image\n   * @returns {string}\n   */\n  widgetImageURL(guild, style) {\n    const urlSearchParams = String(makeURLSearchParams({ style }));\n\n    return `${RouteBases.api}${Routes.guildWidgetImage(this.resolveId(guild))}${\n      urlSearchParams ? `?${urlSearchParams}` : ''\n    }`;\n  }\n}\n\nexports.GuildManager = GuildManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/GuildMemberManager.js",
    "content": "'use strict';\n\nconst { setTimeout, clearTimeout } = require('node:timers');\nconst { Collection } = require('@discordjs/collection');\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { GatewayRateLimitError } = require('@discordjs/util');\nconst { WebSocketShardEvents } = require('@discordjs/ws');\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { Routes, GatewayOpcodes, GatewayDispatchEvents } = require('discord-api-types/v10');\nconst { DiscordjsError, DiscordjsTypeError, DiscordjsRangeError, ErrorCodes } = require('../errors/index.js');\nconst { BaseGuildVoiceChannel } = require('../structures/BaseGuildVoiceChannel.js');\nconst { GuildMember } = require('../structures/GuildMember.js');\nconst { Role } = require('../structures/Role.js');\nconst { resolveImage } = require('../util/DataResolver.js');\nconst { Events } = require('../util/Events.js');\nconst { GuildMemberFlagsBitField } = require('../util/GuildMemberFlagsBitField.js');\nconst { Partials } = require('../util/Partials.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for GuildMembers and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass GuildMemberManager extends CachedManager {\n  constructor(guild, iterable) {\n    super(guild.client, GuildMember, iterable);\n\n    /**\n     * The guild this manager belongs to\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n  }\n\n  /**\n   * The cache of this Manager\n   *\n   * @type {Collection<Snowflake, GuildMember>}\n   * @name GuildMemberManager#cache\n   */\n\n  _add(data, cache = true) {\n    return super._add(data, cache, { id: data.user.id, extras: [this.guild] });\n  }\n\n  /**\n   * Resolves a {@link UserResolvable} to a {@link GuildMember} object.\n   *\n   * @param {UserResolvable} member The user that is part of the guild\n   * @returns {?GuildMember}\n   */\n  resolve(member) {\n    const memberResolvable = super.resolve(member);\n    if (memberResolvable) return memberResolvable;\n    const userResolvable = this.client.users.resolveId(member);\n    if (userResolvable) return super.cache.get(userResolvable) ?? null;\n    return null;\n  }\n\n  /**\n   * Resolves a {@link UserResolvable} to a member id.\n   *\n   * @param {UserResolvable} member The user that is part of the guild\n   * @returns {?Snowflake}\n   */\n  resolveId(member) {\n    const memberResolvable = super.resolveId(member);\n    if (memberResolvable) return memberResolvable;\n    const userResolvable = this.client.users.resolveId(member);\n    return this.cache.has(userResolvable) ? userResolvable : null;\n  }\n\n  /**\n   * Options used to add a user to a guild using OAuth2.\n   *\n   * @typedef {Object} AddGuildMemberOptions\n   * @property {string} accessToken An OAuth2 access token for the user with the {@link OAuth2Scopes.GuildsJoin}\n   * scope granted to the bot's application\n   * @property {string} [nick] The nickname to give to the member\n   * <info>This property requires the {@link PermissionFlagsBits.ManageNicknames} permission.</info>\n   * @property {Collection<Snowflake, Role>|RoleResolvable[]} [roles] The roles to add to the member\n   * <info>This property requires the {@link PermissionFlagsBits.ManageRoles} permission.</info>\n   * @property {boolean} [mute] Whether the member should be muted\n   * <info>This property requires the {@link PermissionFlagsBits.MuteMembers} permission.</info>\n   * @property {boolean} [deaf] Whether the member should be deafened\n   * <info>This property requires the {@link PermissionFlagsBits.MuteMembers} permission.</info>\n   * @property {boolean} [force] Whether to skip the cache check and request the API directly\n   * @property {boolean} [fetchWhenExisting=true] Whether to fetch the user if not cached and already a member\n   */\n\n  /**\n   * Adds a user to the guild using OAuth2.\n   * <info>This method requires the {@link PermissionFlagsBits.CreateInstantInvite} permission.\n   *\n   * @param {UserResolvable} user The user to add to the guild\n   * @param {AddGuildMemberOptions} options Options for adding the user to the guild\n   * @returns {Promise<?GuildMember>}\n   */\n  async add(user, options) {\n    const userId = this.client.users.resolveId(user);\n    if (!userId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'user', 'UserResolvable');\n    if (!options.force) {\n      const cachedUser = this.cache.get(userId);\n      if (cachedUser) return cachedUser;\n    }\n\n    const resolvedOptions = {\n      access_token: options.accessToken,\n      nick: options.nick,\n      mute: options.mute,\n      deaf: options.deaf,\n    };\n    if (options.roles) {\n      if (!Array.isArray(options.roles) && !(options.roles instanceof Collection)) {\n        throw new DiscordjsTypeError(\n          ErrorCodes.InvalidType,\n          'options.roles',\n          'Array or Collection of Roles or Snowflakes',\n          true,\n        );\n      }\n\n      const resolvedRoles = [];\n      for (const role of options.roles.values()) {\n        const resolvedRole = this.guild.roles.resolveId(role);\n        if (!resolvedRole) {\n          throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'options.roles', role);\n        }\n\n        resolvedRoles.push(resolvedRole);\n      }\n\n      resolvedOptions.roles = resolvedRoles;\n    }\n\n    const data = await this.client.rest.put(Routes.guildMember(this.guild.id, userId), { body: resolvedOptions });\n\n    // Data is an empty array buffer if the member is already part of the guild.\n    return data instanceof ArrayBuffer\n      ? options.fetchWhenExisting === false\n        ? null\n        : this.fetch(userId)\n      : this._add(data);\n  }\n\n  /**\n   * The client user as a GuildMember of this guild\n   *\n   * @type {?GuildMember}\n   * @readonly\n   */\n  get me() {\n    return (\n      this.cache.get(this.client.user.id) ??\n      (this.client.options.partials.includes(Partials.GuildMember)\n        ? this._add({ user: { id: this.client.user.id } }, true)\n        : null)\n    );\n  }\n\n  /**\n   * Options used to fetch a single member from a guild.\n   *\n   * @typedef {BaseFetchOptions} FetchMemberOptions\n   * @property {UserResolvable} user The user to fetch\n   */\n\n  /**\n   * Options used to fetch multiple members from a guild.\n   *\n   * @typedef {Object} FetchMembersOptions\n   * @property {UserResolvable|UserResolvable[]} [user] The user(s) to fetch\n   * @property {?string} [query] Limit fetch to members with similar usernames\n   * @property {number} [limit=0] Maximum number of members to request\n   * @property {boolean} [withPresences=false] Whether to include the presences\n   * @property {number} [time=120e3] Timeout for receipt of members\n   * @property {?string} [nonce] Nonce for this request (32 characters max - default to base 16 now timestamp)\n   */\n\n  /**\n   * Fetches member(s) from a guild.\n   *\n   * @param {UserResolvable|FetchMemberOptions|FetchMembersOptions} [options] Options for fetching member(s).\n   * Omitting the parameter or providing `undefined` will fetch all members.\n   * @returns {Promise<GuildMember|Collection<Snowflake, GuildMember>>}\n   * @example\n   * // Fetch all members from a guild\n   * guild.members.fetch()\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Fetch a single member\n   * guild.members.fetch('66564597481480192')\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Fetch a single member without checking cache\n   * guild.members.fetch({ user, force: true })\n   *   .then(console.log)\n   *   .catch(console.error)\n   * @example\n   * // Fetch a single member without caching\n   * guild.members.fetch({ user, cache: false })\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Fetch by an array of users including their presences\n   * guild.members.fetch({ user: ['66564597481480192', '191615925336670208'], withPresences: true })\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Fetch by query\n   * guild.members.fetch({ query: 'hydra', limit: 1 })\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async fetch(options) {\n    if (!options) return this._fetchMany();\n    const { user: users, limit, withPresences, cache, force } = options;\n    const resolvedUser = this.client.users.resolveId(users ?? options);\n    if (resolvedUser && !limit && !withPresences) return this._fetchSingle({ user: resolvedUser, cache, force });\n    const resolvedUsers = users?.map?.(user => this.client.users.resolveId(user)) ?? resolvedUser ?? undefined;\n    return this._fetchMany({ ...options, users: resolvedUsers });\n  }\n\n  async _fetchSingle({ user, cache, force = false }) {\n    if (!force) {\n      const existing = this.cache.get(user);\n      if (existing && !existing.partial) return existing;\n    }\n\n    const data = await this.client.rest.get(Routes.guildMember(this.guild.id, user));\n    return this._add(data, cache);\n  }\n\n  async _fetchMany({\n    limit = 0,\n    withPresences: presences,\n    users,\n    query: initialQuery,\n    time = 120e3,\n    nonce = DiscordSnowflake.generate().toString(),\n  } = {}) {\n    if (nonce.length > 32) throw new DiscordjsRangeError(ErrorCodes.MemberFetchNonceLength);\n\n    const query = initialQuery ?? (users ? undefined : '');\n\n    return new Promise((resolve, reject) => {\n      const fetchedMembers = new Collection();\n      let index = 0;\n\n      const cleanup = () => {\n        /* eslint-disable no-use-before-define */\n        clearTimeout(timeout);\n\n        this.client.ws.removeListener(WebSocketShardEvents.Dispatch, rateLimitHandler);\n        this.client.removeListener(Events.GuildMembersChunk, handler);\n        this.client.decrementMaxListeners();\n        /* eslint-enable no-use-before-define */\n      };\n\n      const timeout = setTimeout(() => {\n        cleanup();\n        reject(new DiscordjsError(ErrorCodes.GuildMembersTimeout));\n      }, time).unref();\n\n      const handler = (members, _, chunk) => {\n        if (chunk.nonce !== nonce) return;\n\n        timeout.refresh();\n        index++;\n        for (const member of members.values()) {\n          fetchedMembers.set(member.id, member);\n        }\n\n        if (members.size < 1_000 || (limit && fetchedMembers.size >= limit) || index === chunk.count) {\n          cleanup();\n          resolve(users && !Array.isArray(users) && fetchedMembers.size ? fetchedMembers.first() : fetchedMembers);\n        }\n      };\n\n      const requestData = {\n        guild_id: this.guild.id,\n        presences,\n        user_ids: users,\n        query,\n        nonce,\n        limit,\n      };\n\n      const rateLimitHandler = payload => {\n        if (payload.t === GatewayDispatchEvents.RateLimited && payload.d.meta.nonce === nonce) {\n          cleanup();\n          reject(new GatewayRateLimitError(payload.d, requestData));\n        }\n      };\n\n      this.client.ws.on(WebSocketShardEvents.Dispatch, rateLimitHandler);\n\n      this.client.incrementMaxListeners();\n      this.client.on(Events.GuildMembersChunk, handler);\n\n      this.guild.client.ws.send(this.guild.shardId, {\n        op: GatewayOpcodes.RequestGuildMembers,\n        // eslint-disable-next-line id-length\n        d: requestData,\n      });\n    });\n  }\n\n  /**\n   * Fetches the client user as a GuildMember of the guild.\n   *\n   * @param {BaseFetchOptions} [options] The options for fetching the member\n   * @returns {Promise<GuildMember>}\n   */\n  async fetchMe(options) {\n    return this.fetch({ ...options, user: this.client.user.id });\n  }\n\n  /**\n   * Options used for searching guild members.\n   *\n   * @typedef {Object} GuildSearchMembersOptions\n   * @property {string} query Filter members whose username or nickname start with this query\n   * @property {number} [limit] Maximum number of members to search\n   * @property {boolean} [cache=true] Whether or not to cache the fetched member(s)\n   */\n\n  /**\n   * Searches for members in the guild based on a query.\n   *\n   * @param {GuildSearchMembersOptions} options Options for searching members\n   * @returns {Promise<Collection<Snowflake, GuildMember>>}\n   */\n  async search({ query, limit, cache = true } = {}) {\n    const data = await this.client.rest.get(Routes.guildMembersSearch(this.guild.id), {\n      query: makeURLSearchParams({ query, limit }),\n    });\n    return data.reduce((col, member) => col.set(member.user.id, this._add(member, cache)), new Collection());\n  }\n\n  /**\n   * Options used for listing guild members.\n   *\n   * @typedef {Object} GuildListMembersOptions\n   * @property {Snowflake} [after] Limit fetching members to those with an id greater than the supplied id\n   * @property {number} [limit] Maximum number of members to list\n   * @property {boolean} [cache=true] Whether or not to cache the fetched member(s)\n   */\n\n  /**\n   * Lists up to 1000 members of the guild.\n   *\n   * @param {GuildListMembersOptions} [options] Options for listing members\n   * @returns {Promise<Collection<Snowflake, GuildMember>>}\n   */\n  async list({ after, limit, cache = true } = {}) {\n    const query = makeURLSearchParams({ limit, after });\n    const data = await this.client.rest.get(Routes.guildMembers(this.guild.id), { query });\n    return data.reduce((col, member) => col.set(member.user.id, this._add(member, cache)), new Collection());\n  }\n\n  /**\n   * The data for editing a guild member.\n   *\n   * @typedef {Object} GuildMemberEditOptions\n   * @property {?string} [nick] The nickname to set for the member\n   * @property {Collection<Snowflake, Role>|RoleResolvable[]} [roles] The roles or role ids to apply\n   * @property {boolean} [mute] Whether or not the member should be muted\n   * @property {boolean} [deaf] Whether or not the member should be deafened\n   * @property {?GuildVoiceChannelResolvable} [channel] Channel to move the member to\n   * (if they are connected to voice), or `null` if you want to disconnect them from voice\n   * @property {?DateResolvable} [communicationDisabledUntil] The date or timestamp\n   * for the member's communication to be disabled until. Provide `null` to enable communication again.\n   * @property {GuildMemberFlagsResolvable} [flags] The flags to set for the member\n   * @property {string} [reason] Reason for editing this user\n   */\n\n  /**\n   * Edits a member of a guild.\n   *\n   * @param {UserResolvable} user The member to edit\n   * @param {GuildMemberEditOptions} options The options to provide\n   * @returns {Promise<GuildMember>}\n   */\n  async edit(user, { reason, ...options }) {\n    const id = this.client.users.resolveId(user);\n    if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'user', 'UserResolvable');\n\n    if (options.channel) {\n      options.channel = this.guild.channels.resolve(options.channel);\n      if (!(options.channel instanceof BaseGuildVoiceChannel)) {\n        throw new DiscordjsError(ErrorCodes.GuildVoiceChannelResolve);\n      }\n\n      options.channel_id = options.channel.id;\n      options.channel = undefined;\n    } else if (options.channel === null) {\n      options.channel_id = null;\n      options.channel = undefined;\n    }\n\n    options.roles &&= options.roles.map(role => (role instanceof Role ? role.id : role));\n\n    if (options.communicationDisabledUntil !== undefined) {\n      options.communication_disabled_until =\n        // eslint-disable-next-line eqeqeq\n        options.communicationDisabledUntil == null\n          ? options.communicationDisabledUntil\n          : new Date(options.communicationDisabledUntil).toISOString();\n    }\n\n    if (options.flags !== undefined) {\n      options.flags = GuildMemberFlagsBitField.resolve(options.flags);\n    }\n\n    const data = await this.client.rest.patch(Routes.guildMember(this.guild.id, id), { body: options, reason });\n    const clone = this.cache.get(id)?._clone();\n    clone?._patch(data);\n    return clone ?? this._add(data, false);\n  }\n\n  /**\n   * The data for editing the current application's guild member.\n   *\n   * @typedef {Object} GuildMemberEditMeOptions\n   * @property {?string} [nick] The nickname to set\n   * @property {?(BufferResolvable|Base64Resolvable)} [banner] The banner to set\n   * @property {?(BufferResolvable|Base64Resolvable)} [avatar] The avatar to set\n   * @property {?string} [bio] The bio to set\n   * @property {string} [reason] The reason to use\n   */\n\n  /**\n   * Edits the current application's guild member in a guild.\n   *\n   * @param {GuildMemberEditMeOptions} options The options to provide\n   * @returns {Promise<GuildMember>}\n   */\n  async editMe({ reason, ...options }) {\n    const data = await this.client.rest.patch(Routes.guildMember(this.guild.id, '@me'), {\n      body: {\n        ...options,\n        banner: options.banner && (await resolveImage(options.banner)),\n        avatar: options.avatar && (await resolveImage(options.avatar)),\n      },\n      reason,\n    });\n\n    const clone = this.me?._clone();\n    clone?._patch(data);\n    return clone ?? this._add(data, false);\n  }\n\n  /**\n   * Options used for pruning guild members.\n   * <info>It's recommended to set {@link GuildPruneMembersOptions#count options.count}\n   * to `false` for large guilds.</info>\n   *\n   * @typedef {Object} GuildPruneMembersOptions\n   * @property {number} [days] Number of days of inactivity required to kick\n   * @property {boolean} [dry=false] Get the number of users that will be kicked, without actually kicking them\n   * @property {boolean} [count] Whether or not to return the number of users that have been kicked.\n   * @property {RoleResolvable[]} [roles] Array of roles to bypass the \"...and no roles\" constraint when pruning\n   * @property {string} [reason] Reason for this prune\n   */\n\n  /**\n   * Prunes members from the guild based on how long they have been inactive.\n   *\n   * @param {GuildPruneMembersOptions} [options] Options for pruning\n   * @returns {Promise<?number>} The number of members that were/will be kicked\n   * @example\n   * // See how many members will be pruned\n   * guild.members.prune({ dry: true })\n   *   .then(pruned => console.log(`This will prune ${pruned} people!`))\n   *   .catch(console.error);\n   * @example\n   * // Actually prune the members\n   * guild.members.prune({ days: 1, reason: 'too many people!' })\n   *   .then(pruned => console.log(`I just pruned ${pruned} people!`))\n   *   .catch(console.error);\n   * @example\n   * // Include members with a specified role\n   * guild.members.prune({ days: 7, roles: ['657259391652855808'] })\n   *    .then(pruned => console.log(`I just pruned ${pruned} people!`))\n   *    .catch(console.error);\n   */\n  async prune({ days, dry = false, count: compute_prune_count, roles = [], reason } = {}) {\n    if (typeof days !== 'number') throw new DiscordjsTypeError(ErrorCodes.PruneDaysType);\n\n    const query = { days };\n    const resolvedRoles = [];\n\n    for (const role of roles) {\n      const resolvedRole = this.guild.roles.resolveId(role);\n      if (!resolvedRole) {\n        throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array', 'options.roles', role);\n      }\n\n      resolvedRoles.push(resolvedRole);\n    }\n\n    if (resolvedRoles.length) {\n      query.include_roles = dry ? resolvedRoles.join(',') : resolvedRoles;\n    }\n\n    const endpoint = Routes.guildPrune(this.guild.id);\n\n    const { pruned } = await (dry\n      ? this.client.rest.get(endpoint, { query: makeURLSearchParams(query), reason })\n      : this.client.rest.post(endpoint, { body: { ...query, compute_prune_count }, reason }));\n\n    return pruned;\n  }\n\n  /**\n   * Kicks a user from the guild.\n   * <info>The user must be a member of the guild</info>\n   *\n   * @param {UserResolvable} user The member to kick\n   * @param {string} [reason] Reason for kicking\n   * @returns {Promise<void>}\n   * @example\n   * // Kick a user by id (or with a user/guild member object)\n   * await guild.members.kick('84484653687267328');\n   */\n  async kick(user, reason) {\n    const id = this.client.users.resolveId(user);\n    if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'user', 'UserResolvable');\n\n    await this.client.rest.delete(Routes.guildMember(this.guild.id, id), { reason });\n  }\n\n  /**\n   * Bans a user from the guild. Internally calls the {@link GuildBanManager#create} method.\n   *\n   * @param {UserResolvable} user The user to ban\n   * @param {BanOptions} [options] Options for the ban\n   * @returns {Promise<void>}\n   * @example\n   * // Ban a user by id (or with a user/guild member object)\n   * await guild.members.ban('84484653687267328');\n   */\n  async ban(user, options) {\n    await this.guild.bans.create(user, options);\n  }\n\n  /**\n   * Unbans a user from the guild. Internally calls the {@link GuildBanManager#remove} method.\n   *\n   * @param {UserResolvable} user The user to unban\n   * @param {string} [reason] Reason for unbanning user\n   * @returns {Promise<void>}\n   * @example\n   * // Unban a user by id (or with a user/guild member object)\n   * await guild.members.unban('84484653687267328');\n   */\n  async unban(user, reason) {\n    await this.guild.bans.remove(user, reason);\n  }\n\n  /**\n   * Bulk ban users from a guild, and optionally delete previous messages sent by them.\n   *\n   * @param {Collection<Snowflake, UserResolvable>|UserResolvable[]} users The users to ban\n   * @param {BanOptions} [options] The options for bulk banning users\n   * @returns {Promise<BulkBanResult>} Returns an object with `bannedUsers` key containing the IDs of the banned users\n   * and the key `failedUsers` with the IDs that could not be banned or were already banned.\n   * Internally calls the GuildBanManager#bulkCreate method.\n   * @example\n   * // Bulk ban users by ids (or with user/guild member objects) and delete all their messages from the past 7 days\n   * guild.members.bulkBan(['84484653687267328'], { deleteMessageSeconds: 7 * 24 * 60 * 60 })\n   *   .then(result => {\n   *     console.log(`Banned ${result.bannedUsers.length} users, failed to ban ${result.failedUsers.length} users.`)\n   *   })\n   *   .catch(console.error);\n   */\n  async bulkBan(users, options = {}) {\n    return this.guild.bans.bulkCreate(users, options);\n  }\n\n  /**\n   * Options used for adding or removing a role from a member.\n   *\n   * @typedef {Object} AddOrRemoveGuildMemberRoleOptions\n   * @property {UserResolvable} user The user to add/remove the role from\n   * @property {RoleResolvable} role The role to add/remove\n   * @property {string} [reason] Reason for adding/removing the role\n   */\n\n  /**\n   * Adds a role to a member.\n   *\n   * @param {AddOrRemoveGuildMemberRoleOptions} options Options for adding the role\n   * @returns {Promise<void>}\n   */\n  async addRole(options) {\n    const { user, role, reason } = options;\n    const userId = this.resolveId(user);\n    const roleId = this.guild.roles.resolveId(role);\n    await this.client.rest.put(Routes.guildMemberRole(this.guild.id, userId, roleId), { reason });\n  }\n\n  /**\n   * Removes a role from a member.\n   *\n   * @param {AddOrRemoveGuildMemberRoleOptions} options Options for removing the role\n   * @returns {Promise<void>}\n   */\n  async removeRole(options) {\n    const { user, role, reason } = options;\n    const userId = this.resolveId(user);\n    const roleId = this.guild.roles.resolveId(role);\n    await this.client.rest.delete(Routes.guildMemberRole(this.guild.id, userId, roleId), { reason });\n  }\n}\n\nexports.GuildMemberManager = GuildMemberManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/GuildMemberRoleManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { Role } = require('../structures/Role.js');\nconst { DataManager } = require('./DataManager.js');\n\n/**\n * Manages API methods for roles of a GuildMember and stores their cache.\n *\n * @extends {DataManager}\n */\nclass GuildMemberRoleManager extends DataManager {\n  constructor(member) {\n    super(member.client, Role);\n\n    /**\n     * The GuildMember this manager belongs to\n     *\n     * @type {GuildMember}\n     */\n    this.member = member;\n\n    /**\n     * The Guild this manager belongs to\n     *\n     * @type {Guild}\n     */\n    this.guild = member.guild;\n  }\n\n  /**\n   * The roles of this member\n   *\n   * @type {Collection<Snowflake, Role>}\n   * @readonly\n   */\n  get cache() {\n    const cache = new Collection();\n    cache.set(this.guild.id, this.guild.roles.everyone);\n\n    for (const roleId of this.member._roles) {\n      const role = this.guild.roles.cache.get(roleId);\n      if (role !== undefined) {\n        cache.set(roleId, role);\n      }\n    }\n\n    return cache;\n  }\n\n  /**\n   * The role of the member used to hoist them in a separate category in the users list\n   *\n   * @type {?Role}\n   * @readonly\n   */\n  get hoist() {\n    const hoistedRoles = this.cache.filter(role => role.hoist);\n    if (!hoistedRoles.size) return null;\n    return hoistedRoles.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev));\n  }\n\n  /**\n   * The role of the member used to set their role icon\n   *\n   * @type {?Role}\n   * @readonly\n   */\n  get icon() {\n    const iconRoles = this.cache.filter(role => role.icon ?? role.unicodeEmoji);\n    if (!iconRoles.size) return null;\n    return iconRoles.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev));\n  }\n\n  /**\n   * The role of the member used to set their color\n   *\n   * @type {?Role}\n   * @readonly\n   */\n  get color() {\n    const coloredRoles = this.cache.filter(role => role.colors.primaryColor);\n    if (!coloredRoles.size) return null;\n    return coloredRoles.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev));\n  }\n\n  /**\n   * The role of the member with the highest position\n   *\n   * @type {Role}\n   * @readonly\n   */\n  get highest() {\n    return this.cache.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev), this.cache.first());\n  }\n\n  /**\n   * The premium subscriber role of the guild, if present on the member\n   *\n   * @type {?Role}\n   * @readonly\n   */\n  get premiumSubscriberRole() {\n    return this.cache.find(role => role.tags?.premiumSubscriberRole) ?? null;\n  }\n\n  /**\n   * The managed role this member created when joining the guild, if any\n   * <info>Only ever available on bots</info>\n   *\n   * @type {?Role}\n   * @readonly\n   */\n  get botRole() {\n    if (!this.member.user.bot) return null;\n    return this.cache.find(role => role.tags?.botId === this.member.user.id) ?? null;\n  }\n\n  /**\n   * Adds a role (or multiple roles) to the member.\n   *\n   * <info>Uses the idempotent PUT route for singular roles, otherwise PATCHes the underlying guild member</info>\n   *\n   * @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to add\n   * @param {string} [reason] Reason for adding the role(s)\n   * @returns {Promise<GuildMember>}\n   */\n  async add(roleOrRoles, reason) {\n    if (roleOrRoles instanceof Collection || Array.isArray(roleOrRoles)) {\n      const resolvedRoles = [];\n      for (const role of roleOrRoles.values()) {\n        const resolvedRole = this.guild.roles.resolveId(role);\n        if (!resolvedRole) {\n          throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role);\n        }\n\n        resolvedRoles.push(resolvedRole);\n      }\n\n      const newRoles = [...new Set(resolvedRoles.concat(...this.cache.keys()))];\n      return this.set(newRoles, reason);\n    } else {\n      const resolvedRoleId = this.guild.roles.resolveId(roleOrRoles);\n      if (resolvedRoleId === null) {\n        throw new DiscordjsTypeError(\n          ErrorCodes.InvalidType,\n          'roles',\n          'Role, Snowflake or Array or Collection of Roles or Snowflakes',\n        );\n      }\n\n      await this.client.rest.put(Routes.guildMemberRole(this.guild.id, this.member.id, resolvedRoleId), { reason });\n\n      const clone = this.member._clone();\n      clone._roles = [...this.cache.keys(), resolvedRoleId];\n      return clone;\n    }\n  }\n\n  /**\n   * Removes a role (or multiple roles) from the member.\n   *\n   * <info>Uses the idempotent DELETE route for singular roles, otherwise PATCHes the underlying guild member</info>\n   *\n   * @param {RoleResolvable|RoleResolvable[]|Collection<Snowflake, Role>} roleOrRoles The role or roles to remove\n   * @param {string} [reason] Reason for removing the role(s)\n   * @returns {Promise<GuildMember>}\n   */\n  async remove(roleOrRoles, reason) {\n    if (roleOrRoles instanceof Collection || Array.isArray(roleOrRoles)) {\n      const resolvedRoles = [];\n      for (const role of roleOrRoles.values()) {\n        const resolvedRole = this.guild.roles.resolveId(role);\n        if (!resolvedRole) {\n          throw new DiscordjsTypeError(ErrorCodes.InvalidElement, 'Array or Collection', 'roles', role);\n        }\n\n        resolvedRoles.push(resolvedRole);\n      }\n\n      const newRoles = this.cache.filter(role => !resolvedRoles.includes(role.id));\n      return this.set(newRoles, reason);\n    } else {\n      const resolvedRoleId = this.guild.roles.resolveId(roleOrRoles);\n      if (resolvedRoleId === null) {\n        throw new DiscordjsTypeError(\n          ErrorCodes.InvalidType,\n          'roles',\n          'Role, Snowflake or Array or Collection of Roles or Snowflakes',\n        );\n      }\n\n      await this.client.rest.delete(Routes.guildMemberRole(this.guild.id, this.member.id, resolvedRoleId), { reason });\n\n      const clone = this.member._clone();\n      const newRoles = this.cache.filter(role => role.id !== resolvedRoleId);\n      clone._roles = [...newRoles.keys()];\n      return clone;\n    }\n  }\n\n  /**\n   * Sets the roles applied to the member.\n   *\n   * @param {Collection<Snowflake, Role>|RoleResolvable[]} roles The roles or role ids to apply\n   * @param {string} [reason] Reason for applying the roles\n   * @returns {Promise<GuildMember>}\n   * @example\n   * // Set the member's roles to a single role\n   * guildMember.roles.set(['391156570408615936'])\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Remove all the roles from a member\n   * guildMember.roles.set([])\n   *   .then(member => console.log(`Member roles is now of ${member.roles.cache.size} size`))\n   *   .catch(console.error);\n   */\n  async set(roles, reason) {\n    return this.member.edit({ roles, reason });\n  }\n\n  clone() {\n    const clone = new this.constructor(this.member);\n    clone.member._roles = [...this.cache.keys()];\n    return clone;\n  }\n}\n\nexports.GuildMemberRoleManager = GuildMemberRoleManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/GuildMessageManager.js",
    "content": "'use strict';\n\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { MessageManager } = require('./MessageManager.js');\n\n/**\n * Manages API methods for messages in a guild and holds their cache.\n *\n * @extends {MessageManager}\n */\nclass GuildMessageManager extends MessageManager {\n  /**\n   * The channel that the messages belong to\n   *\n   * @name GuildMessageManager#channel\n   * @type {GuildTextBasedChannel}\n   */\n\n  /**\n   * Publishes a message in an announcement channel to all channels following it, even if it's not cached.\n   *\n   * @param {MessageResolvable} message The message to publish\n   * @returns {Promise<Message>}\n   */\n  async crosspost(message) {\n    const messageId = this.resolveId(message);\n    if (!messageId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');\n\n    const data = await this.client.rest.post(Routes.channelMessageCrosspost(this.channel.id, messageId));\n    return this.cache.get(data.id) ?? this._add(data);\n  }\n}\n\nexports.GuildMessageManager = GuildMessageManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/GuildScheduledEventManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { GuildScheduledEventEntityType, Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { GuildScheduledEvent } = require('../structures/GuildScheduledEvent.js');\nconst { resolveImage } = require('../util/DataResolver.js');\nconst { _transformGuildScheduledEventRecurrenceRule } = require('../util/Transformers.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for GuildScheduledEvents and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass GuildScheduledEventManager extends CachedManager {\n  constructor(guild, iterable) {\n    super(guild.client, GuildScheduledEvent, iterable);\n\n    /**\n     * The guild this manager belongs to\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n  }\n\n  /**\n   * The cache of this manager\n   *\n   * @type {Collection<Snowflake, GuildScheduledEvent>}\n   * @name GuildScheduledEventManager#cache\n   */\n\n  /**\n   * Data that resolves to give a GuildScheduledEvent object. This can be:\n   * - A Snowflake\n   * - A GuildScheduledEvent object\n   *\n   * @typedef {Snowflake|GuildScheduledEvent} GuildScheduledEventResolvable\n   */\n\n  /**\n   * Options for setting a recurrence rule for a guild scheduled event.\n   *\n   * @typedef {Object} GuildScheduledEventRecurrenceRuleOptions\n   * @property {DateResolvable} startAt The time the recurrence rule interval starts at\n   * @property {GuildScheduledEventRecurrenceRuleFrequency} frequency How often the event occurs\n   * @property {number} interval The spacing between the events\n   * @property {?GuildScheduledEventRecurrenceRuleWeekday[]} byWeekday The days within a week to recur on\n   * @property {?GuildScheduledEventRecurrenceRuleNWeekday[]} byNWeekday The days within a week to recur on\n   * @property {?GuildScheduledEventRecurrenceRuleMonth[]} byMonth The months to recur on\n   * @property {?number[]} byMonthDay The days within a month to recur on\n   */\n\n  /**\n   * Options used to create a guild scheduled event.\n   *\n   * @typedef {Object} GuildScheduledEventCreateOptions\n   * @property {string} name The name of the guild scheduled event\n   * @property {DateResolvable} scheduledStartTime The time to schedule the event at\n   * @property {DateResolvable} [scheduledEndTime] The time to end the event at\n   * <warn>This is required if `entityType` is {@link GuildScheduledEventEntityType.External}</warn>\n   * @property {GuildScheduledEventPrivacyLevel} privacyLevel The privacy level of the guild scheduled event\n   * @property {GuildScheduledEventEntityType} entityType The scheduled entity type of the event\n   * @property {string} [description] The description of the guild scheduled event\n   * @property {GuildVoiceChannelResolvable} [channel] The channel of the guild scheduled event\n   * <warn>This is required if `entityType` is {@link GuildScheduledEventEntityType.StageInstance} or\n   * {@link GuildScheduledEventEntityType.Voice}</warn>\n   * @property {GuildScheduledEventEntityMetadataOptions} [entityMetadata] The entity metadata of the\n   * guild scheduled event\n   * <warn>This is required if `entityType` is {@link GuildScheduledEventEntityType.External}</warn>\n   * @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event\n   * @property {string} [reason] The reason for creating the guild scheduled event\n   * @property {GuildScheduledEventRecurrenceRuleOptions} [recurrenceRule]\n   * The recurrence rule of the guild scheduled event\n   */\n\n  /**\n   * Options used to set entity metadata of a guild scheduled event.\n   *\n   * @typedef {Object} GuildScheduledEventEntityMetadataOptions\n   * @property {string} [location] The location of the guild scheduled event\n   * <warn>This is required if `entityType` is {@link GuildScheduledEventEntityType.External}</warn>\n   */\n\n  /**\n   * Creates a new guild scheduled event.\n   *\n   * @param {GuildScheduledEventCreateOptions} options Options for creating the guild scheduled event\n   * @returns {Promise<GuildScheduledEvent>}\n   */\n  async create(options) {\n    if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true);\n    const {\n      privacyLevel,\n      entityType,\n      channel,\n      name,\n      scheduledStartTime,\n      description,\n      scheduledEndTime,\n      entityMetadata,\n      reason,\n      image,\n      recurrenceRule,\n    } = options;\n\n    let channel_id;\n    let entity_metadata;\n    if (entityType === GuildScheduledEventEntityType.External) {\n      channel_id = channel === undefined ? channel : null;\n      entity_metadata = { location: entityMetadata?.location };\n    } else {\n      channel_id = this.guild.channels.resolveId(channel);\n      if (!channel_id) throw new DiscordjsError(ErrorCodes.GuildVoiceChannelResolve);\n      entity_metadata = entityMetadata === undefined ? entityMetadata : null;\n    }\n\n    const data = await this.client.rest.post(Routes.guildScheduledEvents(this.guild.id), {\n      body: {\n        channel_id,\n        name,\n        privacy_level: privacyLevel,\n        scheduled_start_time: new Date(scheduledStartTime).toISOString(),\n        scheduled_end_time: scheduledEndTime ? new Date(scheduledEndTime).toISOString() : scheduledEndTime,\n        description,\n        entity_type: entityType,\n        entity_metadata,\n        image: image && (await resolveImage(image)),\n        recurrence_rule: recurrenceRule && _transformGuildScheduledEventRecurrenceRule(recurrenceRule),\n      },\n      reason,\n    });\n\n    return this._add(data);\n  }\n\n  /**\n   * Options used to fetch a single guild scheduled event from a guild.\n   *\n   * @typedef {BaseFetchOptions} FetchGuildScheduledEventOptions\n   * @property {GuildScheduledEventResolvable} guildScheduledEvent The guild scheduled event to fetch\n   * @property {boolean} [withUserCount=true] Whether to fetch the number of users subscribed to the scheduled event\n   */\n\n  /**\n   * Options used to fetch multiple guild scheduled events from a guild.\n   *\n   * @typedef {Object} FetchGuildScheduledEventsOptions\n   * @property {boolean} [cache] Whether or not to cache the fetched guild scheduled events\n   * @property {boolean} [withUserCount=true] Whether to fetch the number of users subscribed to each scheduled event\n   * should be returned\n   */\n\n  /**\n   * Obtains one or more guild scheduled events from Discord, or the guild cache if it's already available.\n   *\n   * @param {GuildScheduledEventResolvable|FetchGuildScheduledEventOptions|FetchGuildScheduledEventsOptions} [options]\n   * The id of the guild scheduled event or options\n   * @returns {Promise<GuildScheduledEvent|Collection<Snowflake, GuildScheduledEvent>>}\n   */\n  async fetch(options = {}) {\n    const id = this.resolveId(options.guildScheduledEvent ?? options);\n\n    if (id) {\n      if (!options.force) {\n        const existing = this.cache.get(id);\n        if (existing) return existing;\n      }\n\n      const innerData = await this.client.rest.get(Routes.guildScheduledEvent(this.guild.id, id), {\n        query: makeURLSearchParams({ with_user_count: options.withUserCount ?? true }),\n      });\n      return this._add(innerData, options.cache);\n    }\n\n    const data = await this.client.rest.get(Routes.guildScheduledEvents(this.guild.id), {\n      query: makeURLSearchParams({ with_user_count: options.withUserCount ?? true }),\n    });\n\n    return data.reduce(\n      (coll, rawGuildScheduledEventData) =>\n        coll.set(rawGuildScheduledEventData.id, this._add(rawGuildScheduledEventData, options.cache)),\n      new Collection(),\n    );\n  }\n\n  /**\n   * Options used to edit a guild scheduled event.\n   *\n   * @typedef {Object} GuildScheduledEventEditOptions\n   * @property {string} [name] The name of the guild scheduled event\n   * @property {DateResolvable} [scheduledStartTime] The time to schedule the event at\n   * @property {DateResolvable} [scheduledEndTime] The time to end the event at\n   * @property {GuildScheduledEventPrivacyLevel} [privacyLevel] The privacy level of the guild scheduled event\n   * @property {GuildScheduledEventEntityType} [entityType] The scheduled entity type of the event\n   * @property {string} [description] The description of the guild scheduled event\n   * @property {?GuildVoiceChannelResolvable} [channel] The channel of the guild scheduled event\n   * @property {GuildScheduledEventStatus} [status] The status of the guild scheduled event\n   * @property {GuildScheduledEventEntityMetadataOptions} [entityMetadata] The entity metadata of the\n   * guild scheduled event\n   * <warn>This can be modified only if `entityType` of the `GuildScheduledEvent` to be edited is\n   * {@link GuildScheduledEventEntityType.External}</warn>\n   * @property {?(BufferResolvable|Base64Resolvable)} [image] The cover image of the guild scheduled event\n   * @property {string} [reason] The reason for editing the guild scheduled event\n   * @property {?GuildScheduledEventRecurrenceRuleOptions} [recurrenceRule]\n   * The recurrence rule of the guild scheduled event\n   */\n\n  /**\n   * Edits a guild scheduled event.\n   *\n   * @param {GuildScheduledEventResolvable} guildScheduledEvent The guild scheduled event to edit\n   * @param {GuildScheduledEventEditOptions} options Options to edit the guild scheduled event\n   * @returns {Promise<GuildScheduledEvent>}\n   */\n  async edit(guildScheduledEvent, options) {\n    const guildScheduledEventId = this.resolveId(guildScheduledEvent);\n    if (!guildScheduledEventId) throw new DiscordjsError(ErrorCodes.GuildScheduledEventResolve);\n\n    if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true);\n    const {\n      privacyLevel,\n      entityType,\n      channel,\n      status,\n      name,\n      scheduledStartTime,\n      description,\n      scheduledEndTime,\n      entityMetadata,\n      reason,\n      image,\n      recurrenceRule,\n    } = options;\n\n    let entity_metadata;\n    if (entityMetadata) {\n      entity_metadata = {\n        location: entityMetadata.location,\n      };\n    }\n\n    const data = await this.client.rest.patch(Routes.guildScheduledEvent(this.guild.id, guildScheduledEventId), {\n      body: {\n        channel_id: channel === undefined ? channel : this.guild.channels.resolveId(channel),\n        name,\n        privacy_level: privacyLevel,\n        scheduled_start_time: scheduledStartTime ? new Date(scheduledStartTime).toISOString() : undefined,\n        scheduled_end_time: scheduledEndTime ? new Date(scheduledEndTime).toISOString() : scheduledEndTime,\n        description,\n        entity_type: entityType,\n        status,\n        image: image && (await resolveImage(image)),\n        entity_metadata,\n        recurrence_rule: recurrenceRule && _transformGuildScheduledEventRecurrenceRule(recurrenceRule),\n      },\n      reason,\n    });\n\n    return this._add(data);\n  }\n\n  /**\n   * Deletes a guild scheduled event.\n   *\n   * @param {GuildScheduledEventResolvable} guildScheduledEvent The guild scheduled event to delete\n   * @returns {Promise<void>}\n   */\n  async delete(guildScheduledEvent) {\n    const guildScheduledEventId = this.resolveId(guildScheduledEvent);\n    if (!guildScheduledEventId) throw new DiscordjsError(ErrorCodes.GuildScheduledEventResolve);\n\n    await this.client.rest.delete(Routes.guildScheduledEvent(this.guild.id, guildScheduledEventId));\n  }\n\n  /**\n   * Options used to fetch subscribers of a guild scheduled event\n   *\n   * @typedef {Object} FetchGuildScheduledEventSubscribersOptions\n   * @property {number} [limit] The maximum numbers of users to fetch\n   * @property {boolean} [withMember] Whether to fetch guild member data of the users\n   * @property {Snowflake} [before] Consider only users before this user id\n   * @property {Snowflake} [after] Consider only users after this user id\n   * <warn>If both `before` and `after` are provided, only `before` is respected</warn>\n   */\n\n  /**\n   * Represents a subscriber of a {@link GuildScheduledEvent}\n   *\n   * @typedef {Object} GuildScheduledEventUser\n   * @property {Snowflake} guildScheduledEventId The id of the guild scheduled event which the user subscribed to\n   * @property {User} user The user that subscribed to the guild scheduled event\n   * @property {?GuildMember} member The guild member associated with the user, if any\n   */\n\n  /**\n   * Fetches subscribers of a guild scheduled event.\n   *\n   * @param {GuildScheduledEventResolvable} guildScheduledEvent The guild scheduled event to fetch subscribers of\n   * @param {FetchGuildScheduledEventSubscribersOptions} [options={}] Options for fetching the subscribers\n   * @returns {Promise<Collection<Snowflake, GuildScheduledEventUser>>}\n   */\n  async fetchSubscribers(guildScheduledEvent, options = {}) {\n    const guildScheduledEventId = this.resolveId(guildScheduledEvent);\n    if (!guildScheduledEventId) throw new DiscordjsError(ErrorCodes.GuildScheduledEventResolve);\n\n    const query = makeURLSearchParams({\n      limit: options.limit,\n      with_member: options.withMember,\n      before: options.before,\n      after: options.after,\n    });\n\n    const data = await this.client.rest.get(Routes.guildScheduledEventUsers(this.guild.id, guildScheduledEventId), {\n      query,\n    });\n\n    return data.reduce(\n      (coll, rawData) =>\n        coll.set(rawData.user.id, {\n          guildScheduledEventId: rawData.guild_scheduled_event_id,\n          user: this.client.users._add(rawData.user),\n          member: rawData.member ? this.guild.members._add({ ...rawData.member, user: rawData.user }) : null,\n        }),\n      new Collection(),\n    );\n  }\n}\n\nexports.GuildScheduledEventManager = GuildScheduledEventManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/GuildSoundboardSoundManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { lazy } = require('@discordjs/util');\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { SoundboardSound } = require('../structures/SoundboardSound.js');\nconst { resolveBase64, resolveFile } = require('../util/DataResolver.js');\nconst { CachedManager } = require('./CachedManager.js');\n\nconst fileTypeMime = lazy(() => require('magic-bytes.js').filetypemime);\n\n/**\n * Manages API methods for Soundboard Sounds and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass GuildSoundboardSoundManager extends CachedManager {\n  constructor(guild, iterable) {\n    super(guild.client, SoundboardSound, iterable);\n\n    /**\n     * The guild this manager belongs to\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n  }\n\n  /**\n   * The cache of Soundboard Sounds\n   *\n   * @type {Collection<Snowflake, SoundboardSound>}\n   * @name GuildSoundboardSoundManager#cache\n   */\n\n  _add(data, cache) {\n    return super._add(data, cache, { extras: [this.guild], id: data.sound_id });\n  }\n\n  /**\n   * Data that resolves to give a SoundboardSound object. This can be:\n   * - A SoundboardSound object\n   * - A Snowflake\n   *\n   * @typedef {SoundboardSound|Snowflake} SoundboardSoundResolvable\n   */\n\n  /**\n   * Resolves a SoundboardSoundResolvable to a SoundboardSound object.\n   *\n   * @method resolve\n   * @memberof GuildSoundboardSoundManager\n   * @instance\n   * @param {SoundboardSoundResolvable} soundboardSound The SoundboardSound resolvable to identify\n   * @returns {?SoundboardSound}\n   */\n\n  /**\n   * Resolves a {@link SoundboardSoundResolvable} to a {@link SoundboardSound} id.\n   *\n   * @param {SoundboardSoundResolvable} soundboardSound The soundboard sound resolvable to resolve\n   * @returns {?Snowflake}\n   */\n  resolveId(soundboardSound) {\n    if (soundboardSound instanceof this.holds) return soundboardSound.soundId;\n    if (typeof soundboardSound === 'string') return soundboardSound;\n    return null;\n  }\n\n  /**\n   * Options used to create a soundboard sound in a guild.\n   *\n   * @typedef {Object} GuildSoundboardSoundCreateOptions\n   * @property {BufferResolvable|Stream} file The file for the soundboard sound\n   * @property {string} name The name for the soundboard sound\n   * @property {string} [contentType] The content type for the soundboard sound file\n   * @property {number} [volume] The volume (a double) for the soundboard sound, from 0 (inclusive) to 1. Defaults to 1\n   * @property {Snowflake} [emojiId] The emoji id for the soundboard sound\n   * @property {string} [emojiName] The emoji name for the soundboard sound\n   * @property {string} [reason] The reason for creating the soundboard sound\n   */\n\n  /**\n   * Creates a new guild soundboard sound.\n   *\n   * @param {GuildSoundboardSoundCreateOptions} options Options for creating a guild soundboard sound\n   * @returns {Promise<SoundboardSound>} The created soundboard sound\n   * @example\n   * // Create a new soundboard sound from a file on your computer\n   * guild.soundboardSounds.create({ file: './sound.mp3', name: 'sound' })\n   *   .then(sound => console.log(`Created new soundboard sound with name ${sound.name}!`))\n   *   .catch(console.error);\n   */\n  async create({ contentType, emojiId, emojiName, file, name, reason, volume }) {\n    const resolvedFile = await resolveFile(file);\n\n    const resolvedContentType = contentType ?? resolvedFile.contentType ?? fileTypeMime()(resolvedFile.data)[0];\n\n    const sound = resolveBase64(resolvedFile.data, resolvedContentType);\n\n    const body = { emoji_id: emojiId, emoji_name: emojiName, name, sound, volume };\n\n    const soundboardSound = await this.client.rest.post(Routes.guildSoundboardSounds(this.guild.id), {\n      body,\n      reason,\n    });\n\n    return this._add(soundboardSound);\n  }\n\n  /**\n   * Data for editing a soundboard sound.\n   *\n   * @typedef {Object} GuildSoundboardSoundEditOptions\n   * @property {string} [name] The name of the soundboard sound\n   * @property {?number} [volume] The volume (a double) of the soundboard sound, from 0 (inclusive) to 1\n   * @property {?Snowflake} [emojiId] The emoji id of the soundboard sound\n   * @property {?string} [emojiName] The emoji name of the soundboard sound\n   * @property {string} [reason] The reason for editing the soundboard sound\n   */\n\n  /**\n   * Edits a soundboard sound.\n   *\n   * @param {SoundboardSoundResolvable} soundboardSound The soundboard sound to edit\n   * @param {GuildSoundboardSoundEditOptions} [options={}] The new data for the soundboard sound\n   * @returns {Promise<SoundboardSound>}\n   */\n  async edit(soundboardSound, options = {}) {\n    const soundId = this.resolveId(soundboardSound);\n\n    if (!soundId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'soundboardSound', 'SoundboardSoundResolvable');\n\n    const { emojiId, emojiName, name, reason, volume } = options;\n\n    const body = { emoji_id: emojiId, emoji_name: emojiName, name, volume };\n\n    const data = await this.client.rest.patch(Routes.guildSoundboardSound(this.guild.id, soundId), {\n      body,\n      reason,\n    });\n\n    const existing = this.cache.get(soundId);\n\n    if (existing) {\n      const clone = existing._clone();\n\n      clone._patch(data);\n      return clone;\n    }\n\n    return this._add(data);\n  }\n\n  /**\n   * Deletes a soundboard sound.\n   *\n   * @param {SoundboardSoundResolvable} soundboardSound The soundboard sound to delete\n   * @param {string} [reason] Reason for deleting this soundboard sound\n   * @returns {Promise<void>}\n   */\n  async delete(soundboardSound, reason) {\n    const soundId = this.resolveId(soundboardSound);\n\n    if (!soundId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'soundboardSound', 'SoundboardSoundResolvable');\n\n    await this.client.rest.delete(Routes.guildSoundboardSound(this.guild.id, soundId), { reason });\n  }\n\n  /**\n   * Options used to fetch a soundboard sound.\n   *\n   * @typedef {BaseFetchOptions} FetchSoundboardSoundOptions\n   * @property {SoundboardSoundResolvable} soundboardSound The soundboard sound to fetch\n   */\n\n  /**\n   * Options used to fetch soundboard sounds from Discord\n   *\n   * @typedef {Object} FetchGuildSoundboardSoundsOptions\n   * @property {boolean} [cache] Whether to cache the fetched soundboard sounds\n   */\n\n  /**\n   * Obtains one or more soundboard sounds from Discord, or the soundboard sound cache if they're already available.\n   *\n   * @param {SoundboardSoundResolvable|FetchSoundboardSoundOptions|FetchGuildSoundboardSoundsOptions} [options] Options for fetching soundboard sound(s)\n   * @returns {Promise<SoundboardSound|Collection<Snowflake, SoundboardSound>>}\n   * @example\n   * // Fetch a single soundboard sound\n   * guild.soundboardSounds.fetch('222078108977594368')\n   *   .then(sound => console.log(`The soundboard sound name is: ${sound.name}`))\n   *   .catch(console.error);\n   * @example\n   * // Fetch all soundboard sounds from the guild\n   * guild.soundboardSounds.fetch()\n   *   .then(sounds => console.log(`There are ${sounds.size} soundboard sounds.`))\n   *   .catch(console.error);\n   */\n  async fetch(options) {\n    if (!options) return this._fetchMany();\n    const { cache, force, soundboardSound } = options;\n    const resolvedSoundboardSound = this.resolveId(soundboardSound ?? options);\n    if (resolvedSoundboardSound) return this._fetchSingle({ cache, force, soundboardSound: resolvedSoundboardSound });\n    return this._fetchMany({ cache });\n  }\n\n  async _fetchSingle({ cache, force, soundboardSound } = {}) {\n    if (!force) {\n      const existing = this.cache.get(soundboardSound);\n      if (existing) return existing;\n    }\n\n    const data = await this.client.rest.get(Routes.guildSoundboardSound(this.guild.id, soundboardSound));\n    return this._add(data, cache);\n  }\n\n  async _fetchMany({ cache } = {}) {\n    const data = await this.client.rest.get(Routes.guildSoundboardSounds(this.guild.id));\n\n    return data.items.reduce((coll, sound) => coll.set(sound.sound_id, this._add(sound, cache)), new Collection());\n  }\n}\n\nexports.GuildSoundboardSoundManager = GuildSoundboardSoundManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/GuildStickerManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { MessagePayload } = require('../structures/MessagePayload.js');\nconst { Sticker } = require('../structures/Sticker.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for Guild Stickers and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass GuildStickerManager extends CachedManager {\n  constructor(guild, iterable) {\n    super(guild.client, Sticker, iterable);\n\n    /**\n     * The guild this manager belongs to\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n  }\n\n  /**\n   * The cache of Guild Stickers\n   *\n   * @type {Collection<Snowflake, Sticker>}\n   * @name GuildStickerManager#cache\n   */\n\n  _add(data, cache) {\n    return super._add(data, cache, { extras: [this.guild] });\n  }\n\n  /**\n   * Options used to create a guild sticker.\n   *\n   * @typedef {Object} GuildStickerCreateOptions\n   * @property {AttachmentPayload|BufferResolvable|Stream} file The file for the sticker\n   * @property {string} name The name for the sticker\n   * @property {string} tags The Discord name of a unicode emoji representing the sticker's expression\n   * @property {?string} [description] The description for the sticker\n   * @property {string} [reason] Reason for creating the sticker\n   */\n\n  /**\n   * Creates a new custom sticker in the guild.\n   *\n   * @param {GuildStickerCreateOptions} options Options for creating a guild sticker\n   * @returns {Promise<Sticker>} The created sticker\n   * @example\n   * // Create a new sticker from a URL\n   * guild.stickers.create({ file: 'https://i.imgur.com/w3duR07.png', name: 'rip', tags: 'headstone' })\n   *   .then(sticker => console.log(`Created new sticker with name ${sticker.name}!`))\n   *   .catch(console.error);\n   * @example\n   * // Create a new sticker from a file on your computer\n   * guild.stickers.create({ file: './memes/banana.png', name: 'banana', tags: 'banana' })\n   *   .then(sticker => console.log(`Created new sticker with name ${sticker.name}!`))\n   *   .catch(console.error);\n   */\n  async create({ file, name, tags, description, reason } = {}) {\n    const resolvedFile = await MessagePayload.resolveFile(file);\n    resolvedFile.key = 'file';\n\n    const body = { name, tags, description: description ?? '' };\n\n    const sticker = await this.client.rest.post(Routes.guildStickers(this.guild.id), {\n      appendToFormData: true,\n      body,\n      files: [resolvedFile],\n      reason,\n    });\n    return this.client.actions.GuildStickerCreate.handle(this.guild, sticker).sticker;\n  }\n\n  /**\n   * Data that resolves to give a Sticker object. This can be:\n   * - A Sticker object\n   * - A Snowflake\n   *\n   * @typedef {Sticker|Snowflake} StickerResolvable\n   */\n\n  /**\n   * Resolves a StickerResolvable to a Sticker object.\n   *\n   * @method resolve\n   * @memberof GuildStickerManager\n   * @instance\n   * @param {StickerResolvable} sticker The Sticker resolvable to identify\n   * @returns {?Sticker}\n   */\n\n  /**\n   * Resolves a StickerResolvable to a Sticker id string.\n   *\n   * @method resolveId\n   * @memberof GuildStickerManager\n   * @instance\n   * @param {StickerResolvable} sticker The Sticker resolvable to identify\n   * @returns {?Snowflake}\n   */\n\n  /**\n   * Edits a sticker.\n   *\n   * @param {StickerResolvable} sticker The sticker to edit\n   * @param {GuildStickerEditOptions} [options={}] The new data for the sticker\n   * @returns {Promise<Sticker>}\n   */\n  async edit(sticker, options = {}) {\n    const stickerId = this.resolveId(sticker);\n    if (!stickerId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'sticker', 'StickerResolvable');\n\n    const data = await this.client.rest.patch(Routes.guildSticker(this.guild.id, stickerId), {\n      body: options,\n      reason: options.reason,\n    });\n\n    const existing = this.cache.get(stickerId);\n    if (existing) {\n      const clone = existing._clone();\n      clone._patch(data);\n      return clone;\n    }\n\n    return this._add(data);\n  }\n\n  /**\n   * Deletes a sticker.\n   *\n   * @param {StickerResolvable} sticker The sticker to delete\n   * @param {string} [reason] Reason for deleting this sticker\n   * @returns {Promise<void>}\n   */\n  async delete(sticker, reason) {\n    const resolvedStickerId = this.resolveId(sticker);\n    if (!resolvedStickerId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'sticker', 'StickerResolvable');\n\n    await this.client.rest.delete(Routes.guildSticker(this.guild.id, resolvedStickerId), { reason });\n  }\n\n  /**\n   * Obtains one or more stickers from Discord, or the sticker cache if they're already available.\n   *\n   * @param {Snowflake} [id] The Sticker's id\n   * @param {BaseFetchOptions} [options] Additional options for this fetch\n   * @returns {Promise<Sticker|Collection<Snowflake, Sticker>>}\n   * @example\n   * // Fetch all stickers from the guild\n   * message.guild.stickers.fetch()\n   *   .then(stickers => console.log(`There are ${stickers.size} stickers.`))\n   *   .catch(console.error);\n   * @example\n   * // Fetch a single sticker\n   * message.guild.stickers.fetch('222078108977594368')\n   *   .then(sticker => console.log(`The sticker name is: ${sticker.name}`))\n   *   .catch(console.error);\n   */\n  async fetch(id, { cache = true, force = false } = {}) {\n    if (id) {\n      if (!force) {\n        const existing = this.cache.get(id);\n        if (existing) return existing;\n      }\n\n      const sticker = await this.client.rest.get(Routes.guildSticker(this.guild.id, id));\n      return this._add(sticker, cache);\n    }\n\n    const data = await this.client.rest.get(Routes.guildStickers(this.guild.id));\n    return new Collection(data.map(sticker => [sticker.id, this._add(sticker, cache)]));\n  }\n\n  /**\n   * Fetches the user who uploaded this sticker, if this is a guild sticker.\n   *\n   * @param {StickerResolvable} sticker The sticker to fetch the user for\n   * @returns {Promise<?User>}\n   */\n  async fetchUser(sticker) {\n    const resolvedSticker = this.resolve(sticker);\n    if (!resolvedSticker) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'sticker', 'StickerResolvable');\n    const data = await this.client.rest.get(Routes.guildSticker(this.guild.id, resolvedSticker.id));\n    resolvedSticker._patch(data);\n    return resolvedSticker.user;\n  }\n}\n\nexports.GuildStickerManager = GuildStickerManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/GuildTextThreadManager.js",
    "content": "'use strict';\n\nconst { ChannelType, Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { ThreadManager } = require('./ThreadManager.js');\n\n/**\n * Manages API methods for {@link ThreadChannel} objects and stores their cache.\n *\n * @extends {ThreadManager}\n */\nclass GuildTextThreadManager extends ThreadManager {\n  /**\n   * The channel this Manager belongs to\n   *\n   * @name GuildTextThreadManager#channel\n   * @type {TextChannel|AnnouncementChannel}\n   */\n\n  /**\n   * Options for creating a thread. <warn>Only one of `startMessage` or `type` can be defined.</warn>\n   *\n   * @typedef {StartThreadOptions} GuildTextThreadCreateOptions\n   * @property {MessageResolvable} [startMessage] The message to start a thread from.\n   * <warn>If this is defined, then the `type` of thread gets inferred automatically and cannot be changed.</warn>\n   * @property {ThreadChannelTypes} [type] The type of thread to create.\n   * Defaults to {@link ChannelType.PublicThread} if created in a {@link TextChannel}\n   * <warn>When creating threads in a {@link AnnouncementChannel}, this is ignored and is always\n   * {@link ChannelType.AnnouncementThread}</warn>\n   * @property {boolean} [invitable] Whether non-moderators can add other non-moderators to the thread\n   * <info>Can only be set when type will be {@link ChannelType.PrivateThread}</info>\n   */\n\n  /**\n   * Creates a new thread in the channel.\n   *\n   * @param {GuildTextThreadCreateOptions} [options] Options to create a new thread\n   * @returns {Promise<ThreadChannel>}\n   * @example\n   * // Create a new public thread\n   * channel.threads\n   *   .create({\n   *     name: 'food-talk',\n   *     autoArchiveDuration: ThreadAutoArchiveDuration.OneHour,\n   *     reason: 'Needed a separate thread for food',\n   *   })\n   *   .then(threadChannel => console.log(threadChannel))\n   *   .catch(console.error);\n   * @example\n   * // Create a new private thread\n   * channel.threads\n   *   .create({\n   *      name: 'mod-talk',\n   *      autoArchiveDuration: ThreadAutoArchiveDuration.OneHour,\n   *      type: ChannelType.PrivateThread,\n   *      reason: 'Needed a separate thread for moderation',\n   *    })\n   *   .then(threadChannel => console.log(threadChannel))\n   *   .catch(console.error);\n   */\n  async create({\n    name,\n    autoArchiveDuration = this.channel.defaultAutoArchiveDuration,\n    startMessage,\n    type,\n    invitable,\n    reason,\n    rateLimitPerUser,\n  } = {}) {\n    let resolvedType =\n      this.channel.type === ChannelType.GuildAnnouncement ? ChannelType.AnnouncementThread : ChannelType.PublicThread;\n    let startMessageId;\n    if (startMessage) {\n      startMessageId = this.channel.messages.resolveId(startMessage);\n      if (!startMessageId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'startMessage', 'MessageResolvable');\n    } else if (this.channel.type !== ChannelType.GuildAnnouncement) {\n      resolvedType = type ?? resolvedType;\n    }\n\n    const data = await this.client.rest.post(Routes.threads(this.channel.id, startMessageId), {\n      body: {\n        name,\n        auto_archive_duration: autoArchiveDuration,\n        type: resolvedType,\n        invitable: resolvedType === ChannelType.PrivateThread ? invitable : undefined,\n        rate_limit_per_user: rateLimitPerUser,\n      },\n      reason,\n    });\n\n    return this.client.actions.ThreadCreate.handle(data).thread;\n  }\n}\n\nexports.GuildTextThreadManager = GuildTextThreadManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/MessageManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { isFileBodyEncodable, isJSONEncodable } = require('@discordjs/util');\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { Message } = require('../structures/Message.js');\nconst { MessagePayload } = require('../structures/MessagePayload.js');\nconst { MakeCacheOverrideSymbol } = require('../util/Symbols.js');\nconst { resolvePartialEmoji } = require('../util/Util.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for Messages and holds their cache.\n *\n * @extends {CachedManager}\n * @abstract\n */\nclass MessageManager extends CachedManager {\n  static [MakeCacheOverrideSymbol] = MessageManager;\n\n  constructor(channel, iterable) {\n    super(channel.client, Message, iterable);\n\n    /**\n     * The channel that the messages belong to\n     *\n     * @type {TextBasedChannels}\n     */\n    this.channel = channel;\n  }\n\n  /**\n   * The cache of Messages\n   *\n   * @type {Collection<Snowflake, Message>}\n   * @name MessageManager#cache\n   */\n\n  _add(data, cache) {\n    return super._add(data, cache);\n  }\n\n  /**\n   * Data that can be resolved to a Message object. This can be:\n   * - A Message\n   * - A Snowflake\n   *\n   * @typedef {Message|Snowflake} MessageResolvable\n   */\n\n  /**\n   * Options used to fetch a message.\n   *\n   * @typedef {BaseFetchOptions} FetchMessageOptions\n   * @property {MessageResolvable} message The message to fetch\n   */\n\n  /**\n   * Options used to fetch multiple messages.\n   * <info>The `before`, `after`, and `around` parameters are mutually exclusive.</info>\n   *\n   * @typedef {Object} FetchMessagesOptions\n   * @property {number} [limit] The maximum number of messages to return\n   * @property {Snowflake} [before] Consider only messages before this id\n   * @property {Snowflake} [after] Consider only messages after this id\n   * @property {Snowflake} [around] Consider only messages around this id\n   * @property {boolean} [cache] Whether to cache the fetched messages\n   */\n\n  /**\n   * Fetches message(s) from a channel.\n   * <info>The returned Collection does not contain reaction users of the messages if they were not cached.\n   * Those need to be fetched separately in such a case.</info>\n   *\n   * @param {MessageResolvable|FetchMessageOptions|FetchMessagesOptions} [options] Options for fetching message(s)\n   * @returns {Promise<Message|Collection<Snowflake, Message>>}\n   * @example\n   * // Fetch a message\n   * channel.messages.fetch('99539446449315840')\n   *   .then(message => console.log(message.content))\n   *   .catch(console.error);\n   * @example\n   * // Fetch a maximum of 10 messages without caching\n   * channel.messages.fetch({ limit: 10, cache: false })\n   *   .then(messages => console.log(`Received ${messages.size} messages`))\n   *   .catch(console.error);\n   * @example\n   * // Fetch a maximum of 10 messages without caching around a message id\n   * channel.messages.fetch({ limit: 10, cache: false, around: '99539446449315840' })\n   *   .then(messages => console.log(`Received ${messages.size} messages`))\n   *   .catch(console.error);\n   * @example\n   * // Fetch messages and filter by a user id\n   * channel.messages.fetch()\n   *   .then(messages => console.log(`${messages.filter(message =>\n   *          message.author.id === '84484653687267328').size} messages`))\n   *   .catch(console.error);\n   */\n  async fetch(options) {\n    if (!options) return this._fetchMany();\n    const { message, cache, force } = options;\n    const resolvedMessage = this.resolveId(message ?? options);\n    if (resolvedMessage) return this._fetchSingle({ message: resolvedMessage, cache, force });\n    return this._fetchMany(options);\n  }\n\n  async _fetchSingle({ message, cache, force = false }) {\n    if (!force) {\n      const existing = this.cache.get(message);\n      if (existing && !existing.partial) return existing;\n    }\n\n    const data = await this.client.rest.get(Routes.channelMessage(this.channel.id, message));\n    return this._add(data, cache);\n  }\n\n  async _fetchMany({ cache, ...apiOptions } = {}) {\n    const data = await this.client.rest.get(Routes.channelMessages(this.channel.id), {\n      query: makeURLSearchParams(apiOptions),\n    });\n\n    return data.reduce((_data, message) => _data.set(message.id, this._add(message, cache)), new Collection());\n  }\n\n  /**\n   * Options used to fetch pinned messages.\n   *\n   * @typedef {Object} FetchPinnedMessagesOptions\n   * @property {DateResolvable} [before] Consider only pinned messages before this time\n   * @property {number} [limit] The maximum number of pinned messages to return\n   * @property {boolean} [cache] Whether to cache the pinned messages\n   */\n\n  /**\n   * Data returned from fetching pinned messages.\n   *\n   * @typedef {Object} FetchPinnedMessagesResponse\n   * @property {MessagePin[]} items The pinned messages\n   * @property {boolean} hasMore Whether there are additional pinned messages that require a subsequent call\n   */\n\n  /**\n   * Pinned message data returned from fetching pinned messages.\n   *\n   * @typedef {Object} MessagePin\n   * @property {Date} pinnedAt The time the message was pinned at\n   * @property {number} pinnedTimestamp The timestamp the message was pinned at\n   * @property {Message} message The pinned message\n   */\n\n  /**\n   * Fetches the pinned messages of this channel, returning a paginated result.\n   * <info>The returned messages do not contain any reaction data.\n   * Those need to be fetched separately.</info>\n   *\n   * @param {FetchPinnedMessagesOptions} [options={}] Options for fetching pinned messages\n   * @returns {Promise<FetchPinnedMessagesResponse>}\n   * @example\n   * // Get pinned messages\n   * channel.messages.fetchPins()\n   *   .then(messages => console.log(`Received ${messages.items.length} messages`))\n   *   .catch(console.error);\n   */\n  async fetchPins({ cache, ...apiOptions } = {}) {\n    const data = await this.client.rest.get(Routes.channelMessagesPins(this.channel.id), {\n      query: makeURLSearchParams({\n        ...apiOptions,\n        before: apiOptions.before && new Date(apiOptions.before).toISOString(),\n      }),\n    });\n\n    return {\n      items: data.items.map(item => ({\n        pinnedTimestamp: Date.parse(item.pinned_at),\n        get pinnedAt() {\n          return new Date(this.pinnedTimestamp);\n        },\n        message: this._add(item.message, cache),\n      })),\n      hasMore: data.has_more,\n    };\n  }\n\n  /**\n   * Resolves a {@link MessageResolvable} to a {@link Message} object.\n   *\n   * @method resolve\n   * @memberof MessageManager\n   * @instance\n   * @param {MessageResolvable} message The message resolvable to resolve\n   * @returns {?Message}\n   */\n\n  /**\n   * Resolves a {@link MessageResolvable} to a {@link Message} id.\n   *\n   * @method resolveId\n   * @memberof MessageManager\n   * @instance\n   * @param {MessageResolvable} message The message resolvable to resolve\n   * @returns {?Snowflake}\n   */\n\n  /**\n   * Data used to reference an attachment.\n   *\n   * @typedef {Object} MessageEditAttachmentData\n   * @property {Snowflake} id The id of the attachment\n   */\n\n  /**\n   * Options that can be passed to edit a message.\n   *\n   * @typedef {BaseMessageOptions} MessageEditOptions\n   * @property {Array<Attachment|MessageEditAttachmentData>} [attachments] An array of attachments to keep.\n   * All attachments will be kept if omitted\n   * @property {MessageFlags} [flags] Which flags to set for the message\n   * <info>Only the {@link MessageFlags.SuppressEmbeds} flag can be modified.</info>\n   */\n\n  /**\n   * Edits a message, even if it's not cached.\n   *\n   * @param {MessageResolvable} message The message to edit\n   * @param {string|MessageEditOptions|MessagePayload|FileBodyEncodable<RESTPatchAPIChannelMessageJSONBody>|JSONEncodable<RESTPatchAPIChannelMessageJSONBody>} options The options to edit the message\n   * @returns {Promise<Message>}\n   */\n  async edit(message, options) {\n    const messageId = this.resolveId(message);\n    if (!messageId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');\n\n    let payload;\n    if (options instanceof MessagePayload) {\n      payload = await options.resolveBody().resolveFiles();\n    } else if (isFileBodyEncodable(options)) {\n      payload = options.toFileBody();\n    } else if (isJSONEncodable(options)) {\n      payload = { body: options.toJSON() };\n    } else {\n      payload = await MessagePayload.create(message instanceof Message ? message : this, options)\n        .resolveBody()\n        .resolveFiles();\n    }\n\n    const data = await this.client.rest.patch(Routes.channelMessage(this.channel.id, messageId), payload);\n\n    const existing = this.cache.get(messageId);\n    if (existing) {\n      const clone = existing._clone();\n      clone._patch(data);\n      return clone;\n    }\n\n    return this._add(data);\n  }\n\n  /**\n   * Pins a message to the channel's pinned messages, even if it's not cached.\n   *\n   * @param {MessageResolvable} message The message to pin\n   * @param {string} [reason] Reason for pinning\n   * @returns {Promise<void>}\n   */\n  async pin(message, reason) {\n    const messageId = this.resolveId(message);\n    if (!messageId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');\n\n    await this.client.rest.put(Routes.channelMessagesPin(this.channel.id, messageId), { reason });\n  }\n\n  /**\n   * Unpins a message from the channel's pinned messages, even if it's not cached.\n   *\n   * @param {MessageResolvable} message The message to unpin\n   * @param {string} [reason] Reason for unpinning\n   * @returns {Promise<void>}\n   */\n  async unpin(message, reason) {\n    const messageId = this.resolveId(message);\n    if (!messageId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');\n\n    await this.client.rest.delete(Routes.channelMessagesPin(this.channel.id, messageId), { reason });\n  }\n\n  /**\n   * Adds a reaction to a message, even if it's not cached.\n   *\n   * @param {MessageResolvable} message The message to react to\n   * @param {EmojiIdentifierResolvable} emoji The emoji to react with\n   * @returns {Promise<void>}\n   */\n  async react(message, emoji) {\n    const messageId = this.resolveId(message);\n    if (!messageId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');\n\n    const resolvedEmoji = resolvePartialEmoji(emoji);\n    if (!resolvedEmoji) throw new DiscordjsTypeError(ErrorCodes.EmojiType, 'emoji', 'EmojiIdentifierResolvable');\n\n    const emojiId = resolvedEmoji.id\n      ? `${resolvedEmoji.animated ? 'a:' : ''}${resolvedEmoji.name}:${resolvedEmoji.id}`\n      : encodeURIComponent(resolvedEmoji.name);\n\n    await this.client.rest.put(Routes.channelMessageOwnReaction(this.channel.id, messageId, emojiId));\n  }\n\n  /**\n   * Deletes a message, even if it's not cached.\n   *\n   * @param {MessageResolvable} message The message to delete\n   * @returns {Promise<void>}\n   */\n  async delete(message) {\n    const messageId = this.resolveId(message);\n    if (!messageId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');\n\n    await this.client.rest.delete(Routes.channelMessage(this.channel.id, messageId));\n  }\n\n  /**\n   * Ends a poll.\n   *\n   * @param {Snowflake} messageId The id of the message\n   * @returns {Promise<Message>}\n   */\n  async endPoll(messageId) {\n    const message = await this.client.rest.post(Routes.expirePoll(this.channel.id, messageId));\n    return this._add(message, false);\n  }\n\n  /**\n   * Options used for fetching voters of an answer in a poll.\n   *\n   * @typedef {BaseFetchPollAnswerVotersOptions} FetchPollAnswerVotersOptions\n   * @param {Snowflake} messageId The id of the message\n   * @param {number} answerId The id of the answer\n   */\n\n  /**\n   * Fetches the users that voted for a poll answer.\n   *\n   * @param {FetchPollAnswerVotersOptions} options The options for fetching the poll answer voters\n   * @returns {Promise<Collection<Snowflake, User>>}\n   */\n  async fetchPollAnswerVoters({ messageId, answerId, after, limit }) {\n    const voters = await this.client.rest.get(Routes.pollAnswerVoters(this.channel.id, messageId, answerId), {\n      query: makeURLSearchParams({ limit, after }),\n    });\n\n    return voters.users.reduce((acc, user) => acc.set(user.id, this.client.users._add(user, false)), new Collection());\n  }\n}\n\nexports.MessageManager = MessageManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/PartialGroupDMMessageManager.js",
    "content": "'use strict';\n\nconst { MessageManager } = require('./MessageManager.js');\n\n/**\n * Manages API methods for messages in group direct message channels and holds their cache.\n *\n * @extends {MessageManager}\n */\nclass PartialGroupDMMessageManager extends MessageManager {\n  /**\n   * The channel that the messages belong to\n   *\n   * @name PartialGroupDMMessageManager#channel\n   * @type {PartialGroupDMChannel}\n   */\n}\n\nexports.PartialGroupDMMessageManager = PartialGroupDMMessageManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/PermissionOverwriteManager.js",
    "content": "'use strict';\n\nconst process = require('node:process');\nconst { Collection } = require('@discordjs/collection');\nconst { OverwriteType, Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { PermissionOverwrites } = require('../structures/PermissionOverwrites.js');\nconst { Role } = require('../structures/Role.js');\nconst { CachedManager } = require('./CachedManager.js');\n\nlet cacheWarningEmitted = false;\n\n/**\n * Manages API methods for guild channel permission overwrites and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass PermissionOverwriteManager extends CachedManager {\n  constructor(channel, iterable) {\n    super(channel.client, PermissionOverwrites);\n    if (!cacheWarningEmitted && this._cache.constructor.name !== 'Collection') {\n      cacheWarningEmitted = true;\n      process.emitWarning(\n        `Overriding the cache handling for ${this.constructor.name} is unsupported and breaks functionality.`,\n        'UnsupportedCacheOverwriteWarning',\n      );\n    }\n\n    /**\n     * The channel of the permission overwrite this manager belongs to\n     *\n     * @type {GuildChannel}\n     */\n    this.channel = channel;\n\n    if (iterable) {\n      for (const item of iterable) {\n        this._add(item);\n      }\n    }\n  }\n\n  /**\n   * The cache of this Manager\n   *\n   * @type {Collection<Snowflake, PermissionOverwrites>}\n   * @name PermissionOverwriteManager#cache\n   */\n\n  _add(data, cache) {\n    return super._add(data, cache, { extras: [this.channel] });\n  }\n\n  /**\n   * Replaces the permission overwrites in this channel.\n   *\n   * @param {OverwriteResolvable[]|Collection<Snowflake, OverwriteResolvable>} overwrites\n   * Permission overwrites the channel gets updated with\n   * @param {string} [reason] Reason for updating the channel overwrites\n   * @returns {Promise<GuildChannel>}\n   * @example\n   * message.channel.permissionOverwrites.set([\n   *   {\n   *      id: message.author.id,\n   *      deny: [PermissionFlagsBits.ViewChannel],\n   *   },\n   * ], 'Needed to change permissions');\n   */\n  async set(overwrites, reason) {\n    if (!Array.isArray(overwrites) && !(overwrites instanceof Collection)) {\n      throw new DiscordjsTypeError(\n        ErrorCodes.InvalidType,\n        'overwrites',\n        'Array or Collection of Permission Overwrites',\n        true,\n      );\n    }\n\n    return this.channel.edit({ permissionOverwrites: overwrites, reason });\n  }\n\n  /**\n   * Extra information about the overwrite.\n   *\n   * @typedef {Object} GuildChannelOverwriteOptions\n   * @property {string} [reason] The reason for creating/editing this overwrite\n   * @property {OverwriteType} [type] The type of overwrite. Use this to bypass automatic resolution of `type`\n   * that results in an error for an uncached structure\n   */\n\n  /**\n   * Creates or edits permission overwrites for a user or role in this channel.\n   *\n   * @param {RoleResolvable|UserResolvable} userOrRole The user or role to update\n   * @param {PermissionOverwriteOptions} options The options for the update\n   * @param {GuildChannelOverwriteOptions} [overwriteOptions] The extra information for the update\n   * @param {PermissionOverwrites} [existing] The existing overwrites to merge with this update\n   * @returns {Promise<GuildChannel>}\n   * @private\n   */\n  async upsert(userOrRole, options, { reason, type } = {}, existing = undefined) {\n    const userOrRoleId = this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole);\n\n    let resolvedType = type;\n    if (typeof resolvedType !== 'number') {\n      const resolvedUserOrRole = this.channel.guild.roles.resolve(userOrRole) ?? this.client.users.resolve(userOrRole);\n      if (!resolvedUserOrRole) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'parameter', 'User nor a Role');\n      resolvedType = resolvedUserOrRole instanceof Role ? OverwriteType.Role : OverwriteType.Member;\n    }\n\n    const { allow, deny } = PermissionOverwrites.resolveOverwriteOptions(options, existing);\n\n    await this.client.rest.put(Routes.channelPermission(this.channel.id, userOrRoleId), {\n      body: { id: userOrRoleId, type: resolvedType, allow, deny },\n      reason,\n    });\n    return this.channel;\n  }\n\n  /**\n   * Creates permission overwrites for a user or role in this channel, or replaces them if already present.\n   *\n   * @param {RoleResolvable|UserResolvable} userOrRole The user or role to update\n   * @param {PermissionOverwriteOptions} options The options for the update\n   * @param {GuildChannelOverwriteOptions} [overwriteOptions] The extra information for the update\n   * @returns {Promise<GuildChannel>}\n   * @example\n   * // Create or Replace permission overwrites for a message author\n   * message.channel.permissionOverwrites.create(message.author, {\n   *   SendMessages: false\n   * })\n   *   .then(channel => console.log(channel.permissionOverwrites.cache.get(message.author.id)))\n   *   .catch(console.error);\n   */\n  async create(userOrRole, options, overwriteOptions) {\n    return this.upsert(userOrRole, options, overwriteOptions);\n  }\n\n  /**\n   * Edits permission overwrites for a user or role in this channel, or creates an entry if not already present.\n   *\n   * @param {RoleResolvable|UserResolvable} userOrRole The user or role to update\n   * @param {PermissionOverwriteOptions} options The options for the update\n   * @param {GuildChannelOverwriteOptions} [overwriteOptions] The extra information for the update\n   * @returns {Promise<GuildChannel>}\n   * @example\n   * // Edit or Create permission overwrites for a message author\n   * message.channel.permissionOverwrites.edit(message.author, {\n   *   SendMessages: false\n   * })\n   *   .then(channel => console.log(channel.permissionOverwrites.cache.get(message.author.id)))\n   *   .catch(console.error);\n   */\n  async edit(userOrRole, options, overwriteOptions) {\n    const existing = this.cache.get(\n      this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole),\n    );\n    return this.upsert(userOrRole, options, overwriteOptions, existing);\n  }\n\n  /**\n   * Deletes permission overwrites for a user or role in this channel.\n   *\n   * @param {UserResolvable|RoleResolvable} userOrRole The user or role to delete\n   * @param {string} [reason] The reason for deleting the overwrite\n   * @returns {Promise<GuildChannel>}\n   */\n  async delete(userOrRole, reason) {\n    const userOrRoleId = this.channel.guild.roles.resolveId(userOrRole) ?? this.client.users.resolveId(userOrRole);\n    if (!userOrRoleId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'parameter', 'User nor a Role');\n\n    await this.client.rest.delete(Routes.channelPermission(this.channel.id, userOrRoleId), { reason });\n    return this.channel;\n  }\n}\n\nexports.PermissionOverwriteManager = PermissionOverwriteManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/PollAnswerVoterManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { Routes } = require('discord-api-types/v10');\nconst { User } = require('../structures/User.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for users who voted on a poll and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass PollAnswerVoterManager extends CachedManager {\n  constructor(answer) {\n    super(answer.client, User);\n\n    /**\n     * The poll answer that this manager belongs to\n     *\n     * @type {PollAnswer}\n     */\n    this.answer = answer;\n  }\n\n  /**\n   * The cache of this manager\n   *\n   * @type {Collection<Snowflake, User>}\n   * @name PollAnswerVoterManager#cache\n   */\n\n  /**\n   * Options used for fetching voters of a poll answer.\n   *\n   * @typedef {Object} BaseFetchPollAnswerVotersOptions\n   * @property {number} [limit] The maximum number of voters to fetch\n   * @property {Snowflake} [after] The user id to fetch voters after\n   */\n\n  /**\n   * Fetches the users that voted on this poll answer. Resolves with a collection of users, mapped by their ids.\n   *\n   * @param {BaseFetchPollAnswerVotersOptions} [options={}] Options for fetching the users\n   * @returns {Promise<Collection<Snowflake, User>>}\n   */\n  async fetch({ after, limit } = {}) {\n    const poll = this.answer.poll;\n    const query = makeURLSearchParams({ limit, after });\n    const data = await this.client.rest.get(Routes.pollAnswerVoters(poll.channelId, poll.messageId, this.answer.id), {\n      query,\n    });\n\n    return data.users.reduce((coll, rawUser) => {\n      const user = this.client.users._add(rawUser);\n      this.cache.set(user.id, user);\n      return coll.set(user.id, user);\n    }, new Collection());\n  }\n}\n\nexports.PollAnswerVoterManager = PollAnswerVoterManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/PresenceManager.js",
    "content": "'use strict';\n\nconst { Presence } = require('../structures/Presence.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for Presences and holds their cache.\n *\n * @extends {CachedManager}\n */\nclass PresenceManager extends CachedManager {\n  constructor(client, iterable) {\n    super(client, Presence, iterable);\n  }\n\n  /**\n   * The cache of Presences\n   *\n   * @type {Collection<Snowflake, Presence>}\n   * @name PresenceManager#cache\n   */\n\n  _add(data, cache) {\n    return super._add(data, cache, { id: data.user.id });\n  }\n\n  /**\n   * Data that can be resolved to a Presence object. This can be:\n   * - A Presence\n   * - A UserResolvable\n   * - A Snowflake\n   *\n   * @typedef {Presence|UserResolvable|Snowflake} PresenceResolvable\n   */\n\n  /**\n   * Resolves a {@link PresenceResolvable} to a {@link Presence} object.\n   *\n   * @param {PresenceResolvable} presence The presence resolvable to resolve\n   * @returns {?Presence}\n   */\n  resolve(presence) {\n    const presenceResolvable = super.resolve(presence);\n    if (presenceResolvable) return presenceResolvable;\n    const userId = this.client.users.resolveId(presence);\n    return super.cache.get(userId) ?? null;\n  }\n\n  /**\n   * Resolves a {@link PresenceResolvable} to a {@link Presence} id.\n   *\n   * @param {PresenceResolvable} presence The presence resolvable to resolve\n   * @returns {?Snowflake}\n   */\n  resolveId(presence) {\n    const presenceResolvable = super.resolveId(presence);\n    if (presenceResolvable) return presenceResolvable;\n    const userId = this.client.users.resolveId(presence);\n    return this.cache.has(userId) ? userId : null;\n  }\n}\n\nexports.PresenceManager = PresenceManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/ReactionManager.js",
    "content": "'use strict';\n\nconst { Routes } = require('discord-api-types/v10');\nconst { MessageReaction } = require('../structures/MessageReaction.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for reactions and holds their cache.\n *\n * @extends {CachedManager}\n */\nclass ReactionManager extends CachedManager {\n  constructor(message, iterable) {\n    super(message.client, MessageReaction, iterable);\n\n    /**\n     * The message that this manager belongs to\n     *\n     * @type {Message}\n     */\n    this.message = message;\n  }\n\n  _add(data, cache) {\n    return super._add(data, cache, { id: data.emoji.id ?? data.emoji.name, extras: [this.message] });\n  }\n\n  /**\n   * The reaction cache of this manager\n   *\n   * @type {Collection<string|Snowflake, MessageReaction>}\n   * @name ReactionManager#cache\n   */\n\n  /**\n   * Data that can be resolved to a MessageReaction object. This can be:\n   * - A MessageReaction\n   * - A Snowflake\n   * - The Unicode representation of an emoji\n   *\n   * @typedef {MessageReaction|Snowflake} MessageReactionResolvable\n   */\n\n  /**\n   * Resolves a {@link MessageReactionResolvable} to a {@link MessageReaction} object.\n   *\n   * @method resolve\n   * @memberof ReactionManager\n   * @instance\n   * @param {MessageReactionResolvable} reaction The MessageReaction to resolve\n   * @returns {?MessageReaction}\n   */\n\n  /**\n   * Resolves a {@link MessageReactionResolvable} to a {@link MessageReaction} id.\n   *\n   * @method resolveId\n   * @memberof ReactionManager\n   * @instance\n   * @param {MessageReactionResolvable} reaction The MessageReaction to resolve\n   * @returns {?Snowflake}\n   */\n\n  /**\n   * Removes all reactions from a message.\n   *\n   * @returns {Promise<Message>}\n   */\n  async removeAll() {\n    await this.client.rest.delete(Routes.channelMessageAllReactions(this.message.channelId, this.message.id));\n    return this.message;\n  }\n}\n\nexports.ReactionManager = ReactionManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/ReactionUserManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { ReactionType, Routes } = require('discord-api-types/v10');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { User } = require('../structures/User.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for users who reacted to a reaction and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass ReactionUserManager extends CachedManager {\n  constructor(reaction, iterable) {\n    super(reaction.client, User, iterable);\n\n    /**\n     * The reaction that this manager belongs to\n     *\n     * @type {MessageReaction}\n     */\n    this.reaction = reaction;\n  }\n\n  /**\n   * The cache of this manager\n   *\n   * @type {Collection<Snowflake, User>}\n   * @name ReactionUserManager#cache\n   */\n\n  /**\n   * Options used to fetch users who gave a reaction.\n   *\n   * @typedef {Object} FetchReactionUsersOptions\n   * @property {ReactionType} [type=ReactionType.Normal] The reaction type to fetch\n   * @property {number} [limit=100] The maximum amount of users to fetch, defaults to `100`\n   * @property {Snowflake} [after] Limit fetching users to those with an id greater than the supplied id\n   */\n\n  /**\n   * Fetches all the users that gave this reaction. Resolves with a collection of users, mapped by their ids.\n   *\n   * @param {FetchReactionUsersOptions} [options] Options for fetching the users\n   * @returns {Promise<Collection<Snowflake, User>>}\n   */\n  async fetch({ type = ReactionType.Normal, limit = 100, after } = {}) {\n    const message = this.reaction.message;\n    const query = makeURLSearchParams({ limit, after, type });\n    const data = await this.client.rest.get(\n      Routes.channelMessageReaction(message.channelId, message.id, this.reaction.emoji.identifier),\n      { query },\n    );\n    const users = new Collection();\n    for (const rawUser of data) {\n      const user = this.client.users._add(rawUser);\n      this.cache.set(user.id, user);\n      users.set(user.id, user);\n    }\n\n    return users;\n  }\n\n  /**\n   * Removes a user from this reaction.\n   *\n   * @param {UserResolvable} [user=this.client.user] The user to remove the reaction of\n   * @returns {Promise<MessageReaction>}\n   */\n  async remove(user = this.client.user) {\n    const userId = this.client.users.resolveId(user);\n    if (!userId) throw new DiscordjsError(ErrorCodes.ReactionResolveUser);\n    const message = this.reaction.message;\n    const route =\n      userId === this.client.user.id\n        ? Routes.channelMessageOwnReaction(message.channelId, message.id, this.reaction.emoji.identifier)\n        : Routes.channelMessageUserReaction(message.channelId, message.id, this.reaction.emoji.identifier, userId);\n    await this.client.rest.delete(route);\n    return this.reaction;\n  }\n}\n\nexports.ReactionUserManager = ReactionUserManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/RoleManager.js",
    "content": "'use strict';\n\nconst process = require('node:process');\nconst { Collection } = require('@discordjs/collection');\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { Role } = require('../structures/Role.js');\nconst { resolveImage } = require('../util/DataResolver.js');\nconst { PermissionsBitField } = require('../util/PermissionsBitField.js');\nconst { setPosition, resolveColor } = require('../util/Util.js');\nconst { CachedManager } = require('./CachedManager.js');\n\nlet cacheWarningEmitted = false;\n\n/**\n * Manages API methods for roles and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass RoleManager extends CachedManager {\n  constructor(guild, iterable) {\n    super(guild.client, Role, iterable);\n    if (!cacheWarningEmitted && this._cache.constructor.name !== 'Collection') {\n      cacheWarningEmitted = true;\n      process.emitWarning(\n        `Overriding the cache handling for ${this.constructor.name} is unsupported and breaks functionality.`,\n        'UnsupportedCacheOverwriteWarning',\n      );\n    }\n\n    /**\n     * The guild belonging to this manager\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n  }\n\n  /**\n   * The role cache of this manager\n   *\n   * @type {Collection<Snowflake, Role>}\n   * @name RoleManager#cache\n   */\n\n  _add(data, cache) {\n    return super._add(data, cache, { extras: [this.guild] });\n  }\n\n  /**\n   * Obtains a role from Discord, or the role cache if they're already available.\n   *\n   * @param {Snowflake} [id] The role's id\n   * @param {BaseFetchOptions} [options] Additional options for this fetch\n   * @returns {Promise<Role|Collection<Snowflake, Role>>}\n   * @example\n   * // Fetch all roles from the guild\n   * message.guild.roles.fetch()\n   *   .then(roles => console.log(`There are ${roles.size} roles.`))\n   *   .catch(console.error);\n   * @example\n   * // Fetch a single role\n   * message.guild.roles.fetch('222078108977594368')\n   *   .then(role => console.log(`The role color is: ${role.colors.primaryColor}`))\n   *   .catch(console.error);\n   */\n  async fetch(id, { cache = true, force = false } = {}) {\n    if (!id) {\n      const innerData = await this.client.rest.get(Routes.guildRoles(this.guild.id));\n      const roles = new Collection();\n      for (const role of innerData) roles.set(role.id, this._add(role, cache));\n      return roles;\n    }\n\n    if (!force) {\n      const existing = this.cache.get(id);\n      if (existing) return existing;\n    }\n\n    const data = await this.client.rest.get(Routes.guildRole(this.guild.id, id));\n    return this._add(data, cache);\n  }\n\n  /**\n   * Fetches the member count of each role in the guild.\n   * <info>This does not include the `@everyone` role.</info>\n   *\n   * @returns {Promise<Collection<Snowflake, number>>} A collection mapping role ids to their respective member counts.\n   */\n  async fetchMemberCounts() {\n    const data = await this.client.rest.get(Routes.guildRoleMemberCounts(this.guild.id));\n    return new Collection(Object.entries(data));\n  }\n\n  /**\n   * Data that can be resolved to a Role object. This can be:\n   * - A Role\n   * - A Snowflake\n   *\n   * @typedef {Role|Snowflake} RoleResolvable\n   */\n\n  /**\n   * Resolves a {@link RoleResolvable} to a {@link Role} object.\n   *\n   * @method resolve\n   * @memberof RoleManager\n   * @instance\n   * @param {RoleResolvable} role The role resolvable to resolve\n   * @returns {?Role}\n   */\n\n  /**\n   * Resolves a {@link RoleResolvable} to a {@link Role} id.\n   *\n   * @method resolveId\n   * @memberof RoleManager\n   * @instance\n   * @param {RoleResolvable} role The role resolvable to resolve\n   * @returns {?Snowflake}\n   */\n\n  /**\n   * @typedef {Object} RoleColorsResolvable\n   * @property {ColorResolvable} primaryColor The primary color of the role\n   * @property {ColorResolvable} [secondaryColor] The secondary color of the role.\n   * This will make the role a gradient between the other provided colors\n   * @property {ColorResolvable} [tertiaryColor] The tertiary color of the role.\n   * When sending `tertiaryColor` the API enforces the role color to be a holographic style with values of `primaryColor = 11127295`, `secondaryColor = 16759788`, and `tertiaryColor = 16761760`.\n   * These values are available as a constant: `Constants.HolographicStyle`\n   */\n\n  /**\n   * Options used to create a new role.\n   *\n   * @typedef {Object} RoleCreateOptions\n   * @property {string} [name] The name of the new role\n   * @property {RoleColorsResolvable} [colors] The colors to create the role with\n   * @property {boolean} [hoist] Whether or not the new role should be hoisted\n   * @property {PermissionResolvable} [permissions] The permissions for the new role\n   * @property {number} [position] The position of the new role\n   * @property {boolean} [mentionable] Whether or not the new role should be mentionable\n   * @property {?(BufferResolvable|Base64Resolvable|EmojiResolvable)} [icon] The icon for the role\n   * <warn>The `EmojiResolvable` should belong to the same guild as the role.\n   * If not, pass the emoji's URL directly</warn>\n   * @property {?string} [unicodeEmoji] The unicode emoji for the role\n   * @property {string} [reason] The reason for creating this role\n   */\n\n  /**\n   * Creates a new role in the guild with given information.\n   * <warn>The position will silently reset to 1 if an invalid one is provided, or none.</warn>\n   *\n   * @param {RoleCreateOptions} [options] Options for creating the new role\n   * @returns {Promise<Role>}\n   * @example\n   * // Create a new role\n   * guild.roles.create()\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Create a new role with data and a reason\n   * guild.roles.create({\n   *   name: 'Super Cool Blue People',\n   *   reason: 'we needed a role for Super Cool People',\n   *   colors: {\n   *     primaryColor: Colors.Blue,\n   *   },\n   * })\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Create a role with holographic colors\n   * guild.roles.create({\n   *   name: 'Holographic Role',\n   *   reason: 'Creating a role with holographic effect',\n   *   colors: {\n   *     primaryColor: Constants.HolographicStyle.Primary,\n   *     secondaryColor: Constants.HolographicStyle.Secondary,\n   *     tertiaryColor: Constants.HolographicStyle.Tertiary,\n   *   },\n   * })\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async create(options = {}) {\n    let { permissions, icon } = options;\n    const { name, hoist, position, mentionable, reason, unicodeEmoji } = options;\n    if (permissions !== undefined) permissions = new PermissionsBitField(permissions);\n    if (icon) {\n      const guildEmojiURL = this.guild.emojis.resolve(icon)?.imageURL();\n      icon = guildEmojiURL ? await resolveImage(guildEmojiURL) : await resolveImage(icon);\n      if (typeof icon !== 'string') icon = undefined;\n    }\n\n    const colors = options.colors && {\n      primary_color: resolveColor(options.colors.primaryColor),\n      secondary_color: options.colors.secondaryColor && resolveColor(options.colors.secondaryColor),\n      tertiary_color: options.colors.tertiaryColor && resolveColor(options.colors.tertiaryColor),\n    };\n\n    const data = await this.client.rest.post(Routes.guildRoles(this.guild.id), {\n      body: {\n        name,\n        colors,\n        hoist,\n        permissions,\n        mentionable,\n        icon,\n        unicode_emoji: unicodeEmoji,\n      },\n      reason,\n    });\n    const { role } = this.client.actions.GuildRoleCreate.handle({\n      guild_id: this.guild.id,\n      role: data,\n    });\n    if (position) return this.setPosition(role, position, { reason });\n    return role;\n  }\n\n  /**\n   * Options for editing a role\n   *\n   * @typedef {RoleData} RoleEditOptions\n   * @property {string} [reason] The reason for editing this role\n   */\n\n  /**\n   * Edits a role of the guild.\n   *\n   * @param {RoleResolvable} role The role to edit\n   * @param {RoleEditOptions} options The options to provide\n   * @returns {Promise<Role>}\n   * @example\n   * // Edit a role\n   * guild.roles.edit('222079219327434752', { name: 'buddies' })\n   *   .then(updated => console.log(`Edited role name to ${updated.name}`))\n   *   .catch(console.error);\n   */\n  async edit(role, options) {\n    const resolvedRole = this.resolve(role);\n    if (!resolvedRole) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'role', 'RoleResolvable');\n\n    if (typeof options.position === 'number') {\n      await this.setPosition(resolvedRole, options.position, { reason: options.reason });\n    }\n\n    let icon = options.icon;\n    if (icon) {\n      const guildEmojiURL = this.guild.emojis.resolve(icon)?.imageURL();\n      icon = guildEmojiURL ? await resolveImage(guildEmojiURL) : await resolveImage(icon);\n      if (typeof icon !== 'string') icon = undefined;\n    }\n\n    const colors = options.colors && {\n      primary_color: resolveColor(options.colors.primaryColor),\n      secondary_color: options.colors.secondaryColor && resolveColor(options.colors.secondaryColor),\n      tertiary_color: options.colors.tertiaryColor && resolveColor(options.colors.tertiaryColor),\n    };\n\n    const body = {\n      name: options.name,\n      colors,\n      hoist: options.hoist,\n      permissions: options.permissions === undefined ? undefined : new PermissionsBitField(options.permissions),\n      mentionable: options.mentionable,\n      icon,\n      unicode_emoji: options.unicodeEmoji,\n    };\n\n    const data = await this.client.rest.patch(Routes.guildRole(this.guild.id, resolvedRole.id), {\n      body,\n      reason: options.reason,\n    });\n\n    const clone = resolvedRole._clone();\n    clone._patch(data);\n    return clone;\n  }\n\n  /**\n   * Deletes a role.\n   *\n   * @param {RoleResolvable} role The role to delete\n   * @param {string} [reason] Reason for deleting the role\n   * @returns {Promise<void>}\n   * @example\n   * // Delete a role\n   * guild.roles.delete('222079219327434752', 'The role needed to go')\n   *   .then(() => console.log('Deleted the role'))\n   *   .catch(console.error);\n   */\n  async delete(role, reason) {\n    const id = this.resolveId(role);\n    await this.client.rest.delete(Routes.guildRole(this.guild.id, id), { reason });\n    this.client.actions.GuildRoleDelete.handle({ guild_id: this.guild.id, role_id: id });\n  }\n\n  /**\n   * Sets the new position of the role.\n   *\n   * @param {RoleResolvable} role The role to change the position of\n   * @param {number} position The new position for the role\n   * @param {SetRolePositionOptions} [options] Options for setting the position\n   * @returns {Promise<Role>}\n   * @example\n   * // Set the position of the role\n   * guild.roles.setPosition('222197033908436994', 1)\n   *   .then(updated => console.log(`Role position: ${updated.position}`))\n   *   .catch(console.error);\n   */\n  async setPosition(role, position, { relative, reason } = {}) {\n    const resolvedRole = this.resolve(role);\n    if (!resolvedRole) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'role', 'RoleResolvable');\n    const updatedRoles = await setPosition(\n      resolvedRole,\n      position,\n      relative,\n      this.guild._sortedRoles(),\n      this.client,\n      Routes.guildRoles(this.guild.id),\n      reason,\n    );\n\n    this.client.actions.GuildRolesPositionUpdate.handle({\n      guild_id: this.guild.id,\n      roles: updatedRoles,\n    });\n    return resolvedRole;\n  }\n\n  /**\n   * The data needed for updating a guild role's position\n   *\n   * @typedef {Object} GuildRolePosition\n   * @property {RoleResolvable} role The role's id\n   * @property {number} position The position to update\n   */\n\n  /**\n   * Batch-updates the guild's role positions\n   *\n   * @param {GuildRolePosition[]} rolePositions Role positions to update\n   * @returns {Promise<Guild>}\n   * @example\n   * guild.roles.setPositions([{ role: roleId, position: updatedRoleIndex }])\n   *  .then(guild => console.log(`Role positions updated for ${guild}`))\n   *  .catch(console.error);\n   */\n  async setPositions(rolePositions) {\n    // Make sure rolePositions are prepared for API\n    const resolvedRolePositions = rolePositions.map(rolePosition => ({\n      id: this.resolveId(rolePosition.role),\n      position: rolePosition.position,\n    }));\n\n    // Call the API to update role positions\n    await this.client.rest.patch(Routes.guildRoles(this.guild.id), { body: resolvedRolePositions });\n    return this.client.actions.GuildRolesPositionUpdate.handle({\n      guild_id: this.guild.id,\n      roles: resolvedRolePositions,\n    }).guild;\n  }\n\n  /**\n   * Compares the positions of two roles.\n   *\n   * @param {RoleResolvable} role1 First role to compare\n   * @param {RoleResolvable} role2 Second role to compare\n   * @returns {number} Negative number if the first role's position is lower (second role's is higher),\n   * positive number if the first's is higher (second's is lower), 0 if equal\n   */\n  comparePositions(role1, role2) {\n    const resolvedRole1 = this.resolve(role1);\n    const resolvedRole2 = this.resolve(role2);\n    if (!resolvedRole1 || !resolvedRole2) {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'role', 'Role nor a Snowflake');\n    }\n\n    const role1Position = resolvedRole1.position;\n    const role2Position = resolvedRole2.position;\n\n    if (role1Position === role2Position) {\n      return Number(BigInt(resolvedRole2.id) - BigInt(resolvedRole1.id));\n    }\n\n    return role1Position - role2Position;\n  }\n\n  /**\n   * Gets the managed role a user created when joining the guild, if any\n   * <info>Only ever available for bots</info>\n   *\n   * @param {UserResolvable} user The user to access the bot role for\n   * @returns {?Role}\n   */\n  botRoleFor(user) {\n    const userId = this.client.users.resolveId(user);\n    if (!userId) return null;\n    return this.cache.find(role => role.tags?.botId === userId) ?? null;\n  }\n\n  /**\n   * The `@everyone` role of the guild\n   *\n   * @type {Role}\n   * @readonly\n   */\n  get everyone() {\n    return this.cache.get(this.guild.id);\n  }\n\n  /**\n   * The premium subscriber role of the guild, if any\n   *\n   * @type {?Role}\n   * @readonly\n   */\n  get premiumSubscriberRole() {\n    return this.cache.find(role => role.tags?.premiumSubscriberRole) ?? null;\n  }\n\n  /**\n   * The role with the highest position in the cache\n   *\n   * @type {Role}\n   * @readonly\n   */\n  get highest() {\n    return this.cache.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev), this.cache.first());\n  }\n}\n\nexports.RoleManager = RoleManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/StageInstanceManager.js",
    "content": "'use strict';\n\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { StageInstance } = require('../structures/StageInstance.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for {@link StageInstance} objects and holds their cache.\n *\n * @extends {CachedManager}\n */\nclass StageInstanceManager extends CachedManager {\n  constructor(guild, iterable) {\n    super(guild.client, StageInstance, iterable);\n\n    /**\n     * The guild this manager belongs to\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n  }\n\n  /**\n   * The cache of this Manager\n   *\n   * @type {Collection<Snowflake, StageInstance>}\n   * @name StageInstanceManager#cache\n   */\n\n  /**\n   * Options used to create a stage instance.\n   *\n   * @typedef {Object} StageInstanceCreateOptions\n   * @property {string} topic The topic of the stage instance\n   * @property {StageInstancePrivacyLevel} [privacyLevel] The privacy level of the stage instance\n   * @property {boolean} [sendStartNotification] Whether to notify `@everyone` that the stage instance has started\n   * @property {GuildScheduledEventResolvable} [guildScheduledEvent]\n   * The guild scheduled event associated with the stage instance\n   */\n\n  /**\n   * Data that can be resolved to a Stage Channel object. This can be:\n   * - A StageChannel\n   * - A Snowflake\n   *\n   * @typedef {StageChannel|Snowflake} StageChannelResolvable\n   */\n\n  /**\n   * Creates a new stage instance.\n   *\n   * @param {StageChannelResolvable} channel The stage channel to associate the created stage instance to\n   * @param {StageInstanceCreateOptions} options The options to create the stage instance\n   * @returns {Promise<StageInstance>}\n   * @example\n   * // Create a stage instance\n   * guild.stageInstances.create('1234567890123456789', {\n   *  topic: 'A very creative topic',\n   *  privacyLevel: GuildPrivacyLevel.GuildOnly\n   * })\n   *  .then(stageInstance => console.log(stageInstance))\n   *  .catch(console.error);\n   */\n  async create(channel, options) {\n    const channelId = this.guild.channels.resolveId(channel);\n    if (!channelId) throw new DiscordjsError(ErrorCodes.StageChannelResolve);\n    if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true);\n    const { guildScheduledEvent, topic, privacyLevel, sendStartNotification } = options;\n\n    const guildScheduledEventId = guildScheduledEvent && this.resolveId(guildScheduledEvent);\n\n    const data = await this.client.rest.post(Routes.stageInstances(), {\n      body: {\n        channel_id: channelId,\n        topic,\n        privacy_level: privacyLevel,\n        send_start_notification: sendStartNotification,\n        guild_scheduled_event_id: guildScheduledEventId,\n      },\n    });\n\n    return this._add(data);\n  }\n\n  /**\n   * Fetches the stage instance associated with a stage channel, if it exists.\n   *\n   * @param {StageChannelResolvable} channel The stage channel whose associated stage instance is to be fetched\n   * @param {BaseFetchOptions} [options] Additional options for this fetch\n   * @returns {Promise<StageInstance>}\n   * @example\n   * // Fetch a stage instance\n   * guild.stageInstances.fetch('1234567890123456789')\n   *  .then(stageInstance => console.log(stageInstance))\n   *  .catch(console.error);\n   */\n  async fetch(channel, { cache = true, force = false } = {}) {\n    const channelId = this.guild.channels.resolveId(channel);\n    if (!channelId) throw new DiscordjsError(ErrorCodes.StageChannelResolve);\n\n    if (!force) {\n      const existing = this.cache.find(stageInstance => stageInstance.channelId === channelId);\n      if (existing) return existing;\n    }\n\n    const data = await this.client.rest.get(Routes.stageInstance(channelId));\n    return this._add(data, cache);\n  }\n\n  /**\n   * Options used to edit an existing stage instance.\n   *\n   * @typedef {Object} StageInstanceEditOptions\n   * @property {string} [topic] The new topic of the stage instance\n   * @property {StageInstancePrivacyLevel} [privacyLevel] The new privacy level of the stage instance\n   */\n\n  /**\n   * Edits an existing stage instance.\n   *\n   * @param {StageChannelResolvable} channel The stage channel whose associated stage instance is to be edited\n   * @param {StageInstanceEditOptions} options The options to edit the stage instance\n   * @returns {Promise<StageInstance>}\n   * @example\n   * // Edit a stage instance\n   * guild.stageInstances.edit('1234567890123456789', { topic: 'new topic' })\n   *  .then(stageInstance => console.log(stageInstance))\n   *  .catch(console.error);\n   */\n  async edit(channel, options) {\n    if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true);\n    const channelId = this.guild.channels.resolveId(channel);\n    if (!channelId) throw new DiscordjsError(ErrorCodes.StageChannelResolve);\n\n    const { topic, privacyLevel } = options;\n\n    const data = await this.client.rest.patch(Routes.stageInstance(channelId), {\n      body: {\n        topic,\n        privacy_level: privacyLevel,\n      },\n    });\n\n    if (this.cache.has(data.id)) {\n      const clone = this.cache.get(data.id)._clone();\n      clone._patch(data);\n      return clone;\n    }\n\n    return this._add(data);\n  }\n\n  /**\n   * Deletes an existing stage instance.\n   *\n   * @param {StageChannelResolvable} channel The stage channel whose associated stage instance is to be deleted\n   * @returns {Promise<void>}\n   */\n  async delete(channel) {\n    const channelId = this.guild.channels.resolveId(channel);\n    if (!channelId) throw new DiscordjsError(ErrorCodes.StageChannelResolve);\n\n    await this.client.rest.delete(Routes.stageInstance(channelId));\n  }\n}\n\nexports.StageInstanceManager = StageInstanceManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/SubscriptionManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { Subscription } = require('../structures/Subscription.js');\nconst { resolveSKUId } = require('../util/Util.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for subscriptions and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass SubscriptionManager extends CachedManager {\n  constructor(client, iterable) {\n    super(client, Subscription, iterable);\n  }\n\n  /**\n   * The cache of this manager\n   *\n   * @type {Collection<Snowflake, Subscription>}\n   * @name SubscriptionManager#cache\n   */\n\n  /**\n   * Options used to fetch a subscription\n   *\n   * @typedef {BaseFetchOptions} FetchSubscriptionOptions\n   * @property {SKUResolvable} sku The SKU to fetch the subscription for\n   * @property {Snowflake} subscriptionId The id of the subscription to fetch\n   */\n\n  /**\n   * Options used to fetch subscriptions\n   *\n   * @typedef {Object} FetchSubscriptionsOptions\n   * @property {Snowflake} [after] Consider only subscriptions after this subscription id\n   * @property {Snowflake} [before] Consider only subscriptions before this subscription id\n   * @property {number} [limit] The maximum number of subscriptions to fetch\n   * @property {SKUResolvable} sku The SKU to fetch subscriptions for\n   * @property {UserResolvable} user The user to fetch entitlements for\n   * <warn>If both `before` and `after` are provided, only `before` is respected</warn>\n   */\n\n  /**\n   * Fetches subscriptions for this application\n   *\n   * @param {FetchSubscriptionOptions|FetchSubscriptionsOptions} [options={}] Options for fetching the subscriptions\n   * @returns {Promise<Subscription|Collection<Snowflake, Subscription>>}\n   */\n  async fetch(options = {}) {\n    if (typeof options !== 'object') throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true);\n\n    const { after, before, cache, limit, sku, subscriptionId, user } = options;\n\n    const skuId = resolveSKUId(sku);\n\n    if (!skuId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'sku', 'SKUResolvable');\n\n    if (subscriptionId) {\n      const subscription = await this.client.rest.get(Routes.skuSubscription(skuId, subscriptionId));\n\n      return this._add(subscription, cache);\n    }\n\n    const query = makeURLSearchParams({\n      limit,\n      user_id: this.client.users.resolveId(user) ?? undefined,\n      sku_id: skuId,\n      before,\n      after,\n    });\n\n    const subscriptions = await this.client.rest.get(Routes.skuSubscriptions(skuId), { query });\n\n    return subscriptions.reduce(\n      (coll, subscription) => coll.set(subscription.id, this._add(subscription, cache)),\n      new Collection(),\n    );\n  }\n}\n\nexports.SubscriptionManager = SubscriptionManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/ThreadManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { ThreadChannel } = require('../structures/ThreadChannel.js');\nconst { MakeCacheOverrideSymbol } = require('../util/Symbols.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for thread-based channels and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass ThreadManager extends CachedManager {\n  static [MakeCacheOverrideSymbol] = ThreadManager;\n\n  constructor(channel, iterable) {\n    super(channel.client, ThreadChannel, iterable);\n\n    /**\n     * The channel this Manager belongs to\n     *\n     * @type {TextChannel|AnnouncementChannel|ForumChannel|MediaChannel}\n     */\n    this.channel = channel;\n  }\n\n  /**\n   * Data that can be resolved to a Thread Channel object. This can be:\n   * - A ThreadChannel object\n   * - A Snowflake\n   *\n   * @typedef {ThreadChannel|Snowflake} ThreadChannelResolvable\n   */\n\n  /**\n   * The cache of this Manager\n   *\n   * @type {Collection<Snowflake, ThreadChannel>}\n   * @name ThreadManager#cache\n   */\n\n  _add(thread) {\n    const existing = this.cache.get(thread.id);\n    if (existing) return existing;\n    this.cache.set(thread.id, thread);\n    return thread;\n  }\n\n  /**\n   * Resolves a {@link ThreadChannelResolvable} to a {@link ThreadChannel} object.\n   *\n   * @method resolve\n   * @memberof ThreadManager\n   * @instance\n   * @param {ThreadChannelResolvable} thread The ThreadChannel resolvable to resolve\n   * @returns {?ThreadChannel}\n   */\n\n  /**\n   * Resolves a {@link ThreadChannelResolvable} to a {@link ThreadChannel} id.\n   *\n   * @method resolveId\n   * @memberof ThreadManager\n   * @instance\n   * @param {ThreadChannelResolvable} thread The ThreadChannel resolvable to resolve\n   * @returns {?Snowflake}\n   */\n\n  /**\n   * Options for fetching multiple threads.\n   *\n   * @typedef {Object} FetchThreadsOptions\n   * @property {FetchArchivedThreadOptions} [archived] Options used to fetch archived threads\n   */\n\n  /**\n   * Obtains a thread from Discord, or the channel cache if it's already available.\n   *\n   * @param {ThreadChannelResolvable|FetchThreadsOptions} [options] The options to fetch threads. If it is a\n   * ThreadChannelResolvable then the specified thread will be fetched. Fetches all active threads if `undefined`\n   * @param {BaseFetchOptions} [cacheOptions] Additional options for this fetch. <warn>The `force` field gets ignored\n   * if `options` is not a {@link ThreadChannelResolvable}</warn>\n   * @returns {Promise<?(ThreadChannel|FetchedThreads|FetchedThreadsMore)>}\n   * {@link FetchedThreads} if active & {@link FetchedThreadsMore} if archived.\n   * @example\n   * // Fetch a thread by its id\n   * channel.threads.fetch('831955138126104859')\n   *   .then(channel => console.log(channel.name))\n   *   .catch(console.error);\n   */\n  async fetch(options, { cache, force } = {}) {\n    if (!options) return this.fetchActive(cache);\n    const channel = this.client.channels.resolveId(options);\n    if (channel) {\n      const threadChannel = await this.client.channels.fetch(channel, { cache, force });\n      if (threadChannel.parentId !== this.channel.id) throw new DiscordjsTypeError(ErrorCodes.NotAThreadOfParent);\n      return threadChannel;\n    }\n\n    if (options.archived) {\n      return this.fetchArchived(options.archived, cache);\n    }\n\n    return this.fetchActive(cache);\n  }\n\n  /**\n   * Data that can be resolved to a Date object. This can be:\n   * - A Date object\n   * - A number representing a timestamp\n   * - An {@link https://en.wikipedia.org/wiki/ISO_8601 ISO 8601} string\n   *\n   * @typedef {Date|number|string} DateResolvable\n   */\n\n  /**\n   * The options used to fetch archived threads.\n   *\n   * @typedef {Object} FetchArchivedThreadOptions\n   * @property {string} [type='public'] The type of threads to fetch (`public` or `private`)\n   * @property {boolean} [fetchAll=false] Whether to fetch **all** archived threads when `type` is `private`\n   * <info>This property requires the {@link PermissionFlagsBits.ManageThreads} permission if `true`.</info>\n   * @property {DateResolvable|ThreadChannelResolvable} [before] Only return threads that were archived before this Date\n   * or Snowflake\n   * <warn>Must be a {@link ThreadChannelResolvable} when `type` is `private` and `fetchAll` is `false`.</warn>\n   * @property {number} [limit] Maximum number of threads to return\n   */\n\n  /**\n   * Data returned from fetching multiple threads.\n   *\n   * @typedef {FetchedThreads} FetchedThreadsMore\n   * @property {?boolean} hasMore Whether there are potentially additional threads that require a subsequent call\n   */\n\n  /**\n   * Obtains a set of archived threads from Discord.\n   * <info>This method requires the {@link PermissionFlagsBits.ReadMessageHistory} permission\n   * in the parent channel.</info>\n   *\n   * @param {FetchArchivedThreadOptions} [options] The options to fetch archived threads\n   * @param {boolean} [cache=true] Whether to cache the new thread objects if they aren't already\n   * @returns {Promise<FetchedThreadsMore>}\n   */\n  async fetchArchived({ type = 'public', fetchAll = false, before, limit } = {}, cache = true) {\n    let path = Routes.channelThreads(this.channel.id, type);\n    if (type === 'private' && !fetchAll) {\n      path = Routes.channelJoinedArchivedThreads(this.channel.id);\n    }\n\n    let timestamp;\n    let id;\n    const query = makeURLSearchParams({ limit });\n    if (before !== undefined) {\n      if (before instanceof ThreadChannel || /^\\d{17,19}$/.test(String(before))) {\n        id = this.resolveId(before);\n        timestamp = this.resolve(before)?.archivedAt?.toISOString();\n        const toUse = type === 'private' && !fetchAll ? id : timestamp;\n        if (toUse) {\n          query.set('before', toUse);\n        }\n      } else {\n        try {\n          timestamp = new Date(before).toISOString();\n          if (type === 'public' || fetchAll) {\n            query.set('before', timestamp);\n          }\n        } catch {\n          throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'before', 'DateResolvable or ThreadChannelResolvable');\n        }\n      }\n    }\n\n    const raw = await this.client.rest.get(path, { query });\n    return this.constructor._mapThreads(raw, this.client, { parent: this.channel, cache });\n  }\n\n  /**\n   * Obtains all active threads in the channel.\n   *\n   * @param {boolean} [cache=true] Whether to cache the fetched data\n   * @returns {Promise<FetchedThreads>}\n   */\n  async fetchActive(cache = true) {\n    const data = await this.channel.guild.channels.rawFetchGuildActiveThreads();\n    return this.constructor._mapThreads(data, this.client, { parent: this.channel, cache });\n  }\n\n  static _mapThreads(rawThreads, client, { parent, guild, cache }) {\n    const threads = rawThreads.threads.reduce((coll, raw) => {\n      const thread = client.channels._add(raw, guild ?? parent?.guild, { cache });\n      if (parent && thread.parentId !== parent.id) return coll;\n      return coll.set(thread.id, thread);\n    }, new Collection());\n\n    // Discord sends the thread id as id in this object\n    const threadMembers = rawThreads.members.reduce((coll, raw) => {\n      const thread = threads.get(raw.id);\n      return thread ? coll.set(raw.user_id, thread.members._add(raw)) : coll;\n    }, new Collection());\n\n    const response = { threads, members: threadMembers };\n\n    // The GET `/guilds/{guild.id}/threads/active` route does not return `has_more`.\n    if ('has_more' in rawThreads) response.hasMore = rawThreads.has_more;\n    return response;\n  }\n}\n\nexports.ThreadManager = ThreadManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/ThreadMemberManager.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { ThreadMember } = require('../structures/ThreadMember.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for GuildMembers and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass ThreadMemberManager extends CachedManager {\n  constructor(thread, iterable) {\n    super(thread.client, ThreadMember, iterable);\n\n    /**\n     * The thread this manager belongs to\n     *\n     * @type {ThreadChannel}\n     */\n    this.thread = thread;\n  }\n\n  /**\n   * The cache of this Manager\n   *\n   * @type {Collection<Snowflake, ThreadMember>}\n   * @name ThreadMemberManager#cache\n   */\n\n  _add(data, cache = true) {\n    const existing = this.cache.get(data.user_id);\n    if (cache) existing?._patch(data, { cache });\n    if (existing) return existing;\n\n    const member = new ThreadMember(this.thread, data, { cache });\n    if (cache) this.cache.set(data.user_id, member);\n    return member;\n  }\n\n  /**\n   * Fetches the client user as a ThreadMember of the thread.\n   *\n   * @param {BaseFetchOptions} [options] The options for fetching the member\n   * @returns {Promise<ThreadMember>}\n   */\n  async fetchMe(options) {\n    return this.fetch({ ...options, member: this.client.user.id });\n  }\n\n  /**\n   * The client user as a ThreadMember of this ThreadChannel\n   *\n   * @type {?ThreadMember}\n   * @readonly\n   */\n  get me() {\n    return this.cache.get(this.client.user.id) ?? null;\n  }\n\n  /**\n   * Data that resolves to give a ThreadMember object. This can be:\n   * - A ThreadMember object\n   * - A User resolvable\n   *\n   * @typedef {ThreadMember|UserResolvable} ThreadMemberResolvable\n   */\n\n  /**\n   * Resolves a {@link ThreadMemberResolvable} to a {@link ThreadMember} object.\n   *\n   * @param {ThreadMemberResolvable} member The user that is part of the thread\n   * @returns {?GuildMember}\n   */\n  resolve(member) {\n    const memberResolvable = super.resolve(member);\n    if (memberResolvable) return memberResolvable;\n    const userId = this.client.users.resolveId(member);\n    if (userId) return super.cache.get(userId) ?? null;\n    return null;\n  }\n\n  /**\n   * Resolves a {@link ThreadMemberResolvable} to a {@link ThreadMember} id string.\n   *\n   * @param {ThreadMemberResolvable} member The user that is part of the guild\n   * @returns {?Snowflake}\n   */\n  resolveId(member) {\n    const memberResolvable = super.resolveId(member);\n    if (memberResolvable) return memberResolvable;\n    const userResolvable = this.client.users.resolveId(member);\n    return this.cache.has(userResolvable) ? userResolvable : null;\n  }\n\n  /**\n   * Adds a member to the thread.\n   *\n   * @param {UserResolvable|'@me'} member The member to add\n   * @returns {Promise<Snowflake>}\n   */\n  async add(member) {\n    const id = member === '@me' ? member : this.client.users.resolveId(member);\n    if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'member', 'UserResolvable');\n    await this.client.rest.put(Routes.threadMembers(this.thread.id, id));\n    return id;\n  }\n\n  /**\n   * Remove a user from the thread.\n   *\n   * @param {UserResolvable|'@me'} member The member to remove\n   * @returns {Promise<Snowflake>}\n   */\n  async remove(member) {\n    const id = member === '@me' ? member : this.client.users.resolveId(member);\n    if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'member', 'UserResolvable');\n    await this.client.rest.delete(Routes.threadMembers(this.thread.id, id));\n    return id;\n  }\n\n  /**\n   * Options used to fetch a thread member.\n   *\n   * @typedef {BaseFetchOptions} FetchThreadMemberOptions\n   * @property {ThreadMemberResolvable} member The thread member to fetch\n   * @property {boolean} [withMember] Whether to also return the guild member associated with this thread member\n   */\n\n  /**\n   * Options used to fetch multiple thread members with guild member data.\n   * <info>With `withMember` set to `true`, pagination is enabled.</info>\n   *\n   * @typedef {Object} FetchThreadMembersWithGuildMemberDataOptions\n   * @property {true} withMember Whether to also return the guild member data\n   * @property {Snowflake} [after] Consider only thread members after this id\n   * @property {number} [limit] The maximum number of thread members to return\n   * @property {boolean} [cache] Whether to cache the fetched thread members and guild members\n   */\n\n  /**\n   * Options used to fetch multiple thread members without guild member data.\n   *\n   * @typedef {Object} FetchThreadMembersWithoutGuildMemberDataOptions\n   * @property {false} [withMember] Whether to also return the guild member data\n   * @property {boolean} [cache] Whether to cache the fetched thread members\n   */\n\n  /**\n   * Options used to fetch multiple thread members.\n   *\n   * @typedef {FetchThreadMembersWithGuildMemberDataOptions|\n   * FetchThreadMembersWithoutGuildMemberDataOptions} FetchThreadMembersOptions\n   */\n\n  /**\n   * Fetches thread member(s) from Discord.\n   * <info>This method requires the {@link GatewayIntentBits.GuildMembers} privileged gateway intent.</info>\n   *\n   * @param {ThreadMemberResolvable|FetchThreadMemberOptions|FetchThreadMembersOptions} [options]\n   * Options for fetching thread member(s)\n   * @returns {Promise<ThreadMember|Collection<Snowflake, ThreadMember>>}\n   */\n  async fetch(options) {\n    if (!options) return this._fetchMany();\n    const { member, withMember, cache, force } = options;\n    const resolvedMember = this.resolveId(member ?? options);\n    if (resolvedMember) return this._fetchSingle({ member: resolvedMember, withMember, cache, force });\n    return this._fetchMany(options);\n  }\n\n  async _fetchSingle({ member, withMember, cache, force = false }) {\n    if (!force) {\n      const existing = this.cache.get(member);\n      if (existing) return existing;\n    }\n\n    const data = await this.client.rest.get(Routes.threadMembers(this.thread.id, member), {\n      query: makeURLSearchParams({ with_member: withMember }),\n    });\n\n    return this._add(data, cache);\n  }\n\n  async _fetchMany({ withMember, after, limit, cache } = {}) {\n    const data = await this.client.rest.get(Routes.threadMembers(this.thread.id), {\n      query: makeURLSearchParams({ with_member: withMember, after, limit }),\n    });\n\n    return data.reduce((col, member) => col.set(member.user_id, this._add(member, cache)), new Collection());\n  }\n}\n\nexports.ThreadMemberManager = ThreadMemberManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/UserManager.js",
    "content": "'use strict';\n\nconst { ChannelType, Routes } = require('discord-api-types/v10');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { GuildMember } = require('../structures/GuildMember.js');\nconst { Message } = require('../structures/Message.js');\nconst { ThreadMember } = require('../structures/ThreadMember.js');\nconst { User } = require('../structures/User.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for users and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass UserManager extends CachedManager {\n  constructor(client, iterable) {\n    super(client, User, iterable);\n  }\n\n  /**\n   * The cache of this manager\n   *\n   * @type {Collection<Snowflake, User>}\n   * @name UserManager#cache\n   */\n\n  /**\n   * Data that resolves to give a User object. This can be:\n   * - A User object\n   * - A Snowflake\n   * - A Message object (resolves to the message author)\n   * - A GuildMember object\n   * - A ThreadMember object\n   *\n   * @typedef {User|Snowflake|Message|GuildMember|ThreadMember} UserResolvable\n   */\n\n  /**\n   * The DM between the client's user and a user\n   *\n   * @param {Snowflake} userId The user id\n   * @returns {?DMChannel}\n   * @private\n   */\n  dmChannel(userId) {\n    return (\n      this.client.channels.cache.find(channel => channel.type === ChannelType.DM && channel.recipientId === userId) ??\n      null\n    );\n  }\n\n  /**\n   * Creates a {@link DMChannel} between the client and a user.\n   *\n   * @param {UserResolvable} user The UserResolvable to identify\n   * @param {BaseFetchOptions} [options] Additional options for this fetch\n   * @returns {Promise<DMChannel>}\n   */\n  async createDM(user, { cache = true, force = false } = {}) {\n    const id = this.resolveId(user);\n\n    if (!force) {\n      const dmChannel = this.dmChannel(id);\n      if (dmChannel && !dmChannel.partial) return dmChannel;\n    }\n\n    const data = await this.client.rest.post(Routes.userChannels(), { body: { recipient_id: id } });\n    return this.client.channels._add(data, null, { cache });\n  }\n\n  /**\n   * Deletes a {@link DMChannel} (if one exists) between the client and a user. Resolves with the channel if successful.\n   *\n   * @param {UserResolvable} user The UserResolvable to identify\n   * @returns {Promise<DMChannel>}\n   */\n  async deleteDM(user) {\n    const id = this.resolveId(user);\n    const dmChannel = this.dmChannel(id);\n    if (!dmChannel) throw new DiscordjsError(ErrorCodes.UserNoDMChannel);\n    await this.client.rest.delete(Routes.channel(dmChannel.id));\n    this.client.channels._remove(dmChannel.id);\n    return dmChannel;\n  }\n\n  /**\n   * Obtains a user from Discord, or the user cache if it's already available.\n   *\n   * @param {UserResolvable} user The user to fetch\n   * @param {BaseFetchOptions} [options] Additional options for this fetch\n   * @returns {Promise<User>}\n   */\n  async fetch(user, { cache = true, force = false } = {}) {\n    const id = this.resolveId(user);\n    if (!force) {\n      const existing = this.cache.get(id);\n      if (existing && !existing.partial) return existing;\n    }\n\n    const data = await this.client.rest.get(Routes.user(id));\n    return this._add(data, cache);\n  }\n\n  /**\n   * Sends a message to a user.\n   *\n   * @param {UserResolvable} user The UserResolvable to identify\n   * @param {string|MessagePayload|MessageCreateOptions} options The options to provide\n   * @returns {Promise<Message>}\n   */\n  async send(user, options) {\n    return (await this.createDM(user)).send(options);\n  }\n\n  /**\n   * Resolves a {@link UserResolvable} to a {@link User} object.\n   *\n   * @param {UserResolvable} user The UserResolvable to identify\n   * @returns {?User}\n   */\n  resolve(user) {\n    if (user instanceof GuildMember || user instanceof ThreadMember) return user.user;\n    if (user instanceof Message) return user.author;\n    return super.resolve(user);\n  }\n\n  /**\n   * Resolves a {@link UserResolvable} to a {@link User} id.\n   *\n   * @param {UserResolvable} user The UserResolvable to identify\n   * @returns {?Snowflake}\n   */\n  resolveId(user) {\n    if (user instanceof ThreadMember) return user.id;\n    if (user instanceof GuildMember) return user.user.id;\n    if (user instanceof Message) return user.author.id;\n    return super.resolveId(user);\n  }\n}\n\nexports.UserManager = UserManager;\n"
  },
  {
    "path": "packages/discord.js/src/managers/VoiceStateManager.js",
    "content": "'use strict';\n\nconst { Routes } = require('discord-api-types/v10');\nconst { VoiceState } = require('../structures/VoiceState.js');\nconst { CachedManager } = require('./CachedManager.js');\n\n/**\n * Manages API methods for VoiceStates and stores their cache.\n *\n * @extends {CachedManager}\n */\nclass VoiceStateManager extends CachedManager {\n  constructor(guild, iterable) {\n    super(guild.client, VoiceState, iterable);\n\n    /**\n     * The guild this manager belongs to\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n  }\n\n  /**\n   * The cache of this manager\n   *\n   * @type {Collection<Snowflake, VoiceState>}\n   * @name VoiceStateManager#cache\n   */\n\n  _add(data, cache = true) {\n    const existing = this.cache.get(data.user_id);\n    if (existing) return existing._patch(data);\n\n    const entry = new this.holds(this.guild, data);\n    if (cache) this.cache.set(data.user_id, entry);\n    return entry;\n  }\n\n  /**\n   * Obtains a user's voice state from discord or from the cache if it's already available.\n   *\n   * @param {UserResolvable|'@me'} member The member whose voice state is to be fetched\n   * @param {BaseFetchOptions} [options] Additional options for this fetch\n   * @returns {Promise<VoiceState>}\n   * @example\n   * // Fetch a member's voice state\n   * guild.voiceStates.fetch(\"66564597481480192\")\n   *    .then(console.log)\n   *    .catch(console.error);\n   */\n  async fetch(member, { cache = true, force = false } = {}) {\n    const id = member === '@me' ? member : this.guild.members.resolveId(member);\n    if (!force) {\n      const existing = this.cache.get(id === '@me' ? this.client.user.id : id);\n      if (existing) return existing;\n    }\n\n    const data = await this.client.rest.get(Routes.guildVoiceState(this.guild.id, id));\n    return this._add(data, cache);\n  }\n}\n\nexports.VoiceStateManager = VoiceStateManager;\n"
  },
  {
    "path": "packages/discord.js/src/sharding/Shard.js",
    "content": "/* eslint-disable promise/prefer-await-to-callbacks, promise/prefer-await-to-then, no-use-before-define */\n'use strict';\n\nconst path = require('node:path');\nconst process = require('node:process');\nconst { setTimeout, clearTimeout } = require('node:timers');\nconst { setTimeout: sleep } = require('node:timers/promises');\nconst { SHARE_ENV } = require('node:worker_threads');\nconst { AsyncEventEmitter } = require('@vladfrangu/async_event_emitter');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { ShardEvents } = require('../util/ShardEvents.js');\nconst { makeError, makePlainError } = require('../util/Util.js');\n\nlet childProcess = null;\nlet Worker = null;\n\n/**\n * A self-contained shard created by the {@link ShardingManager}. Each one has a {@link ChildProcess} that contains\n * an instance of the bot and its {@link Client}. When its child process/worker exits for any reason, the shard will\n * spawn a new one to replace it as necessary.\n *\n * @extends {AsyncEventEmitter}\n */\nclass Shard extends AsyncEventEmitter {\n  constructor(manager, id) {\n    super();\n\n    switch (manager.mode) {\n      case 'process':\n        childProcess = require('node:child_process');\n        break;\n      case 'worker':\n        Worker = require('node:worker_threads').Worker;\n        break;\n      default:\n        throw new Error(`Invalid sharding mode in Shard ${id}`);\n    }\n\n    /**\n     * Manager that created the shard\n     *\n     * @type {ShardingManager}\n     */\n    this.manager = manager;\n\n    /**\n     * The shard's id in the manager\n     *\n     * @type {number}\n     */\n    this.id = id;\n\n    /**\n     * Whether to pass silent flag to the shard's process (only when {@link ShardingManager#mode} is `process`)\n     *\n     * @type {boolean}\n     */\n    this.silent = manager.silent;\n\n    /**\n     * Arguments for the shard's process/worker\n     *\n     * @type {string[]}\n     */\n    this.args = manager.shardArgs ?? [];\n\n    /**\n     * Arguments for the shard's process/worker executable\n     *\n     * @type {string[]}\n     */\n    this.execArgv = manager.execArgv;\n\n    /**\n     * Environment variables for the shard's process, or workerData for the shard's worker\n     *\n     * @type {Object}\n     */\n    this.env = {\n      ...process.env,\n      SHARDING_MANAGER: true,\n      SHARDS: this.id,\n      SHARD_COUNT: this.manager.totalShards,\n      DISCORD_TOKEN: this.manager.token,\n    };\n\n    /**\n     * Whether the shard's {@link Client} is ready\n     *\n     * @type {boolean}\n     */\n    this.ready = false;\n\n    /**\n     * Process of the shard (if {@link ShardingManager#mode} is `process`)\n     *\n     * @type {?ChildProcess}\n     */\n    this.process = null;\n\n    /**\n     * Worker of the shard (if {@link ShardingManager#mode} is `worker`)\n     *\n     * @type {?Worker}\n     */\n    this.worker = null;\n\n    /**\n     * Ongoing promises for calls to {@link Shard#eval}, mapped by the `script` they were called with\n     *\n     * @type {Map<string, Promise>}\n     * @private\n     */\n    this._evals = new Map();\n\n    /**\n     * Ongoing promises for calls to {@link Shard#fetchClientValue}, mapped by the `prop` they were called with\n     *\n     * @type {Map<string, Promise>}\n     * @private\n     */\n    this._fetches = new Map();\n\n    /**\n     * Listener function for the {@link ChildProcess}' `exit` event\n     *\n     * @type {Function}\n     * @private\n     */\n    this._exitListener = null;\n  }\n\n  /**\n   * Forks a child process or creates a worker thread for the shard.\n   * <warn>You should not need to call this manually.</warn>\n   *\n   * @param {number} [timeout=30000] The amount in milliseconds to wait until the {@link Client} has become ready\n   * before resolving (`-1` or `Infinity` for no wait)\n   * @returns {Promise<ChildProcess>}\n   */\n  async spawn(timeout = 30_000) {\n    if (this.process) throw new DiscordjsError(ErrorCodes.ShardingProcessExists, this.id);\n    if (this.worker) throw new DiscordjsError(ErrorCodes.ShardingWorkerExists, this.id);\n\n    this._exitListener = this._handleExit.bind(this, undefined, timeout);\n\n    switch (this.manager.mode) {\n      case 'process':\n        this.process = childProcess\n          .fork(path.resolve(this.manager.file), this.args, {\n            env: this.env,\n            execArgv: this.execArgv,\n            silent: this.silent,\n          })\n          .on('message', this._handleMessage.bind(this))\n          .on('exit', this._exitListener);\n        break;\n      case 'worker':\n        this.worker = new Worker(path.resolve(this.manager.file), {\n          workerData: this.env,\n          env: SHARE_ENV,\n          execArgv: this.execArgv,\n          argv: this.args,\n        })\n          .on('message', this._handleMessage.bind(this))\n          .on('exit', this._exitListener);\n        break;\n      default:\n        break;\n    }\n\n    this._evals.clear();\n    this._fetches.clear();\n\n    const child = this.process ?? this.worker;\n\n    /**\n     * Emitted upon the creation of the shard's child process/worker.\n     *\n     * @event Shard#spawn\n     * @param {ChildProcess|Worker} process Child process/worker that was created\n     */\n    this.emit(ShardEvents.Spawn, child);\n\n    if (timeout === -1 || timeout === Infinity) return child;\n    return new Promise((resolve, reject) => {\n      const cleanup = () => {\n        clearTimeout(spawnTimeoutTimer);\n        this.off('ready', onReady);\n        this.off('disconnect', onDisconnect);\n        this.off('death', onDeath);\n      };\n\n      const onReady = () => {\n        cleanup();\n        resolve(child);\n      };\n\n      const onDisconnect = () => {\n        cleanup();\n        reject(new DiscordjsError(ErrorCodes.ShardingReadyDisconnected, this.id));\n      };\n\n      const onDeath = () => {\n        cleanup();\n        reject(new DiscordjsError(ErrorCodes.ShardingReadyDied, this.id));\n      };\n\n      const onTimeout = () => {\n        cleanup();\n        reject(new DiscordjsError(ErrorCodes.ShardingReadyTimeout, this.id));\n      };\n\n      const spawnTimeoutTimer = setTimeout(onTimeout, timeout);\n      this.once('ready', onReady);\n      this.once('disconnect', onDisconnect);\n      this.once('death', onDeath);\n    });\n  }\n\n  /**\n   * Immediately kills the shard's process/worker and does not restart it.\n   */\n  kill() {\n    if (this.process) {\n      this.process.removeListener('exit', this._exitListener);\n      this.process.kill();\n    } else {\n      this.worker.removeListener('exit', this._exitListener);\n      this.worker.terminate();\n    }\n\n    this._handleExit(false);\n  }\n\n  /**\n   * Options used to respawn a shard.\n   *\n   * @typedef {Object} ShardRespawnOptions\n   * @property {number} [delay=500] How long to wait between killing the process/worker and\n   * restarting it (in milliseconds)\n   * @property {number} [timeout=30000] The amount in milliseconds to wait until the {@link Client}\n   * has become ready before resolving (`-1` or `Infinity` for no wait)\n   */\n\n  /**\n   * Kills and restarts the shard's process/worker.\n   *\n   * @param {ShardRespawnOptions} [options] Options for respawning the shard\n   * @returns {Promise<ChildProcess>}\n   */\n  async respawn({ delay = 500, timeout = 30_000 } = {}) {\n    this.kill();\n    if (delay > 0) await sleep(delay);\n    return this.spawn(timeout);\n  }\n\n  /**\n   * Sends a message to the shard's process/worker.\n   *\n   * @param {*} message Message to send to the shard\n   * @returns {Promise<Shard>}\n   */\n  async send(message) {\n    return new Promise((resolve, reject) => {\n      if (this.process) {\n        this.process.send(message, err => {\n          if (err) reject(err);\n          else resolve(this);\n        });\n      } else {\n        this.worker.postMessage(message);\n        resolve(this);\n      }\n    });\n  }\n\n  /**\n   * Fetches a client property value of the shard.\n   *\n   * @param {string} prop Name of the client property to get, using periods for nesting\n   * @returns {Promise<*>}\n   * @example\n   * shard.fetchClientValue('guilds.cache.size')\n   *   .then(count => console.log(`${count} guilds in shard ${shard.id}`))\n   *   .catch(console.error);\n   */\n  async fetchClientValue(prop) {\n    // Shard is dead (maybe respawning), don't cache anything and error immediately\n    if (!this.process && !this.worker) {\n      throw new DiscordjsError(ErrorCodes.ShardingNoChildExists, this.id);\n    }\n\n    // Cached promise from previous call\n    if (this._fetches.has(prop)) return this._fetches.get(prop);\n\n    const promise = new Promise((resolve, reject) => {\n      const child = this.process ?? this.worker;\n\n      const listener = message => {\n        if (message?._fetchProp !== prop) return;\n        child.removeListener('message', listener);\n        this.decrementMaxListeners(child);\n        this._fetches.delete(prop);\n        if (message._error) reject(makeError(message._error));\n        else resolve(message._result);\n      };\n\n      this.incrementMaxListeners(child);\n      child.on('message', listener);\n\n      this.send({ _fetchProp: prop }).catch(error => {\n        child.removeListener('message', listener);\n        this.decrementMaxListeners(child);\n        this._fetches.delete(prop);\n        reject(error);\n      });\n    });\n\n    this._fetches.set(prop, promise);\n    return promise;\n  }\n\n  /**\n   * Evaluates a script or function on the shard, in the context of the {@link Client}.\n   *\n   * @param {string|Function} script JavaScript to run on the shard\n   * @param {*} [context] The context for the eval\n   * @returns {Promise<*>} Result of the script execution\n   */\n  async eval(script, context) {\n    // Stringify the script if it's a Function\n    const _eval = typeof script === 'function' ? `(${script})(this, ${JSON.stringify(context)})` : script;\n\n    // Shard is dead (maybe respawning), don't cache anything and error immediately\n    if (!this.process && !this.worker) {\n      throw new DiscordjsError(ErrorCodes.ShardingNoChildExists, this.id);\n    }\n\n    // Cached promise from previous call\n    if (this._evals.has(_eval)) return this._evals.get(_eval);\n\n    const promise = new Promise((resolve, reject) => {\n      const child = this.process ?? this.worker;\n\n      const listener = message => {\n        if (message?._eval !== _eval) return;\n        child.removeListener('message', listener);\n        this.decrementMaxListeners(child);\n        this._evals.delete(_eval);\n        if (message._error) reject(makeError(message._error));\n        else resolve(message._result);\n      };\n\n      this.incrementMaxListeners(child);\n      child.on('message', listener);\n\n      this.send({ _eval }).catch(error => {\n        child.removeListener('message', listener);\n        this.decrementMaxListeners(child);\n        this._evals.delete(_eval);\n        reject(error);\n      });\n    });\n\n    this._evals.set(_eval, promise);\n    return promise;\n  }\n\n  /**\n   * Handles a message received from the child process/worker.\n   *\n   * @param {*} message Message received\n   * @private\n   */\n  _handleMessage(message) {\n    if (message) {\n      // Shard is ready\n      if (message._ready) {\n        this.ready = true;\n        /**\n         * Emitted upon the shard's {@link Client#event:clientReady} event.\n         *\n         * @event Shard#ready\n         */\n        this.emit(ShardEvents.Ready);\n        return;\n      }\n\n      // Shard has disconnected\n      if (message._disconnect) {\n        this.ready = false;\n        /**\n         * Emitted upon the shard's {@link WebSocketShardEvents#Closed} event.\n         *\n         * @event Shard#disconnect\n         */\n        this.emit(ShardEvents.Disconnect);\n        return;\n      }\n\n      // Shard has resumed\n      if (message._resume) {\n        this.ready = true;\n        /**\n         * Emitted upon the shard's {@link WebSocketShardEvents#Resumed} event.\n         *\n         * @event Shard#resume\n         */\n        this.emit(ShardEvents.Resume);\n        return;\n      }\n\n      // Shard is requesting a property fetch\n      if (message._sFetchProp) {\n        const resp = { _sFetchProp: message._sFetchProp, _sFetchPropShard: message._sFetchPropShard };\n        this.manager.fetchClientValues(message._sFetchProp, message._sFetchPropShard).then(\n          async results => this.send({ ...resp, _result: results }),\n          async error => this.send({ ...resp, _error: makePlainError(error) }),\n        );\n        return;\n      }\n\n      // Shard is requesting an eval broadcast\n      if (message._sEval) {\n        const resp = { _sEval: message._sEval, _sEvalShard: message._sEvalShard };\n        this.manager._performOnShards('eval', [message._sEval], message._sEvalShard).then(\n          async results => this.send({ ...resp, _result: results }),\n          async error => this.send({ ...resp, _error: makePlainError(error) }),\n        );\n        return;\n      }\n\n      // Shard is requesting a respawn of all shards\n      if (message._sRespawnAll) {\n        const { shardDelay, respawnDelay, timeout } = message._sRespawnAll;\n        this.manager.respawnAll({ shardDelay, respawnDelay, timeout }).catch(() => {\n          // Do nothing\n        });\n        return;\n      }\n    }\n\n    /**\n     * Emitted upon receiving a message from the child process/worker.\n     *\n     * @event Shard#message\n     * @param {*} message Message that was received\n     */\n    this.emit(ShardEvents.Message, message);\n  }\n\n  /**\n   * Handles the shard's process/worker exiting.\n   *\n   * @param {boolean} [respawn=this.manager.respawn] Whether to spawn the shard again\n   * @param {number} [timeout] The amount in milliseconds to wait until the {@link Client}\n   * has become ready (`-1` or `Infinity` for no wait)\n   * @private\n   */\n  _handleExit(respawn = this.manager.respawn, timeout = undefined) {\n    /**\n     * Emitted upon the shard's child process/worker exiting.\n     *\n     * @event Shard#death\n     * @param {ChildProcess|Worker} process Child process/worker that exited\n     */\n    this.emit(ShardEvents.Death, this.process ?? this.worker);\n\n    this.ready = false;\n    this.process = null;\n    this.worker = null;\n    this._evals.clear();\n    this._fetches.clear();\n\n    if (respawn) this.spawn(timeout).catch(error => this.emit(ShardEvents.Error, error));\n  }\n\n  /**\n   * Increments max listeners by one for a given emitter, if they are not zero.\n   *\n   * @param {Worker|ChildProcess} emitter The emitter that emits the events.\n   * @private\n   */\n  incrementMaxListeners(emitter) {\n    const maxListeners = emitter.getMaxListeners();\n    if (maxListeners !== 0) {\n      emitter.setMaxListeners(maxListeners + 1);\n    }\n  }\n\n  /**\n   * Decrements max listeners by one for a given emitter, if they are not zero.\n   *\n   * @param {Worker|ChildProcess} emitter The emitter that emits the events.\n   * @private\n   */\n  decrementMaxListeners(emitter) {\n    const maxListeners = emitter.getMaxListeners();\n    if (maxListeners !== 0) {\n      emitter.setMaxListeners(maxListeners - 1);\n    }\n  }\n}\n\nexports.Shard = Shard;\n"
  },
  {
    "path": "packages/discord.js/src/sharding/ShardClientUtil.js",
    "content": "/* eslint-disable promise/prefer-await-to-callbacks, promise/prefer-await-to-then */\n'use strict';\n\nconst process = require('node:process');\nconst { calculateShardId } = require('@discordjs/util');\nconst { WebSocketShardEvents } = require('@discordjs/ws');\nconst { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { Events } = require('../util/Events.js');\nconst { makeError, makePlainError } = require('../util/Util.js');\n\n/**\n * Helper class for sharded clients spawned as a child process/worker, such as from a {@link ShardingManager}.\n * Utilizes IPC to send and receive data to/from the master process and other shards.\n */\nclass ShardClientUtil {\n  constructor(client, mode) {\n    /**\n     * Client for the shard\n     *\n     * @type {Client}\n     */\n    this.client = client;\n\n    /**\n     * Mode the shard was spawned with\n     *\n     * @type {ShardingManagerMode}\n     */\n    this.mode = mode;\n\n    /**\n     * Message port for the master process (only when {@link ShardClientUtil#mode} is `worker`)\n     *\n     * @type {?MessagePort}\n     */\n    this.parentPort = null;\n\n    switch (mode) {\n      case 'process':\n        process.on('message', this._handleMessage.bind(this));\n        client.on(Events.ClientReady, () => {\n          process.send({ _ready: true });\n        });\n        client.ws.on(WebSocketShardEvents.Closed, () => {\n          process.send({ _disconnect: true });\n        });\n        client.ws.on(WebSocketShardEvents.Resumed, () => {\n          process.send({ _resume: true });\n        });\n        break;\n      case 'worker':\n        this.parentPort = require('node:worker_threads').parentPort;\n        this.parentPort.on('message', this._handleMessage.bind(this));\n        client.on(Events.ClientReady, () => {\n          this.parentPort.postMessage({ _ready: true });\n        });\n        client.ws.on(WebSocketShardEvents.Closed, () => {\n          this.parentPort.postMessage({ _disconnect: true });\n        });\n        client.ws.on(WebSocketShardEvents.Resumed, () => {\n          this.parentPort.postMessage({ _resume: true });\n        });\n        break;\n      default:\n        break;\n    }\n  }\n\n  /**\n   * Sends a message to the master process.\n   *\n   * @param {*} message Message to send\n   * @returns {Promise<void>}\n   * @emits Shard#message\n   */\n  async send(message) {\n    return new Promise((resolve, reject) => {\n      switch (this.mode) {\n        case 'process':\n          process.send(message, err => {\n            if (err) reject(err);\n            else resolve();\n          });\n          break;\n        case 'worker':\n          this.parentPort.postMessage(message);\n          resolve();\n          break;\n        default:\n          break;\n      }\n    });\n  }\n\n  /**\n   * Fetches a client property value of each shard, or a given shard.\n   *\n   * @param {string} prop Name of the client property to get, using periods for nesting\n   * @param {number} [shard] Shard to fetch property from, all if undefined\n   * @returns {Promise<*|Array<*>>}\n   * @example\n   * client.shard.fetchClientValues('guilds.cache.size')\n   *   .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`))\n   *   .catch(console.error);\n   * @see {@link ShardingManager#fetchClientValues}\n   */\n  async fetchClientValues(prop, shard) {\n    return new Promise((resolve, reject) => {\n      const parent = this.parentPort ?? process;\n\n      const listener = message => {\n        if (message?._sFetchProp !== prop || message._sFetchPropShard !== shard) return;\n        parent.removeListener('message', listener);\n        this.decrementMaxListeners(parent);\n        if (message._error) reject(makeError(message._error));\n        else resolve(message._result);\n      };\n\n      this.incrementMaxListeners(parent);\n      parent.on('message', listener);\n\n      this.send({ _sFetchProp: prop, _sFetchPropShard: shard }).catch(error => {\n        parent.removeListener('message', listener);\n        this.decrementMaxListeners(parent);\n        reject(error);\n      });\n    });\n  }\n\n  /**\n   * Evaluates a script or function on all shards, or a given shard, in the context of the {@link Client}s.\n   *\n   * @param {Function} script JavaScript to run on each shard\n   * @param {BroadcastEvalOptions} [options={}] The options for the broadcast\n   * @returns {Promise<*|Array<*>>} Results of the script execution\n   * @example\n   * client.shard.broadcastEval(client => client.guilds.cache.size)\n   *   .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`))\n   *   .catch(console.error);\n   * @see {@link ShardingManager#broadcastEval}\n   */\n  async broadcastEval(script, options = {}) {\n    return new Promise((resolve, reject) => {\n      const parent = this.parentPort ?? process;\n      if (typeof script !== 'function') {\n        reject(new DiscordjsTypeError(ErrorCodes.ShardingInvalidEvalBroadcast));\n        return;\n      }\n\n      const evalScript = `(${script})(this, ${JSON.stringify(options.context)})`;\n\n      const listener = message => {\n        if (message?._sEval !== evalScript || message._sEvalShard !== options.shard) return;\n        parent.removeListener('message', listener);\n        this.decrementMaxListeners(parent);\n        if (message._error) reject(makeError(message._error));\n        else resolve(message._result);\n      };\n\n      this.incrementMaxListeners(parent);\n      parent.on('message', listener);\n      this.send({ _sEval: evalScript, _sEvalShard: options.shard }).catch(error => {\n        parent.removeListener('message', listener);\n        this.decrementMaxListeners(parent);\n        reject(error);\n      });\n    });\n  }\n\n  /**\n   * Requests a respawn of all shards.\n   *\n   * @param {MultipleShardRespawnOptions} [options] Options for respawning shards\n   * @returns {Promise<void>} Resolves upon the message being sent\n   * @see {@link ShardingManager#respawnAll}\n   */\n  async respawnAll({ shardDelay = 5_000, respawnDelay = 500, timeout = 30_000 } = {}) {\n    return this.send({ _sRespawnAll: { shardDelay, respawnDelay, timeout } });\n  }\n\n  /**\n   * Handles an IPC message.\n   *\n   * @param {*} message Message received\n   * @private\n   */\n  async _handleMessage(message) {\n    if (!message) return;\n    if (message._fetchProp) {\n      try {\n        const props = message._fetchProp.split('.');\n        let value = this.client;\n        for (const prop of props) value = value[prop];\n        this._respond('fetchProp', { _fetchProp: message._fetchProp, _result: value });\n      } catch (error) {\n        this._respond('fetchProp', { _fetchProp: message._fetchProp, _error: makePlainError(error) });\n      }\n    } else if (message._eval) {\n      try {\n        this._respond('eval', { _eval: message._eval, _result: await this.client._eval(message._eval) });\n      } catch (error) {\n        this._respond('eval', { _eval: message._eval, _error: makePlainError(error) });\n      }\n    }\n  }\n\n  /**\n   * Sends a message to the master process, emitting an error from the client upon failure.\n   *\n   * @param {string} type Type of response to send\n   * @param {*} message Message to send\n   * @private\n   */\n  _respond(type, message) {\n    this.send(message).catch(error_ => {\n      const error = new Error(`Error when sending ${type} response to master process: ${error_.message}`);\n      error.stack = error_.stack;\n      /**\n       * Emitted when the client encounters an error.\n       * <warn>Errors thrown within this event do not have a catch handler, it is\n       * recommended to not use async functions as `error` event handlers. See the\n       * {@link https://nodejs.org/api/events.html#capture-rejections-of-promises Node.js documentation}\n       * for details.)</warn>\n       *\n       * @event Client#error\n       * @param {Error} error The error encountered\n       */\n      this.client.emit(Events.Error, error);\n    });\n  }\n\n  /**\n   * Creates/gets the singleton of this class.\n   *\n   * @param {Client} client The client to use\n   * @param {ShardingManagerMode} mode Mode the shard was spawned with\n   * @returns {ShardClientUtil}\n   */\n  static singleton(client, mode) {\n    if (this._singleton) {\n      client.emit(\n        Events.Warn,\n        'Multiple clients created in child process/worker; only the first will handle sharding helpers.',\n      );\n    } else {\n      this._singleton = new this(client, mode);\n    }\n\n    return this._singleton;\n  }\n\n  /**\n   * Get the shard id for a given guild id.\n   *\n   * @param {Snowflake} guildId Snowflake guild id to get shard id for\n   * @param {number} shardCount Number of shards\n   * @returns {number}\n   */\n  static shardIdForGuildId(guildId, shardCount) {\n    const shard = calculateShardId(guildId, shardCount);\n    if (shard < 0) throw new DiscordjsError(ErrorCodes.ShardingShardMiscalculation, shard, guildId, shardCount);\n    return shard;\n  }\n\n  /**\n   * Increments max listeners by one for a given emitter, if they are not zero.\n   *\n   * @param {Worker|ChildProcess} emitter The emitter that emits the events.\n   * @private\n   */\n  incrementMaxListeners(emitter) {\n    const maxListeners = emitter.getMaxListeners();\n    if (maxListeners !== 0) {\n      emitter.setMaxListeners(maxListeners + 1);\n    }\n  }\n\n  /**\n   * Decrements max listeners by one for a given emitter, if they are not zero.\n   *\n   * @param {Worker|ChildProcess} emitter The emitter that emits the events.\n   * @private\n   */\n  decrementMaxListeners(emitter) {\n    const maxListeners = emitter.getMaxListeners();\n    if (maxListeners !== 0) {\n      emitter.setMaxListeners(maxListeners - 1);\n    }\n  }\n}\n\nexports.ShardClientUtil = ShardClientUtil;\n"
  },
  {
    "path": "packages/discord.js/src/sharding/ShardingManager.js",
    "content": "'use strict';\n\nconst fs = require('node:fs');\nconst path = require('node:path');\nconst process = require('node:process');\nconst { setTimeout: sleep } = require('node:timers/promises');\nconst { Collection } = require('@discordjs/collection');\nconst { range } = require('@discordjs/util');\nconst { AsyncEventEmitter } = require('@vladfrangu/async_event_emitter');\nconst { DiscordjsError, DiscordjsTypeError, DiscordjsRangeError, ErrorCodes } = require('../errors/index.js');\nconst { fetchRecommendedShardCount } = require('../util/Util.js');\nconst { Shard } = require('./Shard.js');\n\n/**\n * This is a utility class that makes multi-process sharding of a bot an easy and painless experience.\n * It works by spawning a self-contained {@link ChildProcess} or {@link Worker} for each individual shard, each\n * containing its own instance of your bot's {@link Client}. They all have a line of communication with the master\n * process, and there are several useful methods that utilize it in order to simplify tasks that are normally difficult\n * with sharding. It can spawn a specific number of shards or the amount that Discord suggests for the bot, and takes a\n * path to your main bot script to launch for each one.\n *\n * @extends {AsyncEventEmitter}\n */\nclass ShardingManager extends AsyncEventEmitter {\n  /**\n   * The mode to spawn shards with for a {@link ShardingManager}. Can be either one of:\n   * - 'process' to use child processes\n   * - 'worker' to use {@link Worker} threads\n   *\n   * @typedef {string} ShardingManagerMode\n   */\n\n  /**\n   * The options to spawn shards with for a {@link ShardingManager}.\n   *\n   * @typedef {Object} ShardingManagerOptions\n   * @property {string|number} [totalShards='auto'] Number of total shards of all shard managers or \"auto\"\n   * @property {string|number[]} [shardList='auto'] List of shards to spawn or \"auto\"\n   * @property {ShardingManagerMode} [mode='process'] Which mode to use for shards\n   * @property {boolean} [respawn=true] Whether shards should automatically respawn upon exiting\n   * @property {boolean} [silent=false] Whether to pass the silent flag to child process\n   * (only available when mode is set to 'process')\n   * @property {string[]} [shardArgs=[]] Arguments to pass to the shard script when spawning\n   * @property {string[]} [execArgv=[]] Arguments to pass to the shard script executable when spawning\n   * @property {string} [token] Token to use for automatic shard count and passing to shards\n   */\n\n  /**\n   * @param {string} file Path to your shard script file\n   * @param {ShardingManagerOptions} [options] Options for the sharding manager\n   */\n  constructor(file, options) {\n    super();\n    const _options = {\n      totalShards: 'auto',\n      mode: 'process',\n      respawn: true,\n      silent: false,\n      shardArgs: [],\n      execArgv: [],\n      token: process.env.DISCORD_TOKEN,\n      ...options,\n    };\n\n    /**\n     * Path to the shard script file\n     *\n     * @type {string}\n     */\n    this.file = file;\n    if (!file) throw new DiscordjsError(ErrorCodes.ClientInvalidOption, 'File', 'specified.');\n    if (!path.isAbsolute(file)) this.file = path.resolve(process.cwd(), file);\n    // eslint-disable-next-line n/no-sync\n    const stats = fs.statSync(this.file);\n    if (!stats.isFile()) throw new DiscordjsError(ErrorCodes.ClientInvalidOption, 'File', 'a file');\n\n    /**\n     * List of shards this sharding manager spawns\n     *\n     * @type {string|number[]}\n     */\n    this.shardList = _options.shardList ?? 'auto';\n    if (this.shardList !== 'auto') {\n      if (!Array.isArray(this.shardList)) {\n        throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'shardList', 'an array.');\n      }\n\n      this.shardList = [...new Set(this.shardList)];\n      if (this.shardList.length < 1) {\n        throw new DiscordjsRangeError(ErrorCodes.ClientInvalidOption, 'shardList', 'at least 1 id.');\n      }\n\n      if (\n        this.shardList.some(\n          shardId => typeof shardId !== 'number' || Number.isNaN(shardId) || !Number.isInteger(shardId) || shardId < 0,\n        )\n      ) {\n        throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'shardList', 'an array of positive integers.');\n      }\n    }\n\n    /**\n     * Amount of shards that all sharding managers spawn in total\n     *\n     * @type {number}\n     */\n    this.totalShards = _options.totalShards || 'auto';\n    if (this.totalShards !== 'auto') {\n      if (typeof this.totalShards !== 'number' || Number.isNaN(this.totalShards)) {\n        throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'Amount of shards', 'a number.');\n      }\n\n      if (this.totalShards < 1) {\n        throw new DiscordjsRangeError(ErrorCodes.ClientInvalidOption, 'Amount of shards', 'at least 1.');\n      }\n\n      if (!Number.isInteger(this.totalShards)) {\n        throw new DiscordjsRangeError(ErrorCodes.ClientInvalidOption, 'Amount of shards', 'an integer.');\n      }\n    }\n\n    /**\n     * Mode for shards to spawn with\n     *\n     * @type {ShardingManagerMode}\n     */\n    this.mode = _options.mode;\n    if (this.mode !== 'process' && this.mode !== 'worker') {\n      throw new DiscordjsRangeError(ErrorCodes.ClientInvalidOption, 'Sharding mode', '\"process\" or \"worker\"');\n    }\n\n    /**\n     * Whether shards should automatically respawn upon exiting\n     *\n     * @type {boolean}\n     */\n    this.respawn = _options.respawn;\n\n    /**\n     * Whether to pass the silent flag to child process (only when {@link ShardingManager#mode} is `process`)\n     *\n     * @type {boolean}\n     */\n    this.silent = _options.silent;\n\n    /**\n     * An array of arguments to pass to shards (only when {@link ShardingManager#mode} is `process`)\n     *\n     * @type {string[]}\n     */\n    this.shardArgs = _options.shardArgs;\n\n    /**\n     * An array of arguments to pass to the executable (only when {@link ShardingManager#mode} is `process`)\n     *\n     * @type {string[]}\n     */\n    this.execArgv = _options.execArgv;\n\n    /**\n     * Token to use for obtaining the automatic shard count, and passing to shards\n     *\n     * @type {?string}\n     */\n    this.token = _options.token?.replace(/^bot\\s*/i, '') ?? null;\n\n    /**\n     * A collection of shards that this manager has spawned\n     *\n     * @type {Collection<number, Shard>}\n     */\n    this.shards = new Collection();\n\n    process.env.SHARDING_MANAGER = true;\n    process.env.SHARDING_MANAGER_MODE = this.mode;\n    process.env.DISCORD_TOKEN = this.token;\n  }\n\n  /**\n   * Creates a single shard.\n   * <warn>Using this method is usually not necessary if you use the spawn method.</warn>\n   *\n   * @param {number} [id=this.shards.size] Id of the shard to create\n   * <info>This is usually not necessary to manually specify.</info>\n   * @returns {Shard} Note that the created shard needs to be explicitly spawned using its spawn method.\n   */\n  createShard(id = this.shards.size) {\n    const shard = new Shard(this, id);\n    this.shards.set(id, shard);\n    /**\n     * Emitted upon creating a shard.\n     *\n     * @event ShardingManager#shardCreate\n     * @param {Shard} shard Shard that was created\n     */\n    this.emit('shardCreate', shard);\n    return shard;\n  }\n\n  /**\n   * Options used to spawn multiple shards.\n   *\n   * @typedef {Object} MultipleShardSpawnOptions\n   * @property {number|string} [amount=this.totalShards] Number of shards to spawn\n   * @property {number} [delay=5500] How long to wait in between spawning each shard (in milliseconds)\n   * @property {number} [timeout=30000] The amount in milliseconds to wait until the {@link Client} has become ready\n   */\n\n  /**\n   * Spawns multiple shards.\n   *\n   * @param {MultipleShardSpawnOptions} [options] Options for spawning shards\n   * @returns {Promise<Collection<number, Shard>>}\n   */\n  async spawn({ amount = this.totalShards, delay = 5_500, timeout = 30_000 } = {}) {\n    // Obtain/verify the number of shards to spawn\n    let shardAmount = amount;\n    if (shardAmount === 'auto') {\n      // eslint-disable-next-line require-atomic-updates\n      shardAmount = await fetchRecommendedShardCount(this.token);\n    } else {\n      if (typeof shardAmount !== 'number' || Number.isNaN(shardAmount)) {\n        throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'Amount of shards', 'a number.');\n      }\n\n      if (shardAmount < 1) {\n        throw new DiscordjsRangeError(ErrorCodes.ClientInvalidOption, 'Amount of shards', 'at least 1.');\n      }\n\n      if (!Number.isInteger(shardAmount)) {\n        throw new DiscordjsTypeError(ErrorCodes.ClientInvalidOption, 'Amount of shards', 'an integer.');\n      }\n    }\n\n    // Make sure this many shards haven't already been spawned\n    if (this.shards.size >= shardAmount) throw new DiscordjsError(ErrorCodes.ShardingAlreadySpawned, this.shards.size);\n    if (this.shardList === 'auto' || this.totalShards === 'auto' || this.totalShards !== shardAmount) {\n      this.shardList = [...range(shardAmount)];\n    }\n\n    if (this.totalShards === 'auto' || this.totalShards !== shardAmount) {\n      this.totalShards = shardAmount;\n    }\n\n    if (this.shardList.some(shardId => shardId >= shardAmount)) {\n      throw new DiscordjsRangeError(\n        ErrorCodes.ClientInvalidOption,\n        'Amount of shards',\n        'bigger than the highest shardId in the shardList option.',\n      );\n    }\n\n    // Spawn the shards\n    for (const shardId of this.shardList) {\n      const promises = [];\n      const shard = this.createShard(shardId);\n      promises.push(shard.spawn(timeout));\n      if (delay > 0 && this.shards.size !== this.shardList.length) promises.push(sleep(delay));\n      await Promise.all(promises);\n    }\n\n    return this.shards;\n  }\n\n  /**\n   * Sends a message to all shards.\n   *\n   * @param {*} message Message to be sent to the shards\n   * @returns {Promise<Shard[]>}\n   */\n  async broadcast(message) {\n    const promises = [];\n    for (const shard of this.shards.values()) promises.push(shard.send(message));\n    return Promise.all(promises);\n  }\n\n  /**\n   * Options for {@link ShardingManager#broadcastEval} and {@link ShardClientUtil#broadcastEval}.\n   *\n   * @typedef {Object} BroadcastEvalOptions\n   * @property {number} [shard] Shard to run script on, all if undefined\n   * @property {*} [context] The JSON-serializable values to call the script with\n   */\n\n  /**\n   * Evaluates a script on all shards, or a given shard, in the context of the {@link Client}s.\n   *\n   * @param {Function} script JavaScript to run on each shard\n   * @param {BroadcastEvalOptions} [options={}] The options for the broadcast\n   * @returns {Promise<*|Array<*>>} Results of the script execution\n   */\n  async broadcastEval(script, options = {}) {\n    if (typeof script !== 'function') {\n      throw new DiscordjsTypeError(ErrorCodes.ShardingInvalidEvalBroadcast);\n    }\n\n    return this._performOnShards('eval', [`(${script})(this, ${JSON.stringify(options.context)})`], options.shard);\n  }\n\n  /**\n   * Fetches a client property value of each shard, or a given shard.\n   *\n   * @param {string} prop Name of the client property to get, using periods for nesting\n   * @param {number} [shard] Shard to fetch property from, all if undefined\n   * @returns {Promise<*|Array<*>>}\n   * @example\n   * manager.fetchClientValues('guilds.cache.size')\n   *   .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`))\n   *   .catch(console.error);\n   */\n  async fetchClientValues(prop, shard) {\n    return this._performOnShards('fetchClientValue', [prop], shard);\n  }\n\n  /**\n   * Runs a method with given arguments on all shards, or a given shard.\n   *\n   * @param {string} method Method name to run on each shard\n   * @param {Array<*>} args Arguments to pass through to the method call\n   * @param {number} [shard] Shard to run on, all if undefined\n   * @returns {Promise<*|Array<*>>} Results of the method execution\n   * @private\n   */\n  async _performOnShards(method, args, shard) {\n    if (this.shards.size === 0) throw new DiscordjsError(ErrorCodes.ShardingNoShards);\n\n    if (typeof shard === 'number') {\n      if (this.shards.has(shard)) return this.shards.get(shard)[method](...args);\n      throw new DiscordjsError(ErrorCodes.ShardingShardNotFound, shard);\n    }\n\n    if (this.shards.size !== this.shardList.length) {\n      throw new DiscordjsError(ErrorCodes.ShardingInProcess);\n    }\n\n    const promises = [];\n    for (const sh of this.shards.values()) promises.push(sh[method](...args));\n    return Promise.all(promises);\n  }\n\n  /**\n   * Options used to respawn all shards.\n   *\n   * @typedef {Object} MultipleShardRespawnOptions\n   * @property {number} [shardDelay=5000] How long to wait between shards (in milliseconds)\n   * @property {number} [respawnDelay=500] How long to wait between killing a shard's process and restarting it\n   * (in milliseconds)\n   * @property {number} [timeout=30000] The amount in milliseconds to wait for a shard to become ready before\n   * continuing to another (`-1` or `Infinity` for no wait)\n   */\n\n  /**\n   * Kills all running shards and respawns them.\n   *\n   * @param {MultipleShardRespawnOptions} [options] Options for respawning shards\n   * @returns {Promise<Collection<number, Shard>>}\n   */\n  async respawnAll({ shardDelay = 5_000, respawnDelay = 500, timeout = 30_000 } = {}) {\n    let shardCounter = 0;\n    for (const shard of this.shards.values()) {\n      const promises = [shard.respawn({ delay: respawnDelay, timeout })];\n      if (++shardCounter < this.shards.size && shardDelay > 0) promises.push(sleep(shardDelay));\n      await Promise.all(promises);\n    }\n\n    return this.shards;\n  }\n}\n\nexports.ShardingManager = ShardingManager;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ActionRow.js",
    "content": "'use strict';\n\nconst { createComponent } = require('../util/Components.js');\nconst { Component } = require('./Component.js');\n\n/**\n * Represents an action row\n *\n * @extends {Component}\n */\nclass ActionRow extends Component {\n  constructor({ components, ...data }) {\n    super(data);\n\n    /**\n     * The components in this action row\n     *\n     * @type {Component[]}\n     * @readonly\n     */\n    this.components = components.map(component => createComponent(component));\n  }\n\n  /**\n   * Returns the API-compatible JSON for this component\n   *\n   * @returns {APIActionRowComponent}\n   */\n  toJSON() {\n    return { ...this.data, components: this.components.map(component => component.toJSON()) };\n  }\n}\n\nexports.ActionRow = ActionRow;\n"
  },
  {
    "path": "packages/discord.js/src/structures/AnnouncementChannel.js",
    "content": "'use strict';\n\nconst { BaseGuildTextChannel } = require('./BaseGuildTextChannel.js');\n\n/**\n * Represents a guild announcement channel on Discord.\n *\n * @extends {BaseGuildTextChannel}\n */\nclass AnnouncementChannel extends BaseGuildTextChannel {\n  /**\n   * Adds the target to this channel's followers.\n   *\n   * @param {TextChannelResolvable} channel The channel where the webhook should be created\n   * @param {string} [reason] Reason for creating the webhook\n   * @returns {Promise<FollowedChannelData>} Returns the data for the followed channel\n   * @example\n   * if (channel.type === ChannelType.GuildAnnouncement) {\n   *   channel.addFollower('222197033908436994', 'Important announcements')\n   *     .then(() => console.log('Added follower'))\n   *     .catch(console.error);\n   * }\n   */\n  async addFollower(channel, reason) {\n    return this.guild.channels.addFollower(this, channel, reason);\n  }\n}\n\nexports.AnnouncementChannel = AnnouncementChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/AnonymousGuild.js",
    "content": "'use strict';\n\nconst { BaseGuild } = require('./BaseGuild.js');\n\n/**\n * Bundles common attributes and methods between {@link Guild} and {@link InviteGuild}\n *\n * @extends {BaseGuild}\n * @abstract\n */\nclass AnonymousGuild extends BaseGuild {\n  constructor(client, data, immediatePatch = true) {\n    super(client, data);\n    if (immediatePatch) this._patch(data);\n  }\n\n  _patch(data) {\n    if ('features' in data) this.features = data.features;\n\n    if ('splash' in data) {\n      /**\n       * The hash of the guild invite splash image\n       *\n       * @type {?string}\n       */\n      this.splash = data.splash;\n    }\n\n    if ('banner' in data) {\n      /**\n       * The hash of the guild banner\n       *\n       * @type {?string}\n       */\n      this.banner = data.banner;\n    }\n\n    if ('description' in data) {\n      /**\n       * The description of the guild, if any\n       *\n       * @type {?string}\n       */\n      this.description = data.description;\n    }\n\n    if ('verification_level' in data) {\n      /**\n       * The verification level of the guild\n       *\n       * @type {GuildVerificationLevel}\n       */\n      this.verificationLevel = data.verification_level;\n    }\n\n    if ('vanity_url_code' in data) {\n      /**\n       * The vanity invite code of the guild, if any\n       *\n       * @type {?string}\n       */\n      this.vanityURLCode = data.vanity_url_code;\n    }\n\n    if ('nsfw_level' in data) {\n      /**\n       * The NSFW level of this guild\n       *\n       * @type {GuildNSFWLevel}\n       */\n      this.nsfwLevel = data.nsfw_level;\n    }\n\n    if ('premium_subscription_count' in data) {\n      /**\n       * The total number of boosts for this server\n       *\n       * @type {?number}\n       */\n      this.premiumSubscriptionCount = data.premium_subscription_count;\n    } else {\n      this.premiumSubscriptionCount ??= null;\n    }\n  }\n\n  /**\n   * The URL to this guild's banner.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  bannerURL(options = {}) {\n    return this.banner && this.client.rest.cdn.banner(this.id, this.banner, options);\n  }\n\n  /**\n   * The URL to this guild's invite splash image.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  splashURL(options = {}) {\n    return this.splash && this.client.rest.cdn.splash(this.id, this.splash, options);\n  }\n}\n\nexports.AnonymousGuild = AnonymousGuild;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ApplicationCommand.js",
    "content": "'use strict';\n\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { ApplicationCommandOptionType } = require('discord-api-types/v10');\nconst isEqual = require('fast-deep-equal');\nconst { ApplicationCommandPermissionsManager } = require('../managers/ApplicationCommandPermissionsManager.js');\nconst { PermissionsBitField } = require('../util/PermissionsBitField.js');\nconst { Base } = require('./Base.js');\n\n/**\n * Represents an application command.\n *\n * @extends {Base}\n */\nclass ApplicationCommand extends Base {\n  constructor(client, data, guild, guildId) {\n    super(client);\n\n    /**\n     * The command's id\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    /**\n     * The parent application's id\n     *\n     * @type {Snowflake}\n     */\n    this.applicationId = data.application_id;\n\n    /**\n     * The guild this command is part of\n     *\n     * @type {?Guild}\n     */\n    this.guild = guild ?? null;\n\n    /**\n     * The guild's id this command is part of, this may be non-null when `guild` is `null` if the command\n     * was fetched from the `ApplicationCommandManager`\n     *\n     * @type {?Snowflake}\n     */\n    this.guildId = guild?.id ?? guildId ?? null;\n\n    /**\n     * The manager for permissions of this command on its guild or arbitrary guilds when the command is global\n     *\n     * @type {ApplicationCommandPermissionsManager}\n     */\n    this.permissions = new ApplicationCommandPermissionsManager(this);\n\n    /**\n     * The type of this application command\n     *\n     * @type {ApplicationCommandType}\n     */\n    this.type = data.type;\n\n    /**\n     * Whether this command is age-restricted (18+)\n     *\n     * @type {boolean}\n     */\n    this.nsfw = data.nsfw ?? false;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('name' in data) {\n      /**\n       * The name of this command\n       *\n       * @type {string}\n       */\n      this.name = data.name;\n    }\n\n    if ('name_localizations' in data) {\n      /**\n       * The name localizations for this command\n       *\n       * @type {?LocalizationMap}\n       */\n      this.nameLocalizations = data.name_localizations;\n    } else {\n      this.nameLocalizations ??= null;\n    }\n\n    if ('name_localized' in data) {\n      /**\n       * The localized name for this command\n       *\n       * @type {?string}\n       */\n      this.nameLocalized = data.name_localized;\n    } else {\n      this.nameLocalized ??= null;\n    }\n\n    if ('description' in data) {\n      /**\n       * The description of this command\n       *\n       * @type {string}\n       */\n      this.description = data.description;\n    }\n\n    if ('description_localizations' in data) {\n      /**\n       * The description localizations for this command\n       *\n       * @type {?LocalizationMap}\n       */\n      this.descriptionLocalizations = data.description_localizations;\n    } else {\n      this.descriptionLocalizations ??= null;\n    }\n\n    if ('description_localized' in data) {\n      /**\n       * The localized description for this command\n       *\n       * @type {?string}\n       */\n      this.descriptionLocalized = data.description_localized;\n    } else {\n      this.descriptionLocalized ??= null;\n    }\n\n    if ('options' in data) {\n      /**\n       * The options of this command\n       *\n       * @type {?ApplicationCommandOption[]}\n       */\n      this.options = data.options.map(option => this.constructor.transformOption(option, true));\n    } else {\n      this.options ??= null;\n    }\n\n    if ('default_member_permissions' in data) {\n      /**\n       * The default bitfield used to determine whether this command be used in a guild\n       *\n       * @type {?Readonly<PermissionsBitField>}\n       */\n      this.defaultMemberPermissions = data.default_member_permissions\n        ? new PermissionsBitField(BigInt(data.default_member_permissions)).freeze()\n        : null;\n    } else {\n      this.defaultMemberPermissions ??= null;\n    }\n\n    if ('integration_types' in data) {\n      /**\n       * Installation context(s) where the command is available\n       * <info>Only for globally-scoped commands</info>\n       *\n       * @type {?ApplicationIntegrationType[]}\n       */\n      this.integrationTypes = data.integration_types;\n    } else {\n      this.integrationTypes ??= null;\n    }\n\n    if ('contexts' in data) {\n      /**\n       * Interaction context(s) where the command can be used\n       * <info>Only for globally-scoped commands</info>\n       *\n       * @type {?InteractionContextType[]}\n       */\n      this.contexts = data.contexts;\n    } else {\n      this.contexts ??= null;\n    }\n\n    if ('handler' in data) {\n      /**\n       * Determines whether the interaction is handled by the app's interactions handler or by Discord.\n       * <info>Only available for {@link ApplicationCommandType.PrimaryEntryPoint} commands on\n       * applications with the {@link ApplicationFlags.Embedded} flag (i.e, those that have an Activity)</info>\n       *\n       * @type {?EntryPointCommandHandlerType}\n       */\n      this.handler = data.handler;\n    } else {\n      this.handler ??= null;\n    }\n\n    if ('version' in data) {\n      /**\n       * Autoincrementing version identifier updated during substantial record changes\n       *\n       * @type {Snowflake}\n       */\n      this.version = data.version;\n    }\n  }\n\n  /**\n   * The timestamp the command was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time the command was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * The manager that this command belongs to\n   *\n   * @type {ApplicationCommandManager}\n   * @readonly\n   */\n  get manager() {\n    return (this.guild ?? this.client.application).commands;\n  }\n\n  /**\n   * Data for creating or editing an application command.\n   *\n   * @typedef {Object} ApplicationCommandData\n   * @property {string} name The name of the command, must be in all lowercase if type is\n   * {@link ApplicationCommandType.ChatInput}\n   * @property {LocalizationMap} [nameLocalizations] The localizations for the command name\n   * @property {string} description The description of the command,\n   * if type is {@link ApplicationCommandType.ChatInput} or {@link ApplicationCommandType.PrimaryEntryPoint}\n   * @property {boolean} [nsfw] Whether the command is age-restricted\n   * @property {LocalizationMap} [descriptionLocalizations] The localizations for the command description,\n   * if type is {@link ApplicationCommandType.ChatInput} or {@link ApplicationCommandType.PrimaryEntryPoint}\n   * @property {ApplicationCommandType} [type=ApplicationCommandType.ChatInput] The type of the command\n   * @property {ApplicationCommandOptionData[]} [options] Options for the command\n   * @property {?PermissionResolvable} [defaultMemberPermissions] The bitfield used to determine the default permissions\n   * a member needs in order to run the command\n   * @property {ApplicationIntegrationType[]} [integrationTypes] Installation contexts where the command is available\n   * @property {InteractionContextType[]} [contexts] Interaction contexts where the command can be used\n   * @property {EntryPointCommandHandlerType} [handler] Whether the interaction is handled by the app's\n   * interactions handler or by Discord.\n   */\n\n  /**\n   * An option for an application command or subcommand.\n   * <info>In addition to the listed properties, when used as a parameter,\n   * API style `snake_case` properties can be used for compatibility with generators like `@discordjs/builders`.</info>\n   * <warn>Note that providing a value for the `camelCase` counterpart for any `snake_case` property\n   * will discard the provided `snake_case` property.</warn>\n   *\n   * @typedef {Object} ApplicationCommandOptionData\n   * @property {ApplicationCommandOptionType} type The type of the option\n   * @property {string} name The name of the option\n   * @property {LocalizationMap} [nameLocalizations] The name localizations for the option\n   * @property {string} description The description of the option\n   * @property {LocalizationMap} [descriptionLocalizations] The description localizations for the option\n   * @property {boolean} [autocomplete] Whether the autocomplete interaction is enabled for a\n   * {@link ApplicationCommandOptionType.String}, {@link ApplicationCommandOptionType.Integer} or\n   * {@link ApplicationCommandOptionType.Number} option\n   * @property {boolean} [required] Whether the option is required\n   * @property {ApplicationCommandOptionChoiceData[]} [choices] The choices of the option for the user to pick from\n   * @property {ApplicationCommandOptionData[]} [options] Additional options if this option is a subcommand (group)\n   * @property {ChannelType[]} [channelTypes] When the option type is channel,\n   * the allowed types of channels that can be selected\n   * @property {number} [minValue] The minimum value for an {@link ApplicationCommandOptionType.Integer} or\n   * {@link ApplicationCommandOptionType.Number} option\n   * @property {number} [maxValue] The maximum value for an {@link ApplicationCommandOptionType.Integer} or\n   * {@link ApplicationCommandOptionType.Number} option\n   * @property {number} [minLength] The minimum length for an {@link ApplicationCommandOptionType.String} option\n   * (maximum of `6000`)\n   * @property {number} [maxLength] The maximum length for an {@link ApplicationCommandOptionType.String} option\n   * (maximum of `6000`)\n   */\n\n  /**\n   * @typedef {Object} ApplicationCommandOptionChoiceData\n   * @property {string} name The name of the choice\n   * @property {LocalizationMap} [nameLocalizations] The localized names for this choice\n   * @property {string|number} value The value of the choice\n   */\n\n  /**\n   * Edits this application command.\n   *\n   * @param {Partial<ApplicationCommandData>} data The data to update the command with\n   * @returns {Promise<ApplicationCommand>}\n   * @example\n   * // Edit the description of this command\n   * command.edit({\n   *   description: 'New description',\n   * })\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async edit(data) {\n    return this.manager.edit(this, data, this.guildId);\n  }\n\n  /**\n   * Edits the name of this ApplicationCommand\n   *\n   * @param {string} name The new name of the command\n   * @returns {Promise<ApplicationCommand>}\n   */\n  async setName(name) {\n    return this.edit({ name });\n  }\n\n  /**\n   * Edits the localized names of this ApplicationCommand\n   *\n   * @param {LocalizationMap} nameLocalizations The new localized names for the command\n   * @returns {Promise<ApplicationCommand>}\n   * @example\n   * // Edit the name localizations of this command\n   * command.setNameLocalizations({\n   *   'en-GB': 'test',\n   *   'pt-BR': 'teste',\n   * })\n   *   .then(console.log)\n   *   .catch(console.error)\n   */\n  async setNameLocalizations(nameLocalizations) {\n    return this.edit({ nameLocalizations });\n  }\n\n  /**\n   * Edits the description of this ApplicationCommand\n   *\n   * @param {string} description The new description of the command\n   * @returns {Promise<ApplicationCommand>}\n   */\n  async setDescription(description) {\n    return this.edit({ description });\n  }\n\n  /**\n   * Edits the localized descriptions of this ApplicationCommand\n   *\n   * @param {LocalizationMap} descriptionLocalizations The new localized descriptions for the command\n   * @returns {Promise<ApplicationCommand>}\n   * @example\n   * // Edit the description localizations of this command\n   * command.setDescriptionLocalizations({\n   *   'en-GB': 'A test command',\n   *   'pt-BR': 'Um comando de teste',\n   * })\n   *   .then(console.log)\n   *   .catch(console.error)\n   */\n  async setDescriptionLocalizations(descriptionLocalizations) {\n    return this.edit({ descriptionLocalizations });\n  }\n\n  /**\n   * Edits the default member permissions of this ApplicationCommand\n   *\n   * @param {?PermissionResolvable} defaultMemberPermissions The default member permissions required to run this command\n   * @returns {Promise<ApplicationCommand>}\n   */\n  async setDefaultMemberPermissions(defaultMemberPermissions) {\n    return this.edit({ defaultMemberPermissions });\n  }\n\n  /**\n   * Edits the options of this ApplicationCommand\n   *\n   * @param {ApplicationCommandOptionData[]} options The options to set for this command\n   * @returns {Promise<ApplicationCommand>}\n   */\n  async setOptions(options) {\n    return this.edit({ options });\n  }\n\n  /**\n   * Deletes this command.\n   *\n   * @returns {Promise<ApplicationCommand>}\n   * @example\n   * // Delete this command\n   * command.delete()\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async delete() {\n    return this.manager.delete(this, this.guildId);\n  }\n\n  /**\n   * Whether this command equals another command. It compares all properties, so for most operations\n   * it is advisable to just compare `command.id === command2.id` as it is much faster and is often\n   * what most users need.\n   *\n   * @param {ApplicationCommand|ApplicationCommandData|APIApplicationCommand} command The command to compare with\n   * @param {boolean} [enforceOptionOrder=false] Whether to strictly check that options and choices are in the same\n   * order in the array <info>The client may not always respect this ordering!</info>\n   * @returns {boolean}\n   */\n  equals(command, enforceOptionOrder = false) {\n    // If given an id, check if the id matches\n    if (command.id && this.id !== command.id) return false;\n\n    let defaultMemberPermissions = null;\n\n    if ('default_member_permissions' in command) {\n      defaultMemberPermissions = command.default_member_permissions\n        ? new PermissionsBitField(BigInt(command.default_member_permissions)).bitfield\n        : null;\n    }\n\n    if ('defaultMemberPermissions' in command) {\n      defaultMemberPermissions =\n        command.defaultMemberPermissions === null\n          ? null\n          : new PermissionsBitField(command.defaultMemberPermissions).bitfield;\n    }\n\n    // Check top level parameters\n    if (\n      command.name !== this.name ||\n      ('description' in command && command.description !== this.description) ||\n      ('version' in command && command.version !== this.version) ||\n      (command.type && command.type !== this.type) ||\n      ('nsfw' in command && command.nsfw !== this.nsfw) ||\n      command.options?.length !== this.options?.length ||\n      defaultMemberPermissions !== (this.defaultMemberPermissions?.bitfield ?? null) ||\n      !isEqual(command.nameLocalizations ?? command.name_localizations ?? {}, this.nameLocalizations ?? {}) ||\n      !isEqual(\n        command.descriptionLocalizations ?? command.description_localizations ?? {},\n        this.descriptionLocalizations ?? {},\n      ) ||\n      !isEqual(command.integrationTypes ?? command.integration_types ?? [], this.integrationTypes ?? []) ||\n      !isEqual(command.contexts ?? [], this.contexts ?? []) ||\n      ('handler' in command && command.handler !== this.handler)\n    ) {\n      return false;\n    }\n\n    // Don't need to check both because we already checked the lengths above\n    if (command.options) {\n      return this.constructor.optionsEqual(this.options, command.options, enforceOptionOrder);\n    }\n\n    return true;\n  }\n\n  /**\n   * Recursively checks that all options for an {@link ApplicationCommand} are equal to the provided options.\n   * In most cases it is better to compare using {@link ApplicationCommand#equals}\n   *\n   * @param {ApplicationCommandOptionData[]} existing The options on the existing command,\n   * should be {@link ApplicationCommand#options}\n   * @param {ApplicationCommandOptionData[]|APIApplicationCommandOption[]} options The options to compare against\n   * @param {boolean} [enforceOptionOrder=false] Whether to strictly check that options and choices are in the same\n   * order in the array <info>The client may not always respect this ordering!</info>\n   * @returns {boolean}\n   */\n  static optionsEqual(existing, options, enforceOptionOrder = false) {\n    if (existing.length !== options.length) return false;\n    if (enforceOptionOrder) {\n      return existing.every((option, index) => this._optionEquals(option, options[index], enforceOptionOrder));\n    }\n\n    const newOptions = new Map(options.map(option => [option.name, option]));\n    for (const option of existing) {\n      const foundOption = newOptions.get(option.name);\n      if (!foundOption || !this._optionEquals(option, foundOption)) return false;\n    }\n\n    return true;\n  }\n\n  /**\n   * Checks that an option for an {@link ApplicationCommand} is equal to the provided option\n   * In most cases it is better to compare using {@link ApplicationCommand#equals}\n   *\n   * @param {ApplicationCommandOptionData} existing The option on the existing command,\n   * should be from {@link ApplicationCommand#options}\n   * @param {ApplicationCommandOptionData|APIApplicationCommandOption} option The option to compare against\n   * @param {boolean} [enforceOptionOrder=false] Whether to strictly check that options or choices are in the same\n   * order in their array <info>The client may not always respect this ordering!</info>\n   * @returns {boolean}\n   * @private\n   */\n  static _optionEquals(existing, option, enforceOptionOrder = false) {\n    if (\n      option.name !== existing.name ||\n      option.type !== existing.type ||\n      option.description !== existing.description ||\n      option.autocomplete !== existing.autocomplete ||\n      (option.required ??\n        ([ApplicationCommandOptionType.Subcommand, ApplicationCommandOptionType.SubcommandGroup].includes(option.type)\n          ? undefined\n          : false)) !== existing.required ||\n      option.choices?.length !== existing.choices?.length ||\n      option.options?.length !== existing.options?.length ||\n      (option.channelTypes ?? option.channel_types)?.length !== existing.channelTypes?.length ||\n      (option.minValue ?? option.min_value) !== existing.minValue ||\n      (option.maxValue ?? option.max_value) !== existing.maxValue ||\n      (option.minLength ?? option.min_length) !== existing.minLength ||\n      (option.maxLength ?? option.max_length) !== existing.maxLength ||\n      !isEqual(option.nameLocalizations ?? option.name_localizations ?? {}, existing.nameLocalizations ?? {}) ||\n      !isEqual(\n        option.descriptionLocalizations ?? option.description_localizations ?? {},\n        existing.descriptionLocalizations ?? {},\n      )\n    ) {\n      return false;\n    }\n\n    if (existing.choices) {\n      if (\n        enforceOptionOrder &&\n        !existing.choices.every(\n          (choice, index) =>\n            choice.name === option.choices[index].name &&\n            choice.value === option.choices[index].value &&\n            isEqual(\n              choice.nameLocalizations ?? {},\n              option.choices[index].nameLocalizations ?? option.choices[index].name_localizations ?? {},\n            ),\n        )\n      ) {\n        return false;\n      }\n\n      if (!enforceOptionOrder) {\n        const newChoices = new Map(option.choices.map(choice => [choice.name, choice]));\n        for (const choice of existing.choices) {\n          const foundChoice = newChoices.get(choice.name);\n          if (!foundChoice || foundChoice.value !== choice.value) return false;\n        }\n      }\n    }\n\n    if (existing.channelTypes) {\n      const newTypes = option.channelTypes ?? option.channel_types;\n      for (const type of existing.channelTypes) {\n        if (!newTypes.includes(type)) return false;\n      }\n    }\n\n    if (existing.options) {\n      return this.optionsEqual(existing.options, option.options, enforceOptionOrder);\n    }\n\n    return true;\n  }\n\n  /**\n   * An option for an application command or subcommand.\n   *\n   * @typedef {Object} ApplicationCommandOption\n   * @property {ApplicationCommandOptionType} type The type of the option\n   * @property {string} name The name of the option\n   * @property {LocalizationMap} [nameLocalizations] The localizations for the option name\n   * @property {string} [nameLocalized] The localized name for this option\n   * @property {string} description The description of the option\n   * @property {LocalizationMap} [descriptionLocalizations] The localizations for the option description\n   * @property {string} [descriptionLocalized] The localized description for this option\n   * @property {boolean} [required] Whether the option is required\n   * @property {boolean} [autocomplete] Whether the autocomplete interaction is enabled for a\n   * {@link ApplicationCommandOptionType.String}, {@link ApplicationCommandOptionType.Integer} or\n   * {@link ApplicationCommandOptionType.Number} option\n   * @property {ApplicationCommandOptionChoice[]} [choices] The choices of the option for the user to pick from\n   * @property {ApplicationCommandOption[]} [options] Additional options if this option is a subcommand (group)\n   * @property {ApplicationCommandOptionAllowedChannelType[]} [channelTypes] When the option type is channel,\n   * the allowed types of channels that can be selected\n   * @property {number} [minValue] The minimum value for an {@link ApplicationCommandOptionType.Integer} or\n   * {@link ApplicationCommandOptionType.Number} option\n   * @property {number} [maxValue] The maximum value for an {@link ApplicationCommandOptionType.Integer} or\n   * {@link ApplicationCommandOptionType.Number} option\n   * @property {number} [minLength] The minimum length for an {@link ApplicationCommandOptionType.String} option\n   * (maximum of `6000`)\n   * @property {number} [maxLength] The maximum length for an {@link ApplicationCommandOptionType.String} option\n   * (maximum of `6000`)\n   */\n\n  /**\n   * A choice for an application command option.\n   *\n   * @typedef {Object} ApplicationCommandOptionChoice\n   * @property {string} name The name of the choice\n   * @property {?string} nameLocalized The localized name of the choice in the provided locale, if any\n   * @property {?LocalizationMap} [nameLocalizations] The localized names for this choice\n   * @property {string|number} value The value of the choice\n   */\n\n  /**\n   * Transforms an {@link ApplicationCommandOptionData} object into something that can be used with the API.\n   *\n   * @param {ApplicationCommandOptionData|ApplicationCommandOption} option The option to transform\n   * @param {boolean} [received] Whether this option has been received from Discord\n   * @returns {APIApplicationCommandOption}\n   * @private\n   */\n  static transformOption(option, received) {\n    const channelTypesKey = received ? 'channelTypes' : 'channel_types';\n    const minValueKey = received ? 'minValue' : 'min_value';\n    const maxValueKey = received ? 'maxValue' : 'max_value';\n    const minLengthKey = received ? 'minLength' : 'min_length';\n    const maxLengthKey = received ? 'maxLength' : 'max_length';\n    const nameLocalizationsKey = received ? 'nameLocalizations' : 'name_localizations';\n    const nameLocalizedKey = received ? 'nameLocalized' : 'name_localized';\n    const descriptionLocalizationsKey = received ? 'descriptionLocalizations' : 'description_localizations';\n    const descriptionLocalizedKey = received ? 'descriptionLocalized' : 'description_localized';\n    return {\n      type: option.type,\n      name: option.name,\n      [nameLocalizationsKey]: option.nameLocalizations ?? option.name_localizations,\n      [nameLocalizedKey]: option.nameLocalized ?? option.name_localized,\n      description: option.description,\n      [descriptionLocalizationsKey]: option.descriptionLocalizations ?? option.description_localizations,\n      [descriptionLocalizedKey]: option.descriptionLocalized ?? option.description_localized,\n      required:\n        option.required ??\n        (option.type === ApplicationCommandOptionType.Subcommand ||\n        option.type === ApplicationCommandOptionType.SubcommandGroup\n          ? undefined\n          : false),\n      autocomplete: option.autocomplete,\n      choices: option.choices?.map(choice => ({\n        name: choice.name,\n        [nameLocalizedKey]: choice.nameLocalized ?? choice.name_localized,\n        [nameLocalizationsKey]: choice.nameLocalizations ?? choice.name_localizations,\n        value: choice.value,\n      })),\n      options: option.options?.map(opt => this.transformOption(opt, received)),\n      [channelTypesKey]: option.channelTypes ?? option.channel_types,\n      [minValueKey]: option.minValue ?? option.min_value,\n      [maxValueKey]: option.maxValue ?? option.max_value,\n      [minLengthKey]: option.minLength ?? option.min_length,\n      [maxLengthKey]: option.maxLength ?? option.max_length,\n    };\n  }\n}\n\nexports.ApplicationCommand = ApplicationCommand;\n\n/**\n * @external ApplicationCommandOptionAllowedChannelType\n * @see {@link https://discord.js.org/docs/packages/builders/stable/ApplicationCommandOptionAllowedChannelType:TypeAlias}\n */\n"
  },
  {
    "path": "packages/discord.js/src/structures/ApplicationEmoji.js",
    "content": "'use strict';\n\nconst { Emoji } = require('./Emoji.js');\n\n/**\n * Represents a custom emoji.\n *\n * @extends {Emoji}\n */\nclass ApplicationEmoji extends Emoji {\n  constructor(client, data, application) {\n    super(client, data);\n\n    /**\n     * The application this emoji originates from\n     *\n     * @type {ClientApplication}\n     */\n    this.application = application;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('name' in data) this.name = data.name;\n    if (data.user) {\n      /**\n       * The user who created this emoji\n       *\n       * @type {User}\n       */\n      this.author = this.client.users._add(data.user);\n    }\n\n    if ('managed' in data) {\n      /**\n       * Whether this emoji is managed by an external service. Always `false` for application emojis\n       *\n       * @type {false}\n       */\n      this.managed = data.managed;\n    }\n\n    if ('require_colons' in data) {\n      /**\n       * Whether this emoji requires colons surrounding it. Always `true` for application emojis\n       *\n       * @type {true}\n       */\n      this.requiresColons = data.require_colons;\n    }\n\n    if ('available' in data) {\n      /**\n       * Whether this emoji is available. Always `true` for application emojis\n       *\n       * @type {true}\n       */\n      this.available = data.available;\n    }\n  }\n\n  /**\n   * Fetches the author for this emoji\n   *\n   * @returns {Promise<User>}\n   */\n  async fetchAuthor() {\n    return this.application.emojis.fetchAuthor(this);\n  }\n\n  /**\n   * Data for editing an emoji.\n   *\n   * @typedef {Object} ApplicationEmojiEditOptions\n   * @property {string} [name] The name of the emoji\n   */\n\n  /**\n   * Edits the emoji.\n   *\n   * @param {ApplicationEmojiEditOptions} options The options to provide\n   * @returns {Promise<ApplicationEmoji>}\n   * @example\n   * // Edit an emoji\n   * emoji.edit({ name: 'newemoji' })\n   *   .then(emoji => console.log(`Edited emoji ${emoji}`))\n   *   .catch(console.error);\n   */\n  async edit(options) {\n    return this.application.emojis.edit(this.id, options);\n  }\n\n  /**\n   * Sets the name of the emoji.\n   *\n   * @param {string} name The new name for the emoji\n   * @returns {Promise<ApplicationEmoji>}\n   */\n  async setName(name) {\n    return this.edit({ name });\n  }\n\n  /**\n   * Deletes the emoji.\n   *\n   * @returns {Promise<ApplicationEmoji>}\n   */\n  async delete() {\n    await this.application.emojis.delete(this.id);\n    return this;\n  }\n\n  /**\n   * Whether this emoji is the same as another one.\n   *\n   * @param {ApplicationEmoji|APIEmoji} other The emoji to compare it to\n   * @returns {boolean}\n   */\n  equals(other) {\n    if (other instanceof ApplicationEmoji) {\n      return (\n        other.animated === this.animated &&\n        other.id === this.id &&\n        other.name === this.name &&\n        other.managed === this.managed &&\n        other.requiresColons === this.requiresColons &&\n        other.available === this.available\n      );\n    }\n\n    return other.id === this.id && other.name === this.name;\n  }\n}\n\n/**\n * The emoji's name\n *\n * @name name\n * @memberof ApplicationEmoji\n * @instance\n * @type {string}\n * @readonly\n */\n\n/**\n * Whether the emoji is animated\n *\n * @name animated\n * @memberof ApplicationEmoji\n * @instance\n * @type {boolean}\n * @readonly\n */\n\n/**\n * Returns a URL for the emoji.\n *\n * @method imageURL\n * @memberof ApplicationEmoji\n * @instance\n * @param {EmojiURLOptions} [options] Options for the image URL\n * @returns {string}\n */\n\n/**\n * The time the emoji was created at\n *\n * @name createdAt\n * @memberof ApplicationEmoji\n * @instance\n * @type {Date}\n * @readonly\n */\n\n/**\n * The timestamp the emoji was created at\n *\n * @name createdTimestamp\n * @memberof ApplicationEmoji\n * @instance\n * @type {number}\n * @readonly\n */\n\nexports.ApplicationEmoji = ApplicationEmoji;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ApplicationRoleConnectionMetadata.js",
    "content": "'use strict';\n\n/**\n * Role connection metadata object for an application.\n */\nclass ApplicationRoleConnectionMetadata {\n  constructor(data) {\n    /**\n     * The name of this metadata field\n     *\n     * @type {string}\n     */\n    this.name = data.name;\n\n    /**\n     * The name localizations for this metadata field\n     *\n     * @type {?LocalizationMap}\n     */\n    this.nameLocalizations = data.name_localizations ?? null;\n\n    /**\n     * The description of this metadata field\n     *\n     * @type {string}\n     */\n    this.description = data.description;\n\n    /**\n     * The description localizations for this metadata field\n     *\n     * @type {?LocalizationMap}\n     */\n    this.descriptionLocalizations = data.description_localizations ?? null;\n\n    /**\n     * The dictionary key for this metadata field\n     *\n     * @type {string}\n     */\n    this.key = data.key;\n\n    /**\n     * The type of this metadata field\n     *\n     * @type {ApplicationRoleConnectionMetadataType}\n     */\n    this.type = data.type;\n  }\n}\n\nexports.ApplicationRoleConnectionMetadata = ApplicationRoleConnectionMetadata;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Attachment.js",
    "content": "'use strict';\n\nconst { AttachmentFlagsBitField } = require('../util/AttachmentFlagsBitField.js');\nconst { basename, flatten } = require('../util/Util.js');\n\n/**\n * @typedef {Object} AttachmentPayload\n * @property {Stream|BufferResolvable} attachment The attachment in this payload\n * @property {string} [name] The name of the attachment\n * @property {string} [description] The description of the attachment\n * @property {title} [title] The title of the attachment\n * @property {string} [waveform] The base64 encoded byte array representing a sampled waveform (from voice message attachments)\n * @property {number} [duration] The duration of the attachment in seconds (from voice message attachments)\n */\n\n/**\n * Represents an attachment\n */\nclass Attachment {\n  constructor(data) {\n    this.attachment = data.url;\n    /**\n     * The name of this attachment\n     *\n     * @type {string}\n     */\n    this.name = data.filename;\n    this._patch(data);\n  }\n\n  _patch(data) {\n    /**\n     * The attachment's id\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    if ('size' in data) {\n      /**\n       * The size of this attachment in bytes\n       *\n       * @type {number}\n       */\n      this.size = data.size;\n    }\n\n    if ('url' in data) {\n      /**\n       * The URL to this attachment\n       *\n       * @type {string}\n       */\n      this.url = data.url;\n    }\n\n    if ('proxy_url' in data) {\n      /**\n       * The Proxy URL to this attachment\n       *\n       * @type {string}\n       */\n      this.proxyURL = data.proxy_url;\n    }\n\n    if ('height' in data) {\n      /**\n       * The height of this attachment (if an image or video)\n       *\n       * @type {?number}\n       */\n      this.height = data.height;\n    } else {\n      this.height ??= null;\n    }\n\n    if ('width' in data) {\n      /**\n       * The width of this attachment (if an image or video)\n       *\n       * @type {?number}\n       */\n      this.width = data.width;\n    } else {\n      this.width ??= null;\n    }\n\n    if ('content_type' in data) {\n      /**\n       * The media (MIME) type of this attachment\n       *\n       * @type {?string}\n       * @see {@link https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types}\n       */\n      this.contentType = data.content_type;\n    } else {\n      this.contentType ??= null;\n    }\n\n    if ('description' in data) {\n      /**\n       * The description (alt text) of this attachment\n       *\n       * @type {?string}\n       */\n      this.description = data.description;\n    } else {\n      this.description ??= null;\n    }\n\n    /**\n     * Whether this attachment is ephemeral\n     *\n     * @type {boolean}\n     */\n    this.ephemeral = data.ephemeral ?? false;\n\n    if ('duration_secs' in data) {\n      /**\n       * The duration of this attachment in seconds\n       * <info>This will only be available if the attachment is the audio file from a voice message.</info>\n       *\n       * @type {?number}\n       */\n      this.duration = data.duration_secs;\n    } else {\n      this.duration ??= null;\n    }\n\n    if ('waveform' in data) {\n      /**\n       * The base64 encoded byte array representing a sampled waveform\n       * <info>This will only be available if this attachment is the audio file from a voice message.</info>\n       *\n       * @type {?string}\n       */\n      this.waveform = data.waveform;\n    } else {\n      this.waveform ??= null;\n    }\n\n    if ('flags' in data) {\n      /**\n       * The flags of this attachment\n       *\n       * @type {Readonly<AttachmentFlagsBitField>}\n       */\n      this.flags = new AttachmentFlagsBitField(data.flags).freeze();\n    } else {\n      this.flags ??= new AttachmentFlagsBitField().freeze();\n    }\n\n    if ('title' in data) {\n      /**\n       * The title of this attachment\n       * <info>This will only be available if the attachment name contains special characters.</info>\n       *\n       * @type {?string}\n       */\n      this.title = data.title;\n    } else {\n      this.title ??= null;\n    }\n  }\n\n  /**\n   * Whether or not this attachment has been marked as a spoiler\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get spoiler() {\n    return basename(this.url ?? this.name).startsWith('SPOILER_');\n  }\n\n  toJSON() {\n    return flatten(this);\n  }\n}\n\nexports.Attachment = Attachment;\n"
  },
  {
    "path": "packages/discord.js/src/structures/AuthorizingIntegrationOwners.js",
    "content": "'use strict';\n\nconst { ApplicationIntegrationType } = require('discord-api-types/v10');\nconst { Base } = require('./Base.js');\n\n/**\n * Represents the owners of an authorizing integration.\n *\n * @extends {Base}\n */\nclass AuthorizingIntegrationOwners extends Base {\n  constructor(client, data) {\n    super(client);\n\n    Object.defineProperty(this, 'data', { value: data });\n\n    // Support accessing authorizingIntegrationOwners[ApplicationIntegrationType.GuildInstall] or similar, + forward compatibility if new installation types get added\n    for (const value of Object.values(ApplicationIntegrationType)) {\n      if (typeof value !== 'number') {\n        continue;\n      }\n\n      Object.defineProperty(this, value, { value: this.data[value] });\n    }\n\n    /**\n     * The id of the guild where the integration is installed, if applicable.\n     *\n     * @type {?Snowflake}\n     */\n    this.guildId = this.data[ApplicationIntegrationType.GuildInstall] ?? null;\n\n    /**\n     * The id of the user on which the integration is installed, if applicable.\n     *\n     * @type {?Snowflake}\n     */\n    this.userId = this.data[ApplicationIntegrationType.UserInstall] ?? null;\n  }\n\n  /**\n   * The guild where the integration is installed, if applicable.\n   *\n   * @type {?Guild}\n   */\n  get guild() {\n    return (this.guildId && this.client.guilds.cache.get(this.guildId)) ?? null;\n  }\n\n  /**\n   * The user on which the integration is installed, if applicable.\n   *\n   * @type {?User}\n   */\n  get user() {\n    return (this.userId && this.client.users.cache.get(this.userId)) ?? null;\n  }\n\n  toJSON() {\n    return this.data;\n  }\n}\n\nexports.AuthorizingIntegrationOwners = AuthorizingIntegrationOwners;\n"
  },
  {
    "path": "packages/discord.js/src/structures/AutoModerationActionExecution.js",
    "content": "'use strict';\n\nconst { _transformAPIAutoModerationAction } = require('../util/Transformers.js');\n\n/**\n * Represents the structure of an executed action when an {@link AutoModerationRule} is triggered.\n */\nclass AutoModerationActionExecution {\n  constructor(data, guild) {\n    /**\n     * The guild where this action was executed from.\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n\n    /**\n     * The action that was executed.\n     *\n     * @type {AutoModerationAction}\n     */\n    this.action = _transformAPIAutoModerationAction(data.action);\n\n    /**\n     * The id of the auto moderation rule this action belongs to.\n     *\n     * @type {Snowflake}\n     */\n    this.ruleId = data.rule_id;\n\n    /**\n     * The trigger type of the auto moderation rule which was triggered.\n     *\n     * @type {AutoModerationRuleTriggerType}\n     */\n    this.ruleTriggerType = data.rule_trigger_type;\n\n    /**\n     * The id of the user that triggered this action.\n     *\n     * @type {Snowflake}\n     */\n    this.userId = data.user_id;\n\n    /**\n     * The id of the channel where this action was triggered from.\n     *\n     * @type {?Snowflake}\n     */\n    this.channelId = data.channel_id ?? null;\n\n    /**\n     * The id of the message that triggered this action.\n     * <info>This will not be present if the message was blocked or the content was not part of any message.</info>\n     *\n     * @type {?Snowflake}\n     */\n    this.messageId = data.message_id ?? null;\n\n    /**\n     * The id of any system auto moderation messages posted as a result of this action.\n     *\n     * @type {?Snowflake}\n     */\n    this.alertSystemMessageId = data.alert_system_message_id ?? null;\n\n    /**\n     * The content that triggered this action.\n     * <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged gateway intent.</info>\n     *\n     * @type {string}\n     */\n    this.content = data.content;\n\n    /**\n     * The word or phrase configured in the rule that triggered this action.\n     *\n     * @type {?string}\n     */\n    this.matchedKeyword = data.matched_keyword ?? null;\n\n    /**\n     * The substring in content that triggered this action.\n     *\n     * @type {?string}\n     */\n    this.matchedContent = data.matched_content ?? null;\n  }\n\n  /**\n   * The auto moderation rule this action belongs to.\n   *\n   * @type {?AutoModerationRule}\n   * @readonly\n   */\n  get autoModerationRule() {\n    return this.guild.autoModerationRules.cache.get(this.ruleId) ?? null;\n  }\n\n  /**\n   * The channel where this action was triggered from.\n   *\n   * @type {?(GuildTextBasedChannel|ForumChannel|MediaChannel)}\n   * @readonly\n   */\n  get channel() {\n    return this.guild.channels.cache.get(this.channelId) ?? null;\n  }\n\n  /**\n   * The user that triggered this action.\n   *\n   * @type {?User}\n   * @readonly\n   */\n  get user() {\n    return this.guild.client.users.cache.get(this.userId) ?? null;\n  }\n\n  /**\n   * The guild member that triggered this action.\n   *\n   * @type {?GuildMember}\n   * @readonly\n   */\n  get member() {\n    return this.guild.members.cache.get(this.userId) ?? null;\n  }\n}\n\nexports.AutoModerationActionExecution = AutoModerationActionExecution;\n"
  },
  {
    "path": "packages/discord.js/src/structures/AutoModerationRule.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { _transformAPIAutoModerationAction } = require('../util/Transformers.js');\nconst { Base } = require('./Base.js');\n\n/**\n * Represents an auto moderation rule.\n *\n * @extends {Base}\n */\nclass AutoModerationRule extends Base {\n  constructor(client, data, guild) {\n    super(client);\n\n    /**\n     * The id of this auto moderation rule.\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    /**\n     * The guild this auto moderation rule is for.\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n\n    /**\n     * The user that created this auto moderation rule.\n     *\n     * @type {Snowflake}\n     */\n    this.creatorId = data.creator_id;\n\n    /**\n     * The trigger type of this auto moderation rule.\n     *\n     * @type {AutoModerationRuleTriggerType}\n     */\n    this.triggerType = data.trigger_type;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('name' in data) {\n      /**\n       * The name of this auto moderation rule.\n       *\n       * @type {string}\n       */\n      this.name = data.name;\n    }\n\n    if ('event_type' in data) {\n      /**\n       * The event type of this auto moderation rule.\n       *\n       * @type {AutoModerationRuleEventType}\n       */\n      this.eventType = data.event_type;\n    }\n\n    if ('trigger_metadata' in data) {\n      /**\n       * Additional data used to determine whether an auto moderation rule should be triggered.\n       *\n       * @typedef {Object} AutoModerationTriggerMetadata\n       * @property {string[]} keywordFilter The substrings that will be searched for in the content\n       * @property {string[]} regexPatterns The regular expression patterns which will be matched against the content\n       * <info>Only Rust-flavored regular expressions are supported.</info>\n       * @property {AutoModerationRuleKeywordPresetType[]} presets\n       * The internally pre-defined wordsets which will be searched for in the content\n       * @property {string[]} allowList The substrings that will be exempt from triggering\n       * {@link AutoModerationRuleTriggerType.Keyword},\n       * {@link AutoModerationRuleTriggerType.KeywordPreset},\n       * and {@link AutoModerationRuleTriggerType.MemberProfile}\n       * @property {?number} mentionTotalLimit The total number of role & user mentions allowed per message\n       * @property {boolean} mentionRaidProtectionEnabled Whether mention raid protection is enabled\n       */\n\n      /**\n       * The trigger metadata of the rule.\n       *\n       * @type {AutoModerationTriggerMetadata}\n       */\n      this.triggerMetadata = {\n        keywordFilter: data.trigger_metadata.keyword_filter ?? [],\n        regexPatterns: data.trigger_metadata.regex_patterns ?? [],\n        presets: data.trigger_metadata.presets ?? [],\n        allowList: data.trigger_metadata.allow_list ?? [],\n        mentionTotalLimit: data.trigger_metadata.mention_total_limit ?? null,\n        mentionRaidProtectionEnabled: data.trigger_metadata.mention_raid_protection_enabled ?? false,\n      };\n    }\n\n    if ('actions' in data) {\n      /**\n       * An object containing information about an auto moderation rule action.\n       *\n       * @typedef {Object} AutoModerationAction\n       * @property {AutoModerationActionType} type The type of this auto moderation rule action\n       * @property {AutoModerationActionMetadata} metadata Additional metadata needed during execution\n       */\n\n      /**\n       * Additional data used when an auto moderation rule is executed.\n       *\n       * @typedef {Object} AutoModerationActionMetadata\n       * @property {?Snowflake} channelId The id of the channel to which content will be logged\n       * @property {?number} durationSeconds The timeout duration in seconds\n       * @property {?string} customMessage The custom message that is shown whenever a message is blocked\n       */\n\n      /**\n       * The actions of this auto moderation rule.\n       *\n       * @type {AutoModerationAction[]}\n       */\n      this.actions = data.actions.map(action => _transformAPIAutoModerationAction(action));\n    }\n\n    if ('enabled' in data) {\n      /**\n       * Whether this auto moderation rule is enabled.\n       *\n       * @type {boolean}\n       */\n      this.enabled = data.enabled;\n    }\n\n    if ('exempt_roles' in data) {\n      /**\n       * The roles exempt by this auto moderation rule.\n       *\n       * @type {Collection<Snowflake, Role>}\n       */\n      this.exemptRoles = new Collection(\n        data.exempt_roles.map(exemptRole => [exemptRole, this.guild.roles.cache.get(exemptRole)]),\n      );\n    }\n\n    if ('exempt_channels' in data) {\n      /**\n       * The channels exempt by this auto moderation rule.\n       *\n       * @type {Collection<Snowflake, GuildChannel|ThreadChannel>}\n       */\n      this.exemptChannels = new Collection(\n        data.exempt_channels.map(exemptChannel => [exemptChannel, this.guild.channels.cache.get(exemptChannel)]),\n      );\n    }\n  }\n\n  /**\n   * Edits this auto moderation rule.\n   *\n   * @param {AutoModerationRuleEditOptions} options Options for editing this auto moderation rule\n   * @returns {Promise<AutoModerationRule>}\n   */\n  async edit(options) {\n    return this.guild.autoModerationRules.edit(this.id, options);\n  }\n\n  /**\n   * Deletes this auto moderation rule.\n   *\n   * @param {string} [reason] The reason for deleting this auto moderation rule\n   * @returns {Promise<void>}\n   */\n  async delete(reason) {\n    return this.guild.autoModerationRules.delete(this.id, reason);\n  }\n\n  /**\n   * Sets the name for this auto moderation rule.\n   *\n   * @param {string} name The name of this auto moderation rule\n   * @param {string} [reason] The reason for changing the name of this auto moderation rule\n   * @returns {Promise<AutoModerationRule>}\n   */\n  async setName(name, reason) {\n    return this.edit({ name, reason });\n  }\n\n  /**\n   * Sets the event type for this auto moderation rule.\n   *\n   * @param {AutoModerationRuleEventType} eventType The event type of this auto moderation rule\n   * @param {string} [reason] The reason for changing the event type of this auto moderation rule\n   * @returns {Promise<AutoModerationRule>}\n   */\n  async setEventType(eventType, reason) {\n    return this.edit({ eventType, reason });\n  }\n\n  /**\n   * Sets the keyword filter for this auto moderation rule.\n   *\n   * @param {string[]} keywordFilter The keyword filter of this auto moderation rule\n   * @param {string} [reason] The reason for changing the keyword filter of this auto moderation rule\n   * @returns {Promise<AutoModerationRule>}\n   */\n  async setKeywordFilter(keywordFilter, reason) {\n    return this.edit({ triggerMetadata: { ...this.triggerMetadata, keywordFilter }, reason });\n  }\n\n  /**\n   * Sets the regular expression patterns for this auto moderation rule.\n   *\n   * @param {string[]} regexPatterns The regular expression patterns of this auto moderation rule\n   * <info>Only Rust-flavored regular expressions are supported.</info>\n   * @param {string} [reason] The reason for changing the regular expression patterns of this auto moderation rule\n   * @returns {Promise<AutoModerationRule>}\n   */\n  async setRegexPatterns(regexPatterns, reason) {\n    return this.edit({ triggerMetadata: { ...this.triggerMetadata, regexPatterns }, reason });\n  }\n\n  /**\n   * Sets the presets for this auto moderation rule.\n   *\n   * @param {AutoModerationRuleKeywordPresetType[]} presets The presets of this auto moderation rule\n   * @param {string} [reason] The reason for changing the presets of this auto moderation rule\n   * @returns {Promise<AutoModerationRule>}\n   */\n  async setPresets(presets, reason) {\n    return this.edit({ triggerMetadata: { ...this.triggerMetadata, presets }, reason });\n  }\n\n  /**\n   * Sets the allow list for this auto moderation rule.\n   *\n   * @param {string[]} allowList The substrings that will be exempt from triggering\n   * {@link AutoModerationRuleTriggerType.Keyword},\n   * {@link AutoModerationRuleTriggerType.KeywordPreset},\n   * and {@link AutoModerationRuleTriggerType.MemberProfile}\n   * @param {string} [reason] The reason for changing the allow list of this auto moderation rule\n   * @returns {Promise<AutoModerationRule>}\n   */\n  async setAllowList(allowList, reason) {\n    return this.edit({ triggerMetadata: { ...this.triggerMetadata, allowList }, reason });\n  }\n\n  /**\n   * Sets the mention total limit for this auto moderation rule.\n   *\n   * @param {number} mentionTotalLimit The total number of unique role and user mentions allowed per message\n   * @param {string} [reason] The reason for changing the mention total limit of this auto moderation rule\n   * @returns {Promise<AutoModerationRule>}\n   */\n  async setMentionTotalLimit(mentionTotalLimit, reason) {\n    return this.edit({ triggerMetadata: { ...this.triggerMetadata, mentionTotalLimit }, reason });\n  }\n\n  /**\n   * Sets whether to enable mention raid protection for this auto moderation rule.\n   *\n   * @param {boolean} mentionRaidProtectionEnabled\n   * Whether to enable mention raid protection for this auto moderation rule\n   * @param {string} [reason] The reason for changing the mention raid protection of this auto moderation rule\n   * @returns {Promise<AutoModerationRule>}\n   */\n  async setMentionRaidProtectionEnabled(mentionRaidProtectionEnabled, reason) {\n    return this.edit({ triggerMetadata: { ...this.triggerMetadata, mentionRaidProtectionEnabled }, reason });\n  }\n\n  /**\n   * Sets the actions for this auto moderation rule.\n   *\n   * @param {AutoModerationActionOptions[]} actions The actions of this auto moderation rule\n   * @param {string} [reason] The reason for changing the actions of this auto moderation rule\n   * @returns {Promise<AutoModerationRule>}\n   */\n  async setActions(actions, reason) {\n    return this.edit({ actions, reason });\n  }\n\n  /**\n   * Sets whether this auto moderation rule should be enabled.\n   *\n   * @param {boolean} [enabled=true] Whether to enable this auto moderation rule\n   * @param {string} [reason] The reason for enabling or disabling this auto moderation rule\n   * @returns {Promise<AutoModerationRule>}\n   */\n  async setEnabled(enabled = true, reason = undefined) {\n    return this.edit({ enabled, reason });\n  }\n\n  /**\n   * Sets the exempt roles for this auto moderation rule.\n   *\n   * @param {Collection<Snowflake, Role>|RoleResolvable[]} [exemptRoles]\n   * The roles that should not be affected by the auto moderation rule\n   * @param {string} [reason] The reason for changing the exempt roles of this auto moderation rule\n   * @returns {Promise<AutoModerationRule>}\n   */\n  async setExemptRoles(exemptRoles, reason) {\n    return this.edit({ exemptRoles, reason });\n  }\n\n  /**\n   * Sets the exempt channels for this auto moderation rule.\n   *\n   * @param {Collection<Snowflake, GuildChannel|ThreadChannel>|GuildChannelResolvable[]} [exemptChannels]\n   * The channels that should not be affected by the auto moderation rule\n   * @param {string} [reason] The reason for changing the exempt channels of this auto moderation rule\n   * @returns {Promise<AutoModerationRule>}\n   */\n  async setExemptChannels(exemptChannels, reason) {\n    return this.edit({ exemptChannels, reason });\n  }\n}\n\nexports.AutoModerationRule = AutoModerationRule;\n"
  },
  {
    "path": "packages/discord.js/src/structures/AutocompleteInteraction.js",
    "content": "'use strict';\n\nconst { InteractionResponseType, Routes } = require('discord-api-types/v10');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { BaseInteraction } = require('./BaseInteraction.js');\nconst { CommandInteractionOptionResolver } = require('./CommandInteractionOptionResolver.js');\n\n/**\n * Represents an autocomplete interaction.\n *\n * @extends {BaseInteraction}\n */\nclass AutocompleteInteraction extends BaseInteraction {\n  constructor(client, data) {\n    super(client, data);\n\n    /**\n     * The id of the channel this interaction was sent in\n     *\n     * @type {Snowflake}\n     * @name AutocompleteInteraction#channelId\n     */\n\n    /**\n     * The invoked application command's id\n     *\n     * @type {Snowflake}\n     */\n    this.commandId = data.data.id;\n\n    /**\n     * The invoked application command's name\n     *\n     * @type {string}\n     */\n    this.commandName = data.data.name;\n\n    /**\n     * The invoked application command's type\n     *\n     * @type {ApplicationCommandType}\n     */\n    this.commandType = data.data.type;\n\n    /**\n     * The id of the guild the invoked application command is registered to\n     *\n     * @type {?Snowflake}\n     */\n    this.commandGuildId = data.data.guild_id ?? null;\n\n    /**\n     * Whether this interaction has already received a response\n     *\n     * @type {boolean}\n     */\n    this.responded = false;\n\n    /**\n     * The options passed to the command\n     *\n     * @type {CommandInteractionOptionResolver}\n     */\n    this.options = new CommandInteractionOptionResolver(this.client, data.data.options ?? []);\n  }\n\n  /**\n   * The invoked application command, if it was fetched before\n   *\n   * @type {?ApplicationCommand}\n   */\n  get command() {\n    const id = this.commandId;\n    return this.guild?.commands.cache.get(id) ?? this.client.application.commands.cache.get(id) ?? null;\n  }\n\n  /**\n   * Sends results for the autocomplete of this interaction.\n   *\n   * @param {ApplicationCommandOptionChoiceData[]} options The options for the autocomplete\n   * @returns {Promise<void>}\n   * @example\n   * // respond to autocomplete interaction\n   * interaction.respond([\n   *  {\n   *    name: 'Option 1',\n   *    value: 'option1',\n   *  },\n   * ])\n   *  .then(() => console.log('Successfully responded to the autocomplete interaction'))\n   *  .catch(console.error);\n   */\n  async respond(options) {\n    if (this.responded) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);\n\n    await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {\n      body: {\n        type: InteractionResponseType.ApplicationCommandAutocompleteResult,\n        data: {\n          choices: options.map(({ nameLocalizations, ...option }) => ({\n            ...this.client.options.jsonTransformer(option),\n            name_localizations: nameLocalizations,\n          })),\n        },\n      },\n      auth: false,\n    });\n    this.responded = true;\n  }\n}\n\nexports.AutocompleteInteraction = AutocompleteInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Base.js",
    "content": "'use strict';\n\nconst { flatten } = require('../util/Util.js');\n\n/**\n * Represents a data model that is identifiable by a Snowflake (i.e. Discord API data models).\n *\n * @abstract\n */\nclass Base {\n  constructor(client) {\n    /**\n     * The client that instantiated this\n     *\n     * @name Base#client\n     * @type {Client}\n     * @readonly\n     */\n    Object.defineProperty(this, 'client', { value: client });\n  }\n\n  _clone() {\n    return Object.assign(Object.create(this), this);\n  }\n\n  _patch(data) {\n    return data;\n  }\n\n  _update(data) {\n    const clone = this._clone();\n    this._patch(data);\n    return clone;\n  }\n\n  toJSON(...props) {\n    return flatten(this, ...props);\n  }\n\n  valueOf() {\n    return this.id;\n  }\n}\n\nexports.Base = Base;\n"
  },
  {
    "path": "packages/discord.js/src/structures/BaseChannel.js",
    "content": "'use strict';\n\nconst { channelLink, channelMention } = require('@discordjs/formatters');\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { ChannelType, Routes } = require('discord-api-types/v10');\nconst { ChannelFlagsBitField } = require('../util/ChannelFlagsBitField.js');\nconst { ThreadChannelTypes } = require('../util/Constants.js');\nconst { Base } = require('./Base.js');\n\n/**\n * Represents any channel on Discord.\n *\n * @extends {Base}\n * @abstract\n */\nclass BaseChannel extends Base {\n  constructor(client, data, immediatePatch = true) {\n    super(client);\n\n    /**\n     * The type of the channel\n     *\n     * @type {ChannelType}\n     */\n    this.type = data.type;\n\n    if (data && immediatePatch) this._patch(data);\n  }\n\n  _patch(data) {\n    if ('flags' in data) {\n      /**\n       * The flags that are applied to the channel.\n       * <info>This is only `null` in a {@link PartialGroupDMChannel}. In all other cases, it is not `null`.</info>\n       *\n       * @type {?Readonly<ChannelFlagsBitField>}\n       */\n      this.flags = new ChannelFlagsBitField(data.flags).freeze();\n    } else {\n      this.flags ??= new ChannelFlagsBitField().freeze();\n    }\n\n    /**\n     * The channel's id\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n  }\n\n  /**\n   * The timestamp the channel was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time the channel was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * The URL to the channel\n   *\n   * @type {string}\n   * @readonly\n   */\n  get url() {\n    return this.isDMBased() ? channelLink(this.id) : channelLink(this.id, this.guildId);\n  }\n\n  /**\n   * Whether this Channel is a partial\n   * <info>This is always false outside of DM channels.</info>\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get partial() {\n    return false;\n  }\n\n  /**\n   * When concatenated with a string, this automatically returns the channel's mention instead of the Channel object.\n   *\n   * @returns {string}\n   * @example\n   * // Logs: Hello from <#123456789012345678>!\n   * console.log(`Hello from ${channel}!`);\n   */\n  toString() {\n    return channelMention(this.id);\n  }\n\n  /**\n   * Deletes this channel.\n   *\n   * @returns {Promise<BaseChannel>}\n   * @example\n   * // Delete the channel\n   * channel.delete()\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async delete() {\n    await this.client.rest.delete(Routes.channel(this.id));\n    return this;\n  }\n\n  /**\n   * Fetches this channel.\n   *\n   * @param {boolean} [force=true] Whether to skip the cache check and request the API\n   * @returns {Promise<BaseChannel>}\n   */\n  async fetch(force = true) {\n    return this.client.channels.fetch(this.id, { force });\n  }\n\n  /**\n   * Indicates whether this channel is a {@link ThreadChannel}.\n   *\n   * @returns {boolean}\n   */\n  isThread() {\n    return ThreadChannelTypes.includes(this.type);\n  }\n\n  /**\n   * Indicates whether this channel is {@link TextBasedChannels text-based}.\n   *\n   * @returns {boolean}\n   */\n  isTextBased() {\n    return 'messages' in this;\n  }\n\n  /**\n   * Indicates whether this channel is DM-based (either a {@link DMChannel} or a {@link PartialGroupDMChannel}).\n   *\n   * @returns {boolean}\n   */\n  isDMBased() {\n    return [ChannelType.DM, ChannelType.GroupDM].includes(this.type);\n  }\n\n  /**\n   * Indicates whether this channel is {@link BaseGuildVoiceChannel voice-based}.\n   *\n   * @returns {boolean}\n   */\n  isVoiceBased() {\n    return 'bitrate' in this;\n  }\n\n  /**\n   * Indicates whether this channel is {@link ThreadOnlyChannel thread-only}.\n   *\n   * @returns {boolean}\n   */\n  isThreadOnly() {\n    return 'availableTags' in this;\n  }\n\n  /**\n   * Indicates whether this channel is sendable.\n   *\n   * @returns {boolean}\n   */\n  isSendable() {\n    return 'send' in this;\n  }\n\n  toJSON(...props) {\n    return super.toJSON({ createdTimestamp: true }, ...props);\n  }\n}\n\nexports.BaseChannel = BaseChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/BaseGuild.js",
    "content": "'use strict';\n\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { Routes, GuildFeature } = require('discord-api-types/v10');\nconst { Base } = require('./Base.js');\n\n/**\n * The base class for {@link Guild}, {@link OAuth2Guild} and {@link InviteGuild}.\n *\n * @extends {Base}\n * @abstract\n */\nclass BaseGuild extends Base {\n  constructor(client, data) {\n    super(client);\n\n    /**\n     * The guild's id\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    /**\n     * The name of this guild\n     *\n     * @type {string}\n     */\n    this.name = data.name;\n\n    /**\n     * The icon hash of this guild\n     *\n     * @type {?string}\n     */\n    this.icon = data.icon;\n\n    /**\n     * An array of features available to this guild\n     *\n     * @type {GuildFeature[]}\n     */\n    this.features = data.features;\n  }\n\n  /**\n   * The timestamp this guild was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time this guild was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * The acronym that shows up in place of a guild icon\n   *\n   * @type {string}\n   * @readonly\n   */\n  get nameAcronym() {\n    /* eslint-disable unicorn/prefer-string-replace-all */\n    return this.name\n      .replace(/'s /g, ' ')\n      .replace(/\\w+/g, word => word[0])\n      .replace(/\\s/g, '');\n    /* eslint-enable unicorn/prefer-string-replace-all */\n  }\n\n  /**\n   * Whether this guild is partnered\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get partnered() {\n    return this.features.includes(GuildFeature.Partnered);\n  }\n\n  /**\n   * Whether this guild is verified\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get verified() {\n    return this.features.includes(GuildFeature.Verified);\n  }\n\n  /**\n   * The URL to this guild's icon.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  iconURL(options = {}) {\n    return this.icon && this.client.rest.cdn.icon(this.id, this.icon, options);\n  }\n\n  /**\n   * Fetches this guild.\n   *\n   * @returns {Promise<Guild>}\n   */\n  async fetch() {\n    const data = await this.client.rest.get(Routes.guild(this.id), {\n      query: makeURLSearchParams({ with_counts: true }),\n    });\n    return this.client.guilds._add(data);\n  }\n\n  /**\n   * When concatenated with a string, this automatically returns the guild's name instead of the Guild object.\n   *\n   * @returns {string}\n   */\n  toString() {\n    return this.name;\n  }\n}\n\nexports.BaseGuild = BaseGuild;\n"
  },
  {
    "path": "packages/discord.js/src/structures/BaseGuildEmoji.js",
    "content": "'use strict';\n\nconst { Emoji } = require('./Emoji.js');\n\n/**\n * Parent class for {@link GuildEmoji} and {@link GuildPreviewEmoji}.\n *\n * @extends {Emoji}\n * @abstract\n */\nclass BaseGuildEmoji extends Emoji {\n  constructor(client, data, guild) {\n    super(client, data);\n\n    /**\n     * The guild this emoji is a part of\n     *\n     * @type {Guild|GuildPreview}\n     */\n    this.guild = guild;\n\n    this.requiresColons = null;\n    this.managed = null;\n    this.available = null;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('name' in data) this.name = data.name;\n\n    if ('require_colons' in data) {\n      /**\n       * Whether or not this emoji requires colons surrounding it\n       *\n       * @type {?boolean}\n       */\n      this.requiresColons = data.require_colons;\n    }\n\n    if ('managed' in data) {\n      /**\n       * Whether this emoji is managed by an external service\n       *\n       * @type {?boolean}\n       */\n      this.managed = data.managed;\n    }\n\n    if ('available' in data) {\n      /**\n       * Whether this emoji is available\n       *\n       * @type {?boolean}\n       */\n      this.available = data.available;\n    }\n  }\n}\n\n/**\n * Returns a URL for the emoji.\n *\n * @method imageURL\n * @memberof BaseGuildEmoji\n * @instance\n * @param {EmojiURLOptions} [options={}] Options for the emoji URL\n * @returns {string}\n */\n\n/**\n * The emoji's name\n *\n * @name name\n * @memberof BaseGuildEmoji\n * @instance\n * @type {string}\n * @readonly\n */\n\n/**\n * Whether or not the emoji is animated\n *\n * @name animated\n * @memberof BaseGuildEmoji\n * @instance\n * @type {boolean}\n * @readonly\n */\n\n/**\n * The time the emoji was created at.\n *\n * @name createdAt\n * @memberof BaseGuildEmoji\n * @instance\n * @type {Date}\n * @readonly\n */\n\n/**\n * The timestamp the emoji was created at.\n *\n * @name createdTimestamp\n * @memberof BaseGuildEmoji\n * @instance\n * @type {number}\n * @readonly\n */\n\nexports.BaseGuildEmoji = BaseGuildEmoji;\n"
  },
  {
    "path": "packages/discord.js/src/structures/BaseGuildTextChannel.js",
    "content": "'use strict';\n\nconst { GuildMessageManager } = require('../managers/GuildMessageManager.js');\nconst { GuildTextThreadManager } = require('../managers/GuildTextThreadManager.js');\nconst { GuildChannel } = require('./GuildChannel.js');\nconst { TextBasedChannel } = require('./interfaces/TextBasedChannel.js');\n\n/**\n * Represents a text-based guild channel on Discord.\n *\n * @extends {GuildChannel}\n * @implements {TextBasedChannel}\n */\nclass BaseGuildTextChannel extends GuildChannel {\n  constructor(guild, data, client) {\n    super(guild, data, client, false);\n\n    /**\n     * A manager of the messages sent to this channel\n     *\n     * @type {GuildMessageManager}\n     */\n    this.messages = new GuildMessageManager(this);\n\n    /**\n     * A manager of the threads belonging to this channel\n     *\n     * @type {GuildTextThreadManager}\n     */\n    this.threads = new GuildTextThreadManager(this);\n\n    /**\n     * If the guild considers this channel NSFW\n     *\n     * @type {boolean}\n     */\n    this.nsfw = Boolean(data.nsfw);\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    super._patch(data);\n\n    if ('topic' in data) {\n      /**\n       * The topic of the text channel\n       *\n       * @type {?string}\n       */\n      this.topic = data.topic;\n    }\n\n    if ('nsfw' in data) {\n      this.nsfw = Boolean(data.nsfw);\n    }\n\n    if ('last_message_id' in data) {\n      /**\n       * The last message id sent in the channel, if one was sent\n       *\n       * @type {?Snowflake}\n       */\n      this.lastMessageId = data.last_message_id;\n    }\n\n    if ('last_pin_timestamp' in data) {\n      /**\n       * The timestamp when the last pinned message was pinned, if there was one\n       *\n       * @type {?number}\n       */\n      this.lastPinTimestamp = data.last_pin_timestamp ? Date.parse(data.last_pin_timestamp) : null;\n    }\n\n    if ('default_auto_archive_duration' in data) {\n      /**\n       * The default auto archive duration for newly created threads in this channel\n       *\n       * @type {?ThreadAutoArchiveDuration}\n       */\n      this.defaultAutoArchiveDuration = data.default_auto_archive_duration;\n    }\n\n    if ('default_thread_rate_limit_per_user' in data) {\n      /**\n       * The initial rate limit per user (slowmode) to set on newly created threads in a channel.\n       *\n       * @type {?number}\n       */\n      this.defaultThreadRateLimitPerUser = data.default_thread_rate_limit_per_user;\n    } else {\n      this.defaultThreadRateLimitPerUser ??= null;\n    }\n\n    if ('messages' in data) {\n      for (const message of data.messages) this.messages._add(message);\n    }\n  }\n\n  /**\n   * Sets the default auto archive duration for all newly created threads in this channel.\n   *\n   * @param {ThreadAutoArchiveDuration} defaultAutoArchiveDuration The new default auto archive duration\n   * @param {string} [reason] Reason for changing the channel's default auto archive duration\n   * @returns {Promise<TextChannel>}\n   */\n  async setDefaultAutoArchiveDuration(defaultAutoArchiveDuration, reason) {\n    return this.edit({ defaultAutoArchiveDuration, reason });\n  }\n\n  /**\n   * Sets the type of this channel.\n   * <info>Only conversion between {@link TextChannel} and {@link AnnouncementChannel} is supported.</info>\n   *\n   * @param {ChannelType.GuildText|ChannelType.GuildAnnouncement} type The new channel type\n   * @param {string} [reason] Reason for changing the channel's type\n   * @returns {Promise<GuildChannel>}\n   */\n  async setType(type, reason) {\n    return this.edit({ type, reason });\n  }\n\n  /**\n   * Sets a new topic for the guild channel.\n   *\n   * @param {?string} topic The new topic for the guild channel\n   * @param {string} [reason] Reason for changing the guild channel's topic\n   * @returns {Promise<GuildChannel>}\n   * @example\n   * // Set a new channel topic\n   * channel.setTopic('needs more rate limiting')\n   *   .then(newChannel => console.log(`Channel's new topic is ${newChannel.topic}`))\n   *   .catch(console.error);\n   */\n  async setTopic(topic, reason) {\n    return this.edit({ topic, reason });\n  }\n\n  /**\n   * Data that can be resolved to an Application. This can be:\n   * - An Application\n   * - An Activity with associated Application\n   * - A Snowflake\n   *\n   * @typedef {Application|Snowflake} ApplicationResolvable\n   */\n\n  /**\n   * Options used to create an invite to a guild channel.\n   *\n   * @typedef {Object} InviteCreateOptions\n   * @property {boolean} [temporary] Whether members that joined via the invite should be automatically\n   * kicked after 24 hours if they have not yet received a role\n   * @property {number} [maxAge] How long the invite should last (in seconds, 0 for forever)\n   * @property {number} [maxUses] Maximum number of uses\n   * @property {boolean} [unique] Create a unique invite, or use an existing one with similar settings\n   * @property {UserResolvable} [targetUser] The user whose stream to display for this invite,\n   * required if `targetType` is {@link InviteTargetType.Stream}, the user must be streaming in the channel\n   * @property {ApplicationResolvable} [targetApplication] The embedded application to open for this invite,\n   * required if `targetType` is {@link InviteTargetType.Stream}, the application must have the\n   * {@link InviteTargetType.EmbeddedApplication} flag\n   * @property {InviteTargetType} [targetType] The type of the target for this voice channel invite\n   * @property {string} [reason] The reason for creating the invite\n   */\n\n  /**\n   * Creates an invite to this guild channel.\n   *\n   * @param {InviteCreateOptions} [options={}] The options for creating the invite\n   * @returns {Promise<Invite>}\n   * @example\n   * // Create an invite to a channel\n   * channel.createInvite()\n   *   .then(invite => console.log(`Created an invite with a code of ${invite.code}`))\n   *   .catch(console.error);\n   */\n  async createInvite(options) {\n    return this.guild.invites.create(this.id, options);\n  }\n\n  /**\n   * Fetches a collection of invites to this guild channel.\n   * Resolves with a collection mapping invites by their codes.\n   *\n   * @param {boolean} [cache=true] Whether or not to cache the fetched invites\n   * @returns {Promise<Collection<string, Invite>>}\n   */\n  async fetchInvites(cache = true) {\n    return this.guild.invites.fetch({ channelId: this.id, cache });\n  }\n\n  // These are here only for documentation purposes - they are implemented by TextBasedChannel\n\n  /* eslint-disable getter-return */\n  get lastMessage() {}\n\n  get lastPinAt() {}\n\n  send() {}\n\n  sendTyping() {}\n\n  createMessageCollector() {}\n\n  awaitMessages() {}\n\n  createMessageComponentCollector() {}\n\n  awaitMessageComponent() {}\n\n  bulkDelete() {}\n\n  fetchWebhooks() {}\n\n  createWebhook() {}\n\n  setRateLimitPerUser() {}\n\n  setNSFW() {}\n}\n\nTextBasedChannel.applyToClass(BaseGuildTextChannel);\n\nexports.BaseGuildTextChannel = BaseGuildTextChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/BaseGuildVoiceChannel.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { PermissionFlagsBits } = require('discord-api-types/v10');\nconst { GuildMessageManager } = require('../managers/GuildMessageManager.js');\nconst { GuildChannel } = require('./GuildChannel.js');\nconst { TextBasedChannel } = require('./interfaces/TextBasedChannel.js');\n\n/**\n * Represents a voice-based guild channel on Discord.\n *\n * @extends {GuildChannel}\n * @implements {TextBasedChannel}\n */\nclass BaseGuildVoiceChannel extends GuildChannel {\n  constructor(guild, data, client) {\n    super(guild, data, client, false);\n    /**\n     * A manager of the messages sent to this channel\n     *\n     * @type {GuildMessageManager}\n     */\n    this.messages = new GuildMessageManager(this);\n\n    /**\n     * If the guild considers this channel NSFW\n     *\n     * @type {boolean}\n     */\n    this.nsfw = Boolean(data.nsfw);\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    super._patch(data);\n\n    if ('rtc_region' in data) {\n      /**\n       * The RTC region for this voice-based channel. This region is automatically selected if `null`.\n       *\n       * @type {?string}\n       */\n      this.rtcRegion = data.rtc_region;\n    }\n\n    if ('bitrate' in data) {\n      /**\n       * The bitrate of this voice-based channel\n       *\n       * @type {number}\n       */\n      this.bitrate = data.bitrate;\n    }\n\n    if ('user_limit' in data) {\n      /**\n       * The maximum amount of users allowed in this channel.\n       *\n       * @type {number}\n       */\n      this.userLimit = data.user_limit;\n    }\n\n    if ('video_quality_mode' in data) {\n      /**\n       * The camera video quality mode of the channel.\n       *\n       * @type {?VideoQualityMode}\n       */\n      this.videoQualityMode = data.video_quality_mode;\n    } else {\n      this.videoQualityMode ??= null;\n    }\n\n    if ('last_message_id' in data) {\n      /**\n       * The last message id sent in the channel, if one was sent\n       *\n       * @type {?Snowflake}\n       */\n      this.lastMessageId = data.last_message_id;\n    }\n\n    if ('messages' in data) {\n      for (const message of data.messages) this.messages._add(message);\n    }\n\n    if ('rate_limit_per_user' in data) {\n      /**\n       * The rate limit per user (slowmode) for this channel in seconds\n       *\n       * @type {number}\n       */\n      this.rateLimitPerUser = data.rate_limit_per_user;\n    }\n\n    if ('nsfw' in data) {\n      this.nsfw = data.nsfw;\n    }\n  }\n\n  /**\n   * The members in this voice-based channel\n   *\n   * @type {Collection<Snowflake, GuildMember>}\n   * @readonly\n   */\n  get members() {\n    const coll = new Collection();\n    for (const state of this.guild.voiceStates.cache.values()) {\n      if (state.channelId === this.id && state.member) {\n        coll.set(state.id, state.member);\n      }\n    }\n\n    return coll;\n  }\n\n  /**\n   * Checks if the voice-based channel is full\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get full() {\n    return this.userLimit > 0 && this.members.size >= this.userLimit;\n  }\n\n  /**\n   * Whether the channel is joinable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get joinable() {\n    if (!this.viewable) return false;\n    const permissions = this.permissionsFor(this.client.user);\n    if (!permissions) return false;\n\n    // This flag allows joining even if timed out\n    if (permissions.has(PermissionFlagsBits.Administrator, false)) return true;\n\n    return (\n      this.guild.members.me.communicationDisabledUntilTimestamp < Date.now() &&\n      permissions.has(PermissionFlagsBits.Connect, false)\n    );\n  }\n\n  /**\n   * Creates an invite to this guild channel.\n   *\n   * @param {InviteCreateOptions} [options={}] The options for creating the invite\n   * @returns {Promise<Invite>}\n   * @example\n   * // Create an invite to a channel\n   * channel.createInvite()\n   *   .then(invite => console.log(`Created an invite with a code of ${invite.code}`))\n   *   .catch(console.error);\n   */\n  async createInvite(options) {\n    return this.guild.invites.create(this.id, options);\n  }\n\n  /**\n   * Fetches a collection of invites to this guild channel.\n   *\n   * @param {boolean} [cache=true] Whether to cache the fetched invites\n   * @returns {Promise<Collection<string, Invite>>}\n   */\n  async fetchInvites(cache = true) {\n    return this.guild.invites.fetch({ channelId: this.id, cache });\n  }\n\n  /**\n   * Sets the bitrate of the channel.\n   *\n   * @param {number} bitrate The new bitrate\n   * @param {string} [reason] Reason for changing the channel's bitrate\n   * @returns {Promise<BaseGuildVoiceChannel>}\n   * @example\n   * // Set the bitrate of a voice channel\n   * channel.setBitrate(48_000)\n   *   .then(channel => console.log(`Set bitrate to ${channel.bitrate}bps for ${channel.name}`))\n   *   .catch(console.error);\n   */\n  async setBitrate(bitrate, reason) {\n    return this.edit({ bitrate, reason });\n  }\n\n  /**\n   * Sets the RTC region of the channel.\n   *\n   * @param {?string} rtcRegion The new region of the channel. Set to `null` to remove a specific region for the channel\n   * @param {string} [reason] The reason for modifying this region.\n   * @returns {Promise<BaseGuildVoiceChannel>}\n   * @example\n   * // Set the RTC region to sydney\n   * channel.setRTCRegion('sydney');\n   * @example\n   * // Remove a fixed region for this channel - let Discord decide automatically\n   * channel.setRTCRegion(null, 'We want to let Discord decide.');\n   */\n  async setRTCRegion(rtcRegion, reason) {\n    return this.edit({ rtcRegion, reason });\n  }\n\n  /**\n   * Sets the user limit of the channel.\n   *\n   * @param {number} userLimit The new user limit\n   * @param {string} [reason] Reason for changing the user limit\n   * @returns {Promise<BaseGuildVoiceChannel>}\n   * @example\n   * // Set the user limit of a voice channel\n   * channel.setUserLimit(42)\n   *   .then(channel => console.log(`Set user limit to ${channel.userLimit} for ${channel.name}`))\n   *   .catch(console.error);\n   */\n  async setUserLimit(userLimit, reason) {\n    return this.edit({ userLimit, reason });\n  }\n\n  /**\n   * Sets the camera video quality mode of the channel.\n   *\n   * @param {VideoQualityMode} videoQualityMode The new camera video quality mode.\n   * @param {string} [reason] Reason for changing the camera video quality mode.\n   * @returns {Promise<BaseGuildVoiceChannel>}\n   */\n  async setVideoQualityMode(videoQualityMode, reason) {\n    return this.edit({ videoQualityMode, reason });\n  }\n\n  // These are here only for documentation purposes - they are implemented by TextBasedChannel\n\n  // eslint-disable-next-line getter-return\n  get lastMessage() {}\n\n  send() {}\n\n  sendTyping() {}\n\n  createMessageCollector() {}\n\n  awaitMessages() {}\n\n  createMessageComponentCollector() {}\n\n  awaitMessageComponent() {}\n\n  bulkDelete() {}\n\n  fetchWebhooks() {}\n\n  createWebhook() {}\n\n  setRateLimitPerUser() {}\n\n  setNSFW() {}\n}\n\nTextBasedChannel.applyToClass(BaseGuildVoiceChannel, ['lastPinAt']);\n\nexports.BaseGuildVoiceChannel = BaseGuildVoiceChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/BaseInteraction.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { InteractionType, ApplicationCommandType, ComponentType } = require('discord-api-types/v10');\nconst { SelectMenuTypes } = require('../util/Constants.js');\nconst { PermissionsBitField } = require('../util/PermissionsBitField.js');\nconst { AuthorizingIntegrationOwners } = require('./AuthorizingIntegrationOwners.js');\nconst { Base } = require('./Base.js');\n\n/**\n * Represents an interaction.\n *\n * @extends {Base}\n * @abstract\n */\nclass BaseInteraction extends Base {\n  constructor(client, data) {\n    super(client);\n\n    /**\n     * The interaction's type\n     *\n     * @type {InteractionType}\n     */\n    this.type = data.type;\n\n    /**\n     * The interaction's id\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    /**\n     * The interaction's token\n     *\n     * @type {string}\n     * @name BaseInteraction#token\n     * @readonly\n     */\n    Object.defineProperty(this, 'token', { value: data.token });\n\n    /**\n     * The application's id\n     *\n     * @type {Snowflake}\n     */\n    this.applicationId = data.application_id;\n\n    /**\n     * The id of the channel this interaction was sent in\n     *\n     * @type {?Snowflake}\n     */\n    this.channelId = data.channel?.id ?? null;\n\n    /**\n     * The id of the guild this interaction was sent in\n     *\n     * @type {?Snowflake}\n     */\n    this.guildId = data.guild_id ?? null;\n\n    /**\n     * The user who created this interaction\n     *\n     * @type {User}\n     */\n    this.user = this.client.users._add(data.user ?? data.member.user);\n\n    /**\n     * If this interaction was sent in a guild, the member which sent it\n     *\n     * @type {?(GuildMember|APIInteractionGuildMember)}\n     */\n    this.member = data.member ? (this.guild?.members._add(data.member) ?? data.member) : null;\n\n    /**\n     * The version\n     *\n     * @type {number}\n     */\n    this.version = data.version;\n\n    /**\n     * Set of permissions the application or bot has within the channel the interaction was sent from\n     *\n     * @type {Readonly<PermissionsBitField>}\n     */\n    this.appPermissions = new PermissionsBitField(data.app_permissions).freeze();\n\n    /**\n     * The permissions of the member, if one exists, in the channel this interaction was executed in\n     *\n     * @type {?Readonly<PermissionsBitField>}\n     */\n    this.memberPermissions = data.member?.permissions\n      ? new PermissionsBitField(data.member.permissions).freeze()\n      : null;\n\n    /**\n     * The locale of the user who invoked this interaction\n     *\n     * @type {Locale}\n     */\n    this.locale = data.locale;\n\n    /**\n     * The preferred locale from the guild this interaction was sent in\n     *\n     * @type {?Locale}\n     */\n    this.guildLocale = data.guild_locale ?? null;\n\n    /**\n     * The entitlements for the invoking user, representing access to premium SKUs\n     *\n     * @type {Collection<Snowflake, Entitlement>}\n     */\n    this.entitlements = data.entitlements.reduce(\n      (coll, entitlement) => coll.set(entitlement.id, this.client.application.entitlements._add(entitlement)),\n      new Collection(),\n    );\n\n    /**\n     * Mapping of integration types that the application was authorized for the related user or guild ids\n     *\n     * @type {AuthorizingIntegrationOwners}\n     * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-authorizing-integration-owners-object}\n     */\n    this.authorizingIntegrationOwners = new AuthorizingIntegrationOwners(\n      this.client,\n      data.authorizing_integration_owners,\n    );\n\n    /**\n     * Context where the interaction was triggered from\n     *\n     * @type {?InteractionContextType}\n     */\n    this.context = data.context ?? null;\n\n    /**\n     * Attachment size limit in bytes\n     *\n     * @type {number}\n     */\n    this.attachmentSizeLimit = data.attachment_size_limit;\n  }\n\n  /**\n   * The timestamp the interaction was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time the interaction was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * The channel this interaction was sent in\n   *\n   * @type {?TextBasedChannels}\n   * @readonly\n   */\n  get channel() {\n    return this.client.channels.cache.get(this.channelId) ?? null;\n  }\n\n  /**\n   * The guild this interaction was sent in\n   *\n   * @type {?Guild}\n   * @readonly\n   */\n  get guild() {\n    return this.client.guilds.cache.get(this.guildId) ?? null;\n  }\n\n  /**\n   * Indicates whether this interaction is received from a guild.\n   *\n   * @returns {boolean}\n   */\n  inGuild() {\n    return Boolean(this.guildId && this.member);\n  }\n\n  /**\n   * Indicates whether this interaction is received from a cached guild.\n   *\n   * @returns {boolean}\n   */\n  inCachedGuild() {\n    return Boolean(this.guild && this.member);\n  }\n\n  /**\n   * Indicates whether or not this interaction is received from an uncached guild.\n   *\n   * @returns {boolean}\n   */\n  inRawGuild() {\n    return Boolean(this.guildId && !this.guild && this.member);\n  }\n\n  /**\n   * Indicates whether this interaction is an {@link AutocompleteInteraction}\n   *\n   * @returns {boolean}\n   */\n  isAutocomplete() {\n    return this.type === InteractionType.ApplicationCommandAutocomplete;\n  }\n\n  /**\n   * Indicates whether this interaction is a {@link CommandInteraction}\n   *\n   * @returns {boolean}\n   */\n  isCommand() {\n    return this.type === InteractionType.ApplicationCommand;\n  }\n\n  /**\n   * Indicates whether this interaction is a {@link ChatInputCommandInteraction}.\n   *\n   * @returns {boolean}\n   */\n  isChatInputCommand() {\n    return this.type === InteractionType.ApplicationCommand && this.commandType === ApplicationCommandType.ChatInput;\n  }\n\n  /**\n   * Indicates whether this interaction is a {@link ContextMenuCommandInteraction}\n   *\n   * @returns {boolean}\n   */\n  isContextMenuCommand() {\n    return (\n      this.type === InteractionType.ApplicationCommand &&\n      [ApplicationCommandType.User, ApplicationCommandType.Message].includes(this.commandType)\n    );\n  }\n\n  /**\n   * Indicates whether this interaction is a {@link PrimaryEntryPointCommandInteraction}\n   *\n   * @returns {boolean}\n   */\n  isPrimaryEntryPointCommand() {\n    return (\n      this.type === InteractionType.ApplicationCommand && this.commandType === ApplicationCommandType.PrimaryEntryPoint\n    );\n  }\n\n  /**\n   * Indicates whether this interaction is a {@link MessageComponentInteraction}\n   *\n   * @returns {boolean}\n   */\n  isMessageComponent() {\n    return this.type === InteractionType.MessageComponent;\n  }\n\n  /**\n   * Indicates whether this interaction is a {@link ModalSubmitInteraction}\n   *\n   * @returns {boolean}\n   */\n  isModalSubmit() {\n    return this.type === InteractionType.ModalSubmit;\n  }\n\n  /**\n   * Indicates whether this interaction is a {@link UserContextMenuCommandInteraction}\n   *\n   * @returns {boolean}\n   */\n  isUserContextMenuCommand() {\n    return this.isContextMenuCommand() && this.commandType === ApplicationCommandType.User;\n  }\n\n  /**\n   * Indicates whether this interaction is a {@link MessageContextMenuCommandInteraction}\n   *\n   * @returns {boolean}\n   */\n  isMessageContextMenuCommand() {\n    return this.isContextMenuCommand() && this.commandType === ApplicationCommandType.Message;\n  }\n\n  /**\n   * Indicates whether this interaction is a {@link ButtonInteraction}.\n   *\n   * @returns {boolean}\n   */\n  isButton() {\n    return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.Button;\n  }\n\n  /**\n   * Indicates whether this interaction is a select menu of any known type.\n   *\n   * @returns {boolean}\n   */\n  isSelectMenu() {\n    return this.type === InteractionType.MessageComponent && SelectMenuTypes.includes(this.componentType);\n  }\n\n  /**\n   * Indicates whether this interaction is a {@link StringSelectMenuInteraction}.\n   *\n   * @returns {boolean}\n   */\n  isStringSelectMenu() {\n    return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.StringSelect;\n  }\n\n  /**\n   * Indicates whether this interaction is a {@link UserSelectMenuInteraction}\n   *\n   * @returns {boolean}\n   */\n  isUserSelectMenu() {\n    return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.UserSelect;\n  }\n\n  /**\n   * Indicates whether this interaction is a {@link RoleSelectMenuInteraction}\n   *\n   * @returns {boolean}\n   */\n  isRoleSelectMenu() {\n    return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.RoleSelect;\n  }\n\n  /**\n   * Indicates whether this interaction is a {@link ChannelSelectMenuInteraction}\n   *\n   * @returns {boolean}\n   */\n  isChannelSelectMenu() {\n    return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.ChannelSelect;\n  }\n\n  /**\n   * Indicates whether this interaction is a {@link MentionableSelectMenuInteraction}\n   *\n   * @returns {boolean}\n   */\n  isMentionableSelectMenu() {\n    return this.type === InteractionType.MessageComponent && this.componentType === ComponentType.MentionableSelect;\n  }\n\n  /**\n   * Indicates whether this interaction can be replied to.\n   *\n   * @returns {boolean}\n   */\n  isRepliable() {\n    return ![InteractionType.Ping, InteractionType.ApplicationCommandAutocomplete].includes(this.type);\n  }\n}\n\nexports.BaseInteraction = BaseInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/BaseInvite.js",
    "content": "'use strict';\n\nconst { RouteBases } = require('discord-api-types/v10');\nconst { Base } = require('./Base.js');\n\n/**\n * The base invite class.\n *\n * @extends {Base}\n */\nclass BaseInvite extends Base {\n  constructor(client, data) {\n    super(client);\n\n    /**\n     * The type of this invite.\n     *\n     * @type {InviteType}\n     */\n    this.type = data.type;\n\n    /**\n     * The invite code.\n     *\n     * @type {string}\n     */\n    this.code = data.code;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('inviter_id' in data) {\n      /**\n       * The id of the user that created this invite.\n       *\n       * @type {?Snowflake}\n       */\n      this.inviterId = data.inviter_id;\n    } else {\n      this.inviterId ??= null;\n    }\n\n    if ('inviter' in data) {\n      this.client.users._add(data.inviter);\n      this.inviterId ??= data.inviter.id;\n    }\n\n    if ('max_age' in data) {\n      /**\n       * The maximum age of the invite in seconds. `0` for no expiry.\n       *\n       * @type {?number}\n       */\n      this.maxAge = data.max_age;\n    } else {\n      this.maxAge ??= null;\n    }\n\n    if ('created_at' in data) {\n      /**\n       * The timestamp this invite was created at.\n       *\n       * @type {?number}\n       */\n      this.createdTimestamp = Date.parse(data.created_at);\n    } else {\n      this.createdTimestamp ??= null;\n    }\n\n    if ('expires_at' in data) {\n      this._expiresTimestamp = data.expires_at && Date.parse(data.expires_at);\n    } else {\n      this._expiresTimestamp ??= null;\n    }\n\n    if ('channel_id' in data) {\n      /**\n       * The id of the channel this invite is for.\n       *\n       * @type {?Snowflake}\n       */\n      this.channelId = data.channel_id;\n    }\n\n    if ('approximate_member_count' in data) {\n      /**\n       * The approximate total number of members.\n       *\n       * @type {?number}\n       */\n      this.approximateMemberCount = data.approximate_member_count;\n    } else {\n      this.approximateMemberCount ??= null;\n    }\n  }\n\n  /**\n   * The user that created this invite.\n   *\n   * @type {?User}\n   * @readonly\n   */\n  get inviter() {\n    return this.inviterId && this.client.users.resolve(this.inviterId);\n  }\n\n  /**\n   * The creation date of this invite.\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get createdAt() {\n    return this.createdTimestamp && new Date(this.createdTimestamp);\n  }\n\n  /**\n   * The timestamp this invite expires at.\n   *\n   * @type {?number}\n   * @readonly\n   */\n  get expiresTimestamp() {\n    return (\n      this._expiresTimestamp ??\n      (this.createdTimestamp && this.maxAge ? this.createdTimestamp + this.maxAge * 1_000 : null)\n    );\n  }\n\n  /**\n   * The expiry date of this invite.\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get expiresAt() {\n    return this.expiresTimestamp && new Date(this.expiresTimestamp);\n  }\n\n  /**\n   * The URL to the invite.\n   *\n   * @type {string}\n   * @readonly\n   */\n  get url() {\n    return `${RouteBases.invite}/${this.code}`;\n  }\n\n  /**\n   * A regular expression that matches Discord invite links.\n   * The `code` group property is present on the `exec()` result of this expression.\n   *\n   * @type {RegExp}\n   * @memberof BaseInvite\n   */\n  static InvitesPattern = /discord(?:(?:app)?\\.com\\/invite|\\.gg(?:\\/invite)?)\\/(?<code>[\\w-]{2,255})/i;\n\n  /**\n   * When concatenated with a string, this automatically concatenates the invite's URL instead of the object.\n   *\n   * @returns {string}\n   * @example\n   * // Logs: Invite: https://discord.gg/djs\n   * console.log(`Invite: ${invite}`);\n   */\n  toString() {\n    return this.url;\n  }\n\n  toJSON() {\n    return super.toJSON({\n      url: true,\n      expiresTimestamp: true,\n      uses: false,\n      channel: 'channelId',\n      inviter: 'inviterId',\n    });\n  }\n\n  valueOf() {\n    return this.code;\n  }\n}\n\nexports.BaseInvite = BaseInvite;\n"
  },
  {
    "path": "packages/discord.js/src/structures/BaseSelectMenuComponent.js",
    "content": "'use strict';\n\nconst { Component } = require('./Component.js');\n\n/**\n * Represents a select menu component\n *\n * @extends {Component}\n */\nclass BaseSelectMenuComponent extends Component {\n  /**\n   * The placeholder for this select menu\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get placeholder() {\n    return this.data.placeholder ?? null;\n  }\n\n  /**\n   * The maximum amount of options that can be selected\n   *\n   * @type {?number}\n   * @readonly\n   */\n  get maxValues() {\n    return this.data.max_values ?? null;\n  }\n\n  /**\n   * The minimum amount of options that must be selected\n   *\n   * @type {?number}\n   * @readonly\n   */\n  get minValues() {\n    return this.data.min_values ?? null;\n  }\n\n  /**\n   * The custom id of this select menu\n   *\n   * @type {string}\n   * @readonly\n   */\n  get customId() {\n    return this.data.custom_id;\n  }\n\n  /**\n   * Whether this select menu is disabled\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get disabled() {\n    return this.data.disabled ?? false;\n  }\n}\n\nexports.BaseSelectMenuComponent = BaseSelectMenuComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ButtonComponent.js",
    "content": "'use strict';\n\nconst { Component } = require('./Component.js');\n\n/**\n * Represents a button component\n *\n * @extends {Component}\n */\nclass ButtonComponent extends Component {\n  /**\n   * The style of this button\n   *\n   * @type {ButtonStyle}\n   * @readonly\n   */\n  get style() {\n    return this.data.style;\n  }\n\n  /**\n   * The label of this button\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get label() {\n    return this.data.label ?? null;\n  }\n\n  /**\n   * The emoji used in this button\n   *\n   * @type {?APIMessageComponentEmoji}\n   * @readonly\n   */\n  get emoji() {\n    return this.data.emoji ?? null;\n  }\n\n  /**\n   * Whether this button is disabled\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get disabled() {\n    return this.data.disabled ?? false;\n  }\n\n  /**\n   * The custom id of this button (only defined on non-link buttons)\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get customId() {\n    return this.data.custom_id ?? null;\n  }\n\n  /**\n   * The URL of this button (only defined on link buttons)\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get url() {\n    return this.data.url ?? null;\n  }\n}\n\nexports.ButtonComponent = ButtonComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ButtonInteraction.js",
    "content": "'use strict';\n\nconst { MessageComponentInteraction } = require('./MessageComponentInteraction.js');\n\n/**\n * Represents a button interaction.\n *\n * @extends {MessageComponentInteraction}\n */\nclass ButtonInteraction extends MessageComponentInteraction {}\n\nexports.ButtonInteraction = ButtonInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/CategoryChannel.js",
    "content": "'use strict';\n\nconst { CategoryChannelChildManager } = require('../managers/CategoryChannelChildManager.js');\nconst { GuildChannel } = require('./GuildChannel.js');\n\n/**\n * Represents a guild category channel on Discord.\n *\n * @extends {GuildChannel}\n */\nclass CategoryChannel extends GuildChannel {\n  /**\n   * The id of the parent of this channel.\n   *\n   * @name CategoryChannel#parentId\n   * @type {null}\n   */\n\n  /**\n   * The parent of this channel.\n   *\n   * @name CategoryChannel#parent\n   * @type {null}\n   * @readonly\n   */\n\n  /**\n   * Sets the category parent of this channel.\n   * <warn>It is not possible to set the parent of a CategoryChannel.</warn>\n   *\n   * @method setParent\n   * @memberof CategoryChannel\n   * @instance\n   * @param {?CategoryChannelResolvable} channel The channel to set as parent\n   * @param {SetParentOptions} [options={}] The options for setting the parent\n   * @returns {Promise<GuildChannel>}\n   */\n\n  /**\n   * A manager of the channels belonging to this category\n   *\n   * @type {CategoryChannelChildManager}\n   * @readonly\n   */\n  get children() {\n    return new CategoryChannelChildManager(this);\n  }\n}\n\nexports.CategoryChannel = CategoryChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ChannelSelectMenuComponent.js",
    "content": "'use strict';\n\nconst { BaseSelectMenuComponent } = require('./BaseSelectMenuComponent.js');\n\n/**\n * Represents a channel select menu component\n *\n * @extends {BaseSelectMenuComponent}\n */\nclass ChannelSelectMenuComponent extends BaseSelectMenuComponent {\n  /**\n   * The options in this select menu\n   *\n   * @type {?(ChannelType[])}\n   * @readonly\n   */\n  get channelTypes() {\n    return this.data.channel_types ?? null;\n  }\n}\n\nexports.ChannelSelectMenuComponent = ChannelSelectMenuComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ChannelSelectMenuInteraction.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { MessageComponentInteraction } = require('./MessageComponentInteraction.js');\n\n/**\n * Represents a {@link ComponentType.ChannelSelect} select menu interaction.\n *\n * @extends {MessageComponentInteraction}\n */\nclass ChannelSelectMenuInteraction extends MessageComponentInteraction {\n  constructor(client, data) {\n    super(client, data);\n    const { resolved, values } = data.data;\n\n    /**\n     * An array of the selected channel ids\n     *\n     * @type {Snowflake[]}\n     */\n    this.values = values ?? [];\n\n    /**\n     * Collection of the selected channels\n     *\n     * @type {Collection<Snowflake, BaseChannel|APIChannel>}\n     */\n    this.channels = new Collection();\n\n    for (const channel of Object.values(resolved?.channels ?? {})) {\n      this.channels.set(channel.id, this.client.channels._add(channel, this.guild) ?? channel);\n    }\n  }\n}\n\nexports.ChannelSelectMenuInteraction = ChannelSelectMenuInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ChatInputCommandInteraction.js",
    "content": "'use strict';\n\nconst { transformResolved } = require('../util/Util.js');\nconst { CommandInteraction } = require('./CommandInteraction.js');\nconst { CommandInteractionOptionResolver } = require('./CommandInteractionOptionResolver.js');\n\n/**\n * Represents a command interaction.\n *\n * @extends {CommandInteraction}\n */\nclass ChatInputCommandInteraction extends CommandInteraction {\n  constructor(client, data) {\n    super(client, data);\n\n    /**\n     * The options passed to the command.\n     *\n     * @type {CommandInteractionOptionResolver}\n     */\n    this.options = new CommandInteractionOptionResolver(\n      this.client,\n      data.data.options?.map(option => this.transformOption(option, data.data.resolved)) ?? [],\n      transformResolved({ client: this.client, guild: this.guild, channel: this.channel }, data.data.resolved),\n    );\n  }\n\n  /**\n   * Returns a string representation of the command interaction.\n   * This can then be copied by a user and executed again in a new command while keeping the option order.\n   *\n   * @returns {string}\n   */\n  toString() {\n    const properties = [\n      this.commandName,\n      this.options._group,\n      this.options._subcommand,\n      ...this.options._hoistedOptions.map(option => `${option.name}:${option.value}`),\n    ];\n    return `/${properties.filter(Boolean).join(' ')}`;\n  }\n}\n\nexports.ChatInputCommandInteraction = ChatInputCommandInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ClientApplication.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Routes } = require('discord-api-types/v10');\nconst { ApplicationCommandManager } = require('../managers/ApplicationCommandManager.js');\nconst { ApplicationEmojiManager } = require('../managers/ApplicationEmojiManager.js');\nconst { EntitlementManager } = require('../managers/EntitlementManager.js');\nconst { SubscriptionManager } = require('../managers/SubscriptionManager.js');\nconst { ApplicationFlagsBitField } = require('../util/ApplicationFlagsBitField.js');\nconst { resolveImage } = require('../util/DataResolver.js');\nconst { PermissionsBitField } = require('../util/PermissionsBitField.js');\nconst { ApplicationRoleConnectionMetadata } = require('./ApplicationRoleConnectionMetadata.js');\nconst { SKU } = require('./SKU.js');\nconst { Team } = require('./Team.js');\nconst { Application } = require('./interfaces/Application.js');\n\n/**\n * @typedef {Object} ClientApplicationInstallParams\n * @property {OAuth2Scopes[]} scopes Scopes that will be set upon adding this application\n * @property {Readonly<PermissionsBitField>} permissions Permissions that will be requested for the integrated role\n */\n\n/**\n * Represents a client application.\n *\n * @extends {Application}\n */\nclass ClientApplication extends Application {\n  constructor(client, data) {\n    super(client, data);\n\n    /**\n     * The application command manager for this application\n     *\n     * @type {ApplicationCommandManager}\n     */\n    this.commands = new ApplicationCommandManager(this.client);\n\n    /**\n     * The application emoji manager for this application\n     *\n     * @type {ApplicationEmojiManager}\n     */\n    this.emojis = new ApplicationEmojiManager(this);\n\n    /**\n     * The entitlement manager for this application\n     *\n     * @type {EntitlementManager}\n     */\n    this.entitlements = new EntitlementManager(this.client);\n\n    /**\n     * The subscription manager for this application\n     *\n     * @type {SubscriptionManager}\n     */\n    this.subscriptions = new SubscriptionManager(this.client);\n  }\n\n  _patch(data) {\n    super._patch(data);\n\n    /**\n     * The tags this application has (max of 5)\n     *\n     * @type {string[]}\n     */\n    this.tags = data.tags ?? [];\n\n    if ('install_params' in data) {\n      /**\n       * Settings for this application's default in-app authorization\n       *\n       * @type {?ClientApplicationInstallParams}\n       */\n      this.installParams = {\n        scopes: data.install_params.scopes,\n        permissions: new PermissionsBitField(data.install_params.permissions).freeze(),\n      };\n    } else {\n      this.installParams ??= null;\n    }\n\n    /**\n     * OAuth2 installation parameters.\n     *\n     * @typedef {Object} IntegrationTypesConfigurationParameters\n     * @property {OAuth2Scopes[]} scopes Scopes that will be set upon adding this application\n     * @property {Readonly<PermissionsBitField>} permissions Permissions that will be requested for the integrated role\n     */\n\n    /**\n     * The application's supported installation context data.\n     *\n     * @typedef {Object} IntegrationTypesConfigurationContext\n     * @property {?IntegrationTypesConfigurationParameters} oauth2InstallParams\n     * Scopes and permissions regarding the installation context\n     */\n\n    /* eslint-disable jsdoc/valid-types */\n    /**\n     * The application's supported installation context data.\n     *\n     * @typedef {Object} IntegrationTypesConfiguration\n     * @property {IntegrationTypesConfigurationContext} [0] Scopes and permissions\n     * regarding the guild-installation context\n     * @property {IntegrationTypesConfigurationContext} [1] Scopes and permissions\n     * regarding the user-installation context\n     */\n    /* eslint-enable jsdoc/valid-types */\n\n    if ('integration_types_config' in data) {\n      /**\n       * Default scopes and permissions for each supported installation context.\n       * The keys are stringified variants of {@link ApplicationIntegrationType}.\n       *\n       * @type {?IntegrationTypesConfiguration}\n       */\n      this.integrationTypesConfig = Object.fromEntries(\n        Object.entries(data.integration_types_config).map(([key, config]) => {\n          let oauth2InstallParams = null;\n          if (config.oauth2_install_params) {\n            oauth2InstallParams = {\n              scopes: config.oauth2_install_params.scopes,\n              permissions: new PermissionsBitField(config.oauth2_install_params.permissions).freeze(),\n            };\n          }\n\n          const context = {\n            oauth2InstallParams,\n          };\n\n          return [key, context];\n        }),\n      );\n    } else {\n      this.integrationTypesConfig ??= null;\n    }\n\n    if ('custom_install_url' in data) {\n      /**\n       * This application's custom installation URL\n       *\n       * @type {?string}\n       */\n      this.customInstallURL = data.custom_install_url;\n    } else {\n      this.customInstallURL = null;\n    }\n\n    if ('flags' in data) {\n      /**\n       * The flags this application has\n       *\n       * @type {ApplicationFlagsBitField}\n       */\n      this.flags = new ApplicationFlagsBitField(data.flags).freeze();\n    }\n\n    if ('approximate_guild_count' in data) {\n      /**\n       * An approximate amount of guilds this application is in.\n       *\n       * @type {?number}\n       */\n      this.approximateGuildCount = data.approximate_guild_count;\n    } else {\n      this.approximateGuildCount ??= null;\n    }\n\n    if ('approximate_user_install_count' in data) {\n      /**\n       * An approximate amount of users that have installed this application.\n       *\n       * @type {?number}\n       */\n      this.approximateUserInstallCount = data.approximate_user_install_count;\n    } else {\n      this.approximateUserInstallCount ??= null;\n    }\n\n    if ('approximate_user_authorization_count' in data) {\n      /**\n       * An approximate amount of users that have OAuth2 authorizations for this application.\n       *\n       * @type {?number}\n       */\n      this.approximateUserAuthorizationCount = data.approximate_user_authorization_count;\n    } else {\n      this.approximateUserAuthorizationCount ??= null;\n    }\n\n    if ('guild_id' in data) {\n      /**\n       * The id of the guild associated with this application.\n       *\n       * @type {?Snowflake}\n       */\n      this.guildId = data.guild_id;\n    } else {\n      this.guildId ??= null;\n    }\n\n    if ('bot_require_code_grant' in data) {\n      /**\n       * If this application's bot requires a code grant when using the OAuth2 flow\n       *\n       * @type {?boolean}\n       */\n      this.botRequireCodeGrant = data.bot_require_code_grant;\n    } else {\n      this.botRequireCodeGrant ??= null;\n    }\n\n    if ('bot' in data) {\n      /**\n       * The bot associated with this application.\n       *\n       * @type {?User}\n       */\n      this.bot = this.client.users._add(data.bot);\n    } else {\n      this.bot ??= null;\n    }\n\n    if ('bot_public' in data) {\n      /**\n       * If this application's bot is public\n       *\n       * @type {?boolean}\n       */\n      this.botPublic = data.bot_public;\n    } else {\n      this.botPublic ??= null;\n    }\n\n    if ('interactions_endpoint_url' in data) {\n      /**\n       * This application's interaction endpoint URL.\n       *\n       * @type {?string}\n       */\n      this.interactionsEndpointURL = data.interactions_endpoint_url;\n    } else {\n      this.interactionsEndpointURL ??= null;\n    }\n\n    if ('role_connections_verification_url' in data) {\n      /**\n       * This application's role connection verification entry point URL\n       *\n       * @type {?string}\n       */\n      this.roleConnectionsVerificationURL = data.role_connections_verification_url;\n    } else {\n      this.roleConnectionsVerificationURL ??= null;\n    }\n\n    if ('event_webhooks_url' in data) {\n      /**\n       * This application's URL to receive event webhooks\n       *\n       * @type {?string}\n       */\n      this.eventWebhooksURL = data.event_webhooks_url;\n    } else {\n      this.eventWebhooksURL ??= null;\n    }\n\n    if ('event_webhooks_status' in data) {\n      /**\n       * This application's event webhooks status\n       *\n       * @type {?ApplicationWebhookEventStatus}\n       */\n      this.eventWebhooksStatus = data.event_webhooks_status;\n    } else {\n      this.eventWebhooksStatus ??= null;\n    }\n\n    if ('event_webhooks_types' in data) {\n      /**\n       * List of event webhooks types this application subscribes to\n       *\n       * @type {?ApplicationWebhookEventType[]}\n       */\n      this.eventWebhooksTypes = data.event_webhooks_types;\n    } else {\n      this.eventWebhooksTypes ??= null;\n    }\n\n    /**\n     * The owner of this OAuth application\n     *\n     * @type {?(User|Team)}\n     */\n    this.owner = data.team\n      ? new Team(this.client, data.team)\n      : data.owner\n        ? this.client.users._add(data.owner)\n        : (this.owner ?? null);\n  }\n\n  /**\n   * The guild associated with this application.\n   *\n   * @type {?Guild}\n   * @readonly\n   */\n  get guild() {\n    return this.client.guilds.cache.get(this.guildId) ?? null;\n  }\n\n  /**\n   * Whether this application is partial\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get partial() {\n    return !this.name;\n  }\n\n  /**\n   * Options used for editing an application.\n   *\n   * @typedef {Object} ClientApplicationEditOptions\n   * @property {string} [customInstallURL] The application's custom installation URL\n   * @property {string} [description] The application's description\n   * @property {string} [roleConnectionsVerificationURL] The application's role connection verification URL\n   * @property {ClientApplicationInstallParams} [installParams]\n   * Settings for the application's default in-app authorization\n   * @property {ApplicationFlagsResolvable} [flags] The flags for the application\n   * @property {?(BufferResolvable|Base64Resolvable)} [icon] The application's icon\n   * @property {?(BufferResolvable|Base64Resolvable)} [coverImage] The application's cover image\n   * @property {string} [interactionsEndpointURL] The application's interaction endpoint URL\n   * @property {string} [eventWebhooksURL] The application's event webhooks URL\n   * @property {ApplicationWebhookEventStatus.Enabled|ApplicationWebhookEventStatus.Disabled} [eventWebhooksStatus]\n   * The application's event webhooks status.\n   * @property {ApplicationWebhookEventType[]} [eventWebhooksTypes] The application's event webhooks types\n   * @property {string[]} [tags] The application's tags\n   */\n\n  /**\n   * Edits this application.\n   *\n   * @param {ClientApplicationEditOptions} [options] The options for editing this application\n   * @returns {Promise<ClientApplication>}\n   */\n  async edit({\n    customInstallURL,\n    description,\n    roleConnectionsVerificationURL,\n    installParams,\n    flags,\n    icon,\n    coverImage,\n    interactionsEndpointURL,\n    eventWebhooksURL,\n    eventWebhooksStatus,\n    eventWebhooksTypes,\n    tags,\n  } = {}) {\n    const data = await this.client.rest.patch(Routes.currentApplication(), {\n      body: {\n        custom_install_url: customInstallURL,\n        description,\n        role_connections_verification_url: roleConnectionsVerificationURL,\n        install_params: installParams,\n        flags: flags === undefined ? undefined : ApplicationFlagsBitField.resolve(flags),\n        icon: icon && (await resolveImage(icon)),\n        cover_image: coverImage && (await resolveImage(coverImage)),\n        interactions_endpoint_url: interactionsEndpointURL,\n        event_webhooks_url: eventWebhooksURL,\n        event_webhooks_status: eventWebhooksStatus,\n        event_webhooks_types: eventWebhooksTypes,\n        tags,\n      },\n    });\n\n    this._patch(data);\n    return this;\n  }\n\n  /**\n   * Obtains this application from Discord.\n   *\n   * @returns {Promise<ClientApplication>}\n   */\n  async fetch() {\n    const data = await this.client.rest.get(Routes.currentApplication());\n    this._patch(data);\n    return this;\n  }\n\n  /**\n   * Gets this application's role connection metadata records\n   *\n   * @returns {Promise<ApplicationRoleConnectionMetadata[]>}\n   */\n  async fetchRoleConnectionMetadataRecords() {\n    const metadata = await this.client.rest.get(Routes.applicationRoleConnectionMetadata(this.client.user.id));\n    return metadata.map(data => new ApplicationRoleConnectionMetadata(data));\n  }\n\n  /**\n   * Data for creating or editing an application role connection metadata.\n   *\n   * @typedef {Object} ApplicationRoleConnectionMetadataEditOptions\n   * @property {string} name The name of the metadata field\n   * @property {?LocalizationMap} [nameLocalizations] The name localizations for the metadata field\n   * @property {string} description The description of the metadata field\n   * @property {?LocalizationMap} [descriptionLocalizations] The description localizations for the metadata field\n   * @property {string} key The dictionary key of the metadata field\n   * @property {ApplicationRoleConnectionMetadataType} type The type of the metadata field\n   */\n\n  /**\n   * Updates this application's role connection metadata records\n   *\n   * @param {ApplicationRoleConnectionMetadataEditOptions[]} records The new role connection metadata records\n   * @returns {Promise<ApplicationRoleConnectionMetadata[]>}\n   */\n  async editRoleConnectionMetadataRecords(records) {\n    const newRecords = await this.client.rest.put(Routes.applicationRoleConnectionMetadata(this.client.user.id), {\n      body: records.map(record => ({\n        type: record.type,\n        key: record.key,\n        name: record.name,\n        name_localizations: record.nameLocalizations,\n        description: record.description,\n        description_localizations: record.descriptionLocalizations,\n      })),\n    });\n\n    return newRecords.map(data => new ApplicationRoleConnectionMetadata(data));\n  }\n\n  /**\n   * Gets this application's SKUs\n   *\n   * @returns {Promise<Collection<Snowflake, SKU>>}\n   */\n  async fetchSKUs() {\n    const skus = await this.client.rest.get(Routes.skus(this.id));\n    return skus.reduce((coll, sku) => coll.set(sku.id, new SKU(this.client, sku)), new Collection());\n  }\n}\n\nexports.ClientApplication = ClientApplication;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ClientPresence.js",
    "content": "/* eslint-disable id-length */\n'use strict';\n\nconst { GatewayOpcodes, ActivityType } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { Presence } = require('./Presence.js');\n\n/**\n * Represents the client's presence.\n *\n * @extends {Presence}\n */\nclass ClientPresence extends Presence {\n  constructor(client, data = {}) {\n    super(client, Object.assign(data, { status: data.status ?? 'online', user: { id: null } }));\n  }\n\n  /**\n   * Sets the client's presence\n   *\n   * @param {PresenceData} presence The data to set the presence to\n   * @returns {Promise<ClientPresence>}\n   */\n  async set(presence) {\n    const packet = this._parse(presence);\n    this._patch(packet);\n    if (presence.shardId === undefined) {\n      await this.client._broadcast({ op: GatewayOpcodes.PresenceUpdate, d: packet });\n    } else if (Array.isArray(presence.shardId)) {\n      await Promise.all(\n        presence.shardId.map(shardId => this.client.ws.send(shardId, { op: GatewayOpcodes.PresenceUpdate, d: packet })),\n      );\n    } else {\n      await this.client.ws.send(presence.shardId, { op: GatewayOpcodes.PresenceUpdate, d: packet });\n    }\n\n    return this;\n  }\n\n  /**\n   * Parses presence data into a packet ready to be sent to Discord\n   *\n   * @param {PresenceData} presence The data to parse\n   * @returns {GatewayPresenceUpdateData}\n   * @private\n   */\n  _parse({ status, since, afk, activities }) {\n    const data = {\n      activities: [],\n      afk: typeof afk === 'boolean' ? afk : false,\n      since: typeof since === 'number' && !Number.isNaN(since) ? since : null,\n      status: status ?? this.status,\n    };\n    if (activities?.length) {\n      for (const [i, activity] of activities.entries()) {\n        if (typeof activity.name !== 'string') {\n          throw new DiscordjsTypeError(ErrorCodes.InvalidType, `activities[${i}].name`, 'string');\n        }\n\n        activity.type ??= ActivityType.Playing;\n\n        if (activity.type === ActivityType.Custom && !activity.state) {\n          activity.state = activity.name;\n          activity.name = 'Custom Status';\n        }\n\n        data.activities.push({\n          type: activity.type,\n          name: activity.name,\n          state: activity.state,\n          url: activity.url,\n        });\n      }\n    } else if (!activities && (status || afk || since) && this.activities.length) {\n      data.activities.push(\n        ...this.activities.map(activity => ({\n          name: activity.name,\n          state: activity.state ?? undefined,\n          type: activity.type,\n          url: activity.url ?? undefined,\n        })),\n      );\n    }\n\n    return data;\n  }\n}\n\nexports.ClientPresence = ClientPresence;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ClientUser.js",
    "content": "'use strict';\n\nconst { Routes } = require('discord-api-types/v10');\nconst { resolveImage } = require('../util/DataResolver.js');\nconst { User } = require('./User.js');\n\n/**\n * Represents the logged in client's Discord user.\n *\n * @extends {User}\n */\nclass ClientUser extends User {\n  _patch(data) {\n    super._patch(data);\n\n    if ('verified' in data) {\n      /**\n       * Whether or not this account has been verified\n       *\n       * @type {boolean}\n       */\n      this.verified = data.verified;\n    }\n\n    if ('mfa_enabled' in data) {\n      /**\n       * If the bot's {@link ClientApplication#owner Owner} has MFA enabled on their account\n       *\n       * @type {?boolean}\n       */\n      this.mfaEnabled = typeof data.mfa_enabled === 'boolean' ? data.mfa_enabled : null;\n    } else {\n      this.mfaEnabled ??= null;\n    }\n\n    if ('token' in data) this.client.token = data.token;\n  }\n\n  /**\n   * Represents the client user's presence\n   *\n   * @type {ClientPresence}\n   * @readonly\n   */\n  get presence() {\n    return this.client.presence;\n  }\n\n  /**\n   * Data used to edit the logged in client\n   *\n   * @typedef {Object} ClientUserEditOptions\n   * @property {string} [username] The new username\n   * @property {?(BufferResolvable|Base64Resolvable)} [avatar] The new avatar\n   * @property {?(BufferResolvable|Base64Resolvable)} [banner] The new banner\n   */\n\n  /**\n   * Edits the logged in client.\n   *\n   * @param {ClientUserEditOptions} options The options to provide\n   * @returns {Promise<ClientUser>}\n   */\n  async edit({ username, avatar, banner }) {\n    const data = await this.client.rest.patch(Routes.user(), {\n      body: {\n        username,\n        avatar: avatar && (await resolveImage(avatar)),\n        banner: banner && (await resolveImage(banner)),\n      },\n    });\n\n    const { updated } = this.client.actions.UserUpdate.handle(data);\n    return updated ?? this;\n  }\n\n  /**\n   * Sets the username of the logged in client.\n   * <info>Changing usernames in Discord is heavily rate limited, with only 2 requests\n   * every hour. Use this sparingly!</info>\n   *\n   * @param {string} username The new username\n   * @returns {Promise<ClientUser>}\n   * @example\n   * // Set username\n   * client.user.setUsername('discordjs')\n   *   .then(user => console.log(`My new username is ${user.username}`))\n   *   .catch(console.error);\n   */\n  async setUsername(username) {\n    return this.edit({ username });\n  }\n\n  /**\n   * Sets the avatar of the logged in client.\n   *\n   * @param {?(BufferResolvable|Base64Resolvable)} avatar The new avatar\n   * @returns {Promise<ClientUser>}\n   * @example\n   * // Set avatar\n   * client.user.setAvatar('./avatar.png')\n   *   .then(user => console.log(`New avatar set!`))\n   *   .catch(console.error);\n   */\n  async setAvatar(avatar) {\n    return this.edit({ avatar });\n  }\n\n  /**\n   * Sets the banner of the logged in client.\n   *\n   * @param {?(BufferResolvable|Base64Resolvable)} banner The new banner\n   * @returns {Promise<ClientUser>}\n   * @example\n   * // Set banner\n   * client.user.setBanner('./banner.png')\n   *   .then(user => console.log(`New banner set!`))\n   *   .catch(console.error);\n   */\n  async setBanner(banner) {\n    return this.edit({ banner });\n  }\n\n  /**\n   * Options for setting activities\n   *\n   * @typedef {Object} ActivitiesOptions\n   * @property {string} name Name of the activity\n   * @property {string} [state] State of the activity\n   * @property {ActivityType} [type] Type of the activity\n   * @property {string} [url] Twitch / YouTube stream URL\n   */\n\n  /**\n   * Data resembling a raw Discord presence.\n   *\n   * @typedef {Object} PresenceData\n   * @property {PresenceStatusData} [status] Status of the user\n   * @property {boolean} [afk] Whether the user is AFK\n   * @property {ActivitiesOptions[]} [activities] Activity the user is playing\n   * @property {number|number[]} [shardId] Shard id(s) to have the activity set on\n   */\n\n  /**\n   * Sets the full presence of the client user.\n   *\n   * @param {PresenceData} data Data for the presence\n   * @returns {Promise<ClientPresence>}\n   * @example\n   * // Set the client user's presence\n   * client.user.setPresence({ activities: [{ name: 'with discord.js' }], status: 'idle' });\n   */\n  async setPresence(data) {\n    return this.client.presence.set(data);\n  }\n\n  /**\n   * A user's status. Must be one of:\n   * - `online`\n   * - `idle`\n   * - `invisible`\n   * - `dnd` (do not disturb)\n   *\n   * @typedef {string} PresenceStatusData\n   */\n\n  /**\n   * Sets the status of the client user.\n   *\n   * @param {PresenceStatusData} status Status to change to\n   * @param {number|number[]} [shardId] Shard id(s) to have the activity set on\n   * @returns {Promise<ClientPresence>}\n   * @example\n   * // Set the client user's status\n   * client.user.setStatus('idle');\n   */\n  async setStatus(status, shardId) {\n    return this.setPresence({ status, shardId });\n  }\n\n  /**\n   * Options for setting an activity.\n   *\n   * @typedef {Object} ActivityOptions\n   * @property {string} name Name of the activity\n   * @property {string} [state] State of the activity\n   * @property {string} [url] Twitch / YouTube stream URL\n   * @property {ActivityType} [type] Type of the activity\n   * @property {number|number[]} [shardId] Shard Id(s) to have the activity set on\n   */\n\n  /**\n   * Sets the activity the client user is playing.\n   *\n   * @param {string|ActivityOptions} name Activity being played, or options for setting the activity\n   * @param {ActivityOptions} [options] Options for setting the activity\n   * @returns {Promise<ClientPresence>}\n   * @example\n   * // Set the client user's activity\n   * client.user.setActivity('discord.js', { type: ActivityType.Watching });\n   */\n  async setActivity(name, options = {}) {\n    if (!name) return this.setPresence({ activities: [], shardId: options.shardId });\n\n    const activity = { ...options, ...(typeof name === 'object' ? name : { name }) };\n    return this.setPresence({ activities: [activity], shardId: activity.shardId });\n  }\n\n  /**\n   * Sets/removes the AFK flag for the client user.\n   *\n   * @param {boolean} [afk=true] Whether or not the user is AFK\n   * @param {number|number[]} [shardId] Shard Id(s) to have the AFK flag set on\n   * @returns {Promise<ClientPresence>}\n   */\n  async setAFK(afk = true, shardId = undefined) {\n    return this.setPresence({ afk, shardId });\n  }\n}\n\nexports.ClientUser = ClientUser;\n"
  },
  {
    "path": "packages/discord.js/src/structures/CommandInteraction.js",
    "content": "'use strict';\n\nconst { Attachment } = require('./Attachment.js');\nconst { BaseInteraction } = require('./BaseInteraction.js');\nconst { InteractionWebhook } = require('./InteractionWebhook.js');\nconst { InteractionResponses } = require('./interfaces/InteractionResponses.js');\n\n/**\n * Represents a command interaction.\n *\n * @extends {BaseInteraction}\n * @implements {InteractionResponses}\n * @abstract\n */\nclass CommandInteraction extends BaseInteraction {\n  constructor(client, data) {\n    super(client, data);\n\n    /**\n     * The id of the channel this interaction was sent in\n     *\n     * @type {Snowflake}\n     * @name CommandInteraction#channelId\n     */\n\n    /**\n     * The invoked application command's id\n     *\n     * @type {Snowflake}\n     */\n    this.commandId = data.data.id;\n\n    /**\n     * The invoked application command's name\n     *\n     * @type {string}\n     */\n    this.commandName = data.data.name;\n\n    /**\n     * The invoked application command's type\n     *\n     * @type {ApplicationCommandType}\n     */\n    this.commandType = data.data.type;\n\n    /**\n     * The id of the guild the invoked application command is registered to\n     *\n     * @type {?Snowflake}\n     */\n    this.commandGuildId = data.data.guild_id ?? null;\n\n    /**\n     * Whether the reply to this interaction has been deferred\n     *\n     * @type {boolean}\n     */\n    this.deferred = false;\n\n    /**\n     * Whether this interaction has already been replied to\n     *\n     * @type {boolean}\n     */\n    this.replied = false;\n\n    /**\n     * Whether the reply to this interaction is ephemeral\n     *\n     * @type {?boolean}\n     */\n    this.ephemeral = null;\n\n    /**\n     * An associated interaction webhook, can be used to further interact with this interaction\n     *\n     * @type {InteractionWebhook}\n     */\n    this.webhook = new InteractionWebhook(this.client, this.applicationId, this.token);\n  }\n\n  /**\n   * The invoked application command, if it was fetched before\n   *\n   * @type {?ApplicationCommand}\n   */\n  get command() {\n    const id = this.commandId;\n    return this.guild?.commands.cache.get(id) ?? this.client.application.commands.cache.get(id) ?? null;\n  }\n\n  /**\n   * @typedef {Object} BaseInteractionResolvedData\n   * @property {Collection<Snowflake, User>} [users] The resolved users\n   * @property {Collection<Snowflake, GuildMember|APIGuildMember>} [members] The resolved guild members\n   * @property {Collection<Snowflake, Role|APIRole>} [roles] The resolved roles\n   * @property {Collection<Snowflake, BaseChannel|APIChannel>} [channels] The resolved channels\n   * @property {Collection<Snowflake, Attachment>} [attachments] The resolved attachments\n   */\n\n  /**\n   * Represents the resolved data of a received command interaction.\n   *\n   * @typedef {BaseInteractionResolvedData} CommandInteractionResolvedData\n   * @property {Collection<Snowflake, Message|APIMessage>} [messages] The resolved messages\n   */\n\n  /**\n   * Represents an option of a received command interaction.\n   *\n   * @typedef {Object} CommandInteractionOption\n   * @property {string} name The name of the option\n   * @property {ApplicationCommandOptionType} type The type of the option\n   * @property {boolean} [autocomplete] Whether the autocomplete interaction is enabled for a\n   * {@link ApplicationCommandOptionType.String}, {@link ApplicationCommandOptionType.Integer} or\n   * {@link ApplicationCommandOptionType.Number} option\n   * @property {string|number|boolean} [value] The value of the option\n   * @property {CommandInteractionOption[]} [options] Additional options if this option is a\n   * subcommand (group)\n   * @property {User} [user] The resolved user\n   * @property {GuildMember|APIGuildMember} [member] The resolved member\n   * @property {GuildChannel|ThreadChannel|APIChannel} [channel] The resolved channel\n   * @property {Role|APIRole} [role] The resolved role\n   * @property {Attachment} [attachment] The resolved attachment\n   */\n\n  /**\n   * Transforms an option received from the API.\n   *\n   * @param {APIApplicationCommandOption} option The received option\n   * @param {APIInteractionDataResolved} resolved The resolved interaction data\n   * @returns {CommandInteractionOption}\n   * @private\n   */\n  transformOption(option, resolved) {\n    const result = {\n      name: option.name,\n      type: option.type,\n    };\n\n    if ('value' in option) result.value = option.value;\n    if ('options' in option) result.options = option.options.map(opt => this.transformOption(opt, resolved));\n\n    if (resolved) {\n      const user = resolved.users?.[option.value];\n      if (user) result.user = this.client.users._add(user);\n\n      const member = resolved.members?.[option.value];\n      if (member) result.member = this.guild?.members._add({ user, ...member }) ?? member;\n\n      const channel = resolved.channels?.[option.value];\n      if (channel) result.channel = this.client.channels._add(channel, this.guild) ?? channel;\n\n      const role = resolved.roles?.[option.value];\n      if (role) result.role = this.guild?.roles._add(role) ?? role;\n\n      const attachment = resolved.attachments?.[option.value];\n      if (attachment) result.attachment = new Attachment(attachment);\n    }\n\n    return result;\n  }\n\n  // These are here only for documentation purposes - they are implemented by InteractionResponses\n\n  deferReply() {}\n\n  reply() {}\n\n  fetchReply() {}\n\n  editReply() {}\n\n  deleteReply() {}\n\n  followUp() {}\n\n  launchActivity() {}\n\n  showModal() {}\n\n  awaitModalSubmit() {}\n}\n\nInteractionResponses.applyToClass(CommandInteraction, ['deferUpdate', 'update']);\n\nexports.CommandInteraction = CommandInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/CommandInteractionOptionResolver.js",
    "content": "'use strict';\n\nconst { ApplicationCommandOptionType } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\n\n/**\n * A resolver for command interaction options.\n */\nclass CommandInteractionOptionResolver {\n  constructor(client, options, resolved) {\n    /**\n     * The client that instantiated this.\n     *\n     * @name CommandInteractionOptionResolver#client\n     * @type {Client}\n     * @readonly\n     */\n    Object.defineProperty(this, 'client', { value: client });\n\n    /**\n     * The name of the subcommand group.\n     *\n     * @type {?string}\n     * @private\n     */\n    this._group = null;\n\n    /**\n     * The name of the subcommand.\n     *\n     * @type {?string}\n     * @private\n     */\n    this._subcommand = null;\n\n    /**\n     * The bottom-level options for the interaction.\n     * If there is a subcommand (or subcommand and group), this is the options for the subcommand.\n     *\n     * @type {CommandInteractionOption[]}\n     * @private\n     */\n    this._hoistedOptions = options;\n\n    // Hoist subcommand group if present\n    if (this._hoistedOptions[0]?.type === ApplicationCommandOptionType.SubcommandGroup) {\n      this._group = this._hoistedOptions[0].name;\n      this._hoistedOptions = this._hoistedOptions[0].options ?? [];\n    }\n\n    // Hoist subcommand if present\n    if (this._hoistedOptions[0]?.type === ApplicationCommandOptionType.Subcommand) {\n      this._subcommand = this._hoistedOptions[0].name;\n      this._hoistedOptions = this._hoistedOptions[0].options ?? [];\n    }\n\n    /**\n     * The interaction options array.\n     *\n     * @name CommandInteractionOptionResolver#data\n     * @type {ReadonlyArray<CommandInteractionOption>}\n     * @readonly\n     */\n    Object.defineProperty(this, 'data', { value: Object.freeze([...options]) });\n\n    /**\n     * The interaction resolved data\n     *\n     * @name CommandInteractionOptionResolver#resolved\n     * @type {?Readonly<CommandInteractionResolvedData>}\n     */\n    Object.defineProperty(this, 'resolved', { value: resolved ? Object.freeze(resolved) : null });\n  }\n\n  /**\n   * Gets an option by its name.\n   *\n   * @param {string} name The name of the option.\n   * @param {boolean} [required=false] Whether to throw an error if the option is not found.\n   * @returns {?CommandInteractionOption} The option, if found.\n   */\n  get(name, required = false) {\n    const option = this._hoistedOptions.find(opt => opt.name === name);\n    if (!option) {\n      if (required) {\n        throw new DiscordjsTypeError(ErrorCodes.CommandInteractionOptionNotFound, name);\n      }\n\n      return null;\n    }\n\n    return option;\n  }\n\n  /**\n   * Gets an option by name and property and checks its type.\n   *\n   * @param {string} name The name of the option.\n   * @param {ApplicationCommandOptionType[]} allowedTypes The allowed types of the option.\n   * @param {string[]} properties The properties to check for for `required`.\n   * @param {boolean} required Whether to throw an error if the option is not found.\n   * @returns {?CommandInteractionOption} The option, if found.\n   * @private\n   */\n  _getTypedOption(name, allowedTypes, properties, required) {\n    const option = this.get(name, required);\n    if (!option) {\n      return null;\n    } else if (!allowedTypes.includes(option.type)) {\n      throw new DiscordjsTypeError(ErrorCodes.CommandInteractionOptionType, name, option.type, allowedTypes.join(', '));\n    } else if (required && properties.every(prop => option[prop] === null || option[prop] === undefined)) {\n      throw new DiscordjsTypeError(ErrorCodes.CommandInteractionOptionEmpty, name, option.type);\n    }\n\n    return option;\n  }\n\n  /**\n   * Gets the selected subcommand.\n   *\n   * @param {boolean} [required=true] Whether to throw an error if there is no subcommand.\n   * @returns {?string} The name of the selected subcommand, or null if not set and not required.\n   */\n  getSubcommand(required = true) {\n    if (required && !this._subcommand) {\n      throw new DiscordjsTypeError(ErrorCodes.CommandInteractionOptionNoSubcommand);\n    }\n\n    return this._subcommand;\n  }\n\n  /**\n   * Gets the selected subcommand group.\n   *\n   * @param {boolean} [required=false] Whether to throw an error if there is no subcommand group.\n   * @returns {?string} The name of the selected subcommand group, or null if not set and not required.\n   */\n  getSubcommandGroup(required = false) {\n    if (required && !this._group) {\n      throw new DiscordjsTypeError(ErrorCodes.CommandInteractionOptionNoSubcommandGroup);\n    }\n\n    return this._group;\n  }\n\n  /**\n   * Gets a boolean option.\n   *\n   * @param {string} name The name of the option.\n   * @param {boolean} [required=false] Whether to throw an error if the option is not found.\n   * @returns {?boolean} The value of the option, or null if not set and not required.\n   */\n  getBoolean(name, required = false) {\n    const option = this._getTypedOption(name, [ApplicationCommandOptionType.Boolean], ['value'], required);\n    return option?.value ?? null;\n  }\n\n  /**\n   * Gets a channel option.\n   *\n   * @param {string} name The name of the option.\n   * @param {boolean} [required=false] Whether to throw an error if the option is not found.\n   * @param {ChannelType[]} [channelTypes=[]] The allowed types of channels. If empty, all channel types are allowed.\n   * @returns {?(GuildChannel|ThreadChannel|APIChannel)}\n   * The value of the option, or null if not set and not required.\n   */\n  getChannel(name, required = false, channelTypes = []) {\n    const option = this._getTypedOption(name, [ApplicationCommandOptionType.Channel], ['channel'], required);\n    const channel = option?.channel ?? null;\n\n    if (channel && channelTypes.length > 0 && !channelTypes.includes(channel.type)) {\n      throw new DiscordjsTypeError(\n        ErrorCodes.CommandInteractionOptionInvalidChannelType,\n        name,\n        channel.type,\n        channelTypes.join(', '),\n      );\n    }\n\n    return channel;\n  }\n\n  /**\n   * Gets a string option.\n   *\n   * @param {string} name The name of the option.\n   * @param {boolean} [required=false] Whether to throw an error if the option is not found.\n   * @returns {?string} The value of the option, or null if not set and not required.\n   */\n  getString(name, required = false) {\n    const option = this._getTypedOption(name, [ApplicationCommandOptionType.String], ['value'], required);\n    return option?.value ?? null;\n  }\n\n  /**\n   * Gets an integer option.\n   *\n   * @param {string} name The name of the option.\n   * @param {boolean} [required=false] Whether to throw an error if the option is not found.\n   * @returns {?number} The value of the option, or null if not set and not required.\n   */\n  getInteger(name, required = false) {\n    const option = this._getTypedOption(name, [ApplicationCommandOptionType.Integer], ['value'], required);\n    return option?.value ?? null;\n  }\n\n  /**\n   * Gets a number option.\n   *\n   * @param {string} name The name of the option.\n   * @param {boolean} [required=false] Whether to throw an error if the option is not found.\n   * @returns {?number} The value of the option, or null if not set and not required.\n   */\n  getNumber(name, required = false) {\n    const option = this._getTypedOption(name, [ApplicationCommandOptionType.Number], ['value'], required);\n    return option?.value ?? null;\n  }\n\n  /**\n   * Gets a user option.\n   *\n   * @param {string} name The name of the option.\n   * @param {boolean} [required=false] Whether to throw an error if the option is not found.\n   * @returns {?User} The value of the option, or null if not set and not required.\n   */\n  getUser(name, required = false) {\n    const option = this._getTypedOption(\n      name,\n      [ApplicationCommandOptionType.User, ApplicationCommandOptionType.Mentionable],\n      ['user'],\n      required,\n    );\n    return option?.user ?? null;\n  }\n\n  /**\n   * Gets a member option.\n   *\n   * @param {string} name The name of the option.\n   * @returns {?(GuildMember|APIGuildMember)}\n   * The value of the option, or null if the user is not present in the guild or the option is not set.\n   */\n  getMember(name) {\n    const option = this._getTypedOption(\n      name,\n      [ApplicationCommandOptionType.User, ApplicationCommandOptionType.Mentionable],\n      ['member'],\n      false,\n    );\n    return option?.member ?? null;\n  }\n\n  /**\n   * Gets a role option.\n   *\n   * @param {string} name The name of the option.\n   * @param {boolean} [required=false] Whether to throw an error if the option is not found.\n   * @returns {?(Role|APIRole)} The value of the option, or null if not set and not required.\n   */\n  getRole(name, required = false) {\n    const option = this._getTypedOption(\n      name,\n      [ApplicationCommandOptionType.Role, ApplicationCommandOptionType.Mentionable],\n      ['role'],\n      required,\n    );\n    return option?.role ?? null;\n  }\n\n  /**\n   * Gets an attachment option.\n   *\n   * @param {string} name The name of the option.\n   * @param {boolean} [required=false] Whether to throw an error if the option is not found.\n   * @returns {?Attachment} The value of the option, or null if not set and not required.\n   */\n  getAttachment(name, required = false) {\n    const option = this._getTypedOption(name, [ApplicationCommandOptionType.Attachment], ['attachment'], required);\n    return option?.attachment ?? null;\n  }\n\n  /**\n   * Gets a mentionable option.\n   *\n   * @param {string} name The name of the option.\n   * @param {boolean} [required=false] Whether to throw an error if the option is not found.\n   * @returns {?(User|GuildMember|APIGuildMember|Role|APIRole)}\n   * The value of the option, or null if not set and not required.\n   */\n  getMentionable(name, required = false) {\n    const option = this._getTypedOption(\n      name,\n      [ApplicationCommandOptionType.Mentionable],\n      ['user', 'member', 'role'],\n      required,\n    );\n    return option?.member ?? option?.user ?? option?.role ?? null;\n  }\n\n  /**\n   * Gets a message option.\n   *\n   * @param {string} name The name of the option.\n   * @param {boolean} [required=false] Whether to throw an error if the option is not found.\n   * @returns {?Message}\n   * The value of the option, or null if not set and not required.\n   */\n  getMessage(name, required = false) {\n    const option = this._getTypedOption(name, ['_MESSAGE'], ['message'], required);\n    return option?.message ?? null;\n  }\n\n  /**\n   * The full autocomplete option object.\n   *\n   * @typedef {Object} AutocompleteFocusedOption\n   * @property {string} name The name of the option\n   * @property {ApplicationCommandOptionType} type The type of the application command option\n   * @property {string} value The value of the option\n   * @property {boolean} focused Whether this option is currently in focus for autocomplete\n   */\n\n  /**\n   * Gets the focused option.\n   *\n   * @returns {AutocompleteFocusedOption}\n   * The whole object of the option that is focused\n   */\n  getFocused() {\n    const focusedOption = this._hoistedOptions.find(option => option.focused);\n    if (!focusedOption) throw new DiscordjsTypeError(ErrorCodes.AutocompleteInteractionOptionNoFocusedOption);\n    return focusedOption;\n  }\n}\n\nexports.CommandInteractionOptionResolver = CommandInteractionOptionResolver;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Component.js",
    "content": "'use strict';\n\nconst isEqual = require('fast-deep-equal');\n\n/**\n * Represents a component\n */\nclass Component {\n  constructor(data) {\n    /**\n     * The API data associated with this component\n     *\n     * @type {APIMessageComponent}\n     */\n    this.data = data;\n  }\n\n  /**\n   * The id of this component\n   *\n   * @type {number}\n   * @readonly\n   */\n  get id() {\n    return this.data.id;\n  }\n\n  /**\n   * The type of the component\n   *\n   * @type {ComponentType}\n   * @readonly\n   */\n  get type() {\n    return this.data.type;\n  }\n\n  /**\n   * Whether or not the given components are equal\n   *\n   * @param {Component|APIMessageComponent} other The component to compare against\n   * @returns {boolean}\n   */\n  equals(other) {\n    if (other instanceof Component) {\n      return isEqual(other.data, this.data);\n    }\n\n    return isEqual(other, this.data);\n  }\n\n  /**\n   * Returns the API-compatible JSON for this component\n   *\n   * @returns {APIMessageComponent}\n   */\n  toJSON() {\n    return { ...this.data };\n  }\n}\n\nexports.Component = Component;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ContainerComponent.js",
    "content": "'use strict';\n\nconst { createComponent } = require('../util/Components.js');\nconst { Component } = require('./Component.js');\n\n/**\n * Represents a container component\n *\n * @extends {Component}\n */\nclass ContainerComponent extends Component {\n  constructor({ components, ...data }) {\n    super(data);\n\n    /**\n     * The components in this container\n     *\n     * @type {Component[]}\n     * @readonly\n     */\n    this.components = components.map(component => createComponent(component));\n  }\n\n  /**\n   * The accent color of this container\n   *\n   * @type {?number}\n   * @readonly\n   */\n  get accentColor() {\n    return this.data.accent_color ?? null;\n  }\n\n  /**\n   * The hex accent color of this container\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get hexAccentColor() {\n    return typeof this.data.accent_color === 'number'\n      ? `#${this.data.accent_color.toString(16).padStart(6, '0')}`\n      : (this.data.accent_color ?? null);\n  }\n\n  /**\n   * Whether this container is spoilered\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get spoiler() {\n    return this.data.spoiler ?? false;\n  }\n\n  /**\n   * Returns the API-compatible JSON for this component\n   *\n   * @returns {APIContainerComponent}\n   */\n  toJSON() {\n    return { ...this.data, components: this.components.map(component => component.toJSON()) };\n  }\n}\n\nexports.ContainerComponent = ContainerComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ContextMenuCommandInteraction.js",
    "content": "'use strict';\n\nconst { lazy } = require('@discordjs/util');\nconst { ApplicationCommandOptionType } = require('discord-api-types/v10');\nconst { transformResolved } = require('../util/Util.js');\nconst { CommandInteraction } = require('./CommandInteraction.js');\nconst { CommandInteractionOptionResolver } = require('./CommandInteractionOptionResolver.js');\n\nconst getMessage = lazy(() => require('./Message.js').Message);\n\n/**\n * Represents a context menu interaction.\n *\n * @extends {CommandInteraction}\n */\nclass ContextMenuCommandInteraction extends CommandInteraction {\n  constructor(client, data) {\n    super(client, data);\n    /**\n     * The target of the interaction, parsed into options\n     *\n     * @type {CommandInteractionOptionResolver}\n     */\n    this.options = new CommandInteractionOptionResolver(\n      this.client,\n      this.resolveContextMenuOptions(data.data),\n      transformResolved({ client: this.client, guild: this.guild, channel: this.channel }, data.data.resolved),\n    );\n\n    /**\n     * The id of the target of this interaction\n     *\n     * @type {Snowflake}\n     */\n    this.targetId = data.data.target_id;\n  }\n\n  /**\n   * Resolves and transforms options received from the API for a context menu interaction.\n   *\n   * @param {APIApplicationCommandInteractionData} data The interaction data\n   * @returns {CommandInteractionOption[]}\n   * @private\n   */\n  resolveContextMenuOptions({ target_id, resolved }) {\n    const result = [];\n\n    if (resolved.users?.[target_id]) {\n      result.push(\n        this.transformOption({ name: 'user', type: ApplicationCommandOptionType.User, value: target_id }, resolved),\n      );\n    }\n\n    if (resolved.messages?.[target_id]) {\n      result.push({\n        name: 'message',\n        type: '_MESSAGE',\n        value: target_id,\n        message:\n          this.channel?.messages._add(resolved.messages[target_id]) ??\n          new (getMessage())(this.client, resolved.messages[target_id]),\n      });\n    }\n\n    return result;\n  }\n}\n\nexports.ContextMenuCommandInteraction = ContextMenuCommandInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/DMChannel.js",
    "content": "'use strict';\n\nconst { userMention } = require('@discordjs/formatters');\nconst { ChannelType } = require('discord-api-types/v10');\nconst { DMMessageManager } = require('../managers/DMMessageManager.js');\nconst { Partials } = require('../util/Partials.js');\nconst { BaseChannel } = require('./BaseChannel.js');\nconst { TextBasedChannel } = require('./interfaces/TextBasedChannel.js');\n\n/**\n * Represents a direct message channel between two users.\n *\n * @extends {BaseChannel}\n * @implements {TextBasedChannel}\n */\nclass DMChannel extends BaseChannel {\n  constructor(client, data) {\n    super(client, data);\n\n    // Override the channel type so partials have a known type\n    this.type = ChannelType.DM;\n\n    /**\n     * A manager of the messages belonging to this channel\n     *\n     * @type {DMMessageManager}\n     */\n    this.messages = new DMMessageManager(this);\n  }\n\n  _patch(data) {\n    super._patch(data);\n\n    if (data.recipients) {\n      const recipient = data.recipients[0];\n\n      /**\n       * The recipient's id\n       *\n       * @type {Snowflake}\n       */\n      this.recipientId = recipient.id;\n\n      if ('username' in recipient || this.client.options.partials.includes(Partials.User)) {\n        this.client.users._add(recipient);\n      }\n    }\n\n    if ('last_message_id' in data) {\n      /**\n       * The channel's last message id, if one was sent\n       *\n       * @type {?Snowflake}\n       */\n      this.lastMessageId = data.last_message_id;\n    }\n\n    if ('last_pin_timestamp' in data) {\n      /**\n       * The timestamp when the last pinned message was pinned, if there was one\n       *\n       * @type {?number}\n       */\n      this.lastPinTimestamp = Date.parse(data.last_pin_timestamp);\n    } else {\n      this.lastPinTimestamp ??= null;\n    }\n  }\n\n  /**\n   * Whether this DMChannel is a partial\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get partial() {\n    return this.lastMessageId === undefined;\n  }\n\n  /**\n   * The recipient on the other end of the DM\n   *\n   * @type {?User}\n   * @readonly\n   */\n  get recipient() {\n    return this.client.users.resolve(this.recipientId);\n  }\n\n  /**\n   * Fetch this DMChannel.\n   *\n   * @param {boolean} [force=true] Whether to skip the cache check and request the API\n   * @returns {Promise<DMChannel>}\n   */\n  async fetch(force = true) {\n    return this.client.users.createDM(this.recipientId, { force });\n  }\n\n  /**\n   * When concatenated with a string, this automatically returns the recipient's mention instead of the\n   * DMChannel object.\n   *\n   * @returns {string}\n   * @example\n   * // Logs: Hello from <@123456789012345678>!\n   * console.log(`Hello from ${channel}!`);\n   */\n  toString() {\n    return userMention(this.recipientId);\n  }\n\n  // These are here only for documentation purposes - they are implemented by TextBasedChannel\n\n  /* eslint-disable getter-return */\n  get lastMessage() {}\n\n  get lastPinAt() {}\n\n  send() {}\n\n  sendTyping() {}\n\n  createMessageCollector() {}\n\n  awaitMessages() {}\n\n  createMessageComponentCollector() {}\n\n  awaitMessageComponent() {}\n  // Doesn't work on DM channels; bulkDelete() {}\n  // Doesn't work on DM channels; fetchWebhooks() {}\n  // Doesn't work on DM channels; createWebhook() {}\n  // Doesn't work on DM channels; setRateLimitPerUser() {}\n  // Doesn't work on DM channels; setNSFW() {}\n}\n\nTextBasedChannel.applyToClass(DMChannel, [\n  'bulkDelete',\n  'fetchWebhooks',\n  'createWebhook',\n  'setRateLimitPerUser',\n  'setNSFW',\n]);\n\nexports.DMChannel = DMChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/DirectoryChannel.js",
    "content": "'use strict';\n\nconst { BaseChannel } = require('./BaseChannel.js');\n\n/**\n * Represents a channel that displays a directory of guilds.\n *\n * @extends {BaseChannel}\n */\nclass DirectoryChannel extends BaseChannel {\n  constructor(guild, data, client) {\n    super(client, data);\n\n    /**\n     * The guild the channel is in\n     *\n     * @type {InviteGuild}\n     */\n    this.guild = guild;\n\n    /**\n     * The id of the guild the channel is in\n     *\n     * @type {Snowflake}\n     */\n    this.guildId = guild.id;\n  }\n\n  _patch(data) {\n    super._patch(data);\n    /**\n     * The channel's name\n     *\n     * @type {string}\n     */\n    this.name = data.name;\n  }\n}\n\nexports.DirectoryChannel = DirectoryChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Embed.js",
    "content": "'use strict';\n\nconst { embedLength } = require('@discordjs/util');\nconst isEqual = require('fast-deep-equal');\n\n/**\n * Represents an embed.\n */\nclass Embed {\n  constructor(data) {\n    /**\n     * The API embed data.\n     *\n     * @type {APIEmbed}\n     * @readonly\n     */\n    this.data = { ...data };\n  }\n\n  /**\n   * An array of fields of this embed.\n   *\n   * @type {Array<APIEmbedField>}\n   * @readonly\n   */\n  get fields() {\n    return this.data.fields ?? [];\n  }\n\n  /**\n   * The title of this embed.\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get title() {\n    return this.data.title ?? null;\n  }\n\n  /**\n   * The description of this embed.\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get description() {\n    return this.data.description ?? null;\n  }\n\n  /**\n   * The URL of this embed.\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get url() {\n    return this.data.url ?? null;\n  }\n\n  /**\n   * The color of this embed.\n   *\n   * @type {?number}\n   * @readonly\n   */\n  get color() {\n    return this.data.color ?? null;\n  }\n\n  /**\n   * The timestamp of this embed. This is in an ISO 8601 format.\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get timestamp() {\n    return this.data.timestamp ?? null;\n  }\n\n  /**\n   * @typedef {Object} EmbedAssetData\n   * @property {?string} url The URL of the image\n   * @property {?string} proxyURL The proxy URL of the image\n   * @property {?number} height The height of the image\n   * @property {?number} width The width of the image\n   */\n\n  /**\n   * The thumbnail of this embed.\n   *\n   * @type {?EmbedAssetData}\n   * @readonly\n   */\n  get thumbnail() {\n    if (!this.data.thumbnail) return null;\n    return {\n      url: this.data.thumbnail.url,\n      proxyURL: this.data.thumbnail.proxy_url,\n      height: this.data.thumbnail.height,\n      width: this.data.thumbnail.width,\n    };\n  }\n\n  /**\n   * The image of this embed.\n   *\n   * @type {?EmbedAssetData}\n   * @readonly\n   */\n  get image() {\n    if (!this.data.image) return null;\n    return {\n      url: this.data.image.url,\n      proxyURL: this.data.image.proxy_url,\n      height: this.data.image.height,\n      width: this.data.image.width,\n    };\n  }\n\n  /**\n   * The video of this embed.\n   *\n   * @type {?EmbedAssetData}\n   * @readonly\n   */\n  get video() {\n    if (!this.data.video) return null;\n    return {\n      url: this.data.video.url,\n      proxyURL: this.data.video.proxy_url,\n      height: this.data.video.height,\n      width: this.data.video.width,\n    };\n  }\n\n  /**\n   * @typedef {Object} EmbedAuthorData\n   * @property {string} name The name of the author\n   * @property {?string} url The URL of the author\n   * @property {?string} iconURL The icon URL of the author\n   * @property {?string} proxyIconURL The proxy icon URL of the author\n   */\n\n  /**\n   * The author of this embed.\n   *\n   * @type {?EmbedAuthorData}\n   * @readonly\n   */\n  get author() {\n    if (!this.data.author) return null;\n    return {\n      name: this.data.author.name,\n      url: this.data.author.url,\n      iconURL: this.data.author.icon_url,\n      proxyIconURL: this.data.author.proxy_icon_url,\n    };\n  }\n\n  /**\n   * The provider of this embed.\n   *\n   * @type {?APIEmbedProvider}\n   * @readonly\n   */\n  get provider() {\n    return this.data.provider ?? null;\n  }\n\n  /**\n   * @typedef {Object} EmbedFooterData\n   * @property {string} text The text of the footer\n   * @property {?string} iconURL The URL of the icon\n   * @property {?string} proxyIconURL The proxy URL of the icon\n   */\n\n  /**\n   * The footer of this embed.\n   *\n   * @type {?EmbedFooterData}\n   * @readonly\n   */\n  get footer() {\n    if (!this.data.footer) return null;\n    return {\n      text: this.data.footer.text,\n      iconURL: this.data.footer.icon_url,\n      proxyIconURL: this.data.footer.proxy_icon_url,\n    };\n  }\n\n  /**\n   * The accumulated length for the embed title, description, fields, footer text, and author name.\n   *\n   * @type {number}\n   * @readonly\n   */\n  get length() {\n    return embedLength(this.data);\n  }\n\n  /**\n   * The hex color of this embed.\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get hexColor() {\n    return typeof this.data.color === 'number'\n      ? `#${this.data.color.toString(16).padStart(6, '0')}`\n      : (this.data.color ?? null);\n  }\n\n  /**\n   * Returns the API-compatible JSON for this embed.\n   *\n   * @returns {APIEmbed}\n   */\n  toJSON() {\n    return { ...this.data };\n  }\n\n  /**\n   * Whether the given embeds are equal.\n   *\n   * @param {Embed|APIEmbed} other The embed to compare against\n   * @returns {boolean}\n   */\n  equals(other) {\n    if (other instanceof Embed) {\n      return isEqual(this.data, other.data);\n    }\n\n    return (\n      this.author?.iconURL === other.author?.icon_url &&\n      this.author?.name === other.author?.name &&\n      this.author?.url === other.author?.url &&\n      this.color === (other.color ?? null) &&\n      this.description === (other.description ?? null) &&\n      this.footer?.iconURL === other.footer?.icon_url &&\n      this.footer?.text === other.footer?.text &&\n      this.image?.url === other.image?.url &&\n      this.thumbnail?.url === other.thumbnail?.url &&\n      (this.timestamp && Date.parse(this.timestamp)) === (other.timestamp ? Date.parse(other.timestamp) : null) &&\n      this.title === (other.title ?? null) &&\n      this.url === (other.url ?? null) &&\n      this.video?.url === other.video?.url &&\n      isEqual(this.fields, other.fields?.map(field => ({ ...field, inline: field.inline ?? false })) ?? []) &&\n      isEqual(this.provider, other.provider ?? null)\n    );\n  }\n}\n\nexports.Embed = Embed;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Emoji.js",
    "content": "'use strict';\n\nconst { formatEmoji } = require('@discordjs/formatters');\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { Base } = require('./Base.js');\n\n/**\n * Represents an emoji, see {@link ApplicationEmoji}, {@link GuildEmoji} and {@link ReactionEmoji}.\n *\n * @extends {Base}\n */\nclass Emoji extends Base {\n  constructor(client, emoji) {\n    super(client);\n    /**\n     * Whether or not the emoji is animated\n     *\n     * @type {?boolean}\n     */\n    this.animated = emoji.animated ?? null;\n\n    /**\n     * The emoji's name\n     *\n     * @type {?string}\n     */\n    this.name = emoji.name ?? null;\n\n    /**\n     * The emoji's id\n     *\n     * @type {?Snowflake}\n     */\n    this.id = emoji.id ?? null;\n  }\n\n  /**\n   * The identifier of this emoji, used for message reactions\n   *\n   * @type {string}\n   * @readonly\n   */\n  get identifier() {\n    if (this.id) return `${this.animated ? 'a:' : ''}${this.name}:${this.id}`;\n    return encodeURIComponent(this.name);\n  }\n\n  /**\n   * Returns a URL for the emoji or `null` if this is not a custom emoji.\n   *\n   * @param {EmojiURLOptions} [options={}] Options for the emoji URL\n   * @returns {?string}\n   */\n  imageURL(options = {}) {\n    if (!this.id) return null;\n\n    // Return a dynamic extension depending on whether the emoji is animated.\n    const resolvedOptions = { extension: options.extension, size: options.size };\n\n    if (!options.extension || options.extension === 'webp') {\n      resolvedOptions.animated = options.animated ?? (this.animated || undefined);\n    }\n\n    return this.client.rest.cdn.emoji(this.id, resolvedOptions);\n  }\n\n  /**\n   * The timestamp the emoji was created at, or null if unicode\n   *\n   * @type {?number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return this.id && DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time the emoji was created at, or null if unicode\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get createdAt() {\n    return this.id && new Date(this.createdTimestamp);\n  }\n\n  /**\n   * When concatenated with a string, this automatically returns the text required to form a graphical emoji on Discord\n   * instead of the Emoji object.\n   *\n   * @returns {string}\n   * @example\n   * // Send a custom emoji from a guild:\n   * const emoji = guild.emojis.cache.first();\n   * msg.channel.send(`Hello! ${emoji}`);\n   * @example\n   * // Send the emoji used in a reaction to the channel the reaction is part of\n   * reaction.message.channel.send(`The emoji used was: ${reaction.emoji}`);\n   */\n  toString() {\n    return this.id ? formatEmoji({ animated: this.animated, id: this.id, name: this.name }) : this.name;\n  }\n\n  toJSON() {\n    const json = super.toJSON({\n      guild: 'guildId',\n      createdTimestamp: true,\n      identifier: true,\n    });\n    json.imageURL = this.imageURL();\n    return json;\n  }\n}\n\nexports.Emoji = Emoji;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Entitlement.js",
    "content": "'use strict';\n\nconst { Base } = require('./Base.js');\n\n/**\n * Represents an Entitlement\n *\n * @extends {Base}\n */\nclass Entitlement extends Base {\n  constructor(client, data) {\n    super(client);\n\n    /**\n     * The id of the entitlement\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('sku_id' in data) {\n      /**\n       * The id of the associated SKU\n       *\n       * @type {Snowflake}\n       */\n      this.skuId = data.sku_id;\n    }\n\n    if ('user_id' in data) {\n      /**\n       * The id of the user that is granted access to this entitlement's SKU\n       *\n       * @type {Snowflake}\n       */\n      this.userId = data.user_id;\n    }\n\n    if ('guild_id' in data) {\n      /**\n       * The id of the guild that is granted access to this entitlement's SKU\n       *\n       * @type {?Snowflake}\n       */\n      this.guildId = data.guild_id;\n    } else {\n      this.guildId ??= null;\n    }\n\n    if ('application_id' in data) {\n      /**\n       * The id of the parent application\n       *\n       * @type {Snowflake}\n       */\n      this.applicationId = data.application_id;\n    }\n\n    if ('type' in data) {\n      /**\n       * The type of this entitlement\n       *\n       * @type {EntitlementType}\n       */\n      this.type = data.type;\n    }\n\n    if ('deleted' in data) {\n      /**\n       * Whether this entitlement was deleted\n       *\n       * @type {boolean}\n       */\n      this.deleted = data.deleted;\n    }\n\n    if ('starts_at' in data) {\n      /**\n       * The timestamp at which this entitlement is valid\n       *\n       * @type {?number}\n       */\n      this.startsTimestamp = data.starts_at ? Date.parse(data.starts_at) : null;\n    } else {\n      this.startsTimestamp ??= null;\n    }\n\n    if ('ends_at' in data) {\n      /**\n       * The timestamp at which this entitlement is no longer valid\n       *\n       * @type {?number}\n       */\n      this.endsTimestamp = data.ends_at ? Date.parse(data.ends_at) : null;\n    } else {\n      this.endsTimestamp ??= null;\n    }\n\n    if ('consumed' in data) {\n      /**\n       * Whether this entitlement has been consumed\n       *\n       * @type {boolean}\n       */\n      this.consumed = data.consumed;\n    } else {\n      this.consumed ??= false;\n    }\n  }\n\n  /**\n   * The guild that is granted access to this entitlement's SKU\n   *\n   * @type {?Guild}\n   */\n  get guild() {\n    if (!this.guildId) return null;\n    return this.client.guilds.cache.get(this.guildId) ?? null;\n  }\n\n  /**\n   * The start date at which this entitlement is valid\n   *\n   * @type {?Date}\n   */\n  get startsAt() {\n    return this.startsTimestamp && new Date(this.startsTimestamp);\n  }\n\n  /**\n   * The end date at which this entitlement is no longer valid\n   *\n   * @type {?Date}\n   */\n  get endsAt() {\n    return this.endsTimestamp && new Date(this.endsTimestamp);\n  }\n\n  /**\n   * Indicates whether this entitlement is active\n   *\n   * @returns {boolean}\n   */\n  isActive() {\n    return !this.deleted && (!this.endsTimestamp || this.endsTimestamp > Date.now());\n  }\n\n  /**\n   * Indicates whether this entitlement is a test entitlement\n   *\n   * @returns {boolean}\n   */\n  isTest() {\n    return this.startsTimestamp === null;\n  }\n\n  /**\n   * Indicates whether this entitlement is a user subscription\n   *\n   * @returns {boolean}\n   */\n  isUserSubscription() {\n    return this.guildId === null;\n  }\n\n  /**\n   * Indicates whether this entitlement is a guild subscription\n   *\n   * @returns {boolean}\n   */\n  isGuildSubscription() {\n    return this.guildId !== null;\n  }\n\n  /**\n   * Fetches the user that is granted access to this entitlement's SKU\n   *\n   * @returns {Promise<User>}\n   */\n  async fetchUser() {\n    return this.client.users.fetch(this.userId);\n  }\n\n  /**\n   * Marks this entitlement as consumed\n   * <info>Only available for One-Time Purchase consumable SKUs.</info>\n   *\n   * @returns {Promise<void>}\n   */\n  async consume() {\n    await this.client.application.entitlements.consume(this.id);\n  }\n}\n\nexports.Entitlement = Entitlement;\n"
  },
  {
    "path": "packages/discord.js/src/structures/FileComponent.js",
    "content": "'use strict';\n\nconst { Component } = require('./Component.js');\nconst { UnfurledMediaItem } = require('./UnfurledMediaItem.js');\n\n/**\n * Represents a file component\n *\n * @extends {Component}\n */\nclass FileComponent extends Component {\n  constructor({ file, ...data }) {\n    super(data);\n\n    /**\n     * The media associated with this file\n     *\n     * @type {UnfurledMediaItem}\n     * @readonly\n     */\n    this.file = new UnfurledMediaItem(file);\n  }\n\n  /**\n   * Whether this thumbnail is spoilered\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get spoiler() {\n    return this.data.spoiler ?? false;\n  }\n\n  /**\n   * Returns the API-compatible JSON for this component\n   *\n   * @returns {APIFileComponent}\n   */\n  toJSON() {\n    return { ...this.data, file: this.file.toJSON() };\n  }\n}\n\nexports.FileComponent = FileComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ForumChannel.js",
    "content": "'use strict';\n\nconst { ThreadOnlyChannel } = require('./ThreadOnlyChannel.js');\n\n/**\n * Represents a forum channel.\n *\n * @extends {ThreadOnlyChannel}\n */\nclass ForumChannel extends ThreadOnlyChannel {\n  _patch(data) {\n    super._patch(data);\n\n    /**\n     * The default layout type used to display posts\n     *\n     * @type {ForumLayoutType}\n     */\n    this.defaultForumLayout = data.default_forum_layout;\n  }\n\n  /**\n   * Sets the default forum layout type used to display posts\n   *\n   * @param {ForumLayoutType} defaultForumLayout The default forum layout type to set on this channel\n   * @param {string} [reason] Reason for changing the default forum layout\n   * @returns {Promise<ForumChannel>}\n   */\n  async setDefaultForumLayout(defaultForumLayout, reason) {\n    return this.edit({ defaultForumLayout, reason });\n  }\n}\n\nexports.ForumChannel = ForumChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/GroupDMInvite.js",
    "content": "'use strict';\n\nconst { BaseInvite } = require('./BaseInvite.js');\n\n/**\n * A channel invite leading to a group direct message channel.\n *\n * @extends {BaseInvite}\n */\nclass GroupDMInvite extends BaseInvite {\n  /**\n   * The approximate total number of members of in the group direct message channel.\n   * <info>This is only available when the invite was fetched through {@link Client#fetchInvite}.</info>\n   *\n   * @name GroupDMInvite#approximateMemberCount\n   * @type {?number}\n   */\n\n  _patch(data) {\n    super._patch(data);\n\n    if ('channel' in data) {\n      /**\n       * The channel this invite is for.\n       *\n       * @type {?PartialGroupDMChannel}\n       */\n      this.channel =\n        this.client.channels._add(data.channel, null, { cache: false }) ??\n        this.client.channels.cache.get(this.channelId);\n\n      this.channelId ??= data.channel.id;\n    }\n  }\n}\n\nexports.GroupDMInvite = GroupDMInvite;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Guild.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { ChannelType, GuildPremiumTier, Routes, GuildFeature } = require('discord-api-types/v10');\nconst { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { AutoModerationRuleManager } = require('../managers/AutoModerationRuleManager.js');\nconst { GuildApplicationCommandManager } = require('../managers/GuildApplicationCommandManager.js');\nconst { GuildBanManager } = require('../managers/GuildBanManager.js');\nconst { GuildChannelManager } = require('../managers/GuildChannelManager.js');\nconst { GuildEmojiManager } = require('../managers/GuildEmojiManager.js');\nconst { GuildInviteManager } = require('../managers/GuildInviteManager.js');\nconst { GuildMemberManager } = require('../managers/GuildMemberManager.js');\nconst { GuildScheduledEventManager } = require('../managers/GuildScheduledEventManager.js');\nconst { GuildSoundboardSoundManager } = require('../managers/GuildSoundboardSoundManager.js');\nconst { GuildStickerManager } = require('../managers/GuildStickerManager.js');\nconst { PresenceManager } = require('../managers/PresenceManager.js');\nconst { RoleManager } = require('../managers/RoleManager.js');\nconst { StageInstanceManager } = require('../managers/StageInstanceManager.js');\nconst { VoiceStateManager } = require('../managers/VoiceStateManager.js');\nconst { resolveImage } = require('../util/DataResolver.js');\nconst { SystemChannelFlagsBitField } = require('../util/SystemChannelFlagsBitField.js');\nconst { _transformAPIIncidentsData } = require('../util/Transformers.js');\nconst { discordSort, getSortableGroupTypes, resolvePartialEmoji } = require('../util/Util.js');\nconst { AnonymousGuild } = require('./AnonymousGuild.js');\nconst { GuildAuditLogs } = require('./GuildAuditLogs.js');\nconst { GuildOnboarding } = require('./GuildOnboarding.js');\nconst { GuildPreview } = require('./GuildPreview.js');\nconst { GuildTemplate } = require('./GuildTemplate.js');\nconst { Integration } = require('./Integration.js');\nconst { Webhook } = require('./Webhook.js');\nconst { WelcomeScreen } = require('./WelcomeScreen.js');\n\n/**\n * Represents a guild (or a server) on Discord.\n * <info>It's recommended to see if a guild is available before performing operations or reading data from it. You can\n * check this with {@link Guild#available}.</info>\n *\n * @extends {AnonymousGuild}\n */\nclass Guild extends AnonymousGuild {\n  constructor(client, data) {\n    super(client, data, false);\n\n    /**\n     * A manager of the application commands belonging to this guild\n     *\n     * @type {GuildApplicationCommandManager}\n     */\n    this.commands = new GuildApplicationCommandManager(this);\n\n    /**\n     * A manager of the members belonging to this guild\n     *\n     * @type {GuildMemberManager}\n     */\n    this.members = new GuildMemberManager(this);\n\n    /**\n     * A manager of the channels belonging to this guild\n     *\n     * @type {GuildChannelManager}\n     */\n    this.channels = new GuildChannelManager(this);\n\n    /**\n     * A manager of the bans belonging to this guild\n     *\n     * @type {GuildBanManager}\n     */\n    this.bans = new GuildBanManager(this);\n\n    /**\n     * A manager of the roles belonging to this guild\n     *\n     * @type {RoleManager}\n     */\n    this.roles = new RoleManager(this);\n\n    /**\n     * A manager of the presences belonging to this guild\n     *\n     * @type {PresenceManager}\n     */\n    this.presences = new PresenceManager(this.client);\n\n    /**\n     * A manager of the voice states of this guild\n     *\n     * @type {VoiceStateManager}\n     */\n    this.voiceStates = new VoiceStateManager(this);\n\n    /**\n     * A manager of the stage instances of this guild\n     *\n     * @type {StageInstanceManager}\n     */\n    this.stageInstances = new StageInstanceManager(this);\n\n    /**\n     * A manager of the invites of this guild\n     *\n     * @type {GuildInviteManager}\n     */\n    this.invites = new GuildInviteManager(this);\n\n    /**\n     * A manager of the scheduled events of this guild\n     *\n     * @type {GuildScheduledEventManager}\n     */\n    this.scheduledEvents = new GuildScheduledEventManager(this);\n\n    /**\n     * A manager of the auto moderation rules of this guild.\n     *\n     * @type {AutoModerationRuleManager}\n     */\n    this.autoModerationRules = new AutoModerationRuleManager(this);\n\n    /**\n     * A manager of the soundboard sounds of this guild.\n     *\n     * @type {GuildSoundboardSoundManager}\n     */\n    this.soundboardSounds = new GuildSoundboardSoundManager(this);\n\n    if (!data) return;\n    if (data.unavailable) {\n      /**\n       * Whether the guild is available to access. If it is not available, it indicates a server outage\n       *\n       * @type {boolean}\n       */\n      this.available = false;\n    } else {\n      this._patch(data);\n      if (!data.channels) this.available = false;\n    }\n\n    /**\n     * The id of the shard this Guild belongs to.\n     *\n     * @type {number}\n     */\n    this.shardId = data.shardId;\n  }\n\n  _patch(data) {\n    super._patch(data);\n    this.id = data.id;\n    if ('name' in data) this.name = data.name;\n    if ('icon' in data) this.icon = data.icon;\n    if ('unavailable' in data) {\n      this.available = !data.unavailable;\n    } else {\n      this.available ??= true;\n    }\n\n    if ('discovery_splash' in data) {\n      /**\n       * The hash of the guild discovery splash image\n       *\n       * @type {?string}\n       */\n      this.discoverySplash = data.discovery_splash;\n    }\n\n    if ('member_count' in data) {\n      /**\n       * The full amount of members in this guild\n       *\n       * @type {number}\n       */\n      this.memberCount = data.member_count;\n    }\n\n    if ('large' in data) {\n      /**\n       * Whether the guild is \"large\" (has more than {@link WebSocketOptions large_threshold} members, 50 by default)\n       *\n       * @type {boolean}\n       */\n      this.large = Boolean(data.large);\n    }\n\n    if ('premium_progress_bar_enabled' in data) {\n      /**\n       * Whether this guild has its premium (boost) progress bar enabled\n       *\n       * @type {boolean}\n       */\n      this.premiumProgressBarEnabled = data.premium_progress_bar_enabled;\n    }\n\n    if ('application_id' in data) {\n      /**\n       * The id of the application that created this guild (if applicable)\n       *\n       * @type {?Snowflake}\n       */\n      this.applicationId = data.application_id;\n    }\n\n    if ('afk_timeout' in data) {\n      /**\n       * The time in seconds before a user is counted as \"away from keyboard\"\n       *\n       * @type {?number}\n       */\n      this.afkTimeout = data.afk_timeout;\n    }\n\n    if ('afk_channel_id' in data) {\n      /**\n       * The id of the voice channel where AFK members are moved\n       *\n       * @type {?Snowflake}\n       */\n      this.afkChannelId = data.afk_channel_id;\n    }\n\n    if ('system_channel_id' in data) {\n      /**\n       * The system channel's id\n       *\n       * @type {?Snowflake}\n       */\n      this.systemChannelId = data.system_channel_id;\n    }\n\n    if ('premium_tier' in data) {\n      /**\n       * The premium tier of this guild\n       *\n       * @type {GuildPremiumTier}\n       */\n      this.premiumTier = data.premium_tier;\n    }\n\n    if ('widget_enabled' in data) {\n      /**\n       * Whether widget images are enabled on this guild\n       *\n       * @type {?boolean}\n       */\n      this.widgetEnabled = data.widget_enabled;\n    } else {\n      this.widgetEnabled ??= null;\n    }\n\n    if ('widget_channel_id' in data) {\n      /**\n       * The widget channel's id, if enabled\n       *\n       * @type {?string}\n       */\n      this.widgetChannelId = data.widget_channel_id;\n    } else {\n      this.widgetChannelId ??= null;\n    }\n\n    if ('explicit_content_filter' in data) {\n      /**\n       * The explicit content filter level of the guild\n       *\n       * @type {GuildExplicitContentFilter}\n       */\n      this.explicitContentFilter = data.explicit_content_filter;\n    }\n\n    if ('mfa_level' in data) {\n      /**\n       * The required MFA level for this guild\n       *\n       * @type {GuildMFALevel}\n       */\n      this.mfaLevel = data.mfa_level;\n    }\n\n    if ('joined_at' in data) {\n      /**\n       * The timestamp the client user joined the guild at\n       *\n       * @type {number}\n       */\n      this.joinedTimestamp = Date.parse(data.joined_at);\n    }\n\n    if ('default_message_notifications' in data) {\n      /**\n       * The default message notification level of the guild\n       *\n       * @type {GuildDefaultMessageNotifications}\n       */\n      this.defaultMessageNotifications = data.default_message_notifications;\n    }\n\n    if ('system_channel_flags' in data) {\n      /**\n       * The value set for the guild's system channel flags\n       *\n       * @type {Readonly<SystemChannelFlagsBitField>}\n       */\n      this.systemChannelFlags = new SystemChannelFlagsBitField(data.system_channel_flags).freeze();\n    }\n\n    if ('max_members' in data) {\n      /**\n       * The maximum amount of members the guild can have\n       *\n       * @type {?number}\n       */\n      this.maximumMembers = data.max_members;\n    } else {\n      this.maximumMembers ??= null;\n    }\n\n    if ('max_presences' in data) {\n      /**\n       * The maximum amount of presences the guild can have (this is `null` for all but the largest of guilds)\n       * <info>You will need to fetch the guild using {@link BaseGuild#fetch} if you want to receive\n       * this parameter</info>\n       *\n       * @type {?number}\n       */\n      this.maximumPresences = data.max_presences;\n    } else {\n      this.maximumPresences ??= null;\n    }\n\n    if ('max_video_channel_users' in data) {\n      /**\n       * The maximum amount of users allowed in a video channel.\n       *\n       * @type {?number}\n       */\n      this.maxVideoChannelUsers = data.max_video_channel_users;\n    } else {\n      this.maxVideoChannelUsers ??= null;\n    }\n\n    if ('max_stage_video_channel_users' in data) {\n      /**\n       * The maximum amount of users allowed in a stage video channel.\n       *\n       * @type {?number}\n       */\n      this.maxStageVideoChannelUsers = data.max_stage_video_channel_users;\n    } else {\n      this.maxStageVideoChannelUsers ??= null;\n    }\n\n    if ('approximate_member_count' in data) {\n      /**\n       * The approximate amount of members the guild has\n       * <info>You will need to fetch the guild using {@link BaseGuild#fetch} if you want to receive\n       * this parameter</info>\n       *\n       * @type {?number}\n       */\n      this.approximateMemberCount = data.approximate_member_count;\n    } else {\n      this.approximateMemberCount ??= null;\n    }\n\n    if ('approximate_presence_count' in data) {\n      /**\n       * The approximate amount of presences the guild has\n       * <info>You will need to fetch the guild using {@link BaseGuild#fetch} if you want to receive\n       * this parameter</info>\n       *\n       * @type {?number}\n       */\n      this.approximatePresenceCount = data.approximate_presence_count;\n    } else {\n      this.approximatePresenceCount ??= null;\n    }\n\n    /**\n     * The use count of the vanity URL code of the guild, if any\n     * <info>You will need to fetch this parameter using {@link Guild#fetchVanityData} if you want to receive it</info>\n     *\n     * @type {?number}\n     */\n    this.vanityURLUses ??= null;\n\n    if ('rules_channel_id' in data) {\n      /**\n       * The rules channel's id for the guild\n       *\n       * @type {?Snowflake}\n       */\n      this.rulesChannelId = data.rules_channel_id;\n    }\n\n    if ('public_updates_channel_id' in data) {\n      /**\n       * The community updates channel's id for the guild\n       *\n       * @type {?Snowflake}\n       */\n      this.publicUpdatesChannelId = data.public_updates_channel_id;\n    }\n\n    if ('preferred_locale' in data) {\n      /**\n       * The preferred locale of the guild, defaults to `en-US`\n       *\n       * @type {Locale}\n       */\n      this.preferredLocale = data.preferred_locale;\n    }\n\n    if ('safety_alerts_channel_id' in data) {\n      /**\n       * The safety alerts channel's id for the guild\n       *\n       * @type {?Snowflake}\n       */\n      this.safetyAlertsChannelId = data.safety_alerts_channel_id;\n    } else {\n      this.safetyAlertsChannelId ??= null;\n    }\n\n    if (data.channels) {\n      this.channels.cache.clear();\n      for (const rawChannel of data.channels) {\n        this.client.channels._add(rawChannel, this);\n      }\n    }\n\n    if (data.threads) {\n      for (const rawThread of data.threads) {\n        this.client.channels._add(rawThread, this);\n      }\n    }\n\n    if (data.roles) {\n      this.roles.cache.clear();\n      for (const role of data.roles) this.roles._add(role);\n    }\n\n    if (data.members) {\n      this.members.cache.clear();\n      for (const guildUser of data.members) this.members._add(guildUser);\n    }\n\n    if ('owner_id' in data) {\n      /**\n       * The user id of this guild's owner\n       *\n       * @type {Snowflake}\n       */\n      this.ownerId = data.owner_id;\n    }\n\n    if (data.presences) {\n      for (const presence of data.presences) {\n        this.presences._add(Object.assign(presence, { guild: this }));\n      }\n    }\n\n    if (data.stage_instances) {\n      this.stageInstances.cache.clear();\n      for (const stageInstance of data.stage_instances) {\n        this.stageInstances._add(stageInstance);\n      }\n    }\n\n    if (data.guild_scheduled_events) {\n      this.scheduledEvents.cache.clear();\n      for (const scheduledEvent of data.guild_scheduled_events) {\n        this.scheduledEvents._add(scheduledEvent);\n      }\n    }\n\n    if (data.voice_states) {\n      this.voiceStates.cache.clear();\n      for (const voiceState of data.voice_states) {\n        this.voiceStates._add(voiceState);\n      }\n    }\n\n    if (!this.emojis) {\n      /**\n       * A manager of the emojis belonging to this guild\n       *\n       * @type {GuildEmojiManager}\n       */\n      this.emojis = new GuildEmojiManager(this);\n      if (data.emojis) for (const emoji of data.emojis) this.emojis._add(emoji);\n    } else if (data.emojis) {\n      this.client.actions.GuildEmojisUpdate.handle({\n        guild_id: this.id,\n        emojis: data.emojis,\n      });\n    }\n\n    if (!this.stickers) {\n      /**\n       * A manager of the stickers belonging to this guild\n       *\n       * @type {GuildStickerManager}\n       */\n      this.stickers = new GuildStickerManager(this);\n      if (data.stickers) for (const sticker of data.stickers) this.stickers._add(sticker);\n    } else if (data.stickers) {\n      this.client.actions.GuildStickersUpdate.handle({\n        guild_id: this.id,\n        stickers: data.stickers,\n      });\n    }\n\n    if ('incidents_data' in data) {\n      /**\n       * Incident actions of a guild.\n       *\n       * @typedef {Object} IncidentActions\n       * @property {?Date} invitesDisabledUntil When invites would be enabled again\n       * @property {?Date} dmsDisabledUntil When direct messages would be enabled again\n       * @property {?Date} dmSpamDetectedAt When direct message spam was detected\n       * @property {?Date} raidDetectedAt When a raid was detected\n       */\n\n      /**\n       * The incidents data of this guild.\n       * <info>You will need to fetch the guild using {@link BaseGuild#fetch} if you want to receive\n       * this property.</info>\n       *\n       * @type {?IncidentActions}\n       */\n      this.incidentsData = data.incidents_data && _transformAPIIncidentsData(data.incidents_data);\n    } else {\n      this.incidentsData ??= null;\n    }\n\n    if (data.soundboard_sounds) {\n      this.soundboardSounds.cache.clear();\n      for (const soundboardSound of data.soundboard_sounds) {\n        this.soundboardSounds._add(soundboardSound);\n      }\n    }\n  }\n\n  /**\n   * The time the client user joined the guild\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get joinedAt() {\n    return new Date(this.joinedTimestamp);\n  }\n\n  /**\n   * The URL to this guild's discovery splash image.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  discoverySplashURL(options = {}) {\n    return this.discoverySplash && this.client.rest.cdn.discoverySplash(this.id, this.discoverySplash, options);\n  }\n\n  /**\n   * Fetches the owner of the guild.\n   * If the member object isn't needed, use {@link Guild#ownerId} instead.\n   *\n   * @param {BaseFetchOptions} [options] The options for fetching the member\n   * @returns {Promise<GuildMember>}\n   */\n  async fetchOwner(options) {\n    if (!this.ownerId) {\n      throw new DiscordjsError(ErrorCodes.FetchOwnerId, 'guild');\n    }\n\n    return this.members.fetch({ ...options, user: this.ownerId });\n  }\n\n  /**\n   * AFK voice channel for this guild\n   *\n   * @type {?VoiceChannel}\n   * @readonly\n   */\n  get afkChannel() {\n    return this.client.channels.resolve(this.afkChannelId);\n  }\n\n  /**\n   * System channel for this guild\n   *\n   * @type {?TextChannel}\n   * @readonly\n   */\n  get systemChannel() {\n    return this.client.channels.resolve(this.systemChannelId);\n  }\n\n  /**\n   * Widget channel for this guild\n   *\n   * @type {?(TextChannel|AnnouncementChannel|VoiceChannel|StageChannel|ForumChannel|MediaChannel)}\n   * @readonly\n   */\n  get widgetChannel() {\n    return this.client.channels.resolve(this.widgetChannelId);\n  }\n\n  /**\n   * Rules channel for this guild\n   *\n   * @type {?TextChannel}\n   * @readonly\n   */\n  get rulesChannel() {\n    return this.client.channels.resolve(this.rulesChannelId);\n  }\n\n  /**\n   * Public updates channel for this guild\n   *\n   * @type {?TextChannel}\n   * @readonly\n   */\n  get publicUpdatesChannel() {\n    return this.client.channels.resolve(this.publicUpdatesChannelId);\n  }\n\n  /**\n   * Safety alerts channel for this guild\n   *\n   * @type {?TextChannel}\n   * @readonly\n   */\n  get safetyAlertsChannel() {\n    return this.client.channels.resolve(this.safetyAlertsChannelId);\n  }\n\n  /**\n   * The maximum bitrate available for a voice channel in this guild\n   *\n   * @type {number}\n   * @readonly\n   */\n  get maximumBitrate() {\n    if (this.features.includes(GuildFeature.VIPRegions)) {\n      return 384_000;\n    }\n\n    switch (this.premiumTier) {\n      case GuildPremiumTier.Tier1:\n        return 128_000;\n      case GuildPremiumTier.Tier2:\n        return 256_000;\n      case GuildPremiumTier.Tier3:\n        return 384_000;\n      default:\n        return 96_000;\n    }\n  }\n\n  /**\n   * The maximum bitrate available for a stage channel in this guild\n   *\n   * @type {number}\n   * @readonly\n   */\n  get maximumStageBitrate() {\n    return 64_000;\n  }\n\n  /**\n   * Fetches a collection of integrations to this guild.\n   * Resolves with a collection mapping integrations by their ids.\n   *\n   * @returns {Promise<Collection<Snowflake|string, Integration>>}\n   * @example\n   * // Fetch integrations\n   * guild.fetchIntegrations()\n   *   .then(integrations => console.log(`Fetched ${integrations.size} integrations`))\n   *   .catch(console.error);\n   */\n  async fetchIntegrations() {\n    const data = await this.client.rest.get(Routes.guildIntegrations(this.id));\n    return data.reduce(\n      (collection, integration) => collection.set(integration.id, new Integration(this.client, integration, this)),\n      new Collection(),\n    );\n  }\n\n  /**\n   * Fetches a collection of templates from this guild.\n   * Resolves with a collection mapping templates by their codes.\n   *\n   * @returns {Promise<Collection<string, GuildTemplate>>}\n   */\n  async fetchTemplates() {\n    const templates = await this.client.rest.get(Routes.guildTemplates(this.id));\n    return templates.reduce((col, data) => col.set(data.code, new GuildTemplate(this.client, data)), new Collection());\n  }\n\n  /**\n   * Fetches the welcome screen for this guild.\n   *\n   * @returns {Promise<WelcomeScreen>}\n   */\n  async fetchWelcomeScreen() {\n    const data = await this.client.rest.get(Routes.guildWelcomeScreen(this.id));\n    return new WelcomeScreen(this, data);\n  }\n\n  /**\n   * Creates a template for the guild.\n   *\n   * @param {string} name The name for the template\n   * @param {string} [description] The description for the template\n   * @returns {Promise<GuildTemplate>}\n   */\n  async createTemplate(name, description) {\n    const data = await this.client.rest.post(Routes.guildTemplates(this.id), { body: { name, description } });\n    return new GuildTemplate(this.client, data);\n  }\n\n  /**\n   * Obtains a guild preview for this guild from Discord.\n   *\n   * @returns {Promise<GuildPreview>}\n   */\n  async fetchPreview() {\n    const data = await this.client.rest.get(Routes.guildPreview(this.id));\n    return new GuildPreview(this.client, data);\n  }\n\n  /**\n   * An object containing information about a guild's vanity invite.\n   *\n   * @typedef {Object} Vanity\n   * @property {?string} code Vanity invite code\n   * @property {number} uses How many times this invite has been used\n   */\n\n  /**\n   * Fetches the vanity URL invite object to this guild.\n   * Resolves with an object containing the vanity URL invite code and the use count\n   *\n   * @returns {Promise<Vanity>}\n   * @example\n   * // Fetch invite data\n   * guild.fetchVanityData()\n   *   .then(res => {\n   *     console.log(`Vanity URL: https://discord.gg/${res.code} with ${res.uses} uses`);\n   *   })\n   *   .catch(console.error);\n   */\n  async fetchVanityData() {\n    const data = await this.client.rest.get(Routes.guildVanityUrl(this.id));\n    this.vanityURLCode = data.code;\n    this.vanityURLUses = data.uses;\n\n    return data;\n  }\n\n  /**\n   * Fetches all webhooks for the guild.\n   *\n   * @returns {Promise<Collection<Snowflake, Webhook>>}\n   * @example\n   * // Fetch webhooks\n   * guild.fetchWebhooks()\n   *   .then(webhooks => console.log(`Fetched ${webhooks.size} webhooks`))\n   *   .catch(console.error);\n   */\n  async fetchWebhooks() {\n    const apiHooks = await this.client.rest.get(Routes.guildWebhooks(this.id));\n    const hooks = new Collection();\n    for (const hook of apiHooks) hooks.set(hook.id, new Webhook(this.client, hook));\n    return hooks;\n  }\n\n  /**\n   * Fetches the guild widget data, requires the widget to be enabled.\n   *\n   * @returns {Promise<Widget>}\n   * @example\n   * // Fetches the guild widget data\n   * guild.fetchWidget()\n   *   .then(widget => console.log(`The widget shows ${widget.channels.size} channels`))\n   *   .catch(console.error);\n   */\n  async fetchWidget() {\n    return this.client.fetchGuildWidget(this.id);\n  }\n\n  /**\n   * Data for the Guild Widget Settings object\n   *\n   * @typedef {Object} GuildWidgetSettings\n   * @property {boolean} enabled Whether the widget is enabled\n   * @property {?(TextChannel|AnnouncementChannel|VoiceChannel|StageChannel|ForumChannel|MediaChannel)} channel\n   * The widget invite channel\n   */\n\n  /**\n   * The Guild Widget Settings object\n   *\n   * @typedef {Object} GuildWidgetSettingsData\n   * @property {boolean} enabled Whether the widget is enabled\n   * @property {?(TextChannel|AnnouncementChannel|VoiceChannel|StageChannel|ForumChannel|\n   * MediaChannel|Snowflake)} channel The widget invite channel\n   */\n\n  /**\n   * Fetches the guild widget settings.\n   *\n   * @returns {Promise<GuildWidgetSettings>}\n   * @example\n   * // Fetches the guild widget settings\n   * guild.fetchWidgetSettings()\n   *   .then(widget => console.log(`The widget is ${widget.enabled ? 'enabled' : 'disabled'}`))\n   *   .catch(console.error);\n   */\n  async fetchWidgetSettings() {\n    const data = await this.client.rest.get(Routes.guildWidgetSettings(this.id));\n    this.widgetEnabled = data.enabled;\n    this.widgetChannelId = data.channel_id;\n    return {\n      enabled: data.enabled,\n      channel: data.channel_id ? this.channels.cache.get(data.channel_id) : null,\n    };\n  }\n\n  /**\n   * Returns a URL for the PNG widget of the guild.\n   *\n   * @param {GuildWidgetStyle} [style] The style for the widget image\n   * @returns {string}\n   */\n  widgetImageURL(style) {\n    return this.client.guilds.widgetImageURL(this.id, style);\n  }\n\n  /**\n   * Options used to fetch audit logs.\n   *\n   * @typedef {Object} GuildAuditLogsFetchOptions\n   * @property {Snowflake|GuildAuditLogsEntry} [before] Consider only entries before this entry\n   * @property {Snowflake|GuildAuditLogsEntry} [after] Consider only entries after this entry\n   * @property {number} [limit] The number of entries to return\n   * @property {UserResolvable} [user] Only return entries for actions made by this user\n   * @property {?AuditLogEvent} [type] Only return entries for this action type\n   */\n\n  /**\n   * Fetches audit logs for this guild.\n   *\n   * @param {GuildAuditLogsFetchOptions} [options={}] Options for fetching audit logs\n   * @returns {Promise<GuildAuditLogs>}\n   * @example\n   * // Output audit log entries\n   * guild.fetchAuditLogs()\n   *   .then(audit => console.log(audit.entries.first()))\n   *   .catch(console.error);\n   */\n  async fetchAuditLogs({ before, after, limit, user, type } = {}) {\n    const query = makeURLSearchParams({\n      before: before?.id ?? before,\n      after: after?.id ?? after,\n      limit,\n      action_type: type,\n    });\n\n    if (user) {\n      const userId = this.client.users.resolveId(user);\n      if (!userId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'user', 'UserResolvable');\n      query.set('user_id', userId);\n    }\n\n    const data = await this.client.rest.get(Routes.guildAuditLog(this.id), { query });\n    return new GuildAuditLogs(this, data);\n  }\n\n  /**\n   * Fetches the guild onboarding data for this guild.\n   *\n   * @returns {Promise<GuildOnboarding>}\n   */\n  async fetchOnboarding() {\n    const data = await this.client.rest.get(Routes.guildOnboarding(this.id));\n    return new GuildOnboarding(this.client, data);\n  }\n\n  /**\n   * The data for editing a guild.\n   *\n   * @typedef {Object} GuildEditOptions\n   * @property {string} [name] The name of the guild\n   * @property {?GuildVerificationLevel} [verificationLevel] The verification level of the guild\n   * @property {?GuildDefaultMessageNotifications} [defaultMessageNotifications] The default message\n   * notification level of the guild\n   * @property {?GuildExplicitContentFilter} [explicitContentFilter] The level of the explicit content filter\n   * @property {?VoiceChannelResolvable} [afkChannel] The AFK channel of the guild\n   * @property {number} [afkTimeout] The AFK timeout of the guild\n   * @property {?(BufferResolvable|Base64Resolvable)} [icon] The icon of the guild\n   * @property {?(BufferResolvable|Base64Resolvable)} [splash] The invite splash image of the guild\n   * @property {?(BufferResolvable|Base64Resolvable)} [discoverySplash] The discovery splash image of the guild\n   * @property {?(BufferResolvable|Base64Resolvable)} [banner] The banner of the guild\n   * @property {?TextChannelResolvable} [systemChannel] The system channel of the guild\n   * @property {SystemChannelFlagsResolvable} [systemChannelFlags] The system channel flags of the guild\n   * @property {?TextChannelResolvable} [rulesChannel] The rules channel of the guild\n   * @property {?TextChannelResolvable} [publicUpdatesChannel] The community updates channel of the guild\n   * @property {?TextChannelResolvable} [safetyAlertsChannel] The safety alerts channel of the guild\n   * @property {?string} [preferredLocale] The preferred locale of the guild\n   * @property {GuildFeature[]} [features] The features of the guild\n   * @property {?string} [description] The discovery description of the guild\n   * @property {boolean} [premiumProgressBarEnabled] Whether the guild's premium progress bar is enabled\n   * @property {string} [reason] Reason for editing this guild\n   */\n\n  /**\n   * Data that can be resolved to a Text Channel object. This can be:\n   * - A TextChannel\n   * - A Snowflake\n   *\n   * @typedef {TextChannel|Snowflake} TextChannelResolvable\n   */\n\n  /**\n   * Data that can be resolved to a Voice Channel object. This can be:\n   * - A VoiceChannel\n   * - A Snowflake\n   *\n   * @typedef {VoiceChannel|Snowflake} VoiceChannelResolvable\n   */\n\n  /**\n   * Updates the guild with new information - e.g. a new name.\n   *\n   * @param {GuildEditOptions} options The options to provide\n   * @returns {Promise<Guild>}\n   * @example\n   * // Set the guild name\n   * guild.edit({\n   *   name: 'Discord Guild',\n   * })\n   *   .then(updated => console.log(`New guild name ${updated}`))\n   *   .catch(console.error);\n   */\n  async edit({\n    verificationLevel,\n    defaultMessageNotifications,\n    explicitContentFilter,\n    afkChannel,\n    afkTimeout,\n    icon,\n    splash,\n    discoverySplash,\n    banner,\n    systemChannel,\n    systemChannelFlags,\n    rulesChannel,\n    publicUpdatesChannel,\n    preferredLocale,\n    premiumProgressBarEnabled,\n    safetyAlertsChannel,\n    ...options\n  }) {\n    const data = await this.client.rest.patch(Routes.guild(this.id), {\n      body: {\n        ...options,\n        verification_level: verificationLevel,\n        default_message_notifications: defaultMessageNotifications,\n        explicit_content_filter: explicitContentFilter,\n        afk_channel_id: afkChannel && this.client.channels.resolveId(afkChannel),\n        afk_timeout: afkTimeout,\n        icon: icon && (await resolveImage(icon)),\n        splash: splash && (await resolveImage(splash)),\n        discovery_splash: discoverySplash && (await resolveImage(discoverySplash)),\n        banner: banner && (await resolveImage(banner)),\n        system_channel_id: systemChannel && this.client.channels.resolveId(systemChannel),\n        system_channel_flags:\n          systemChannelFlags === undefined ? undefined : SystemChannelFlagsBitField.resolve(systemChannelFlags),\n        rules_channel_id: rulesChannel && this.client.channels.resolveId(rulesChannel),\n        public_updates_channel_id: publicUpdatesChannel && this.client.channels.resolveId(publicUpdatesChannel),\n        preferred_locale: preferredLocale,\n        premium_progress_bar_enabled: premiumProgressBarEnabled,\n        safety_alerts_channel_id: safetyAlertsChannel && this.client.channels.resolveId(safetyAlertsChannel),\n      },\n      reason: options.reason,\n    });\n\n    return this.client.actions.GuildUpdate.handle(data).updated;\n  }\n\n  /**\n   * Options used to edit the guild onboarding.\n   *\n   * @typedef {Object} GuildOnboardingEditOptions\n   * @property {GuildOnboardingPromptData[]|Collection<Snowflake, GuildOnboardingPrompt>} [prompts]\n   * The prompts shown during onboarding and in customize community\n   * @property {ChannelResolvable[]|Collection<Snowflake, GuildChannel>} [defaultChannels]\n   * The channels that new members get opted into automatically\n   * @property {boolean} [enabled] Whether the onboarding is enabled\n   * @property {GuildOnboardingMode} [mode] The mode to edit the guild onboarding with\n   * @property {string} [reason] The reason for editing the guild onboarding\n   */\n\n  /**\n   * Data for editing a guild onboarding prompt.\n   *\n   * @typedef {Object} GuildOnboardingPromptData\n   * @property {Snowflake} [id] The id of the prompt\n   * @property {string} title The title for the prompt\n   * @property {boolean} [singleSelect] Whether users are limited to selecting one option for the prompt\n   * @property {boolean} [required] Whether the prompt is required before a user completes the onboarding flow\n   * @property {boolean} [inOnboarding] Whether the prompt is present in the onboarding flow\n   * @property {GuildOnboardingPromptType} [type] The type of the prompt\n   * @property {GuildOnboardingPromptOptionData[]|Collection<Snowflake, GuildOnboardingPrompt>} options\n   * The options available within the prompt\n   */\n\n  /**\n   * Data for editing a guild onboarding prompt option.\n   *\n   * @typedef {Object} GuildOnboardingPromptOptionData\n   * @property {?Snowflake} [id] The id of the option\n   * @property {ChannelResolvable[]|Collection<Snowflake, GuildChannel>} [channels]\n   * The channels a member is added to when the option is selected\n   * @property {RoleResolvable[]|Collection<Snowflake, Role>} [roles]\n   * The roles assigned to a member when the option is selected\n   * @property {string} title The title of the option\n   * @property {?string} [description] The description of the option\n   * @property {?(EmojiIdentifierResolvable|Emoji)} [emoji] The emoji of the option\n   */\n\n  /**\n   * Edits the guild onboarding data for this guild.\n   *\n   * @param {GuildOnboardingEditOptions} options The options to provide\n   * @returns {Promise<GuildOnboarding>}\n   */\n  async editOnboarding(options) {\n    const newData = await this.client.rest.put(Routes.guildOnboarding(this.id), {\n      body: {\n        prompts: options.prompts?.map(prompt => ({\n          // Currently, the prompt ids are required even for new ones (which won't be used)\n          id: prompt.id ?? DiscordSnowflake.generate().toString(),\n          title: prompt.title,\n          single_select: prompt.singleSelect,\n          required: prompt.required,\n          in_onboarding: prompt.inOnboarding,\n          type: prompt.type,\n          options: prompt.options.map(option => {\n            const emoji = resolvePartialEmoji(option.emoji);\n\n            return {\n              id: option.id,\n              channel_ids: option.channels?.map(channel => this.channels.resolveId(channel)),\n              role_ids: option.roles?.map(role => this.roles.resolveId(role)),\n              title: option.title,\n              description: option.description,\n              emoji_animated: emoji?.animated,\n              emoji_id: emoji?.id,\n              emoji_name: emoji?.name,\n            };\n          }),\n        })),\n        default_channel_ids: options.defaultChannels?.map(channel => this.channels.resolveId(channel)),\n        enabled: options.enabled,\n        mode: options.mode,\n      },\n      reason: options.reason,\n    });\n\n    return new GuildOnboarding(this.client, newData);\n  }\n\n  /**\n   * Welcome channel data\n   *\n   * @typedef {Object} WelcomeChannelData\n   * @property {string} description The description to show for this welcome channel\n   * @property {TextChannel|AnnouncementChannel|ForumChannel|MediaChannel|Snowflake} channel\n   * The channel to link for this welcome channel\n   * @property {EmojiIdentifierResolvable} [emoji] The emoji to display for this welcome channel\n   */\n\n  /**\n   * Welcome screen edit data\n   *\n   * @typedef {Object} WelcomeScreenEditOptions\n   * @property {boolean} [enabled] Whether the welcome screen is enabled\n   * @property {string} [description] The description for the welcome screen\n   * @property {WelcomeChannelData[]} [welcomeChannels] The welcome channel data for the welcome screen\n   */\n\n  /**\n   * Data that can be resolved to a GuildTextChannel object. This can be:\n   * - A TextChannel\n   * - A AnnouncementChannel\n   * - A Snowflake\n   *\n   * @typedef {TextChannel|AnnouncementChannel|Snowflake} GuildTextChannelResolvable\n   */\n\n  /**\n   * Data that can be resolved to a GuildVoiceChannel object. This can be:\n   * - A VoiceChannel\n   * - A StageChannel\n   * - A Snowflake\n   *\n   * @typedef {VoiceChannel|StageChannel|Snowflake} GuildVoiceChannelResolvable\n   */\n\n  /**\n   * Updates the guild's welcome screen\n   *\n   * @param {WelcomeScreenEditOptions} options The options to provide\n   * @returns {Promise<WelcomeScreen>}\n   * @example\n   * guild.editWelcomeScreen({\n   *   description: 'Hello World',\n   *   enabled: true,\n   *   welcomeChannels: [\n   *     {\n   *       description: 'foobar',\n   *       channel: '222197033908436994',\n   *     }\n   *   ],\n   * })\n   */\n  async editWelcomeScreen(options) {\n    const { enabled, description, welcomeChannels } = options;\n    const welcome_channels = welcomeChannels?.map(welcomeChannelData => {\n      const emoji = this.emojis.resolve(welcomeChannelData.emoji);\n      return {\n        emoji_id: emoji?.id,\n        emoji_name: emoji?.name ?? welcomeChannelData.emoji,\n        channel_id: this.channels.resolveId(welcomeChannelData.channel),\n        description: welcomeChannelData.description,\n      };\n    });\n\n    const patchData = await this.client.rest.patch(Routes.guildWelcomeScreen(this.id), {\n      body: {\n        welcome_channels,\n        description,\n        enabled,\n      },\n    });\n    return new WelcomeScreen(this, patchData);\n  }\n\n  /**\n   * Edits the level of the explicit content filter.\n   *\n   * @param {?GuildExplicitContentFilter} explicitContentFilter The new level of the explicit content filter\n   * @param {string} [reason] Reason for changing the level of the guild's explicit content filter\n   * @returns {Promise<Guild>}\n   */\n  async setExplicitContentFilter(explicitContentFilter, reason) {\n    return this.edit({ explicitContentFilter, reason });\n  }\n\n  /**\n   * Edits the setting of the default message notifications of the guild.\n   *\n   * @param {?GuildDefaultMessageNotifications} defaultMessageNotifications\n   * The new default message notification level of the guild\n   * @param {string} [reason] Reason for changing the setting of the default message notifications\n   * @returns {Promise<Guild>}\n   */\n  async setDefaultMessageNotifications(defaultMessageNotifications, reason) {\n    return this.edit({ defaultMessageNotifications, reason });\n  }\n\n  /**\n   * Edits the flags of the default message notifications of the guild.\n   *\n   * @param {SystemChannelFlagsResolvable} systemChannelFlags The new flags for the default message notifications\n   * @param {string} [reason] Reason for changing the flags of the default message notifications\n   * @returns {Promise<Guild>}\n   */\n  async setSystemChannelFlags(systemChannelFlags, reason) {\n    return this.edit({ systemChannelFlags, reason });\n  }\n\n  /**\n   * Edits the name of the guild.\n   *\n   * @param {string} name The new name of the guild\n   * @param {string} [reason] Reason for changing the guild's name\n   * @returns {Promise<Guild>}\n   * @example\n   * // Edit the guild name\n   * guild.setName('Discord Guild')\n   *  .then(updated => console.log(`Updated guild name to ${updated.name}`))\n   *  .catch(console.error);\n   */\n  async setName(name, reason) {\n    return this.edit({ name, reason });\n  }\n\n  /**\n   * Edits the verification level of the guild.\n   *\n   * @param {?GuildVerificationLevel} verificationLevel The new verification level of the guild\n   * @param {string} [reason] Reason for changing the guild's verification level\n   * @returns {Promise<Guild>}\n   * @example\n   * // Edit the guild verification level\n   * guild.setVerificationLevel(1)\n   *  .then(updated => console.log(`Updated guild verification level to ${guild.verificationLevel}`))\n   *  .catch(console.error);\n   */\n  async setVerificationLevel(verificationLevel, reason) {\n    return this.edit({ verificationLevel, reason });\n  }\n\n  /**\n   * Edits the AFK channel of the guild.\n   *\n   * @param {?VoiceChannelResolvable} afkChannel The new AFK channel\n   * @param {string} [reason] Reason for changing the guild's AFK channel\n   * @returns {Promise<Guild>}\n   * @example\n   * // Edit the guild AFK channel\n   * guild.setAFKChannel(channel)\n   *  .then(updated => console.log(`Updated guild AFK channel to ${guild.afkChannel.name}`))\n   *  .catch(console.error);\n   */\n  async setAFKChannel(afkChannel, reason) {\n    return this.edit({ afkChannel, reason });\n  }\n\n  /**\n   * Edits the system channel of the guild.\n   *\n   * @param {?TextChannelResolvable} systemChannel The new system channel\n   * @param {string} [reason] Reason for changing the guild's system channel\n   * @returns {Promise<Guild>}\n   * @example\n   * // Edit the guild system channel\n   * guild.setSystemChannel(channel)\n   *  .then(updated => console.log(`Updated guild system channel to ${guild.systemChannel.name}`))\n   *  .catch(console.error);\n   */\n  async setSystemChannel(systemChannel, reason) {\n    return this.edit({ systemChannel, reason });\n  }\n\n  /**\n   * Edits the AFK timeout of the guild.\n   *\n   * @param {number} afkTimeout The time in seconds that a user must be idle to be considered AFK\n   * @param {string} [reason] Reason for changing the guild's AFK timeout\n   * @returns {Promise<Guild>}\n   * @example\n   * // Edit the guild AFK channel\n   * guild.setAFKTimeout(60)\n   *  .then(updated => console.log(`Updated guild AFK timeout to ${guild.afkTimeout}`))\n   *  .catch(console.error);\n   */\n  async setAFKTimeout(afkTimeout, reason) {\n    return this.edit({ afkTimeout, reason });\n  }\n\n  /**\n   * Sets a new guild icon.\n   *\n   * @param {?(Base64Resolvable|BufferResolvable)} icon The new icon of the guild\n   * @param {string} [reason] Reason for changing the guild's icon\n   * @returns {Promise<Guild>}\n   * @example\n   * // Edit the guild icon\n   * guild.setIcon('./icon.png')\n   *  .then(updated => console.log('Updated the guild icon'))\n   *  .catch(console.error);\n   */\n  async setIcon(icon, reason) {\n    return this.edit({ icon, reason });\n  }\n\n  /**\n   * Sets a new guild invite splash image.\n   *\n   * @param {?(Base64Resolvable|BufferResolvable)} splash The new invite splash image of the guild\n   * @param {string} [reason] Reason for changing the guild's invite splash image\n   * @returns {Promise<Guild>}\n   * @example\n   * // Edit the guild splash\n   * guild.setSplash('./splash.png')\n   *  .then(updated => console.log('Updated the guild splash'))\n   *  .catch(console.error);\n   */\n  async setSplash(splash, reason) {\n    return this.edit({ splash, reason });\n  }\n\n  /**\n   * Sets a new guild discovery splash image.\n   *\n   * @param {?(Base64Resolvable|BufferResolvable)} discoverySplash The new discovery splash image of the guild\n   * @param {string} [reason] Reason for changing the guild's discovery splash image\n   * @returns {Promise<Guild>}\n   * @example\n   * // Edit the guild discovery splash\n   * guild.setDiscoverySplash('./discoverysplash.png')\n   *   .then(updated => console.log('Updated the guild discovery splash'))\n   *   .catch(console.error);\n   */\n  async setDiscoverySplash(discoverySplash, reason) {\n    return this.edit({ discoverySplash, reason });\n  }\n\n  /**\n   * Sets a new guild banner.\n   *\n   * @param {?(Base64Resolvable|BufferResolvable)} banner The new banner of the guild\n   * @param {string} [reason] Reason for changing the guild's banner\n   * @returns {Promise<Guild>}\n   * @example\n   * guild.setBanner('./banner.png')\n   *  .then(updated => console.log('Updated the guild banner'))\n   *  .catch(console.error);\n   */\n  async setBanner(banner, reason) {\n    return this.edit({ banner, reason });\n  }\n\n  /**\n   * Edits the rules channel of the guild.\n   *\n   * @param {?TextChannelResolvable} rulesChannel The new rules channel\n   * @param {string} [reason] Reason for changing the guild's rules channel\n   * @returns {Promise<Guild>}\n   * @example\n   * // Edit the guild rules channel\n   * guild.setRulesChannel(channel)\n   *  .then(updated => console.log(`Updated guild rules channel to ${guild.rulesChannel.name}`))\n   *  .catch(console.error);\n   */\n  async setRulesChannel(rulesChannel, reason) {\n    return this.edit({ rulesChannel, reason });\n  }\n\n  /**\n   * Edits the community updates channel of the guild.\n   *\n   * @param {?TextChannelResolvable} publicUpdatesChannel The new community updates channel\n   * @param {string} [reason] Reason for changing the guild's community updates channel\n   * @returns {Promise<Guild>}\n   * @example\n   * // Edit the guild community updates channel\n   * guild.setPublicUpdatesChannel(channel)\n   *  .then(updated => console.log(`Updated guild community updates channel to ${guild.publicUpdatesChannel.name}`))\n   *  .catch(console.error);\n   */\n  async setPublicUpdatesChannel(publicUpdatesChannel, reason) {\n    return this.edit({ publicUpdatesChannel, reason });\n  }\n\n  /**\n   * Edits the preferred locale of the guild.\n   *\n   * @param {?Locale} preferredLocale The new preferred locale of the guild\n   * @param {string} [reason] Reason for changing the guild's preferred locale\n   * @returns {Promise<Guild>}\n   * @example\n   * // Edit the guild preferred locale\n   * guild.setPreferredLocale('en-US')\n   *  .then(updated => console.log(`Updated guild preferred locale to ${guild.preferredLocale}`))\n   *  .catch(console.error);\n   */\n  async setPreferredLocale(preferredLocale, reason) {\n    return this.edit({ preferredLocale, reason });\n  }\n\n  /**\n   * Edits the enabled state of the guild's premium progress bar\n   *\n   * @param {boolean} [enabled=true] The new enabled state of the guild's premium progress bar\n   * @param {string} [reason] Reason for changing the state of the guild's premium progress bar\n   * @returns {Promise<Guild>}\n   */\n  async setPremiumProgressBarEnabled(enabled = true, reason = undefined) {\n    return this.edit({ premiumProgressBarEnabled: enabled, reason });\n  }\n\n  /**\n   * Edits the safety alerts channel of the guild.\n   *\n   * @param {?TextChannelResolvable} safetyAlertsChannel The new safety alerts channel\n   * @param {string} [reason] Reason for changing the guild's safety alerts channel\n   * @returns {Promise<Guild>}\n   * @example\n   * // Edit the guild safety alerts channel\n   * guild.setSafetyAlertsChannel(channel)\n   *  .then(updated => console.log(`Updated guild safety alerts channel to ${updated.safetyAlertsChannel.name}`))\n   *  .catch(console.error);\n   */\n  async setSafetyAlertsChannel(safetyAlertsChannel, reason) {\n    return this.edit({ safetyAlertsChannel, reason });\n  }\n\n  /**\n   * Edits the guild's widget settings.\n   *\n   * @param {GuildWidgetSettingsData} settings The widget settings for the guild\n   * @param {string} [reason] Reason for changing the guild's widget settings\n   * @returns {Promise<Guild>}\n   */\n  async setWidgetSettings(settings, reason) {\n    await this.client.rest.patch(Routes.guildWidgetSettings(this.id), {\n      body: {\n        enabled: settings.enabled,\n        channel_id: this.channels.resolveId(settings.channel),\n      },\n      reason,\n    });\n    return this;\n  }\n\n  /**\n   * Leaves the guild.\n   *\n   * @returns {Promise<Guild>}\n   * @example\n   * // Leave a guild\n   * guild.leave()\n   *   .then(guild => console.log(`Left the guild: ${guild.name}`))\n   *   .catch(console.error);\n   */\n  async leave() {\n    await this.client.rest.delete(Routes.userGuild(this.id));\n    return this;\n  }\n\n  /**\n   * Sets whether this guild's invites are disabled.\n   *\n   * @param {boolean} [disabled=true] Whether the invites are disabled\n   * @returns {Promise<Guild>}\n   */\n  async disableInvites(disabled = true) {\n    const features = this.features.filter(feature => feature !== GuildFeature.InvitesDisabled);\n    if (disabled) features.push(GuildFeature.InvitesDisabled);\n    return this.edit({ features });\n  }\n\n  /**\n   * Sets the incident actions for a guild.\n   *\n   * @param {IncidentActionsEditOptions} incidentActions The incident actions to set\n   * @returns {Promise<IncidentActions>}\n   */\n  async setIncidentActions(incidentActions) {\n    return this.client.guilds.setIncidentActions(this.id, incidentActions);\n  }\n\n  /**\n   * Whether this guild equals another guild. It compares all properties, so for most operations\n   * it is advisable to just compare `guild.id === guild2.id` as it is much faster and is often\n   * what most users need.\n   *\n   * @param {Guild} guild The guild to compare with\n   * @returns {boolean}\n   */\n  equals(guild) {\n    return (\n      guild &&\n      guild instanceof this.constructor &&\n      this.id === guild.id &&\n      this.available === guild.available &&\n      this.splash === guild.splash &&\n      this.discoverySplash === guild.discoverySplash &&\n      this.name === guild.name &&\n      this.memberCount === guild.memberCount &&\n      this.large === guild.large &&\n      this.icon === guild.icon &&\n      this.ownerId === guild.ownerId &&\n      this.verificationLevel === guild.verificationLevel &&\n      (this.features === guild.features ||\n        (this.features.length === guild.features.length &&\n          this.features.every((feat, index) => feat === guild.features[index])))\n    );\n  }\n\n  toJSON() {\n    const json = super.toJSON({\n      available: false,\n      createdTimestamp: true,\n      nameAcronym: true,\n      presences: false,\n      voiceStates: false,\n    });\n    json.iconURL = this.iconURL();\n    json.splashURL = this.splashURL();\n    json.discoverySplashURL = this.discoverySplashURL();\n    json.bannerURL = this.bannerURL();\n    return json;\n  }\n\n  /**\n   * The voice state adapter for this guild that can be used with `@discordjs/voice` to play audio in voice\n   * and stage channels.\n   *\n   * @type {Function}\n   * @readonly\n   */\n  get voiceAdapterCreator() {\n    return methods => {\n      this.client.voice.adapters.set(this.id, methods);\n      return {\n        sendPayload: data => {\n          this.client.ws.send(this.shardId, data);\n          return true;\n        },\n        destroy: () => {\n          this.client.voice.adapters.delete(this.id);\n        },\n      };\n    };\n  }\n\n  /**\n   * Creates a collection of this guild's roles, sorted by their position and ids.\n   *\n   * @returns {Collection<Snowflake, Role>}\n   * @private\n   */\n  _sortedRoles() {\n    return discordSort(this.roles.cache);\n  }\n\n  /**\n   * Creates a collection of this guild's or a specific category's channels, sorted by their position and ids.\n   *\n   * @param {GuildChannel} [channel] Category to get the channels of\n   * @returns {Collection<Snowflake, GuildChannel>}\n   * @private\n   */\n  _sortedChannels(channel) {\n    const channelIsCategory = channel.type === ChannelType.GuildCategory;\n    const types = getSortableGroupTypes(channel.type);\n    return discordSort(\n      this.channels.cache.filter(\n        ({ parentId, type }) => types.includes(type) && (channelIsCategory || parentId === channel.parentId),\n      ),\n    );\n  }\n}\n\nexports.Guild = Guild;\n"
  },
  {
    "path": "packages/discord.js/src/structures/GuildAuditLogs.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { flatten } = require('../util/Util.js');\nconst { ApplicationCommand } = require('./ApplicationCommand.js');\nconst { GuildAuditLogsEntry } = require('./GuildAuditLogsEntry.js');\nconst { Integration } = require('./Integration.js');\nconst { Webhook } = require('./Webhook.js');\n\n/**\n * Audit logs entries are held in this class.\n */\nclass GuildAuditLogs {\n  constructor(guild, data) {\n    if (data.users) for (const user of data.users) guild.client.users._add(user);\n    if (data.threads) for (const thread of data.threads) guild.client.channels._add(thread, guild);\n    /**\n     * Cached webhooks\n     *\n     * @type {Collection<Snowflake, Webhook>}\n     * @private\n     */\n    this.webhooks = new Collection();\n    if (data.webhooks) {\n      for (const hook of data.webhooks) {\n        this.webhooks.set(hook.id, new Webhook(guild.client, hook));\n      }\n    }\n\n    /**\n     * Cached integrations\n     *\n     * @type {Collection<Snowflake|string, Integration>}\n     * @private\n     */\n    this.integrations = new Collection();\n    if (data.integrations) {\n      for (const integration of data.integrations) {\n        this.integrations.set(integration.id, new Integration(guild.client, integration, guild));\n      }\n    }\n\n    /**\n     * Cached {@link GuildScheduledEvent}s.\n     *\n     * @type {Collection<Snowflake, GuildScheduledEvent>}\n     * @private\n     */\n    this.guildScheduledEvents = data.guild_scheduled_events.reduce(\n      (guildScheduledEvents, guildScheduledEvent) =>\n        guildScheduledEvents.set(guildScheduledEvent.id, guild.scheduledEvents._add(guildScheduledEvent)),\n      new Collection(),\n    );\n\n    /**\n     * Cached application commands, includes application commands from other applications\n     *\n     * @type {Collection<Snowflake, ApplicationCommand>}\n     * @private\n     */\n    this.applicationCommands = new Collection();\n    if (data.application_commands) {\n      for (const command of data.application_commands) {\n        this.applicationCommands.set(command.id, new ApplicationCommand(guild.client, command, guild));\n      }\n    }\n\n    /**\n     * Cached auto moderation rules.\n     *\n     * @type {Collection<Snowflake, AutoModerationRule>}\n     * @private\n     */\n    this.autoModerationRules = data.auto_moderation_rules.reduce(\n      (autoModerationRules, autoModerationRule) =>\n        autoModerationRules.set(autoModerationRule.id, guild.autoModerationRules._add(autoModerationRule)),\n      new Collection(),\n    );\n\n    /**\n     * The entries for this guild's audit logs\n     *\n     * @type {Collection<Snowflake, GuildAuditLogsEntry>}\n     */\n    this.entries = new Collection();\n    for (const item of data.audit_log_entries) {\n      const entry = new GuildAuditLogsEntry(guild, item, this);\n      this.entries.set(entry.id, entry);\n    }\n  }\n\n  toJSON() {\n    return flatten(this);\n  }\n}\n\nexports.GuildAuditLogs = GuildAuditLogs;\n"
  },
  {
    "path": "packages/discord.js/src/structures/GuildAuditLogsEntry.js",
    "content": "'use strict';\n\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { AuditLogOptionsType, AuditLogEvent } = require('discord-api-types/v10');\nconst { Partials } = require('../util/Partials.js');\nconst { flatten } = require('../util/Util.js');\nconst { AutoModerationRule } = require('./AutoModerationRule.js');\nconst { GuildInvite } = require('./GuildInvite.js');\nconst { GuildOnboardingPrompt } = require('./GuildOnboardingPrompt.js');\nconst { GuildScheduledEvent } = require('./GuildScheduledEvent.js');\nconst { Integration } = require('./Integration.js');\nconst { StageInstance } = require('./StageInstance.js');\nconst { Sticker } = require('./Sticker.js');\nconst { Webhook } = require('./Webhook.js');\n\nconst Targets = {\n  Guild: 'Guild',\n  GuildScheduledEvent: 'GuildScheduledEvent',\n  Channel: 'Channel',\n  User: 'User',\n  Role: 'Role',\n  Invite: 'Invite',\n  Webhook: 'Webhook',\n  Emoji: 'Emoji',\n  Message: 'Message',\n  Integration: 'Integration',\n  StageInstance: 'StageInstance',\n  Sticker: 'Sticker',\n  Thread: 'Thread',\n  ApplicationCommand: 'ApplicationCommand',\n  AutoModeration: 'AutoModeration',\n  GuildOnboardingPrompt: 'GuildOnboardingPrompt',\n  SoundboardSound: 'SoundboardSound',\n  Unknown: 'Unknown',\n};\n\n/**\n * The target of a guild audit log entry. It can be one of:\n * - A guild\n * - A channel\n * - A user\n * - A role\n * - An invite\n * - A webhook\n * - A guild emoji\n * - An integration\n * - A stage instance\n * - A sticker\n * - A guild scheduled event\n * - A thread\n * - An application command\n * - An auto moderation rule\n * - A guild onboarding prompt\n * - A soundboard sound\n * - An object with an id key if target was deleted or fake entity\n * - An object where the keys represent either the new value or the old value\n *\n * @typedef {?(Object|Guild|BaseChannel|User|Role|Invite|Webhook|GuildEmoji|Integration|StageInstance|Sticker|\n * GuildScheduledEvent|ApplicationCommand|AutoModerationRule|GuildOnboardingPrompt|SoundboardSound)} AuditLogEntryTarget\n */\n\n/**\n * The action type of an entry. Here are the available types:\n * - Create\n * - Delete\n * - Update\n * - All\n *\n * @typedef {string} AuditLogActionType\n */\n\n/**\n * The target type of an entry. Here are the available types:\n * - Guild\n * - Channel\n * - User\n * - Role\n * - Invite\n * - Webhook\n * - Emoji\n * - Message\n * - Integration\n * - StageInstance\n * - Sticker\n * - Thread\n * - GuildScheduledEvent\n * - ApplicationCommand\n * - GuildOnboardingPrompt\n * - SoundboardSound\n * - AutoModeration\n * - Unknown\n *\n * @typedef {string} AuditLogTargetType\n */\n\n/**\n * Constructs an object of known properties for a structure from an array of changes.\n *\n * @param {AuditLogChange[]} changes The array of changes\n * @param {Object} [initialData={}] The initial data passed to the function\n * @returns {Object}\n * @ignore\n */\nfunction changesReduce(changes, initialData = {}) {\n  return changes.reduce((accumulator, change) => {\n    accumulator[change.key] = change.new ?? change.old;\n    return accumulator;\n  }, initialData);\n}\n\n/**\n * Audit logs entry.\n */\nclass GuildAuditLogsEntry {\n  /**\n   * Key mirror of all available audit log targets.\n   *\n   * @type {Object<string, string>}\n   * @memberof GuildAuditLogsEntry\n   */\n  static Targets = Targets;\n\n  constructor(guild, data, logs) {\n    /**\n     * The target type of this entry\n     *\n     * @type {AuditLogTargetType}\n     */\n    this.targetType = GuildAuditLogsEntry.targetType(data.action_type);\n    const targetType = this.targetType;\n\n    /**\n     * The action type of this entry\n     *\n     * @type {AuditLogActionType}\n     */\n    this.actionType = GuildAuditLogsEntry.actionType(data.action_type);\n\n    /**\n     * The type of action that occurred.\n     *\n     * @type {AuditLogEvent}\n     */\n    this.action = data.action_type;\n\n    /**\n     * The reason of this entry\n     *\n     * @type {?string}\n     */\n    this.reason = data.reason ?? null;\n\n    /**\n     * The id of the user that executed this entry\n     *\n     * @type {?Snowflake}\n     */\n    this.executorId = data.user_id;\n\n    /**\n     * The user that executed this entry\n     *\n     * @type {?User}\n     */\n    this.executor = data.user_id\n      ? guild.client.options.partials.includes(Partials.User)\n        ? guild.client.users._add({ id: data.user_id })\n        : (guild.client.users.cache.get(data.user_id) ?? null)\n      : null;\n\n    /**\n     * An entry in the audit log representing a specific change.\n     *\n     * @typedef {Object} AuditLogChange\n     * @property {string} key The property that was changed, e.g. `nick` for nickname changes\n     * <warn>For application command permissions updates the key is the id of the user, channel,\n     * role, or a permission constant that was updated instead of an actual property name</warn>\n     * @property {*} [old] The old value of the change, e.g. for nicknames, the old nickname\n     * @property {*} [new] The new value of the change, e.g. for nicknames, the new nickname\n     */\n\n    /**\n     * Specific property changes\n     *\n     * @type {AuditLogChange[]}\n     */\n    this.changes =\n      data.changes?.map(change => ({\n        key: change.key,\n        ...('old_value' in change ? { old: change.old_value } : {}),\n        ...('new_value' in change ? { new: change.new_value } : {}),\n      })) ?? [];\n\n    /**\n     * The entry's id\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    /**\n     * Any extra data from the entry\n     *\n     * @type {?(Object|Role|GuildMember)}\n     */\n    this.extra = null;\n    switch (data.action_type) {\n      case AuditLogEvent.MemberPrune:\n        this.extra = {\n          removed: Number(data.options.members_removed),\n          days: Number(data.options.delete_member_days),\n        };\n        break;\n\n      case AuditLogEvent.MemberMove:\n      case AuditLogEvent.MessageDelete:\n        this.extra = {\n          channel: guild.channels.cache.get(data.options.channel_id) ?? { id: data.options.channel_id },\n          count: Number(data.options.count),\n        };\n        break;\n\n      case AuditLogEvent.MessagePin:\n      case AuditLogEvent.MessageUnpin:\n        this.extra = {\n          channel: guild.client.channels.cache.get(data.options.channel_id) ?? { id: data.options.channel_id },\n          messageId: data.options.message_id,\n        };\n        break;\n\n      case AuditLogEvent.MessageBulkDelete:\n      case AuditLogEvent.MemberDisconnect:\n        this.extra = {\n          count: Number(data.options.count),\n        };\n        break;\n\n      case AuditLogEvent.ChannelOverwriteCreate:\n      case AuditLogEvent.ChannelOverwriteUpdate:\n      case AuditLogEvent.ChannelOverwriteDelete:\n        switch (data.options.type) {\n          case AuditLogOptionsType.Role:\n            this.extra = guild.roles.cache.get(data.options.id) ?? {\n              id: data.options.id,\n              name: data.options.role_name,\n              type: AuditLogOptionsType.Role,\n            };\n            break;\n\n          case AuditLogOptionsType.Member:\n            this.extra = guild.members.cache.get(data.options.id) ?? {\n              id: data.options.id,\n              type: AuditLogOptionsType.Member,\n            };\n            break;\n\n          default:\n            break;\n        }\n\n        break;\n\n      case AuditLogEvent.StageInstanceCreate:\n      case AuditLogEvent.StageInstanceDelete:\n      case AuditLogEvent.StageInstanceUpdate:\n        this.extra = {\n          channel: guild.client.channels.cache.get(data.options?.channel_id) ?? { id: data.options?.channel_id },\n        };\n        break;\n\n      case AuditLogEvent.ApplicationCommandPermissionUpdate:\n        this.extra = {\n          applicationId: data.options.application_id,\n        };\n        break;\n\n      case AuditLogEvent.AutoModerationBlockMessage:\n      case AuditLogEvent.AutoModerationFlagToChannel:\n      case AuditLogEvent.AutoModerationUserCommunicationDisabled:\n        this.extra = {\n          autoModerationRuleName: data.options.auto_moderation_rule_name,\n          autoModerationRuleTriggerType: data.options.auto_moderation_rule_trigger_type,\n          channel: guild.client.channels.cache.get(data.options?.channel_id) ?? { id: data.options?.channel_id },\n        };\n        break;\n\n      case AuditLogEvent.MemberKick:\n      case AuditLogEvent.MemberRoleUpdate: {\n        if (data.integration_type) {\n          this.extra = {\n            integrationType: data.integration_type,\n          };\n        }\n\n        break;\n      }\n\n      default:\n        break;\n    }\n\n    /**\n     * The id of the target of this entry\n     *\n     * @type {?Snowflake}\n     */\n    this.targetId = data.target_id;\n\n    /**\n     * The target of this entry\n     *\n     * @type {?AuditLogEntryTarget}\n     */\n    this.target = null;\n    if (targetType === Targets.Unknown) {\n      this.target = changesReduce(this.changes);\n      this.target.id = data.target_id;\n      // MemberDisconnect and similar types do not provide a target_id.\n    } else if (targetType === Targets.User && data.target_id) {\n      this.target = guild.client.options.partials.includes(Partials.User)\n        ? guild.client.users._add({ id: data.target_id })\n        : (guild.client.users.cache.get(data.target_id) ?? null);\n    } else if (targetType === Targets.Guild) {\n      this.target = guild.client.guilds.cache.get(data.target_id);\n    } else if (targetType === Targets.Webhook) {\n      this.target =\n        logs?.webhooks.get(data.target_id) ??\n        new Webhook(\n          guild.client,\n          changesReduce(this.changes, {\n            id: data.target_id,\n            guild_id: guild.id,\n          }),\n        );\n    } else if (targetType === Targets.Invite) {\n      const inviteChange = this.changes.find(({ key }) => key === 'code');\n\n      this.target =\n        guild.invites.cache.get(inviteChange.new ?? inviteChange.old) ??\n        new GuildInvite(guild.client, changesReduce(this.changes, { guild }));\n    } else if (targetType === Targets.Message) {\n      // Discord sends a channel id for the MessageBulkDelete action type.\n      this.target =\n        data.action_type === AuditLogEvent.MessageBulkDelete\n          ? (guild.channels.cache.get(data.target_id) ?? { id: data.target_id })\n          : (guild.client.users.cache.get(data.target_id) ?? null);\n    } else if (targetType === Targets.Integration) {\n      this.target =\n        logs?.integrations.get(data.target_id) ??\n        new Integration(guild.client, changesReduce(this.changes, { id: data.target_id }), guild);\n    } else if (targetType === Targets.Channel || targetType === Targets.Thread) {\n      this.target = guild.channels.cache.get(data.target_id) ?? changesReduce(this.changes, { id: data.target_id });\n    } else if (targetType === Targets.StageInstance) {\n      this.target =\n        guild.stageInstances.cache.get(data.target_id) ??\n        new StageInstance(\n          guild.client,\n          changesReduce(this.changes, {\n            id: data.target_id,\n            channel_id: data.options?.channel_id,\n            guild_id: guild.id,\n          }),\n        );\n    } else if (targetType === Targets.Sticker) {\n      this.target =\n        guild.stickers.cache.get(data.target_id) ??\n        new Sticker(guild.client, changesReduce(this.changes, { id: data.target_id }));\n    } else if (targetType === Targets.GuildScheduledEvent) {\n      this.target =\n        guild.scheduledEvents.cache.get(data.target_id) ??\n        new GuildScheduledEvent(guild.client, changesReduce(this.changes, { id: data.target_id, guild_id: guild.id }));\n    } else if (targetType === Targets.ApplicationCommand) {\n      this.target = logs?.applicationCommands.get(data.target_id) ?? { id: data.target_id };\n    } else if (targetType === Targets.AutoModeration) {\n      this.target =\n        guild.autoModerationRules.cache.get(data.target_id) ??\n        new AutoModerationRule(\n          guild.client,\n          changesReduce(this.changes, { id: data.target_id, guild_id: guild.id }),\n          guild,\n        );\n    } else if (targetType === Targets.GuildOnboardingPrompt) {\n      this.target =\n        data.action_type === AuditLogEvent.OnboardingPromptCreate\n          ? new GuildOnboardingPrompt(guild.client, changesReduce(this.changes, { id: data.target_id }), guild.id)\n          : changesReduce(this.changes, { id: data.target_id });\n    } else if (targetType === Targets.Role) {\n      this.target = guild.roles.cache.get(data.target_id) ?? { id: data.target_id };\n    } else if (targetType === Targets.Emoji) {\n      this.target = guild.emojis.cache.get(data.target_id) ?? { id: data.target_id };\n    } else if (targetType === Targets.SoundboardSound) {\n      this.target = guild.soundboardSounds.cache.get(data.target_id) ?? { id: data.target_id };\n    } else if (data.target_id) {\n      this.target = { id: data.target_id };\n    }\n  }\n\n  /**\n   * Finds the target type of a guild audit log entry.\n   *\n   * @param {AuditLogEvent} target The action target\n   * @returns {AuditLogTargetType}\n   */\n  static targetType(target) {\n    if (target < 10) return Targets.Guild;\n    if (target < 20) return Targets.Channel;\n    if (target < 30) return Targets.User;\n    if (target < 40) return Targets.Role;\n    if (target < 50) return Targets.Invite;\n    if (target < 60) return Targets.Webhook;\n    if (target < 70) return Targets.Emoji;\n    if (target < 80) return Targets.Message;\n    if (target < 83) return Targets.Integration;\n    if (target < 86) return Targets.StageInstance;\n    if (target < 100) return Targets.Sticker;\n    if (target < 110) return Targets.GuildScheduledEvent;\n    if (target < 120) return Targets.Thread;\n    if (target < 130) return Targets.ApplicationCommand;\n    if (target < 140) return Targets.SoundboardSound;\n    if (target < 143) return Targets.AutoModeration;\n    if (target < 146) return Targets.User;\n    if (target >= 163 && target <= 165) return Targets.GuildOnboardingPrompt;\n    return Targets.Unknown;\n  }\n\n  /**\n   * Finds the action type from the guild audit log entry action.\n   *\n   * @param {AuditLogEvent} action The action target\n   * @returns {AuditLogActionType}\n   */\n  static actionType(action) {\n    if (\n      [\n        AuditLogEvent.ChannelCreate,\n        AuditLogEvent.ChannelOverwriteCreate,\n        AuditLogEvent.MemberBanRemove,\n        AuditLogEvent.BotAdd,\n        AuditLogEvent.RoleCreate,\n        AuditLogEvent.InviteCreate,\n        AuditLogEvent.WebhookCreate,\n        AuditLogEvent.EmojiCreate,\n        AuditLogEvent.MessagePin,\n        AuditLogEvent.IntegrationCreate,\n        AuditLogEvent.StageInstanceCreate,\n        AuditLogEvent.StickerCreate,\n        AuditLogEvent.GuildScheduledEventCreate,\n        AuditLogEvent.ThreadCreate,\n        AuditLogEvent.SoundboardSoundCreate,\n        AuditLogEvent.AutoModerationRuleCreate,\n        AuditLogEvent.OnboardingPromptCreate,\n      ].includes(action)\n    ) {\n      return 'Create';\n    }\n\n    if (\n      [\n        AuditLogEvent.ChannelDelete,\n        AuditLogEvent.ChannelOverwriteDelete,\n        AuditLogEvent.MemberKick,\n        AuditLogEvent.MemberPrune,\n        AuditLogEvent.MemberBanAdd,\n        AuditLogEvent.MemberDisconnect,\n        AuditLogEvent.RoleDelete,\n        AuditLogEvent.InviteDelete,\n        AuditLogEvent.WebhookDelete,\n        AuditLogEvent.EmojiDelete,\n        AuditLogEvent.MessageDelete,\n        AuditLogEvent.MessageBulkDelete,\n        AuditLogEvent.MessageUnpin,\n        AuditLogEvent.IntegrationDelete,\n        AuditLogEvent.StageInstanceDelete,\n        AuditLogEvent.StickerDelete,\n        AuditLogEvent.GuildScheduledEventDelete,\n        AuditLogEvent.ThreadDelete,\n        AuditLogEvent.SoundboardSoundDelete,\n        AuditLogEvent.AutoModerationRuleDelete,\n        AuditLogEvent.OnboardingPromptDelete,\n      ].includes(action)\n    ) {\n      return 'Delete';\n    }\n\n    if (\n      [\n        AuditLogEvent.GuildUpdate,\n        AuditLogEvent.ChannelUpdate,\n        AuditLogEvent.ChannelOverwriteUpdate,\n        AuditLogEvent.MemberUpdate,\n        AuditLogEvent.MemberRoleUpdate,\n        AuditLogEvent.MemberMove,\n        AuditLogEvent.RoleUpdate,\n        AuditLogEvent.InviteUpdate,\n        AuditLogEvent.WebhookUpdate,\n        AuditLogEvent.EmojiUpdate,\n        AuditLogEvent.IntegrationUpdate,\n        AuditLogEvent.StageInstanceUpdate,\n        AuditLogEvent.StickerUpdate,\n        AuditLogEvent.GuildScheduledEventUpdate,\n        AuditLogEvent.ThreadUpdate,\n        AuditLogEvent.ApplicationCommandPermissionUpdate,\n        AuditLogEvent.SoundboardSoundUpdate,\n        AuditLogEvent.AutoModerationRuleUpdate,\n        AuditLogEvent.AutoModerationBlockMessage,\n        AuditLogEvent.AutoModerationFlagToChannel,\n        AuditLogEvent.AutoModerationUserCommunicationDisabled,\n        AuditLogEvent.OnboardingPromptUpdate,\n      ].includes(action)\n    ) {\n      return 'Update';\n    }\n\n    return 'All';\n  }\n\n  /**\n   * The timestamp this entry was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time this entry was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * Checks whether this GuildAuditLogsEntry is of the specified {@link AuditLogEvent} type.\n   *\n   * @param {AuditLogEvent} action The type to check for\n   * @returns {boolean}\n   */\n  isAction(action) {\n    return this.action === action;\n  }\n\n  toJSON() {\n    return flatten(this, { createdTimestamp: true });\n  }\n}\n\nexports.GuildAuditLogsEntry = GuildAuditLogsEntry;\n"
  },
  {
    "path": "packages/discord.js/src/structures/GuildBan.js",
    "content": "'use strict';\n\nconst { Base } = require('./Base.js');\n\n/**\n * Represents a ban in a guild on Discord.\n *\n * @extends {Base}\n */\nclass GuildBan extends Base {\n  constructor(client, data, guild) {\n    super(client);\n\n    /**\n     * The guild in which the ban is\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('user' in data) {\n      /**\n       * The user this ban applies to\n       *\n       * @type {User}\n       */\n      this.user = this.client.users._add(data.user, true);\n    }\n\n    if ('reason' in data) {\n      /**\n       * The reason for the ban\n       *\n       * @type {?string}\n       */\n      this.reason = data.reason;\n    }\n  }\n\n  /**\n   * Whether this GuildBan is partial. If the reason is not provided the value is null\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get partial() {\n    return !('reason' in this);\n  }\n\n  /**\n   * Fetches this GuildBan.\n   *\n   * @param {boolean} [force=true] Whether to skip the cache check and request the API\n   * @returns {Promise<GuildBan>}\n   */\n  async fetch(force = true) {\n    return this.guild.bans.fetch({ user: this.user, cache: true, force });\n  }\n}\n\nexports.GuildBan = GuildBan;\n"
  },
  {
    "path": "packages/discord.js/src/structures/GuildChannel.js",
    "content": "'use strict';\n\nconst { Snowflake } = require('@sapphire/snowflake');\nconst { PermissionFlagsBits, ChannelType } = require('discord-api-types/v10');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { PermissionOverwriteManager } = require('../managers/PermissionOverwriteManager.js');\nconst { VoiceBasedChannelTypes } = require('../util/Constants.js');\nconst { PermissionsBitField } = require('../util/PermissionsBitField.js');\nconst { getSortableGroupTypes } = require('../util/Util.js');\nconst { BaseChannel } = require('./BaseChannel.js');\n\n/**\n * Represents a guild channel from any of the following:\n * - {@link TextChannel}\n * - {@link VoiceChannel}\n * - {@link CategoryChannel}\n * - {@link AnnouncementChannel}\n * - {@link StageChannel}\n * - {@link ForumChannel}\n * - {@link MediaChannel}\n *\n * @extends {BaseChannel}\n * @abstract\n */\nclass GuildChannel extends BaseChannel {\n  constructor(guild, data, client, immediatePatch = true) {\n    super(client, data, false);\n\n    /**\n     * The guild the channel is in\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n\n    /**\n     * The id of the guild the channel is in\n     *\n     * @type {Snowflake}\n     */\n    this.guildId = guild?.id ?? data.guild_id;\n    /**\n     * A manager of permission overwrites that belong to this channel\n     *\n     * @type {PermissionOverwriteManager}\n     */\n    this.permissionOverwrites = new PermissionOverwriteManager(this);\n\n    if (data && immediatePatch) this._patch(data);\n  }\n\n  _patch(data) {\n    super._patch(data);\n\n    if ('name' in data) {\n      /**\n       * The name of the guild channel\n       *\n       * @type {string}\n       */\n      this.name = data.name;\n    }\n\n    if ('position' in data) {\n      /**\n       * The raw position of the channel from Discord\n       *\n       * @type {number}\n       */\n      this.rawPosition = data.position;\n    }\n\n    if ('guild_id' in data) {\n      this.guildId = data.guild_id;\n    }\n\n    if ('parent_id' in data) {\n      /**\n       * The id of the category parent of this channel\n       *\n       * @type {?Snowflake}\n       */\n      this.parentId = data.parent_id;\n    } else {\n      this.parentId ??= null;\n    }\n\n    if ('permission_overwrites' in data) {\n      this.permissionOverwrites.cache.clear();\n      for (const overwrite of data.permission_overwrites) {\n        this.permissionOverwrites._add(overwrite);\n      }\n    }\n  }\n\n  _clone() {\n    const clone = super._clone();\n    clone.permissionOverwrites = new PermissionOverwriteManager(clone, this.permissionOverwrites.cache.values());\n    return clone;\n  }\n\n  /**\n   * The category parent of this channel\n   *\n   * @type {?CategoryChannel}\n   * @readonly\n   */\n  get parent() {\n    return this.guild.channels.resolve(this.parentId);\n  }\n\n  /**\n   * If the permissionOverwrites match the parent channel, null if no parent\n   *\n   * @type {?boolean}\n   * @readonly\n   */\n  get permissionsLocked() {\n    const { parent } = this;\n    if (!parent) return null;\n\n    // Get all overwrites\n    const overwriteIds = new Set([\n      ...this.permissionOverwrites.cache.keys(),\n      ...parent.permissionOverwrites.cache.keys(),\n    ]);\n\n    // Compare all overwrites\n    return [...overwriteIds].every(key => {\n      const channelVal = this.permissionOverwrites.cache.get(key);\n      const parentVal = parent.permissionOverwrites.cache.get(key);\n\n      // Handle empty overwrite\n      if (\n        key === this.guildId &&\n        ((!channelVal &&\n          parentVal.deny.bitfield === PermissionsBitField.DefaultBit &&\n          parentVal.allow.bitfield === PermissionsBitField.DefaultBit) ||\n          (!parentVal &&\n            channelVal.deny.bitfield === PermissionsBitField.DefaultBit &&\n            channelVal.allow.bitfield === PermissionsBitField.DefaultBit))\n      ) {\n        return true;\n      }\n\n      // Compare overwrites\n      return (\n        channelVal !== undefined &&\n        parentVal !== undefined &&\n        channelVal.deny.bitfield === parentVal.deny.bitfield &&\n        channelVal.allow.bitfield === parentVal.allow.bitfield\n      );\n    });\n  }\n\n  /**\n   * The position of the channel\n   *\n   * @type {number}\n   * @readonly\n   */\n  get position() {\n    const selfIsCategory = this.type === ChannelType.GuildCategory;\n    const types = getSortableGroupTypes(this.type);\n\n    let count = 0;\n    for (const channel of this.guild.channels.cache.values()) {\n      if (!types.includes(channel.type)) continue;\n      if (!selfIsCategory && channel.parentId !== this.parentId) continue;\n      if (this.rawPosition === channel.rawPosition) {\n        if (Snowflake.compare(channel.id, this.id) === -1) count++;\n      } else if (this.rawPosition > channel.rawPosition) {\n        count++;\n      }\n    }\n\n    return count;\n  }\n\n  /**\n   * Gets the overall set of permissions for a member or role in this channel, taking into account channel overwrites.\n   *\n   * @param {UserResolvable|RoleResolvable} memberOrRole The member or role to obtain the overall permissions for\n   * @param {boolean} [checkAdmin=true] Whether having the {@link PermissionFlagsBits.Administrator} permission\n   * will return all permissions\n   * @returns {?Readonly<PermissionsBitField>}\n   */\n  permissionsFor(memberOrRole, checkAdmin = true) {\n    const member = this.guild.members.resolve(memberOrRole);\n    if (member) return this.memberPermissions(member, checkAdmin);\n    const role = this.guild.roles.resolve(memberOrRole);\n    return role && this.rolePermissions(role, checkAdmin);\n  }\n\n  overwritesFor(member, verified = false, roles = null) {\n    const resolvedMember = verified ? member : this.guild.members.resolve(member);\n    if (!resolvedMember) return [];\n\n    const resolvedRoles = roles ?? resolvedMember.roles.cache;\n    const roleOverwrites = [];\n    let memberOverwrites;\n    let everyoneOverwrites;\n\n    for (const overwrite of this.permissionOverwrites.cache.values()) {\n      if (overwrite.id === this.guild.id) {\n        everyoneOverwrites = overwrite;\n      } else if (resolvedRoles.has(overwrite.id)) {\n        roleOverwrites.push(overwrite);\n      } else if (overwrite.id === resolvedMember.id) {\n        memberOverwrites = overwrite;\n      }\n    }\n\n    return {\n      everyone: everyoneOverwrites,\n      roles: roleOverwrites,\n      member: memberOverwrites,\n    };\n  }\n\n  /**\n   * Gets the overall set of permissions for a member in this channel, taking into account channel overwrites.\n   *\n   * @param {GuildMember} member The member to obtain the overall permissions for\n   * @param {boolean} checkAdmin Whether having the {@link PermissionFlagsBits.Administrator} permission\n   * will return all permissions\n   * @returns {Readonly<PermissionsBitField>}\n   * @private\n   */\n  memberPermissions(member, checkAdmin) {\n    if (checkAdmin && member.id === this.guild.ownerId) {\n      return new PermissionsBitField(PermissionsBitField.All).freeze();\n    }\n\n    const roles = member.roles.cache;\n    const permissions = new PermissionsBitField(roles.map(role => role.permissions));\n\n    if (checkAdmin && permissions.has(PermissionFlagsBits.Administrator)) {\n      return new PermissionsBitField(PermissionsBitField.All).freeze();\n    }\n\n    const overwrites = this.overwritesFor(member, true, roles);\n\n    return permissions\n      .remove(overwrites.everyone?.deny ?? PermissionsBitField.DefaultBit)\n      .add(overwrites.everyone?.allow ?? PermissionsBitField.DefaultBit)\n      .remove(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.deny) : PermissionsBitField.DefaultBit)\n      .add(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.allow) : PermissionsBitField.DefaultBit)\n      .remove(overwrites.member?.deny ?? PermissionsBitField.DefaultBit)\n      .add(overwrites.member?.allow ?? PermissionsBitField.DefaultBit)\n      .freeze();\n  }\n\n  /**\n   * Gets the overall set of permissions for a role in this channel, taking into account channel overwrites.\n   *\n   * @param {Role} role The role to obtain the overall permissions for\n   * @param {boolean} checkAdmin Whether having the {@link PermissionFlagsBits.Administrator} permission\n   * will return all permissions\n   * @returns {Readonly<PermissionsBitField>}\n   * @private\n   */\n  rolePermissions(role, checkAdmin) {\n    if (checkAdmin && role.permissions.has(PermissionFlagsBits.Administrator)) {\n      return new PermissionsBitField(PermissionsBitField.All).freeze();\n    }\n\n    const basePermissions = new PermissionsBitField([role.permissions, role.guild.roles.everyone.permissions]);\n    const everyoneOverwrites = this.permissionOverwrites.cache.get(this.guild.id);\n    const roleOverwrites = this.permissionOverwrites.cache.get(role.id);\n\n    return basePermissions\n      .remove(everyoneOverwrites?.deny ?? PermissionsBitField.DefaultBit)\n      .add(everyoneOverwrites?.allow ?? PermissionsBitField.DefaultBit)\n      .remove(roleOverwrites?.deny ?? PermissionsBitField.DefaultBit)\n      .add(roleOverwrites?.allow ?? PermissionsBitField.DefaultBit)\n      .freeze();\n  }\n\n  /**\n   * Locks in the permission overwrites from the parent channel.\n   *\n   * @returns {Promise<GuildChannel>}\n   */\n  async lockPermissions() {\n    if (!this.parent) throw new DiscordjsError(ErrorCodes.GuildChannelOrphan);\n    const permissionOverwrites = this.parent.permissionOverwrites.cache.map(overwrite => overwrite.toJSON());\n    return this.edit({ permissionOverwrites });\n  }\n\n  /**\n   * A collection of cached members of this channel, mapped by their ids.\n   * Members that can view this channel, if the channel is text-based.\n   * Members in the channel, if the channel is voice-based.\n   *\n   * @type {Collection<Snowflake, GuildMember>}\n   * @readonly\n   */\n  get members() {\n    return this.guild.members.cache.filter(member =>\n      this.permissionsFor(member).has(PermissionFlagsBits.ViewChannel, false),\n    );\n  }\n\n  /**\n   * Edits the channel.\n   *\n   * @param {GuildChannelEditOptions} options The options to provide\n   * @returns {Promise<GuildChannel>}\n   * @example\n   * // Edit a channel\n   * channel.edit({ name: 'new-channel' })\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async edit(options) {\n    return this.guild.channels.edit(this, options);\n  }\n\n  /**\n   * Sets a new name for the guild channel.\n   *\n   * @param {string} name The new name for the guild channel\n   * @param {string} [reason] Reason for changing the guild channel's name\n   * @returns {Promise<GuildChannel>}\n   * @example\n   * // Set a new channel name\n   * channel.setName('not_general')\n   *   .then(newChannel => console.log(`Channel's new name is ${newChannel.name}`))\n   *   .catch(console.error);\n   */\n  async setName(name, reason) {\n    return this.edit({ name, reason });\n  }\n\n  /**\n   * Options used to set the parent of a channel.\n   *\n   * @typedef {Object} SetParentOptions\n   * @property {boolean} [lockPermissions=false] Whether to lock the permissions to what the parent's permissions are\n   * @property {string} [reason] The reason for modifying the parent of the channel\n   */\n\n  /**\n   * Sets the parent of this channel.\n   *\n   * @param {?CategoryChannelResolvable} channel The category channel to set as the parent\n   * @param {SetParentOptions} [options={}] The options for setting the parent\n   * @returns {Promise<GuildChannel>}\n   * @example\n   * // Add a parent to a channel\n   * message.channel.setParent('355908108431917066')\n   *   .then(channel => console.log(`New parent of ${channel.name}: ${channel.parent.name}`))\n   *   .catch(console.error);\n   * @example\n   * // Move a channel and sync its permissions with the parent\n   * message.channel.setParent('355908108431917066', { lockPermissions: true })\n   *   .then(channel => console.log(`Moved ${message.channel.name} to ${channel.parent.name}`))\n   *   .catch(console.error);\n   */\n  async setParent(channel, { lockPermissions = false, reason } = {}) {\n    return this.edit({\n      parent: channel ?? null,\n      lockPermissions,\n      reason,\n    });\n  }\n\n  /**\n   * Options used to set the position of a channel.\n   *\n   * @typedef {Object} SetChannelPositionOptions\n   * @property {boolean} [relative=false] Whether or not to change the position relative to its current value\n   * @property {string} [reason] The reason for changing the position\n   */\n\n  /**\n   * Sets a new position for the guild channel.\n   *\n   * @param {number} position The new position for the guild channel\n   * @param {SetChannelPositionOptions} [options] Options for setting position\n   * @returns {Promise<GuildChannel>}\n   * @example\n   * // Set a new channel position\n   * channel.setPosition(2)\n   *   .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`))\n   *   .catch(console.error);\n   */\n  async setPosition(position, options = {}) {\n    return this.guild.channels.setPosition(this, position, options);\n  }\n\n  /**\n   * Options used to clone a guild channel.\n   *\n   * @typedef {GuildChannelCreateOptions} GuildChannelCloneOptions\n   * @property {string} [name=this.name] Name of the new channel\n   */\n\n  /**\n   * Clones this channel.\n   *\n   * @param {GuildChannelCloneOptions} [options] The options for cloning this channel\n   * @returns {Promise<GuildChannel>}\n   */\n  async clone(options = {}) {\n    return this.guild.channels.create({\n      name: options.name ?? this.name,\n      permissionOverwrites: this.permissionOverwrites.cache,\n      topic: this.topic,\n      type: this.type,\n      nsfw: this.nsfw,\n      parent: this.parent,\n      bitrate: this.bitrate,\n      userLimit: this.userLimit,\n      rateLimitPerUser: this.rateLimitPerUser,\n      position: this.rawPosition,\n      reason: null,\n      ...options,\n    });\n  }\n\n  /**\n   * Checks if this channel has the same type, topic, position, name, overwrites, and id as another channel.\n   * In most cases, a simple `channel.id === channel2.id` will do, and is much faster too.\n   *\n   * @param {GuildChannel} channel Channel to compare with\n   * @returns {boolean}\n   */\n  equals(channel) {\n    let equal =\n      channel &&\n      this.id === channel.id &&\n      this.type === channel.type &&\n      this.topic === channel.topic &&\n      this.position === channel.position &&\n      this.name === channel.name;\n\n    if (equal) {\n      if (this.permissionOverwrites && channel.permissionOverwrites) {\n        equal = this.permissionOverwrites.cache.equals(channel.permissionOverwrites.cache);\n      } else {\n        equal = !this.permissionOverwrites && !channel.permissionOverwrites;\n      }\n    }\n\n    return equal;\n  }\n\n  /**\n   * Whether the channel is deletable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get deletable() {\n    return this.manageable && this.guild.rulesChannelId !== this.id && this.guild.publicUpdatesChannelId !== this.id;\n  }\n\n  /**\n   * Whether the channel is manageable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get manageable() {\n    const permissions = this.permissionsFor(this.client.user);\n    if (!permissions) return false;\n\n    // This flag allows managing even if timed out\n    if (permissions.has(PermissionFlagsBits.Administrator, false)) return true;\n    if (this.guild.members.me.communicationDisabledUntilTimestamp > Date.now()) return false;\n\n    const baseBitfield = PermissionFlagsBits.ViewChannel | PermissionFlagsBits.ManageChannels;\n    const bitfield = VoiceBasedChannelTypes.includes(this.type)\n      ? baseBitfield | PermissionFlagsBits.Connect\n      : baseBitfield;\n\n    return permissions.has(bitfield, false);\n  }\n\n  /**\n   * Whether the channel is viewable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get viewable() {\n    const permissions = this.permissionsFor(this.client.user);\n    if (!permissions) return false;\n    return permissions.has(PermissionFlagsBits.ViewChannel, false);\n  }\n\n  /**\n   * Deletes this channel.\n   *\n   * @param {string} [reason] Reason for deleting this channel\n   * @returns {Promise<GuildChannel>}\n   * @example\n   * // Delete the channel\n   * channel.delete('making room for new channels')\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async delete(reason) {\n    await this.guild.channels.delete(this.id, reason);\n    return this;\n  }\n}\n\nexports.GuildChannel = GuildChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/GuildEmoji.js",
    "content": "'use strict';\n\nconst { PermissionFlagsBits } = require('discord-api-types/v10');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { GuildEmojiRoleManager } = require('../managers/GuildEmojiRoleManager.js');\nconst { BaseGuildEmoji } = require('./BaseGuildEmoji.js');\n\n/**\n * Represents a custom emoji.\n *\n * @extends {BaseGuildEmoji}\n */\nclass GuildEmoji extends BaseGuildEmoji {\n  constructor(client, data, guild) {\n    super(client, data, guild);\n\n    /**\n     * The user who created this emoji\n     *\n     * @type {?User}\n     */\n    this.author = null;\n\n    /**\n     * Array of role ids this emoji is active for\n     *\n     * @name GuildEmoji#_roles\n     * @type {Snowflake[]}\n     * @private\n     */\n    Object.defineProperty(this, '_roles', { value: [], writable: true });\n\n    this._patch(data);\n  }\n\n  /**\n   * The guild this emoji is part of\n   *\n   * @type {Guild}\n   * @name GuildEmoji#guild\n   */\n\n  _clone() {\n    const clone = super._clone();\n    clone._roles = this._roles.slice();\n    return clone;\n  }\n\n  _patch(data) {\n    super._patch(data);\n\n    if (data.user) this.author = this.client.users._add(data.user);\n    if (data.roles) this._roles = data.roles;\n  }\n\n  /**\n   * Whether the emoji is deletable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get deletable() {\n    if (!this.guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe);\n    return !this.managed && this.guild.members.me.permissions.has(PermissionFlagsBits.ManageGuildExpressions);\n  }\n\n  /**\n   * A manager for roles this emoji is active for.\n   *\n   * @type {GuildEmojiRoleManager}\n   * @readonly\n   */\n  get roles() {\n    return new GuildEmojiRoleManager(this);\n  }\n\n  /**\n   * Fetches the author for this emoji\n   *\n   * @returns {Promise<User>}\n   */\n  async fetchAuthor() {\n    return this.guild.emojis.fetchAuthor(this);\n  }\n\n  /**\n   * Data for editing an emoji.\n   *\n   * @typedef {Object} GuildEmojiEditOptions\n   * @property {string} [name] The name of the emoji\n   * @property {Collection<Snowflake, Role>|RoleResolvable[]} [roles] Roles to restrict emoji to\n   * @property {string} [reason] Reason for editing this emoji\n   */\n\n  /**\n   * Edits the emoji.\n   *\n   * @param {GuildEmojiEditOptions} options The options to provide\n   * @returns {Promise<GuildEmoji>}\n   * @example\n   * // Edit an emoji\n   * emoji.edit({ name: 'newemoji' })\n   *   .then(emoji => console.log(`Edited emoji ${emoji}`))\n   *   .catch(console.error);\n   */\n  async edit(options) {\n    return this.guild.emojis.edit(this.id, options);\n  }\n\n  /**\n   * Sets the name of the emoji.\n   *\n   * @param {string} name The new name for the emoji\n   * @param {string} [reason] Reason for changing the emoji's name\n   * @returns {Promise<GuildEmoji>}\n   */\n  async setName(name, reason) {\n    return this.edit({ name, reason });\n  }\n\n  /**\n   * Deletes the emoji.\n   *\n   * @param {string} [reason] Reason for deleting the emoji\n   * @returns {Promise<GuildEmoji>}\n   */\n  async delete(reason) {\n    await this.guild.emojis.delete(this.id, reason);\n    return this;\n  }\n\n  /**\n   * Whether this emoji is the same as another one.\n   *\n   * @param {GuildEmoji|APIEmoji} other The emoji to compare it to\n   * @returns {boolean}\n   */\n  equals(other) {\n    if (other instanceof GuildEmoji) {\n      return (\n        other.id === this.id &&\n        other.name === this.name &&\n        other.managed === this.managed &&\n        other.available === this.available &&\n        other.requiresColons === this.requiresColons &&\n        other.roles.cache.size === this.roles.cache.size &&\n        other.roles.cache.every(role => this.roles.cache.has(role.id))\n      );\n    } else {\n      return (\n        other.id === this.id &&\n        other.name === this.name &&\n        other.roles.length === this.roles.cache.size &&\n        other.roles.every(role => this.roles.cache.has(role))\n      );\n    }\n  }\n}\n\nexports.GuildEmoji = GuildEmoji;\n"
  },
  {
    "path": "packages/discord.js/src/structures/GuildInvite.js",
    "content": "'use strict';\n\nconst { Routes, PermissionFlagsBits, InviteType } = require('discord-api-types/v10');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { InviteFlagsBitField } = require('../util/InviteFlagsBitField.js');\nconst { BaseInvite } = require('./BaseInvite.js');\nconst { GuildScheduledEvent } = require('./GuildScheduledEvent.js');\nconst { IntegrationApplication } = require('./IntegrationApplication.js');\nconst { InviteGuild } = require('./InviteGuild.js');\n\n/**\n * A channel invite leading to a guild.\n *\n * @extends {BaseInvite}\n */\nclass GuildInvite extends BaseInvite {\n  constructor(client, data) {\n    super(client, data);\n\n    // Type may be missing from audit logs.\n    this.type = InviteType.Guild;\n\n    /**\n     * The id of the guild this invite is for.\n     *\n     * @type {Snowflake}\n     */\n    // Guild id may be missing from audit logs.\n    this.guildId = data.guild_id ?? data.guild.id;\n\n    /**\n     * The maximum age of the invite in seconds. `0` for no expiry.\n     * <info>This is only available when the invite was fetched through {@link GuildInviteManager#fetch}\n     * or created through {@link GuildInviteManager#create}.</info>\n     *\n     * @name GuildInvite#maxAge\n     * @type {?number}\n     */\n\n    /**\n     * The approximate total number of members of the guild.\n     * <info>This is only available when the invite was fetched through {@link Client#fetchInvite}.</info>\n     *\n     * @name GuildInvite#approximateMemberCount\n     * @type {?number}\n     */\n  }\n\n  _patch(data) {\n    super._patch(data);\n\n    if ('flags' in data) {\n      /**\n       * The flags of this invite.\n       *\n       * @type {Readonly<InviteFlagsBitField>}\n       */\n      this.flags = new InviteFlagsBitField(data.flags).freeze();\n    } else {\n      this.flags ??= new InviteFlagsBitField().freeze();\n    }\n\n    if ('guild' in data) {\n      /**\n       * The guild the invite is for. May include welcome screen data.\n       *\n       * @type {?(Guild|InviteGuild)}\n       */\n      this.guild = this.client.guilds.cache.get(data.guild.id) ?? new InviteGuild(this.client, data.guild);\n    } else {\n      this.guild ??= null;\n    }\n\n    if ('channel' in data) {\n      /**\n       * The channel this invite is for.\n       *\n       * @type {?GuildInvitableChannel}\n       */\n      this.channel =\n        this.client.channels._add(data.channel, this.guild, { cache: false }) ??\n        this.client.channels.cache.get(this.channelId);\n\n      this.channelId ??= data.channel.id;\n    }\n\n    if ('target_type' in data) {\n      /**\n       * The target type.\n       *\n       * @type {?InviteTargetType}\n       */\n      this.targetType = data.target_type;\n    } else {\n      this.targetType ??= null;\n    }\n\n    if ('target_user' in data) {\n      /**\n       * The user whose stream to display for this voice channel stream invite.\n       *\n       * @type {?User}\n       */\n      this.targetUser = this.client.users._add(data.target_user);\n    } else {\n      this.targetUser ??= null;\n    }\n\n    if ('target_application' in data) {\n      /**\n       * The embedded application to open for this voice channel embedded application invite.\n       *\n       * @type {?IntegrationApplication}\n       */\n      this.targetApplication = new IntegrationApplication(this.client, data.target_application);\n    } else {\n      this.targetApplication ??= null;\n    }\n\n    if ('guild_scheduled_event' in data) {\n      /**\n       * The guild scheduled event data if there is a {@link GuildScheduledEvent} in the channel.\n       *\n       * @type {?GuildScheduledEvent}\n       */\n      this.guildScheduledEvent = new GuildScheduledEvent(this.client, data.guild_scheduled_event);\n    } else {\n      this.guildScheduledEvent ??= null;\n    }\n\n    if ('uses' in data) {\n      /**\n       * How many times this invite has been used.\n       * <info>This is only available when the invite was fetched through {@link GuildInviteManager#fetch}\n       * or created through {@link GuildInviteManager#create}.</info>\n       *\n       * @type {?number}\n       */\n      this.uses = data.uses;\n    } else {\n      this.uses ??= null;\n    }\n\n    if ('max_uses' in data) {\n      /**\n       * The maximum uses of this invite.\n       * <info>This is only available when the invite was fetched through {@link GuildInviteManager#fetch}\n       * or created through {@link GuildInviteManager#create}.</info>\n       *\n       * @type {?number}\n       */\n      this.maxUses = data.max_uses;\n    } else {\n      this.maxUses ??= null;\n    }\n\n    if ('temporary' in data) {\n      /**\n       * Whether this invite grants temporary membership.\n       * <info>This is only available when the invite was fetched through {@link GuildInviteManager#fetch}\n       * or created through {@link GuildInviteManager#create}.</info>\n       *\n       * @type {?boolean}\n       */\n      this.temporary = data.temporary ?? null;\n    } else {\n      this.temporary ??= null;\n    }\n\n    if ('approximate_presence_count' in data) {\n      /**\n       * The approximate number of online members of the guild.\n       * <info>This is only available when the invite was fetched through {@link Client#fetchInvite}.</info>\n       *\n       * @type {?number}\n       */\n      this.approximatePresenceCount = data.approximate_presence_count;\n    } else {\n      this.approximatePresenceCount ??= null;\n    }\n  }\n\n  /**\n   * Whether the invite is deletable by the client user.\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get deletable() {\n    const guild = this.guild;\n    if (!guild || !this.client.guilds.cache.has(guild.id)) return false;\n    if (!guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe);\n    return Boolean(\n      this.channel?.permissionsFor(this.client.user).has(PermissionFlagsBits.ManageChannels, false) ||\n      guild.members.me.permissions.has(PermissionFlagsBits.ManageGuild),\n    );\n  }\n\n  /**\n   * Delete this invite.\n   *\n   * @param {string} [reason] Reason for deleting this invite\n   * @returns {Promise<void>}\n   */\n  async delete(reason) {\n    await this.client.rest.delete(Routes.invite(this.code), { reason });\n  }\n\n  toJSON() {\n    return super.toJSON({\n      url: true,\n      expiresTimestamp: true,\n      presenceCount: false,\n      memberCount: false,\n      uses: false,\n      channel: 'channelId',\n      inviter: 'inviterId',\n      guild: 'guildId',\n    });\n  }\n}\n\nexports.GuildInvite = GuildInvite;\n"
  },
  {
    "path": "packages/discord.js/src/structures/GuildMember.js",
    "content": "'use strict';\n\nconst { PermissionFlagsBits } = require('discord-api-types/v10');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { GuildMemberRoleManager } = require('../managers/GuildMemberRoleManager.js');\nconst { GuildMemberFlagsBitField } = require('../util/GuildMemberFlagsBitField.js');\nconst { PermissionsBitField } = require('../util/PermissionsBitField.js');\nconst { Base } = require('./Base.js');\nconst { VoiceState } = require('./VoiceState.js');\n\n/**\n * Represents a member of a guild on Discord.\n *\n * @extends {Base}\n */\nclass GuildMember extends Base {\n  constructor(client, data, guild) {\n    super(client);\n\n    /**\n     * The guild that this member is part of\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n\n    /**\n     * The last timestamp this member started boosting the guild\n     *\n     * @type {?number}\n     */\n    this.premiumSinceTimestamp = null;\n\n    /**\n     * The nickname of this member, if they have one\n     *\n     * @type {?string}\n     */\n    this.nickname = null;\n\n    /**\n     * Whether this member has yet to pass the guild's membership gate\n     *\n     * @type {?boolean}\n     */\n    this.pending = null;\n\n    /**\n     * The timestamp this member's timeout will be removed\n     *\n     * @type {?number}\n     */\n    this.communicationDisabledUntilTimestamp = null;\n\n    /**\n     * The role ids of the member\n     *\n     * @name GuildMember#_roles\n     * @type {Snowflake[]}\n     * @private\n     */\n    Object.defineProperty(this, '_roles', { value: [], writable: true });\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('user' in data) {\n      /**\n       * The user that this guild member instance represents\n       *\n       * @type {?User}\n       */\n      this.user = this.client.users._add(data.user, true);\n    }\n\n    if ('nick' in data) this.nickname = data.nick;\n    if ('avatar' in data) {\n      /**\n       * The guild member's avatar hash\n       *\n       * @type {?string}\n       */\n      this.avatar = data.avatar;\n    } else if (typeof this.avatar !== 'string') {\n      this.avatar = null;\n    }\n\n    if ('banner' in data) {\n      /**\n       * The guild member's banner hash.\n       *\n       * @type {?string}\n       */\n      this.banner = data.banner;\n    } else {\n      this.banner ??= null;\n    }\n\n    if ('joined_at' in data) {\n      /**\n       * The timestamp the member joined the guild at\n       *\n       * @type {?number}\n       */\n      this.joinedTimestamp = data.joined_at && Date.parse(data.joined_at);\n    } else {\n      this.joinedTimestamp ??= null;\n    }\n\n    if ('premium_since' in data) {\n      this.premiumSinceTimestamp = data.premium_since ? Date.parse(data.premium_since) : null;\n    }\n\n    if ('roles' in data) this._roles = data.roles;\n\n    if ('pending' in data) {\n      this.pending = data.pending;\n    } else if (!this.partial) {\n      // See https://github.com/discordjs/discord.js/issues/6546 for more info.\n      this.pending ??= false;\n    }\n\n    if ('communication_disabled_until' in data) {\n      this.communicationDisabledUntilTimestamp =\n        data.communication_disabled_until && Date.parse(data.communication_disabled_until);\n    }\n\n    if ('flags' in data) {\n      /**\n       * The flags of this member\n       *\n       * @type {Readonly<GuildMemberFlagsBitField>}\n       */\n      this.flags = new GuildMemberFlagsBitField(data.flags).freeze();\n    } else {\n      this.flags ??= new GuildMemberFlagsBitField().freeze();\n    }\n\n    if (data.avatar_decoration_data) {\n      /**\n       * The member avatar decoration's data\n       *\n       * @type {?AvatarDecorationData}\n       */\n      this.avatarDecorationData = {\n        asset: data.avatar_decoration_data.asset,\n        skuId: data.avatar_decoration_data.sku_id,\n      };\n    } else {\n      this.avatarDecorationData = null;\n    }\n  }\n\n  _clone() {\n    const clone = super._clone();\n    clone._roles = this._roles.slice();\n    return clone;\n  }\n\n  /**\n   * Whether this GuildMember is a partial\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get partial() {\n    return this.joinedTimestamp === null;\n  }\n\n  /**\n   * A manager for the roles belonging to this member\n   *\n   * @type {GuildMemberRoleManager}\n   * @readonly\n   */\n  get roles() {\n    return new GuildMemberRoleManager(this);\n  }\n\n  /**\n   * The voice state of this member\n   *\n   * @type {VoiceState}\n   * @readonly\n   */\n  get voice() {\n    return this.guild.voiceStates.cache.get(this.id) ?? new VoiceState(this.guild, { user_id: this.id });\n  }\n\n  /**\n   * A link to the member's guild avatar.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  avatarURL(options = {}) {\n    return this.avatar && this.client.rest.cdn.guildMemberAvatar(this.guild.id, this.id, this.avatar, options);\n  }\n\n  /**\n   * A link to the member's avatar decoration.\n   *\n   * @returns {?string}\n   */\n  avatarDecorationURL() {\n    return this.avatarDecorationData ? this.client.rest.cdn.avatarDecoration(this.avatarDecorationData.asset) : null;\n  }\n\n  /**\n   * A link to the member's banner.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the banner URL\n   * @returns {?string}\n   */\n  bannerURL(options = {}) {\n    return this.banner && this.client.rest.cdn.guildMemberBanner(this.guild.id, this.id, this.banner, options);\n  }\n\n  /**\n   * A link to the member's guild avatar if they have one.\n   * Otherwise, a link to their {@link User#displayAvatarURL} will be returned.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {string}\n   */\n  displayAvatarURL(options) {\n    return this.avatarURL(options) ?? this.user.displayAvatarURL(options);\n  }\n\n  /**\n   * A link to the member's guild banner if they have one.\n   * Otherwise, a link to their {@link User#bannerURL} will be returned.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  displayBannerURL(options) {\n    return this.bannerURL(options) ?? this.user.bannerURL(options);\n  }\n\n  /**\n   * A link to the member's guild avatar decoration if they have one.\n   * Otherwise, a link to their {@link User#avatarDecorationURL} will be returned.\n   *\n   * @returns {?string}\n   */\n  displayAvatarDecorationURL() {\n    return this.avatarDecorationURL() ?? this.user.avatarDecorationURL();\n  }\n\n  /**\n   * The time this member joined the guild\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get joinedAt() {\n    return this.joinedTimestamp && new Date(this.joinedTimestamp);\n  }\n\n  /**\n   * The time this member's timeout will be removed\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get communicationDisabledUntil() {\n    return this.communicationDisabledUntilTimestamp && new Date(this.communicationDisabledUntilTimestamp);\n  }\n\n  /**\n   * The last time this member started boosting the guild\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get premiumSince() {\n    return this.premiumSinceTimestamp && new Date(this.premiumSinceTimestamp);\n  }\n\n  /**\n   * The presence of this guild member\n   *\n   * @type {?Presence}\n   * @readonly\n   */\n  get presence() {\n    return this.guild.presences.cache.get(this.id) ?? null;\n  }\n\n  /**\n   * The displayed role color of this member in base 10\n   *\n   * @type {number}\n   * @readonly\n   */\n  get displayColor() {\n    return this.roles.color?.colors.primaryColor ?? 0;\n  }\n\n  /**\n   * The displayed role color of this member in hexadecimal\n   *\n   * @type {string}\n   * @readonly\n   */\n  get displayHexColor() {\n    return this.roles.color?.hexColor ?? '#000000';\n  }\n\n  /**\n   * The member's id\n   *\n   * @type {Snowflake}\n   * @readonly\n   */\n  get id() {\n    return this.user.id;\n  }\n\n  /**\n   * The DM between the client's user and this member\n   *\n   * @type {?DMChannel}\n   * @readonly\n   */\n  get dmChannel() {\n    return this.client.users.dmChannel(this.id);\n  }\n\n  /**\n   * The nickname of this member, or their user display name if they don't have one\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get displayName() {\n    return this.nickname ?? this.user.displayName;\n  }\n\n  /**\n   * The overall set of permissions for this member, taking only roles and owner status into account\n   *\n   * @type {Readonly<PermissionsBitField>}\n   * @readonly\n   */\n  get permissions() {\n    if (this.user.id === this.guild.ownerId) return new PermissionsBitField(PermissionsBitField.All).freeze();\n    return new PermissionsBitField(this.roles.cache.map(role => role.permissions)).freeze();\n  }\n\n  /**\n   * Whether the client user is above this user in the hierarchy, according to role position and guild ownership.\n   * This is a prerequisite for many moderative actions.\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get manageable() {\n    if (this.user.id === this.guild.ownerId) return false;\n    if (this.user.id === this.client.user.id) return false;\n    if (!this.guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe);\n    return this.guild.members.me.roles.highest.comparePositionTo(this.roles.highest) > 0;\n  }\n\n  /**\n   * Whether this member is kickable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get kickable() {\n    if (!this.guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe);\n    return this.manageable && this.guild.members.me.permissions.has(PermissionFlagsBits.KickMembers);\n  }\n\n  /**\n   * Whether this member is bannable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get bannable() {\n    if (!this.guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe);\n    return this.manageable && this.guild.members.me.permissions.has(PermissionFlagsBits.BanMembers);\n  }\n\n  /**\n   * Whether this member is moderatable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get moderatable() {\n    return (\n      !this.permissions.has(PermissionFlagsBits.Administrator) &&\n      this.manageable &&\n      (this.guild.members.me?.permissions.has(PermissionFlagsBits.ModerateMembers) ?? false)\n    );\n  }\n\n  /**\n   * Whether this member is currently timed out\n   *\n   * @returns {boolean}\n   */\n  isCommunicationDisabled() {\n    return this.communicationDisabledUntilTimestamp > Date.now();\n  }\n\n  /**\n   * Returns `channel.permissionsFor(guildMember)`. Returns permissions for a member in a guild channel,\n   * taking into account roles and permission overwrites.\n   *\n   * @param {GuildChannelResolvable} channel The guild channel to use as context\n   * @returns {Readonly<PermissionsBitField>}\n   */\n  permissionsIn(channel) {\n    const resolvedChannel = this.guild.channels.resolve(channel);\n    if (!resolvedChannel) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);\n    return resolvedChannel.permissionsFor(this);\n  }\n\n  /**\n   * Edits this member.\n   *\n   * @param {GuildMemberEditOptions} options The options to provide\n   * @returns {Promise<GuildMember>}\n   */\n  async edit(options) {\n    return this.guild.members.edit(this, options);\n  }\n\n  /**\n   * Sets the flags for this member.\n   *\n   * @param {GuildMemberFlagsResolvable} flags The flags to set\n   * @param {string} [reason] Reason for setting the flags\n   * @returns {Promise<GuildMember>}\n   */\n  async setFlags(flags, reason) {\n    return this.edit({ flags, reason });\n  }\n\n  /**\n   * Sets the nickname for this member.\n   *\n   * @param {?string} nick The nickname for the guild member, or `null` if you want to reset their nickname\n   * @param {string} [reason] Reason for setting the nickname\n   * @returns {Promise<GuildMember>}\n   * @example\n   * // Set a nickname for a guild member\n   * guildMember.setNickname('cool nickname', 'Needed a new nickname')\n   *   .then(member => console.log(`Set nickname of ${member.user.username}`))\n   *   .catch(console.error);\n   * @example\n   * // Remove a nickname for a guild member\n   * guildMember.setNickname(null, 'No nicknames allowed!')\n   *   .then(member => console.log(`Removed nickname for ${member.user.username}`))\n   *   .catch(console.error);\n   */\n  async setNickname(nick, reason) {\n    return this.user.id === this.client.user.id\n      ? this.guild.members.editMe({ nick, reason })\n      : this.edit({ nick, reason });\n  }\n\n  /**\n   * Creates a DM channel between the client and this member.\n   *\n   * @param {boolean} [force=false] Whether to skip the cache check and request the API\n   * @returns {Promise<DMChannel>}\n   */\n  async createDM(force = false) {\n    return this.user.createDM(force);\n  }\n\n  /**\n   * Deletes any DMs with this member.\n   *\n   * @returns {Promise<DMChannel>}\n   */\n  async deleteDM() {\n    return this.user.deleteDM();\n  }\n\n  /**\n   * Kicks this member from the guild.\n   *\n   * @param {string} [reason] Reason for kicking user\n   * @returns {Promise<void>}\n   */\n  async kick(reason) {\n    await this.guild.members.kick(this, reason);\n  }\n\n  /**\n   * Bans this guild member.\n   *\n   * @param {BanOptions} [options] Options for the ban\n   * @returns {Promise<void>}\n   * @example\n   * // Ban a guild member, deleting a week's worth of messages\n   * await guildMember.ban({ deleteMessageSeconds: 60 * 60 * 24 * 7, reason: 'They deserved it' });\n   */\n  async ban(options) {\n    await this.guild.bans.create(this, options);\n  }\n\n  /**\n   * Times this guild member out.\n   *\n   * @param {?DateResolvable} communicationDisabledUntil The date or timestamp\n   * for the member's communication to be disabled until. Provide `null` to remove the timeout.\n   * @param {string} [reason] The reason for this timeout.\n   * @returns {Promise<GuildMember>}\n   * @example\n   * // Time a guild member out for 5 minutes\n   * guildMember.disableCommunicationUntil(Date.now() + (5 * 60 * 1000), 'They deserved it')\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Remove the timeout of a guild member\n   * guildMember.disableCommunicationUntil(null)\n   *   .then(member => console.log(`Removed timeout for ${member.displayName}`))\n   *   .catch(console.error);\n   */\n  async disableCommunicationUntil(communicationDisabledUntil, reason) {\n    return this.edit({ communicationDisabledUntil, reason });\n  }\n\n  /**\n   * Times this guild member out.\n   *\n   * @param {?number} timeout The duration in milliseconds\n   * for the member's communication to be disabled. Provide `null` to remove the timeout.\n   * @param {string} [reason] The reason for this timeout.\n   * @returns {Promise<GuildMember>}\n   * @example\n   * // Time a guild member out for 5 minutes\n   * guildMember.timeout(5 * 60 * 1000, 'They deserved it')\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async timeout(timeout, reason) {\n    return this.disableCommunicationUntil(timeout && Date.now() + timeout, reason);\n  }\n\n  /**\n   * Fetches this GuildMember.\n   *\n   * @param {boolean} [force=true] Whether to skip the cache check and request the API\n   * @returns {Promise<GuildMember>}\n   */\n  async fetch(force = true) {\n    return this.guild.members.fetch({ user: this.id, cache: true, force });\n  }\n\n  /**\n   * Sends a message to this user.\n   *\n   * @param {string|MessagePayload|MessageCreateOptions} options The options to provide\n   * @returns {Promise<Message>}\n   * @example\n   * // Send a direct message\n   * guildMember.send('Hello!')\n   *   .then(message => console.log(`Sent message: ${message.content} to ${guildMember.displayName}`))\n   *   .catch(console.error);\n   */\n  async send(options) {\n    const dmChannel = await this.createDM();\n\n    return this.client.channels.createMessage(dmChannel, options);\n  }\n\n  /**\n   * Whether this guild member equals another guild member. It compares all properties, so for most\n   * comparison it is advisable to just compare `member.id === member2.id` as it is significantly faster\n   * and is often what most users need.\n   *\n   * @param {GuildMember} member The member to compare with\n   * @returns {boolean}\n   */\n  equals(member) {\n    return (\n      member instanceof this.constructor &&\n      this.id === member.id &&\n      this.partial === member.partial &&\n      this.guild.id === member.guild.id &&\n      this.joinedTimestamp === member.joinedTimestamp &&\n      this.nickname === member.nickname &&\n      this.avatar === member.avatar &&\n      this.banner === member.banner &&\n      this.pending === member.pending &&\n      this.communicationDisabledUntilTimestamp === member.communicationDisabledUntilTimestamp &&\n      this.flags.bitfield === member.flags.bitfield &&\n      (this._roles === member._roles ||\n        (this._roles.length === member._roles.length &&\n          this._roles.every((role, index) => role === member._roles[index]))) &&\n      this.avatarDecorationData?.asset === member.avatarDecorationData?.asset &&\n      this.avatarDecorationData?.skuId === member.avatarDecorationData?.skuId\n    );\n  }\n\n  /**\n   * When concatenated with a string, this automatically returns the user's mention instead of the GuildMember object.\n   *\n   * @returns {string}\n   * @example\n   * // Logs: Hello from <@123456789012345678>!\n   * console.log(`Hello from ${member}!`);\n   */\n  toString() {\n    return this.user.toString();\n  }\n\n  toJSON() {\n    const json = super.toJSON({\n      guild: 'guildId',\n      user: 'userId',\n      displayName: true,\n      roles: true,\n    });\n    json.avatarURL = this.avatarURL();\n    json.bannerURL = this.bannerURL();\n    json.displayAvatarURL = this.displayAvatarURL();\n    json.displayBannerURL = this.displayBannerURL();\n    json.avatarDecorationURL = this.avatarDecorationURL();\n    return json;\n  }\n}\n\nexports.GuildMember = GuildMember;\n"
  },
  {
    "path": "packages/discord.js/src/structures/GuildOnboarding.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Base } = require('./Base.js');\nconst { GuildOnboardingPrompt } = require('./GuildOnboardingPrompt.js');\n\n/**\n * Represents the onboarding data of a guild.\n *\n * @extends {Base}\n */\nclass GuildOnboarding extends Base {\n  constructor(client, data) {\n    super(client);\n\n    /**\n     * The id of the guild this onboarding data is for\n     *\n     * @type {Snowflake}\n     */\n    this.guildId = data.guild_id;\n\n    const guild = this.guild;\n\n    /**\n     * The prompts shown during onboarding and in customize community\n     *\n     * @type {Collection<Snowflake, GuildOnboardingPrompt>}\n     */\n    this.prompts = data.prompts.reduce(\n      (prompts, prompt) => prompts.set(prompt.id, new GuildOnboardingPrompt(client, prompt, this.guildId)),\n      new Collection(),\n    );\n\n    /**\n     * The ids of the channels that new members get opted into automatically\n     *\n     * @type {Collection<Snowflake, GuildChannel>}\n     */\n    this.defaultChannels = data.default_channel_ids.reduce(\n      (channels, channelId) => channels.set(channelId, guild.channels.cache.get(channelId)),\n      new Collection(),\n    );\n\n    /**\n     * Whether onboarding is enabled\n     *\n     * @type {boolean}\n     */\n    this.enabled = data.enabled;\n\n    /**\n     * The mode of this onboarding\n     *\n     * @type {GuildOnboardingMode}\n     */\n    this.mode = data.mode;\n  }\n\n  /**\n   * The guild this onboarding is from\n   *\n   * @type {Guild}\n   * @readonly\n   */\n  get guild() {\n    return this.client.guilds.cache.get(this.guildId);\n  }\n}\n\nexports.GuildOnboarding = GuildOnboarding;\n"
  },
  {
    "path": "packages/discord.js/src/structures/GuildOnboardingPrompt.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Base } = require('./Base.js');\nconst { GuildOnboardingPromptOption } = require('./GuildOnboardingPromptOption.js');\n\n/**\n * Represents the data of a prompt of a guilds onboarding.\n *\n * @extends {Base}\n */\nclass GuildOnboardingPrompt extends Base {\n  constructor(client, data, guildId) {\n    super(client);\n\n    /**\n     * The id of the guild this onboarding prompt is from\n     *\n     * @type {Snowflake}\n     */\n    this.guildId = guildId;\n\n    /**\n     * The id of the prompt\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    /**\n     * The options available within the prompt\n     *\n     * @type {Collection<Snowflake, GuildOnboardingPromptOption>}\n     */\n    this.options = data.options.reduce(\n      (options, option) => options.set(option.id, new GuildOnboardingPromptOption(client, option, guildId)),\n      new Collection(),\n    );\n\n    /**\n     * The title of the prompt\n     *\n     * @type {string}\n     */\n    this.title = data.title;\n\n    /**\n     * Whether users are limited to selecting one option for the prompt\n     *\n     * @type {boolean}\n     */\n    this.singleSelect = data.single_select;\n\n    /**\n     * Whether the prompt is required before a user completes the onboarding flow\n     *\n     * @type {boolean}\n     */\n    this.required = data.required;\n\n    /**\n     * Whether the prompt is present in the onboarding flow.\n     * If `false`, the prompt will only appear in the Channels & Roles tab\n     *\n     * @type {boolean}\n     */\n    this.inOnboarding = data.in_onboarding;\n\n    /**\n     * The type of the prompt\n     *\n     * @type {GuildOnboardingPromptType}\n     */\n    this.type = data.type;\n  }\n\n  /**\n   * The guild this onboarding prompt is from\n   *\n   * @type {Guild}\n   * @readonly\n   */\n  get guild() {\n    return this.client.guilds.cache.get(this.guildId);\n  }\n}\n\nexports.GuildOnboardingPrompt = GuildOnboardingPrompt;\n"
  },
  {
    "path": "packages/discord.js/src/structures/GuildOnboardingPromptOption.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Base } = require('./Base.js');\nconst { Emoji } = require('./Emoji.js');\n\n/**\n * Represents the data of an option from a prompt of a guilds onboarding.\n *\n * @extends {Base}\n */\nclass GuildOnboardingPromptOption extends Base {\n  constructor(client, data, guildId) {\n    super(client);\n\n    /**\n     * The id of the guild this onboarding prompt option is from\n     *\n     * @type {Snowflake}\n     */\n    this.guildId = guildId;\n\n    const guild = this.guild;\n\n    /**\n     * The id of the option\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    /**\n     * The channels a member is added to when the option is selected\n     *\n     * @type {Collection<Snowflake, GuildChannel>}\n     */\n    this.channels = data.channel_ids.reduce(\n      (channels, channelId) => channels.set(channelId, guild.channels.cache.get(channelId)),\n      new Collection(),\n    );\n\n    /**\n     * The roles assigned to a member when the option is selected\n     *\n     * @type {Collection<Snowflake, Role>}\n     */\n    this.roles = data.role_ids.reduce(\n      (roles, roleId) => roles.set(roleId, guild.roles.cache.get(roleId)),\n      new Collection(),\n    );\n\n    /**\n     * The raw emoji of the option\n     *\n     * @type {APIPartialEmoji}\n     * @private\n     */\n    this._emoji = data.emoji;\n\n    /**\n     * The title of the option\n     *\n     * @type {string}\n     */\n    this.title = data.title;\n\n    /**\n     * The description of the option\n     *\n     * @type {?string}\n     */\n    this.description = data.description;\n  }\n\n  /**\n   * The guild this onboarding prompt option is from\n   *\n   * @type {Guild}\n   * @readonly\n   */\n  get guild() {\n    return this.client.guilds.cache.get(this.guildId);\n  }\n\n  /**\n   * The emoji of this onboarding prompt option\n   *\n   * @type {?(GuildEmoji|Emoji)}\n   */\n  get emoji() {\n    if (!this._emoji.id && !this._emoji.name) return null;\n    return this.guild.emojis.cache.get(this._emoji.id) ?? new Emoji(this.client, this._emoji);\n  }\n}\n\nexports.GuildOnboardingPromptOption = GuildOnboardingPromptOption;\n"
  },
  {
    "path": "packages/discord.js/src/structures/GuildPreview.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { Routes } = require('discord-api-types/v10');\nconst { Base } = require('./Base.js');\nconst { GuildPreviewEmoji } = require('./GuildPreviewEmoji.js');\nconst { Sticker } = require('./Sticker.js');\n\n/**\n * Represents the data about the guild any bot can preview, connected to the specified guild.\n *\n * @extends {Base}\n */\nclass GuildPreview extends Base {\n  constructor(client, data) {\n    super(client);\n\n    if (!data) return;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    /**\n     * The id of this guild\n     *\n     * @type {string}\n     */\n    this.id = data.id;\n\n    if ('name' in data) {\n      /**\n       * The name of this guild\n       *\n       * @type {string}\n       */\n      this.name = data.name;\n    }\n\n    if ('icon' in data) {\n      /**\n       * The icon of this guild\n       *\n       * @type {?string}\n       */\n      this.icon = data.icon;\n    }\n\n    if ('splash' in data) {\n      /**\n       * The splash icon of this guild\n       *\n       * @type {?string}\n       */\n      this.splash = data.splash;\n    }\n\n    if ('discovery_splash' in data) {\n      /**\n       * The discovery splash icon of this guild\n       *\n       * @type {?string}\n       */\n      this.discoverySplash = data.discovery_splash;\n    }\n\n    if ('features' in data) {\n      /**\n       * An array of enabled guild features\n       *\n       * @type {GuildFeature[]}\n       */\n      this.features = data.features;\n    }\n\n    if ('approximate_member_count' in data) {\n      /**\n       * The approximate count of members in this guild\n       *\n       * @type {number}\n       */\n      this.approximateMemberCount = data.approximate_member_count;\n    }\n\n    if ('approximate_presence_count' in data) {\n      /**\n       * The approximate count of online members in this guild\n       *\n       * @type {number}\n       */\n      this.approximatePresenceCount = data.approximate_presence_count;\n    }\n\n    if ('description' in data) {\n      /**\n       * The description for this guild\n       *\n       * @type {?string}\n       */\n      this.description = data.description;\n    } else {\n      this.description ??= null;\n    }\n\n    if (this.emojis) {\n      this.emojis.clear();\n    } else {\n      /**\n       * Collection of emojis belonging to this guild\n       *\n       * @type {Collection<Snowflake, GuildPreviewEmoji>}\n       */\n      this.emojis = new Collection();\n    }\n\n    for (const emoji of data.emojis) {\n      this.emojis.set(emoji.id, new GuildPreviewEmoji(this.client, emoji, this));\n    }\n\n    /**\n     * Collection of stickers belonging to this guild\n     *\n     * @type {Collection<Snowflake, Sticker>}\n     */\n    this.stickers = data.stickers.reduce(\n      (stickers, sticker) => stickers.set(sticker.id, new Sticker(this.client, sticker)),\n      new Collection(),\n    );\n  }\n\n  /**\n   * The timestamp this guild was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time this guild was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * The URL to this guild's splash.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  splashURL(options = {}) {\n    return this.splash && this.client.rest.cdn.splash(this.id, this.splash, options);\n  }\n\n  /**\n   * The URL to this guild's discovery splash.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  discoverySplashURL(options = {}) {\n    return this.discoverySplash && this.client.rest.cdn.discoverySplash(this.id, this.discoverySplash, options);\n  }\n\n  /**\n   * The URL to this guild's icon.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  iconURL(options = {}) {\n    return this.icon && this.client.rest.cdn.icon(this.id, this.icon, options);\n  }\n\n  /**\n   * Fetches this guild.\n   *\n   * @returns {Promise<GuildPreview>}\n   */\n  async fetch() {\n    const data = await this.client.rest.get(Routes.guildPreview(this.id));\n    this._patch(data);\n    return this;\n  }\n\n  /**\n   * When concatenated with a string, this automatically returns the guild's name instead of the Guild object.\n   *\n   * @returns {string}\n   * @example\n   * // Logs: Hello from My Guild!\n   * console.log(`Hello from ${previewGuild}!`);\n   */\n  toString() {\n    return this.name;\n  }\n\n  toJSON() {\n    const json = super.toJSON();\n    json.iconURL = this.iconURL();\n    json.splashURL = this.splashURL();\n    return json;\n  }\n}\n\nexports.GuildPreview = GuildPreview;\n"
  },
  {
    "path": "packages/discord.js/src/structures/GuildPreviewEmoji.js",
    "content": "'use strict';\n\nconst { BaseGuildEmoji } = require('./BaseGuildEmoji.js');\n\n/**\n * Represents an instance of an emoji belonging to a public guild obtained through Discord's preview endpoint.\n *\n * @extends {BaseGuildEmoji}\n */\nclass GuildPreviewEmoji extends BaseGuildEmoji {\n  /**\n   * The public guild this emoji is part of\n   *\n   * @type {GuildPreview}\n   * @name GuildPreviewEmoji#guild\n   */\n\n  constructor(client, data, guild) {\n    super(client, data, guild);\n\n    /**\n     * The roles this emoji is active for\n     *\n     * @type {Snowflake[]}\n     */\n    this.roles = data.roles;\n  }\n}\n\nexports.GuildPreviewEmoji = GuildPreviewEmoji;\n"
  },
  {
    "path": "packages/discord.js/src/structures/GuildScheduledEvent.js",
    "content": "'use strict';\n\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { GuildScheduledEventStatus, GuildScheduledEventEntityType, RouteBases } = require('discord-api-types/v10');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { Base } = require('./Base.js');\n\n/**\n * Represents a scheduled event in a {@link Guild}.\n *\n * @extends {Base}\n */\nclass GuildScheduledEvent extends Base {\n  constructor(client, data) {\n    super(client);\n\n    /**\n     * The id of the guild scheduled event\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    /**\n     * The id of the guild this guild scheduled event belongs to\n     *\n     * @type {Snowflake}\n     */\n    this.guildId = data.guild_id;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('channel_id' in data) {\n      /**\n       * The channel id in which the scheduled event will be hosted,\n       * or `null` if entity type is {@link GuildScheduledEventEntityType.External}\n       *\n       * @type {?Snowflake}\n       */\n      this.channelId = data.channel_id;\n    } else {\n      this.channelId ??= null;\n    }\n\n    if ('creator_id' in data) {\n      /**\n       * The id of the user that created this guild scheduled event\n       *\n       * @type {?Snowflake}\n       */\n      this.creatorId = data.creator_id;\n    } else {\n      this.creatorId ??= null;\n    }\n\n    if ('name' in data) {\n      /**\n       * The name of the guild scheduled event\n       *\n       * @type {?string}\n       */\n      this.name = data.name;\n    } else {\n      // Only if partial.\n      this.name ??= null;\n    }\n\n    if ('description' in data) {\n      /**\n       * The description of the guild scheduled event\n       *\n       * @type {?string}\n       */\n      this.description = data.description;\n    } else {\n      this.description ??= null;\n    }\n\n    if ('scheduled_start_time' in data) {\n      /**\n       * The timestamp the guild scheduled event will start at\n       *\n       * @type {?number}\n       */\n      this.scheduledStartTimestamp = Date.parse(data.scheduled_start_time);\n    } else {\n      this.scheduledStartTimestamp ??= null;\n    }\n\n    if ('scheduled_end_time' in data) {\n      /**\n       * The timestamp the guild scheduled event will end at\n       * or `null` if the event does not have a scheduled time to end\n       *\n       * @type {?number}\n       */\n      this.scheduledEndTimestamp = data.scheduled_end_time ? Date.parse(data.scheduled_end_time) : null;\n    } else {\n      this.scheduledEndTimestamp ??= null;\n    }\n\n    if ('privacy_level' in data) {\n      /**\n       * The privacy level of the guild scheduled event\n       *\n       * @type {?GuildScheduledEventPrivacyLevel}\n       */\n      this.privacyLevel = data.privacy_level;\n    } else {\n      // Only if partial.\n      this.privacyLevel ??= null;\n    }\n\n    if ('status' in data) {\n      /**\n       * The status of the guild scheduled event\n       *\n       * @type {?GuildScheduledEventStatus}\n       */\n      this.status = data.status;\n    } else {\n      // Only if partial.\n      this.status ??= null;\n    }\n\n    if ('entity_type' in data) {\n      /**\n       * The type of hosting entity associated with the scheduled event\n       *\n       * @type {?GuildScheduledEventEntityType}\n       */\n      this.entityType = data.entity_type;\n    } else {\n      // Only if partial.\n      this.entityType ??= null;\n    }\n\n    if ('entity_id' in data) {\n      /**\n       * The id of the hosting entity associated with the scheduled event\n       *\n       * @type {?Snowflake}\n       */\n      this.entityId = data.entity_id;\n    } else {\n      this.entityId ??= null;\n    }\n\n    if ('user_count' in data) {\n      /**\n       * The number of users who are subscribed to this guild scheduled event\n       *\n       * @type {?number}\n       */\n      this.userCount = data.user_count;\n    } else {\n      this.userCount ??= null;\n    }\n\n    if ('creator' in data) {\n      /**\n       * The user that created this guild scheduled event\n       *\n       * @type {?User}\n       */\n      this.creator = this.client.users._add(data.creator);\n    } else {\n      this.creator ??= this.client.users.resolve(this.creatorId);\n    }\n\n    /**\n     * Represents the additional metadata for a {@link GuildScheduledEvent}\n     *\n     * @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-metadata}\n     * @typedef {Object} GuildScheduledEventEntityMetadata\n     * @property {?string} location The location of the guild scheduled event\n     */\n\n    if ('entity_metadata' in data) {\n      if (data.entity_metadata) {\n        /**\n         * Additional metadata\n         *\n         * @type {?GuildScheduledEventEntityMetadata}\n         */\n        this.entityMetadata = {\n          location: data.entity_metadata.location ?? this.entityMetadata?.location ?? null,\n        };\n      } else {\n        this.entityMetadata = null;\n      }\n    } else {\n      this.entityMetadata ??= null;\n    }\n\n    if ('image' in data) {\n      /**\n       * The cover image hash for this scheduled event\n       *\n       * @type {?string}\n       */\n      this.image = data.image;\n    } else {\n      this.image ??= null;\n    }\n\n    /**\n     * Represents the recurrence rule for a {@link GuildScheduledEvent}.\n     *\n     * @typedef {Object} GuildScheduledEventRecurrenceRule\n     * @property {number} startTimestamp The timestamp the recurrence rule interval starts at\n     * @property {Date} startAt The time the recurrence rule interval starts at\n     * @property {?number} endTimestamp The timestamp the recurrence rule interval ends at\n     * @property {?Date} endAt The time the recurrence rule interval ends at\n     * @property {GuildScheduledEventRecurrenceRuleFrequency} frequency How often the event occurs\n     * @property {number} interval The spacing between the events\n     * @property {?GuildScheduledEventRecurrenceRuleWeekday[]} byWeekday The days within a week to recur on\n     * @property {?GuildScheduledEventRecurrenceRuleNWeekday[]} byNWeekday The days within a week to recur on\n     * @property {?GuildScheduledEventRecurrenceRuleMonth[]} byMonth The months to recur on\n     * @property {?number[]} byMonthDay The days within a month to recur on\n     * @property {?number[]} byYearDay The days within a year to recur on\n     * @property {?number} count The total amount of times the event is allowed to recur before stopping\n     */\n\n    /**\n     * @typedef {Object} GuildScheduledEventRecurrenceRuleNWeekday\n     * @property {number} n The week to recur on\n     * @property {GuildScheduledEventRecurrenceRuleWeekday} day The day within the week to recur on\n     */\n\n    if ('recurrence_rule' in data) {\n      /**\n       * The recurrence rule for this scheduled event\n       *\n       * @type {?GuildScheduledEventRecurrenceRule}\n       */\n      this.recurrenceRule = data.recurrence_rule && {\n        startTimestamp: Date.parse(data.recurrence_rule.start),\n        get startAt() {\n          return new Date(this.startTimestamp);\n        },\n        endTimestamp: data.recurrence_rule.end && Date.parse(data.recurrence_rule.end),\n        get endAt() {\n          return this.endTimestamp && new Date(this.endTimestamp);\n        },\n        frequency: data.recurrence_rule.frequency,\n        interval: data.recurrence_rule.interval,\n        byWeekday: data.recurrence_rule.by_weekday,\n        byNWeekday: data.recurrence_rule.by_n_weekday,\n        byMonth: data.recurrence_rule.by_month,\n        byMonthDay: data.recurrence_rule.by_month_day,\n        byYearDay: data.recurrence_rule.by_year_day,\n        count: data.recurrence_rule.count,\n      };\n    } else {\n      this.recurrenceRule ??= null;\n    }\n  }\n\n  /**\n   * Whether this guild scheduled event is partial.\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get partial() {\n    return this.name === null;\n  }\n\n  /**\n   * The URL of this scheduled event's cover image\n   *\n   * @param {BaseImageURLOptions} [options={}] Options for image URL\n   * @returns {?string}\n   */\n  coverImageURL(options = {}) {\n    return this.image && this.client.rest.cdn.guildScheduledEventCover(this.id, this.image, options);\n  }\n\n  /**\n   * The timestamp the guild scheduled event was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time the guild scheduled event was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * The time the guild scheduled event will start at\n   * <info>This can be potentially `null` only when it's an {@link GuildAuditLogsEntry#target}</info>\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get scheduledStartAt() {\n    return this.scheduledStartTimestamp && new Date(this.scheduledStartTimestamp);\n  }\n\n  /**\n   * The time the guild scheduled event will end at,\n   * or `null` if the event does not have a scheduled time to end\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get scheduledEndAt() {\n    return this.scheduledEndTimestamp && new Date(this.scheduledEndTimestamp);\n  }\n\n  /**\n   * The channel associated with this scheduled event\n   *\n   * @type {?(VoiceChannel|StageChannel)}\n   * @readonly\n   */\n  get channel() {\n    return this.client.channels.resolve(this.channelId);\n  }\n\n  /**\n   * The guild this scheduled event belongs to\n   *\n   * @type {?Guild}\n   * @readonly\n   */\n  get guild() {\n    return this.client.guilds.resolve(this.guildId);\n  }\n\n  /**\n   * The URL to the guild scheduled event\n   *\n   * @type {string}\n   * @readonly\n   */\n  get url() {\n    return `${RouteBases.scheduledEvent}/${this.guildId}/${this.id}`;\n  }\n\n  /**\n   * Options used to create an invite URL to a {@link GuildScheduledEvent}\n   *\n   * @typedef {InviteCreateOptions} GuildScheduledEventInviteURLCreateOptions\n   * @property {GuildInvitableChannelResolvable} [channel] The channel to create the invite in.\n   * <warn>This is required when the `entityType` of `GuildScheduledEvent` is\n   * {@link GuildScheduledEventEntityType.External}, gets ignored otherwise</warn>\n   */\n\n  /**\n   * Creates an invite URL to this guild scheduled event.\n   *\n   * @param {GuildScheduledEventInviteURLCreateOptions} [options] The options to create the invite\n   * @returns {Promise<string>}\n   */\n  async createInviteURL(options) {\n    let channelId = this.channelId;\n    if (this.entityType === GuildScheduledEventEntityType.External) {\n      if (!options?.channel) throw new DiscordjsError(ErrorCodes.InviteOptionsMissingChannel);\n      channelId = this.guild.channels.resolveId(options.channel);\n      if (!channelId) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);\n    }\n\n    const invite = await this.guild.invites.create(channelId, options);\n    return `${RouteBases.invite}/${invite.code}?event=${this.id}`;\n  }\n\n  /**\n   * Edits this guild scheduled event.\n   *\n   * @param {GuildScheduledEventEditOptions} options The options to edit the guild scheduled event\n   * @returns {Promise<GuildScheduledEvent>}\n   * @example\n   * // Edit a guild scheduled event\n   * guildScheduledEvent.edit({ name: 'Party' })\n   *  .then(guildScheduledEvent => console.log(guildScheduledEvent))\n   *  .catch(console.error);\n   */\n  async edit(options) {\n    return this.guild.scheduledEvents.edit(this.id, options);\n  }\n\n  /**\n   * Fetches this guild scheduled event.\n   *\n   * @param {boolean} [force=true] Whether to skip the cache check and request the API\n   * @returns {Promise<GuildScheduledEvent>}\n   */\n  async fetch(force = true) {\n    return this.guild.scheduledEvents.fetch({ guildScheduledEvent: this.id, force });\n  }\n\n  /**\n   * Deletes this guild scheduled event.\n   *\n   * @returns {Promise<GuildScheduledEvent>}\n   * @example\n   * // Delete a guild scheduled event\n   * guildScheduledEvent.delete()\n   *  .then(guildScheduledEvent => console.log(guildScheduledEvent))\n   *  .catch(console.error);\n   */\n  async delete() {\n    await this.guild.scheduledEvents.delete(this.id);\n    return this;\n  }\n\n  /**\n   * Sets a new name for the guild scheduled event.\n   *\n   * @param {string} name The new name of the guild scheduled event\n   * @param {string} [reason] The reason for changing the name\n   * @returns {Promise<GuildScheduledEvent>}\n   * @example\n   * // Set name of a guild scheduled event\n   * guildScheduledEvent.setName('Birthday Party')\n   *  .then(guildScheduledEvent => console.log(`Set the name to: ${guildScheduledEvent.name}`))\n   *  .catch(console.error);\n   */\n  async setName(name, reason) {\n    return this.edit({ name, reason });\n  }\n\n  /**\n   * Sets a new time to schedule the event at.\n   *\n   * @param {DateResolvable} scheduledStartTime The time to schedule the event at\n   * @param {string} [reason] The reason for changing the scheduled start time\n   * @returns {Promise<GuildScheduledEvent>}\n   * @example\n   * // Set start time of a guild scheduled event\n   * guildScheduledEvent.setScheduledStartTime('2022-09-24T00:00:00+05:30')\n   *  .then(guildScheduledEvent => console.log(`Set the start time to: ${guildScheduledEvent.scheduledStartTime}`))\n   *  .catch(console.error);\n   */\n  async setScheduledStartTime(scheduledStartTime, reason) {\n    return this.edit({ scheduledStartTime, reason });\n  }\n\n  // TODO: scheduledEndTime gets reset on passing null but it hasn't been documented\n  /**\n   * Sets a new time to end the event at.\n   *\n   * @param {DateResolvable} scheduledEndTime The time to end the event at\n   * @param {string} [reason] The reason for changing the scheduled end time\n   * @returns {Promise<GuildScheduledEvent>}\n   * @example\n   * // Set end time of a guild scheduled event\n   * guildScheduledEvent.setScheduledEndTime('2022-09-25T00:00:00+05:30')\n   *  .then(guildScheduledEvent => console.log(`Set the end time to: ${guildScheduledEvent.scheduledEndTime}`))\n   *  .catch(console.error);\n   */\n  async setScheduledEndTime(scheduledEndTime, reason) {\n    return this.edit({ scheduledEndTime, reason });\n  }\n\n  /**\n   * Sets the new description of the guild scheduled event.\n   *\n   * @param {string} description The description of the guild scheduled event\n   * @param {string} [reason] The reason for changing the description\n   * @returns {Promise<GuildScheduledEvent>}\n   * @example\n   * // Set description of a guild scheduled event\n   * guildScheduledEvent.setDescription('A virtual birthday party')\n   *  .then(guildScheduledEvent => console.log(`Set the description to: ${guildScheduledEvent.description}`))\n   *  .catch(console.error);\n   */\n  async setDescription(description, reason) {\n    return this.edit({ description, reason });\n  }\n\n  /**\n   * Sets the new status of the guild scheduled event.\n   * <info>If you're working with TypeScript, use this method in conjunction with status type-guards\n   * like {@link GuildScheduledEvent#isScheduled} to get only valid status as suggestion</info>\n   *\n   * @param {GuildScheduledEventStatus} status The status of the guild scheduled event\n   * @param {string} [reason] The reason for changing the status\n   * @returns {Promise<GuildScheduledEvent>}\n   * @example\n   * // Set status of a guild scheduled event\n   * guildScheduledEvent.setStatus(GuildScheduledEventStatus.Active)\n   *  .then(guildScheduledEvent => console.log(`Set the status to: ${guildScheduledEvent.status}`))\n   *  .catch(console.error);\n   */\n  async setStatus(status, reason) {\n    return this.edit({ status, reason });\n  }\n\n  /**\n   * Sets the new location of the guild scheduled event.\n   *\n   * @param {string} location The location of the guild scheduled event\n   * @param {string} [reason] The reason for changing the location\n   * @returns {Promise<GuildScheduledEvent>}\n   * @example\n   * // Set location of a guild scheduled event\n   * guildScheduledEvent.setLocation('Earth')\n   *  .then(guildScheduledEvent => console.log(`Set the location to: ${guildScheduledEvent.entityMetadata.location}`))\n   *  .catch(console.error);\n   */\n  async setLocation(location, reason) {\n    return this.edit({ entityMetadata: { location }, reason });\n  }\n\n  /**\n   * Fetches subscribers of this guild scheduled event.\n   *\n   * @param {FetchGuildScheduledEventSubscribersOptions} [options] Options for fetching the subscribers\n   * @returns {Promise<Collection<Snowflake, GuildScheduledEventUser>>}\n   */\n  async fetchSubscribers(options) {\n    return this.guild.scheduledEvents.fetchSubscribers(this.id, options);\n  }\n\n  /**\n   * When concatenated with a string, this automatically concatenates the event's URL instead of the object.\n   *\n   * @returns {string}\n   * @example\n   * // Logs: Event: https://discord.com/events/412345678901234567/499876543211234567\n   * console.log(`Event: ${guildScheduledEvent}`);\n   */\n  toString() {\n    return this.url;\n  }\n\n  /**\n   * Indicates whether this guild scheduled event has an {@link GuildScheduledEventStatus.Active} status.\n   *\n   * @returns {boolean}\n   */\n  isActive() {\n    return this.status === GuildScheduledEventStatus.Active;\n  }\n\n  /**\n   * Indicates whether this guild scheduled event has a {@link GuildScheduledEventStatus.Canceled} status.\n   *\n   * @returns {boolean}\n   */\n  isCanceled() {\n    return this.status === GuildScheduledEventStatus.Canceled;\n  }\n\n  /**\n   * Indicates whether this guild scheduled event has a {@link GuildScheduledEventStatus.Completed} status.\n   *\n   * @returns {boolean}\n   */\n  isCompleted() {\n    return this.status === GuildScheduledEventStatus.Completed;\n  }\n\n  /**\n   * Indicates whether this guild scheduled event has a {@link GuildScheduledEventStatus.Scheduled} status.\n   *\n   * @returns {boolean}\n   */\n  isScheduled() {\n    return this.status === GuildScheduledEventStatus.Scheduled;\n  }\n}\n\nexports.GuildScheduledEvent = GuildScheduledEvent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/GuildTemplate.js",
    "content": "'use strict';\n\nconst { RouteBases, Routes } = require('discord-api-types/v10');\nconst { Base } = require('./Base.js');\n\n/**\n * Represents the template for a guild.\n *\n * @extends {Base}\n */\nclass GuildTemplate extends Base {\n  /**\n   * A regular expression that matches guild template links.\n   * The `code` group property is present on the `exec()` result of this expression.\n   *\n   * @type {RegExp}\n   * @memberof GuildTemplate\n   */\n  static GuildTemplatesPattern = /discord(?:app)?\\.(?:com\\/template|new)\\/(?<code>[\\w-]{2,255})/i;\n\n  constructor(client, data) {\n    super(client);\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('code' in data) {\n      /**\n       * The unique code of this template\n       *\n       * @type {string}\n       */\n      this.code = data.code;\n    }\n\n    if ('name' in data) {\n      /**\n       * The name of this template\n       *\n       * @type {string}\n       */\n      this.name = data.name;\n    }\n\n    if ('description' in data) {\n      /**\n       * The description of this template\n       *\n       * @type {?string}\n       */\n      this.description = data.description;\n    }\n\n    if ('usage_count' in data) {\n      /**\n       * The amount of times this template has been used\n       *\n       * @type {number}\n       */\n      this.usageCount = data.usage_count;\n    }\n\n    if ('creator_id' in data) {\n      /**\n       * The id of the user that created this template\n       *\n       * @type {Snowflake}\n       */\n      this.creatorId = data.creator_id;\n    }\n\n    if ('creator' in data) {\n      /**\n       * The user that created this template\n       *\n       * @type {User}\n       */\n      this.creator = this.client.users._add(data.creator);\n    }\n\n    if ('created_at' in data) {\n      /**\n       * The timestamp of when this template was created at\n       *\n       * @type {number}\n       */\n      this.createdTimestamp = Date.parse(data.created_at);\n    }\n\n    if ('updated_at' in data) {\n      /**\n       * The timestamp of when this template was last synced to the guild\n       *\n       * @type {number}\n       */\n      this.updatedTimestamp = Date.parse(data.updated_at);\n    }\n\n    if ('source_guild_id' in data) {\n      /**\n       * The id of the guild that this template belongs to\n       *\n       * @type {Snowflake}\n       */\n      this.guildId = data.source_guild_id;\n    }\n\n    if ('serialized_source_guild' in data) {\n      /**\n       * The data of the guild that this template would create\n       *\n       * @type {APIGuild}\n       */\n      this.serializedGuild = data.serialized_source_guild;\n    }\n\n    /**\n     * Whether this template has unsynced changes\n     *\n     * @type {?boolean}\n     */\n    this.unSynced = 'is_dirty' in data ? Boolean(data.is_dirty) : null;\n\n    return this;\n  }\n\n  /**\n   * Options used to edit a guild template.\n   *\n   * @typedef {Object} GuildTemplateEditOptions\n   * @property {string} [name] The name of this template\n   * @property {string} [description] The description of this template\n   */\n\n  /**\n   * Updates the metadata of this template.\n   *\n   * @param {GuildTemplateEditOptions} [options] Options for editing the template\n   * @returns {Promise<GuildTemplate>}\n   */\n  async edit({ name, description } = {}) {\n    const data = await this.client.rest.patch(Routes.guildTemplate(this.guildId, this.code), {\n      body: { name, description },\n    });\n    return this._patch(data);\n  }\n\n  /**\n   * Deletes this template.\n   *\n   * @returns {Promise<GuildTemplate>}\n   */\n  async delete() {\n    await this.client.rest.delete(Routes.guildTemplate(this.guildId, this.code));\n    return this;\n  }\n\n  /**\n   * Syncs this template to the current state of the guild.\n   *\n   * @returns {Promise<GuildTemplate>}\n   */\n  async sync() {\n    const data = await this.client.rest.put(Routes.guildTemplate(this.guildId, this.code));\n    return this._patch(data);\n  }\n\n  /**\n   * The time when this template was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * The time when this template was last synced to the guild\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get updatedAt() {\n    return new Date(this.updatedTimestamp);\n  }\n\n  /**\n   * The guild that this template belongs to\n   *\n   * @type {?Guild}\n   * @readonly\n   */\n  get guild() {\n    return this.client.guilds.resolve(this.guildId);\n  }\n\n  /**\n   * The URL of this template\n   *\n   * @type {string}\n   * @readonly\n   */\n  get url() {\n    return `${RouteBases.template}/${this.code}`;\n  }\n\n  /**\n   * When concatenated with a string, this automatically returns the template's code instead of the template object.\n   *\n   * @returns {string}\n   * @example\n   * // Logs: Template: FKvmczH2HyUf\n   * console.log(`Template: ${guildTemplate}!`);\n   */\n  toString() {\n    return this.code;\n  }\n}\n\nexports.GuildTemplate = GuildTemplate;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Integration.js",
    "content": "'use strict';\n\nconst { Routes } = require('discord-api-types/v10');\nconst { Base } = require('./Base.js');\nconst { IntegrationApplication } = require('./IntegrationApplication.js');\n\n/**\n * The information account for an integration\n *\n * @typedef {Object} IntegrationAccount\n * @property {Snowflake|string} id The id of the account\n * @property {string} name The name of the account\n */\n\n/**\n * The type of an {@link Integration}. This can be:\n * - `twitch`\n * - `youtube`\n * - `discord`\n * - `guild_subscription`\n *\n * @typedef {string} IntegrationType\n */\n\n/**\n * Represents a guild integration.\n *\n * @extends {Base}\n */\nclass Integration extends Base {\n  constructor(client, data, guild) {\n    super(client);\n\n    /**\n     * The guild this integration belongs to\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n\n    /**\n     * The integration id\n     *\n     * @type {Snowflake|string}\n     */\n    this.id = data.id;\n\n    /**\n     * The integration name\n     *\n     * @type {string}\n     */\n    this.name = data.name;\n\n    /**\n     * The integration type\n     *\n     * @type {IntegrationType}\n     */\n    this.type = data.type;\n\n    /**\n     * Whether this integration is enabled\n     *\n     * @type {?boolean}\n     */\n    this.enabled = data.enabled ?? null;\n\n    if ('syncing' in data) {\n      /**\n       * Whether this integration is syncing\n       *\n       * @type {?boolean}\n       */\n      this.syncing = data.syncing;\n    } else {\n      this.syncing ??= null;\n    }\n\n    /**\n     * The role that this integration uses for subscribers\n     *\n     * @type {?Role}\n     */\n    this.role = this.guild.roles.resolve(data.role_id);\n\n    if ('enable_emoticons' in data) {\n      /**\n       * Whether emoticons should be synced for this integration (twitch only currently)\n       *\n       * @type {?boolean}\n       */\n      this.enableEmoticons = data.enable_emoticons;\n    } else {\n      this.enableEmoticons ??= null;\n    }\n\n    if (data.user) {\n      /**\n       * The user for this integration\n       *\n       * @type {?User}\n       */\n      this.user = this.client.users._add(data.user);\n    } else {\n      this.user ??= null;\n    }\n\n    /**\n     * The account integration information\n     *\n     * @type {IntegrationAccount}\n     */\n    this.account = data.account;\n\n    if ('synced_at' in data) {\n      /**\n       * The timestamp at which this integration was last synced at\n       *\n       * @type {?number}\n       */\n      this.syncedTimestamp = Date.parse(data.synced_at);\n    } else {\n      this.syncedTimestamp ??= null;\n    }\n\n    if ('subscriber_count' in data) {\n      /**\n       * How many subscribers this integration has\n       *\n       * @type {?number}\n       */\n      this.subscriberCount = data.subscriber_count;\n    } else {\n      this.subscriberCount ??= null;\n    }\n\n    if ('revoked' in data) {\n      /**\n       * Whether this integration has been revoked\n       *\n       * @type {?boolean}\n       */\n      this.revoked = data.revoked;\n    } else {\n      this.revoked ??= null;\n    }\n\n    this._patch(data);\n  }\n\n  /**\n   * The date at which this integration was last synced at\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get syncedAt() {\n    return this.syncedTimestamp && new Date(this.syncedTimestamp);\n  }\n\n  /**\n   * All roles that are managed by this integration\n   *\n   * @type {Collection<Snowflake, Role>}\n   * @readonly\n   */\n  get roles() {\n    const roles = this.guild.roles.cache;\n    return roles.filter(role => role.tags?.integrationId === this.id);\n  }\n\n  _patch(data) {\n    if ('expire_behavior' in data) {\n      /**\n       * The behavior of expiring subscribers\n       *\n       * @type {?IntegrationExpireBehavior}\n       */\n      this.expireBehavior = data.expire_behavior;\n    } else {\n      this.expireBehavior ??= null;\n    }\n\n    if ('expire_grace_period' in data) {\n      /**\n       * The grace period (in days) before expiring subscribers\n       *\n       * @type {?number}\n       */\n      this.expireGracePeriod = data.expire_grace_period;\n    } else {\n      this.expireGracePeriod ??= null;\n    }\n\n    if ('application' in data) {\n      if (this.application) {\n        this.application._patch(data.application);\n      } else {\n        /**\n         * The application for this integration\n         *\n         * @type {?IntegrationApplication}\n         */\n        this.application = new IntegrationApplication(this.client, data.application);\n      }\n    } else {\n      this.application ??= null;\n    }\n\n    if ('scopes' in data) {\n      /**\n       * The scopes this application has been authorized for\n       *\n       * @type {OAuth2Scopes[]}\n       */\n      this.scopes = data.scopes;\n    } else {\n      this.scopes ??= [];\n    }\n  }\n\n  /**\n   * Deletes this integration.\n   *\n   * @returns {Promise<Integration>}\n   * @param {string} [reason] Reason for deleting this integration\n   */\n  async delete(reason) {\n    await this.client.rest.delete(Routes.guildIntegration(this.guild.id, this.id), { reason });\n    return this;\n  }\n\n  toJSON() {\n    return super.toJSON({\n      role: 'roleId',\n      guild: 'guildId',\n      user: 'userId',\n    });\n  }\n}\n\nexports.Integration = Integration;\n"
  },
  {
    "path": "packages/discord.js/src/structures/IntegrationApplication.js",
    "content": "'use strict';\n\nconst { Application } = require('./interfaces/Application.js');\n\n/**\n * Represents an Integration's OAuth2 Application.\n *\n * @extends {Application}\n */\nclass IntegrationApplication extends Application {\n  _patch(data) {\n    super._patch(data);\n\n    if ('bot' in data) {\n      /**\n       * The bot user for this application\n       *\n       * @type {?User}\n       */\n      this.bot = this.client.users._add(data.bot);\n    } else {\n      this.bot ??= null;\n    }\n\n    if ('terms_of_service_url' in data) {\n      /**\n       * The URL of the application's terms of service\n       *\n       * @type {?string}\n       */\n      this.termsOfServiceURL = data.terms_of_service_url;\n    } else {\n      this.termsOfServiceURL ??= null;\n    }\n\n    if ('privacy_policy_url' in data) {\n      /**\n       * The URL of the application's privacy policy\n       *\n       * @type {?string}\n       */\n      this.privacyPolicyURL = data.privacy_policy_url;\n    } else {\n      this.privacyPolicyURL ??= null;\n    }\n\n    if ('rpc_origins' in data) {\n      /**\n       * The Array of RPC origin URLs\n       *\n       * @type {string[]}\n       */\n      this.rpcOrigins = data.rpc_origins;\n    } else {\n      this.rpcOrigins ??= [];\n    }\n\n    if ('cover_image' in data) {\n      /**\n       * The hash of the application's cover image\n       *\n       * @type {?string}\n       */\n      this.cover = data.cover_image;\n    } else {\n      this.cover ??= null;\n    }\n\n    if ('verify_key' in data) {\n      /**\n       * The hex-encoded key for verification in interactions and the GameSDK's GetTicket\n       *\n       * @type {?string}\n       */\n      this.verifyKey = data.verify_key;\n    } else {\n      this.verifyKey ??= null;\n    }\n  }\n}\n\nexports.IntegrationApplication = IntegrationApplication;\n"
  },
  {
    "path": "packages/discord.js/src/structures/InteractionCallback.js",
    "content": "'use strict';\n\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\n\n/**\n * Represents an interaction callback response from Discord\n */\nclass InteractionCallback {\n  constructor(client, data) {\n    /**\n     * The client that instantiated this.\n     *\n     * @name InteractionCallback#client\n     * @type {Client}\n     * @readonly\n     */\n    Object.defineProperty(this, 'client', { value: client });\n\n    /**\n     * The id of the original interaction response\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    /**\n     * The type of the original interaction\n     *\n     * @type {InteractionType}\n     */\n    this.type = data.type;\n\n    /**\n     * The instance id of the Activity if one was launched or joined\n     *\n     * @type {?string}\n     */\n    this.activityInstanceId = data.activity_instance_id ?? null;\n\n    /**\n     * The id of the message that was created by the interaction\n     *\n     * @type {?Snowflake}\n     */\n    this.responseMessageId = data.response_message_id ?? null;\n\n    /**\n     * Whether the message is in a loading state\n     *\n     * @type {?boolean}\n     */\n    this.responseMessageLoading = data.response_message_loading ?? null;\n\n    /**\n     * Whether the response message was ephemeral\n     *\n     * @type {?boolean}\n     */\n    this.responseMessageEphemeral = data.response_message_ephemeral ?? null;\n  }\n\n  /**\n   * The timestamp the original interaction was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time the original interaction was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n}\n\nexports.InteractionCallback = InteractionCallback;\n"
  },
  {
    "path": "packages/discord.js/src/structures/InteractionCallbackResource.js",
    "content": "'use strict';\n\nconst { lazy } = require('@discordjs/util');\n\nconst getMessage = lazy(() => require('./Message.js').Message);\n\n/**\n * Represents the resource that was created by the interaction response.\n */\nclass InteractionCallbackResource {\n  constructor(client, data) {\n    /**\n     * The client that instantiated this\n     *\n     * @name InteractionCallbackResource#client\n     * @type {Client}\n     * @readonly\n     */\n    Object.defineProperty(this, 'client', { value: client });\n\n    /**\n     * The interaction callback type\n     *\n     * @type {InteractionResponseType}\n     */\n    this.type = data.type;\n\n    /**\n     * The Activity launched by an interaction\n     *\n     * @typedef {Object} ActivityInstance\n     * @property {string} id The instance id of the Activity\n     */\n\n    /**\n     * Represents the Activity launched by this interaction\n     *\n     * @type {?ActivityInstance}\n     */\n    this.activityInstance = data.activity_instance ?? null;\n\n    if ('message' in data) {\n      /**\n       * The message created by the interaction\n       *\n       * @type {?Message}\n       */\n      this.message =\n        this.client.channels.cache.get(data.message.channel_id)?.messages._add(data.message) ??\n        new (getMessage())(client, data.message);\n    } else {\n      this.message = null;\n    }\n  }\n}\n\nexports.InteractionCallbackResource = InteractionCallbackResource;\n"
  },
  {
    "path": "packages/discord.js/src/structures/InteractionCallbackResponse.js",
    "content": "'use strict';\n\nconst { InteractionCallback } = require('./InteractionCallback.js');\nconst { InteractionCallbackResource } = require('./InteractionCallbackResource.js');\n\n/**\n * Represents an interaction's response\n */\nclass InteractionCallbackResponse {\n  constructor(client, data) {\n    /**\n     * The client that instantiated this\n     *\n     * @name InteractionCallbackResponse#client\n     * @type {Client}\n     * @readonly\n     */\n    Object.defineProperty(this, 'client', { value: client });\n\n    /**\n     * The interaction object associated with the interaction callback response\n     *\n     * @type {InteractionCallback}\n     */\n    this.interaction = new InteractionCallback(client, data.interaction);\n\n    /**\n     * The resource that was created by the interaction response\n     *\n     * @type {?InteractionCallbackResource}\n     */\n    this.resource = data.resource ? new InteractionCallbackResource(client, data.resource) : null;\n  }\n}\n\nexports.InteractionCallbackResponse = InteractionCallbackResponse;\n"
  },
  {
    "path": "packages/discord.js/src/structures/InteractionCollector.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Events } = require('../util/Events.js');\nconst { Collector } = require('./interfaces/Collector.js');\n\n/**\n * @typedef {CollectorOptions} InteractionCollectorOptions\n * @property {TextBasedChannelsResolvable} [channel] The channel to listen to interactions from\n * @property {ComponentType} [componentType] The type of component to listen for\n * @property {GuildResolvable} [guild] The guild to listen to interactions from\n * @property {InteractionType} [interactionType] The type of interaction to listen for\n * @property {number} [max] The maximum total amount of interactions to collect\n * @property {number} [maxComponents] The maximum number of components to collect\n * @property {number} [maxUsers] The maximum number of users to interact\n * @property {Message|APIMessage} [message] The message to listen to interactions from\n */\n\n/**\n * Collects interactions.\n * Will automatically stop if the message ({@link Client#event:messageDelete messageDelete} or\n * {@link Client#event:messageDeleteBulk messageDeleteBulk}),\n * channel ({@link Client#event:channelDelete channelDelete}), or\n * guild ({@link Client#event:guildDelete guildDelete}) is deleted.\n * <info>Interaction collectors that do not specify `time` or `idle` may be prone to always running.\n * Ensure your interaction collectors end via either of these options or manual cancellation.</info>\n *\n * @extends {Collector}\n */\nclass InteractionCollector extends Collector {\n  /**\n   * @param {Client} client The client on which to collect interactions\n   * @param {InteractionCollectorOptions} [options={}] The options to apply to this collector\n   */\n  constructor(client, options = {}) {\n    super(client, options);\n\n    /**\n     * The message from which to collect interactions, if provided\n     *\n     * @type {?Snowflake}\n     */\n    this.messageId = options.message?.id ?? null;\n\n    /**\n     * The channel from which to collect interactions, if provided\n     *\n     * @type {?Snowflake}\n     */\n    this.channelId =\n      options.message?.channelId ?? options.message?.channel_id ?? this.client.channels.resolveId(options.channel);\n\n    /**\n     * The guild from which to collect interactions, if provided\n     *\n     * @type {?Snowflake}\n     */\n    this.guildId =\n      options.message?.guildId ??\n      options.message?.guild_id ??\n      this.client.guilds.resolveId(options.channel?.guild) ??\n      this.client.guilds.resolveId(options.guild);\n\n    /**\n     * The type of interaction to collect\n     *\n     * @type {?InteractionType}\n     */\n    this.interactionType = options.interactionType ?? null;\n\n    /**\n     * The type of component to collect\n     *\n     * @type {?ComponentType}\n     */\n    this.componentType = options.componentType ?? null;\n\n    /**\n     * The users that have interacted with this collector\n     *\n     * @type {Collection<Snowflake, User>}\n     */\n    this.users = new Collection();\n\n    /**\n     * The total number of interactions collected\n     *\n     * @type {number}\n     */\n    this.total = 0;\n\n    this.client.incrementMaxListeners();\n\n    const bulkDeleteListener = messages => {\n      if (messages.has(this.messageId)) this.stop('messageDelete');\n    };\n\n    if (this.messageId) {\n      this._handleMessageDeletion = this._handleMessageDeletion.bind(this);\n      this.client.on(Events.MessageDelete, this._handleMessageDeletion);\n      this.client.on(Events.MessageBulkDelete, bulkDeleteListener);\n    }\n\n    if (this.channelId) {\n      this._handleChannelDeletion = this._handleChannelDeletion.bind(this);\n      this._handleThreadDeletion = this._handleThreadDeletion.bind(this);\n      this.client.on(Events.ChannelDelete, this._handleChannelDeletion);\n      this.client.on(Events.ThreadDelete, this._handleThreadDeletion);\n    }\n\n    if (this.guildId) {\n      this._handleGuildDeletion = this._handleGuildDeletion.bind(this);\n      this.client.on(Events.GuildDelete, this._handleGuildDeletion);\n    }\n\n    this.client.on(Events.InteractionCreate, this.handleCollect);\n\n    this.once('end', () => {\n      this.client.removeListener(Events.InteractionCreate, this.handleCollect);\n      this.client.removeListener(Events.MessageDelete, this._handleMessageDeletion);\n      this.client.removeListener(Events.MessageBulkDelete, bulkDeleteListener);\n      this.client.removeListener(Events.ChannelDelete, this._handleChannelDeletion);\n      this.client.removeListener(Events.ThreadDelete, this._handleThreadDeletion);\n      this.client.removeListener(Events.GuildDelete, this._handleGuildDeletion);\n      this.client.decrementMaxListeners();\n    });\n\n    this.on('collect', interaction => {\n      this.total++;\n      this.users.set(interaction.user.id, interaction.user);\n    });\n  }\n\n  /**\n   * Handles an incoming interaction for possible collection.\n   *\n   * @param {BaseInteraction} interaction The interaction to possibly collect\n   * @returns {?Snowflake}\n   * @private\n   */\n  collect(interaction) {\n    /**\n     * Emitted whenever an interaction is collected.\n     *\n     * @event InteractionCollector#collect\n     * @param {BaseInteraction} interaction The interaction that was collected\n     */\n\n    if (this.interactionType && interaction.type !== this.interactionType) return null;\n    if (this.componentType && interaction.componentType !== this.componentType) return null;\n    if (this.messageId && interaction.message?.id !== this.messageId) return null;\n    if (this.channelId && interaction.channelId !== this.channelId) return null;\n    if (this.guildId && interaction.guildId !== this.guildId) return null;\n\n    return interaction.id;\n  }\n\n  /**\n   * Handles an interaction for possible disposal.\n   *\n   * @param {BaseInteraction} interaction The interaction that could be disposed of\n   * @returns {?Snowflake}\n   */\n  dispose(interaction) {\n    /**\n     * Emitted whenever an interaction is disposed of.\n     *\n     * @event InteractionCollector#dispose\n     * @param {BaseInteraction} interaction The interaction that was disposed of\n     */\n    if (this.type && interaction.type !== this.type) return null;\n    if (this.componentType && interaction.componentType !== this.componentType) return null;\n    if (this.messageId && interaction.message?.id !== this.messageId) return null;\n    if (this.channelId && interaction.channelId !== this.channelId) return null;\n    if (this.guildId && interaction.guildId !== this.guildId) return null;\n\n    return interaction.id;\n  }\n\n  /**\n   * Empties this interaction collector.\n   */\n  empty() {\n    this.total = 0;\n    this.collected.clear();\n    this.users.clear();\n    this.checkEnd();\n  }\n\n  /**\n   * The reason this collector has ended with, or null if it hasn't ended yet\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get endReason() {\n    if (this.options.max && this.total >= this.options.max) return 'limit';\n    if (this.options.maxComponents && this.collected.size >= this.options.maxComponents) return 'componentLimit';\n    if (this.options.maxUsers && this.users.size >= this.options.maxUsers) return 'userLimit';\n    return super.endReason;\n  }\n\n  /**\n   * Handles checking if the message has been deleted, and if so, stops the collector with the reason 'messageDelete'.\n   *\n   * @private\n   * @param {Message} message The message that was deleted\n   * @returns {void}\n   */\n  _handleMessageDeletion(message) {\n    if (message.id === this.messageId) {\n      this.stop('messageDelete');\n    }\n  }\n\n  /**\n   * Handles checking if the channel has been deleted, and if so, stops the collector with the reason 'channelDelete'.\n   *\n   * @private\n   * @param {GuildChannel} channel The channel that was deleted\n   * @returns {void}\n   */\n  _handleChannelDeletion(channel) {\n    if (channel.id === this.channelId || channel.threads?.cache.has(this.channelId)) {\n      this.stop('channelDelete');\n    }\n  }\n\n  /**\n   * Handles checking if the thread has been deleted, and if so, stops the collector with the reason 'threadDelete'.\n   *\n   * @private\n   * @param {ThreadChannel} thread The thread that was deleted\n   * @returns {void}\n   */\n  _handleThreadDeletion(thread) {\n    if (thread.id === this.channelId) {\n      this.stop('threadDelete');\n    }\n  }\n\n  /**\n   * Handles checking if the guild has been deleted, and if so, stops the collector with the reason 'guildDelete'.\n   *\n   * @private\n   * @param {Guild} guild The guild that was deleted\n   * @returns {void}\n   */\n  _handleGuildDeletion(guild) {\n    if (guild.id === this.guildId) {\n      this.stop('guildDelete');\n    }\n  }\n}\n\nexports.InteractionCollector = InteractionCollector;\n"
  },
  {
    "path": "packages/discord.js/src/structures/InteractionWebhook.js",
    "content": "'use strict';\n\nconst { Webhook } = require('./Webhook.js');\n\n/**\n * Represents a webhook for an Interaction\n *\n * @implements {Webhook}\n */\nclass InteractionWebhook {\n  /**\n   * @param {Client} client The instantiating client\n   * @param {Snowflake} id The application's id\n   * @param {string} token The interaction's token\n   */\n  constructor(client, id, token) {\n    /**\n     * The client that instantiated the interaction webhook\n     *\n     * @name InteractionWebhook#client\n     * @type {Client}\n     * @readonly\n     */\n    Object.defineProperty(this, 'client', { value: client });\n    this.id = id;\n    Object.defineProperty(this, 'token', { value: token, writable: true, configurable: true });\n  }\n\n  // These are here only for documentation purposes - they are implemented by Webhook\n\n  /**\n   * Sends a message with this webhook.\n   *\n   * @param {string|MessagePayload|InteractionReplyOptions} options The content for the reply\n   * @returns {Promise<Message>}\n   */\n\n  async send() {}\n\n  /**\n   * Gets a message that was sent by this webhook.\n   *\n   * @param {Snowflake|'@original'} message The id of the message to fetch\n   * @returns {Promise<Message>} Returns the message sent by this webhook\n   */\n\n  async fetchMessage() {}\n\n  /**\n   * Edits a message that was sent by this webhook.\n   *\n   * @param {MessageResolvable|'@original'} message The message to edit\n   * @param {string|MessagePayload|WebhookMessageEditOptions} options The options to provide\n   * @returns {Promise<Message>} Returns the message edited by this webhook\n   */\n\n  async editMessage() {}\n\n  deleteMessage() {}\n\n  // eslint-disable-next-line getter-return\n  get url() {}\n}\n\nWebhook.applyToClass(InteractionWebhook, ['sendSlackMessage', 'edit', 'delete', 'createdTimestamp', 'createdAt']);\n\nexports.InteractionWebhook = InteractionWebhook;\n"
  },
  {
    "path": "packages/discord.js/src/structures/InviteGuild.js",
    "content": "'use strict';\n\nconst { AnonymousGuild } = require('./AnonymousGuild.js');\nconst { WelcomeScreen } = require('./WelcomeScreen.js');\n\n/**\n * Represents a guild received from an invite, includes welcome screen data if available.\n *\n * @extends {AnonymousGuild}\n */\nclass InviteGuild extends AnonymousGuild {\n  constructor(client, data) {\n    super(client, data);\n\n    /**\n     * The welcome screen for this invite guild\n     *\n     * @type {?WelcomeScreen}\n     */\n    this.welcomeScreen = data.welcome_screen === undefined ? null : new WelcomeScreen(this, data.welcome_screen);\n  }\n}\n\nexports.InviteGuild = InviteGuild;\n"
  },
  {
    "path": "packages/discord.js/src/structures/LabelComponent.js",
    "content": "'use strict';\n\nconst { createComponent } = require('../util/Components.js');\nconst { Component } = require('./Component.js');\n\n/**\n * Represents a label component\n *\n * @extends {Component}\n */\nclass LabelComponent extends Component {\n  constructor({ component, ...data }) {\n    super(data);\n\n    /**\n     * The component in this label\n     *\n     * @type {Component}\n     * @readonly\n     */\n    this.component = createComponent(component);\n  }\n\n  /**\n   * The label of the component\n   *\n   * @type {string}\n   * @readonly\n   */\n  get label() {\n    return this.data.label;\n  }\n\n  /**\n   * The description of this component\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get description() {\n    return this.data.description ?? null;\n  }\n\n  /**\n   * Returns the API-compatible JSON for this component\n   *\n   * @returns {APILabelComponent}\n   */\n  toJSON() {\n    return { ...this.data, component: this.component.toJSON() };\n  }\n}\n\nexports.LabelComponent = LabelComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/MediaChannel.js",
    "content": "'use strict';\n\nconst { ThreadOnlyChannel } = require('./ThreadOnlyChannel.js');\n\n/**\n * Represents a media channel.\n *\n * @extends {ThreadOnlyChannel}\n */\nclass MediaChannel extends ThreadOnlyChannel {}\n\nexports.MediaChannel = MediaChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/MediaGalleryComponent.js",
    "content": "'use strict';\n\nconst { Component } = require('./Component.js');\nconst { MediaGalleryItem } = require('./MediaGalleryItem.js');\n\n/**\n * Represents a media gallery component\n *\n * @extends {Component}\n */\nclass MediaGalleryComponent extends Component {\n  constructor({ items, ...data }) {\n    super(data);\n\n    /**\n     * The items in this media gallery\n     *\n     * @type {MediaGalleryItem[]}\n     * @readonly\n     */\n    this.items = items.map(item => new MediaGalleryItem(item));\n  }\n\n  /**\n   * Returns the API-compatible JSON for this component\n   *\n   * @returns {APIMediaGalleryComponent}\n   */\n  toJSON() {\n    return { ...this.data, items: this.items.map(item => item.toJSON()) };\n  }\n}\n\nexports.MediaGalleryComponent = MediaGalleryComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/MediaGalleryItem.js",
    "content": "'use strict';\n\nconst { UnfurledMediaItem } = require('./UnfurledMediaItem.js');\n\n/**\n * Represents an item in a media gallery\n */\nclass MediaGalleryItem {\n  constructor({ media, ...data }) {\n    /**\n     * The API data associated with this component\n     *\n     * @type {APIMediaGalleryItem}\n     */\n    this.data = data;\n\n    /**\n     * The media associated with this media gallery item\n     *\n     * @type {UnfurledMediaItem}\n     * @readonly\n     */\n    this.media = new UnfurledMediaItem(media);\n  }\n\n  /**\n   * The description of this media gallery item\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get description() {\n    return this.data.description ?? null;\n  }\n\n  /**\n   * Whether this media gallery item is spoilered\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get spoiler() {\n    return this.data.spoiler ?? false;\n  }\n\n  /**\n   * Returns the API-compatible JSON for this component\n   *\n   * @returns {APIMediaGalleryItem}\n   */\n  toJSON() {\n    return { ...this.data, media: this.media.toJSON() };\n  }\n}\n\nexports.MediaGalleryItem = MediaGalleryItem;\n"
  },
  {
    "path": "packages/discord.js/src/structures/MentionableSelectMenuComponent.js",
    "content": "'use strict';\n\nconst { BaseSelectMenuComponent } = require('./BaseSelectMenuComponent.js');\n\n/**\n * Represents a mentionable select menu component\n *\n * @extends {BaseSelectMenuComponent}\n */\nclass MentionableSelectMenuComponent extends BaseSelectMenuComponent {}\n\nexports.MentionableSelectMenuComponent = MentionableSelectMenuComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/MentionableSelectMenuInteraction.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Events } = require('../util/Events.js');\nconst { MessageComponentInteraction } = require('./MessageComponentInteraction.js');\n\n/**\n * Represents a {@link ComponentType.MentionableSelect} select menu interaction.\n *\n * @extends {MessageComponentInteraction}\n */\nclass MentionableSelectMenuInteraction extends MessageComponentInteraction {\n  constructor(client, data) {\n    super(client, data);\n    const { resolved, values } = data.data;\n    const { members, users, roles } = resolved ?? {};\n\n    /**\n     * An array of the selected user and role ids\n     *\n     * @type {Snowflake[]}\n     */\n    this.values = values ?? [];\n\n    /**\n     * Collection of the selected users\n     *\n     * @type {Collection<Snowflake, User>}\n     */\n    this.users = new Collection();\n\n    /**\n     * Collection of the selected users\n     *\n     * @type {Collection<Snowflake, GuildMember|APIGuildMember>}\n     */\n    this.members = new Collection();\n\n    /**\n     * Collection of the selected roles\n     *\n     * @type {Collection<Snowflake, Role|APIRole>}\n     */\n    this.roles = new Collection();\n\n    if (members) {\n      for (const [id, member] of Object.entries(members)) {\n        const user = users[id];\n        if (!user) {\n          this.client.emit(\n            Events.Debug,\n            `[MentionableSelectMenuInteraction] Received a member without a user, skipping ${id}`,\n          );\n\n          continue;\n        }\n\n        this.members.set(id, this.guild?.members._add({ user, ...member }) ?? { user, ...member });\n      }\n    }\n\n    if (users) {\n      for (const user of Object.values(users)) {\n        this.users.set(user.id, this.client.users._add(user));\n      }\n    }\n\n    if (roles) {\n      for (const role of Object.values(roles)) {\n        this.roles.set(role.id, this.guild?.roles._add(role) ?? role);\n      }\n    }\n  }\n}\n\nexports.MentionableSelectMenuInteraction = MentionableSelectMenuInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Message.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { messageLink } = require('@discordjs/formatters');\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst {\n  InteractionType,\n  ChannelType,\n  MessageType,\n  MessageFlags,\n  MessageReferenceType,\n  PermissionFlagsBits,\n} = require('discord-api-types/v10');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { ReactionManager } = require('../managers/ReactionManager.js');\nconst { createComponent, findComponentByCustomId } = require('../util/Components.js');\nconst { NonSystemMessageTypes, MaxBulkDeletableMessageAge, UndeletableMessageTypes } = require('../util/Constants.js');\nconst { MessageFlagsBitField } = require('../util/MessageFlagsBitField.js');\nconst { PermissionsBitField } = require('../util/PermissionsBitField.js');\nconst { _transformAPIMessageInteractionMetadata } = require('../util/Transformers.js');\nconst { cleanContent, resolvePartialEmoji, transformResolved } = require('../util/Util.js');\nconst { Attachment } = require('./Attachment.js');\nconst { Base } = require('./Base.js');\nconst { ClientApplication } = require('./ClientApplication.js');\nconst { Embed } = require('./Embed.js');\nconst { InteractionCollector } = require('./InteractionCollector.js');\nconst { MessageMentions } = require('./MessageMentions.js');\nconst { MessagePayload } = require('./MessagePayload.js');\nconst { Poll } = require('./Poll.js');\nconst { ReactionCollector } = require('./ReactionCollector.js');\nconst { Sticker } = require('./Sticker.js');\n\n/**\n * Represents a message on Discord.\n *\n * @extends {Base}\n */\nclass Message extends Base {\n  constructor(client, data) {\n    super(client);\n\n    /**\n     * The id of the channel the message was sent in\n     *\n     * @type {Snowflake}\n     */\n    this.channelId = data.channel_id;\n\n    /**\n     * The id of the guild the message was sent in, if any\n     *\n     * @type {?Snowflake}\n     */\n    this.guildId = data.guild_id ?? this.channel?.guild?.id ?? null;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    /**\n     * The message's id\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    /**\n     * The timestamp the message was sent at\n     *\n     * @type {number}\n     */\n    this.createdTimestamp = DiscordSnowflake.timestampFrom(this.id);\n\n    if ('type' in data) {\n      /**\n       * The type of the message\n       *\n       * @type {?MessageType}\n       */\n      this.type = data.type;\n\n      /**\n       * Whether or not this message was sent by Discord, not actually a user (e.g. pin notifications)\n       *\n       * @type {?boolean}\n       */\n      this.system = !NonSystemMessageTypes.includes(this.type);\n    } else {\n      this.system ??= null;\n      this.type ??= null;\n    }\n\n    if ('content' in data) {\n      /**\n       * The content of the message.\n       * <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged intent\n       * in a guild for messages that do not mention the client.</info>\n       *\n       * @type {?string}\n       */\n      this.content = data.content;\n    } else {\n      this.content ??= null;\n    }\n\n    if ('author' in data) {\n      /**\n       * The author of the message\n       *\n       * @type {?User}\n       */\n      this.author = this.client.users._add(data.author, !data.webhook_id);\n    } else {\n      this.author ??= null;\n    }\n\n    if ('pinned' in data) {\n      /**\n       * Whether or not this message is pinned\n       *\n       * @type {?boolean}\n       */\n      this.pinned = Boolean(data.pinned);\n    } else {\n      this.pinned ??= null;\n    }\n\n    if ('tts' in data) {\n      /**\n       * Whether or not the message was Text-To-Speech\n       *\n       * @type {?boolean}\n       */\n      this.tts = data.tts;\n    } else {\n      this.tts ??= null;\n    }\n\n    if ('nonce' in data) {\n      /**\n       * A random number or string used for checking message delivery\n       * <warn>This is only received after the message was sent successfully, and\n       * lost if re-fetched</warn>\n       *\n       * @type {?string}\n       */\n      this.nonce = data.nonce;\n    } else {\n      this.nonce ??= null;\n    }\n\n    if ('embeds' in data) {\n      /**\n       * An array of embeds in the message - e.g. YouTube Player.\n       * <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged intent\n       * in a guild for messages that do not mention the client.</info>\n       *\n       * @type {Embed[]}\n       */\n      this.embeds = data.embeds.map(embed => new Embed(embed));\n    } else {\n      this.embeds = this.embeds?.slice() ?? [];\n    }\n\n    if ('components' in data) {\n      /**\n       * An array of components in the message.\n       * <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged intent\n       * in a guild for messages that do not mention the client.</info>\n       *\n       * @type {Component[]}\n       */\n      this.components = data.components.map(component => createComponent(component));\n    } else {\n      this.components = this.components?.slice() ?? [];\n    }\n\n    if ('attachments' in data) {\n      /**\n       * A collection of attachments in the message - e.g. Pictures - mapped by their ids.\n       * <info>This property requires the {@link GatewayIntentBits.MessageContent} privileged intent\n       * in a guild for messages that do not mention the client.</info>\n       *\n       * @type {Collection<Snowflake, Attachment>}\n       */\n      this.attachments = new Collection();\n      if (data.attachments) {\n        for (const attachment of data.attachments) {\n          this.attachments.set(attachment.id, new Attachment(attachment));\n        }\n      }\n    } else {\n      this.attachments = new Collection(this.attachments);\n    }\n\n    if ('sticker_items' in data || 'stickers' in data) {\n      /**\n       * A collection of stickers in the message\n       *\n       * @type {Collection<Snowflake, Sticker>}\n       */\n      this.stickers = new Collection(\n        (data.sticker_items ?? data.stickers)?.map(sticker => [sticker.id, new Sticker(this.client, sticker)]),\n      );\n    } else {\n      this.stickers = new Collection(this.stickers);\n    }\n\n    if ('position' in data) {\n      /**\n       * A generally increasing integer (there may be gaps or duplicates) that represents\n       * the approximate position of the message in a thread.\n       *\n       * @type {?number}\n       */\n      this.position = data.position;\n    } else {\n      this.position ??= null;\n    }\n\n    if ('role_subscription_data' in data) {\n      /**\n       * Role subscription data found on {@link MessageType.RoleSubscriptionPurchase} messages.\n       *\n       * @typedef {Object} RoleSubscriptionData\n       * @property {Snowflake} roleSubscriptionListingId The id of the SKU and listing the user is subscribed to\n       * @property {string} tierName The name of the tier the user is subscribed to\n       * @property {number} totalMonthsSubscribed The total number of months the user has been subscribed for\n       * @property {boolean} isRenewal Whether this notification is a renewal\n       */\n\n      /**\n       * The data of the role subscription purchase or renewal.\n       * <info>This is present on {@link MessageType.RoleSubscriptionPurchase} messages.</info>\n       *\n       * @type {?RoleSubscriptionData}\n       */\n      this.roleSubscriptionData = {\n        roleSubscriptionListingId: data.role_subscription_data.role_subscription_listing_id,\n        tierName: data.role_subscription_data.tier_name,\n        totalMonthsSubscribed: data.role_subscription_data.total_months_subscribed,\n        isRenewal: data.role_subscription_data.is_renewal,\n      };\n    } else {\n      this.roleSubscriptionData ??= null;\n    }\n\n    if ('resolved' in data) {\n      /**\n       * Resolved data from auto-populated select menus.\n       *\n       * @type {?CommandInteractionResolvedData}\n       */\n      this.resolved = transformResolved(\n        { client: this.client, guild: this.guild, channel: this.channel },\n        data.resolved,\n      );\n    } else {\n      this.resolved ??= null;\n    }\n\n    // Discord sends null if the message has not been edited\n    if (data.edited_timestamp) {\n      /**\n       * The timestamp the message was last edited at (if applicable)\n       *\n       * @type {?number}\n       */\n      this.editedTimestamp = Date.parse(data.edited_timestamp);\n    } else {\n      this.editedTimestamp ??= null;\n    }\n\n    if ('reactions' in data) {\n      /**\n       * A manager of the reactions belonging to this message\n       *\n       * @type {ReactionManager}\n       */\n      this.reactions = new ReactionManager(this);\n      if (data.reactions?.length > 0) {\n        for (const reaction of data.reactions) {\n          this.reactions._add(reaction);\n        }\n      }\n    } else {\n      this.reactions ??= new ReactionManager(this);\n    }\n\n    /**\n     * All valid mentions that the message contains\n     *\n     * @type {MessageMentions}\n     */\n    this.mentions = new MessageMentions(\n      this,\n      data.mentions ?? this.mentions?.users,\n      data.mention_roles ?? this.mentions?.roles,\n      data.mention_everyone ?? this.mentions?.everyone,\n      data.mention_channels ?? this.mentions?.crosspostedChannels,\n      data.referenced_message?.author ?? this.mentions?.repliedUser,\n    );\n\n    if ('webhook_id' in data) {\n      /**\n       * The id of the webhook that sent the message, if applicable\n       *\n       * @type {?Snowflake}\n       */\n      this.webhookId = data.webhook_id;\n    } else {\n      this.webhookId ??= null;\n    }\n\n    if ('application' in data) {\n      /**\n       * Supplemental application information for group activities\n       *\n       * @type {?ClientApplication}\n       */\n      this.groupActivityApplication = new ClientApplication(this.client, data.application);\n    } else {\n      this.groupActivityApplication ??= null;\n    }\n\n    if ('application_id' in data) {\n      /**\n       * The id of the application of the interaction that sent this message, if any\n       *\n       * @type {?Snowflake}\n       */\n      this.applicationId = data.application_id;\n    } else {\n      this.applicationId ??= null;\n    }\n\n    if ('activity' in data) {\n      /**\n       * Group activity\n       *\n       * @type {?MessageActivity}\n       */\n      this.activity = {\n        partyId: data.activity.party_id,\n        type: data.activity.type,\n      };\n    } else {\n      this.activity ??= null;\n    }\n\n    if ('thread' in data) {\n      this.client.channels._add(data.thread, this.guild);\n    }\n\n    if (this.member && data.member) {\n      this.member._patch(data.member);\n    } else if (data.member && this.guild && this.author) {\n      this.guild.members._add(Object.assign(data.member, { user: this.author }));\n    }\n\n    if ('flags' in data) {\n      /**\n       * Flags that are applied to the message\n       *\n       * @type {Readonly<MessageFlagsBitField>}\n       */\n      this.flags = new MessageFlagsBitField(data.flags).freeze();\n    } else {\n      this.flags = new MessageFlagsBitField(this.flags).freeze();\n    }\n\n    /**\n     * Reference data sent in a message that contains ids identifying the referenced message.\n     * This can be present in the following types of message:\n     * - {@link MessageFlags.Crossposted}\n     * - {@link MessageType.ChannelPinnedMessage}\n     * - {@link MessageType.ChannelFollowAdd}\n     * - {@link MessageType.Reply}\n     * - {@link MessageType.ThreadStarterMessage}\n     *\n     * @see {@link https://discord.com/developers/docs/resources/message#message-object-message-types}\n     * @typedef {Object} MessageReference\n     * @property {Snowflake} channelId The channel id that was referenced\n     * @property {Snowflake|undefined} guildId The guild id that was referenced\n     * @property {Snowflake|undefined} messageId The message id that was referenced\n     * @property {MessageReferenceType} type The type of message reference\n     */\n\n    if ('message_reference' in data) {\n      /**\n       * Message reference data\n       *\n       * @type {?MessageReference}\n       */\n      this.reference = {\n        channelId: data.message_reference.channel_id,\n        guildId: data.message_reference.guild_id,\n        messageId: data.message_reference.message_id,\n        type: data.message_reference.type,\n      };\n    } else {\n      this.reference ??= null;\n    }\n\n    if (data.referenced_message) {\n      this.channel?.messages._add({ guild_id: data.message_reference?.guild_id, ...data.referenced_message });\n    }\n\n    if (data.interaction_metadata) {\n      /**\n       * Partial data of the interaction that a message is a result of\n       *\n       * @typedef {Object} MessageInteractionMetadata\n       * @property {Snowflake} id The interaction's id\n       * @property {InteractionType} type The type of the interaction\n       * @property {User} user The user that invoked the interaction\n       * @property {AuthorizingIntegrationOwners} authorizingIntegrationOwners\n       * Mapping of integration types that the application was authorized for the related user or guild ids\n       * @property {?Snowflake} originalResponseMessageId\n       * Id of the original response message. Present only on follow-up messages\n       * @property {?Snowflake} interactedMessageId\n       * Id of the message that contained interactive component.\n       * Present only on messages created from component interactions\n       * @property {?MessageInteractionMetadata} triggeringInteractionMetadata\n       * Metadata for the interaction that was used to open the modal. Present only on modal submit interactions\n       */\n\n      /**\n       * Partial data of the interaction that this message is a result of\n       *\n       * @type {?MessageInteractionMetadata}\n       */\n      this.interactionMetadata = _transformAPIMessageInteractionMetadata(this.client, data.interaction_metadata);\n    } else {\n      this.interactionMetadata ??= null;\n    }\n\n    if (data.poll) {\n      if (this.poll) {\n        this.poll._patch(data.poll);\n      } else {\n        /**\n         * The poll that was sent with the message\n         *\n         * @type {?Poll}\n         */\n        this.poll = new Poll(this.client, data.poll, this, this.channel);\n      }\n    } else {\n      this.poll ??= null;\n    }\n\n    if (data.message_snapshots) {\n      /**\n       * The message snapshots associated with the message reference\n       *\n       * @type {Collection<Snowflake, Message>}\n       */\n      this.messageSnapshots = data.message_snapshots.reduce((coll, snapshot) => {\n        const channel = this.client.channels.resolve(this.reference.channelId);\n        const snapshotData = {\n          ...snapshot.message,\n          id: this.reference.messageId,\n          channel_id: this.reference.channelId,\n          guild_id: this.reference.guildId,\n        };\n\n        return coll.set(\n          this.reference.messageId,\n          channel ? channel.messages._add(snapshotData) : new this.constructor(this.client, snapshotData),\n        );\n      }, new Collection());\n    } else {\n      this.messageSnapshots ??= new Collection();\n    }\n\n    /**\n     * A call associated with a message\n     *\n     * @typedef {Object} MessageCall\n     * @property {Readonly<?Date>} endedAt The time the call ended\n     * @property {?number} endedTimestamp The timestamp the call ended\n     * @property {Snowflake[]} participants The ids of the users that participated in the call\n     */\n\n    if (data.call) {\n      /**\n       * The call associated with the message\n       *\n       * @type {?MessageCall}\n       */\n      this.call = {\n        endedTimestamp: data.call.ended_timestamp ? Date.parse(data.call.ended_timestamp) : null,\n        participants: data.call.participants,\n        get endedAt() {\n          return this.endedTimestamp && new Date(this.endedTimestamp);\n        },\n      };\n    } else {\n      this.call ??= null;\n    }\n  }\n\n  /**\n   * The channel that the message was sent in\n   *\n   * @type {TextBasedChannels}\n   * @readonly\n   */\n  get channel() {\n    return this.client.channels.resolve(this.channelId);\n  }\n\n  /**\n   * Whether or not this message is a partial\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get partial() {\n    return typeof this.content !== 'string' || !this.author;\n  }\n\n  /**\n   * Represents the author of the message as a guild member.\n   * Only available if the message comes from a guild where the author is still a member\n   *\n   * @type {?GuildMember}\n   * @readonly\n   */\n  get member() {\n    return this.guild?.members.resolve(this.author) ?? null;\n  }\n\n  /**\n   * The time the message was sent at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * The time the message was last edited at (if applicable)\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get editedAt() {\n    return this.editedTimestamp && new Date(this.editedTimestamp);\n  }\n\n  /**\n   * The guild the message was sent in (if in a guild channel)\n   *\n   * @type {?Guild}\n   * @readonly\n   */\n  get guild() {\n    return this.client.guilds.resolve(this.guildId) ?? this.channel?.guild ?? null;\n  }\n\n  /**\n   * Whether this message has a thread associated with it\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get hasThread() {\n    return this.flags.has(MessageFlags.HasThread);\n  }\n\n  /**\n   * The thread started by this message\n   * <info>This property is not suitable for checking whether a message has a thread,\n   * use {@link Message#hasThread} instead.</info>\n   *\n   * @type {?ThreadChannel}\n   * @readonly\n   */\n  get thread() {\n    return this.channel?.threads?.cache.get(this.id) ?? null;\n  }\n\n  /**\n   * The URL to jump to this message\n   *\n   * @type {string}\n   * @readonly\n   */\n  get url() {\n    return this.inGuild() ? messageLink(this.channelId, this.id, this.guildId) : messageLink(this.channelId, this.id);\n  }\n\n  /**\n   * The message contents with all mentions replaced by the equivalent text.\n   * If mentions cannot be resolved to a name, the relevant mention in the message content will not be converted.\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get cleanContent() {\n    // eslint-disable-next-line eqeqeq\n    return this.content != null && this.channel ? cleanContent(this.content, this.channel) : null;\n  }\n\n  /**\n   * Creates a reaction collector.\n   *\n   * @param {ReactionCollectorOptions} [options={}] Options to send to the collector\n   * @returns {ReactionCollector}\n   * @example\n   * // Create a reaction collector\n   * const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId';\n   * const collector = message.createReactionCollector({ filter, time: 15_000 });\n   * collector.on('collect', r => console.log(`Collected ${r.emoji.name}`));\n   * collector.on('end', collected => console.log(`Collected ${collected.size} items`));\n   */\n  createReactionCollector(options = {}) {\n    return new ReactionCollector(this, options);\n  }\n\n  /**\n   * An object containing the same properties as CollectorOptions, but a few more:\n   *\n   * @typedef {ReactionCollectorOptions} AwaitReactionsOptions\n   * @property {string[]} [errors] Stop/end reasons that cause the promise to reject\n   */\n\n  /**\n   * Similar to createReactionCollector but in promise form.\n   * Resolves with a collection of reactions that pass the specified filter.\n   *\n   * @param {AwaitReactionsOptions} [options={}] Optional options to pass to the internal collector\n   * @returns {Promise<Collection<string|Snowflake, MessageReaction>>}\n   * @example\n   * // Create a reaction collector\n   * const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someId'\n   * message.awaitReactions({ filter, time: 15_000 })\n   *   .then(collected => console.log(`Collected ${collected.size} reactions`))\n   *   .catch(console.error);\n   */\n  async awaitReactions(options = {}) {\n    return new Promise((resolve, reject) => {\n      const collector = this.createReactionCollector(options);\n      collector.once('end', (reactions, reason) => {\n        if (options.errors?.includes(reason)) reject(reactions);\n        else resolve(reactions);\n      });\n    });\n  }\n\n  /**\n   * @typedef {CollectorOptions} MessageComponentCollectorOptions\n   * @property {ComponentType} [componentType] The type of component to listen for\n   * @property {number} [max] The maximum total amount of interactions to collect\n   * @property {number} [maxComponents] The maximum number of components to collect\n   * @property {number} [maxUsers] The maximum number of users to interact\n   */\n\n  /**\n   * Creates a message component interaction collector.\n   *\n   * @param {MessageComponentCollectorOptions} [options={}] Options to send to the collector\n   * @returns {InteractionCollector}\n   * @example\n   * // Create a message component interaction collector\n   * const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId';\n   * const collector = message.createMessageComponentCollector({ filter, time: 15_000 });\n   * collector.on('collect', i => console.log(`Collected ${i.customId}`));\n   * collector.on('end', collected => console.log(`Collected ${collected.size} items`));\n   */\n  createMessageComponentCollector(options = {}) {\n    return new InteractionCollector(this.client, {\n      ...options,\n      interactionType: InteractionType.MessageComponent,\n      message: this,\n    });\n  }\n\n  /**\n   * An object containing the same properties as CollectorOptions, but a few more:\n   *\n   * @typedef {Object} AwaitMessageComponentOptions\n   * @property {CollectorFilter} [filter] The filter applied to this collector\n   * @property {number} [time] Time to wait for an interaction before rejecting\n   * @property {ComponentType} [componentType] The type of component interaction to collect\n   * @property {number} [idle] Time to wait without another message component interaction before ending the collector\n   * @property {boolean} [dispose] Whether to remove the message component interaction after collecting\n   */\n\n  /**\n   * Collects a single component interaction that passes the filter.\n   * The Promise will reject if the time expires.\n   *\n   * @param {AwaitMessageComponentOptions} [options={}] Options to pass to the internal collector\n   * @returns {Promise<MessageComponentInteraction>}\n   * @example\n   * // Collect a message component interaction\n   * const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId';\n   * message.awaitMessageComponent({ filter, time: 15_000 })\n   *   .then(interaction => console.log(`${interaction.customId} was clicked!`))\n   *   .catch(console.error);\n   */\n  async awaitMessageComponent(options = {}) {\n    const _options = { ...options, max: 1 };\n    return new Promise((resolve, reject) => {\n      const collector = this.createMessageComponentCollector(_options);\n      collector.once('end', (interactions, reason) => {\n        const interaction = interactions.first();\n        if (interaction) resolve(interaction);\n        else reject(new DiscordjsError(ErrorCodes.InteractionCollectorError, reason));\n      });\n    });\n  }\n\n  /**\n   * Whether the message is editable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get editable() {\n    const precheck = Boolean(\n      this.author.id === this.client.user.id &&\n      (!this.guild || this.channel?.viewable) &&\n      this.reference?.type !== MessageReferenceType.Forward,\n    );\n\n    // Regardless of permissions thread messages cannot be edited if\n    // the thread is archived or the thread is locked and the bot does not have permission to manage threads.\n    if (this.channel?.isThread()) {\n      if (this.channel.archived) return false;\n      if (this.channel.locked) {\n        const permissions = this.channel.permissionsFor(this.client.user);\n        if (!permissions?.has(PermissionFlagsBits.ManageThreads, true)) return false;\n      }\n    }\n\n    return precheck;\n  }\n\n  /**\n   * Whether the message is deletable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get deletable() {\n    if (UndeletableMessageTypes.includes(this.type)) return false;\n\n    if (!this.guild) {\n      return this.author.id === this.client.user.id;\n    }\n\n    // DMChannel does not have viewable property, so check viewable after proved that message is on a guild.\n    if (!this.channel?.viewable) {\n      return false;\n    }\n\n    const permissions = this.channel?.permissionsFor(this.client.user);\n    if (!permissions) return false;\n    // This flag allows deleting even if timed out\n    if (permissions.has(PermissionFlagsBits.Administrator, false)) return true;\n\n    // The auto moderation action message author is the reference message author\n    return (\n      (this.type !== MessageType.AutoModerationAction && this.author.id === this.client.user.id) ||\n      (permissions.has(PermissionFlagsBits.ManageMessages, false) && !this.guild.members.me.isCommunicationDisabled())\n    );\n  }\n\n  /**\n   * Whether the message is bulk deletable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   * @example\n   * // Filter for bulk deletable messages\n   * channel.bulkDelete(messages.filter(message => message.bulkDeletable));\n   */\n  get bulkDeletable() {\n    return (\n      (this.inGuild() &&\n        Date.now() - this.createdTimestamp < MaxBulkDeletableMessageAge &&\n        this.deletable &&\n        this.channel?.permissionsFor(this.client.user).has(PermissionFlagsBits.ManageMessages, false)) ??\n      false\n    );\n  }\n\n  /**\n   * Whether the message is pinnable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get pinnable() {\n    const { channel } = this;\n\n    if (this.system) return false;\n    if (!this.guild) return true;\n    if (!channel || channel.isVoiceBased() || !channel.viewable) return false;\n\n    const permissions = channel.permissionsFor(this.client.user);\n    if (!permissions) return false;\n\n    return permissions.has(PermissionFlagsBits.ReadMessageHistory | PermissionFlagsBits.PinMessages);\n  }\n\n  /**\n   * Fetches the Message this crosspost/reply/pin-add references, if available to the client\n   *\n   * @returns {Promise<Message>}\n   */\n  async fetchReference() {\n    if (!this.reference) throw new DiscordjsError(ErrorCodes.MessageReferenceMissing);\n    const { channelId, messageId } = this.reference;\n    if (!messageId) throw new DiscordjsError(ErrorCodes.MessageReferenceMissing);\n    const channel = this.client.channels.resolve(channelId);\n    if (!channel) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);\n    return channel.messages.fetch(messageId);\n  }\n\n  /**\n   * Whether the message is crosspostable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get crosspostable() {\n    const bitfield =\n      PermissionFlagsBits.SendMessages |\n      (this.author.id === this.client.user.id ? PermissionsBitField.DefaultBit : PermissionFlagsBits.ManageMessages);\n    const { channel } = this;\n    return Boolean(\n      channel?.type === ChannelType.GuildAnnouncement &&\n      !this.flags.has(MessageFlags.Crossposted) &&\n      this.reference?.type !== MessageReferenceType.Forward &&\n      this.type === MessageType.Default &&\n      !this.poll &&\n      channel.viewable &&\n      channel.permissionsFor(this.client.user)?.has(bitfield, false),\n    );\n  }\n\n  /**\n   * Edits the content of the message.\n   *\n   * @param {string|MessageEditOptions|MessagePayload|FileBodyEncodable<RESTPatchAPIChannelMessageJSONBody>|JSONEncodable<RESTPatchAPIChannelMessageJSONBody>} options The options to provide\n   * @returns {Promise<Message>}\n   * @example\n   * // Update the content of a message\n   * message.edit('This is my new content!')\n   *   .then(msg => console.log(`Updated the content of a message to ${msg.content}`))\n   *   .catch(console.error);\n   */\n  async edit(options) {\n    if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);\n    return this.channel.messages.edit(this, options);\n  }\n\n  /**\n   * Publishes a message in an announcement channel to all channels following it.\n   *\n   * @returns {Promise<Message>}\n   * @example\n   * // Crosspost a message\n   * if (message.channel.type === ChannelType.GuildAnnouncement) {\n   *   message.crosspost()\n   *     .then(() => console.log('Crossposted message'))\n   *     .catch(console.error);\n   * }\n   */\n  async crosspost() {\n    if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);\n    return this.channel.messages.crosspost(this.id);\n  }\n\n  /**\n   * Pins this message to the channel's pinned messages.\n   *\n   * @param {string} [reason] Reason for pinning\n   * @returns {Promise<Message>}\n   * @example\n   * // Pin a message\n   * message.pin()\n   *   .then(console.log)\n   *   .catch(console.error)\n   */\n  async pin(reason) {\n    if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);\n    await this.channel.messages.pin(this.id, reason);\n    return this;\n  }\n\n  /**\n   * Unpins this message from the channel's pinned messages.\n   *\n   * @param {string} [reason] Reason for unpinning\n   * @returns {Promise<Message>}\n   * @example\n   * // Unpin a message\n   * message.unpin()\n   *   .then(console.log)\n   *   .catch(console.error)\n   */\n  async unpin(reason) {\n    if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);\n    await this.channel.messages.unpin(this.id, reason);\n    return this;\n  }\n\n  /**\n   * Adds a reaction to the message.\n   *\n   * @param {EmojiIdentifierResolvable} emoji The emoji to react with\n   * @returns {Promise<MessageReaction>}\n   * @example\n   * // React to a message with a unicode emoji\n   * message.react('🤔')\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // React to a message with a custom emoji\n   * message.react(message.guild.emojis.cache.get('123456789012345678'))\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async react(emoji) {\n    if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);\n    await this.channel.messages.react(this.id, emoji);\n\n    return this.client.actions.MessageReactionAdd.handle(\n      {\n        [this.client.actions.injectedUser]: this.client.user,\n        [this.client.actions.injectedChannel]: this.channel,\n        [this.client.actions.injectedMessage]: this,\n        emoji: resolvePartialEmoji(emoji),\n      },\n      true,\n    ).reaction;\n  }\n\n  /**\n   * Deletes the message.\n   *\n   * @returns {Promise<Message>}\n   * @example\n   * // Delete a message\n   * message.delete()\n   *   .then(msg => console.log(`Deleted message from ${msg.author.username}`))\n   *   .catch(console.error);\n   */\n  async delete() {\n    if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);\n    await this.channel.messages.delete(this.id);\n    return this;\n  }\n\n  /**\n   * Options provided when sending a message as an inline reply.\n   *\n   * @typedef {BaseMessageCreateOptions} MessageReplyOptions\n   * @property {boolean} [failIfNotExists=this.client.options.failIfNotExists] Whether to error if the referenced\n   * message does not exist (creates a standard message in this case when false)\n   */\n\n  /**\n   * Send an inline reply to this message.\n   *\n   * @param {string|MessagePayload|MessageReplyOptions} options The options to provide\n   * @returns {Promise<Message>}\n   * @example\n   * // Reply to a message\n   * message.reply('This is a reply!')\n   *   .then(() => console.log(`Replied to message \"${message.content}\"`))\n   *   .catch(console.error);\n   */\n  async reply(options) {\n    let data;\n\n    if (options instanceof MessagePayload) {\n      data = options;\n    } else {\n      data = MessagePayload.create(this, options, {\n        messageReference: {\n          messageId: this.id,\n          channelId: this.channelId,\n          guildId: this.guildId ?? undefined,\n          type: MessageReferenceType.Default,\n          failIfNotExists: options?.failIfNotExists ?? this.client.options.failIfNotExists,\n        },\n      });\n    }\n\n    return this.client.channels.createMessage(this.channelId, data);\n  }\n\n  /**\n   * Forwards this message.\n   *\n   * @param {TextChannelResolvable} channel The channel to forward this message to.\n   * @returns {Promise<Message>}\n   */\n  async forward(channel) {\n    return this.client.channels.createMessage(channel, {\n      messageReference: {\n        messageId: this.id,\n        channelId: this.channelId,\n        guildId: this.guildId ?? undefined,\n        type: MessageReferenceType.Forward,\n      },\n    });\n  }\n\n  /**\n   * Options for starting a thread on a message.\n   *\n   * @typedef {Object} StartThreadOptions\n   * @property {string} name The name of the new thread\n   * @property {ThreadAutoArchiveDuration} [autoArchiveDuration=this.channel.defaultAutoArchiveDuration] The amount of\n   * time after which the thread should automatically archive in case of no recent activity\n   * @property {string} [reason] Reason for creating the thread\n   * @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the thread in seconds\n   */\n\n  /**\n   * Create a new public thread from this message\n   *\n   * @see GuildTextThreadManager#create\n   * @param {StartThreadOptions} [options] Options for starting a thread on this message\n   * @returns {Promise<ThreadChannel>}\n   */\n  async startThread(options = {}) {\n    if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);\n    if (![ChannelType.GuildText, ChannelType.GuildAnnouncement].includes(this.channel.type)) {\n      throw new DiscordjsError(ErrorCodes.MessageThreadParent);\n    }\n\n    if (this.hasThread) throw new DiscordjsError(ErrorCodes.MessageExistingThread);\n    return this.channel.threads.create({ ...options, startMessage: this });\n  }\n\n  /**\n   * Fetch this message.\n   *\n   * @param {boolean} [force=true] Whether to skip the cache check and request the API\n   * @returns {Promise<Message>}\n   */\n  async fetch(force = true) {\n    if (!this.channel) throw new DiscordjsError(ErrorCodes.ChannelNotCached);\n    return this.channel.messages.fetch({ message: this.id, force });\n  }\n\n  /**\n   * Fetches the webhook used to create this message.\n   *\n   * @returns {Promise<?Webhook>}\n   */\n  async fetchWebhook() {\n    if (!this.webhookId) throw new DiscordjsError(ErrorCodes.WebhookMessage);\n    if (this.webhookId === this.applicationId) throw new DiscordjsError(ErrorCodes.WebhookApplication);\n    return this.client.fetchWebhook(this.webhookId);\n  }\n\n  /**\n   * Suppresses or unsuppresses embeds on a message.\n   *\n   * @param {boolean} [suppress=true] If the embeds should be suppressed or not\n   * @returns {Promise<Message>}\n   */\n  async suppressEmbeds(suppress = true) {\n    const flags = new MessageFlagsBitField(this.flags.bitfield);\n\n    if (suppress) {\n      flags.add(MessageFlags.SuppressEmbeds);\n    } else {\n      flags.remove(MessageFlags.SuppressEmbeds);\n    }\n\n    return this.edit({ flags });\n  }\n\n  /**\n   * Removes the attachments from this message.\n   *\n   * @returns {Promise<Message>}\n   */\n  async removeAttachments() {\n    return this.edit({ attachments: [] });\n  }\n\n  /**\n   * Resolves a component by a custom id.\n   *\n   * @param {string} customId The custom id to resolve against\n   * @returns {?MessageActionRowComponent}\n   */\n  resolveComponent(customId) {\n    return findComponentByCustomId(this.components, customId);\n  }\n\n  /**\n   * Used mainly internally. Whether two messages are identical in properties. If you want to compare messages\n   * without checking all the properties, use `message.id === message2.id`, which is much more efficient. This\n   * method allows you to see if there are differences in content, embeds, attachments, nonce and tts properties.\n   *\n   * @param {Message} message The message to compare it to\n   * @param {APIMessage} [rawData] Raw data passed through the WebSocket about this message\n   * @returns {boolean}\n   */\n  equals(message, rawData) {\n    if (!message) return false;\n    const embedUpdate = !message.author && !message.attachments;\n    if (embedUpdate) return this.id === message.id && this.embeds.length === message.embeds.length;\n\n    let equal =\n      this.id === message.id &&\n      this.author.id === message.author.id &&\n      this.content === message.content &&\n      this.nonce === message.nonce &&\n      this.tts === message.tts &&\n      this.attachments.size === message.attachments.size &&\n      this.embeds.length === message.embeds.length &&\n      this.attachments.every(attachment => message.attachments.has(attachment.id)) &&\n      this.embeds.every((embed, index) => embed.equals(message.embeds[index]));\n\n    if (equal && rawData) {\n      equal =\n        this.mentions.everyone === message.mentions.everyone &&\n        this.createdTimestamp === Date.parse(rawData.timestamp) &&\n        this.editedTimestamp === Date.parse(rawData.edited_timestamp);\n    }\n\n    return equal;\n  }\n\n  /**\n   * Whether this message is from a guild.\n   *\n   * @returns {boolean}\n   */\n  inGuild() {\n    return Boolean(this.guildId);\n  }\n\n  /**\n   * When concatenated with a string, this automatically concatenates the message's content instead of the object.\n   *\n   * @returns {string}\n   * @example\n   * // Logs: Message: This is a message!\n   * console.log(`Message: ${message}`);\n   */\n  toString() {\n    return this.content;\n  }\n\n  toJSON() {\n    return super.toJSON({\n      channel: 'channelId',\n      author: 'authorId',\n      groupActivityApplication: 'groupActivityApplicationId',\n      guild: 'guildId',\n      cleanContent: true,\n      member: false,\n      reactions: false,\n    });\n  }\n}\n\nexports.Message = Message;\n"
  },
  {
    "path": "packages/discord.js/src/structures/MessageCollector.js",
    "content": "'use strict';\n\nconst { Events } = require('../util/Events.js');\nconst { Collector } = require('./interfaces/Collector.js');\n\n/**\n * @typedef {CollectorOptions} MessageCollectorOptions\n * @property {number} max The maximum amount of messages to collect\n * @property {number} maxProcessed The maximum amount of messages to process\n */\n\n/**\n * Collects messages on a channel.\n * Will automatically stop if the channel ({@link Client#event:channelDelete channelDelete}),\n * thread ({@link Client#event:threadDelete threadDelete}), or\n * guild ({@link Client#event:guildDelete guildDelete}) is deleted.\n *\n * @extends {Collector}\n */\nclass MessageCollector extends Collector {\n  /**\n   * @param {TextBasedChannels} channel The channel\n   * @param {MessageCollectorOptions} options The options to be applied to this collector\n   * @emits MessageCollector#message\n   */\n  constructor(channel, options = {}) {\n    super(channel.client, options);\n\n    /**\n     * The channel\n     *\n     * @type {TextBasedChannels}\n     */\n    this.channel = channel;\n\n    /**\n     * Total number of messages that were received in the channel during message collection\n     *\n     * @type {number}\n     */\n    this.received = 0;\n\n    const bulkDeleteListener = async messages => {\n      for (const message of messages.values()) await this.handleDispose(message);\n    };\n\n    this._handleChannelDeletion = this._handleChannelDeletion.bind(this);\n    this._handleThreadDeletion = this._handleThreadDeletion.bind(this);\n    this._handleGuildDeletion = this._handleGuildDeletion.bind(this);\n\n    this.client.incrementMaxListeners();\n    this.client.on(Events.MessageCreate, this.handleCollect);\n    this.client.on(Events.MessageDelete, this.handleDispose);\n    this.client.on(Events.MessageBulkDelete, bulkDeleteListener);\n    this.client.on(Events.ChannelDelete, this._handleChannelDeletion);\n    this.client.on(Events.ThreadDelete, this._handleThreadDeletion);\n    this.client.on(Events.GuildDelete, this._handleGuildDeletion);\n\n    this.once('end', () => {\n      this.client.removeListener(Events.MessageCreate, this.handleCollect);\n      this.client.removeListener(Events.MessageDelete, this.handleDispose);\n      this.client.removeListener(Events.MessageBulkDelete, bulkDeleteListener);\n      this.client.removeListener(Events.ChannelDelete, this._handleChannelDeletion);\n      this.client.removeListener(Events.ThreadDelete, this._handleThreadDeletion);\n      this.client.removeListener(Events.GuildDelete, this._handleGuildDeletion);\n      this.client.decrementMaxListeners();\n    });\n  }\n\n  /**\n   * Handles a message for possible collection.\n   *\n   * @param {Message} message The message that could be collected\n   * @returns {?Snowflake}\n   * @private\n   */\n  collect(message) {\n    /**\n     * Emitted whenever a message is collected.\n     *\n     * @event MessageCollector#collect\n     * @param {Message} message The message that was collected\n     */\n    if (message.channelId !== this.channel.id) return null;\n    this.received++;\n    return message.id;\n  }\n\n  /**\n   * Handles a message for possible disposal.\n   *\n   * @param {Message} message The message that could be disposed of\n   * @returns {?Snowflake}\n   */\n  dispose(message) {\n    /**\n     * Emitted whenever a message is disposed of.\n     *\n     * @event MessageCollector#dispose\n     * @param {Message} message The message that was disposed of\n     */\n    return message.channelId === this.channel.id ? message.id : null;\n  }\n\n  /**\n   * The reason this collector has ended with, or null if it hasn't ended yet\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get endReason() {\n    if (this.options.max && this.collected.size >= this.options.max) return 'limit';\n    if (this.options.maxProcessed && this.received === this.options.maxProcessed) return 'processedLimit';\n    return super.endReason;\n  }\n\n  /**\n   * Handles checking if the channel has been deleted, and if so, stops the collector with the reason 'channelDelete'.\n   *\n   * @private\n   * @param {GuildChannel} channel The channel that was deleted\n   * @returns {void}\n   */\n  _handleChannelDeletion(channel) {\n    if (channel.id === this.channel.id || channel.id === this.channel.parentId) {\n      this.stop('channelDelete');\n    }\n  }\n\n  /**\n   * Handles checking if the thread has been deleted, and if so, stops the collector with the reason 'threadDelete'.\n   *\n   * @private\n   * @param {ThreadChannel} thread The thread that was deleted\n   * @returns {void}\n   */\n  _handleThreadDeletion(thread) {\n    if (thread.id === this.channel.id) {\n      this.stop('threadDelete');\n    }\n  }\n\n  /**\n   * Handles checking if the guild has been deleted, and if so, stops the collector with the reason 'guildDelete'.\n   *\n   * @private\n   * @param {Guild} guild The guild that was deleted\n   * @returns {void}\n   */\n  _handleGuildDeletion(guild) {\n    if (guild.id === this.channel.guild?.id) {\n      this.stop('guildDelete');\n    }\n  }\n}\n\nexports.MessageCollector = MessageCollector;\n"
  },
  {
    "path": "packages/discord.js/src/structures/MessageComponentInteraction.js",
    "content": "'use strict';\n\nconst { lazy } = require('@discordjs/util');\nconst { findComponentByCustomId } = require('../util/Components.js');\nconst { BaseInteraction } = require('./BaseInteraction.js');\nconst { InteractionWebhook } = require('./InteractionWebhook.js');\nconst { InteractionResponses } = require('./interfaces/InteractionResponses.js');\n\nconst getMessage = lazy(() => require('./Message.js').Message);\n\n/**\n * Represents a message component interaction.\n *\n * @extends {BaseInteraction}\n * @implements {InteractionResponses}\n */\nclass MessageComponentInteraction extends BaseInteraction {\n  constructor(client, data) {\n    super(client, data);\n\n    /**\n     * The id of the channel this interaction was sent in\n     *\n     * @type {Snowflake}\n     * @name MessageComponentInteraction#channelId\n     */\n\n    /**\n     * The message to which the component was attached\n     *\n     * @type {Message}\n     */\n    this.message = this.channel?.messages._add(data.message) ?? new (getMessage())(client, data.message);\n\n    /**\n     * The custom id of the component which was interacted with\n     *\n     * @type {string}\n     */\n    this.customId = data.data.custom_id;\n\n    /**\n     * The type of component which was interacted with\n     *\n     * @type {ComponentType}\n     */\n    this.componentType = data.data.component_type;\n\n    /**\n     * Whether the reply to this interaction has been deferred\n     *\n     * @type {boolean}\n     */\n    this.deferred = false;\n\n    /**\n     * Whether the reply to this interaction is ephemeral\n     *\n     * @type {?boolean}\n     */\n    this.ephemeral = null;\n\n    /**\n     * Whether this interaction has already been replied to\n     *\n     * @type {boolean}\n     */\n    this.replied = false;\n\n    /**\n     * An associated interaction webhook, can be used to further interact with this interaction\n     *\n     * @type {InteractionWebhook}\n     */\n    this.webhook = new InteractionWebhook(this.client, this.applicationId, this.token);\n  }\n\n  /**\n   * Components that can be placed in an action row for messages.\n   * - ButtonComponent\n   * - StringSelectMenuComponent\n   * - UserSelectMenuComponent\n   * - RoleSelectMenuComponent\n   * - MentionableSelectMenuComponent\n   * - ChannelSelectMenuComponent\n   *\n   * @typedef {ButtonComponent|StringSelectMenuComponent|UserSelectMenuComponent|\n   * RoleSelectMenuComponent|MentionableSelectMenuComponent|ChannelSelectMenuComponent} MessageActionRowComponent\n   */\n\n  /**\n   * The component which was interacted with\n   *\n   * @type {MessageActionRowComponent|APIComponentInMessageActionRow}\n   * @readonly\n   */\n  get component() {\n    return findComponentByCustomId(this.message.components, this.customId);\n  }\n\n  // These are here only for documentation purposes - they are implemented by InteractionResponses\n\n  deferReply() {}\n\n  reply() {}\n\n  fetchReply() {}\n\n  editReply() {}\n\n  deleteReply() {}\n\n  followUp() {}\n\n  deferUpdate() {}\n\n  update() {}\n\n  launchActivity() {}\n\n  showModal() {}\n\n  awaitModalSubmit() {}\n}\n\nInteractionResponses.applyToClass(MessageComponentInteraction);\n\nexports.MessageComponentInteraction = MessageComponentInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/MessageContextMenuCommandInteraction.js",
    "content": "'use strict';\n\nconst { ContextMenuCommandInteraction } = require('./ContextMenuCommandInteraction.js');\n\n/**\n * Represents a message context menu interaction.\n *\n * @extends {ContextMenuCommandInteraction}\n */\nclass MessageContextMenuCommandInteraction extends ContextMenuCommandInteraction {\n  /**\n   * The message this interaction was sent from\n   *\n   * @type {Message|APIMessage}\n   * @readonly\n   */\n  get targetMessage() {\n    return this.options.getMessage('message');\n  }\n}\n\nexports.MessageContextMenuCommandInteraction = MessageContextMenuCommandInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/MessageMentions.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { FormattingPatterns } = require('discord-api-types/v10');\nconst { flatten } = require('../util/Util.js');\n\n/**\n * Keeps track of mentions in a {@link Message}.\n */\nclass MessageMentions {\n  /**\n   * A regular expression that matches `@everyone` and `@here`.\n   * The `mention` group property is present on the `exec` result of this expression.\n   *\n   * @type {RegExp}\n   * @memberof MessageMentions\n   */\n  static EveryonePattern = /@(?<mention>everyone|here)/;\n\n  /**\n   * A regular expression that matches user mentions like `<@81440962496172032>`.\n   * The `id` group property is present on the `exec` result of this expression.\n   *\n   * @type {RegExp}\n   * @memberof MessageMentions\n   */\n  static UsersPattern = FormattingPatterns.UserWithOptionalNickname;\n\n  /**\n   * A regular expression that matches role mentions like `<@&297577916114403338>`.\n   * The `id` group property is present on the `exec` result of this expression.\n   *\n   * @type {RegExp}\n   * @memberof MessageMentions\n   */\n  static RolesPattern = FormattingPatterns.Role;\n\n  /**\n   * A regular expression that matches channel mentions like `<#222079895583457280>`.\n   * The `id` group property is present on the `exec` result of this expression.\n   *\n   * @type {RegExp}\n   * @memberof MessageMentions\n   */\n  static ChannelsPattern = FormattingPatterns.Channel;\n\n  /**\n   * A global regular expression variant of {@link MessageMentions.ChannelsPattern}.\n   *\n   * @type {RegExp}\n   * @memberof MessageMentions\n   * @private\n   */\n  static GlobalChannelsPattern = new RegExp(this.ChannelsPattern.source, 'g');\n\n  /**\n   * A global regular expression variant of {@link MessageMentions.UsersPattern}.\n   *\n   * @type {RegExp}\n   * @memberof MessageMentions\n   * @private\n   */\n  static GlobalUsersPattern = new RegExp(this.UsersPattern.source, 'g');\n\n  constructor(message, users, roles, everyone, crosspostedChannels, repliedUser) {\n    /**\n     * The client the message is from\n     *\n     * @type {Client}\n     * @readonly\n     */\n    Object.defineProperty(this, 'client', { value: message.client });\n\n    /**\n     * The guild the message is in\n     *\n     * @type {?Guild}\n     * @readonly\n     */\n    Object.defineProperty(this, 'guild', { value: message.guild });\n\n    /**\n     * The initial message content\n     *\n     * @type {string}\n     * @readonly\n     * @private\n     */\n    Object.defineProperty(this, '_content', { value: message.content });\n\n    /**\n     * Whether `@everyone` or `@here` were mentioned\n     *\n     * @type {boolean}\n     */\n    this.everyone = Boolean(everyone);\n\n    if (users) {\n      if (users instanceof Collection) {\n        /**\n         * Any users that were mentioned\n         * <info>Order as received from the API, not as they appear in the message content</info>\n         *\n         * @type {Collection<Snowflake, User>}\n         */\n        this.users = new Collection(users);\n      } else {\n        this.users = new Collection();\n        for (const mention of users) {\n          if (mention.member && message.guild) {\n            message.guild.members._add(Object.assign(mention.member, { user: mention }));\n          }\n\n          const user = message.client.users._add(mention);\n          this.users.set(user.id, user);\n        }\n      }\n    } else {\n      this.users = new Collection();\n    }\n\n    if (roles instanceof Collection) {\n      /**\n       * Any roles that were mentioned\n       * <info>Order as received from the API, not as they appear in the message content</info>\n       *\n       * @type {Collection<Snowflake, Role>}\n       */\n      this.roles = new Collection(roles);\n    } else if (roles) {\n      this.roles = new Collection();\n      const guild = message.guild;\n      if (guild) {\n        for (const mention of roles) {\n          const role = guild.roles.cache.get(mention);\n          if (role) this.roles.set(role.id, role);\n        }\n      }\n    } else {\n      this.roles = new Collection();\n    }\n\n    /**\n     * Cached members for {@link MessageMentions#members}\n     *\n     * @type {?Collection<Snowflake, GuildMember>}\n     * @private\n     */\n    this._members = null;\n\n    /**\n     * Cached channels for {@link MessageMentions#channels}\n     *\n     * @type {?Collection<Snowflake, BaseChannel>}\n     * @private\n     */\n    this._channels = null;\n\n    /**\n     * Cached users for {@link MessageMentions#parsedUsers}\n     *\n     * @type {?Collection<Snowflake, User>}\n     * @private\n     */\n    this._parsedUsers = null;\n\n    /**\n     * Crossposted channel data.\n     *\n     * @typedef {Object} CrosspostedChannel\n     * @property {Snowflake} channelId The mentioned channel's id\n     * @property {Snowflake} guildId The id of the guild that has the channel\n     * @property {ChannelType} type The channel's type\n     * @property {string} name The channel's name\n     */\n\n    if (crosspostedChannels) {\n      if (crosspostedChannels instanceof Collection) {\n        /**\n         * A collection of crossposted channels\n         * <info>Order as received from the API, not as they appear in the message content</info>\n         *\n         * @type {Collection<Snowflake, CrosspostedChannel>}\n         */\n        this.crosspostedChannels = new Collection(crosspostedChannels);\n      } else {\n        this.crosspostedChannels = new Collection();\n        for (const crosspostedChannel of crosspostedChannels) {\n          this.crosspostedChannels.set(crosspostedChannel.id, {\n            channelId: crosspostedChannel.id,\n            guildId: crosspostedChannel.guild_id,\n            type: crosspostedChannel.type,\n            name: crosspostedChannel.name,\n          });\n        }\n      }\n    } else {\n      this.crosspostedChannels = new Collection();\n    }\n\n    /**\n     * The author of the message that this message is a reply to\n     *\n     * @type {?User}\n     */\n    this.repliedUser = repliedUser ? this.client.users._add(repliedUser) : null;\n  }\n\n  /**\n   * Any members that were mentioned (only in {@link Guild}s)\n   * <info>Order as received from the API, not as they appear in the message content</info>\n   *\n   * @type {?Collection<Snowflake, GuildMember>}\n   * @readonly\n   */\n  get members() {\n    if (this._members) return this._members;\n    if (!this.guild) return null;\n    this._members = new Collection();\n    for (const user of this.users.values()) {\n      const member = this.guild.members.resolve(user);\n      if (member) this._members.set(member.user.id, member);\n    }\n\n    return this._members;\n  }\n\n  /**\n   * Any channels that were mentioned\n   * <info>Order as they appear first in the message content</info>\n   *\n   * @type {Collection<Snowflake, BaseChannel>}\n   * @readonly\n   */\n  get channels() {\n    if (this._channels) return this._channels;\n    this._channels = new Collection();\n    let matches;\n\n    while ((matches = this.constructor.GlobalChannelsPattern.exec(this._content)) !== null) {\n      const channel = this.client.channels.cache.get(matches.groups.id);\n      if (channel) this._channels.set(channel.id, channel);\n    }\n\n    return this._channels;\n  }\n\n  /**\n   * Any user mentions that were included in the message content\n   * <info>Order as they appear first in the message content</info>\n   *\n   * @type {Collection<Snowflake, User>}\n   * @readonly\n   */\n  get parsedUsers() {\n    if (this._parsedUsers) return this._parsedUsers;\n    this._parsedUsers = new Collection();\n    let matches;\n    while ((matches = this.constructor.GlobalUsersPattern.exec(this._content)) !== null) {\n      const user = this.client.users.cache.get(matches[1]);\n      if (user) this._parsedUsers.set(user.id, user);\n    }\n\n    return this._parsedUsers;\n  }\n\n  /**\n   * Options used to check for a mention.\n   *\n   * @typedef {Object} MessageMentionsHasOptions\n   * @property {boolean} [ignoreDirect=false] Whether to ignore direct mentions to the item\n   * @property {boolean} [ignoreRoles=false] Whether to ignore role mentions to a guild member\n   * @property {boolean} [ignoreRepliedUser=false] Whether to ignore replied user mention to an user\n   * @property {boolean} [ignoreEveryone=false] Whether to ignore `@everyone`/`@here` mentions\n   */\n\n  /**\n   * Checks if a user, guild member, thread member, role, or channel is mentioned.\n   * Takes into account user mentions, role mentions, channel mentions,\n   * replied user mention, and `@everyone`/`@here` mentions.\n   *\n   * @param {UserResolvable|RoleResolvable|ChannelResolvable} data The User/Role/Channel to check for\n   * @param {MessageMentionsHasOptions} [options] The options for the check\n   * @returns {boolean}\n   */\n  has(data, { ignoreDirect = false, ignoreRoles = false, ignoreRepliedUser = false, ignoreEveryone = false } = {}) {\n    const user = this.client.users.resolve(data);\n\n    if (!ignoreEveryone && user && this.everyone) return true;\n\n    const userWasRepliedTo = user && this.repliedUser?.id === user.id;\n\n    if (!ignoreRepliedUser && userWasRepliedTo && this.users.has(user.id)) return true;\n\n    if (!ignoreDirect) {\n      if (user && (!ignoreRepliedUser || this.parsedUsers.has(user.id)) && this.users.has(user.id)) return true;\n\n      const role = this.guild?.roles.resolve(data);\n      if (role && this.roles.has(role.id)) return true;\n\n      const channel = this.client.channels.resolve(data);\n      if (channel && this.channels.has(channel.id)) return true;\n    }\n\n    if (!ignoreRoles) {\n      const member = this.guild?.members.resolve(data);\n      if (member) {\n        for (const mentionedRole of this.roles.values()) if (member.roles.cache.has(mentionedRole.id)) return true;\n      }\n    }\n\n    return false;\n  }\n\n  toJSON() {\n    return flatten(this, {\n      members: true,\n      channels: true,\n    });\n  }\n}\n\nexports.MessageMentions = MessageMentions;\n"
  },
  {
    "path": "packages/discord.js/src/structures/MessagePayload.js",
    "content": "'use strict';\n\nconst { Buffer } = require('node:buffer');\nconst { isJSONEncodable, lazy } = require('@discordjs/util');\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { DiscordjsError, DiscordjsRangeError, ErrorCodes } = require('../errors/index.js');\nconst { resolveFile } = require('../util/DataResolver.js');\nconst { MessageFlagsBitField } = require('../util/MessageFlagsBitField.js');\nconst { findName, verifyString, resolvePartialEmoji } = require('../util/Util.js');\n\n// Fixes circular dependencies.\nconst getWebhook = lazy(() => require('./Webhook.js').Webhook);\nconst getUser = lazy(() => require('./User.js').User);\nconst getGuildMember = lazy(() => require('./GuildMember.js').GuildMember);\nconst getMessage = lazy(() => require('./Message.js').Message);\nconst getMessageManager = lazy(() => require('../managers/MessageManager.js').MessageManager);\n\n/**\n * Represents a message to be sent to the API.\n */\nclass MessagePayload {\n  /**\n   * @param {MessageTarget} target The target for this message to be sent to\n   * @param {MessagePayloadOption} options The payload of this message\n   */\n  constructor(target, options) {\n    /**\n     * The target for this message to be sent to\n     *\n     * @type {MessageTarget}\n     */\n    this.target = target;\n\n    /**\n     * The payload of this message.\n     *\n     * @type {MessagePayloadOption}\n     */\n    this.options = options;\n\n    /**\n     * Body sendable to the API\n     *\n     * @type {?APIMessage}\n     */\n    this.body = null;\n\n    /**\n     * Files sendable to the API\n     *\n     * @type {?RawFile[]}\n     */\n    this.files = null;\n  }\n\n  /**\n   * Whether or not the target is a {@link Webhook}\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get isWebhook() {\n    return this.target instanceof getWebhook();\n  }\n\n  /**\n   * Whether or not the target is a {@link User}\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get isUser() {\n    return this.target instanceof getUser() || this.target instanceof getGuildMember();\n  }\n\n  /**\n   * Whether or not the target is a {@link Message}\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get isMessage() {\n    return this.target instanceof getMessage();\n  }\n\n  /**\n   * Whether or not the target is a {@link MessageManager}\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get isMessageManager() {\n    return this.target instanceof getMessageManager();\n  }\n\n  /**\n   * Makes the content of this message.\n   *\n   * @returns {?string}\n   */\n  makeContent() {\n    let content;\n    if (this.options.content === null) {\n      content = '';\n    } else if (this.options.content !== undefined) {\n      content = verifyString(this.options.content, DiscordjsRangeError, ErrorCodes.MessageContentType, true);\n    }\n\n    return content;\n  }\n\n  /**\n   * Resolves the body.\n   *\n   * @returns {MessagePayload}\n   */\n  resolveBody() {\n    if (this.body) return this;\n    const isWebhook = this.isWebhook;\n\n    const content = this.makeContent();\n    const tts = Boolean(this.options.tts);\n\n    let nonce;\n    if (this.options.nonce !== undefined) {\n      nonce = this.options.nonce;\n      if (typeof nonce === 'number' ? !Number.isInteger(nonce) : typeof nonce !== 'string') {\n        throw new DiscordjsRangeError(ErrorCodes.MessageNonceType);\n      }\n    }\n\n    let enforce_nonce = Boolean(this.options.enforceNonce);\n\n    // If `nonce` isn't provided, generate one & set `enforceNonce`\n    // Unless `enforceNonce` is explicitly set to `false`(not just falsy)\n    if (nonce === undefined) {\n      if (this.options.enforceNonce !== false && this.target.client.options.enforceNonce) {\n        nonce = DiscordSnowflake.generate().toString();\n        enforce_nonce = true;\n      } else if (enforce_nonce) {\n        throw new DiscordjsError(ErrorCodes.MessageNonceRequired);\n      }\n    }\n\n    const components = this.options.components?.map(component =>\n      isJSONEncodable(component) ? component.toJSON() : this.target.client.options.jsonTransformer(component),\n    );\n\n    let username;\n    let avatarURL;\n    let threadName;\n    let appliedTags;\n    if (isWebhook) {\n      username = this.options.username ?? this.target.name;\n      if (this.options.avatarURL) avatarURL = this.options.avatarURL;\n      if (this.options.threadName) threadName = this.options.threadName;\n      if (this.options.appliedTags) appliedTags = this.options.appliedTags;\n    }\n\n    let flags;\n    if (\n      // eslint-disable-next-line eqeqeq\n      this.options.flags != null\n    ) {\n      flags = new MessageFlagsBitField(this.options.flags).bitfield;\n    }\n\n    let allowedMentions =\n      this.options.allowedMentions === undefined\n        ? this.target.client.options.allowedMentions\n        : this.options.allowedMentions;\n\n    if (allowedMentions?.repliedUser !== undefined) {\n      allowedMentions = { ...allowedMentions, replied_user: allowedMentions.repliedUser };\n      delete allowedMentions.repliedUser;\n    }\n\n    let message_reference;\n    if (this.options.messageReference) {\n      const reference = this.options.messageReference;\n\n      if (reference.messageId) {\n        message_reference = {\n          message_id: reference.messageId,\n          channel_id: reference.channelId,\n          guild_id: reference.guildId,\n          type: reference.type,\n          fail_if_not_exists: reference.failIfNotExists ?? this.target.client.options.failIfNotExists,\n        };\n      }\n    }\n\n    const attachments = this.options.files?.map((file, index) => ({\n      id: index.toString(),\n      description: file.description,\n      title: file.title,\n      waveform: file.waveform,\n      duration_secs: file.duration,\n    }));\n\n    // Only passable during edits\n    if (Array.isArray(this.options.attachments)) {\n      attachments.push(\n        // Note how we don't check for file body encodable, since we aren't expecting file data here\n        ...this.options.attachments.map(attachment => (isJSONEncodable(attachment) ? attachment.toJSON() : attachment)),\n      );\n    }\n\n    let poll;\n    if (this.options.poll) {\n      poll = isJSONEncodable(this.options.poll)\n        ? this.options.poll.toJSON()\n        : {\n            question: {\n              text: this.options.poll.question.text,\n            },\n            answers: this.options.poll.answers.map(answer => ({\n              poll_media: { text: answer.text, emoji: resolvePartialEmoji(answer.emoji) },\n            })),\n            duration: this.options.poll.duration,\n            allow_multiselect: this.options.poll.allowMultiselect,\n            layout_type: this.options.poll.layoutType,\n          };\n    }\n\n    this.body = {\n      content,\n      tts,\n      nonce,\n      enforce_nonce,\n      embeds: this.options.embeds?.map(embed =>\n        isJSONEncodable(embed) ? embed.toJSON() : this.target.client.options.jsonTransformer(embed),\n      ),\n      components,\n      username,\n      avatar_url: avatarURL,\n      allowed_mentions:\n        this.isMessage && message_reference === undefined && this.target.author.id !== this.target.client.user.id\n          ? undefined\n          : allowedMentions,\n      flags,\n      message_reference,\n      attachments,\n      sticker_ids: this.options.stickers?.map(sticker => sticker.id ?? sticker),\n      thread_name: threadName,\n      applied_tags: appliedTags,\n      poll,\n    };\n    return this;\n  }\n\n  /**\n   * Resolves files.\n   *\n   * @returns {Promise<MessagePayload>}\n   */\n  async resolveFiles() {\n    if (this.files) return this;\n\n    this.files = await Promise.all(this.options.files?.map(file => this.constructor.resolveFile(file)) ?? []);\n    return this;\n  }\n\n  /**\n   * Resolves a single file into an object sendable to the API.\n   *\n   * @param {AttachmentPayload|BufferResolvable|Stream} fileLike Something that could be resolved to a file\n   * @returns {Promise<RawFile>}\n   */\n  static async resolveFile(fileLike) {\n    let attachment;\n    let name;\n\n    const ownAttachment =\n      typeof fileLike === 'string' || fileLike instanceof Buffer || typeof fileLike.pipe === 'function';\n    if (ownAttachment) {\n      attachment = fileLike;\n      name = findName(attachment);\n    } else {\n      attachment = fileLike.attachment;\n      name = fileLike.name ?? findName(attachment);\n    }\n\n    const { data, contentType } = await resolveFile(attachment);\n    return { data, name, contentType };\n  }\n\n  /**\n   * Creates a {@link MessagePayload} from user-level arguments.\n   *\n   * @param {MessageTarget} target Target to send to\n   * @param {string|MessagePayloadOption} options Options or content to use\n   * @param {MessagePayloadOption} [extra={}] Extra options to add onto specified options\n   * @returns {MessagePayload}\n   */\n  static create(target, options, extra = {}) {\n    return new this(\n      target,\n      typeof options !== 'object' || options === null ? { content: options, ...extra } : { ...options, ...extra },\n    );\n  }\n}\n\nexports.MessagePayload = MessagePayload;\n\n/**\n * A target for a message.\n *\n * @typedef {TextBasedChannels|ChannelManager|Webhook|BaseInteraction|InteractionWebhook|\n * Message|MessageManager} MessageTarget\n */\n\n/**\n * A possible payload option.\n *\n * @typedef {MessageCreateOptions|MessageEditOptions|WebhookMessageCreateOptions|WebhookMessageEditOptions|\n * InteractionReplyOptions|InteractionUpdateOptions} MessagePayloadOption\n */\n\n/**\n * @external RawFile\n * @see {@link https://discord.js.org/docs/packages/rest/stable/RawFile:Interface}\n */\n"
  },
  {
    "path": "packages/discord.js/src/structures/MessageReaction.js",
    "content": "'use strict';\n\nconst { Routes } = require('discord-api-types/v10');\nconst { ReactionUserManager } = require('../managers/ReactionUserManager.js');\nconst { flatten, resolveGuildEmoji } = require('../util/Util.js');\nconst { ApplicationEmoji } = require('./ApplicationEmoji.js');\nconst { GuildEmoji } = require('./GuildEmoji.js');\nconst { ReactionEmoji } = require('./ReactionEmoji.js');\n\n/**\n * Represents a reaction to a message.\n */\nclass MessageReaction {\n  constructor(client, data, message) {\n    /**\n     * The client that instantiated this message reaction\n     *\n     * @name MessageReaction#client\n     * @type {Client}\n     * @readonly\n     */\n    Object.defineProperty(this, 'client', { value: client });\n\n    /**\n     * The message that this reaction refers to\n     *\n     * @type {Message}\n     */\n    this.message = message;\n\n    /**\n     * Whether the client has given this reaction\n     *\n     * @type {boolean}\n     */\n    this.me = data.me;\n\n    /**\n     * Whether the client has super-reacted using this emoji\n     *\n     * @type {boolean}\n     */\n    this.meBurst = Boolean(data.me_burst);\n\n    /**\n     * A manager of the users that have given this reaction\n     *\n     * @type {ReactionUserManager}\n     */\n    this.users = new ReactionUserManager(this, this.me ? [client.user] : []);\n\n    this._emoji = new ReactionEmoji(this, data.emoji);\n\n    this.burstColors = null;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if (data.burst_colors) {\n      /**\n       * Hexadecimal colors used for this super reaction\n       *\n       * @type {?string[]}\n       */\n      this.burstColors = data.burst_colors;\n    }\n\n    if ('count' in data) {\n      /**\n       * The number of people that have given the same reaction\n       *\n       * @type {?number}\n       */\n      this.count ??= data.count;\n    }\n\n    if ('count_details' in data) {\n      /**\n       * The reaction count details object contains information about super and normal reaction counts.\n       *\n       * @typedef {Object} ReactionCountDetailsData\n       * @property {number} burst Count of super reactions\n       * @property {number} normal Count of normal reactions\n       */\n\n      /**\n       * The reaction count details object contains information about super and normal reaction counts.\n       *\n       * @type {ReactionCountDetailsData}\n       */\n      this.countDetails = {\n        burst: data.count_details.burst,\n        normal: data.count_details.normal,\n      };\n    } else {\n      this.countDetails ??= { burst: 0, normal: 0 };\n    }\n  }\n\n  /**\n   * Makes the client user react with this reaction\n   *\n   * @returns {Promise<MessageReaction>}\n   */\n  async react() {\n    return this.message.react(this.emoji);\n  }\n\n  /**\n   * Removes all users from this reaction.\n   *\n   * @returns {Promise<MessageReaction>}\n   */\n  async remove() {\n    await this.client.rest.delete(\n      Routes.channelMessageReaction(this.message.channelId, this.message.id, this._emoji.identifier),\n    );\n    return this;\n  }\n\n  /**\n   * The emoji of this reaction. Either a {@link GuildEmoji} object for known custom emojis,\n   * {@link ApplicationEmoji} for application emojis, or a {@link ReactionEmoji} object\n   * which has fewer properties. Whatever the prototype of the emoji, it will still have\n   * `name`, `id`, `identifier` and `toString()`\n   *\n   * @type {GuildEmoji|ReactionEmoji|ApplicationEmoji}\n   * @readonly\n   */\n  get emoji() {\n    if (this._emoji instanceof GuildEmoji) return this._emoji;\n    if (this._emoji instanceof ApplicationEmoji) return this._emoji;\n    // Check to see if the emoji has become known to the client\n    if (this._emoji.id) {\n      const applicationEmojis = this.message.client.application.emojis.cache;\n      if (applicationEmojis.has(this._emoji.id)) {\n        const innerEmoji = applicationEmojis.get(this._emoji.id);\n        this._emoji = innerEmoji;\n        return innerEmoji;\n      }\n    }\n\n    const emoji = resolveGuildEmoji(this.client, this._emoji.id);\n    return emoji ?? this._emoji;\n  }\n\n  /**\n   * Whether or not this reaction is a partial\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get partial() {\n    return this.count === null;\n  }\n\n  /**\n   * Fetch this reaction.\n   *\n   * @returns {Promise<MessageReaction>}\n   */\n  async fetch() {\n    const message = await this.message.fetch();\n    const existing = message.reactions.cache.get(this.emoji.id ?? this.emoji.name);\n    // The reaction won't get set when it has been completely removed\n    this._patch(existing ?? { count: 0 });\n    return this;\n  }\n\n  toJSON() {\n    return flatten(this, { emoji: 'emojiId', message: 'messageId' });\n  }\n\n  valueOf() {\n    return this._emoji.id ?? this._emoji.name;\n  }\n\n  _add(user, burst) {\n    if (this.partial) return;\n    this.users.cache.set(user.id, user);\n    if (!this.me || user.id !== this.message.client.user.id || this.count === 0) {\n      this.count++;\n      if (burst) this.countDetails.burst++;\n      else this.countDetails.normal++;\n    }\n\n    if (user.id === this.message.client.user.id) {\n      if (burst) this.meBurst = true;\n      else this.me = true;\n    }\n  }\n\n  _remove(user, burst) {\n    if (this.partial) return;\n    this.users.cache.delete(user.id);\n    if (!this.me || user.id !== this.message.client.user.id) {\n      this.count--;\n      if (burst) this.countDetails.burst--;\n      else this.countDetails.normal--;\n    }\n\n    if (user.id === this.message.client.user.id) {\n      if (burst) this.meBurst = false;\n      else this.me = false;\n    }\n\n    if (this.count <= 0 && this.users.cache.size === 0) {\n      this.message.reactions.cache.delete(this.emoji.id ?? this.emoji.name);\n    }\n  }\n}\n\nexports.MessageReaction = MessageReaction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ModalComponentResolver.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { ComponentType } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\n\n/**\n * @typedef {Object} ModalSelectedMentionables\n * @property {Collection<Snowflake, User>} users The selected users\n * @property {Collection<Snowflake, GuildMember | APIGuildMember>} members The selected members\n * @property {Collection<Snowflake, Role | APIRole>} roles The selected roles\n */\n\n/**\n * A resolver for modal submit components\n */\nclass ModalComponentResolver {\n  constructor(client, components, resolved) {\n    /**\n     * The client that instantiated this.\n     *\n     * @name ModalComponentResolver#client\n     * @type {Client}\n     * @readonly\n     */\n    Object.defineProperty(this, 'client', { value: client });\n\n    /**\n     * The interaction resolved data\n     *\n     * @name ModalComponentResolver#resolved\n     * @type {?Readonly<BaseInteractionResolvedData>}\n     */\n    Object.defineProperty(this, 'resolved', { value: resolved ? Object.freeze(resolved) : null });\n\n    /**\n     * The components within the modal\n     *\n     * @type {Array<ActionRowModalData|LabelModalData|TextDisplayModalData>}\n     */\n    this.data = components;\n\n    /**\n     * The bottom-level components of the interaction\n     *\n     * @type {Collection<string, ModalData>}\n     */\n    this.hoistedComponents = components.reduce((accumulator, next) => {\n      // For legacy support of action rows\n      if ('components' in next) {\n        for (const component of next.components) accumulator.set(component.customId, component);\n      }\n\n      // For label components\n      if ('component' in next) {\n        accumulator.set(next.component.customId, next.component);\n      }\n\n      return accumulator;\n    }, new Collection());\n  }\n\n  /**\n   * Gets a component by custom id.\n   *\n   * @property {string} customId The custom id of the component.\n   * @returns {ModalData}\n   */\n  getComponent(customId) {\n    const component = this.hoistedComponents.get(customId);\n\n    if (!component) throw new DiscordjsTypeError(ErrorCodes.ModalSubmitInteractionComponentNotFound, customId);\n\n    return component;\n  }\n\n  /**\n   * Gets a component by custom id and property and checks its type.\n   *\n   * @param {string} customId The custom id of the component.\n   * @param {ComponentType[]} allowedTypes The allowed types of the component.\n   * @param {string[]} properties The properties to check for for `required`.\n   * @param {boolean} required Whether to throw an error if the component value(s) are not found.\n   * @returns {ModalData} The option, if found.\n   * @private\n   */\n  _getTypedComponent(customId, allowedTypes, properties, required) {\n    const component = this.getComponent(customId);\n    if (!allowedTypes.includes(component.type)) {\n      throw new DiscordjsTypeError(\n        ErrorCodes.ModalSubmitInteractionComponentType,\n        customId,\n        component.type,\n        allowedTypes.join(', '),\n      );\n    } else if (required && properties.every(prop => component[prop] === null || component[prop] === undefined)) {\n      throw new DiscordjsTypeError(ErrorCodes.ModalSubmitInteractionComponentEmpty, customId, component.type);\n    }\n\n    return component;\n  }\n\n  /**\n   * Gets the value of a text input component\n   *\n   * @param {string} customId The custom id of the text input component\n   * @returns {string}\n   */\n  getTextInputValue(customId) {\n    return this._getTypedComponent(customId, [ComponentType.TextInput]).value;\n  }\n\n  /**\n   * Gets the values of a string select component\n   *\n   * @param {string} customId The custom id of the string select component\n   * @returns {string[]}\n   */\n  getStringSelectValues(customId) {\n    return this._getTypedComponent(customId, [ComponentType.StringSelect]).values;\n  }\n\n  /**\n   * Gets users component\n   *\n   * @param {string} customId The custom id of the component\n   * @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty\n   * @returns {?Collection<Snowflake, User>} The selected users, or null if none were selected and not required\n   */\n  getSelectedUsers(customId, required = false) {\n    const component = this._getTypedComponent(\n      customId,\n      [ComponentType.UserSelect, ComponentType.MentionableSelect],\n      ['users'],\n      required,\n    );\n    return component.users ?? null;\n  }\n\n  /**\n   * Gets roles component\n   *\n   * @param {string} customId The custom id of the component\n   * @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty\n   * @returns {?Collection<Snowflake, Role|APIRole>} The selected roles, or null if none were selected and not required\n   */\n  getSelectedRoles(customId, required = false) {\n    const component = this._getTypedComponent(\n      customId,\n      [ComponentType.RoleSelect, ComponentType.MentionableSelect],\n      ['roles'],\n      required,\n    );\n    return component.roles ?? null;\n  }\n\n  /**\n   * Gets channels component\n   *\n   * @param {string} customId The custom id of the component\n   * @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty\n   * @param {ChannelType[]} [channelTypes=[]] The allowed types of channels. If empty, all channel types are allowed.\n   * @returns {?Collection<Snowflake, GuildChannel|ThreadChannel|APIChannel>} The selected channels, or null if none were selected and not required\n   */\n  getSelectedChannels(customId, required = false, channelTypes = []) {\n    const component = this._getTypedComponent(customId, [ComponentType.ChannelSelect], ['channels'], required);\n    const channels = component.channels;\n    if (channels && channelTypes.length > 0) {\n      for (const channel of channels.values()) {\n        if (!channelTypes.includes(channel.type)) {\n          throw new DiscordjsTypeError(\n            ErrorCodes.ModalSubmitInteractionComponentInvalidChannelType,\n            customId,\n            channel.type,\n            channelTypes.join(', '),\n          );\n        }\n      }\n    }\n\n    return channels ?? null;\n  }\n\n  /**\n   * Gets members component\n   *\n   * @param {string} customId The custom id of the component\n   * @returns {?Collection<Snowflake, GuildMember|APIGuildMember>} The selected members, or null if none were selected or the users were not present in the guild\n   */\n  getSelectedMembers(customId) {\n    const component = this._getTypedComponent(\n      customId,\n      [ComponentType.UserSelect, ComponentType.MentionableSelect],\n      ['members'],\n      false,\n    );\n    return component.members ?? null;\n  }\n\n  /**\n   * Gets mentionables component\n   *\n   * @param {string} customId The custom id of the component\n   * @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty\n   * @returns {?ModalSelectedMentionables} The selected mentionables, or null if none were selected and not required\n   */\n  getSelectedMentionables(customId, required = false) {\n    const component = this._getTypedComponent(\n      customId,\n      [ComponentType.MentionableSelect],\n      ['users', 'members', 'roles'],\n      required,\n    );\n\n    if (component.users || component.members || component.roles) {\n      return {\n        users: component.users ?? new Collection(),\n        members: component.members ?? new Collection(),\n        roles: component.roles ?? new Collection(),\n      };\n    }\n\n    return null;\n  }\n\n  /**\n   * Gets file upload component\n   *\n   * @param {string} customId The custom id of the component\n   * @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty\n   * @returns {?Collection<Snowflake, Attachment>} The uploaded files, or null if none were uploaded and not required\n   */\n  getUploadedFiles(customId, required = false) {\n    return this._getTypedComponent(customId, [ComponentType.FileUpload], ['attachments'], required).attachments ?? null;\n  }\n\n  /**\n   * Get radio group component\n   *\n   * @param {string} customId The custom id of the component\n   * @param {boolean} [required=false] Whether to throw an error if the component value is not found or empty\n   * @returns {?string} The selected radio group option value, or null if none were selected and not required\n   */\n  getRadioGroup(customId, required = false) {\n    return this._getTypedComponent(customId, [ComponentType.RadioGroup], ['value'], required).value;\n  }\n\n  /**\n   * Get checkbox group component\n   *\n   * @param {string} customId The custom id of the component\n   * @returns {string[]} The selected checkbox group option values\n   */\n  getCheckboxGroup(customId) {\n    return this._getTypedComponent(customId, [ComponentType.CheckboxGroup]).values;\n  }\n\n  /**\n   * Get checkbox component\n   *\n   * @param {string} customId The custom id of the component\n   * @returns {boolean} Whether this checkbox was selected\n   */\n  getCheckbox(customId) {\n    return this._getTypedComponent(customId, [ComponentType.Checkbox]).value;\n  }\n}\n\nexports.ModalComponentResolver = ModalComponentResolver;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ModalSubmitInteraction.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { lazy } = require('@discordjs/util');\nconst { transformResolved } = require('../util/Util.js');\nconst { BaseInteraction } = require('./BaseInteraction.js');\nconst { InteractionWebhook } = require('./InteractionWebhook.js');\nconst { ModalComponentResolver } = require('./ModalComponentResolver.js');\nconst { InteractionResponses } = require('./interfaces/InteractionResponses.js');\n\nconst getMessage = lazy(() => require('./Message.js').Message);\nconst getAttachment = lazy(() => require('./Attachment.js').Attachment);\n\n/**\n * @typedef {Object} BaseModalData\n * @property {ComponentType} type The component type of the component\n * @property {number} id The id of the component\n */\n\n/**\n * @typedef {BaseModalData} SelectMenuModalData\n * @property {string} customId The custom id of the component\n * @property {string[]} values The values of the component\n * @property {Collection<Snowflake, GuildMember|APIGuildMember>} [members] The resolved members\n * @property {Collection<Snowflake, User|APIUser>} [users] The resolved users\n * @property {Collection<Snowflake, Role|APIRole>} [roles] The resolved roles\n * @property {Collection<Snowflake, BaseChannel|APIChannel>} [channels] The resolved channels\n */\n\n/**\n * @typedef {BaseModalData} FileUploadModalData\n * @property {string} customId The custom id of the file upload\n * @property {Snowflake[]} values The values of the file upload\n * @property {Collection<Snowflake, Attachment>} [attachments] The resolved attachments\n */\n\n/**\n * @typedef {BaseModalData} RadioGroupModalData\n * @property {string} customId The custom id of the radio group\n * @property {?string} value The value selected for the radio group\n */\n\n/**\n * @typedef {BaseModalData} CheckboxGroupModalData\n * @property {string} customId The custom id of the checkbox group\n * @property {string[]} values The values selected for the checkbox group\n */\n\n/**\n * @typedef {BaseModalData} CheckboxModalData\n * @property {string} customId The custom id of the checkbox\n * @property {boolean} value Whether this checkbox was selected\n */\n\n/**\n * @typedef {BaseModalData} TextInputModalData\n * @property {string} customId The custom id of the component\n * @property {string} value The value of the component\n */\n\n/**\n * @typedef {BaseModalData} TextDisplayModalData\n */\n\n/**\n * @typedef {SelectMenuModalData|TextInputModalData|FileUploadModalData|RadioGroupModalData|CheckboxGroupModalData|CheckboxModalData} ModalData\n */\n\n/**\n * @typedef {BaseModalData} LabelModalData\n * @property {ModalData} component The component within the label\n */\n\n/**\n * @typedef {BaseModalData} ActionRowModalData\n * @property {TextInputModalData[]} components The components of this action row\n */\n\n/**\n * Represents a modal interaction\n *\n * @extends {BaseInteraction}\n * @implements {InteractionResponses}\n */\nclass ModalSubmitInteraction extends BaseInteraction {\n  constructor(client, data) {\n    super(client, data);\n    /**\n     * The custom id of the modal.\n     *\n     * @type {string}\n     */\n    this.customId = data.data.custom_id;\n\n    if ('message' in data) {\n      /**\n       * The message associated with this interaction\n       *\n       * @type {?Message}\n       */\n      this.message = this.channel?.messages._add(data.message) ?? new (getMessage())(this.client, data.message);\n    } else {\n      this.message = null;\n    }\n\n    /**\n     * The components within the modal\n     *\n     * @type {ModalComponentResolver}\n     */\n    this.components = new ModalComponentResolver(\n      this.client,\n      data.data.components?.map(component => this.transformComponent(component, data.data.resolved)),\n      transformResolved({ client: this.client, guild: this.guild, channel: this.channel }, data.data.resolved),\n    );\n\n    /**\n     * Whether the reply to this interaction has been deferred\n     *\n     * @type {boolean}\n     */\n    this.deferred = false;\n\n    /**\n     * Whether this interaction has already been replied to\n     *\n     * @type {boolean}\n     */\n    this.replied = false;\n\n    /**\n     * Whether the reply to this interaction is ephemeral\n     *\n     * @type {?boolean}\n     */\n    this.ephemeral = null;\n\n    /**\n     * An associated interaction webhook, can be used to further interact with this interaction\n     *\n     * @type {InteractionWebhook}\n     */\n    this.webhook = new InteractionWebhook(this.client, this.applicationId, this.token);\n  }\n\n  /**\n   * Transforms component data to discord.js-compatible data\n   *\n   * @param {*} rawComponent The data to transform\n   * @param {APIInteractionDataResolved} resolved The resolved data for the interaction\n   * @returns {ModalData[]}\n   * @private\n   */\n  transformComponent(rawComponent, resolved) {\n    if ('components' in rawComponent) {\n      return {\n        type: rawComponent.type,\n        id: rawComponent.id,\n        components: rawComponent.components.map(component => this.transformComponent(component, resolved)),\n      };\n    }\n\n    if ('component' in rawComponent) {\n      return {\n        type: rawComponent.type,\n        id: rawComponent.id,\n        component: this.transformComponent(rawComponent.component, resolved),\n      };\n    }\n\n    const data = {\n      type: rawComponent.type,\n      id: rawComponent.id,\n    };\n\n    // Text display components do not have custom ids.\n    if ('custom_id' in rawComponent) data.customId = rawComponent.custom_id;\n\n    if ('value' in rawComponent) data.value = rawComponent.value;\n\n    if (rawComponent.values) {\n      data.values = rawComponent.values;\n      if (resolved) {\n        const { members, users, channels, roles, attachments } = resolved;\n        const valueSet = new Set(rawComponent.values);\n\n        if (users) {\n          data.users = new Collection();\n\n          for (const [id, user] of Object.entries(users)) {\n            if (valueSet.has(id)) {\n              data.users.set(id, this.client.users._add(user));\n            }\n          }\n        }\n\n        if (channels) {\n          data.channels = new Collection();\n\n          for (const [id, apiChannel] of Object.entries(channels)) {\n            if (valueSet.has(id)) {\n              data.channels.set(id, this.client.channels._add(apiChannel, this.guild) ?? apiChannel);\n            }\n          }\n        }\n\n        if (members) {\n          data.members = new Collection();\n\n          for (const [id, member] of Object.entries(members)) {\n            if (valueSet.has(id)) {\n              const user = users?.[id];\n              data.members.set(id, this.guild?.members._add({ user, ...member }) ?? member);\n            }\n          }\n        }\n\n        if (roles) {\n          data.roles = new Collection();\n\n          for (const [id, role] of Object.entries(roles)) {\n            if (valueSet.has(id)) {\n              data.roles.set(id, this.guild?.roles._add(role) ?? role);\n            }\n          }\n        }\n\n        if (attachments) {\n          data.attachments = new Collection();\n          for (const [id, attachment] of Object.entries(attachments)) {\n            if (valueSet.has(id)) {\n              data.attachments.set(id, new (getAttachment())(attachment));\n            }\n          }\n        }\n      }\n    }\n\n    return data;\n  }\n\n  /**\n   * Whether this is from a {@link MessageComponentInteraction}.\n   *\n   * @returns {boolean}\n   */\n  isFromMessage() {\n    return Boolean(this.message);\n  }\n\n  // These are here only for documentation purposes - they are implemented by InteractionResponses\n\n  deferReply() {}\n\n  reply() {}\n\n  fetchReply() {}\n\n  editReply() {}\n\n  deleteReply() {}\n\n  followUp() {}\n\n  deferUpdate() {}\n\n  update() {}\n\n  launchActivity() {}\n}\n\nInteractionResponses.applyToClass(ModalSubmitInteraction, 'showModal');\n\nexports.ModalSubmitInteraction = ModalSubmitInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/OAuth2Guild.js",
    "content": "'use strict';\n\nconst { PermissionsBitField } = require('../util/PermissionsBitField.js');\nconst { BaseGuild } = require('./BaseGuild.js');\n\n/**\n * A partial guild received when using {@link GuildManager#fetch} to fetch multiple guilds.\n *\n * @extends {BaseGuild}\n */\nclass OAuth2Guild extends BaseGuild {\n  constructor(client, data) {\n    super(client, data);\n\n    /**\n     * Whether the client user is the owner of the guild\n     *\n     * @type {boolean}\n     */\n    this.owner = data.owner;\n\n    /**\n     * The permissions that the client user has in this guild\n     *\n     * @type {Readonly<PermissionsBitField>}\n     */\n    this.permissions = new PermissionsBitField(BigInt(data.permissions)).freeze();\n  }\n}\n\nexports.OAuth2Guild = OAuth2Guild;\n"
  },
  {
    "path": "packages/discord.js/src/structures/PartialGroupDMChannel.js",
    "content": "'use strict';\n\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { PartialGroupDMMessageManager } = require('../managers/PartialGroupDMMessageManager.js');\nconst { BaseChannel } = require('./BaseChannel.js');\nconst { TextBasedChannel } = require('./interfaces/TextBasedChannel.js');\n\n/**\n * Represents a Partial Group DM Channel on Discord.\n *\n * @extends {BaseChannel}\n * @implements {TextBasedChannel}\n */\nclass PartialGroupDMChannel extends BaseChannel {\n  constructor(client, data) {\n    super(client, data);\n\n    // No flags are present when fetching partial group DM channels.\n    this.flags = null;\n\n    /**\n     * The name of this Group DM Channel\n     *\n     * @type {?string}\n     */\n    this.name = data.name;\n\n    /**\n     * The hash of the channel icon\n     *\n     * @type {?string}\n     */\n    this.icon = data.icon ?? null;\n\n    /**\n     * Recipient data received in a {@link PartialGroupDMChannel}.\n     *\n     * @typedef {Object} PartialRecipient\n     * @property {string} username The username of the recipient\n     */\n\n    /**\n     * The recipients of this Group DM Channel.\n     *\n     * @type {PartialRecipient[]}\n     */\n    this.recipients = data.recipients ?? [];\n\n    /**\n     * A manager of the messages belonging to this channel\n     *\n     * @type {PartialGroupDMMessageManager}\n     */\n    this.messages = new PartialGroupDMMessageManager(this);\n\n    if ('owner_id' in data) {\n      /**\n       * The user id of the owner of this Group DM Channel\n       *\n       * @type {?Snowflake}\n       */\n      this.ownerId = data.owner_id;\n    } else {\n      this.ownerId ??= null;\n    }\n\n    if ('last_message_id' in data) {\n      /**\n       * The channel's last message id, if one was sent\n       *\n       * @type {?Snowflake}\n       */\n      this.lastMessageId = data.last_message_id;\n    } else {\n      this.lastMessageId ??= null;\n    }\n\n    if ('last_pin_timestamp' in data) {\n      /**\n       * The timestamp when the last pinned message was pinned, if there was one\n       *\n       * @type {?number}\n       */\n      this.lastPinTimestamp = data.last_pin_timestamp ? Date.parse(data.last_pin_timestamp) : null;\n    } else {\n      this.lastPinTimestamp ??= null;\n    }\n  }\n\n  /**\n   * The URL to this channel's icon.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  iconURL(options = {}) {\n    return this.icon && this.client.rest.cdn.channelIcon(this.id, this.icon, options);\n  }\n\n  /**\n   * Fetches the owner of this Group DM Channel.\n   *\n   * @param {BaseFetchOptions} [options] The options for fetching the user\n   * @returns {Promise<User>}\n   */\n  async fetchOwner(options) {\n    if (!this.ownerId) {\n      throw new DiscordjsError(ErrorCodes.FetchOwnerId, 'group DM');\n    }\n\n    return this.client.users.fetch(this.ownerId, options);\n  }\n\n  async delete() {\n    throw new DiscordjsError(ErrorCodes.DeleteGroupDMChannel);\n  }\n\n  async fetch() {\n    throw new DiscordjsError(ErrorCodes.FetchGroupDMChannel);\n  }\n\n  // These are here only for documentation purposes - they are implemented by TextBasedChannel\n\n  /* eslint-disable getter-return */\n  get lastMessage() {}\n\n  get lastPinAt() {}\n\n  createMessageComponentCollector() {}\n\n  awaitMessageComponent() {}\n}\n\nTextBasedChannel.applyToClass(PartialGroupDMChannel, [\n  'bulkDelete',\n  'send',\n  'sendTyping',\n  'createMessageCollector',\n  'awaitMessages',\n  'fetchWebhooks',\n  'createWebhook',\n  'setRateLimitPerUser',\n  'setNSFW',\n]);\n\nexports.PartialGroupDMChannel = PartialGroupDMChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/PermissionOverwrites.js",
    "content": "'use strict';\n\nconst { OverwriteType } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { PermissionsBitField } = require('../util/PermissionsBitField.js');\nconst { Base } = require('./Base.js');\nconst { Role } = require('./Role.js');\n\n/**\n * Represents a permission overwrite for a role or member in a guild channel.\n *\n * @extends {Base}\n */\nclass PermissionOverwrites extends Base {\n  constructor(client, data, channel) {\n    super(client);\n\n    /**\n     * The GuildChannel this overwrite is for\n     *\n     * @name PermissionOverwrites#channel\n     * @type {GuildChannel}\n     * @readonly\n     */\n    Object.defineProperty(this, 'channel', { value: channel });\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    /**\n     * The overwrite's id, either a {@link User} or a {@link Role} id\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    if ('type' in data) {\n      /**\n       * The type of this overwrite\n       *\n       * @type {OverwriteType}\n       */\n      this.type = data.type;\n    }\n\n    if ('deny' in data) {\n      /**\n       * The permissions that are denied for the user or role.\n       *\n       * @type {Readonly<PermissionsBitField>}\n       */\n      this.deny = new PermissionsBitField(BigInt(data.deny)).freeze();\n    }\n\n    if ('allow' in data) {\n      /**\n       * The permissions that are allowed for the user or role.\n       *\n       * @type {Readonly<PermissionsBitField>}\n       */\n      this.allow = new PermissionsBitField(BigInt(data.allow)).freeze();\n    }\n  }\n\n  /**\n   * Edits this Permission Overwrite.\n   *\n   * @param {PermissionOverwriteOptions} options The options for the update\n   * @param {string} [reason] Reason for creating/editing this overwrite\n   * @returns {Promise<PermissionOverwrites>}\n   * @example\n   * // Update permission overwrites\n   * permissionOverwrites.edit({\n   *   SendMessages: false\n   * })\n   *   .then(channel => console.log(channel.permissionOverwrites.get(message.author.id)))\n   *   .catch(console.error);\n   */\n  async edit(options, reason) {\n    await this.channel.permissionOverwrites.upsert(this.id, options, { type: this.type, reason }, this);\n    return this;\n  }\n\n  /**\n   * Deletes this Permission Overwrite.\n   *\n   * @param {string} [reason] Reason for deleting this overwrite\n   * @returns {Promise<PermissionOverwrites>}\n   */\n  async delete(reason) {\n    await this.channel.permissionOverwrites.delete(this.id, reason);\n    return this;\n  }\n\n  toJSON() {\n    return {\n      id: this.id,\n      type: this.type,\n      allow: this.allow,\n      deny: this.deny,\n    };\n  }\n\n  /**\n   * An object mapping permission flags to `true` (enabled), `null` (unset) or `false` (disabled).\n   * ```js\n   * {\n   *  'SendMessages': true,\n   *  'EmbedLinks': null,\n   *  'AttachFiles': false,\n   * }\n   * ```\n   *\n   * @typedef {Object<string, ?boolean>} PermissionOverwriteOptions\n   */\n\n  /**\n   * @typedef {Object} ResolvedOverwriteOptions\n   * @property {PermissionsBitField} allow The allowed permissions\n   * @property {PermissionsBitField} deny The denied permissions\n   */\n\n  /**\n   * Resolves bitfield permissions overwrites from an object.\n   *\n   * @param {PermissionOverwriteOptions} options The options for the update\n   * @param {ResolvedOverwriteOptions} initialPermissions The initial permissions\n   * @returns {ResolvedOverwriteOptions}\n   */\n  static resolveOverwriteOptions(options, initialPermissions = {}) {\n    const allow = new PermissionsBitField(initialPermissions.allow);\n    const deny = new PermissionsBitField(initialPermissions.deny);\n\n    for (const [perm, value] of Object.entries(options)) {\n      if (value === true) {\n        allow.add(perm);\n        deny.remove(perm);\n      } else if (value === false) {\n        allow.remove(perm);\n        deny.add(perm);\n      } else if (value === null) {\n        allow.remove(perm);\n        deny.remove(perm);\n      }\n    }\n\n    return { allow, deny };\n  }\n\n  /**\n   * The raw data for a permission overwrite\n   *\n   * @typedef {Object} RawOverwriteData\n   * @property {Snowflake} id The id of the {@link Role} or {@link User} this overwrite belongs to\n   * @property {string} allow The permissions to allow\n   * @property {string} deny The permissions to deny\n   * @property {number} type The type of this OverwriteData\n   */\n\n  /**\n   * Data that can be resolved into {@link APIOverwrite}. This can be:\n   * - PermissionOverwrites\n   * - OverwriteData\n   *\n   * @typedef {PermissionOverwrites|OverwriteData} OverwriteResolvable\n   */\n\n  /**\n   * Data that can be used for a permission overwrite\n   *\n   * @typedef {Object} OverwriteData\n   * @property {UserResolvable|RoleResolvable} id Member or role this overwrite is for\n   * @property {PermissionResolvable} [allow] The permissions to allow\n   * @property {PermissionResolvable} [deny] The permissions to deny\n   * @property {OverwriteType} [type] The type of this OverwriteData (mandatory if `id` is a Snowflake)\n   */\n\n  /**\n   * Resolves an overwrite into {@link APIOverwrite}.\n   *\n   * @param {OverwriteResolvable} overwrite The overwrite-like data to resolve\n   * @param {Guild} [guild] The guild to resolve from\n   * @returns {RawOverwriteData}\n   */\n  static resolve(overwrite, guild) {\n    if (overwrite instanceof this) return overwrite.toJSON();\n\n    const id = guild.roles.resolveId(overwrite.id) ?? guild.client.users.resolveId(overwrite.id);\n    if (!id) {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'overwrite.id', 'UserResolvable or RoleResolvable');\n    }\n\n    if (overwrite.type !== undefined && (typeof overwrite.type !== 'number' || !(overwrite.type in OverwriteType))) {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'overwrite.type', 'OverwriteType', true);\n    }\n\n    let type;\n    if (typeof overwrite.id === 'string') {\n      if (overwrite.type === undefined) {\n        throw new DiscordjsTypeError(ErrorCodes.PermissionOverwritesTypeMandatory);\n      }\n\n      type = overwrite.type;\n    } else {\n      type = overwrite.id instanceof Role ? OverwriteType.Role : OverwriteType.Member;\n      if (overwrite.type !== undefined && type !== overwrite.type) {\n        throw new DiscordjsTypeError(ErrorCodes.PermissionOverwritesTypeMismatch, OverwriteType[type]);\n      }\n    }\n\n    return {\n      id,\n      type,\n      allow: PermissionsBitField.resolve(overwrite.allow ?? PermissionsBitField.DefaultBit).toString(),\n      deny: PermissionsBitField.resolve(overwrite.deny ?? PermissionsBitField.DefaultBit).toString(),\n    };\n  }\n}\n\nexports.PermissionOverwrites = PermissionOverwrites;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Poll.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { Base } = require('./Base.js');\nconst { PollAnswer } = require('./PollAnswer.js');\n\n/**\n * Represents a Poll\n *\n * @extends {Base}\n */\nclass Poll extends Base {\n  constructor(client, data, message, channel) {\n    super(client);\n\n    /**\n     * The id of the channel that this poll is in\n     *\n     * @type {Snowflake}\n     */\n    this.channelId = data.channel_id ?? channel.id;\n\n    /**\n     * The channel that this poll is in\n     *\n     * @name Poll#channel\n     * @type {TextBasedChannel}\n     * @readonly\n     */\n\n    Object.defineProperty(this, 'channel', { value: channel });\n\n    /**\n     * The id of the message that started this poll\n     *\n     * @type {Snowflake}\n     */\n    this.messageId = data.message_id ?? message.id;\n\n    /**\n     * The message that started this poll\n     *\n     * @name Poll#message\n     * @type {Message}\n     * @readonly\n     */\n\n    Object.defineProperty(this, 'message', { value: message });\n\n    /**\n     * The answers of this poll\n     *\n     * @type {Collection<number, PollAnswer|PartialPollAnswer>}\n     */\n    this.answers = new Collection();\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if (data.answers) {\n      for (const answer of data.answers) {\n        const existing = this.answers.get(answer.answer_id);\n        if (existing) {\n          existing._patch(answer);\n        } else {\n          this.answers.set(answer.answer_id, new PollAnswer(this.client, answer, this));\n        }\n      }\n    }\n\n    if (data.results) {\n      /**\n       * Whether this poll's results have been precisely counted\n       *\n       * @type {boolean}\n       */\n      this.resultsFinalized = data.results.is_finalized;\n\n      for (const answerResult of data.results.answer_counts) {\n        const answer = this.answers.get(answerResult.id);\n        answer?._patch(answerResult);\n      }\n    } else {\n      this.resultsFinalized ??= false;\n    }\n\n    if ('allow_multiselect' in data) {\n      /**\n       * Whether this poll allows multiple answers\n       *\n       * @type {boolean}\n       */\n      this.allowMultiselect = data.allow_multiselect;\n    } else {\n      this.allowMultiselect ??= null;\n    }\n\n    if ('layout_type' in data) {\n      /**\n       * The layout type of this poll\n       *\n       * @type {PollLayoutType}\n       */\n      this.layoutType = data.layout_type;\n    } else {\n      this.layoutType ??= null;\n    }\n\n    if ('expiry' in data) {\n      /**\n       * The timestamp when this poll expires\n       *\n       * @type {?number}\n       */\n      this.expiresTimestamp = data.expiry && Date.parse(data.expiry);\n    } else {\n      this.expiresTimestamp ??= null;\n    }\n\n    if (data.question) {\n      /**\n       * The media for a poll's question\n       *\n       * @typedef {Object} PollQuestionMedia\n       * @property {?string} text The text of this question\n       */\n\n      /**\n       * The media for this poll's question\n       *\n       * @type {PollQuestionMedia}\n       */\n      this.question = {\n        text: data.question.text,\n      };\n    } else {\n      this.question ??= {\n        text: null,\n      };\n    }\n  }\n\n  /**\n   * The date when this poll expires\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get expiresAt() {\n    return this.expiresTimestamp && new Date(this.expiresTimestamp);\n  }\n\n  /**\n   * Whether this poll is a partial\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get partial() {\n    return this.allowMultiselect === null;\n  }\n\n  /**\n   * Fetches the message that started this poll, then updates the poll from the fetched message.\n   *\n   * @returns {Promise<Poll>}\n   */\n  async fetch() {\n    await this.channel.messages.fetch(this.messageId);\n\n    return this;\n  }\n\n  /**\n   * Ends this poll.\n   *\n   * @returns {Promise<Message>}\n   */\n  async end() {\n    if (this.expiresTimestamp !== null && Date.now() > this.expiresTimestamp) {\n      throw new DiscordjsError(ErrorCodes.PollAlreadyExpired);\n    }\n\n    return this.channel.messages.endPoll(this.messageId);\n  }\n}\n\nexports.Poll = Poll;\n"
  },
  {
    "path": "packages/discord.js/src/structures/PollAnswer.js",
    "content": "'use strict';\n\nconst { PollAnswerVoterManager } = require('../managers/PollAnswerVoterManager.js');\nconst { resolveGuildEmoji } = require('../util/Util.js');\nconst { Base } = require('./Base.js');\nconst { Emoji } = require('./Emoji.js');\n\n/**\n * Represents an answer to a {@link Poll}\n *\n * @extends {Base}\n */\nclass PollAnswer extends Base {\n  constructor(client, data, poll) {\n    super(client);\n\n    /**\n     * The {@link Poll} this answer is part of\n     *\n     * @name PollAnswer#poll\n     * @type {Poll|PartialPoll}\n     * @readonly\n     */\n    Object.defineProperty(this, 'poll', { value: poll });\n\n    /**\n     * The id of this answer\n     *\n     * @type {number}\n     */\n    this.id = data.answer_id;\n\n    /**\n     * The manager of the voters for this answer\n     *\n     * @type {PollAnswerVoterManager}\n     */\n    this.voters = new PollAnswerVoterManager(this);\n\n    /**\n     * The raw emoji of this answer\n     *\n     * @name PollAnswer#_emoji\n     * @type {?APIPartialEmoji}\n     * @private\n     */\n    Object.defineProperty(this, '_emoji', { value: null, writable: true });\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    // This `count` field comes from `poll.results.answer_counts`\n    if ('count' in data) {\n      /**\n       * The amount of votes this answer has\n       *\n       * @type {number}\n       */\n      this.voteCount = data.count;\n    } else {\n      this.voteCount ??= this.voters.cache.size;\n    }\n\n    /**\n     * The text of this answer\n     *\n     * @type {?string}\n     */\n    this.text ??= data.poll_media?.text ?? null;\n\n    if (data.poll_media?.emoji) {\n      this._emoji = data.poll_media.emoji;\n    }\n  }\n\n  /**\n   * The emoji of this answer\n   *\n   * @type {?(GuildEmoji|Emoji)}\n   */\n  get emoji() {\n    if (!this._emoji || (!this._emoji.id && !this._emoji.name)) return null;\n    return resolveGuildEmoji(this.client, this._emoji.id) ?? new Emoji(this.client, this._emoji);\n  }\n\n  /**\n   * Whether this poll answer is a partial.\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get partial() {\n    return this.poll.partial || (this.text === null && this.emoji === null);\n  }\n}\n\nexports.PollAnswer = PollAnswer;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Presence.js",
    "content": "/* eslint-disable no-use-before-define */\n'use strict';\n\nconst { ActivityFlagsBitField } = require('../util/ActivityFlagsBitField.js');\nconst { flatten } = require('../util/Util.js');\nconst { Base } = require('./Base.js');\nconst { Emoji } = require('./Emoji.js');\n\n/**\n * Activity sent in a message.\n *\n * @typedef {Object} MessageActivity\n * @property {string} [partyId] Id of the party represented in activity\n * @property {MessageActivityType} type Type of activity sent\n */\n\n/**\n * The status of this presence:\n * - `online` - user is online\n * - `idle` - user is AFK\n * - `offline` - user is offline or invisible\n * - `dnd` - user is in Do Not Disturb\n *\n * @typedef {string} PresenceStatus\n */\n\n/**\n * The status of this presence:\n * - `online` - user is online\n * - `idle` - user is AFK\n * - `dnd` - user is in Do Not Disturb\n *\n * @typedef {string} ClientPresenceStatus\n */\n\n/**\n * Represents a user's presence.\n *\n * @extends {Base}\n */\nclass Presence extends Base {\n  constructor(client, data = {}) {\n    super(client);\n\n    /**\n     * The presence's user id\n     *\n     * @type {Snowflake}\n     */\n    this.userId = data.user.id;\n\n    /**\n     * The guild this presence is in\n     *\n     * @type {?Guild}\n     */\n    this.guild = data.guild ?? null;\n\n    this._patch(data);\n  }\n\n  /**\n   * The user of this presence\n   *\n   * @type {?User}\n   * @readonly\n   */\n  get user() {\n    return this.client.users.resolve(this.userId);\n  }\n\n  /**\n   * The member of this presence\n   *\n   * @type {?GuildMember}\n   * @readonly\n   */\n  get member() {\n    return this.guild.members.resolve(this.userId);\n  }\n\n  _patch(data) {\n    if ('status' in data) {\n      /**\n       * The status of this presence\n       *\n       * @type {PresenceStatus}\n       */\n      this.status = data.status;\n    } else {\n      this.status ??= 'offline';\n    }\n\n    if ('activities' in data) {\n      /**\n       * The activities of this presence\n       *\n       * @type {Activity[]}\n       */\n      this.activities = data.activities.map(activity => new Activity(this, activity));\n    } else {\n      this.activities ??= [];\n    }\n\n    if ('client_status' in data) {\n      /**\n       * @typedef {Object} ClientPresenceStatusData\n       * @property {?ClientPresenceStatus} web The current presence in the web application\n       * @property {?ClientPresenceStatus} mobile The current presence in the mobile application\n       * @property {?ClientPresenceStatus} desktop The current presence in the desktop application\n       */\n\n      /**\n       * The devices this presence is on\n       *\n       * @type {?ClientPresenceStatusData}\n       */\n      this.clientStatus = data.client_status;\n    } else {\n      this.clientStatus ??= null;\n    }\n\n    return this;\n  }\n\n  _clone() {\n    const clone = Object.assign(Object.create(this), this);\n    clone.activities = this.activities.map(activity => activity._clone());\n    return clone;\n  }\n\n  /**\n   * Whether this presence is equal to another.\n   *\n   * @param {Presence} presence The presence to compare with\n   * @returns {boolean}\n   */\n  equals(presence) {\n    return (\n      this === presence ||\n      (presence &&\n        this.status === presence.status &&\n        this.clientStatus?.web === presence.clientStatus?.web &&\n        this.clientStatus?.mobile === presence.clientStatus?.mobile &&\n        this.clientStatus?.desktop === presence.clientStatus?.desktop &&\n        this.activities.length === presence.activities.length &&\n        this.activities.every((activity, index) => activity.equals(presence.activities[index])))\n    );\n  }\n\n  toJSON() {\n    return flatten(this);\n  }\n}\n\n/**\n * Represents an activity that is part of a user's presence.\n */\nclass Activity {\n  constructor(presence, data) {\n    /**\n     * The presence of the Activity\n     *\n     * @type {Presence}\n     * @readonly\n     * @name Activity#presence\n     */\n    Object.defineProperty(this, 'presence', { value: presence });\n\n    /**\n     * The activity's name\n     *\n     * @type {string}\n     */\n    this.name = data.name;\n\n    /**\n     * The activity status's type\n     *\n     * @type {ActivityType}\n     */\n    this.type = data.type;\n\n    /**\n     * If the activity is being streamed, a link to the stream\n     *\n     * @type {?string}\n     */\n    this.url = data.url ?? null;\n\n    /**\n     * Details about the activity\n     *\n     * @type {?string}\n     */\n    this.details = data.details ?? null;\n\n    /**\n     * State of the activity\n     *\n     * @type {?string}\n     */\n    this.state = data.state ?? null;\n\n    /**\n     * The id of the application associated with this activity\n     *\n     * @type {?Snowflake}\n     */\n    this.applicationId = data.application_id ?? null;\n\n    /**\n     * Represents timestamps of an activity\n     *\n     * @typedef {Object} ActivityTimestamps\n     * @property {?Date} start When the activity started\n     * @property {?Date} end When the activity will end\n     */\n\n    /**\n     * Timestamps for the activity\n     *\n     * @type {?ActivityTimestamps}\n     */\n    this.timestamps = data.timestamps\n      ? {\n          start: data.timestamps.start ? new Date(Number(data.timestamps.start)) : null,\n          end: data.timestamps.end ? new Date(Number(data.timestamps.end)) : null,\n        }\n      : null;\n\n    /**\n     * Represents a party of an activity\n     *\n     * @typedef {Object} ActivityParty\n     * @property {?string} id The party's id\n     * @property {number[]} size Size of the party as `[current, max]`\n     */\n\n    /**\n     * Party of the activity\n     *\n     * @type {?ActivityParty}\n     */\n    this.party = data.party ?? null;\n\n    /**\n     * The sync id of the activity\n     * <info>This property is not documented by Discord and represents the track id in spotify activities.</info>\n     *\n     * @type {?string}\n     */\n    this.syncId = data.sync_id ?? null;\n\n    /**\n     * Assets for rich presence\n     *\n     * @type {?RichPresenceAssets}\n     */\n    this.assets = data.assets ? new RichPresenceAssets(this, data.assets) : null;\n\n    /**\n     * Flags that describe the activity\n     *\n     * @type {Readonly<ActivityFlagsBitField>}\n     */\n    this.flags = new ActivityFlagsBitField(data.flags).freeze();\n\n    /**\n     * Emoji for a custom activity\n     *\n     * @type {?Emoji}\n     */\n    this.emoji = data.emoji ? new Emoji(presence.client, data.emoji) : null;\n\n    /**\n     * The labels of the buttons of this rich presence\n     *\n     * @type {string[]}\n     */\n    this.buttons = data.buttons ?? [];\n\n    /**\n     * Creation date of the activity\n     *\n     * @type {number}\n     */\n    this.createdTimestamp = data.created_at;\n  }\n\n  /**\n   * Whether this activity is equal to another activity.\n   *\n   * @param {Activity} activity The activity to compare with\n   * @returns {boolean}\n   */\n  equals(activity) {\n    return (\n      this === activity ||\n      (activity &&\n        this.name === activity.name &&\n        this.type === activity.type &&\n        this.url === activity.url &&\n        this.state === activity.state &&\n        this.details === activity.details &&\n        this.emoji?.id === activity.emoji?.id &&\n        this.emoji?.name === activity.emoji?.name)\n    );\n  }\n\n  /**\n   * The time the activity was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * When concatenated with a string, this automatically returns the activity's name instead of the Activity object.\n   *\n   * @returns {string}\n   */\n  toString() {\n    return this.name;\n  }\n\n  _clone() {\n    return Object.assign(Object.create(this), this);\n  }\n}\n\n/**\n * Assets for a rich presence\n */\nclass RichPresenceAssets {\n  constructor(activity, assets) {\n    /**\n     * The activity of the RichPresenceAssets\n     *\n     * @type {Activity}\n     * @readonly\n     * @name RichPresenceAssets#activity\n     */\n    Object.defineProperty(this, 'activity', { value: activity });\n\n    /**\n     * Hover text for the large image\n     *\n     * @type {?string}\n     */\n    this.largeText = assets.large_text ?? null;\n\n    /**\n     * Hover text for the small image\n     *\n     * @type {?string}\n     */\n    this.smallText = assets.small_text ?? null;\n\n    /**\n     * The large image asset's id\n     *\n     * @type {?Snowflake}\n     */\n    this.largeImage = assets.large_image ?? null;\n\n    /**\n     * The small image asset's id\n     *\n     * @type {?Snowflake}\n     */\n    this.smallImage = assets.small_image ?? null;\n  }\n\n  /**\n   * Gets the URL of the small image asset\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  smallImageURL(options = {}) {\n    if (!this.smallImage) return null;\n    if (this.smallImage.includes(':')) {\n      const [platform, id] = this.smallImage.split(':');\n      switch (platform) {\n        case 'mp':\n          return `https://media.discordapp.net/${id}`;\n        default:\n          return null;\n      }\n    }\n\n    return this.activity.presence.client.rest.cdn.appAsset(this.activity.applicationId, this.smallImage, options);\n  }\n\n  /**\n   * Gets the URL of the large image asset\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  largeImageURL(options = {}) {\n    if (!this.largeImage) return null;\n    if (this.largeImage.includes(':')) {\n      const [platform, id] = this.largeImage.split(':');\n      switch (platform) {\n        case 'mp':\n          return `https://media.discordapp.net/${id}`;\n        case 'spotify':\n          return `https://i.scdn.co/image/${id}`;\n        case 'youtube':\n          return `https://i.ytimg.com/vi/${id}/hqdefault_live.jpg`;\n        case 'twitch':\n          return `https://static-cdn.jtvnw.net/previews-ttv/live_user_${id}.png`;\n        default:\n          return null;\n      }\n    }\n\n    return this.activity.presence.client.rest.cdn.appAsset(this.activity.applicationId, this.largeImage, options);\n  }\n}\n\nexports.Presence = Presence;\nexports.Activity = Activity;\nexports.RichPresenceAssets = RichPresenceAssets;\n"
  },
  {
    "path": "packages/discord.js/src/structures/PrimaryEntryPointCommandInteraction.js",
    "content": "'use strict';\n\nconst { CommandInteraction } = require('./CommandInteraction.js');\n\n/**\n * Represents a primary entry point command interaction.\n *\n * @extends {CommandInteraction}\n */\nclass PrimaryEntryPointCommandInteraction extends CommandInteraction {}\n\nexports.PrimaryEntryPointCommandInteraction = PrimaryEntryPointCommandInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ReactionCollector.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Events } = require('../util/Events.js');\nconst { Collector } = require('./interfaces/Collector.js');\n\n/**\n * @typedef {CollectorOptions} ReactionCollectorOptions\n * @property {number} max The maximum total amount of reactions to collect\n * @property {number} maxEmojis The maximum number of emojis to collect\n * @property {number} maxUsers The maximum number of users to react\n */\n\n/**\n * Collects reactions on messages.\n * Will automatically stop if the message ({@link Client#event:messageDelete messageDelete} or\n * {@link Client#event:messageDeleteBulk messageDeleteBulk}),\n * channel ({@link Client#event:channelDelete channelDelete}),\n * thread ({@link Client#event:threadDelete threadDelete}), or\n * guild ({@link Client#event:guildDelete guildDelete}) is deleted.\n *\n * @extends {Collector}\n */\nclass ReactionCollector extends Collector {\n  /**\n   * @param {Message} message The message upon which to collect reactions\n   * @param {ReactionCollectorOptions} [options={}] The options to apply to this collector\n   */\n  constructor(message, options = {}) {\n    super(message.client, options);\n\n    /**\n     * The message upon which to collect reactions\n     *\n     * @type {Message}\n     */\n    this.message = message;\n\n    /**\n     * The users that have reacted to this message\n     *\n     * @type {Collection}\n     */\n    this.users = new Collection();\n\n    /**\n     * The total number of reactions collected\n     *\n     * @type {number}\n     */\n    this.total = 0;\n\n    this.empty = this.empty.bind(this);\n    this._handleChannelDeletion = this._handleChannelDeletion.bind(this);\n    this._handleThreadDeletion = this._handleThreadDeletion.bind(this);\n    this._handleGuildDeletion = this._handleGuildDeletion.bind(this);\n    this._handleMessageDeletion = this._handleMessageDeletion.bind(this);\n\n    const bulkDeleteListener = messages => {\n      if (messages.has(this.message.id)) this.stop('messageDelete');\n    };\n\n    this.client.incrementMaxListeners();\n    this.client.on(Events.MessageReactionAdd, this.handleCollect);\n    this.client.on(Events.MessageReactionRemove, this.handleDispose);\n    this.client.on(Events.MessageReactionRemoveAll, this.empty);\n    this.client.on(Events.MessageDelete, this._handleMessageDeletion);\n    this.client.on(Events.MessageBulkDelete, bulkDeleteListener);\n    this.client.on(Events.ChannelDelete, this._handleChannelDeletion);\n    this.client.on(Events.ThreadDelete, this._handleThreadDeletion);\n    this.client.on(Events.GuildDelete, this._handleGuildDeletion);\n\n    this.once('end', () => {\n      this.client.removeListener(Events.MessageReactionAdd, this.handleCollect);\n      this.client.removeListener(Events.MessageReactionRemove, this.handleDispose);\n      this.client.removeListener(Events.MessageReactionRemoveAll, this.empty);\n      this.client.removeListener(Events.MessageDelete, this._handleMessageDeletion);\n      this.client.removeListener(Events.MessageBulkDelete, bulkDeleteListener);\n      this.client.removeListener(Events.ChannelDelete, this._handleChannelDeletion);\n      this.client.removeListener(Events.ThreadDelete, this._handleThreadDeletion);\n      this.client.removeListener(Events.GuildDelete, this._handleGuildDeletion);\n      this.client.decrementMaxListeners();\n    });\n\n    this.on('collect', (reaction, user) => {\n      /**\n       * Emitted whenever a reaction is newly created on a message. Will emit only when a new reaction is\n       * added to the message, as opposed to {@link Collector#event:collect} which will\n       * be emitted even when a reaction has already been added to the message.\n       *\n       * @event ReactionCollector#create\n       * @param {MessageReaction} reaction The reaction that was added\n       * @param {User} user The user that added the reaction\n       */\n      if (reaction.count === 1) {\n        this.emit('create', reaction, user);\n      }\n\n      this.total++;\n      this.users.set(user.id, user);\n    });\n\n    this.on('remove', (_reaction, user) => {\n      this.total--;\n      if (!this.collected.some(reaction => reaction.users.cache.has(user.id))) this.users.delete(user.id);\n    });\n  }\n\n  /**\n   * Handles an incoming reaction for possible collection.\n   *\n   * @param {MessageReaction} reaction The reaction to possibly collect\n   * @returns {?(Snowflake|string)}\n   * @private\n   */\n  collect(reaction) {\n    /**\n     * Emitted whenever a reaction is collected.\n     *\n     * @event ReactionCollector#collect\n     * @param {MessageReaction} reaction The reaction that was collected\n     * @param {User} user The user that added the reaction\n     */\n    if (reaction.message.id !== this.message.id) return null;\n\n    return ReactionCollector.key(reaction);\n  }\n\n  /**\n   * Handles a reaction deletion for possible disposal.\n   *\n   * @param {MessageReaction} reaction The reaction to possibly dispose of\n   * @param {User} user The user that removed the reaction\n   * @returns {?(Snowflake|string)}\n   */\n  dispose(reaction, user) {\n    /**\n     * Emitted when the reaction had all the users removed and the `dispose` option is set to true.\n     *\n     * @event ReactionCollector#dispose\n     * @param {MessageReaction} reaction The reaction that was disposed of\n     * @param {User} user The user that removed the reaction\n     */\n    if (reaction.message.id !== this.message.id) return null;\n\n    /**\n     * Emitted when the reaction had one user removed and the `dispose` option is set to true.\n     *\n     * @event ReactionCollector#remove\n     * @param {MessageReaction} reaction The reaction that was removed\n     * @param {User} user The user that removed the reaction\n     */\n    if (this.collected.has(ReactionCollector.key(reaction)) && this.users.has(user.id)) {\n      this.emit('remove', reaction, user);\n    }\n\n    return reaction.count ? null : ReactionCollector.key(reaction);\n  }\n\n  /**\n   * Empties this reaction collector.\n   */\n  empty() {\n    this.total = 0;\n    this.collected.clear();\n    this.users.clear();\n    this.checkEnd();\n  }\n\n  /**\n   * The reason this collector has ended with, or null if it hasn't ended yet\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get endReason() {\n    if (this.options.max && this.total >= this.options.max) return 'limit';\n    if (this.options.maxEmojis && this.collected.size >= this.options.maxEmojis) return 'emojiLimit';\n    if (this.options.maxUsers && this.users.size >= this.options.maxUsers) return 'userLimit';\n    return super.endReason;\n  }\n\n  /**\n   * Handles checking if the message has been deleted, and if so, stops the collector with the reason 'messageDelete'.\n   *\n   * @private\n   * @param {Message} message The message that was deleted\n   * @returns {void}\n   */\n  _handleMessageDeletion(message) {\n    if (message.id === this.message.id) {\n      this.stop('messageDelete');\n    }\n  }\n\n  /**\n   * Handles checking if the channel has been deleted, and if so, stops the collector with the reason 'channelDelete'.\n   *\n   * @private\n   * @param {GuildChannel} channel The channel that was deleted\n   * @returns {void}\n   */\n  _handleChannelDeletion(channel) {\n    if (channel.id === this.message.channelId || channel.threads?.cache.has(this.message.channelId)) {\n      this.stop('channelDelete');\n    }\n  }\n\n  /**\n   * Handles checking if the thread has been deleted, and if so, stops the collector with the reason 'threadDelete'.\n   *\n   * @private\n   * @param {ThreadChannel} thread The thread that was deleted\n   * @returns {void}\n   */\n  _handleThreadDeletion(thread) {\n    if (thread.id === this.message.channelId) {\n      this.stop('threadDelete');\n    }\n  }\n\n  /**\n   * Handles checking if the guild has been deleted, and if so, stops the collector with the reason 'guildDelete'.\n   *\n   * @private\n   * @param {Guild} guild The guild that was deleted\n   * @returns {void}\n   */\n  _handleGuildDeletion(guild) {\n    if (guild.id === this.message.guild?.id) {\n      this.stop('guildDelete');\n    }\n  }\n\n  /**\n   * Gets the collector key for a reaction.\n   *\n   * @param {MessageReaction} reaction The message reaction to get the key for\n   * @returns {Snowflake|string}\n   */\n  static key(reaction) {\n    return reaction.emoji.id ?? reaction.emoji.name;\n  }\n}\n\nexports.ReactionCollector = ReactionCollector;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ReactionEmoji.js",
    "content": "'use strict';\n\nconst { flatten } = require('../util/Util.js');\nconst { Emoji } = require('./Emoji.js');\n\n/**\n * Represents a limited emoji set used for both custom and unicode emojis. Custom emojis\n * will use this class opposed to the Emoji class when the client doesn't know enough\n * information about them.\n *\n * @extends {Emoji}\n */\nclass ReactionEmoji extends Emoji {\n  constructor(reaction, emoji) {\n    super(reaction.message.client, emoji);\n    /**\n     * The message reaction this emoji refers to\n     *\n     * @type {MessageReaction}\n     */\n    this.reaction = reaction;\n  }\n\n  toJSON() {\n    return flatten(this, { identifier: true });\n  }\n\n  valueOf() {\n    return this.id;\n  }\n}\n\nexports.ReactionEmoji = ReactionEmoji;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Role.js",
    "content": "'use strict';\n\nconst { roleMention } = require('@discordjs/formatters');\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { PermissionFlagsBits } = require('discord-api-types/v10');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { PermissionsBitField } = require('../util/PermissionsBitField.js');\nconst { RoleFlagsBitField } = require('../util/RoleFlagsBitField.js');\nconst { Base } = require('./Base.js');\n\n/**\n * Represents a role on Discord.\n *\n * @extends {Base}\n */\nclass Role extends Base {\n  constructor(client, data, guild) {\n    super(client);\n\n    /**\n     * The guild that the role belongs to\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n\n    /**\n     * The icon hash of the role\n     *\n     * @type {?string}\n     */\n    this.icon = null;\n\n    /**\n     * The unicode emoji for the role\n     *\n     * @type {?string}\n     */\n    this.unicodeEmoji = null;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    /**\n     * The role's id (unique to the guild it is part of)\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n    if ('name' in data) {\n      /**\n       * The name of the role\n       *\n       * @type {string}\n       */\n      this.name = data.name;\n    }\n\n    /**\n     * @typedef {Object} RoleColors\n     * @property {number} primaryColor The primary color of the role\n     * @property {?number} secondaryColor The secondary color of the role.\n     * This will make the role a gradient between the other provided colors\n     * @property {?number} tertiaryColor The tertiary color of the role.\n     * When sending `tertiaryColor` the API enforces the role color to be a holographic style with values of `primaryColor = 11127295`, `secondaryColor = 16759788`, and `tertiaryColor = 16761760`.\n     * These values are available as a constant: `Constants.HolographicStyle`\n     */\n\n    if ('colors' in data) {\n      /**\n       * The colors of the role\n       *\n       * @type {RoleColors}\n       */\n      this.colors = {\n        primaryColor: data.colors.primary_color,\n        secondaryColor: data.colors.secondary_color,\n        tertiaryColor: data.colors.tertiary_color,\n      };\n    }\n\n    if ('hoist' in data) {\n      /**\n       * If true, users that are part of this role will appear in a separate category in the users list\n       *\n       * @type {boolean}\n       */\n      this.hoist = data.hoist;\n    }\n\n    if ('position' in data) {\n      /**\n       * The raw position of the role from the API\n       *\n       * @type {number}\n       */\n      this.rawPosition = data.position;\n    }\n\n    if ('permissions' in data) {\n      /**\n       * The permissions of the role\n       *\n       * @type {Readonly<PermissionsBitField>}\n       */\n      this.permissions = new PermissionsBitField(BigInt(data.permissions)).freeze();\n    }\n\n    if ('managed' in data) {\n      /**\n       * Whether or not the role is managed by an external service\n       *\n       * @type {boolean}\n       */\n      this.managed = data.managed;\n    }\n\n    if ('mentionable' in data) {\n      /**\n       * Whether or not the role can be mentioned by anyone\n       *\n       * @type {boolean}\n       */\n      this.mentionable = data.mentionable;\n    }\n\n    if ('icon' in data) this.icon = data.icon;\n\n    if ('unicode_emoji' in data) this.unicodeEmoji = data.unicode_emoji;\n\n    if ('flags' in data) {\n      /**\n       * The flags of this role\n       *\n       * @type {Readonly<RoleFlagsBitField>}\n       */\n      this.flags = new RoleFlagsBitField(data.flags).freeze();\n    } else {\n      this.flags ??= new RoleFlagsBitField().freeze();\n    }\n\n    /**\n     * The tags this role has\n     *\n     * @type {?Object}\n     * @property {Snowflake} [botId] The id of the bot this role belongs to\n     * @property {Snowflake|string} [integrationId] The id of the integration this role belongs to\n     * @property {true} [premiumSubscriberRole] Whether this is the guild's premium subscription role\n     * @property {Snowflake} [subscriptionListingId] The id of this role's subscription SKU and listing\n     * @property {true} [availableForPurchase] Whether this role is available for purchase\n     * @property {true} [guildConnections] Whether this role is a guild's linked role\n     */\n    this.tags = data.tags ? {} : null;\n    if (data.tags) {\n      if ('bot_id' in data.tags) {\n        this.tags.botId = data.tags.bot_id;\n      }\n\n      if ('integration_id' in data.tags) {\n        this.tags.integrationId = data.tags.integration_id;\n      }\n\n      if ('premium_subscriber' in data.tags) {\n        this.tags.premiumSubscriberRole = true;\n      }\n\n      if ('subscription_listing_id' in data.tags) {\n        this.tags.subscriptionListingId = data.tags.subscription_listing_id;\n      }\n\n      if ('available_for_purchase' in data.tags) {\n        this.tags.availableForPurchase = true;\n      }\n\n      if ('guild_connections' in data.tags) {\n        this.tags.guildConnections = true;\n      }\n    }\n  }\n\n  /**\n   * The timestamp the role was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time the role was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * The hexadecimal version of the role color, with a leading hashtag\n   *\n   * @type {string}\n   * @readonly\n   */\n  get hexColor() {\n    return `#${this.colors.primaryColor.toString(16).padStart(6, '0')}`;\n  }\n\n  /**\n   * The cached guild members that have this role\n   *\n   * @type {Collection<Snowflake, GuildMember>}\n   * @readonly\n   */\n  get members() {\n    return this.id === this.guild.id\n      ? this.guild.members.cache.clone()\n      : this.guild.members.cache.filter(member => member._roles.includes(this.id));\n  }\n\n  /**\n   * Whether the role is editable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get editable() {\n    if (this.managed) return false;\n    const clientMember = this.guild.members.resolve(this.client.user);\n    if (!clientMember.permissions.has(PermissionFlagsBits.ManageRoles)) return false;\n    return clientMember.roles.highest.comparePositionTo(this) > 0;\n  }\n\n  /**\n   * The position of the role in the role manager\n   *\n   * @type {number}\n   * @readonly\n   */\n  get position() {\n    return this.guild.roles.cache.reduce(\n      (acc, role) =>\n        acc +\n        (this.rawPosition === role.rawPosition\n          ? BigInt(this.id) < BigInt(role.id)\n          : this.rawPosition > role.rawPosition),\n      0,\n    );\n  }\n\n  /**\n   * Compares this role's position to another role's.\n   *\n   * @param {RoleResolvable} role Role to compare to this one\n   * @returns {number} Negative number if this role's position is lower (other role's is higher),\n   * positive number if this one is higher (other's is lower), 0 if equal\n   * @example\n   * // Compare the position of a role to another\n   * const roleCompare = role.comparePositionTo(otherRole);\n   * if (roleCompare >= 1) console.log(`${role.name} is higher than ${otherRole.name}`);\n   */\n  comparePositionTo(role) {\n    return this.guild.roles.comparePositions(this, role);\n  }\n\n  /**\n   * The data for a role.\n   *\n   * @typedef {Object} RoleData\n   * @property {string} [name] The name of the role\n   * @property {RoleColorsResolvable} [colors] The colors of the role\n   * @property {boolean} [hoist] Whether or not the role should be hoisted\n   * @property {number} [position] The position of the role\n   * @property {PermissionResolvable} [permissions] The permissions of the role\n   * @property {boolean} [mentionable] Whether or not the role should be mentionable\n   * @property {?(BufferResolvable|Base64Resolvable|EmojiResolvable)} [icon] The icon for the role\n   * <warn>The `EmojiResolvable` should belong to the same guild as the role.\n   * If not, pass the emoji's URL directly</warn>\n   * @property {?string} [unicodeEmoji] The unicode emoji for the role\n   */\n\n  /**\n   * Edits the role.\n   *\n   * @param {RoleEditOptions} options The options to provide\n   * @returns {Promise<Role>}\n   * @example\n   * // Edit a role\n   * role.edit({ name: 'new role' })\n   *   .then(updated => console.log(`Edited role name to ${updated.name}`))\n   *   .catch(console.error);\n   */\n  async edit(options) {\n    return this.guild.roles.edit(this, options);\n  }\n\n  /**\n   * Returns `channel.permissionsFor(role)`. Returns permissions for a role in a guild channel,\n   * taking into account permission overwrites.\n   *\n   * @param {GuildChannel|Snowflake} channel The guild channel to use as context\n   * @param {boolean} [checkAdmin=true] Whether having the {@link PermissionFlagsBits.Administrator} permission\n   * will return all permissions\n   * @returns {Readonly<PermissionsBitField>}\n   */\n  permissionsIn(channel, checkAdmin = true) {\n    const resolvedChannel = this.guild.channels.resolve(channel);\n    if (!resolvedChannel) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);\n    return resolvedChannel.rolePermissions(this, checkAdmin);\n  }\n\n  /**\n   * Sets a new name for the role.\n   *\n   * @param {string} name The new name of the role\n   * @param {string} [reason] Reason for changing the role's name\n   * @returns {Promise<Role>}\n   * @example\n   * // Set the name of the role\n   * role.setName('new role')\n   *   .then(updated => console.log(`Updated role name to ${updated.name}`))\n   *   .catch(console.error);\n   */\n  async setName(name, reason) {\n    return this.edit({ name, reason });\n  }\n\n  /**\n   * Sets new colors for the role.\n   *\n   * @param {RoleColorsResolvable} colors The colors of the role\n   * @param {string} [reason] Reason for changing the role's colors\n   * @returns {Promise<Role>}\n   * @example\n   * // Set the colors of a role\n   * role.setColors({ primaryColor: '#FF0000', secondaryColor: '#00FF00', tertiaryColor: '#0000FF' })\n   *   .then(updated => console.log(`Set colors of role to ${updated.colors}`))\n   *   .catch(console.error);\n   * @example\n   * // Set holographic colors using constants\n   * role.setColors({\n   *   primaryColor: Constants.HolographicStyle.Primary,\n   *   secondaryColor: Constants.HolographicStyle.Secondary,\n   *   tertiaryColor: Constants.HolographicStyle.Tertiary,\n   * })\n   *   .then(updated => console.log(`Set holographic colors for role ${updated.name}`))\n   *   .catch(console.error);\n   */\n  async setColors(colors, reason) {\n    return this.edit({ colors, reason });\n  }\n\n  /**\n   * Sets whether or not the role should be hoisted.\n   *\n   * @param {boolean} [hoist=true] Whether or not to hoist the role\n   * @param {string} [reason] Reason for setting whether or not the role should be hoisted\n   * @returns {Promise<Role>}\n   * @example\n   * // Set the hoist of the role\n   * role.setHoist(true)\n   *   .then(updated => console.log(`Role hoisted: ${updated.hoist}`))\n   *   .catch(console.error);\n   */\n  async setHoist(hoist = true, reason = undefined) {\n    return this.edit({ hoist, reason });\n  }\n\n  /**\n   * Sets the permissions of the role.\n   *\n   * @param {PermissionResolvable} permissions The permissions of the role\n   * @param {string} [reason] Reason for changing the role's permissions\n   * @returns {Promise<Role>}\n   * @example\n   * // Set the permissions of the role\n   * role.setPermissions([PermissionFlagsBits.KickMembers, PermissionFlagsBits.BanMembers])\n   *   .then(updated => console.log(`Updated permissions to ${updated.permissions.bitfield}`))\n   *   .catch(console.error);\n   * @example\n   * // Remove all permissions from a role\n   * role.setPermissions(0n)\n   *   .then(updated => console.log(`Updated permissions to ${updated.permissions.bitfield}`))\n   *   .catch(console.error);\n   */\n  async setPermissions(permissions, reason) {\n    return this.edit({ permissions, reason });\n  }\n\n  /**\n   * Sets whether this role is mentionable.\n   *\n   * @param {boolean} [mentionable=true] Whether this role should be mentionable\n   * @param {string} [reason] Reason for setting whether or not this role should be mentionable\n   * @returns {Promise<Role>}\n   * @example\n   * // Make the role mentionable\n   * role.setMentionable(true)\n   *   .then(updated => console.log(`Role updated ${updated.name}`))\n   *   .catch(console.error);\n   */\n  async setMentionable(mentionable = true, reason = undefined) {\n    return this.edit({ mentionable, reason });\n  }\n\n  /**\n   * Sets a new icon for the role.\n   *\n   * @param {?(BufferResolvable|Base64Resolvable|EmojiResolvable)} icon The icon for the role\n   * <warn>The `EmojiResolvable` should belong to the same guild as the role.\n   * If not, pass the emoji's URL directly</warn>\n   * @param {string} [reason] Reason for changing the role's icon\n   * @returns {Promise<Role>}\n   */\n  async setIcon(icon, reason) {\n    return this.edit({ icon, reason });\n  }\n\n  /**\n   * Sets a new unicode emoji for the role.\n   *\n   * @param {?string} unicodeEmoji The new unicode emoji for the role\n   * @param {string} [reason] Reason for changing the role's unicode emoji\n   * @returns {Promise<Role>}\n   * @example\n   * // Set a new unicode emoji for the role\n   * role.setUnicodeEmoji('🤖')\n   *   .then(updated => console.log(`Set unicode emoji for the role to ${updated.unicodeEmoji}`))\n   *   .catch(console.error);\n   */\n  async setUnicodeEmoji(unicodeEmoji, reason) {\n    return this.edit({ unicodeEmoji, reason });\n  }\n\n  /**\n   * Options used to set the position of a role.\n   *\n   * @typedef {Object} SetRolePositionOptions\n   * @property {boolean} [relative=false] Whether to change the position relative to its current value or not\n   * @property {string} [reason] The reason for changing the position\n   */\n\n  /**\n   * Sets the new position of the role.\n   *\n   * @param {number} position The new position for the role\n   * @param {SetRolePositionOptions} [options] Options for setting the position\n   * @returns {Promise<Role>}\n   * @example\n   * // Set the position of the role\n   * role.setPosition(1)\n   *   .then(updated => console.log(`Role position: ${updated.position}`))\n   *   .catch(console.error);\n   */\n  async setPosition(position, options = {}) {\n    return this.guild.roles.setPosition(this, position, options);\n  }\n\n  /**\n   * Deletes the role.\n   *\n   * @param {string} [reason] Reason for deleting this role\n   * @returns {Promise<Role>}\n   * @example\n   * // Delete a role\n   * role.delete('The role needed to go')\n   *   .then(deleted => console.log(`Deleted role ${deleted.name}`))\n   *   .catch(console.error);\n   */\n  async delete(reason) {\n    await this.guild.roles.delete(this.id, reason);\n    return this;\n  }\n\n  /**\n   * A link to the role's icon\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  iconURL(options = {}) {\n    return this.icon && this.client.rest.cdn.roleIcon(this.id, this.icon, options);\n  }\n\n  /**\n   * Whether this role equals another role. It compares all properties, so for most operations\n   * it is advisable to just compare `role.id === role2.id` as it is much faster and is often\n   * what most users need.\n   *\n   * @param {Role} role Role to compare with\n   * @returns {boolean}\n   */\n  equals(role) {\n    return (\n      role &&\n      this.id === role.id &&\n      this.name === role.name &&\n      this.colors.primaryColor === role.colors.primaryColor &&\n      this.colors.secondaryColor === role.colors.secondaryColor &&\n      this.colors.tertiaryColor === role.colors.tertiaryColor &&\n      this.hoist === role.hoist &&\n      this.position === role.position &&\n      this.permissions.bitfield === role.permissions.bitfield &&\n      this.managed === role.managed &&\n      this.icon === role.icon &&\n      this.unicodeEmoji === role.unicodeEmoji\n    );\n  }\n\n  /**\n   * When concatenated with a string, this automatically returns the role's mention instead of the Role object.\n   *\n   * @returns {string}\n   * @example\n   * // Logs: Role: <@&123456789012345678>\n   * console.log(`Role: ${role}`);\n   */\n  toString() {\n    if (this.id === this.guild.id) return '@everyone';\n    return roleMention(this.id);\n  }\n\n  toJSON() {\n    return {\n      ...super.toJSON({ createdTimestamp: true }),\n      permissions: this.permissions.toJSON(),\n    };\n  }\n}\n\nexports.Role = Role;\n"
  },
  {
    "path": "packages/discord.js/src/structures/RoleSelectMenuComponent.js",
    "content": "'use strict';\n\nconst { BaseSelectMenuComponent } = require('./BaseSelectMenuComponent.js');\n\n/**\n * Represents a role select menu component\n *\n * @extends {BaseSelectMenuComponent}\n */\nclass RoleSelectMenuComponent extends BaseSelectMenuComponent {}\n\nexports.RoleSelectMenuComponent = RoleSelectMenuComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/RoleSelectMenuInteraction.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { MessageComponentInteraction } = require('./MessageComponentInteraction.js');\n\n/**\n * Represents a {@link ComponentType.RoleSelect} select menu interaction.\n *\n * @extends {MessageComponentInteraction}\n */\nclass RoleSelectMenuInteraction extends MessageComponentInteraction {\n  constructor(client, data) {\n    super(client, data);\n    const { resolved, values } = data.data;\n\n    /**\n     * An array of the selected role ids\n     *\n     * @type {Snowflake[]}\n     */\n    this.values = values ?? [];\n\n    /**\n     * Collection of the selected roles\n     *\n     * @type {Collection<Snowflake, Role|APIRole>}\n     */\n    this.roles = new Collection();\n\n    for (const role of Object.values(resolved?.roles ?? {})) {\n      this.roles.set(role.id, this.guild?.roles._add(role) ?? role);\n    }\n  }\n}\n\nexports.RoleSelectMenuInteraction = RoleSelectMenuInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/SKU.js",
    "content": "'use strict';\n\nconst { SKUFlagsBitField } = require('../util/SKUFlagsBitField.js');\nconst { Base } = require('./Base.js');\n\n/**\n * Represents a premium application SKU.\n *\n * @extends {Base}\n */\nclass SKU extends Base {\n  constructor(client, data) {\n    super(client);\n\n    /**\n     * The id of the SKU\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    /**\n     * The type of the SKU\n     *\n     * @type {SKUType}\n     */\n    this.type = data.type;\n\n    /**\n     * The id of the parent application\n     *\n     * @type {Snowflake}\n     */\n    this.applicationId = data.application_id;\n\n    /**\n     * The customer-facing name of the premium offering\n     *\n     * @type {string}\n     */\n    this.name = data.name;\n\n    /**\n     * The system-generated URL slug based on this SKU's name\n     *\n     * @type {string}\n     */\n    this.slug = data.slug;\n\n    /**\n     * Flags that describe the SKU\n     *\n     * @type {Readonly<SKUFlagsBitField>}\n     */\n    this.flags = new SKUFlagsBitField(data.flags).freeze();\n  }\n}\n\nexports.SKU = SKU;\n"
  },
  {
    "path": "packages/discord.js/src/structures/SectionComponent.js",
    "content": "'use strict';\n\nconst { createComponent } = require('../util/Components.js');\nconst { Component } = require('./Component.js');\n\n/**\n * Represents a section component\n *\n * @extends {Component}\n */\nclass SectionComponent extends Component {\n  constructor({ accessory, components, ...data }) {\n    super(data);\n\n    /**\n     * The components in this section\n     *\n     * @type {Component[]}\n     * @readonly\n     */\n    this.components = components.map(component => createComponent(component));\n\n    /**\n     * The accessory component of this section\n     *\n     * @type {Component}\n     * @readonly\n     */\n    this.accessory = createComponent(accessory);\n  }\n\n  /**\n   * Returns the API-compatible JSON for this component\n   *\n   * @returns {APISectionComponent}\n   */\n  toJSON() {\n    return {\n      ...this.data,\n      accessory: this.accessory.toJSON(),\n      components: this.components.map(component => component.toJSON()),\n    };\n  }\n}\n\nexports.SectionComponent = SectionComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/SeparatorComponent.js",
    "content": "'use strict';\n\nconst { SeparatorSpacingSize } = require('discord-api-types/v10');\nconst { Component } = require('./Component.js');\n\n/**\n * Represents a separator component\n *\n * @extends {Component}\n */\nclass SeparatorComponent extends Component {\n  /**\n   * The spacing of this separator\n   *\n   * @type {SeparatorSpacingSize}\n   * @readonly\n   */\n  get spacing() {\n    return this.data.spacing ?? SeparatorSpacingSize.Small;\n  }\n\n  /**\n   * Whether this separator is a divider\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get divider() {\n    return this.data.divider ?? true;\n  }\n}\n\nexports.SeparatorComponent = SeparatorComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/SoundboardSound.js",
    "content": "'use strict';\n\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { Base } = require('./Base.js');\nconst { Emoji } = require('./Emoji.js');\n\n/**\n * Represents a soundboard sound.\n *\n * @extends {Base}\n */\nclass SoundboardSound extends Base {\n  constructor(client, data) {\n    super(client);\n\n    /**\n     * The id of this soundboard sound\n     *\n     * @type {Snowflake|string}\n     */\n    this.soundId = data.sound_id;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('available' in data) {\n      /**\n       * Whether this soundboard sound is available\n       *\n       * @type {?boolean}\n       */\n      this.available = data.available;\n    } else {\n      this.available ??= null;\n    }\n\n    if ('name' in data) {\n      /**\n       * The name of this soundboard sound\n       *\n       * @type {?string}\n       */\n      this.name = data.name;\n    } else {\n      this.name ??= null;\n    }\n\n    if ('volume' in data) {\n      /**\n       * The volume (a double) of this soundboard sound, from 0 to 1\n       *\n       * @type {?number}\n       */\n      this.volume = data.volume;\n    } else {\n      this.volume ??= null;\n    }\n\n    if ('emoji_id' in data) {\n      /**\n       * The raw emoji data of this soundboard sound\n       *\n       * @type {?Object}\n       * @private\n       */\n      this._emoji = {\n        id: data.emoji_id,\n        name: data.emoji_name,\n      };\n    } else {\n      this._emoji ??= null;\n    }\n\n    if ('guild_id' in data) {\n      /**\n       * The guild id of this soundboard sound\n       *\n       * @type {?Snowflake}\n       */\n      this.guildId = data.guild_id;\n    } else {\n      this.guildId ??= null;\n    }\n\n    if ('user' in data) {\n      /**\n       * The user who created this soundboard sound\n       *\n       * @type {?User}\n       */\n      this.user = this.client.users._add(data.user);\n    } else {\n      this.user ??= null;\n    }\n  }\n\n  /**\n   * The timestamp this soundboard sound was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.soundId);\n  }\n\n  /**\n   * The time this soundboard sound was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * The emoji of this soundboard sound\n   *\n   * @type {?Emoji}\n   * @readonly\n   */\n  get emoji() {\n    if (!this._emoji) return null;\n\n    return this.guild?.emojis.cache.get(this._emoji.id) ?? new Emoji(this.client, this._emoji);\n  }\n\n  /**\n   * The guild this soundboard sound is part of\n   *\n   * @type {?Guild}\n   * @readonly\n   */\n  get guild() {\n    return this.client.guilds.resolve(this.guildId);\n  }\n\n  /**\n   * A link to this soundboard sound\n   *\n   * @type {string}\n   * @readonly\n   */\n  get url() {\n    return this.client.rest.cdn.soundboardSound(this.soundId);\n  }\n\n  /**\n   * Edits this soundboard sound.\n   *\n   * @param {GuildSoundboardSoundEditOptions} options The options to provide\n   * @returns {Promise<SoundboardSound>}\n   * @example\n   * // Update the name of a soundboard sound\n   * soundboardSound.edit({ name: 'new name' })\n   *   .then(sound => console.log(`Updated the name of the soundboard sound to ${sound.name}`))\n   *   .catch(console.error);\n   */\n  async edit(options) {\n    if (!this.guildId) throw new DiscordjsError(ErrorCodes.NotGuildSoundboardSound, 'edited');\n\n    return this.guild.soundboardSounds.edit(this, options);\n  }\n\n  /**\n   * Deletes this soundboard sound.\n   *\n   * @param {string} [reason] Reason for deleting this soundboard sound\n   * @returns {Promise<SoundboardSound>}\n   * @example\n   * // Delete a soundboard sound\n   * soundboardSound.delete()\n   *   .then(sound => console.log(`Deleted soundboard sound ${sound.name}`))\n   *   .catch(console.error);\n   */\n  async delete(reason) {\n    if (!this.guildId) throw new DiscordjsError(ErrorCodes.NotGuildSoundboardSound, 'deleted');\n\n    await this.guild.soundboardSounds.delete(this, reason);\n\n    return this;\n  }\n\n  /**\n   * Whether this soundboard sound is the same as another one.\n   *\n   * @param {SoundboardSound|APISoundboardSound} other The soundboard sound to compare it to\n   * @returns {boolean}\n   */\n  equals(other) {\n    if (other instanceof SoundboardSound) {\n      return (\n        this.soundId === other.soundId &&\n        this.available === other.available &&\n        this.name === other.name &&\n        this.volume === other.volume &&\n        this._emoji?.id === other._emoji?.id &&\n        this._emoji?.name === other._emoji?.name &&\n        this.guildId === other.guildId &&\n        this.user?.id === other.user?.id\n      );\n    }\n\n    return (\n      this.soundId === other.sound_id &&\n      this.available === other.available &&\n      this.name === other.name &&\n      this.volume === other.volume &&\n      (this._emoji?.id ?? null) === other.emoji_id &&\n      (this._emoji?.name ?? null) === other.emoji_name &&\n      this.guildId === other.guild_id &&\n      this.user?.id === other.user?.id\n    );\n  }\n}\n\nexports.SoundboardSound = SoundboardSound;\n"
  },
  {
    "path": "packages/discord.js/src/structures/StageChannel.js",
    "content": "'use strict';\n\nconst { BaseGuildVoiceChannel } = require('./BaseGuildVoiceChannel.js');\n\n/**\n * Represents a guild stage channel on Discord.\n *\n * @extends {BaseGuildVoiceChannel}\n */\nclass StageChannel extends BaseGuildVoiceChannel {\n  _patch(data) {\n    super._patch(data);\n\n    if ('topic' in data) {\n      /**\n       * The topic of the stage channel\n       *\n       * @type {?string}\n       */\n      this.topic = data.topic;\n    }\n  }\n\n  /**\n   * The stage instance of this stage channel, if it exists\n   *\n   * @type {?StageInstance}\n   * @readonly\n   */\n  get stageInstance() {\n    return this.guild.stageInstances.cache.find(stageInstance => stageInstance.channelId === this.id) ?? null;\n  }\n\n  /**\n   * Creates a stage instance associated with this stage channel.\n   *\n   * @param {StageInstanceCreateOptions} options The options to create the stage instance\n   * @returns {Promise<StageInstance>}\n   */\n  async createStageInstance(options) {\n    return this.guild.stageInstances.create(this.id, options);\n  }\n\n  /**\n   * Sets a new topic for the guild channel.\n   *\n   * @param {?string} topic The new topic for the guild channel\n   * @param {string} [reason] Reason for changing the guild channel's topic\n   * @returns {Promise<StageChannel>}\n   * @example\n   * // Set a new channel topic\n   * stageChannel.setTopic('needs more rate limiting')\n   *   .then(channel => console.log(`Channel's new topic is ${channel.topic}`))\n   *   .catch(console.error);\n   */\n  async setTopic(topic, reason) {\n    return this.edit({ topic, reason });\n  }\n}\n\n/**\n * Sets the bitrate of the channel.\n *\n * @method setBitrate\n * @memberof StageChannel\n * @instance\n * @param {number} bitrate The new bitrate\n * @param {string} [reason] Reason for changing the channel's bitrate\n * @returns {Promise<StageChannel>}\n * @example\n * // Set the bitrate of a voice channel\n * stageChannel.setBitrate(48_000)\n *   .then(channel => console.log(`Set bitrate to ${channel.bitrate}bps for ${channel.name}`))\n *   .catch(console.error);\n */\n\n/**\n * Sets the RTC region of the channel.\n *\n * @method setRTCRegion\n * @memberof StageChannel\n * @instance\n * @param {?string} rtcRegion The new region of the channel. Set to `null` to remove a specific region for the channel\n * @param {string} [reason] The reason for modifying this region.\n * @returns {Promise<StageChannel>}\n * @example\n * // Set the RTC region to sydney\n * stageChannel.setRTCRegion('sydney');\n * @example\n * // Remove a fixed region for this channel - let Discord decide automatically\n * stageChannel.setRTCRegion(null, 'We want to let Discord decide.');\n */\n\n/**\n * Sets the user limit of the channel.\n *\n * @method setUserLimit\n * @memberof StageChannel\n * @instance\n * @param {number} userLimit The new user limit\n * @param {string} [reason] Reason for changing the user limit\n * @returns {Promise<StageChannel>}\n * @example\n * // Set the user limit of a voice channel\n * stageChannel.setUserLimit(42)\n *   .then(channel => console.log(`Set user limit to ${channel.userLimit} for ${channel.name}`))\n *   .catch(console.error);\n */\n\n/**\n * Sets the camera video quality mode of the channel.\n *\n * @method setVideoQualityMode\n * @memberof StageChannel\n * @instance\n * @param {VideoQualityMode} videoQualityMode The new camera video quality mode.\n * @param {string} [reason] Reason for changing the camera video quality mode.\n * @returns {Promise<StageChannel>}\n */\n\nexports.StageChannel = StageChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/StageInstance.js",
    "content": "'use strict';\n\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { Base } = require('./Base.js');\n\n/**\n * Represents a stage instance.\n *\n * @extends {Base}\n */\nclass StageInstance extends Base {\n  constructor(client, data) {\n    super(client);\n\n    /**\n     * The stage instance's id\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('guild_id' in data) {\n      /**\n       * The id of the guild associated with the stage channel\n       *\n       * @type {Snowflake}\n       */\n      this.guildId = data.guild_id;\n    }\n\n    if ('channel_id' in data) {\n      /**\n       * The id of the channel associated with the stage channel\n       *\n       * @type {Snowflake}\n       */\n      this.channelId = data.channel_id;\n    }\n\n    if ('topic' in data) {\n      /**\n       * The topic of the stage instance\n       *\n       * @type {string}\n       */\n      this.topic = data.topic;\n    }\n\n    if ('privacy_level' in data) {\n      /**\n       * The privacy level of the stage instance\n       *\n       * @type {StageInstancePrivacyLevel}\n       */\n      this.privacyLevel = data.privacy_level;\n    }\n\n    if ('guild_scheduled_event_id' in data) {\n      /**\n       * The associated guild scheduled event id of this stage instance\n       *\n       * @type {?Snowflake}\n       */\n      this.guildScheduledEventId = data.guild_scheduled_event_id;\n    } else {\n      this.guildScheduledEventId ??= null;\n    }\n  }\n\n  /**\n   * The stage channel associated with this stage instance\n   *\n   * @type {?StageChannel}\n   * @readonly\n   */\n  get channel() {\n    return this.client.channels.resolve(this.channelId);\n  }\n\n  /**\n   * The guild this stage instance belongs to\n   *\n   * @type {?Guild}\n   * @readonly\n   */\n  get guild() {\n    return this.client.guilds.resolve(this.guildId);\n  }\n\n  /**\n   * The associated guild scheduled event of this stage instance\n   *\n   * @type {?GuildScheduledEvent}\n   * @readonly\n   */\n  get guildScheduledEvent() {\n    return this.guild?.scheduledEvents.resolve(this.guildScheduledEventId) ?? null;\n  }\n\n  /**\n   * Edits this stage instance.\n   *\n   * @param {StageInstanceEditOptions} options The options to edit the stage instance\n   * @returns {Promise<StageInstance>}\n   * @example\n   * // Edit a stage instance\n   * stageInstance.edit({ topic: 'new topic' })\n   *  .then(stageInstance => console.log(stageInstance))\n   *  .catch(console.error)\n   */\n  async edit(options) {\n    return this.guild.stageInstances.edit(this.channelId, options);\n  }\n\n  /**\n   * Deletes this stage instance.\n   *\n   * @returns {Promise<StageInstance>}\n   * @example\n   * // Delete a stage instance\n   * stageInstance.delete()\n   *  .then(stageInstance => console.log(stageInstance))\n   *  .catch(console.error);\n   */\n  async delete() {\n    await this.guild.stageInstances.delete(this.channelId);\n    return this._clone();\n  }\n\n  /**\n   * Sets the topic of this stage instance.\n   *\n   * @param {string} topic The topic for the stage instance\n   * @returns {Promise<StageInstance>}\n   * @example\n   * // Set topic of a stage instance\n   * stageInstance.setTopic('new topic')\n   *  .then(stageInstance => console.log(`Set the topic to: ${stageInstance.topic}`))\n   *  .catch(console.error);\n   */\n  async setTopic(topic) {\n    return this.guild.stageInstances.edit(this.channelId, { topic });\n  }\n\n  /**\n   * The timestamp this stage instances was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time this stage instance was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n}\n\nexports.StageInstance = StageInstance;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Sticker.js",
    "content": "'use strict';\n\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { Routes } = require('discord-api-types/v10');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { StickerFormatExtensionMap } = require('../util/Constants.js');\nconst { Base } = require('./Base.js');\n\n/**\n * Represents a Sticker.\n *\n * @extends {Base}\n */\nclass Sticker extends Base {\n  constructor(client, sticker) {\n    super(client);\n\n    this._patch(sticker);\n  }\n\n  _patch(sticker) {\n    /**\n     * The sticker's id\n     *\n     * @type {Snowflake}\n     */\n    this.id = sticker.id;\n\n    if ('description' in sticker) {\n      /**\n       * The description of the sticker\n       *\n       * @type {?string}\n       */\n      this.description = sticker.description;\n    } else {\n      this.description ??= null;\n    }\n\n    if ('type' in sticker) {\n      /**\n       * The type of the sticker\n       *\n       * @type {?StickerType}\n       */\n      this.type = sticker.type;\n    } else {\n      this.type ??= null;\n    }\n\n    if ('format_type' in sticker) {\n      /**\n       * The format of the sticker\n       *\n       * @type {StickerFormatType}\n       */\n      this.format = sticker.format_type;\n    }\n\n    if ('name' in sticker) {\n      /**\n       * The name of the sticker\n       *\n       * @type {string}\n       */\n      this.name = sticker.name;\n    }\n\n    if ('pack_id' in sticker) {\n      /**\n       * The id of the pack the sticker is from, for standard stickers\n       *\n       * @type {?Snowflake}\n       */\n      this.packId = sticker.pack_id;\n    } else {\n      this.packId ??= null;\n    }\n\n    if ('tags' in sticker) {\n      /**\n       * Autocomplete/suggestions for the sticker\n       *\n       * @type {?string}\n       */\n      this.tags = sticker.tags;\n    } else {\n      this.tags ??= null;\n    }\n\n    if ('available' in sticker) {\n      /**\n       * Whether or not the guild sticker is available\n       *\n       * @type {?boolean}\n       */\n      this.available = sticker.available;\n    } else {\n      this.available ??= null;\n    }\n\n    if ('guild_id' in sticker) {\n      /**\n       * The id of the guild that owns this sticker\n       *\n       * @type {?Snowflake}\n       */\n      this.guildId = sticker.guild_id;\n    } else {\n      this.guildId ??= null;\n    }\n\n    if ('user' in sticker) {\n      /**\n       * The user that uploaded the guild sticker\n       *\n       * @type {?User}\n       */\n      this.user = this.client.users._add(sticker.user);\n    } else {\n      this.user ??= null;\n    }\n\n    if ('sort_value' in sticker) {\n      /**\n       * The standard sticker's sort order within its pack\n       *\n       * @type {?number}\n       */\n      this.sortValue = sticker.sort_value;\n    } else {\n      this.sortValue ??= null;\n    }\n  }\n\n  /**\n   * The timestamp the sticker was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time the sticker was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * Whether this sticker is partial\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get partial() {\n    return !this.type;\n  }\n\n  /**\n   * The guild that owns this sticker\n   *\n   * @type {?Guild}\n   * @readonly\n   */\n  get guild() {\n    return this.client.guilds.resolve(this.guildId);\n  }\n\n  /**\n   * A link to the sticker\n   * <info>If the sticker's format is {@link StickerFormatType.Lottie}, it returns\n   * the URL of the Lottie JSON file.</info>\n   *\n   * @type {string}\n   * @readonly\n   */\n  get url() {\n    return this.client.rest.cdn.sticker(this.id, StickerFormatExtensionMap[this.format]);\n  }\n\n  /**\n   * Fetches this sticker.\n   *\n   * @returns {Promise<Sticker>}\n   */\n  async fetch() {\n    const data = await this.client.rest.get(Routes.sticker(this.id));\n    this._patch(data);\n    return this;\n  }\n\n  /**\n   * Fetches the pack that contains this sticker.\n   *\n   * @returns {Promise<?StickerPack>} The sticker pack or `null` if this sticker does not belong to one.\n   */\n  async fetchPack() {\n    if (!this.packId) return null;\n    return this.client.fetchStickerPacks({ packId: this.packId });\n  }\n\n  /**\n   * Fetches the user who uploaded this sticker, if this is a guild sticker.\n   *\n   * @returns {Promise<?User>}\n   */\n  async fetchUser() {\n    if (this.partial) await this.fetch();\n    if (!this.guildId) throw new DiscordjsError(ErrorCodes.NotGuildSticker);\n    return this.guild.stickers.fetchUser(this);\n  }\n\n  /**\n   * Data for editing a sticker.\n   *\n   * @typedef {Object} GuildStickerEditOptions\n   * @property {string} [name] The name of the sticker\n   * @property {?string} [description] The description of the sticker\n   * @property {string} [tags] The Discord name of a unicode emoji representing the sticker's expression\n   * @property {string} [reason] Reason for editing this sticker\n   */\n\n  /**\n   * Edits the sticker.\n   *\n   * @param {GuildStickerEditOptions} options The options to provide\n   * @returns {Promise<Sticker>}\n   * @example\n   * // Update the name of a sticker\n   * sticker.edit({ name: 'new name' })\n   *   .then(sticker => console.log(`Updated the name of the sticker to ${sticker.name}`))\n   *   .catch(console.error);\n   */\n  async edit(options) {\n    return this.guild.stickers.edit(this, options);\n  }\n\n  /**\n   * Deletes the sticker.\n   *\n   * @returns {Promise<Sticker>}\n   * @param {string} [reason] Reason for deleting this sticker\n   * @example\n   * // Delete a sticker\n   * sticker.delete()\n   *   .then(sticker => console.log(`Deleted sticker ${sticker.name}`))\n   *   .catch(console.error);\n   */\n  async delete(reason) {\n    await this.guild.stickers.delete(this, reason);\n    return this;\n  }\n\n  /**\n   * Whether this sticker is the same as another one.\n   *\n   * @param {Sticker|APISticker} other The sticker to compare it to\n   * @returns {boolean}\n   */\n  equals(other) {\n    if (other instanceof Sticker) {\n      return (\n        other.id === this.id &&\n        other.description === this.description &&\n        other.type === this.type &&\n        other.format === this.format &&\n        other.name === this.name &&\n        other.packId === this.packId &&\n        other.tags === this.tags &&\n        other.available === this.available &&\n        other.guildId === this.guildId &&\n        other.sortValue === this.sortValue\n      );\n    } else {\n      return (\n        other.id === this.id &&\n        other.description === this.description &&\n        other.name === this.name &&\n        other.tags === this.tags\n      );\n    }\n  }\n}\n\nexports.Sticker = Sticker;\n"
  },
  {
    "path": "packages/discord.js/src/structures/StickerPack.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { Base } = require('./Base.js');\nconst { Sticker } = require('./Sticker.js');\n\n/**\n * Represents a pack of standard stickers.\n *\n * @extends {Base}\n */\nclass StickerPack extends Base {\n  constructor(client, pack) {\n    super(client);\n    /**\n     * The Sticker pack's id\n     *\n     * @type {Snowflake}\n     */\n    this.id = pack.id;\n\n    /**\n     * The stickers in the pack\n     *\n     * @type {Collection<Snowflake, Sticker>}\n     */\n    this.stickers = new Collection(pack.stickers.map(sticker => [sticker.id, new Sticker(client, sticker)]));\n\n    /**\n     * The name of the sticker pack\n     *\n     * @type {string}\n     */\n    this.name = pack.name;\n\n    /**\n     * The id of the pack's SKU\n     *\n     * @type {Snowflake}\n     */\n    this.skuId = pack.sku_id;\n\n    /**\n     * The id of a sticker in the pack which is shown as the pack's icon\n     *\n     * @type {?Snowflake}\n     */\n    this.coverStickerId = pack.cover_sticker_id ?? null;\n\n    /**\n     * The description of the sticker pack\n     *\n     * @type {string}\n     */\n    this.description = pack.description;\n\n    /**\n     * The id of the sticker pack's banner image\n     *\n     * @type {?Snowflake}\n     */\n    this.bannerId = pack.banner_asset_id ?? null;\n  }\n\n  /**\n   * The timestamp the sticker was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time the sticker was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * The sticker which is shown as the pack's icon\n   *\n   * @type {?Sticker}\n   * @readonly\n   */\n  get coverSticker() {\n    return this.coverStickerId && this.stickers.get(this.coverStickerId);\n  }\n\n  /**\n   * The URL to this sticker pack's banner.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  bannerURL(options = {}) {\n    return this.bannerId && this.client.rest.cdn.stickerPackBanner(this.bannerId, options);\n  }\n}\n\nexports.StickerPack = StickerPack;\n"
  },
  {
    "path": "packages/discord.js/src/structures/StringSelectMenuComponent.js",
    "content": "'use strict';\n\nconst { BaseSelectMenuComponent } = require('./BaseSelectMenuComponent.js');\n\n/**\n * Represents a string select menu component\n *\n * @extends {BaseSelectMenuComponent}\n */\nclass StringSelectMenuComponent extends BaseSelectMenuComponent {\n  /**\n   * The options in this select menu\n   *\n   * @type {APISelectMenuOption[]}\n   * @readonly\n   */\n  get options() {\n    return this.data.options;\n  }\n}\n\nexports.StringSelectMenuComponent = StringSelectMenuComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/StringSelectMenuInteraction.js",
    "content": "'use strict';\n\nconst { MessageComponentInteraction } = require('./MessageComponentInteraction.js');\n\n/**\n * Represents a {@link ComponentType.StringSelect} select menu interaction.\n *\n * @extends {MessageComponentInteraction}\n */\nclass StringSelectMenuInteraction extends MessageComponentInteraction {\n  constructor(client, data) {\n    super(client, data);\n\n    /**\n     * The values selected\n     *\n     * @type {string[]}\n     */\n    this.values = data.data.values ?? [];\n  }\n}\n\nexports.StringSelectMenuInteraction = StringSelectMenuInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Subscription.js",
    "content": "'use strict';\n\nconst { Base } = require('./Base.js');\n\n/**\n * Represents a Subscription\n *\n * @extends {Base}\n */\nclass Subscription extends Base {\n  constructor(client, data) {\n    super(client);\n\n    /**\n     * The id of the subscription\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    /**\n     * The id of the user who subscribed\n     *\n     * @type {Snowflake}\n     */\n    this.userId = data.user_id;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    /**\n     * The SKU ids subscribed to\n     *\n     * @type {Snowflake[]}\n     */\n    this.skuIds = data.sku_ids;\n\n    /**\n     * The entitlement ids granted for this subscription\n     *\n     * @type {Snowflake[]}\n     */\n    this.entitlementIds = data.entitlement_ids;\n\n    /**\n     * The timestamp the current subscription period will start at\n     *\n     * @type {number}\n     */\n    this.currentPeriodStartTimestamp = Date.parse(data.current_period_start);\n\n    /**\n     * The timestamp the current subscription period will end at\n     *\n     * @type {number}\n     */\n    this.currentPeriodEndTimestamp = Date.parse(data.current_period_end);\n\n    /**\n     * The current status of the subscription\n     *\n     * @type {SubscriptionStatus}\n     */\n    this.status = data.status;\n\n    if ('renewal_sku_ids' in data) {\n      /**\n       * The SKU ids that this user will be subscribed to at renewal\n       *\n       * @type {?Snowflake[]}\n       */\n      this.renewalSkuIds = data.renewal_sku_ids;\n    }\n\n    if ('canceled_at' in data) {\n      /**\n       * The timestamp of when the subscription was canceled\n       *\n       * @type {?number}\n       */\n      this.canceledTimestamp = data.canceled_at ? Date.parse(data.canceled_at) : null;\n    } else {\n      this.canceledTimestamp ??= null;\n    }\n\n    if ('country' in data) {\n      /**\n       * ISO 3166-1 alpha-2 country code of the payment source used to purchase the subscription.\n       * Missing unless queried with a private OAuth scope.\n       *\n       * @type {?string}\n       */\n      this.country = data.country;\n    } else {\n      this.country ??= null;\n    }\n  }\n\n  /**\n   * The time the subscription was canceled\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get canceledAt() {\n    return this.canceledTimestamp && new Date(this.canceledTimestamp);\n  }\n\n  /**\n   * The time the current subscription period will start at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get currentPeriodStartAt() {\n    return new Date(this.currentPeriodStartTimestamp);\n  }\n\n  /**\n   * The time the current subscription period will end at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get currentPeriodEndAt() {\n    return new Date(this.currentPeriodEndTimestamp);\n  }\n}\n\nexports.Subscription = Subscription;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Team.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { Base } = require('./Base.js');\nconst { TeamMember } = require('./TeamMember.js');\n\n/**\n * Represents a Client OAuth2 Application Team.\n *\n * @extends {Base}\n */\nclass Team extends Base {\n  constructor(client, data) {\n    super(client);\n    this._patch(data);\n  }\n\n  _patch(data) {\n    /**\n     * The Team's id\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    if ('name' in data) {\n      /**\n       * The name of the Team\n       *\n       * @type {string}\n       */\n      this.name = data.name;\n    }\n\n    if ('icon' in data) {\n      /**\n       * The Team's icon hash\n       *\n       * @type {?string}\n       */\n      this.icon = data.icon;\n    } else {\n      this.icon ??= null;\n    }\n\n    if ('owner_user_id' in data) {\n      /**\n       * The Team's owner id\n       *\n       * @type {?Snowflake}\n       */\n      this.ownerId = data.owner_user_id;\n    } else {\n      this.ownerId ??= null;\n    }\n\n    /**\n     * The Team's members\n     *\n     * @type {Collection<Snowflake, TeamMember>}\n     */\n    this.members = new Collection();\n\n    for (const memberData of data.members) {\n      const member = new TeamMember(this, memberData);\n      this.members.set(member.id, member);\n    }\n  }\n\n  /**\n   * The owner of this team\n   *\n   * @type {?TeamMember}\n   * @readonly\n   */\n  get owner() {\n    return this.members.get(this.ownerId) ?? null;\n  }\n\n  /**\n   * The timestamp the team was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time the team was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * A link to the team's icon.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  iconURL(options = {}) {\n    return this.icon && this.client.rest.cdn.teamIcon(this.id, this.icon, options);\n  }\n\n  /**\n   * When concatenated with a string, this automatically returns the Team's name instead of the\n   * Team object.\n   *\n   * @returns {string}\n   * @example\n   * // Logs: Team name: My Team\n   * console.log(`Team name: ${team}`);\n   */\n  toString() {\n    return this.name;\n  }\n\n  toJSON() {\n    return super.toJSON({ createdTimestamp: true });\n  }\n}\n\nexports.Team = Team;\n"
  },
  {
    "path": "packages/discord.js/src/structures/TeamMember.js",
    "content": "'use strict';\n\nconst { Base } = require('./Base.js');\n\n/**\n * Represents a Client OAuth2 Application Team Member.\n *\n * @extends {Base}\n */\nclass TeamMember extends Base {\n  constructor(team, data) {\n    super(team.client);\n\n    /**\n     * The Team this member is part of\n     *\n     * @type {Team}\n     */\n    this.team = team;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('membership_state' in data) {\n      /**\n       * The permissions this Team Member has with regard to the team\n       *\n       * @type {TeamMemberMembershipState}\n       */\n      this.membershipState = data.membership_state;\n    }\n\n    if ('user' in data) {\n      /**\n       * The user for this Team Member\n       *\n       * @type {User}\n       */\n      this.user = this.client.users._add(data.user);\n    }\n\n    if ('role' in data) {\n      /**\n       * The role of this Team Member\n       *\n       * @type {TeamMemberRole}\n       */\n      this.role = data.role;\n    }\n  }\n\n  /**\n   * The Team Member's id\n   *\n   * @type {Snowflake}\n   * @readonly\n   */\n  get id() {\n    return this.user.id;\n  }\n\n  /**\n   * When concatenated with a string, this automatically returns the team member's mention instead of the\n   * TeamMember object.\n   *\n   * @returns {string}\n   * @example\n   * // Logs: Team Member's mention: <@123456789012345678>\n   * console.log(`Team Member's mention: ${teamMember}`);\n   */\n  toString() {\n    return this.user.toString();\n  }\n}\n\nexports.TeamMember = TeamMember;\n"
  },
  {
    "path": "packages/discord.js/src/structures/TextChannel.js",
    "content": "'use strict';\n\nconst { BaseGuildTextChannel } = require('./BaseGuildTextChannel.js');\n\n/**\n * Represents a guild text channel on Discord.\n *\n * @extends {BaseGuildTextChannel}\n */\nclass TextChannel extends BaseGuildTextChannel {\n  _patch(data) {\n    super._patch(data);\n\n    if ('rate_limit_per_user' in data) {\n      /**\n       * The rate limit per user (slowmode) for this channel in seconds\n       *\n       * @type {number}\n       */\n      this.rateLimitPerUser = data.rate_limit_per_user;\n    }\n  }\n\n  /**\n   * Sets the rate limit per user (slowmode) for this channel.\n   *\n   * @param {number} rateLimitPerUser The new rate limit in seconds\n   * @param {string} [reason] Reason for changing the channel's rate limit\n   * @returns {Promise<TextChannel>}\n   */\n  async setRateLimitPerUser(rateLimitPerUser, reason) {\n    return this.edit({ rateLimitPerUser, reason });\n  }\n}\n\nexports.TextChannel = TextChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/TextDisplayComponent.js",
    "content": "'use strict';\n\nconst { Component } = require('./Component.js');\n\n/**\n * Represents a text display component\n *\n * @extends {Component}\n */\nclass TextDisplayComponent extends Component {\n  /**\n   * The content of this text display\n   *\n   * @type {string}\n   * @readonly\n   */\n  get content() {\n    return this.data.content;\n  }\n}\n\nexports.TextDisplayComponent = TextDisplayComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/TextInputComponent.js",
    "content": "'use strict';\n\nconst { Component } = require('./Component.js');\n\n/**\n * Represents a text input component.\n *\n * @extends {Component}\n */\nclass TextInputComponent extends Component {\n  /**\n   * The custom id of this text input\n   *\n   * @type {string}\n   * @readonly\n   */\n  get customId() {\n    return this.data.custom_id;\n  }\n\n  /**\n   * The value for this text input\n   *\n   * @type {string}\n   * @readonly\n   */\n  get value() {\n    return this.data.value;\n  }\n}\n\nexports.TextInputComponent = TextInputComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ThreadChannel.js",
    "content": "'use strict';\n\nconst { lazy } = require('@discordjs/util');\nconst { ChannelFlags, ChannelType, PermissionFlagsBits, Routes } = require('discord-api-types/v10');\nconst { DiscordjsRangeError, ErrorCodes } = require('../errors/index.js');\nconst { GuildMessageManager } = require('../managers/GuildMessageManager.js');\nconst { ThreadMemberManager } = require('../managers/ThreadMemberManager.js');\nconst { ChannelFlagsBitField } = require('../util/ChannelFlagsBitField.js');\nconst { BaseChannel } = require('./BaseChannel.js');\nconst { TextBasedChannel } = require('./interfaces/TextBasedChannel.js');\n\nconst getThreadOnlyChannel = lazy(() => require('./ThreadOnlyChannel.js'));\n\n/**\n * Represents a thread channel on Discord.\n *\n * @extends {BaseChannel}\n * @implements {TextBasedChannel}\n */\nclass ThreadChannel extends BaseChannel {\n  constructor(guild, data, client) {\n    super(guild?.client ?? client, data, false);\n\n    /**\n     * The guild the thread is in\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n\n    /**\n     * The id of the guild the channel is in\n     *\n     * @type {Snowflake}\n     */\n    this.guildId = guild?.id ?? data.guild_id;\n\n    /**\n     * The id of the member who created this thread\n     *\n     * @type {Snowflake}\n     */\n    this.ownerId = data.owner_id;\n\n    /**\n     * A manager of the messages sent to this thread\n     *\n     * @type {GuildMessageManager}\n     */\n    this.messages = new GuildMessageManager(this);\n\n    /**\n     * A manager of the members that are part of this thread\n     *\n     * @type {ThreadMemberManager}\n     */\n    this.members = new ThreadMemberManager(this);\n    this._patch(data);\n  }\n\n  _patch(data) {\n    super._patch(data);\n\n    if ('message' in data) this.messages._add(data.message);\n\n    if ('name' in data) {\n      /**\n       * The name of the thread\n       *\n       * @type {string}\n       */\n      this.name = data.name;\n    }\n\n    if ('guild_id' in data) {\n      this.guildId = data.guild_id;\n    }\n\n    if ('parent_id' in data) {\n      /**\n       * The id of the parent channel of this thread\n       *\n       * @type {?Snowflake}\n       */\n      this.parentId = data.parent_id;\n    } else {\n      this.parentId ??= null;\n    }\n\n    if ('thread_metadata' in data) {\n      /**\n       * Whether the thread is locked\n       *\n       * @type {?boolean}\n       */\n      this.locked = data.thread_metadata.locked ?? false;\n\n      /**\n       * Whether members without the {@link PermissionFlagsBits.ManageThreads} permission\n       * can invite other members to this thread.\n       * <info>This property is always `null` in public threads.</info>\n       *\n       * @type {?boolean}\n       */\n      this.invitable = this.type === ChannelType.PrivateThread ? (data.thread_metadata.invitable ?? false) : null;\n\n      /**\n       * Whether the thread is archived\n       *\n       * @type {?boolean}\n       */\n      this.archived = data.thread_metadata.archived;\n\n      /**\n       * The amount of time (in minutes) after which the thread will automatically archive in case of no recent activity\n       *\n       * @type {?ThreadAutoArchiveDuration}\n       */\n      this.autoArchiveDuration = data.thread_metadata.auto_archive_duration;\n\n      /**\n       * The timestamp when the thread's archive status was last changed\n       * <info>If the thread was never archived or unarchived, this is the timestamp at which the thread was\n       * created</info>\n       *\n       * @type {?number}\n       */\n      this.archiveTimestamp = Date.parse(data.thread_metadata.archive_timestamp);\n\n      if ('create_timestamp' in data.thread_metadata) {\n        // Note: this is needed because we can't assign directly to getters\n        this._createdTimestamp = Date.parse(data.thread_metadata.create_timestamp);\n      }\n    } else {\n      this.locked ??= null;\n      this.archived ??= null;\n      this.autoArchiveDuration ??= null;\n      this.archiveTimestamp ??= null;\n      this.invitable ??= null;\n    }\n\n    this._createdTimestamp ??= this.type === ChannelType.PrivateThread ? super.createdTimestamp : null;\n\n    if ('last_message_id' in data) {\n      /**\n       * The last message id sent in this thread, if one was sent\n       *\n       * @type {?Snowflake}\n       */\n      this.lastMessageId = data.last_message_id;\n    } else {\n      this.lastMessageId ??= null;\n    }\n\n    if ('last_pin_timestamp' in data) {\n      /**\n       * The timestamp when the last pinned message was pinned, if there was one\n       *\n       * @type {?number}\n       */\n      this.lastPinTimestamp = data.last_pin_timestamp ? Date.parse(data.last_pin_timestamp) : null;\n    } else {\n      this.lastPinTimestamp ??= null;\n    }\n\n    if ('rate_limit_per_user' in data) {\n      /**\n       * The rate limit per user (slowmode) for this thread in seconds\n       *\n       * @type {?number}\n       */\n      this.rateLimitPerUser = data.rate_limit_per_user ?? 0;\n    } else {\n      this.rateLimitPerUser ??= null;\n    }\n\n    if ('message_count' in data) {\n      /**\n       * The approximate count of messages in this thread\n       * <info>Threads created before July 1, 2022 may have an inaccurate count.\n       * If you need an approximate value higher than that, use `ThreadChannel#messages.cache.size`</info>\n       *\n       * @type {?number}\n       */\n      this.messageCount = data.message_count;\n    } else {\n      this.messageCount ??= null;\n    }\n\n    if ('member_count' in data) {\n      /**\n       * The approximate count of users in this thread\n       * <info>This stops counting at 50. If you need an approximate value higher than that, use\n       * `ThreadChannel#members.cache.size`</info>\n       *\n       * @type {?number}\n       */\n      this.memberCount = data.member_count;\n    } else {\n      this.memberCount ??= null;\n    }\n\n    if ('total_message_sent' in data) {\n      /**\n       * The number of messages ever sent in a thread, similar to {@link ThreadChannel#messageCount} except it\n       * will not decrement whenever a message is deleted\n       *\n       * @type {?number}\n       */\n      this.totalMessageSent = data.total_message_sent;\n    } else {\n      this.totalMessageSent ??= null;\n    }\n\n    if (data.member && this.client.user) this.members._add({ user_id: this.client.user.id, ...data.member });\n    if (data.messages) for (const message of data.messages) this.messages._add(message);\n\n    if ('applied_tags' in data) {\n      /**\n       * The tags applied to this thread\n       *\n       * @type {Snowflake[]}\n       */\n      this.appliedTags = data.applied_tags;\n    } else {\n      this.appliedTags ??= [];\n    }\n  }\n\n  /**\n   * The timestamp when this thread was created. This isn't available for threads\n   * created before 2022-01-09\n   *\n   * @type {?number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return this._createdTimestamp;\n  }\n\n  /**\n   * A collection of associated guild member objects of this thread's members\n   *\n   * @type {Collection<Snowflake, GuildMember>}\n   * @readonly\n   */\n  get guildMembers() {\n    return this.members.cache.mapValues(member => member.guildMember);\n  }\n\n  /**\n   * The time at which this thread's archive status was last changed\n   * <info>If the thread was never archived or unarchived, this is the time at which the thread was created</info>\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get archivedAt() {\n    return this.archiveTimestamp && new Date(this.archiveTimestamp);\n  }\n\n  /**\n   * The time the thread was created at\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get createdAt() {\n    return this.createdTimestamp && new Date(this.createdTimestamp);\n  }\n\n  /**\n   * The parent channel of this thread\n   *\n   * @type {?(AnnouncementChannel|TextChannel|ForumChannel|MediaChannel)}\n   * @readonly\n   */\n  get parent() {\n    return this.guild.channels.resolve(this.parentId);\n  }\n\n  /**\n   * Makes the client user join the thread.\n   *\n   * @returns {Promise<ThreadChannel>}\n   */\n  async join() {\n    await this.members.add('@me');\n    return this;\n  }\n\n  /**\n   * Makes the client user leave the thread.\n   *\n   * @returns {Promise<ThreadChannel>}\n   */\n  async leave() {\n    await this.members.remove('@me');\n    return this;\n  }\n\n  /**\n   * Gets the overall set of permissions for a member or role in this thread's parent channel, taking overwrites into\n   * account.\n   *\n   * @param {UserResolvable|RoleResolvable} memberOrRole The member or role to obtain the overall permissions for\n   * @param {boolean} [checkAdmin=true] Whether having the {@link PermissionFlagsBits.Administrator} permission\n   * will return all permissions\n   * @returns {?Readonly<PermissionsBitField>}\n   */\n  permissionsFor(memberOrRole, checkAdmin) {\n    return this.parent?.permissionsFor(memberOrRole, checkAdmin) ?? null;\n  }\n\n  /**\n   * Options used to fetch a thread owner.\n   *\n   * @typedef {BaseFetchOptions} FetchThreadOwnerOptions\n   * @property {boolean} [withMember] Whether to also return the guild member associated with this thread member\n   */\n\n  /**\n   * Fetches the owner of this thread. If the thread member object isn't needed,\n   * use {@link ThreadChannel#ownerId} instead.\n   *\n   * @param {FetchThreadOwnerOptions} [options] Options for fetching the owner\n   * @returns {Promise<ThreadMember>}\n   */\n  async fetchOwner(options) {\n    return this.members._fetchSingle({ ...options, member: this.ownerId });\n  }\n\n  /**\n   * Fetches the message that started this thread, if any.\n   * <info>The `Promise` will reject if the original message in a forum post is deleted\n   * or when the original message in the parent channel is deleted.\n   * If you just need the id of that message, use {@link BaseChannel#id} instead.</info>\n   *\n   * @param {BaseFetchOptions} [options] Additional options for this fetch\n   * @returns {Promise<?Message<true>>}\n   */\n  async fetchStarterMessage(options) {\n    const channel = this.parent instanceof getThreadOnlyChannel() ? this : this.parent;\n    return channel?.messages.fetch({ message: this.id, ...options }) ?? null;\n  }\n\n  /**\n   * The options used to edit a thread channel\n   *\n   * @typedef {Object} ThreadEditOptions\n   * @property {string} [name] The new name for the thread\n   * @property {boolean} [archived] Whether the thread is archived\n   * @property {ThreadAutoArchiveDuration} [autoArchiveDuration] The amount of time after which the thread\n   * should automatically archive in case of no recent activity\n   * @property {number} [rateLimitPerUser] The rate limit per user (slowmode) for the thread in seconds\n   * @property {boolean} [locked] Whether the thread is locked\n   * @property {boolean} [invitable] Whether non-moderators can add other non-moderators to a thread\n   * <info>Can only be edited on {@link ChannelType.PrivateThread}</info>\n   * @property {Snowflake[]} [appliedTags] The tags to apply to the thread\n   * @property {ChannelFlagsResolvable} [flags] The flags to set on the channel\n   * @property {string} [reason] Reason for editing the thread\n   */\n\n  /**\n   * Edits this thread.\n   *\n   * @param {ThreadEditOptions} options The options to provide\n   * @returns {Promise<ThreadChannel>}\n   * @example\n   * // Edit a thread\n   * thread.edit({ name: 'new-thread' })\n   *   .then(editedThread => console.log(editedThread))\n   *   .catch(console.error);\n   */\n  async edit(options) {\n    const newData = await this.client.rest.patch(Routes.channel(this.id), {\n      body: {\n        name: options.name,\n        archived: options.archived,\n        auto_archive_duration: options.autoArchiveDuration,\n        rate_limit_per_user: options.rateLimitPerUser,\n        locked: options.locked,\n        invitable: this.type === ChannelType.PrivateThread ? options.invitable : undefined,\n        applied_tags: options.appliedTags,\n        flags: 'flags' in options ? ChannelFlagsBitField.resolve(options.flags) : undefined,\n      },\n      reason: options.reason,\n    });\n\n    return this.client.actions.ChannelUpdate.handle(newData).updated;\n  }\n\n  /**\n   * Sets whether the thread is archived.\n   *\n   * @param {boolean} [archived=true] Whether the thread is archived\n   * @param {string} [reason] Reason for archiving or unarchiving\n   * @returns {Promise<ThreadChannel>}\n   * @example\n   * // Archive the thread\n   * thread.setArchived(true)\n   *   .then(newThread => console.log(`Thread is now ${newThread.archived ? 'archived' : 'active'}`))\n   *   .catch(console.error);\n   */\n  async setArchived(archived = true, reason = undefined) {\n    return this.edit({ archived, reason });\n  }\n\n  /**\n   * Sets the duration after which the thread will automatically archive in case of no recent activity.\n   *\n   * @param {ThreadAutoArchiveDuration} autoArchiveDuration The amount of time after which the thread\n   * should automatically archive in case of no recent activity\n   * @param {string} [reason] Reason for changing the auto archive duration\n   * @returns {Promise<ThreadChannel>}\n   * @example\n   * // Set the thread's auto archive time to 1 hour\n   * thread.setAutoArchiveDuration(ThreadAutoArchiveDuration.OneHour)\n   *   .then(newThread => {\n   *     console.log(`Thread will now archive after ${newThread.autoArchiveDuration} minutes of inactivity`);\n   *    });\n   *   .catch(console.error);\n   */\n  async setAutoArchiveDuration(autoArchiveDuration, reason) {\n    return this.edit({ autoArchiveDuration, reason });\n  }\n\n  /**\n   * Sets whether members without the {@link PermissionFlagsBits.ManageThreads} permission\n   * can invite other members to this thread.\n   *\n   * @param {boolean} [invitable=true] Whether non-moderators can invite non-moderators to this thread\n   * @param {string} [reason] Reason for changing invite\n   * @returns {Promise<ThreadChannel>}\n   */\n  async setInvitable(invitable = true, reason = undefined) {\n    if (this.type !== ChannelType.PrivateThread) {\n      throw new DiscordjsRangeError(ErrorCodes.ThreadInvitableType, this.type);\n    }\n\n    return this.edit({ invitable, reason });\n  }\n\n  /**\n   * Sets whether the thread can be **unarchived** by anyone with the\n   * {@link PermissionFlagsBits.SendMessages} permission. When a thread is locked, only members with the\n   * {@link PermissionFlagsBits.ManageThreads} permission can unarchive it.\n   *\n   * @param {boolean} [locked=true] Whether the thread is locked\n   * @param {string} [reason] Reason for locking or unlocking the thread\n   * @returns {Promise<ThreadChannel>}\n   * @example\n   * // Set the thread to locked\n   * thread.setLocked(true)\n   *   .then(newThread => console.log(`Thread is now ${newThread.locked ? 'locked' : 'unlocked'}`))\n   *   .catch(console.error);\n   */\n  async setLocked(locked = true, reason = undefined) {\n    return this.edit({ locked, reason });\n  }\n\n  /**\n   * Sets a new name for this thread.\n   *\n   * @param {string} name The new name for the thread\n   * @param {string} [reason] Reason for changing the thread's name\n   * @returns {Promise<ThreadChannel>}\n   * @example\n   * // Change the thread's name\n   * thread.setName('not_general')\n   *   .then(newThread => console.log(`Thread's new name is ${newThread.name}`))\n   *   .catch(console.error);\n   */\n  async setName(name, reason) {\n    return this.edit({ name, reason });\n  }\n\n  /**\n   * Sets the rate limit per user (slowmode) for this thread.\n   *\n   * @param {number} rateLimitPerUser The new rate limit in seconds\n   * @param {string} [reason] Reason for changing the thread's rate limit\n   * @returns {Promise<ThreadChannel>}\n   */\n  async setRateLimitPerUser(rateLimitPerUser, reason) {\n    return this.edit({ rateLimitPerUser, reason });\n  }\n\n  /**\n   * Set the applied tags for this channel (only applicable to forum threads)\n   *\n   * @param {Snowflake[]} appliedTags The tags to set for this channel\n   * @param {string} [reason] Reason for changing the thread's applied tags\n   * @returns {Promise<ThreadChannel>}\n   */\n  async setAppliedTags(appliedTags, reason) {\n    return this.edit({ appliedTags, reason });\n  }\n\n  /**\n   * Pins this thread from the forum channel (only applicable to forum threads).\n   *\n   * @param {string} [reason] Reason for pinning\n   * @returns {Promise<ThreadChannel>}\n   */\n  async pin(reason) {\n    return this.edit({ flags: this.flags.add(ChannelFlags.Pinned), reason });\n  }\n\n  /**\n   * Unpins this thread from the forum channel (only applicable to forum threads).\n   *\n   * @param {string} [reason] Reason for unpinning\n   * @returns {Promise<ThreadChannel>}\n   */\n  async unpin(reason) {\n    return this.edit({ flags: this.flags.remove(ChannelFlags.Pinned), reason });\n  }\n\n  /**\n   * Whether the client user is a member of the thread.\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get joined() {\n    return this.members.cache.has(this.client.user?.id);\n  }\n\n  /**\n   * Whether the thread is editable by the client user (name, archived, autoArchiveDuration)\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get editable() {\n    return (\n      (this.ownerId === this.client.user.id && (this.type !== ChannelType.PrivateThread || this.joined)) ||\n      this.manageable\n    );\n  }\n\n  /**\n   * Whether the thread is joinable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get joinable() {\n    return (\n      !this.archived &&\n      !this.joined &&\n      this.permissionsFor(this.client.user)?.has(\n        this.type === ChannelType.PrivateThread ? PermissionFlagsBits.ManageThreads : PermissionFlagsBits.ViewChannel,\n        false,\n      )\n    );\n  }\n\n  /**\n   * Whether the thread is manageable by the client user, for deleting or editing rateLimitPerUser or locked.\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get manageable() {\n    const permissions = this.permissionsFor(this.client.user);\n    if (!permissions) return false;\n    // This flag allows managing even if timed out\n    if (permissions.has(PermissionFlagsBits.Administrator, false)) return true;\n\n    return (\n      this.guild.members.me.communicationDisabledUntilTimestamp < Date.now() &&\n      permissions.has(PermissionFlagsBits.ManageThreads, false)\n    );\n  }\n\n  /**\n   * Whether the thread is viewable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get viewable() {\n    const permissions = this.permissionsFor(this.client.user);\n    if (!permissions) return false;\n    return permissions.has(PermissionFlagsBits.ViewChannel, false);\n  }\n\n  /**\n   * Whether the client user can send messages in this thread\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get sendable() {\n    const permissions = this.permissionsFor(this.client.user);\n    if (!permissions) return false;\n    // This flag allows sending even if timed out\n    if (permissions.has(PermissionFlagsBits.Administrator, false)) return true;\n\n    return (\n      !(this.archived && this.locked && !this.manageable) &&\n      (this.type !== ChannelType.PrivateThread || this.joined || this.manageable) &&\n      permissions.has(PermissionFlagsBits.SendMessagesInThreads, false) &&\n      this.guild.members.me.communicationDisabledUntilTimestamp < Date.now()\n    );\n  }\n\n  /**\n   * Whether the thread is unarchivable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get unarchivable() {\n    return this.archived && this.sendable && (!this.locked || this.manageable);\n  }\n\n  /**\n   * Deletes this thread.\n   *\n   * @param {string} [reason] Reason for deleting this thread\n   * @returns {Promise<ThreadChannel>}\n   * @example\n   * // Delete the thread\n   * thread.delete('cleaning out old threads')\n   *   .then(deletedThread => console.log(deletedThread))\n   *   .catch(console.error);\n   */\n  async delete(reason) {\n    await this.guild.channels.delete(this.id, reason);\n    return this;\n  }\n\n  // These are here only for documentation purposes - they are implemented by TextBasedChannel\n\n  /* eslint-disable getter-return */\n  get lastMessage() {}\n\n  get lastPinAt() {}\n\n  send() {}\n\n  sendTyping() {}\n\n  createMessageCollector() {}\n\n  awaitMessages() {}\n\n  createMessageComponentCollector() {}\n\n  awaitMessageComponent() {}\n\n  bulkDelete() {}\n  // Doesn't work on Thread channels; setRateLimitPerUser() {}\n  // Doesn't work on Thread channels; setNSFW() {}\n}\n\nTextBasedChannel.applyToClass(ThreadChannel, ['fetchWebhooks', 'setRateLimitPerUser', 'setNSFW']);\n\nexports.ThreadChannel = ThreadChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ThreadMember.js",
    "content": "'use strict';\n\nconst { ThreadMemberFlagsBitField } = require('../util/ThreadMemberFlagsBitField.js');\nconst { Base } = require('./Base.js');\n\n/**\n * Represents a Member for a Thread.\n *\n * @extends {Base}\n */\nclass ThreadMember extends Base {\n  constructor(thread, data, extra = {}) {\n    super(thread.client);\n\n    /**\n     * The thread that this member is a part of\n     *\n     * @type {ThreadChannel}\n     */\n    this.thread = thread;\n\n    /**\n     * The timestamp the member last joined the thread at\n     *\n     * @type {?number}\n     */\n    this.joinedTimestamp = null;\n\n    /**\n     * The flags for this thread member. This will be `null` if partial.\n     *\n     * @type {?ThreadMemberFlagsBitField}\n     */\n    this.flags = null;\n\n    /**\n     * The id of the thread member\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.user_id;\n\n    this._patch(data, extra);\n  }\n\n  _patch(data, extra = {}) {\n    if ('join_timestamp' in data) this.joinedTimestamp = Date.parse(data.join_timestamp);\n    if ('flags' in data) this.flags = new ThreadMemberFlagsBitField(data.flags).freeze();\n\n    if ('member' in data) {\n      /**\n       * The guild member associated with this thread member.\n       *\n       * @type {?GuildMember}\n       * @private\n       */\n      this.member = this.thread.guild.members._add(data.member, extra.cache);\n    } else {\n      this.member ??= null;\n    }\n  }\n\n  /**\n   * Whether this thread member is a partial\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get partial() {\n    return this.flags === null;\n  }\n\n  /**\n   * The guild member associated with this thread member\n   *\n   * @type {?GuildMember}\n   * @readonly\n   */\n  get guildMember() {\n    return this.member ?? this.thread.guild.members.cache.get(this.id) ?? null;\n  }\n\n  /**\n   * The last time this member joined the thread\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get joinedAt() {\n    return this.joinedTimestamp && new Date(this.joinedTimestamp);\n  }\n\n  /**\n   * The user associated with this thread member\n   *\n   * @type {?User}\n   * @readonly\n   */\n  get user() {\n    return this.client.users.cache.get(this.id) ?? null;\n  }\n\n  /**\n   * Whether the client user can manage this thread member\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get manageable() {\n    return !this.thread.archived && this.thread.editable;\n  }\n\n  /**\n   * Removes this member from the thread.\n   *\n   * @returns {Promise<ThreadMember>}\n   */\n  async remove() {\n    await this.thread.members.remove(this.id);\n    return this;\n  }\n}\n\nexports.ThreadMember = ThreadMember;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ThreadOnlyChannel.js",
    "content": "'use strict';\n\nconst { GuildForumThreadManager } = require('../managers/GuildForumThreadManager.js');\nconst { transformAPIGuildForumTag, transformAPIGuildDefaultReaction } = require('../util/Channels.js');\nconst { GuildChannel } = require('./GuildChannel.js');\nconst { TextBasedChannel } = require('./interfaces/TextBasedChannel.js');\n\n/**\n * @typedef {Object} GuildForumTagEmoji\n * @property {?Snowflake} id The id of a guild's custom emoji\n * @property {?string} name The unicode character of the emoji\n */\n\n/**\n * @typedef {Object} GuildForumTag\n * @property {Snowflake} id The id of the tag\n * @property {string} name The name of the tag\n * @property {boolean} moderated Whether this tag can only be added to or removed from threads\n * by a member with the `ManageThreads` permission\n * @property {?GuildForumTagEmoji} emoji The emoji of this tag\n */\n\n/**\n * @typedef {Object} GuildForumTagData\n * @property {Snowflake} [id] The id of the tag\n * @property {string} name The name of the tag\n * @property {boolean} [moderated] Whether this tag can only be added to or removed from threads\n * by a member with the `ManageThreads` permission\n * @property {?GuildForumTagEmoji} [emoji] The emoji of this tag\n */\n\n/**\n * @typedef {Object} DefaultReactionEmoji\n * @property {?Snowflake} id The id of a guild's custom emoji\n * @property {?string} name The unicode character of the emoji\n */\n\n/**\n * Represents symbols utilized by thread-only channels.\n *\n * @extends {GuildChannel}\n * @implements {TextBasedChannel}\n * @abstract\n */\nclass ThreadOnlyChannel extends GuildChannel {\n  constructor(guild, data, client) {\n    super(guild, data, client, false);\n\n    /**\n     * A manager of the threads belonging to this channel\n     *\n     * @type {GuildForumThreadManager}\n     */\n    this.threads = new GuildForumThreadManager(this);\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    super._patch(data);\n    if ('available_tags' in data) {\n      /**\n       * The set of tags that can be used in this channel.\n       *\n       * @type {GuildForumTag[]}\n       */\n      this.availableTags = data.available_tags.map(tag => transformAPIGuildForumTag(tag));\n    } else {\n      this.availableTags ??= [];\n    }\n\n    if ('default_reaction_emoji' in data) {\n      /**\n       * The emoji to show in the add reaction button on a thread in a guild forum channel\n       *\n       * @type {?DefaultReactionEmoji}\n       */\n      this.defaultReactionEmoji = data.default_reaction_emoji\n        ? transformAPIGuildDefaultReaction(data.default_reaction_emoji)\n        : null;\n    } else {\n      this.defaultReactionEmoji ??= null;\n    }\n\n    if ('default_thread_rate_limit_per_user' in data) {\n      /**\n       * The initial rate limit per user (slowmode) to set on newly created threads in a channel.\n       *\n       * @type {?number}\n       */\n      this.defaultThreadRateLimitPerUser = data.default_thread_rate_limit_per_user;\n    } else {\n      this.defaultThreadRateLimitPerUser ??= null;\n    }\n\n    if ('rate_limit_per_user' in data) {\n      /**\n       * The rate limit per user (slowmode) for this channel.\n       *\n       * @type {?number}\n       */\n      this.rateLimitPerUser = data.rate_limit_per_user;\n    } else {\n      this.rateLimitPerUser ??= null;\n    }\n\n    if ('default_auto_archive_duration' in data) {\n      /**\n       * The default auto archive duration for newly created threads in this channel.\n       *\n       * @type {?ThreadAutoArchiveDuration}\n       */\n      this.defaultAutoArchiveDuration = data.default_auto_archive_duration;\n    } else {\n      this.defaultAutoArchiveDuration ??= null;\n    }\n\n    if ('nsfw' in data) {\n      /**\n       * If this channel is considered NSFW.\n       *\n       * @type {boolean}\n       */\n      this.nsfw = data.nsfw;\n    } else {\n      this.nsfw ??= false;\n    }\n\n    if ('topic' in data) {\n      /**\n       * The topic of this channel.\n       *\n       * @type {?string}\n       */\n      this.topic = data.topic;\n    }\n\n    if ('default_sort_order' in data) {\n      /**\n       * The default sort order mode used to order posts\n       *\n       * @type {?SortOrderType}\n       */\n      this.defaultSortOrder = data.default_sort_order;\n    } else {\n      this.defaultSortOrder ??= null;\n    }\n  }\n\n  /**\n   * Sets the available tags for this forum channel\n   *\n   * @param {GuildForumTagData[]} availableTags The tags to set as available in this channel\n   * @param {string} [reason] Reason for changing the available tags\n   * @returns {Promise<this>}\n   */\n  async setAvailableTags(availableTags, reason) {\n    return this.edit({ availableTags, reason });\n  }\n\n  /**\n   * Sets the default reaction emoji for this channel\n   *\n   * @param {?DefaultReactionEmoji} defaultReactionEmoji The emoji to set as the default reaction emoji\n   * @param {string} [reason] Reason for changing the default reaction emoji\n   * @returns {Promise<this>}\n   */\n  async setDefaultReactionEmoji(defaultReactionEmoji, reason) {\n    return this.edit({ defaultReactionEmoji, reason });\n  }\n\n  /**\n   * Sets the default rate limit per user (slowmode) for new threads in this channel\n   *\n   * @param {number} defaultThreadRateLimitPerUser The rate limit to set on newly created threads in this channel\n   * @param {string} [reason] Reason for changing the default rate limit\n   * @returns {Promise<this>}\n   */\n  async setDefaultThreadRateLimitPerUser(defaultThreadRateLimitPerUser, reason) {\n    return this.edit({ defaultThreadRateLimitPerUser, reason });\n  }\n\n  /**\n   * Creates an invite to this guild channel.\n   *\n   * @param {InviteCreateOptions} [options={}] The options for creating the invite\n   * @returns {Promise<Invite>}\n   * @example\n   * // Create an invite to a channel\n   * channel.createInvite()\n   *   .then(invite => console.log(`Created an invite with a code of ${invite.code}`))\n   *   .catch(console.error);\n   */\n  async createInvite(options) {\n    return this.guild.invites.create(this.id, options);\n  }\n\n  /**\n   * Fetches a collection of invites to this guild channel.\n   * Resolves with a collection mapping invites by their codes.\n   *\n   * @param {boolean} [cache=true] Whether to cache the fetched invites\n   * @returns {Promise<Collection<string, Invite>>}\n   */\n  async fetchInvites(cache) {\n    return this.guild.invites.fetch({ channelId: this.id, cache });\n  }\n\n  /**\n   * Sets the default auto archive duration for all newly created threads in this channel.\n   *\n   * @param {ThreadAutoArchiveDuration} defaultAutoArchiveDuration The new default auto archive duration\n   * @param {string} [reason] Reason for changing the channel's default auto archive duration\n   * @returns {Promise<this>}\n   */\n  async setDefaultAutoArchiveDuration(defaultAutoArchiveDuration, reason) {\n    return this.edit({ defaultAutoArchiveDuration, reason });\n  }\n\n  /**\n   * Sets a new topic for the guild channel.\n   *\n   * @param {?string} topic The new topic for the guild channel\n   * @param {string} [reason] Reason for changing the guild channel's topic\n   * @returns {Promise<this>}\n   * @example\n   * // Set a new channel topic\n   * channel.setTopic('needs more rate limiting')\n   *   .then(newChannel => console.log(`Channel's new topic is ${newChannel.topic}`))\n   *   .catch(console.error);\n   */\n  async setTopic(topic, reason) {\n    return this.edit({ topic, reason });\n  }\n\n  /**\n   * Sets the default sort order mode used to order posts\n   *\n   * @param {?SortOrderType} defaultSortOrder The default sort order mode to set on this channel\n   * @param {string} [reason] Reason for changing the default sort order\n   * @returns {Promise<this>}\n   */\n  async setDefaultSortOrder(defaultSortOrder, reason) {\n    return this.edit({ defaultSortOrder, reason });\n  }\n\n  // These are here only for documentation purposes - they are implemented by TextBasedChannel\n\n  createWebhook() {}\n\n  fetchWebhooks() {}\n\n  setNSFW() {}\n\n  setRateLimitPerUser() {}\n}\n\nTextBasedChannel.applyToClass(ThreadOnlyChannel, [\n  'send',\n  'lastMessage',\n  'lastPinAt',\n  'bulkDelete',\n  'sendTyping',\n  'createMessageCollector',\n  'awaitMessages',\n  'createMessageComponentCollector',\n  'awaitMessageComponent',\n]);\n\nexports.ThreadOnlyChannel = ThreadOnlyChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/ThumbnailComponent.js",
    "content": "'use strict';\n\nconst { Component } = require('./Component.js');\nconst { UnfurledMediaItem } = require('./UnfurledMediaItem.js');\n\n/**\n * Represents a thumbnail component\n *\n * @extends {Component}\n */\nclass ThumbnailComponent extends Component {\n  constructor({ media, ...data }) {\n    super(data);\n\n    /**\n     * The media associated with this thumbnail\n     *\n     * @type {UnfurledMediaItem}\n     * @readonly\n     */\n    this.media = new UnfurledMediaItem(media);\n  }\n\n  /**\n   * The description of this thumbnail\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get description() {\n    return this.data.description ?? null;\n  }\n\n  /**\n   * Whether this thumbnail is spoilered\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get spoiler() {\n    return this.data.spoiler ?? false;\n  }\n\n  /**\n   * Returns the API-compatible JSON for this component\n   *\n   * @returns {APIThumbnailComponent}\n   */\n  toJSON() {\n    return { ...this.data, media: this.media.toJSON() };\n  }\n}\n\nexports.ThumbnailComponent = ThumbnailComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Typing.js",
    "content": "'use strict';\n\nconst { Base } = require('./Base.js');\n\n/**\n * Represents a typing state for a user in a channel.\n *\n * @extends {Base}\n */\nclass Typing extends Base {\n  constructor(channel, user, data) {\n    super(channel.client);\n\n    /**\n     * The channel the status is from\n     *\n     * @type {TextBasedChannels}\n     */\n    this.channel = channel;\n\n    /**\n     * The user who is typing\n     *\n     * @type {User}\n     */\n    this.user = user;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('timestamp' in data) {\n      /**\n       * The UNIX timestamp in milliseconds the user started typing at\n       *\n       * @type {number}\n       */\n      this.startedTimestamp = data.timestamp * 1_000;\n    }\n  }\n\n  /**\n   * Indicates whether the status is received from a guild.\n   *\n   * @returns {boolean}\n   */\n  inGuild() {\n    return this.guild !== null;\n  }\n\n  /**\n   * The time the user started typing at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get startedAt() {\n    return new Date(this.startedTimestamp);\n  }\n\n  /**\n   * The guild the status is from\n   *\n   * @type {?Guild}\n   * @readonly\n   */\n  get guild() {\n    return this.channel.guild ?? null;\n  }\n\n  /**\n   * The member who is typing\n   *\n   * @type {?GuildMember}\n   * @readonly\n   */\n  get member() {\n    return this.guild?.members.resolve(this.user) ?? null;\n  }\n}\n\nexports.Typing = Typing;\n"
  },
  {
    "path": "packages/discord.js/src/structures/UnfurledMediaItem.js",
    "content": "'use strict';\n\n/**\n * Represents a media item in a component\n */\nclass UnfurledMediaItem {\n  constructor(data) {\n    /**\n     * The API data associated with this media item\n     *\n     * @type {APIUnfurledMediaItem}\n     */\n    this.data = data;\n  }\n\n  /**\n   * The URL of this media item\n   *\n   * @type {string}\n   * @readonly\n   */\n  get url() {\n    return this.data.url;\n  }\n\n  /**\n   * Returns the API-compatible JSON for this media item\n   *\n   * @returns {APIUnfurledMediaItem}\n   */\n  toJSON() {\n    return { ...this.data };\n  }\n}\n\nexports.UnfurledMediaItem = UnfurledMediaItem;\n"
  },
  {
    "path": "packages/discord.js/src/structures/User.js",
    "content": "'use strict';\n\nconst { userMention } = require('@discordjs/formatters');\nconst { calculateUserDefaultAvatarIndex } = require('@discordjs/rest');\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { _transformCollectibles } = require('../util/Transformers.js');\nconst { UserFlagsBitField } = require('../util/UserFlagsBitField.js');\nconst { Base } = require('./Base.js');\n\n/**\n * Represents a user on Discord.\n *\n * @extends {Base}\n */\nclass User extends Base {\n  constructor(client, data) {\n    super(client);\n\n    /**\n     * The user's id\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    this.bot = null;\n\n    this.system = null;\n\n    this.flags = null;\n\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('username' in data) {\n      /**\n       * The username of the user\n       *\n       * @type {?string}\n       */\n      this.username = data.username;\n    } else {\n      this.username ??= null;\n    }\n\n    if ('global_name' in data) {\n      /**\n       * The global name of this user\n       *\n       * @type {?string}\n       */\n      this.globalName = data.global_name;\n    } else {\n      this.globalName ??= null;\n    }\n\n    if ('bot' in data) {\n      /**\n       * Whether or not the user is a bot\n       *\n       * @type {?boolean}\n       */\n      this.bot = Boolean(data.bot);\n    } else if (!this.partial && typeof this.bot !== 'boolean') {\n      this.bot = false;\n    }\n\n    if ('discriminator' in data) {\n      /**\n       * The discriminator of this user\n       * <info>`'0'`, or a 4-digit stringified number if they're using the legacy username system</info>\n       *\n       * @type {?string}\n       */\n      this.discriminator = data.discriminator;\n    } else {\n      this.discriminator ??= null;\n    }\n\n    if ('avatar' in data) {\n      /**\n       * The user avatar's hash\n       *\n       * @type {?string}\n       */\n      this.avatar = data.avatar;\n    } else {\n      this.avatar ??= null;\n    }\n\n    if ('banner' in data) {\n      /**\n       * The user banner's hash\n       * <info>The user must be force fetched for this property to be present or be updated</info>\n       *\n       * @type {?string}\n       */\n      this.banner = data.banner;\n    } else if (this.banner !== null) {\n      this.banner ??= undefined;\n    }\n\n    if ('accent_color' in data) {\n      /**\n       * The base 10 accent color of the user's banner\n       * <info>The user must be force fetched for this property to be present or be updated</info>\n       *\n       * @type {?number}\n       */\n      this.accentColor = data.accent_color;\n    } else if (this.accentColor !== null) {\n      this.accentColor ??= undefined;\n    }\n\n    if ('system' in data) {\n      /**\n       * Whether the user is an Official Discord System user (part of the urgent message system)\n       *\n       * @type {?boolean}\n       */\n      this.system = Boolean(data.system);\n    } else if (!this.partial && typeof this.system !== 'boolean') {\n      this.system = false;\n    }\n\n    if ('public_flags' in data) {\n      /**\n       * The flags for this user\n       *\n       * @type {?UserFlagsBitField}\n       */\n      this.flags = new UserFlagsBitField(data.public_flags);\n    }\n\n    /**\n     * @typedef {Object} AvatarDecorationData\n     * @property {string} asset The avatar decoration hash\n     * @property {Snowflake} skuId The id of the avatar decoration's SKU\n     */\n\n    if ('avatar_decoration_data' in data) {\n      if (data.avatar_decoration_data) {\n        /**\n         * The user avatar decoration's data\n         *\n         * @type {?AvatarDecorationData}\n         */\n        this.avatarDecorationData = {\n          asset: data.avatar_decoration_data.asset,\n          skuId: data.avatar_decoration_data.sku_id,\n        };\n      } else {\n        this.avatarDecorationData = null;\n      }\n    } else {\n      this.avatarDecorationData ??= null;\n    }\n\n    /**\n     * @typedef {Object} NameplateData\n     * @property {Snowflake} skuId The id of the nameplate's SKU\n     * @property {string} asset The nameplate's asset path\n     * @property {string} label The nameplate's label\n     * @property {NameplatePalette} palette Background color of the nameplate\n     */\n\n    /**\n     * @typedef {Object} Collectibles\n     * @property {?NameplateData} nameplate The user's nameplate data\n     */\n\n    if (data.collectibles) {\n      /**\n       * The user's collectibles\n       *\n       * @type {?Collectibles}\n       */\n      this.collectibles = _transformCollectibles(data.collectibles);\n    } else {\n      this.collectibles = null;\n    }\n\n    /**\n     * @typedef {Object} UserPrimaryGuild\n     * @property {?Snowflake} identityGuildId The id of the user's primary guild\n     * @property {?boolean} identityEnabled Whether the user is displaying the primary guild's tag\n     * @property {?string} tag The user's guild tag. Limited to 4 characters\n     * @property {?string} badge The guild tag badge hash\n     */\n\n    if ('primary_guild' in data) {\n      if (data.primary_guild) {\n        /**\n         * The primary guild of the user\n         *\n         * @type {?UserPrimaryGuild}\n         */\n        this.primaryGuild = {\n          identityGuildId: data.primary_guild.identity_guild_id,\n          identityEnabled: data.primary_guild.identity_enabled,\n          tag: data.primary_guild.tag,\n          badge: data.primary_guild.badge,\n        };\n      } else {\n        this.primaryGuild = null;\n      }\n    } else {\n      this.primaryGuild ??= null;\n    }\n  }\n\n  /**\n   * Whether this User is a partial\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get partial() {\n    return typeof this.username !== 'string';\n  }\n\n  /**\n   * The timestamp the user was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time the user was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * A link to the user's avatar.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  avatarURL(options = {}) {\n    return this.avatar && this.client.rest.cdn.avatar(this.id, this.avatar, options);\n  }\n\n  /**\n   * A link to the user's avatar decoration.\n   *\n   * @returns {?string}\n   */\n  avatarDecorationURL() {\n    return this.avatarDecorationData ? this.client.rest.cdn.avatarDecoration(this.avatarDecorationData.asset) : null;\n  }\n\n  /**\n   * A link to the user's default avatar\n   *\n   * @type {string}\n   * @readonly\n   */\n  get defaultAvatarURL() {\n    const index =\n      this.discriminator === '0' || this.discriminator === '0000'\n        ? calculateUserDefaultAvatarIndex(this.id)\n        : this.discriminator % 5;\n\n    return this.client.rest.cdn.defaultAvatar(index);\n  }\n\n  /**\n   * A link to the user's avatar if they have one.\n   * Otherwise a link to their default avatar will be returned.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {string}\n   */\n  displayAvatarURL(options) {\n    return this.avatarURL(options) ?? this.defaultAvatarURL;\n  }\n\n  /**\n   * The hexadecimal version of the user accent color, with a leading hash\n   * <info>The user must be force fetched for this property to be present</info>\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get hexAccentColor() {\n    if (typeof this.accentColor !== 'number') return this.accentColor;\n    return `#${this.accentColor.toString(16).padStart(6, '0')}`;\n  }\n\n  /**\n   * A link to the user's banner. See {@link User#banner} for more info\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  bannerURL(options = {}) {\n    return this.banner && this.client.rest.cdn.banner(this.id, this.banner, options);\n  }\n\n  /**\n   * A link to the user's guild tag badge.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  guildTagBadgeURL(options = {}) {\n    return this.primaryGuild?.badge\n      ? this.client.rest.cdn.guildTagBadge(this.primaryGuild.identityGuildId, this.primaryGuild.badge, options)\n      : null;\n  }\n\n  /**\n   * The tag of this user\n   * <info>This user's username, or their legacy tag (e.g. `hydrabolt#0001`)\n   * if they're using the legacy username system</info>\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get tag() {\n    return typeof this.username === 'string'\n      ? this.discriminator === '0' || this.discriminator === '0000'\n        ? this.username\n        : `${this.username}#${this.discriminator}`\n      : null;\n  }\n\n  /**\n   * The global name of this user, or their username if they don't have one\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get displayName() {\n    return this.globalName ?? this.username;\n  }\n\n  /**\n   * The DM between the client's user and this user\n   *\n   * @type {?DMChannel}\n   * @readonly\n   */\n  get dmChannel() {\n    return this.client.users.dmChannel(this.id);\n  }\n\n  /**\n   * Creates a DM channel between the client and the user.\n   *\n   * @param {boolean} [force=false] Whether to skip the cache check and request the API\n   * @returns {Promise<DMChannel>}\n   */\n  async createDM(force = false) {\n    return this.client.users.createDM(this.id, { force });\n  }\n\n  /**\n   * Deletes a DM channel (if one exists) between the client and the user. Resolves with the channel if successful.\n   *\n   * @returns {Promise<DMChannel>}\n   */\n  async deleteDM() {\n    return this.client.users.deleteDM(this.id);\n  }\n\n  /**\n   * Sends a message to this user.\n   *\n   * @param {string|MessagePayload|MessageCreateOptions} options The options to provide\n   * @returns {Promise<Message>}\n   * @example\n   * // Send a direct message\n   * user.send('Hello!')\n   *   .then(message => console.log(`Sent message: ${message.content} to ${user.tag}`))\n   *   .catch(console.error);\n   */\n  async send(options) {\n    const dmChannel = await this.createDM();\n\n    return this.client.channels.createMessage(dmChannel, options);\n  }\n\n  /**\n   * Checks if the user is equal to another.\n   * It compares id, username, discriminator, avatar, banner, accent color, and bot flags.\n   * It is recommended to compare equality by using `user.id === user2.id` unless you want to compare all properties.\n   *\n   * @param {User} user User to compare with\n   * @returns {boolean}\n   */\n  equals(user) {\n    return (\n      user &&\n      this.id === user.id &&\n      this.username === user.username &&\n      this.discriminator === user.discriminator &&\n      this.globalName === user.globalName &&\n      this.avatar === user.avatar &&\n      this.flags?.bitfield === user.flags?.bitfield &&\n      this.banner === user.banner &&\n      this.accentColor === user.accentColor &&\n      this.avatarDecorationData?.asset === user.avatarDecorationData?.asset &&\n      this.avatarDecorationData?.skuId === user.avatarDecorationData?.skuId &&\n      this.collectibles?.nameplate?.skuId === user.collectibles?.nameplate?.skuId &&\n      this.collectibles?.nameplate?.asset === user.collectibles?.nameplate?.asset &&\n      this.collectibles?.nameplate?.label === user.collectibles?.nameplate?.label &&\n      this.collectibles?.nameplate?.palette === user.collectibles?.nameplate?.palette &&\n      this.primaryGuild?.identityGuildId === user.primaryGuild?.identityGuildId &&\n      this.primaryGuild?.identityEnabled === user.primaryGuild?.identityEnabled &&\n      this.primaryGuild?.tag === user.primaryGuild?.tag &&\n      this.primaryGuild?.badge === user.primaryGuild?.badge\n    );\n  }\n\n  /**\n   * Compares the user with an API user object\n   *\n   * @param {APIUser} user The API user object to compare\n   * @returns {boolean}\n   * @private\n   */\n  _equals(user) {\n    return (\n      user &&\n      this.id === user.id &&\n      this.username === user.username &&\n      this.discriminator === user.discriminator &&\n      this.globalName === user.global_name &&\n      this.avatar === user.avatar &&\n      this.flags?.bitfield === user.public_flags &&\n      ('banner' in user ? this.banner === user.banner : true) &&\n      ('accent_color' in user ? this.accentColor === user.accent_color : true) &&\n      ('avatar_decoration_data' in user\n        ? this.avatarDecorationData?.asset === user.avatar_decoration_data?.asset &&\n          this.avatarDecorationData?.skuId === user.avatar_decoration_data?.sku_id\n        : true) &&\n      ('collectibles' in user\n        ? this.collectibles?.nameplate?.skuId === user.collectibles?.nameplate?.sku_id &&\n          this.collectibles?.nameplate?.asset === user.collectibles?.nameplate?.asset &&\n          this.collectibles?.nameplate?.label === user.collectibles?.nameplate?.label &&\n          this.collectibles?.nameplate?.palette === user.collectibles?.nameplate?.palette\n        : true) &&\n      ('primary_guild' in user\n        ? this.primaryGuild?.identityGuildId === user.primary_guild?.identity_guild_id &&\n          this.primaryGuild?.identityEnabled === user.primary_guild?.identity_enabled &&\n          this.primaryGuild?.tag === user.primary_guild?.tag &&\n          this.primaryGuild?.badge === user.primary_guild?.badge\n        : true)\n    );\n  }\n\n  /**\n   * Fetches this user.\n   *\n   * @param {boolean} [force=true] Whether to skip the cache check and request the API\n   * @returns {Promise<User>}\n   */\n  async fetch(force = true) {\n    return this.client.users.fetch(this.id, { force });\n  }\n\n  /**\n   * When concatenated with a string, this automatically returns the user's mention instead of the User object.\n   *\n   * @returns {string}\n   * @example\n   * // Logs: Hello from <@123456789012345678>!\n   * console.log(`Hello from ${user}!`);\n   */\n  toString() {\n    return userMention(this.id);\n  }\n\n  toJSON(...props) {\n    const json = super.toJSON(\n      {\n        createdTimestamp: true,\n        defaultAvatarURL: true,\n        hexAccentColor: true,\n        tag: true,\n      },\n      ...props,\n    );\n    json.avatarURL = this.avatarURL();\n    json.displayAvatarURL = this.displayAvatarURL();\n    json.bannerURL = this.banner ? this.bannerURL() : this.banner;\n    json.guildTagBadgeURL = this.guildTagBadgeURL();\n    return json;\n  }\n}\n\nexports.User = User;\n"
  },
  {
    "path": "packages/discord.js/src/structures/UserContextMenuCommandInteraction.js",
    "content": "'use strict';\n\nconst { ContextMenuCommandInteraction } = require('./ContextMenuCommandInteraction.js');\n\n/**\n * Represents a user context menu interaction.\n *\n * @extends {ContextMenuCommandInteraction}\n */\nclass UserContextMenuCommandInteraction extends ContextMenuCommandInteraction {\n  /**\n   * The target user from this interaction\n   *\n   * @type {User}\n   * @readonly\n   */\n  get targetUser() {\n    return this.options.getUser('user');\n  }\n\n  /**\n   * The target member from this interaction\n   *\n   * @type {?(GuildMember|APIGuildMember)}\n   * @readonly\n   */\n  get targetMember() {\n    return this.options.getMember('user');\n  }\n}\n\nexports.UserContextMenuCommandInteraction = UserContextMenuCommandInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/UserSelectMenuComponent.js",
    "content": "'use strict';\n\nconst { BaseSelectMenuComponent } = require('./BaseSelectMenuComponent.js');\n\n/**\n * Represents a user select menu component\n *\n * @extends {BaseSelectMenuComponent}\n */\nclass UserSelectMenuComponent extends BaseSelectMenuComponent {}\n\nexports.UserSelectMenuComponent = UserSelectMenuComponent;\n"
  },
  {
    "path": "packages/discord.js/src/structures/UserSelectMenuInteraction.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Events } = require('../util/Events.js');\nconst { MessageComponentInteraction } = require('./MessageComponentInteraction.js');\n\n/**\n * Represents a {@link ComponentType.UserSelect} select menu interaction.\n *\n * @extends {MessageComponentInteraction}\n */\nclass UserSelectMenuInteraction extends MessageComponentInteraction {\n  constructor(client, data) {\n    super(client, data);\n    const { resolved, values } = data.data;\n\n    /**\n     * An array of the selected user ids\n     *\n     * @type {Snowflake[]}\n     */\n    this.values = values ?? [];\n\n    /**\n     * Collection of the selected users\n     *\n     * @type {Collection<Snowflake, User>}\n     */\n    this.users = new Collection();\n\n    /**\n     * Collection of the selected members\n     *\n     * @type {Collection<Snowflake, GuildMember|APIGuildMember>}\n     */\n    this.members = new Collection();\n\n    for (const user of Object.values(resolved?.users ?? {})) {\n      this.users.set(user.id, this.client.users._add(user));\n    }\n\n    for (const [id, member] of Object.entries(resolved?.members ?? {})) {\n      const user = resolved.users[id];\n\n      if (!user) {\n        this.client.emit(Events.Debug, `[UserSelectMenuInteraction] Received a member without a user, skipping ${id}`);\n        continue;\n      }\n\n      this.members.set(id, this.guild?.members._add({ user, ...member }) ?? { user, ...member });\n    }\n  }\n}\n\nexports.UserSelectMenuInteraction = UserSelectMenuInteraction;\n"
  },
  {
    "path": "packages/discord.js/src/structures/VoiceChannel.js",
    "content": "'use strict';\n\nconst { PermissionFlagsBits, Routes } = require('discord-api-types/v10');\nconst { BaseGuildVoiceChannel } = require('./BaseGuildVoiceChannel.js');\n\n/**\n * Represents a guild voice channel on Discord.\n *\n * @extends {BaseGuildVoiceChannel}\n */\nclass VoiceChannel extends BaseGuildVoiceChannel {\n  /**\n   * Whether the channel is joinable by the client user\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get joinable() {\n    if (!super.joinable) return false;\n    return !this.full || this.permissionsFor(this.client.user).has(PermissionFlagsBits.MoveMembers, false);\n  }\n\n  /**\n   * Checks if the client has permission to send audio to the voice channel\n   *\n   * @type {boolean}\n   * @readonly\n   */\n  get speakable() {\n    const permissions = this.permissionsFor(this.client.user);\n    if (!permissions) return false;\n    // This flag allows speaking even if timed out\n    if (permissions.has(PermissionFlagsBits.Administrator, false)) return true;\n\n    return (\n      this.guild.members.me.communicationDisabledUntilTimestamp < Date.now() &&\n      permissions.has(PermissionFlagsBits.Speak, false)\n    );\n  }\n\n  /**\n   * @typedef {Object} SendSoundboardSoundOptions\n   * @property {string} soundId The id of the soundboard sound to send\n   * @property {string} [guildId] The id of the guild the soundboard sound is a part of\n   */\n\n  /**\n   * Send a soundboard sound to a voice channel the user is connected to.\n   *\n   * @param {SoundboardSound|SendSoundboardSoundOptions} sound The sound to send\n   * @returns {Promise<void>}\n   */\n  async sendSoundboardSound(sound) {\n    await this.client.rest.post(Routes.sendSoundboardSound(this.id), {\n      body: {\n        sound_id: sound.soundId,\n        source_guild_id: sound.guildId ?? undefined,\n      },\n    });\n  }\n}\n\n/**\n * Sets the bitrate of the channel.\n *\n * @method setBitrate\n * @memberof VoiceChannel\n * @instance\n * @param {number} bitrate The new bitrate\n * @param {string} [reason] Reason for changing the channel's bitrate\n * @returns {Promise<VoiceChannel>}\n * @example\n * // Set the bitrate of a voice channel\n * voiceChannel.setBitrate(48_000)\n *   .then(channel => console.log(`Set bitrate to ${channel.bitrate}bps for ${channel.name}`))\n *   .catch(console.error);\n */\n\n/**\n * Sets the RTC region of the channel.\n *\n * @method setRTCRegion\n * @memberof VoiceChannel\n * @instance\n * @param {?string} rtcRegion The new region of the channel. Set to `null` to remove a specific region for the channel\n * @param {string} [reason] The reason for modifying this region.\n * @returns {Promise<VoiceChannel>}\n * @example\n * // Set the RTC region to sydney\n * voiceChannel.setRTCRegion('sydney');\n * @example\n * // Remove a fixed region for this channel - let Discord decide automatically\n * voiceChannel.setRTCRegion(null, 'We want to let Discord decide.');\n */\n\n/**\n * Sets the user limit of the channel.\n *\n * @method setUserLimit\n * @memberof VoiceChannel\n * @instance\n * @param {number} userLimit The new user limit\n * @param {string} [reason] Reason for changing the user limit\n * @returns {Promise<VoiceChannel>}\n * @example\n * // Set the user limit of a voice channel\n * voiceChannel.setUserLimit(42)\n *   .then(channel => console.log(`Set user limit to ${channel.userLimit} for ${channel.name}`))\n *   .catch(console.error);\n */\n\n/**\n * Sets the camera video quality mode of the channel.\n *\n * @method setVideoQualityMode\n * @memberof VoiceChannel\n * @instance\n * @param {VideoQualityMode} videoQualityMode The new camera video quality mode.\n * @param {string} [reason] Reason for changing the camera video quality mode.\n * @returns {Promise<VoiceChannel>}\n */\n\nexports.VoiceChannel = VoiceChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/VoiceChannelEffect.js",
    "content": "'use strict';\n\nconst { Emoji } = require('./Emoji.js');\n\n/**\n * Represents an effect used in a {@link VoiceChannel}.\n */\nclass VoiceChannelEffect {\n  constructor(data, guild) {\n    /**\n     * The guild where the effect was sent from.\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n\n    /**\n     * The id of the channel the effect was sent in.\n     *\n     * @type {Snowflake}\n     */\n    this.channelId = data.channel_id;\n\n    /**\n     * The id of the user that sent the effect.\n     *\n     * @type {Snowflake}\n     */\n    this.userId = data.user_id;\n\n    /**\n     * The emoji of the effect.\n     *\n     * @type {?Emoji}\n     */\n    this.emoji = data.emoji ? new Emoji(guild.client, data.emoji) : null;\n\n    /**\n     * The animation type of the effect.\n     *\n     * @type {?VoiceChannelEffectSendAnimationType}\n     */\n    this.animationType = data.animation_type ?? null;\n\n    /**\n     * The animation id of the effect.\n     *\n     * @type {?number}\n     */\n    this.animationId = data.animation_id ?? null;\n\n    /**\n     * The id of the soundboard sound for soundboard effects.\n     *\n     * @type {?(Snowflake|number)}\n     */\n    this.soundId = data.sound_id ?? null;\n\n    /**\n     * The volume of the soundboard sound [0-1] for soundboard effects.\n     *\n     * @type {?number}\n     */\n    this.soundVolume = data.sound_volume ?? null;\n  }\n\n  /**\n   * The channel the effect was sent in.\n   *\n   * @type {?VoiceChannel}\n   * @readonly\n   */\n  get channel() {\n    return this.guild.channels.cache.get(this.channelId) ?? null;\n  }\n\n  /**\n   * The soundboard sound for soundboard effects.\n   *\n   * @type {?SoundboardSound}\n   * @readonly\n   */\n  get soundboardSound() {\n    return this.guild.soundboardSounds.cache.get(this.soundId) ?? null;\n  }\n}\n\nexports.VoiceChannelEffect = VoiceChannelEffect;\n"
  },
  {
    "path": "packages/discord.js/src/structures/VoiceRegion.js",
    "content": "'use strict';\n\nconst { flatten } = require('../util/Util.js');\n\n/**\n * Represents a Discord voice region for guilds.\n */\nclass VoiceRegion {\n  constructor(data) {\n    /**\n     * The region's id\n     *\n     * @type {string}\n     */\n    this.id = data.id;\n\n    /**\n     * Name of the region\n     *\n     * @type {string}\n     */\n    this.name = data.name;\n\n    /**\n     * Whether the region is deprecated\n     *\n     * @type {boolean}\n     */\n    this.deprecated = data.deprecated;\n\n    /**\n     * Whether the region is optimal\n     *\n     * @type {boolean}\n     */\n    this.optimal = data.optimal;\n\n    /**\n     * Whether the region is custom\n     *\n     * @type {boolean}\n     */\n    this.custom = data.custom;\n  }\n\n  toJSON() {\n    return flatten(this);\n  }\n}\n\nexports.VoiceRegion = VoiceRegion;\n"
  },
  {
    "path": "packages/discord.js/src/structures/VoiceState.js",
    "content": "'use strict';\n\nconst { ChannelType, Routes } = require('discord-api-types/v10');\nconst { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { Base } = require('./Base.js');\n\n/**\n * Represents the voice state for a Guild Member.\n *\n * @extends {Base}\n */\nclass VoiceState extends Base {\n  constructor(guild, data) {\n    super(guild.client);\n    /**\n     * The guild of this voice state\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n    /**\n     * The id of the member of this voice state\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.user_id;\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('deaf' in data) {\n      /**\n       * Whether this member is deafened server-wide\n       *\n       * @type {?boolean}\n       */\n      this.serverDeaf = data.deaf;\n    } else {\n      this.serverDeaf ??= null;\n    }\n\n    if ('mute' in data) {\n      /**\n       * Whether this member is muted server-wide\n       *\n       * @type {?boolean}\n       */\n      this.serverMute = data.mute;\n    } else {\n      this.serverMute ??= null;\n    }\n\n    if ('self_deaf' in data) {\n      /**\n       * Whether this member is self-deafened\n       *\n       * @type {?boolean}\n       */\n      this.selfDeaf = data.self_deaf;\n    } else {\n      this.selfDeaf ??= null;\n    }\n\n    if ('self_mute' in data) {\n      /**\n       * Whether this member is self-muted\n       *\n       * @type {?boolean}\n       */\n      this.selfMute = data.self_mute;\n    } else {\n      this.selfMute ??= null;\n    }\n\n    if ('self_video' in data) {\n      /**\n       * Whether this member's camera is enabled\n       *\n       * @type {?boolean}\n       */\n      this.selfVideo = data.self_video;\n    } else {\n      this.selfVideo ??= null;\n    }\n\n    if ('session_id' in data) {\n      /**\n       * The session id for this member's connection\n       *\n       * @type {?string}\n       */\n      this.sessionId = data.session_id;\n    } else {\n      this.sessionId ??= null;\n    }\n\n    // The self_stream is property is omitted if false, check for another property\n    // here to avoid incorrectly clearing this when partial data is specified\n    if ('self_video' in data) {\n      /**\n       * Whether this member is streaming using \"Screen Share\"\n       *\n       * @type {?boolean}\n       */\n      this.streaming = data.self_stream ?? false;\n    } else {\n      this.streaming ??= null;\n    }\n\n    if ('channel_id' in data) {\n      /**\n       * The {@link VoiceChannel} or {@link StageChannel} id the member is in\n       *\n       * @type {?Snowflake}\n       */\n      this.channelId = data.channel_id;\n    } else {\n      this.channelId ??= null;\n    }\n\n    if ('suppress' in data) {\n      /**\n       * Whether this member is suppressed from speaking. This property is specific to stage channels only.\n       *\n       * @type {?boolean}\n       */\n      this.suppress = data.suppress;\n    } else {\n      this.suppress ??= null;\n    }\n\n    if ('request_to_speak_timestamp' in data) {\n      /**\n       * The time at which the member requested to speak. This property is specific to stage channels only.\n       *\n       * @type {?number}\n       */\n      this.requestToSpeakTimestamp = data.request_to_speak_timestamp && Date.parse(data.request_to_speak_timestamp);\n    } else {\n      this.requestToSpeakTimestamp ??= null;\n    }\n\n    return this;\n  }\n\n  /**\n   * The member that this voice state belongs to\n   *\n   * @type {?GuildMember}\n   * @readonly\n   */\n  get member() {\n    return this.guild.members.cache.get(this.id) ?? null;\n  }\n\n  /**\n   * The channel that the member is connected to\n   *\n   * @type {?(VoiceChannel|StageChannel)}\n   * @readonly\n   */\n  get channel() {\n    return this.guild.channels.cache.get(this.channelId) ?? null;\n  }\n\n  /**\n   * Whether this member is either self-deafened or server-deafened\n   *\n   * @type {?boolean}\n   * @readonly\n   */\n  get deaf() {\n    return this.serverDeaf || this.selfDeaf;\n  }\n\n  /**\n   * Whether this member is either self-muted or server-muted\n   *\n   * @type {?boolean}\n   * @readonly\n   */\n  get mute() {\n    return this.serverMute || this.selfMute;\n  }\n\n  /**\n   * Mutes/unmutes the member of this voice state.\n   *\n   * @param {boolean} [mute=true] Whether or not the member should be muted\n   * @param {string} [reason] Reason for muting or unmuting\n   * @returns {Promise<GuildMember>}\n   */\n  async setMute(mute = true, reason = undefined) {\n    return this.guild.members.edit(this.id, { mute, reason });\n  }\n\n  /**\n   * Deafens/undeafens the member of this voice state.\n   *\n   * @param {boolean} [deaf=true] Whether or not the member should be deafened\n   * @param {string} [reason] Reason for deafening or undeafening\n   * @returns {Promise<GuildMember>}\n   */\n  async setDeaf(deaf = true, reason = undefined) {\n    return this.guild.members.edit(this.id, { deaf, reason });\n  }\n\n  /**\n   * Disconnects the member from the channel.\n   *\n   * @param {string} [reason] Reason for disconnecting the member from the channel\n   * @returns {Promise<GuildMember>}\n   */\n  async disconnect(reason) {\n    return this.setChannel(null, reason);\n  }\n\n  /**\n   * Moves the member to a different channel, or disconnects them from the one they're in.\n   *\n   * @param {?GuildVoiceChannelResolvable} channel Channel to move the member to, or `null` if you want to\n   * disconnect them from voice.\n   * @param {string} [reason] Reason for moving member to another channel or disconnecting\n   * @returns {Promise<GuildMember>}\n   */\n  async setChannel(channel, reason) {\n    return this.guild.members.edit(this.id, { channel, reason });\n  }\n\n  /**\n   * Data to edit the logged in user's own voice state with, when in a stage channel\n   *\n   * @typedef {Object} VoiceStateEditOptions\n   * @property {boolean} [requestToSpeak] Whether or not the client is requesting to become a speaker.\n   * <info>Only available to the logged in user's own voice state.</info>\n   * @property {boolean} [suppressed] Whether or not the user should be suppressed.\n   */\n\n  /**\n   * Edits this voice state. Currently only available when in a stage channel\n   *\n   * @param {VoiceStateEditOptions} options The options to provide\n   * @returns {Promise<VoiceState>}\n   */\n  async edit(options) {\n    if (this.channel?.type !== ChannelType.GuildStageVoice) throw new DiscordjsError(ErrorCodes.VoiceNotStageChannel);\n\n    const target = this.client.user.id === this.id ? '@me' : this.id;\n\n    if (target !== '@me' && options.requestToSpeak !== undefined) {\n      throw new DiscordjsError(ErrorCodes.VoiceStateNotOwn);\n    }\n\n    if (!['boolean', 'undefined'].includes(typeof options.requestToSpeak)) {\n      throw new DiscordjsTypeError(ErrorCodes.VoiceStateInvalidType, 'requestToSpeak');\n    }\n\n    if (!['boolean', 'undefined'].includes(typeof options.suppressed)) {\n      throw new DiscordjsTypeError(ErrorCodes.VoiceStateInvalidType, 'suppressed');\n    }\n\n    await this.client.rest.patch(Routes.guildVoiceState(this.guild.id, target), {\n      body: {\n        channel_id: this.channelId,\n        request_to_speak_timestamp: options.requestToSpeak\n          ? new Date().toISOString()\n          : options.requestToSpeak === false\n            ? null\n            : undefined,\n        suppress: options.suppressed,\n      },\n    });\n    return this;\n  }\n\n  /**\n   * Fetches this voice state.\n   *\n   * @param {boolean} [force=true] Whether to skip the cache check and request the API\n   * @returns {Promise<VoiceState>}\n   */\n  async fetch(force = true) {\n    return this.guild.voiceStates.fetch(this.id, { force });\n  }\n\n  /**\n   * Toggles the request to speak in the channel.\n   * Only applicable for stage channels and for the client's own voice state.\n   *\n   * @param {boolean} [requestToSpeak=true] Whether or not the client is requesting to become a speaker.\n   * @example\n   * // Making the client request to speak in a stage channel (raise its hand)\n   * guild.members.me.voice.setRequestToSpeak(true);\n   * @example\n   * // Making the client cancel a request to speak\n   * guild.members.me.voice.setRequestToSpeak(false);\n   * @returns {Promise<VoiceState>}\n   */\n  async setRequestToSpeak(requestToSpeak = true) {\n    return this.edit({ requestToSpeak });\n  }\n\n  /**\n   * Suppress/unsuppress the user. Only applicable for stage channels.\n   *\n   * @param {boolean} [suppressed=true] Whether or not the user should be suppressed.\n   * @example\n   * // Making the client a speaker\n   * guild.members.me.voice.setSuppressed(false);\n   * @example\n   * // Making the client an audience member\n   * guild.members.me.voice.setSuppressed(true);\n   * @example\n   * // Inviting another user to speak\n   * voiceState.setSuppressed(false);\n   * @example\n   * // Moving another user to the audience, or cancelling their invite to speak\n   * voiceState.setSuppressed(true);\n   * @returns {Promise<VoiceState>}\n   */\n  async setSuppressed(suppressed = true) {\n    return this.edit({ suppressed });\n  }\n\n  toJSON() {\n    return super.toJSON({\n      id: true,\n      serverDeaf: true,\n      serverMute: true,\n      selfDeaf: true,\n      selfMute: true,\n      sessionId: true,\n      channelId: 'channel',\n    });\n  }\n}\n\nexports.VoiceState = VoiceState;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Webhook.js",
    "content": "'use strict';\n\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { lazy } = require('@discordjs/util');\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { Routes, WebhookType } = require('discord-api-types/v10');\nconst { DiscordjsError, ErrorCodes } = require('../errors/index.js');\nconst { resolveImage } = require('../util/DataResolver.js');\nconst { MessagePayload } = require('./MessagePayload.js');\n\nconst getMessage = lazy(() => require('./Message.js').Message);\n\n/**\n * Represents a webhook.\n */\nclass Webhook {\n  constructor(client, data) {\n    /**\n     * The client that instantiated the webhook\n     *\n     * @name Webhook#client\n     * @type {Client}\n     * @readonly\n     */\n    Object.defineProperty(this, 'client', { value: client });\n    this._patch(data);\n  }\n\n  _patch(data) {\n    if ('name' in data) {\n      /**\n       * The name of the webhook\n       *\n       * @type {string}\n       */\n      this.name = data.name;\n    }\n\n    /**\n     * The token for the webhook, unavailable for follower webhooks and webhooks owned by another application.\n     *\n     * @name Webhook#token\n     * @type {?string}\n     */\n    Object.defineProperty(this, 'token', {\n      value: data.token ?? null,\n      writable: true,\n      configurable: true,\n    });\n\n    if ('avatar' in data) {\n      /**\n       * The avatar for the webhook\n       *\n       * @type {?string}\n       */\n      this.avatar = data.avatar;\n    }\n\n    /**\n     * The webhook's id\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    if ('type' in data) {\n      /**\n       * The type of the webhook\n       *\n       * @type {WebhookType}\n       */\n      this.type = data.type;\n    }\n\n    if ('guild_id' in data) {\n      /**\n       * The guild the webhook belongs to\n       *\n       * @type {Snowflake}\n       */\n      this.guildId = data.guild_id;\n    }\n\n    if ('channel_id' in data) {\n      /**\n       * The id of the channel the webhook belongs to\n       *\n       * @type {Snowflake}\n       */\n      this.channelId = data.channel_id;\n    }\n\n    if ('user' in data) {\n      /**\n       * The owner of the webhook\n       *\n       * @type {?User}\n       */\n      this.owner = this.client.users._add(data.user);\n    } else {\n      this.owner ??= null;\n    }\n\n    if ('application_id' in data) {\n      /**\n       * The application that created this webhook\n       *\n       * @type {?Snowflake}\n       */\n      this.applicationId = data.application_id;\n    } else {\n      this.applicationId ??= null;\n    }\n\n    if ('source_guild' in data) {\n      /**\n       * The source guild of the webhook\n       *\n       * @type {?(Guild|APIGuild)}\n       */\n      this.sourceGuild = this.client.guilds.cache.get(data.source_guild.id) ?? data.source_guild;\n    } else {\n      this.sourceGuild ??= null;\n    }\n\n    if ('source_channel' in data) {\n      /**\n       * The source channel of the webhook\n       *\n       * @type {?(AnnouncementChannel|APIChannel)}\n       */\n      this.sourceChannel = this.client.channels.cache.get(data.source_channel?.id) ?? data.source_channel;\n    } else {\n      this.sourceChannel ??= null;\n    }\n  }\n\n  /**\n   * Options that can be passed into send.\n   *\n   * @typedef {BaseMessageOptionsWithPoll} WebhookMessageCreateOptions\n   * @property {boolean} [tts=false] Whether the message should be spoken aloud\n   * @property {MessageFlags} [flags] Which flags to set for the message.\n   * <info>Only {@link MessageFlags.SuppressEmbeds} and {@link MessageFlags.IsVoiceMessage} can be set.</info>\n   * @property {string} [username=this.name] Username override for the message\n   * @property {string} [avatarURL] Avatar URL override for the message\n   * @property {Snowflake} [threadId] The id of the thread in the channel to send to.\n   * <info>For interaction webhooks, this property is ignored</info>\n   * @property {string} [threadName] Name of the thread to create (only available if the webhook is in a forum channel)\n   * @property {Snowflake[]} [appliedTags]\n   * The tags to apply to the created thread (only available if the webhook is in a forum channel)\n   * @property {boolean} [withComponents] Whether to allow sending non-interactive components in the message.\n   * <info>For application-owned webhooks, this property is ignored</info>\n   */\n\n  /**\n   * Options that can be passed into editMessage.\n   *\n   * @typedef {MessageEditOptions} WebhookMessageEditOptions\n   * @property {Snowflake} [threadId] The id of the thread this message belongs to\n   * <info>For interaction webhooks, this property is ignored</info>\n   * @property {boolean} [withComponents] Whether to allow sending non-interactive components in the message.\n   * <info>For application-owned webhooks, this property is ignored</info>\n   */\n\n  /**\n   * The channel the webhook belongs to\n   *\n   * @type {?(TextChannel|VoiceChannel|StageChannel|AnnouncementChannel|ForumChannel|MediaChannel)}\n   * @readonly\n   */\n  get channel() {\n    return this.client.channels.resolve(this.channelId);\n  }\n\n  /**\n   * Sends a message with this webhook.\n   *\n   * @param {string|MessagePayload|WebhookMessageCreateOptions} options The options to provide\n   * @returns {Promise<Message>}\n   * @example\n   * // Send a basic message\n   * webhook.send('hello!')\n   *   .then(message => console.log(`Sent message: ${message.content}`))\n   *   .catch(console.error);\n   * @example\n   * // Send a basic message in a thread\n   * webhook.send({ content: 'hello!', threadId: '836856309672348295' })\n   *   .then(message => console.log(`Sent message: ${message.content}`))\n   *   .catch(console.error);\n   * @example\n   * // Send a remote file\n   * webhook.send({\n   *   files: ['https://github.com/discordjs.png']\n   * })\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Send a local file\n   * webhook.send({\n   *   files: [{\n   *     attachment: 'entire/path/to/file.jpg',\n   *     name: 'file.jpg'\n   *   }]\n   * })\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Send an embed with a local image inside\n   * webhook.send({\n   *   content: 'This is an embed',\n   *   embeds: [{\n   *     thumbnail: {\n   *          url: 'attachment://file.jpg'\n   *       }\n   *    }],\n   *    files: [{\n   *       attachment: 'entire/path/to/file.jpg',\n   *       name: 'file.jpg'\n   *    }]\n   * })\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async send(options) {\n    if (!this.token) throw new DiscordjsError(ErrorCodes.WebhookTokenUnavailable);\n\n    let messagePayload;\n\n    if (options instanceof MessagePayload) {\n      messagePayload = options.resolveBody();\n    } else {\n      messagePayload = MessagePayload.create(this, options).resolveBody();\n    }\n\n    const query = makeURLSearchParams({\n      wait: true,\n      thread_id: messagePayload.options.threadId,\n      with_components: messagePayload.options.withComponents,\n    });\n\n    const { body, files } = await messagePayload.resolveFiles();\n    const data = await this.client.rest.post(Routes.webhook(this.id, this.token), {\n      body,\n      files,\n      query,\n      auth: false,\n    });\n\n    return (\n      this.client.channels.cache.get(data.channel_id)?.messages._add(data, false) ??\n      new (getMessage())(this.client, data)\n    );\n  }\n\n  /**\n   * Sends a raw slack message with this webhook.\n   *\n   * @param {Object} body The raw body to send\n   * @returns {Promise<boolean>}\n   * @example\n   * // Send a slack message\n   * webhook.sendSlackMessage({\n   *   'username': 'Wumpus',\n   *   'attachments': [{\n   *     'pretext': 'this looks pretty cool',\n   *     'color': '#F0F',\n   *     'footer_icon': 'http://snek.s3.amazonaws.com/topSnek.png',\n   *     'footer': 'Powered by sneks',\n   *     'ts': Date.now() / 1_000\n   *   }]\n   * }).catch(console.error);\n   * @see {@link https://api.slack.com/messaging/webhooks}\n   */\n  async sendSlackMessage(body) {\n    if (!this.token) throw new DiscordjsError(ErrorCodes.WebhookTokenUnavailable);\n\n    const data = await this.client.rest.post(Routes.webhookPlatform(this.id, this.token, 'slack'), {\n      query: makeURLSearchParams({ wait: true }),\n      auth: false,\n      body,\n    });\n    return data.toString() === 'ok';\n  }\n\n  /**\n   * Options used to edit a {@link Webhook}.\n   *\n   * @typedef {Object} WebhookEditOptions\n   * @property {string} [name=this.name] The new name for the webhook\n   * @property {?(BufferResolvable)} [avatar] The new avatar for the webhook\n   * @property {GuildTextChannelResolvable|VoiceChannel|StageChannel|ForumChannel|MediaChannel} [channel]\n   * The new channel for the webhook\n   * @property {string} [reason] Reason for editing the webhook\n   */\n\n  /**\n   * Edits this webhook.\n   *\n   * @param {WebhookEditOptions} options Options for editing the webhook\n   * @returns {Promise<Webhook>}\n   */\n  async edit({ name = this.name, avatar: newAvatar, channel: newChannel, reason }) {\n    let avatar = newAvatar;\n    if (avatar && !(typeof avatar === 'string' && avatar.startsWith('data:'))) {\n      avatar = await resolveImage(avatar);\n    }\n\n    const channel = newChannel?.id ?? newChannel;\n    const data = await this.client.rest.patch(Routes.webhook(this.id, channel ? undefined : this.token), {\n      body: { name, avatar, channel_id: channel },\n      reason,\n      auth: !this.token || Boolean(channel),\n    });\n\n    this.name = data.name;\n    this.avatar = data.avatar;\n    this.channelId = data.channel_id;\n    return this;\n  }\n\n  /**\n   * Options that can be passed into fetchMessage.\n   *\n   * @typedef {options} WebhookFetchMessageOptions\n   * @property {boolean} [cache=true] Whether to cache the message.\n   * @property {Snowflake} [threadId] The id of the thread this message belongs to.\n   * <info>For interaction webhooks, this property is ignored</info>\n   */\n\n  /**\n   * Gets a message that was sent by this webhook.\n   *\n   * @param {Snowflake|'@original'} message The id of the message to fetch\n   * @param {WebhookFetchMessageOptions} [options={}] The options to provide to fetch the message.\n   * @returns {Promise<Message>} Returns the message sent by this webhook\n   */\n  async fetchMessage(message, { threadId } = {}) {\n    if (!this.token) throw new DiscordjsError(ErrorCodes.WebhookTokenUnavailable);\n\n    const data = await this.client.rest.get(Routes.webhookMessage(this.id, this.token, message), {\n      query: threadId ? makeURLSearchParams({ thread_id: threadId }) : undefined,\n      auth: false,\n    });\n\n    return (\n      this.client.channels.cache.get(data.channel_id)?.messages._add(data, false) ??\n      new (getMessage())(this.client, data)\n    );\n  }\n\n  /**\n   * Edits a message that was sent by this webhook.\n   *\n   * @param {MessageResolvable|'@original'} message The message to edit\n   * @param {string|MessagePayload|WebhookMessageEditOptions} options The options to provide\n   * @returns {Promise<Message>} Returns the message edited by this webhook\n   */\n  async editMessage(message, options) {\n    if (!this.token) throw new DiscordjsError(ErrorCodes.WebhookTokenUnavailable);\n\n    let messagePayload;\n\n    if (options instanceof MessagePayload) messagePayload = options;\n    else messagePayload = MessagePayload.create(this, options);\n\n    const { body, files } = await messagePayload.resolveBody().resolveFiles();\n\n    const query = makeURLSearchParams({\n      thread_id: messagePayload.options.threadId,\n      with_components: messagePayload.options.withComponents,\n    });\n\n    const data = await this.client.rest.patch(\n      Routes.webhookMessage(this.id, this.token, typeof message === 'string' ? message : message.id),\n      {\n        body,\n        files,\n        query,\n        auth: false,\n      },\n    );\n\n    const messageManager = this.client.channels.cache.get(data.channel_id)?.messages;\n    if (!messageManager) return new (getMessage())(this.client, data);\n\n    const existing = messageManager.cache.get(data.id);\n    if (!existing) return messageManager._add(data);\n\n    const clone = existing._clone();\n    clone._patch(data);\n    return clone;\n  }\n\n  /**\n   * Deletes the webhook.\n   *\n   * @param {string} [reason] Reason for deleting this webhook\n   * @returns {Promise<void>}\n   */\n  async delete(reason) {\n    return this.client.deleteWebhook(this.id, { token: this.token, reason });\n  }\n\n  /**\n   * Delete a message that was sent by this webhook.\n   *\n   * @param {MessageResolvable|'@original'} message The message to delete\n   * @param {Snowflake} [threadId] The id of the thread this message belongs to\n   * @returns {Promise<void>}\n   */\n  async deleteMessage(message, threadId) {\n    if (!this.token) throw new DiscordjsError(ErrorCodes.WebhookTokenUnavailable);\n\n    await this.client.rest.delete(\n      Routes.webhookMessage(this.id, this.token, typeof message === 'string' ? message : message.id),\n      {\n        query: threadId ? makeURLSearchParams({ thread_id: threadId }) : undefined,\n        auth: false,\n      },\n    );\n  }\n\n  /**\n   * The timestamp the webhook was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time the webhook was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * The URL of this webhook\n   *\n   * @type {string}\n   * @readonly\n   */\n  get url() {\n    return this.client.options.rest.api + Routes.webhook(this.id, this.token);\n  }\n\n  /**\n   * A link to the webhook's avatar.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  avatarURL(options = {}) {\n    return this.avatar && this.client.rest.cdn.avatar(this.id, this.avatar, options);\n  }\n\n  /**\n   * Whether this webhook is created by a user.\n   *\n   * @returns {boolean}\n   */\n  isUserCreated() {\n    return Boolean(this.type === WebhookType.Incoming && this.owner && !this.owner.bot);\n  }\n\n  /**\n   * Whether this webhook is created by an application.\n   *\n   * @returns {boolean}\n   */\n  isApplicationCreated() {\n    return this.type === WebhookType.Application;\n  }\n\n  /**\n   * Whether or not this webhook is a channel follower webhook.\n   *\n   * @returns {boolean}\n   */\n  isChannelFollower() {\n    return this.type === WebhookType.ChannelFollower;\n  }\n\n  /**\n   * Whether or not this webhook is an incoming webhook.\n   *\n   * @returns {boolean}\n   */\n  isIncoming() {\n    return this.type === WebhookType.Incoming;\n  }\n\n  static applyToClass(structure, ignore = []) {\n    for (const prop of [\n      'send',\n      'sendSlackMessage',\n      'fetchMessage',\n      'edit',\n      'editMessage',\n      'delete',\n      'deleteMessage',\n      'createdTimestamp',\n      'createdAt',\n      'url',\n    ]) {\n      if (ignore.includes(prop)) continue;\n      Object.defineProperty(structure.prototype, prop, Object.getOwnPropertyDescriptor(Webhook.prototype, prop));\n    }\n  }\n}\n\nexports.Webhook = Webhook;\n"
  },
  {
    "path": "packages/discord.js/src/structures/WelcomeChannel.js",
    "content": "'use strict';\n\nconst { Base } = require('./Base.js');\nconst { Emoji } = require('./Emoji.js');\n\n/**\n * Represents a channel link in a guild's welcome screen.\n *\n * @extends {Base}\n */\nclass WelcomeChannel extends Base {\n  constructor(guild, data) {\n    super(guild.client);\n\n    /**\n     * The guild for this welcome channel\n     *\n     * @type {Guild|InviteGuild}\n     */\n    this.guild = guild;\n\n    /**\n     * The description of this welcome channel\n     *\n     * @type {string}\n     */\n    this.description = data.description;\n\n    /**\n     * The raw emoji data\n     *\n     * @type {Object}\n     * @private\n     */\n    this._emoji = {\n      name: data.emoji_name,\n      id: data.emoji_id,\n    };\n\n    /**\n     * The id of this welcome channel\n     *\n     * @type {Snowflake}\n     */\n    this.channelId = data.channel_id;\n  }\n\n  /**\n   * The channel of this welcome channel\n   *\n   * @type {?(TextChannel|AnnouncementChannel|ForumChannel|MediaChannel)}\n   */\n  get channel() {\n    return this.client.channels.resolve(this.channelId);\n  }\n\n  /**\n   * The emoji of this welcome channel\n   *\n   * @type {GuildEmoji|Emoji}\n   */\n  get emoji() {\n    return this.guild.emojis.cache.get(this._emoji.id) ?? new Emoji(this.client, this._emoji);\n  }\n}\n\nexports.WelcomeChannel = WelcomeChannel;\n"
  },
  {
    "path": "packages/discord.js/src/structures/WelcomeScreen.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { GuildFeature } = require('discord-api-types/v10');\nconst { Base } = require('./Base.js');\nconst { WelcomeChannel } = require('./WelcomeChannel.js');\n\n/**\n * Represents a welcome screen.\n *\n * @extends {Base}\n */\nclass WelcomeScreen extends Base {\n  constructor(guild, data) {\n    super(guild.client);\n\n    /**\n     * The guild for this welcome screen\n     *\n     * @type {Guild}\n     */\n    this.guild = guild;\n\n    /**\n     * The description of this welcome screen\n     *\n     * @type {?string}\n     */\n    this.description = data.description ?? null;\n\n    /**\n     * Collection of welcome channels belonging to this welcome screen\n     *\n     * @type {Collection<Snowflake, WelcomeChannel>}\n     */\n    this.welcomeChannels = new Collection();\n\n    for (const channel of data.welcome_channels) {\n      const welcomeChannel = new WelcomeChannel(this.guild, channel);\n      this.welcomeChannels.set(welcomeChannel.channelId, welcomeChannel);\n    }\n  }\n\n  /**\n   * Whether the welcome screen is enabled on the guild\n   *\n   * @type {boolean}\n   */\n  get enabled() {\n    return this.guild.features.includes(GuildFeature.WelcomeScreenEnabled);\n  }\n}\n\nexports.WelcomeScreen = WelcomeScreen;\n"
  },
  {
    "path": "packages/discord.js/src/structures/Widget.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { Routes } = require('discord-api-types/v10');\nconst { Base } = require('./Base.js');\nconst { WidgetMember } = require('./WidgetMember.js');\n\n/**\n * Represents a Widget.\n *\n * @extends {Base}\n */\nclass Widget extends Base {\n  constructor(client, data) {\n    super(client);\n    this._patch(data);\n  }\n\n  /**\n   * Represents a channel in a Widget\n   *\n   * @typedef {Object} WidgetChannel\n   * @property {Snowflake} id Id of the channel\n   * @property {string} name Name of the channel\n   * @property {number} position Position of the channel\n   */\n\n  _patch(data) {\n    /**\n     * The id of the guild.\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    if ('name' in data) {\n      /**\n       * The name of the guild.\n       *\n       * @type {string}\n       */\n      this.name = data.name;\n    }\n\n    if ('instant_invite' in data) {\n      /**\n       * The invite of the guild.\n       *\n       * @type {?string}\n       */\n      this.instantInvite = data.instant_invite;\n    }\n\n    /**\n     * The list of channels in the guild.\n     *\n     * @type {Collection<Snowflake, WidgetChannel>}\n     */\n    this.channels = new Collection();\n    for (const channel of data.channels) {\n      this.channels.set(channel.id, channel);\n    }\n\n    /**\n     * The list of members in the guild.\n     * These strings are just arbitrary numbers, they aren't Snowflakes.\n     *\n     * @type {Collection<string, WidgetMember>}\n     */\n    this.members = new Collection();\n    for (const member of data.members) {\n      this.members.set(member.id, new WidgetMember(this.client, member));\n    }\n\n    if ('presence_count' in data) {\n      /**\n       * The number of members online.\n       *\n       * @type {number}\n       */\n      this.presenceCount = data.presence_count;\n    }\n  }\n\n  /**\n   * Update the Widget.\n   *\n   * @returns {Promise<Widget>}\n   */\n  async fetch() {\n    const data = await this.client.rest.get(Routes.guildWidgetJSON(this.id));\n    this._patch(data);\n    return this;\n  }\n\n  /**\n   * Returns a URL for the PNG widget of the guild.\n   *\n   * @param {GuildWidgetStyle} [style] The style for the widget image\n   * @returns {string}\n   */\n  imageURL(style) {\n    return this.client.guilds.widgetImageURL(this.id, style);\n  }\n}\n\nexports.Widget = Widget;\n"
  },
  {
    "path": "packages/discord.js/src/structures/WidgetMember.js",
    "content": "'use strict';\n\nconst { Base } = require('./Base.js');\n\n/**\n * Represents a WidgetMember.\n *\n * @extends {Base}\n */\nclass WidgetMember extends Base {\n  /**\n   * Activity sent in a {@link WidgetMember}.\n   *\n   * @typedef {Object} WidgetActivity\n   * @property {string} name The name of the activity\n   */\n\n  constructor(client, data) {\n    super(client);\n\n    /**\n     * The id of the user. It's an arbitrary number.\n     *\n     * @type {string}\n     */\n    this.id = data.id;\n\n    /**\n     * The username of the member.\n     *\n     * @type {string}\n     */\n    this.username = data.username;\n\n    /**\n     * The discriminator of the member.\n     *\n     * @type {string}\n     */\n    this.discriminator = data.discriminator;\n\n    /**\n     * The avatar of the member.\n     *\n     * @type {?string}\n     */\n    this.avatar = data.avatar;\n\n    /**\n     * The status of the member.\n     *\n     * @type {PresenceStatus}\n     */\n    this.status = data.status;\n\n    /**\n     * If the member is server deafened\n     *\n     * @type {?boolean}\n     */\n    this.deaf = data.deaf ?? null;\n\n    /**\n     * If the member is server muted\n     *\n     * @type {?boolean}\n     */\n    this.mute = data.mute ?? null;\n\n    /**\n     * If the member is self deafened\n     *\n     * @type {?boolean}\n     */\n    this.selfDeaf = data.self_deaf ?? null;\n\n    /**\n     * If the member is self muted\n     *\n     * @type {?boolean}\n     */\n    this.selfMute = data.self_mute ?? null;\n\n    /**\n     * If the member is suppressed\n     *\n     * @type {?boolean}\n     */\n    this.suppress = data.suppress ?? null;\n\n    /**\n     * The id of the voice channel the member is in, if any\n     *\n     * @type {?Snowflake}\n     */\n    this.channelId = data.channel_id ?? null;\n\n    /**\n     * The avatar URL of the member.\n     *\n     * @type {string}\n     */\n    this.avatarURL = data.avatar_url;\n\n    /**\n     * The activity of the member.\n     *\n     * @type {?WidgetActivity}\n     */\n    this.activity = data.activity ?? null;\n  }\n}\n\nexports.WidgetMember = WidgetMember;\n"
  },
  {
    "path": "packages/discord.js/src/structures/interfaces/Application.js",
    "content": "'use strict';\n\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { Base } = require('../Base.js');\n\n/**\n * Represents an OAuth2 Application.\n *\n * @extends {Base}\n * @abstract\n */\nclass Application extends Base {\n  constructor(client, data) {\n    super(client);\n    this._patch(data);\n  }\n\n  _patch(data) {\n    /**\n     * The application's id\n     *\n     * @type {Snowflake}\n     */\n    this.id = data.id;\n\n    if ('name' in data) {\n      /**\n       * The name of the application\n       *\n       * @type {?string}\n       */\n      this.name = data.name;\n    } else {\n      this.name ??= null;\n    }\n\n    if ('description' in data) {\n      /**\n       * The application's description\n       *\n       * @type {?string}\n       */\n      this.description = data.description;\n    } else {\n      this.description ??= null;\n    }\n\n    if ('icon' in data) {\n      /**\n       * The application's icon hash\n       *\n       * @type {?string}\n       */\n      this.icon = data.icon;\n    } else {\n      this.icon ??= null;\n    }\n\n    if ('terms_of_service_url' in data) {\n      /**\n       * The URL of the application's terms of service\n       *\n       * @type {?string}\n       */\n      this.termsOfServiceURL = data.terms_of_service_url;\n    } else {\n      this.termsOfServiceURL ??= null;\n    }\n\n    if ('privacy_policy_url' in data) {\n      /**\n       * The URL of the application's privacy policy\n       *\n       * @type {?string}\n       */\n      this.privacyPolicyURL = data.privacy_policy_url;\n    } else {\n      this.privacyPolicyURL ??= null;\n    }\n\n    if ('rpc_origins' in data) {\n      /**\n       * The application's RPC origins, if enabled\n       *\n       * @type {string[]}\n       */\n      this.rpcOrigins = data.rpc_origins;\n    } else {\n      this.rpcOrigins ??= [];\n    }\n\n    if ('cover_image' in data) {\n      /**\n       * The hash of the application's cover image\n       *\n       * @type {?string}\n       */\n      this.cover = data.cover_image;\n    } else {\n      this.cover ??= null;\n    }\n\n    if ('verify_key' in data) {\n      /**\n       * The hex-encoded key for verification in interactions and the GameSDK's GetTicket\n       *\n       * @type {?string}\n       */\n      this.verifyKey = data.verify_key;\n    } else {\n      this.verifyKey ??= null;\n    }\n  }\n\n  /**\n   * The timestamp the application was created at\n   *\n   * @type {number}\n   * @readonly\n   */\n  get createdTimestamp() {\n    return DiscordSnowflake.timestampFrom(this.id);\n  }\n\n  /**\n   * The time the application was created at\n   *\n   * @type {Date}\n   * @readonly\n   */\n  get createdAt() {\n    return new Date(this.createdTimestamp);\n  }\n\n  /**\n   * A link to the application's icon.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  iconURL(options = {}) {\n    return this.icon && this.client.rest.cdn.appIcon(this.id, this.icon, options);\n  }\n\n  /**\n   * A link to this application's cover image.\n   *\n   * @param {ImageURLOptions} [options={}] Options for the image URL\n   * @returns {?string}\n   */\n  coverURL(options = {}) {\n    return this.cover && this.client.rest.cdn.appIcon(this.id, this.cover, options);\n  }\n\n  /**\n   * When concatenated with a string, this automatically returns the application's name instead of the\n   * Application object.\n   *\n   * @returns {?string}\n   * @example\n   * // Logs: Application name: My App\n   * console.log(`Application name: ${application}`);\n   */\n  toString() {\n    return this.name;\n  }\n\n  toJSON() {\n    return super.toJSON({ createdTimestamp: true });\n  }\n}\n\nexports.Application = Application;\n"
  },
  {
    "path": "packages/discord.js/src/structures/interfaces/Collector.js",
    "content": "'use strict';\n\nconst { setTimeout, clearTimeout } = require('node:timers');\nconst { Collection } = require('@discordjs/collection');\nconst { AsyncEventEmitter } = require('@vladfrangu/async_event_emitter');\nconst { DiscordjsTypeError, ErrorCodes } = require('../../errors/index.js');\nconst { flatten } = require('../../util/Util.js');\n\n/**\n * Filter to be applied to the collector.\n *\n * @typedef {Function} CollectorFilter\n * @param {...*} args Any arguments received by the listener\n * @param {Collection} collection The items collected by this collector\n * @returns {boolean|Promise<boolean>}\n */\n\n/**\n * Options to be applied to the collector.\n *\n * @typedef {Object} CollectorOptions\n * @property {CollectorFilter} [filter] The filter applied to this collector\n * @property {number} [time] How long to run the collector for in milliseconds\n * @property {number} [idle] How long to stop the collector after inactivity in milliseconds\n * @property {boolean} [dispose=false] Whether to dispose data when it's deleted\n */\n\n/**\n * Abstract class for defining a new Collector.\n *\n * @extends {AsyncEventEmitter}\n * @abstract\n */\nclass Collector extends AsyncEventEmitter {\n  constructor(client, options = {}) {\n    super();\n\n    /**\n     * The client that instantiated this Collector\n     *\n     * @name Collector#client\n     * @type {Client}\n     * @readonly\n     */\n    Object.defineProperty(this, 'client', { value: client });\n\n    /**\n     * The filter applied to this collector\n     *\n     * @type {CollectorFilter}\n     * @returns {boolean|Promise<boolean>}\n     */\n    this.filter = options.filter ?? (() => true);\n\n    /**\n     * The options of this collector\n     *\n     * @type {CollectorOptions}\n     */\n    this.options = options;\n\n    /**\n     * The items collected by this collector\n     *\n     * @type {Collection}\n     */\n    this.collected = new Collection();\n\n    /**\n     * Whether this collector has finished collecting\n     *\n     * @type {boolean}\n     */\n    this.ended = false;\n\n    /**\n     * Timeout for cleanup\n     *\n     * @type {?Timeout}\n     * @private\n     */\n    this._timeout = null;\n\n    /**\n     * Timeout for cleanup due to inactivity\n     *\n     * @type {?Timeout}\n     * @private\n     */\n    this._idletimeout = null;\n\n    /**\n     * The reason the collector ended\n     *\n     * @type {?string}\n     * @private\n     */\n    this._endReason = null;\n\n    if (typeof this.filter !== 'function') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options.filter', 'function');\n    }\n\n    this.handleCollect = this.handleCollect.bind(this);\n    this.handleDispose = this.handleDispose.bind(this);\n\n    if (options.time) this._timeout = setTimeout(() => this.stop('time'), options.time).unref();\n    if (options.idle) this._idletimeout = setTimeout(() => this.stop('idle'), options.idle).unref();\n\n    /**\n     * The timestamp at which this collector last collected an item\n     *\n     * @type {?number}\n     */\n    this.lastCollectedTimestamp = null;\n  }\n\n  /**\n   * The Date at which this collector last collected an item\n   *\n   * @type {?Date}\n   */\n  get lastCollectedAt() {\n    return this.lastCollectedTimestamp && new Date(this.lastCollectedTimestamp);\n  }\n\n  /**\n   * Call this to handle an event as a collectable element. Accepts any event data as parameters.\n   *\n   * @param {...*} args The arguments emitted by the listener\n   * @returns {Promise<void>}\n   * @emits Collector#collect\n   */\n  async handleCollect(...args) {\n    const collectedId = await this.collect(...args);\n\n    if (collectedId) {\n      const filterResult = await this.filter(...args, this.collected);\n      if (filterResult) {\n        this.collected.set(collectedId, args[0]);\n\n        /**\n         * Emitted whenever an element is collected.\n         *\n         * @event Collector#collect\n         * @param {...*} args The arguments emitted by the listener\n         */\n        this.emit('collect', ...args);\n\n        this.lastCollectedTimestamp = Date.now();\n        if (this._idletimeout) {\n          clearTimeout(this._idletimeout);\n          this._idletimeout = setTimeout(() => this.stop('idle'), this.options.idle).unref();\n        }\n      } else {\n        /**\n         * Emitted whenever an element is not collected by the collector.\n         *\n         * @event Collector#ignore\n         * @param {...*} args The arguments emitted by the listener\n         */\n        this.emit('ignore', ...args);\n      }\n    }\n\n    this.checkEnd();\n  }\n\n  /**\n   * Call this to remove an element from the collection. Accepts any event data as parameters.\n   *\n   * @param {...*} args The arguments emitted by the listener\n   * @returns {Promise<void>}\n   * @emits Collector#dispose\n   */\n  async handleDispose(...args) {\n    if (!this.options.dispose) return;\n\n    const dispose = this.dispose(...args);\n    if (!dispose || !(await this.filter(...args)) || !this.collected.has(dispose)) return;\n    this.collected.delete(dispose);\n\n    /**\n     * Emitted whenever an element is disposed of.\n     *\n     * @event Collector#dispose\n     * @param {...*} args The arguments emitted by the listener\n     */\n    this.emit('dispose', ...args);\n    this.checkEnd();\n  }\n\n  /**\n   * Returns a promise that resolves with the next collected element;\n   * rejects with collected elements if the collector finishes without receiving a next element\n   *\n   * @type {Promise}\n   * @readonly\n   */\n  get next() {\n    return new Promise((resolve, reject) => {\n      if (this.ended) {\n        reject(this.collected);\n        return;\n      }\n\n      const cleanup = () => {\n        // eslint-disable-next-line no-use-before-define\n        this.removeListener('collect', onCollect);\n        // eslint-disable-next-line no-use-before-define\n        this.removeListener('end', onEnd);\n      };\n\n      const onCollect = item => {\n        cleanup();\n        resolve(item);\n      };\n\n      const onEnd = () => {\n        cleanup();\n        reject(this.collected);\n      };\n\n      this.on('collect', onCollect);\n      this.on('end', onEnd);\n    });\n  }\n\n  /**\n   * Stops this collector and emits the `end` event.\n   *\n   * @param {string} [reason='user'] The reason this collector is ending\n   * @emits Collector#end\n   */\n  stop(reason = 'user') {\n    if (this.ended) return;\n\n    if (this._timeout) {\n      clearTimeout(this._timeout);\n      this._timeout = null;\n    }\n\n    if (this._idletimeout) {\n      clearTimeout(this._idletimeout);\n      this._idletimeout = null;\n    }\n\n    this._endReason = reason;\n    this.ended = true;\n\n    /**\n     * Emitted when the collector is finished collecting.\n     *\n     * @event Collector#end\n     * @param {Collection} collected The elements collected by the collector\n     * @param {string} reason The reason the collector ended\n     */\n    this.emit('end', this.collected, reason);\n  }\n\n  /**\n   * Options used to reset the timeout and idle timer of a {@link Collector}.\n   *\n   * @typedef {Object} CollectorResetTimerOptions\n   * @property {number} [time] How long to run the collector for (in milliseconds)\n   * @property {number} [idle] How long to wait to stop the collector after inactivity (in milliseconds)\n   */\n\n  /**\n   * Resets the collector's timeout and idle timer.\n   *\n   * @param {CollectorResetTimerOptions} [options] Options for resetting\n   */\n  resetTimer({ time, idle } = {}) {\n    if (this._timeout) {\n      clearTimeout(this._timeout);\n      this._timeout = setTimeout(() => this.stop('time'), time ?? this.options.time).unref();\n    }\n\n    if (this._idletimeout) {\n      clearTimeout(this._idletimeout);\n      this._idletimeout = setTimeout(() => this.stop('idle'), idle ?? this.options.idle).unref();\n    }\n  }\n\n  /**\n   * Checks whether the collector should end, and if so, ends it.\n   *\n   * @returns {boolean} Whether the collector ended or not\n   */\n  checkEnd() {\n    const reason = this.endReason;\n    if (reason) this.stop(reason);\n    return Boolean(reason);\n  }\n\n  /**\n   * Allows collectors to be consumed with for-await-of loops\n   *\n   * @see {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/for-await...of}\n   */\n  async *[Symbol.asyncIterator]() {\n    const queue = [];\n    const onCollect = (...item) => queue.push(item);\n    this.on('collect', onCollect);\n\n    try {\n      while (queue.length || !this.ended) {\n        if (queue.length) {\n          yield queue.shift();\n        } else {\n          await new Promise(resolve => {\n            const tick = () => {\n              this.removeListener('collect', tick);\n              this.removeListener('end', tick);\n              resolve();\n            };\n\n            this.on('collect', tick);\n            this.on('end', tick);\n          });\n        }\n      }\n    } finally {\n      this.removeListener('collect', onCollect);\n    }\n  }\n\n  toJSON() {\n    return flatten(this);\n  }\n\n  /**\n   * The reason this collector has ended with, or null if it hasn't ended yet\n   *\n   * @type {?string}\n   * @readonly\n   */\n  get endReason() {\n    return this._endReason;\n  }\n\n  /**\n   * Handles incoming events from the `handleCollect` function. Returns null if the event should not\n   * be collected, or returns an object describing the data that should be stored.\n   *\n   * @see Collector#handleCollect\n   * @param {...*} args Any args the event listener emits\n   * @returns {?(*|Promise<?*>)} Data to insert into collection, if any\n   * @abstract\n   */\n  // eslint-disable-next-line no-unused-vars\n  collect(...args) {}\n\n  /**\n   * Handles incoming events from the `handleDispose`. Returns null if the event should not\n   * be disposed, or returns the key that should be removed.\n   *\n   * @see Collector#handleDispose\n   * @param {...*} args Any args the event listener emits\n   * @returns {?*} Key to remove from the collection, if any\n   * @abstract\n   */\n  // eslint-disable-next-line no-unused-vars\n  dispose(...args) {}\n}\n\nexports.Collector = Collector;\n"
  },
  {
    "path": "packages/discord.js/src/structures/interfaces/InteractionResponses.js",
    "content": "'use strict';\n\nconst { makeURLSearchParams } = require('@discordjs/rest');\nconst { isJSONEncodable } = require('@discordjs/util');\nconst { InteractionResponseType, MessageFlags, Routes, InteractionType } = require('discord-api-types/v10');\nconst { DiscordjsError, ErrorCodes } = require('../../errors/index.js');\nconst { MessageFlagsBitField } = require('../../util/MessageFlagsBitField.js');\nconst { InteractionCallbackResponse } = require('../InteractionCallbackResponse.js');\nconst { InteractionCollector } = require('../InteractionCollector.js');\nconst { MessagePayload } = require('../MessagePayload.js');\n\n/**\n * Interface for classes that support shared interaction response types.\n *\n * @interface\n */\nclass InteractionResponses {\n  /**\n   * Options for deferring the reply to an {@link BaseInteraction}.\n   *\n   * @typedef {Object} InteractionDeferReplyOptions\n   * @property {boolean} [withResponse] Whether to return an {@link InteractionCallbackResponse} as the response\n   * @property {MessageFlagsResolvable} [flags] Flags for the reply.\n   * <info>Only `MessageFlags.Ephemeral` can be set.</info>\n   */\n\n  /**\n   * Options for deferring and updating the reply to a {@link MessageComponentInteraction}.\n   *\n   * @typedef {Object} InteractionDeferUpdateOptions\n   * @property {boolean} [withResponse] Whether to return an {@link InteractionCallbackResponse} as the response\n   */\n\n  /**\n   * Options for a reply to a {@link BaseInteraction}.\n   *\n   * @typedef {BaseMessageOptionsWithPoll} InteractionReplyOptions\n   * @property {boolean} [tts=false] Whether the message should be spoken aloud\n   * @property {boolean} [withResponse] Whether to return an {@link InteractionCallbackResponse} as the response\n   * @property {MessageFlagsResolvable} [flags] Which flags to set for the message.\n   * <info>Only {@link MessageFlags.Ephemeral}, {@link MessageFlags.SuppressEmbeds},\n   * {@link MessageFlags.SuppressNotifications}, and {@link MessageFlags.IsVoiceMessage} can be set.</info>\n   */\n\n  /**\n   * Options for updating the message received from a {@link MessageComponentInteraction}.\n   *\n   * @typedef {MessageEditOptions} InteractionUpdateOptions\n   * @property {boolean} [withResponse] Whether to return an {@link InteractionCallbackResponse} as the response\n   */\n\n  /**\n   * Options for launching activity in response to a {@link BaseInteraction}\n   *\n   * @typedef {Object} LaunchActivityOptions\n   * @property {boolean} [withResponse] Whether to return an {@link InteractionCallbackResponse} as the response\n   */\n\n  /**\n   * Options for showing a modal in response to a {@link BaseInteraction}\n   *\n   * @typedef {Object} ShowModalOptions\n   * @property {boolean} [withResponse] Whether to return an {@link InteractionCallbackResponse} as the response\n   */\n\n  /**\n   * Defers the reply to this interaction.\n   *\n   * @param {InteractionDeferReplyOptions} [options] Options for deferring the reply to this interaction\n   * @returns {Promise<InteractionCallbackResponse|undefined>}\n   * @example\n   * // Defer the reply to this interaction\n   * interaction.deferReply()\n   *   .then(console.log)\n   *   .catch(console.error)\n   * @example\n   * // Defer to send an ephemeral reply later\n   * interaction.deferReply({ flags: MessageFlags.Ephemeral })\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async deferReply(options = {}) {\n    if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);\n\n    const resolvedFlags = new MessageFlagsBitField(options.flags);\n\n    const response = await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {\n      body: {\n        type: InteractionResponseType.DeferredChannelMessageWithSource,\n        data: {\n          flags: resolvedFlags.bitfield,\n        },\n      },\n      auth: false,\n      query: makeURLSearchParams({ with_response: options.withResponse ?? false }),\n    });\n\n    this.deferred = true;\n    this.ephemeral = resolvedFlags.has(MessageFlags.Ephemeral);\n\n    return options.withResponse ? new InteractionCallbackResponse(this.client, response) : undefined;\n  }\n\n  /**\n   * Creates a reply to this interaction.\n   * <info>Use the `withResponse` option to get the interaction callback response.</info>\n   *\n   * @param {string|MessagePayload|InteractionReplyOptions} options The options for the reply\n   * @returns {Promise<InteractionCallbackResponse|undefined>}\n   * @example\n   * // Reply to the interaction and fetch the response\n   * interaction.reply({ content: 'Pong!', withResponse: true })\n   *   .then((response) => console.log(`Reply sent with content ${response.resource.message.content}`))\n   *   .catch(console.error);\n   * @example\n   * // Create an ephemeral reply with an embed\n   * const embed = new EmbedBuilder().setDescription('Pong!');\n   *\n   * interaction.reply({ embeds: [embed], flags: MessageFlags.Ephemeral })\n   *   .then(() => console.log('Reply sent.'))\n   *   .catch(console.error);\n   */\n  async reply(options) {\n    if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);\n\n    let messagePayload;\n    if (options instanceof MessagePayload) messagePayload = options;\n    else messagePayload = MessagePayload.create(this, options);\n\n    const { body: data, files } = await messagePayload.resolveBody().resolveFiles();\n\n    const response = await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {\n      body: {\n        type: InteractionResponseType.ChannelMessageWithSource,\n        data,\n      },\n      files,\n      auth: false,\n      query: makeURLSearchParams({ with_response: options.withResponse ?? false }),\n    });\n\n    this.ephemeral = Boolean(data.flags & MessageFlags.Ephemeral);\n    this.replied = true;\n\n    return options.withResponse ? new InteractionCallbackResponse(this.client, response) : undefined;\n  }\n\n  /**\n   * Fetches a reply to this interaction.\n   *\n   * @see Webhook#fetchMessage\n   * @param {Snowflake|'@original'} [message='@original'] The response to fetch\n   * @returns {Promise<Message>}\n   * @example\n   * // Fetch the initial reply to this interaction\n   * interaction.fetchReply()\n   *   .then(reply => console.log(`Replied with ${reply.content}`))\n   *   .catch(console.error);\n   */\n  async fetchReply(message = '@original') {\n    return this.webhook.fetchMessage(message);\n  }\n\n  /**\n   * Options that can be passed into {@link InteractionResponses#editReply}.\n   *\n   * @typedef {WebhookMessageEditOptions} InteractionEditReplyOptions\n   * @property {MessageResolvable|'@original'} [message='@original'] The response to edit\n   */\n\n  /**\n   * Edits a reply to this interaction.\n   *\n   * @see Webhook#editMessage\n   * @param {string|MessagePayload|InteractionEditReplyOptions} options The new options for the message\n   * @returns {Promise<Message>}\n   * @example\n   * // Edit the initial reply to this interaction\n   * interaction.editReply('New content')\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async editReply(options) {\n    if (!this.deferred && !this.replied) throw new DiscordjsError(ErrorCodes.InteractionNotReplied);\n    const msg = await this.webhook.editMessage(options.message ?? '@original', options);\n    this.replied = true;\n    return msg;\n  }\n\n  /**\n   * Deletes a reply to this interaction.\n   *\n   * @see Webhook#deleteMessage\n   * @param {MessageResolvable|'@original'} [message='@original'] The response to delete\n   * @returns {Promise<void>}\n   * @example\n   * // Delete the initial reply to this interaction\n   * interaction.deleteReply()\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async deleteReply(message = '@original') {\n    if (!this.deferred && !this.replied) throw new DiscordjsError(ErrorCodes.InteractionNotReplied);\n\n    await this.webhook.deleteMessage(message);\n  }\n\n  /**\n   * Send a follow-up message to this interaction.\n   *\n   * @param {string|MessagePayload|InteractionReplyOptions} options The options for the reply\n   * @returns {Promise<Message>}\n   */\n  async followUp(options) {\n    if (!this.deferred && !this.replied) throw new DiscordjsError(ErrorCodes.InteractionNotReplied);\n    const msg = await this.webhook.send(options);\n    this.replied = true;\n    return msg;\n  }\n\n  /**\n   * Defers an update to the message to which the component was attached.\n   *\n   * @param {InteractionDeferUpdateOptions} [options] Options for deferring the update to this interaction\n   * @returns {Promise<InteractionCallbackResponse|undefined>}\n   * @example\n   * // Defer updating and reset the component's loading state\n   * interaction.deferUpdate()\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async deferUpdate(options = {}) {\n    if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);\n    const response = await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {\n      body: {\n        type: InteractionResponseType.DeferredMessageUpdate,\n      },\n      auth: false,\n      query: makeURLSearchParams({ with_response: options.withResponse ?? false }),\n    });\n    this.deferred = true;\n\n    return options.withResponse ? new InteractionCallbackResponse(this.client, response) : undefined;\n  }\n\n  /**\n   * Updates the original message of the component on which the interaction was received on.\n   *\n   * @param {string|MessagePayload|InteractionUpdateOptions} [options] The options for the updated message\n   * @returns {Promise<InteractionCallbackResponse|undefined>}\n   * @example\n   * // Remove the components from the message\n   * interaction.update({\n   *   content: \"A component interaction was received\",\n   *   components: []\n   * })\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async update(options = {}) {\n    if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);\n\n    let messagePayload;\n    if (options instanceof MessagePayload) messagePayload = options;\n    else messagePayload = MessagePayload.create(this, options);\n\n    const { body: data, files } = await messagePayload.resolveBody().resolveFiles();\n\n    const response = await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {\n      body: {\n        type: InteractionResponseType.UpdateMessage,\n        data,\n      },\n      files,\n      auth: false,\n      query: makeURLSearchParams({ with_response: options.withResponse ?? false }),\n    });\n    this.replied = true;\n\n    return options.withResponse ? new InteractionCallbackResponse(this.client, response) : undefined;\n  }\n\n  /**\n   * Launches this application's activity, if enabled\n   *\n   * @param {LaunchActivityOptions} [options={}] Options for launching the activity\n   * @returns {Promise<InteractionCallbackResponse|undefined>}\n   */\n  async launchActivity({ withResponse } = {}) {\n    if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);\n    const response = await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {\n      query: makeURLSearchParams({ with_response: withResponse ?? false }),\n      body: {\n        type: InteractionResponseType.LaunchActivity,\n      },\n      auth: false,\n    });\n    this.replied = true;\n\n    return withResponse ? new InteractionCallbackResponse(this.client, response) : undefined;\n  }\n\n  /**\n   * Shows a modal component\n   *\n   * @param {ModalBuilder|ModalComponentData|APIModalInteractionResponseCallbackData} modal The modal to show\n   * @param {ShowModalOptions} [options={}] The options for sending this interaction response\n   * @returns {Promise<InteractionCallbackResponse|undefined>}\n   */\n  async showModal(modal, options = {}) {\n    if (this.deferred || this.replied) throw new DiscordjsError(ErrorCodes.InteractionAlreadyReplied);\n    const response = await this.client.rest.post(Routes.interactionCallback(this.id, this.token), {\n      body: {\n        type: InteractionResponseType.Modal,\n        data: isJSONEncodable(modal) ? modal.toJSON() : this.client.options.jsonTransformer(modal),\n      },\n      auth: false,\n      query: makeURLSearchParams({ with_response: options.withResponse ?? false }),\n    });\n    this.replied = true;\n\n    return options.withResponse ? new InteractionCallbackResponse(this.client, response) : undefined;\n  }\n\n  /**\n   * An object containing the same properties as {@link CollectorOptions}, but a few less:\n   *\n   * @typedef {Object} AwaitModalSubmitOptions\n   * @property {CollectorFilter} [filter] The filter applied to this collector\n   * @property {number} time Time in milliseconds to wait for an interaction before rejecting\n   */\n\n  /**\n   * Collects a single modal submit interaction that passes the filter.\n   * The Promise will reject if the time expires.\n   *\n   * @param {AwaitModalSubmitOptions} options Options to pass to the internal collector\n   * @returns {Promise<ModalSubmitInteraction>}\n   * @example\n   * // Collect a modal submit interaction\n   * const filter = (interaction) => interaction.customId === 'modal';\n   * interaction.awaitModalSubmit({ filter, time: 15_000 })\n   *   .then(interaction => console.log(`${interaction.customId} was submitted!`))\n   *   .catch(console.error);\n   */\n  async awaitModalSubmit(options) {\n    if (typeof options.time !== 'number') throw new DiscordjsError(ErrorCodes.InvalidType, 'time', 'number');\n    const _options = { ...options, max: 1, interactionType: InteractionType.ModalSubmit };\n    return new Promise((resolve, reject) => {\n      const collector = new InteractionCollector(this.client, _options);\n      collector.once('end', (interactions, reason) => {\n        const interaction = interactions.first();\n        if (interaction) resolve(interaction);\n        else reject(new DiscordjsError(ErrorCodes.InteractionCollectorError, reason));\n      });\n    });\n  }\n\n  static applyToClass(structure, ignore = []) {\n    const props = [\n      'deferReply',\n      'reply',\n      'fetchReply',\n      'editReply',\n      'deleteReply',\n      'followUp',\n      'deferUpdate',\n      'update',\n      'launchActivity',\n      'showModal',\n      'awaitModalSubmit',\n    ];\n\n    for (const prop of props) {\n      if (ignore.includes(prop)) continue;\n      Object.defineProperty(\n        structure.prototype,\n        prop,\n        Object.getOwnPropertyDescriptor(InteractionResponses.prototype, prop),\n      );\n    }\n  }\n}\n\nexports.InteractionResponses = InteractionResponses;\n"
  },
  {
    "path": "packages/discord.js/src/structures/interfaces/TextBasedChannel.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { lazy } = require('@discordjs/util');\nconst { DiscordSnowflake } = require('@sapphire/snowflake');\nconst { InteractionType, Routes } = require('discord-api-types/v10');\nconst { DiscordjsTypeError, DiscordjsError, ErrorCodes } = require('../../errors/index.js');\nconst { MaxBulkDeletableMessageAge } = require('../../util/Constants.js');\nconst { InteractionCollector } = require('../InteractionCollector.js');\nconst { MessageCollector } = require('../MessageCollector.js');\n\n// Fixes circular dependencies.\nconst getGuildMessageManager = lazy(() => require('../../managers/GuildMessageManager.js').GuildMessageManager);\n\n/**\n * Interface for classes that have text-channel-like features.\n *\n * @interface\n */\nclass TextBasedChannel {\n  constructor() {\n    /**\n     * A manager of the messages sent to this channel\n     *\n     * @type {GuildMessageManager}\n     */\n    this.messages = new (getGuildMessageManager())(this);\n\n    /**\n     * The channel's last message id, if one was sent\n     *\n     * @type {?Snowflake}\n     */\n    this.lastMessageId = null;\n\n    /**\n     * The timestamp when the last pinned message was pinned, if there was one\n     *\n     * @type {?number}\n     */\n    this.lastPinTimestamp = null;\n  }\n\n  /**\n   * The Message object of the last message in the channel, if one was sent\n   *\n   * @type {?Message}\n   * @readonly\n   */\n  get lastMessage() {\n    return this.messages.resolve(this.lastMessageId);\n  }\n\n  /**\n   * The date when the last pinned message was pinned, if there was one\n   *\n   * @type {?Date}\n   * @readonly\n   */\n  get lastPinAt() {\n    return this.lastPinTimestamp && new Date(this.lastPinTimestamp);\n  }\n\n  /**\n   * Represents the data for a poll answer.\n   *\n   * @typedef {Object} PollAnswerData\n   * @property {string} text The text for the poll answer\n   * @property {EmojiIdentifierResolvable} [emoji] The emoji for the poll answer\n   */\n\n  /**\n   * Represents the data for a poll.\n   *\n   * @typedef {Object} PollData\n   * @property {PollQuestionMedia} question The question for the poll\n   * @property {PollAnswerData[]} answers The answers for the poll\n   * @property {number} duration The duration in hours for the poll\n   * @property {boolean} allowMultiselect Whether the poll allows multiple answers\n   * @property {PollLayoutType} [layoutType] The layout type for the poll\n   */\n\n  /**\n   * The base message options for messages.\n   *\n   * @typedef {Object} BaseMessageOptions\n   * @property {?string} [content=''] The content for the message. This can only be `null` when editing a message.\n   * @property {Array<(EmbedBuilder|Embed|APIEmbed)>} [embeds] The embeds for the message\n   * @property {MessageMentionOptions} [allowedMentions] Which mentions should be parsed from the message content\n   * (see {@link https://discord.com/developers/docs/resources/message#allowed-mentions-object here} for more details)\n   * @property {Array<(Attachment|AttachmentPayload|BufferResolvable|FileBodyEncodable<APIAttachment>|Stream)>} [files]\n   * The files to send with the message.\n   * @property {Array<(ActionRowBuilder|MessageTopLevelComponent|APIMessageTopLevelComponent)>} [components]\n   * Action rows containing interactive components for the message (buttons, select menus) and other\n   * top-level components.\n   * <info>When using components v2, the flag {@link MessageFlags.IsComponentsV2} needs to be set\n   * and `content`, `embeds`, `stickers`, and `poll` cannot be used.</info>\n   */\n\n  /**\n   * The base message options for messages including a poll.\n   *\n   * @typedef {BaseMessageOptions} BaseMessageOptionsWithPoll\n   * @property {PollData} [poll] The poll to send with the message\n   */\n\n  /**\n   * The options for sending a message.\n   *\n   * @typedef {BaseMessageOptionsWithPoll} BaseMessageCreateOptions\n   * @property {boolean} [tts=false] Whether the message should be spoken aloud\n   * @property {string} [nonce] The nonce for the message\n   * <info>This property is required if `enforceNonce` set to `true`.</info>\n   * @property {boolean} [enforceNonce] Whether the nonce should be checked for uniqueness in the past few minutes.\n   * If another message was created by the same author with the same nonce,\n   * that message will be returned and no new message will be created\n   * @property {StickerResolvable[]} [stickers=[]] The stickers to send in the message\n   * @property {MessageFlags} [flags] Which flags to set for the message.\n   * <info>Only {@link MessageFlags.SuppressEmbeds}, {@link MessageFlags.SuppressNotifications},\n   * {@link MessageFlags.IsComponentsV2}, and {@link MessageFlags.IsVoiceMessage} can be set.</info>\n   * <info>{@link MessageFlags.IsComponentsV2} is required if passing components that aren't action rows</info>\n   */\n\n  /**\n   * @typedef {MessageReference} MessageReferenceOptions\n   * @property {boolean} [failIfNotExists=this.client.options.failIfNotExists] Whether to error if the\n   * referenced message doesn't exist instead of sending as a normal (non-reply) message\n   */\n\n  /**\n   * The options for sending a message.\n   *\n   * @typedef {BaseMessageCreateOptions} MessageCreateOptions\n   * @property {MessageReferenceOptions} [messageReference] The options for a reference to a message\n   */\n\n  /**\n   * Options provided to control parsing of mentions by Discord\n   *\n   * @typedef {Object} MessageMentionOptions\n   * @property {MessageMentionTypes[]} [parse] Types of mentions to be parsed\n   * @property {Snowflake[]} [users] Snowflakes of Users to be parsed as mentions\n   * @property {Snowflake[]} [roles] Snowflakes of Roles to be parsed as mentions\n   * @property {boolean} [repliedUser=true] Whether the author of the Message being replied to should be pinged\n   */\n\n  /**\n   * Types of mentions to enable in MessageMentionOptions.\n   * - `roles`\n   * - `users`\n   * - `everyone`\n   *\n   * @typedef {string} MessageMentionTypes\n   */\n\n  /**\n   * Sends a message to this channel.\n   *\n   * @param {string|MessagePayload|MessageCreateOptions|JSONEncodable<RESTPostAPIChannelMessageJSONBody>|FileBodyEncodable<RESTPostAPIChannelMessageJSONBody>} options The options to provide\n   * @returns {Promise<Message>}\n   * @example\n   * // Send a basic message\n   * channel.send('hello!')\n   *   .then(message => console.log(`Sent message: ${message.content}`))\n   *   .catch(console.error);\n   * @example\n   * // Send a remote file\n   * channel.send({\n   *   files: ['https://github.com/discordjs.png']\n   * })\n   *   .then(console.log)\n   *   .catch(console.error);\n   * @example\n   * // Send a local file\n   * channel.send({\n   *   files: [{\n   *     attachment: 'entire/path/to/file.jpg',\n   *     name: 'file.jpg',\n   *     description: 'A description of the file'\n   *   }]\n   * })\n   *   .then(console.log)\n   *   .catch(console.error);\n   */\n  async send(options) {\n    return this.client.channels.createMessage(this, options);\n  }\n\n  /**\n   * Sends a typing indicator in the channel.\n   *\n   * @returns {Promise<void>} Resolves upon the typing status being sent\n   * @example\n   * // Start typing in a channel\n   * channel.sendTyping();\n   */\n  async sendTyping() {\n    await this.client.rest.post(Routes.channelTyping(this.id));\n  }\n\n  /**\n   * Creates a Message Collector.\n   *\n   * @param {MessageCollectorOptions} [options={}] The options to pass to the collector\n   * @returns {MessageCollector}\n   * @example\n   * // Create a message collector\n   * const filter = message => message.content.includes('discord');\n   * const collector = channel.createMessageCollector({ filter, time: 15_000 });\n   * collector.on('collect', message => console.log(`Collected ${message.content}`));\n   * collector.on('end', collected => console.log(`Collected ${collected.size} items`));\n   */\n  createMessageCollector(options = {}) {\n    return new MessageCollector(this, options);\n  }\n\n  /**\n   * An object containing the same properties as CollectorOptions, but a few more:\n   *\n   * @typedef {MessageCollectorOptions} AwaitMessagesOptions\n   * @property {string[]} [errors] Stop/end reasons that cause the promise to reject\n   */\n\n  /**\n   * Similar to createMessageCollector but in promise form.\n   * Resolves with a collection of messages that pass the specified filter.\n   *\n   * @param {AwaitMessagesOptions} [options={}] Optional options to pass to the internal collector\n   * @returns {Promise<Collection<Snowflake, Message>>}\n   * @example\n   * // Await !vote messages\n   * const filter = m => m.content.startsWith('!vote');\n   * // Errors: ['time'] treats ending because of the time limit as an error\n   * channel.awaitMessages({ filter, max: 4, time: 60_000, errors: ['time'] })\n   *   .then(collected => console.log(collected.size))\n   *   .catch(collected => console.log(`After a minute, only ${collected.size} out of 4 voted.`));\n   */\n  async awaitMessages(options = {}) {\n    return new Promise((resolve, reject) => {\n      const collector = this.createMessageCollector(options);\n      collector.once('end', (collection, reason) => {\n        if (options.errors?.includes(reason)) {\n          reject(collection);\n        } else {\n          resolve(collection);\n        }\n      });\n    });\n  }\n\n  /**\n   * Creates a component interaction collector.\n   *\n   * @param {MessageComponentCollectorOptions} [options={}] Options to send to the collector\n   * @returns {InteractionCollector}\n   * @example\n   * // Create a button interaction collector\n   * const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId';\n   * const collector = channel.createMessageComponentCollector({ filter, time: 15_000 });\n   * collector.on('collect', interaction => console.log(`Collected ${interaction.customId}`));\n   * collector.on('end', collected => console.log(`Collected ${collected.size} items`));\n   */\n  createMessageComponentCollector(options = {}) {\n    return new InteractionCollector(this.client, {\n      ...options,\n      interactionType: InteractionType.MessageComponent,\n      channel: this,\n    });\n  }\n\n  /**\n   * Collects a single component interaction that passes the filter.\n   * The Promise will reject if the time expires.\n   *\n   * @param {AwaitMessageComponentOptions} [options={}] Options to pass to the internal collector\n   * @returns {Promise<MessageComponentInteraction>}\n   * @example\n   * // Collect a message component interaction\n   * const filter = (interaction) => interaction.customId === 'button' && interaction.user.id === 'someId';\n   * channel.awaitMessageComponent({ filter, time: 15_000 })\n   *   .then(interaction => console.log(`${interaction.customId} was clicked!`))\n   *   .catch(console.error);\n   */\n  async awaitMessageComponent(options = {}) {\n    const _options = { ...options, max: 1 };\n    return new Promise((resolve, reject) => {\n      const collector = this.createMessageComponentCollector(_options);\n      collector.once('end', (interactions, reason) => {\n        const interaction = interactions.first();\n        if (interaction) resolve(interaction);\n        else reject(new DiscordjsError(ErrorCodes.InteractionCollectorError, reason));\n      });\n    });\n  }\n\n  /**\n   * Bulk deletes given messages up to 2 weeks old.\n   *\n   * @param {Collection<Snowflake, Message>|MessageResolvable[]|number} messages\n   * Messages or number of messages to delete\n   * @param {boolean} [filterOld=false] Filter messages to remove those which are older than two weeks automatically\n   * @returns {Promise<Snowflake[]>} Returns the deleted messages ids\n   * @example\n   * // Bulk delete messages\n   * channel.bulkDelete(5)\n   *   .then(messages => console.log(`Bulk deleted ${messages.length} messages`))\n   *   .catch(console.error);\n   */\n  async bulkDelete(messages, filterOld = false) {\n    if (Array.isArray(messages) || messages instanceof Collection) {\n      let messageIds =\n        messages instanceof Collection ? [...messages.keys()] : messages.map(message => message.id ?? message);\n\n      if (filterOld) {\n        messageIds = messageIds.filter(\n          id => Date.now() - DiscordSnowflake.timestampFrom(id) < MaxBulkDeletableMessageAge,\n        );\n      }\n\n      if (messageIds.length === 0) return [];\n\n      if (messageIds.length === 1) {\n        await this.client.rest.delete(Routes.channelMessage(this.id, messageIds[0]));\n        return messageIds;\n      }\n\n      await this.client.rest.post(Routes.channelBulkDelete(this.id), { body: { messages: messageIds } });\n      return messageIds;\n    }\n\n    if (!Number.isNaN(messages)) {\n      const msgs = await this.messages.fetch({ limit: messages });\n      return this.bulkDelete(msgs, filterOld);\n    }\n\n    throw new DiscordjsTypeError(ErrorCodes.MessageBulkDeleteType);\n  }\n\n  /**\n   * Fetches all webhooks for the channel.\n   *\n   * @returns {Promise<Collection<Snowflake, Webhook>>}\n   * @example\n   * // Fetch webhooks\n   * channel.fetchWebhooks()\n   *   .then(hooks => console.log(`This channel has ${hooks.size} hooks`))\n   *   .catch(console.error);\n   */\n  async fetchWebhooks() {\n    return this.guild.channels.fetchWebhooks(this.id);\n  }\n\n  /**\n   * Options used to create a {@link Webhook}.\n   *\n   * @typedef {Object} ChannelWebhookCreateOptions\n   * @property {string} name The name of the webhook\n   * @property {?(BufferResolvable|Base64Resolvable)} [avatar] Avatar for the webhook\n   * @property {string} [reason] Reason for creating the webhook\n   */\n\n  /**\n   * Creates a webhook for the channel.\n   *\n   * @param {ChannelWebhookCreateOptions} [options] Options for creating the webhook\n   * @returns {Promise<Webhook>} Returns the created Webhook\n   * @example\n   * // Create a webhook for the current channel\n   * channel.createWebhook({\n   *   name: 'Snek',\n   *   avatar: 'https://i.imgur.com/mI8XcpG.jpg',\n   *   reason: 'Needed a cool new Webhook'\n   * })\n   *   .then(console.log)\n   *   .catch(console.error)\n   */\n  async createWebhook(options) {\n    return this.guild.channels.createWebhook({ channel: this.id, ...options });\n  }\n\n  /**\n   * Sets the rate limit per user (slowmode) for this channel.\n   *\n   * @param {number} rateLimitPerUser The new rate limit in seconds\n   * @param {string} [reason] Reason for changing the channel's rate limit\n   * @returns {Promise<this>}\n   */\n  async setRateLimitPerUser(rateLimitPerUser, reason) {\n    return this.edit({ rateLimitPerUser, reason });\n  }\n\n  /**\n   * Sets whether this channel is flagged as NSFW.\n   *\n   * @param {boolean} [nsfw=true] Whether the channel should be considered NSFW\n   * @param {string} [reason] Reason for changing the channel's NSFW flag\n   * @returns {Promise<this>}\n   */\n  async setNSFW(nsfw = true, reason = undefined) {\n    return this.edit({ nsfw, reason });\n  }\n\n  static applyToClass(structure, ignore = []) {\n    const props = [\n      'lastMessage',\n      'lastPinAt',\n      'bulkDelete',\n      'sendTyping',\n      'createMessageCollector',\n      'awaitMessages',\n      'createMessageComponentCollector',\n      'awaitMessageComponent',\n      'fetchWebhooks',\n      'createWebhook',\n      'setRateLimitPerUser',\n      'setNSFW',\n      'send',\n    ];\n\n    for (const prop of props) {\n      if (ignore.includes(prop)) continue;\n      Object.defineProperty(\n        structure.prototype,\n        prop,\n        Object.getOwnPropertyDescriptor(TextBasedChannel.prototype, prop),\n      );\n    }\n  }\n}\n\nexports.TextBasedChannel = TextBasedChannel;\n"
  },
  {
    "path": "packages/discord.js/src/util/APITypes.js",
    "content": "/* eslint-disable unicorn/no-empty-file */\n\n/**\n * @external ActivityFlags\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ActivityFlags}\n */\n\n/**\n * @external ActivityType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ActivityType}\n */\n\n/**\n * @external APIActionRowComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIActionRowComponent}\n */\n\n/**\n * @external APIApplication\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIApplication}\n */\n\n/**\n * @external APIApplicationCommand\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIApplicationCommand}\n */\n\n/**\n * @external APIApplicationCommandOption\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIApplicationCommandOption}\n */\n\n/**\n * @external ApplicationIntegrationType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationIntegrationType}\n */\n\n/**\n * @external APIAutoModerationAction\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIAutoModerationAction}\n */\n\n/**\n * @external APIButtonComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIButtonComponent}\n */\n\n/**\n * @external APIChannel\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIChannel}\n */\n\n/**\n * @external APIChannelSelectComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIChannelSelectComponent}\n */\n\n/**\n * @external APIContainerComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIContainerComponent}\n */\n\n/**\n * @external APIEmbed\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmbed}\n */\n\n/**\n * @external APIEmbedField\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmbedField}\n */\n\n/**\n * @external APIEmbedProvider\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmbedProvider}\n */\n\n/**\n * @external APIEmoji\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIEmoji}\n */\n\n/**\n * @external APIFileComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIFileComponent}\n */\n\n/**\n * @external APIGuild\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuild}\n */\n\n/**\n * @external APIGuildForumDefaultReactionEmoji\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuildForumDefaultReactionEmoji}\n */\n\n/**\n * @external APIGuildForumTag\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuildForumTag}\n */\n\n/**\n * @external APIGuildMember\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuildMember}\n */\n\n/**\n * @external APIGuildScheduledEventRecurrenceRule\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIGuildScheduledEventRecurrenceRule}\n */\n\n/**\n * @external APIIncidentsData\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIIncidentsData}\n */\n\n/**\n * @external APIInteraction\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIInteraction}\n */\n\n/**\n * @external APIInteractionDataResolved\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIInteractionDataResolved}\n */\n\n/**\n * @external APIInteractionDataResolvedChannel\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIInteractionDataResolvedChannel}\n */\n\n/**\n * @external APIInteractionDataResolvedGuildMember\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIInteractionDataResolvedGuildMember}\n */\n\n/**\n * @external APIInteractionGuildMember\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIInteractionGuildMember}\n */\n\n/**\n * @external APIMediaGalleryComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMediaGalleryComponent}\n */\n\n/**\n * @external APIMediaGalleryItem\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMediaGalleryItem}\n */\n\n/**\n * @external APIMentionableSelectComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIMentionableSelectComponent}\n */\n\n/**\n * @external APIMessage\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMessage}\n */\n\n/**\n * @external APIComponentInMessageActionRow\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIComponentInMessageActionRow}\n */\n\n/**\n * @external APIMessageComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIMessageComponent}\n */\n\n/**\n * @external APIMessageComponentEmoji\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMessageComponentEmoji}\n */\n\n/**\n * @external APIMessageInteractionMetadata\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIMessageInteractionMetadata}\n */\n\n/**\n * @external APIMessageTopLevelComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIMessageTopLevelComponent}\n */\n\n/**\n * @external APIModalInteractionResponse\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIModalInteractionResponse}\n */\n\n/**\n * @external APIModalInteractionResponseCallbackData\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIModalInteractionResponseCallbackData}\n */\n\n/**\n * @external APIModalComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIModalComponent}\n */\n\n/**\n * @external APIModalSubmission\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIModalSubmission}\n */\n\n/**\n * @external APIOverwrite\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIOverwrite}\n */\n\n/**\n * @external APIPartialEmoji\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIPartialEmoji}\n */\n\n/**\n * @external APIRole\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIRole}\n */\n\n/**\n * @external APIRoleSelectComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIRoleSelectComponent}\n */\n\n/**\n * @external APISelectMenuOption\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISelectMenuOption}\n */\n\n/**\n * @external APISelectMenuDefaultValue\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISelectMenuDefaultValue}\n */\n\n/**\n * @external APISectionComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISectionComponent}\n */\n\n/**\n * @external APISticker\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APISticker}\n */\n\n/**\n * @external APIStringSelectComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIStringSelectComponent}\n */\n\n/**\n * @external APITextInputComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APITextInputComponent}\n */\n\n/**\n * @external APIThumbnailComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIThumbnailComponent}\n */\n\n/**\n * @external APIUnfurledMediaItem\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIUnfurledMediaItem}\n */\n\n/**\n * @external APIUser\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/APIUser}\n */\n\n/**\n * @external APIUserSelectComponent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#APIUserSelectComponent}\n */\n\n/**\n * @external ApplicationCommandType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationCommandType}\n */\n\n/**\n * @external ApplicationCommandOptionType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationCommandOptionType}\n */\n\n/**\n * @external ApplicationCommandPermissionType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationCommandPermissionType}\n */\n\n/**\n * @external ApplicationFlags\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationFlags}\n */\n\n/**\n * @external ApplicationRoleConnectionMetadataType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationRoleConnectionMetadataType}\n */\n\n/**\n * @external ApplicationWebhookEventStatus\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationWebhookEventStatus}\n */\n\n/**\n * @external ApplicationWebhookEventType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ApplicationWebhookEventType}\n */\n\n/**\n * @external AttachmentFlags\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AttachmentFlags}\n */\n\n/**\n * @external AutoModerationActionType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationActionType}\n */\n\n/**\n * @external AutoModerationRuleEventType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationRuleEventType}\n */\n\n/**\n * @external AutoModerationRuleTriggerType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationRuleTriggerType}\n */\n\n/**\n * @external AutoModerationRuleKeywordPresetType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AutoModerationRuleKeywordPresetType}\n */\n\n/**\n * @external AuditLogEvent\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/AuditLogEvent}\n */\n\n/**\n * @external ButtonStyle\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ButtonStyle}\n */\n\n/**\n * @external ChannelFlags\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ChannelFlags}\n */\n\n/**\n * @external ChannelType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ChannelType}\n */\n\n/**\n * @external ComponentType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ComponentType}\n */\n\n/**\n * @external EntitlementType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/EntitlementType}\n */\n\n/**\n * @external EntryPointCommandHandlerType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/EntryPointCommandHandlerType}\n */\n\n/**\n * @external ForumLayoutType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ForumLayoutType}\n */\n\n/**\n * @external GatewayCloseCodes\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayCloseCodes}\n */\n\n/**\n * @external GatewayDispatchEvents\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayDispatchEvents}\n */\n\n/**\n * @external GatewayDispatchPayload\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#GatewayDispatchPayload}\n */\n/**\n * @external GatewayIntentBits\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayIntentBits}\n */\n\n/**\n * @external GatewayOpcodes\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GatewayOpcodes}\n */\n\n/**\n * @external GatewayPresenceUpdateData\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/GatewayPresenceUpdateData}\n */\n\n/**\n * @external GuildDefaultMessageNotifications\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildDefaultMessageNotifications}\n */\n\n/**\n * @external GuildExplicitContentFilter\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildExplicitContentFilter}\n */\n\n/**\n * @external GuildFeature\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildFeature}\n */\n\n/**\n * @external GuildMFALevel\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildMFALevel}\n */\n\n/**\n * @external GuildMemberFlags\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildMemberFlags}\n */\n\n/**\n * @external GuildNSFWLevel\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildNSFWLevel}\n */\n\n/**\n * @external GuildOnboardingMode\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildOnboardingMode}\n */\n\n/**\n * @external GuildOnboardingPromptType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildOnboardingPromptType}\n */\n\n/**\n * @external GuildPremiumTier\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildPremiumTier}\n */\n\n/**\n * @external GuildScheduledEventEntityType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventEntityType}\n */\n\n/**\n * @external GuildScheduledEventPrivacyLevel\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventPrivacyLevel}\n */\n\n/**\n * @external GuildScheduledEventRecurrenceRuleFrequency\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventRecurrenceRuleFrequency}\n */\n\n/**\n * @external GuildScheduledEventRecurrenceRuleMonth\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventRecurrenceRuleMonth}\n */\n\n/**\n * @external GuildScheduledEventRecurrenceRuleWeekday\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventRecurrenceRuleWeekday}\n */\n\n/**\n * @external GuildScheduledEventStatus\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildScheduledEventStatus}\n */\n\n/**\n * @external GuildSystemChannelFlags\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildSystemChannelFlags}\n */\n\n/**\n * @external GuildVerificationLevel\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildVerificationLevel}\n */\n\n/**\n * @external GuildWidgetStyle\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/GuildWidgetStyle}\n */\n\n/**\n * @external IntegrationExpireBehavior\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/IntegrationExpireBehavior}\n */\n\n/**\n * @external InteractionContextType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InteractionContextType}\n */\n\n/**\n * @external InteractionType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InteractionType}\n */\n\n/**\n * @external InteractionResponseType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InteractionResponseType}\n */\n\n/**\n * @external InviteFlags\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InviteFlags}\n */\n\n/**\n * @external InviteType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InviteType}\n */\n\n/**\n * @external InviteTargetType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/InviteTargetType}\n */\n\n/**\n * @external Locale\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/Locale}\n */\n\n/**\n * @external LocalizationMap\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#LocalizationMap}\n */\n\n/**\n * @external MessageActivityType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/MessageActivityType}\n */\n\n/**\n * @external MessageReferenceType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/MessageReferenceType}\n */\n\n/**\n * @external MessageType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/MessageType}\n */\n\n/**\n * @external MessageFlags\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/MessageFlags}\n */\n\n/**\n * @external NameplatePalette\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/NameplatePalette}\n */\n\n/**\n * @external OAuth2Scopes\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/OAuth2Scopes}\n */\n\n/**\n * @external OverwriteType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/OverwriteType}\n */\n\n/**\n * @external PermissionFlagsBits\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#PermissionFlagsBits}\n */\n\n/**\n * @external PollLayoutType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/PollLayoutType}\n */\n\n/**\n * @external ReactionType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ReactionType}\n */\n\n/**\n * @external RoleFlags\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/RoleFlags}\n */\n\n/**\n * @external RESTGetAPIGuildThreadsResult\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10#RESTGetAPIGuildThreadsResult}\n */\n\n/**\n * @external RESTJSONErrorCodes\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/RESTJSONErrorCodes}\n */\n\n/**\n * @external SKUFlags\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/SKUFlags}\n */\n\n/**\n * @external SKUType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/SKUType}\n */\n\n/**\n * @external SortOrderType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/SortOrderType}\n */\n\n/**\n * @external StageInstancePrivacyLevel\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/StageInstancePrivacyLevel}\n */\n\n/**\n * @external StickerType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/StickerType}\n */\n\n/**\n * @external StickerFormatType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/StickerFormatType}\n */\n\n/**\n * @external TeamMemberMembershipState\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/TeamMemberMembershipState}\n */\n\n/**\n * @external TeamMemberRole\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/TeamMemberRole}\n */\n\n/**\n * @external TextInputStyle\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/TextInputStyle}\n */\n\n/**\n * @external ThreadAutoArchiveDuration\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ThreadAutoArchiveDuration}\n */\n\n/**\n * @external ThreadMemberFlags\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/ThreadMemberFlags}\n */\n\n/**\n * @external UserFlags\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/UserFlags}\n */\n\n/**\n * @external VideoQualityMode\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/VideoQualityMode}\n */\n\n/**\n * @external VoiceChannelEffectSendAnimationType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/VoiceChannelEffectSendAnimationType}\n */\n\n/**\n * @external WebhookType\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/WebhookType}\n */\n\n/**\n * @external RESTPatchAPIChannelMessageJSONBody\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/RESTPatchAPIChannelMessageJSONBody}\n */\n\n/**\n * @external RESTPostAPIChannelMessageJSONBody\n * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/RESTPostAPIChannelMessageJSONBody}\n */\n"
  },
  {
    "path": "packages/discord.js/src/util/ActivityFlagsBitField.js",
    "content": "/* eslint-disable jsdoc/check-values */\n'use strict';\n\nconst { ActivityFlags } = require('discord-api-types/v10');\nconst { BitField } = require('./BitField.js');\n\n/**\n * Data structure that makes it easy to interact with an {@link Activity#flags} bitfield.\n *\n * @extends {BitField}\n */\nclass ActivityFlagsBitField extends BitField {\n  /**\n   * Numeric activity flags.\n   *\n   * @type {ActivityFlags}\n   * @memberof ActivityFlagsBitField\n   */\n  static Flags = ActivityFlags;\n}\n\n/**\n * @name ActivityFlagsBitField\n * @kind constructor\n * @memberof ActivityFlagsBitField\n * @param {BitFieldResolvable} [bits=0] Bit(s) to read from\n */\n\nexports.ActivityFlagsBitField = ActivityFlagsBitField;\n"
  },
  {
    "path": "packages/discord.js/src/util/ApplicationFlagsBitField.js",
    "content": "/* eslint-disable jsdoc/check-values */\n'use strict';\n\nconst { ApplicationFlags } = require('discord-api-types/v10');\nconst { BitField } = require('./BitField.js');\n\n/**\n * Data structure that makes it easy to interact with a {@link ClientApplication#flags} bitfield.\n *\n * @extends {BitField}\n */\nclass ApplicationFlagsBitField extends BitField {\n  /**\n   * Numeric application flags. All available properties:\n   *\n   * @type {ApplicationFlags}\n   * @memberof ApplicationFlagsBitField\n   */\n  static Flags = ApplicationFlags;\n}\n\n/**\n * @name ApplicationFlagsBitField\n * @kind constructor\n * @memberof ApplicationFlagsBitField\n * @param {BitFieldResolvable} [bits=0] Bit(s) to read from\n */\n\n/**\n * Bitfield of the packed bits\n *\n * @type {number}\n * @name ApplicationFlagsBitField#bitfield\n */\n\n/**\n * Data that can be resolved to give an application flag bit field. This can be:\n * - A string (see {@link ApplicationFlagsBitField.Flags})\n * - An application flag\n * - An instance of ApplicationFlagsBitField\n * - An Array of ApplicationFlagsResolvable\n *\n * @typedef {string|number|ApplicationFlagsBitField|ApplicationFlagsResolvable[]} ApplicationFlagsResolvable\n */\n\nexports.ApplicationFlagsBitField = ApplicationFlagsBitField;\n"
  },
  {
    "path": "packages/discord.js/src/util/AttachmentFlagsBitField.js",
    "content": "/* eslint-disable jsdoc/check-values */\n'use strict';\n\nconst { AttachmentFlags } = require('discord-api-types/v10');\nconst { BitField } = require('./BitField.js');\n\n/**\n * Data structure that makes it easy to interact with an {@link Attachment#flags} bitfield.\n *\n * @extends {BitField}\n */\nclass AttachmentFlagsBitField extends BitField {\n  /**\n   * Numeric attachment flags.\n   *\n   * @type {AttachmentFlags}\n   * @memberof AttachmentFlagsBitField\n   */\n  static Flags = AttachmentFlags;\n}\n\n/**\n * @name AttachmentFlagsBitField\n * @kind constructor\n * @memberof AttachmentFlagsBitField\n * @param {BitFieldResolvable} [bits=0] Bit(s) to read from\n */\n\nexports.AttachmentFlagsBitField = AttachmentFlagsBitField;\n"
  },
  {
    "path": "packages/discord.js/src/util/BitField.js",
    "content": "/* eslint-disable unicorn/prefer-number-properties */\n'use strict';\n\nconst { DiscordjsRangeError, ErrorCodes } = require('../errors/index.js');\n\n/**\n * Data structure that makes it easy to interact with a bitfield.\n */\nclass BitField {\n  /**\n   * Numeric bitfield flags.\n   * <info>Defined in extension classes</info>\n   *\n   * @type {Object}\n   * @memberof BitField\n   * @abstract\n   */\n  static Flags = {};\n\n  /**\n   * @type {number|bigint}\n   * @memberof BitField\n   * @private\n   */\n  static DefaultBit = 0;\n\n  /**\n   * @param {BitFieldResolvable} [bits=this.constructor.DefaultBit] Bit(s) to read from\n   */\n  constructor(bits = this.constructor.DefaultBit) {\n    /**\n     * Bitfield of the packed bits\n     *\n     * @type {number|bigint}\n     */\n    this.bitfield = this.constructor.resolve(bits);\n  }\n\n  /**\n   * Checks whether the bitfield has a bit, or any of multiple bits.\n   *\n   * @param {BitFieldResolvable} bit Bit(s) to check for\n   * @returns {boolean}\n   */\n  any(bit) {\n    return (this.bitfield & this.constructor.resolve(bit)) !== this.constructor.DefaultBit;\n  }\n\n  /**\n   * Checks if this bitfield equals another\n   *\n   * @param {BitFieldResolvable} bit Bit(s) to check for\n   * @returns {boolean}\n   */\n  equals(bit) {\n    return this.bitfield === this.constructor.resolve(bit);\n  }\n\n  /**\n   * Checks whether the bitfield has a bit, or multiple bits.\n   *\n   * @param {BitFieldResolvable} bit Bit(s) to check for\n   * @returns {boolean}\n   */\n  has(bit) {\n    const resolvedBit = this.constructor.resolve(bit);\n    return (this.bitfield & resolvedBit) === resolvedBit;\n  }\n\n  /**\n   * Gets all given bits that are missing from the bitfield.\n   *\n   * @param {BitFieldResolvable} bits Bit(s) to check for\n   * @param {...*} hasParams Additional parameters for the has method, if any\n   * @returns {string[]}\n   */\n  missing(bits, ...hasParams) {\n    return new this.constructor(bits).remove(this).toArray(...hasParams);\n  }\n\n  /**\n   * Freezes these bits, making them immutable.\n   *\n   * @returns {Readonly<BitField>}\n   */\n  freeze() {\n    return Object.freeze(this);\n  }\n\n  /**\n   * Adds bits to these ones.\n   *\n   * @param {...BitFieldResolvable} [bits] Bits to add\n   * @returns {BitField} These bits or new BitField if the instance is frozen.\n   */\n  add(...bits) {\n    let total = this.constructor.DefaultBit;\n    for (const bit of bits) {\n      total |= this.constructor.resolve(bit);\n    }\n\n    if (Object.isFrozen(this)) return new this.constructor(this.bitfield | total);\n    this.bitfield |= total;\n    return this;\n  }\n\n  /**\n   * Removes bits from these.\n   *\n   * @param {...BitFieldResolvable} [bits] Bits to remove\n   * @returns {BitField} These bits or new BitField if the instance is frozen.\n   */\n  remove(...bits) {\n    let total = this.constructor.DefaultBit;\n    for (const bit of bits) {\n      total |= this.constructor.resolve(bit);\n    }\n\n    if (Object.isFrozen(this)) return new this.constructor(this.bitfield & ~total);\n    this.bitfield &= ~total;\n    return this;\n  }\n\n  /**\n   * Gets an object mapping field names to a {@link boolean} indicating whether the\n   * bit is available.\n   *\n   * @param {...*} hasParams Additional parameters for the has method, if any\n   * @returns {Object}\n   */\n  serialize(...hasParams) {\n    const serialized = {};\n    for (const [flag, bit] of Object.entries(this.constructor.Flags)) {\n      if (isNaN(flag)) serialized[flag] = this.has(bit, ...hasParams);\n    }\n\n    return serialized;\n  }\n\n  /**\n   * Gets an {@link Array} of bitfield names based on the bits available.\n   *\n   * @param {...*} hasParams Additional parameters for the has method, if any\n   * @returns {string[]}\n   */\n  toArray(...hasParams) {\n    return [...this[Symbol.iterator](...hasParams)];\n  }\n\n  toJSON() {\n    return typeof this.bitfield === 'number' ? this.bitfield : this.bitfield.toString();\n  }\n\n  valueOf() {\n    return this.bitfield;\n  }\n\n  *[Symbol.iterator](...hasParams) {\n    for (const bitName of Object.keys(this.constructor.Flags)) {\n      if (isNaN(bitName) && this.has(bitName, ...hasParams)) yield bitName;\n    }\n  }\n\n  /**\n   * Data that can be resolved to give a bitfield. This can be:\n   * - A bit number (this can be a number literal or a value taken from {@link BitField.Flags})\n   * - A string bit number\n   * - An instance of BitField\n   * - An Array of BitFieldResolvable\n   *\n   * @typedef {number|string|bigint|BitField|BitFieldResolvable[]} BitFieldResolvable\n   */\n\n  /**\n   * Resolves bitfields to their numeric form.\n   *\n   * @param {BitFieldResolvable} [bit] bit(s) to resolve\n   * @returns {number|bigint}\n   */\n  static resolve(bit) {\n    const { DefaultBit } = this;\n    if (typeof DefaultBit === typeof bit && bit >= DefaultBit) return bit;\n    if (bit instanceof BitField) return bit.bitfield;\n    if (Array.isArray(bit)) {\n      return bit.map(bit_ => this.resolve(bit_)).reduce((prev, bit_) => prev | bit_, DefaultBit);\n    }\n\n    if (typeof bit === 'string') {\n      if (!isNaN(bit)) return typeof DefaultBit === 'bigint' ? BigInt(bit) : Number(bit);\n      if (this.Flags[bit] !== undefined) return this.Flags[bit];\n    }\n\n    throw new DiscordjsRangeError(ErrorCodes.BitFieldInvalid, bit);\n  }\n}\n\nexports.BitField = BitField;\n"
  },
  {
    "path": "packages/discord.js/src/util/ChannelFlagsBitField.js",
    "content": "/* eslint-disable jsdoc/check-values */\n'use strict';\n\nconst { ChannelFlags } = require('discord-api-types/v10');\nconst { BitField } = require('./BitField.js');\n\n/**\n * Data structure that makes it easy to interact with a {@link BaseChannel#flags} bitfield.\n *\n * @extends {BitField}\n */\nclass ChannelFlagsBitField extends BitField {\n  /**\n   * Numeric guild channel flags.\n   *\n   * @type {ChannelFlags}\n   * @memberof ChannelFlagsBitField\n   */\n  static Flags = ChannelFlags;\n}\n\n/**\n * @name ChannelFlagsBitField\n * @kind constructor\n * @memberof ChannelFlagsBitField\n * @param {BitFieldResolvable} [bits=0] Bit(s) to read from\n */\n\n/**\n * Bitfield of the packed bits\n *\n * @type {number}\n * @name ChannelFlagsBitField#bitfield\n */\n\n/**\n * Data that can be resolved to give a channel flag bitfield. This can be:\n * - A string (see {@link ChannelFlagsBitField.Flags})\n * - A channel flag\n * - An instance of ChannelFlagsBitField\n * - An Array of ChannelFlagsResolvable\n *\n * @typedef {string|number|ChannelFlagsBitField|ChannelFlagsResolvable[]} ChannelFlagsResolvable\n */\n\nexports.ChannelFlagsBitField = ChannelFlagsBitField;\n"
  },
  {
    "path": "packages/discord.js/src/util/Channels.js",
    "content": "'use strict';\n\nconst { lazy } = require('@discordjs/util');\nconst { ChannelType } = require('discord-api-types/v10');\n\nconst getCategoryChannel = lazy(() => require('../structures/CategoryChannel.js').CategoryChannel);\nconst getDMChannel = lazy(() => require('../structures/DMChannel.js').DMChannel);\nconst getAnnouncementChannel = lazy(() => require('../structures/AnnouncementChannel.js').AnnouncementChannel);\nconst getStageChannel = lazy(() => require('../structures/StageChannel.js').StageChannel);\nconst getTextChannel = lazy(() => require('../structures/TextChannel.js').TextChannel);\nconst getThreadChannel = lazy(() => require('../structures/ThreadChannel.js').ThreadChannel);\nconst getVoiceChannel = lazy(() => require('../structures/VoiceChannel.js').VoiceChannel);\nconst getDirectoryChannel = lazy(() => require('../structures/DirectoryChannel.js').DirectoryChannel);\nconst getPartialGroupDMChannel = lazy(() => require('../structures/PartialGroupDMChannel.js').PartialGroupDMChannel);\nconst getForumChannel = lazy(() => require('../structures/ForumChannel.js').ForumChannel);\nconst getMediaChannel = lazy(() => require('../structures/MediaChannel.js').MediaChannel);\n\n/**\n * Extra options for creating a channel.\n *\n * @typedef {Object} CreateChannelOptions\n * @property {boolean} [allowFromUnknownGuild] Whether to allow creating a channel from an unknown guild\n * @private\n */\n\n/**\n * Creates a discord.js channel from data received from the API.\n *\n * @param {Client} client The client\n * @param {APIChannel} data The data of the channel to create\n * @param {Guild} [guild] The guild where this channel belongs\n * @param {CreateChannelOptions} [extras] Extra information to supply for creating this channel\n * @returns {BaseChannel} Any kind of channel.\n * @ignore\n */\nfunction createChannel(client, data, guild, { allowUnknownGuild } = {}) {\n  let channel;\n  const resolvedGuild = guild ?? client.guilds.cache.get(data.guild_id);\n\n  if (!data.guild_id && !resolvedGuild) {\n    if ((data.recipients && data.type !== ChannelType.GroupDM) || data.type === ChannelType.DM) {\n      channel = new (getDMChannel())(client, data);\n    } else if (data.type === ChannelType.GroupDM) {\n      channel = new (getPartialGroupDMChannel())(client, data);\n    }\n  } else if (resolvedGuild || allowUnknownGuild) {\n    switch (data.type) {\n      case ChannelType.GuildText: {\n        channel = new (getTextChannel())(resolvedGuild, data, client);\n        break;\n      }\n\n      case ChannelType.GuildVoice: {\n        channel = new (getVoiceChannel())(resolvedGuild, data, client);\n        break;\n      }\n\n      case ChannelType.GuildCategory: {\n        channel = new (getCategoryChannel())(resolvedGuild, data, client);\n        break;\n      }\n\n      case ChannelType.GuildAnnouncement: {\n        channel = new (getAnnouncementChannel())(resolvedGuild, data, client);\n        break;\n      }\n\n      case ChannelType.GuildStageVoice: {\n        channel = new (getStageChannel())(resolvedGuild, data, client);\n        break;\n      }\n\n      case ChannelType.AnnouncementThread:\n      case ChannelType.PublicThread:\n      case ChannelType.PrivateThread: {\n        channel = new (getThreadChannel())(resolvedGuild, data, client);\n        if (!allowUnknownGuild) channel.parent?.threads.cache.set(channel.id, channel);\n        break;\n      }\n\n      case ChannelType.GuildDirectory:\n        channel = new (getDirectoryChannel())(resolvedGuild, data, client);\n        break;\n      case ChannelType.GuildForum:\n        channel = new (getForumChannel())(resolvedGuild, data, client);\n        break;\n      case ChannelType.GuildMedia:\n        channel = new (getMediaChannel())(resolvedGuild, data, client);\n        break;\n      default:\n        break;\n    }\n\n    if (channel && !allowUnknownGuild) resolvedGuild.channels?.cache.set(channel.id, channel);\n  }\n\n  return channel;\n}\n\n/**\n * Transforms an API guild forum tag to camel-cased guild forum tag.\n *\n * @param {APIGuildForumTag} tag The tag to transform\n * @returns {GuildForumTag}\n * @ignore\n */\nfunction transformAPIGuildForumTag(tag) {\n  return {\n    id: tag.id,\n    name: tag.name,\n    moderated: tag.moderated,\n    emoji:\n      (tag.emoji_id ?? tag.emoji_name)\n        ? {\n            id: tag.emoji_id,\n            name: tag.emoji_name,\n          }\n        : null,\n  };\n}\n\n/**\n * Transforms a camel-cased guild forum tag to an API guild forum tag.\n *\n * @param {GuildForumTag} tag The tag to transform\n * @returns {APIGuildForumTag}\n * @ignore\n */\nfunction transformGuildForumTag(tag) {\n  return {\n    id: tag.id,\n    name: tag.name,\n    moderated: tag.moderated,\n    emoji_id: tag.emoji?.id ?? null,\n    emoji_name: tag.emoji?.name ?? null,\n  };\n}\n\n/**\n * Transforms an API guild forum default reaction object to a\n * camel-cased guild forum default reaction object.\n *\n * @param {APIGuildForumDefaultReactionEmoji} defaultReaction The default reaction to transform\n * @returns {DefaultReactionEmoji}\n * @ignore\n */\nfunction transformAPIGuildDefaultReaction(defaultReaction) {\n  return {\n    id: defaultReaction.emoji_id,\n    name: defaultReaction.emoji_name,\n  };\n}\n\n/**\n * Transforms a camel-cased guild forum default reaction object to an\n * API guild forum default reaction object.\n *\n * @param {DefaultReactionEmoji} defaultReaction The default reaction to transform\n * @returns {APIGuildForumDefaultReactionEmoji}\n * @ignore\n */\nfunction transformGuildDefaultReaction(defaultReaction) {\n  return {\n    emoji_id: defaultReaction.id,\n    emoji_name: defaultReaction.name,\n  };\n}\n\nexports.createChannel = createChannel;\nexports.transformAPIGuildForumTag = transformAPIGuildForumTag;\nexports.transformGuildForumTag = transformGuildForumTag;\nexports.transformAPIGuildDefaultReaction = transformAPIGuildDefaultReaction;\nexports.transformGuildDefaultReaction = transformGuildDefaultReaction;\n"
  },
  {
    "path": "packages/discord.js/src/util/Colors.js",
    "content": "'use strict';\n\n/**\n * @typedef {Object} Colors\n * @property {number} Aqua 0x1ABC9C | rgb(26,188,156)\n * @property {number} Blue 0x3498DB | rgb(52,152,219)\n * @property {number} Blurple 0x5865F2 | rgb(88,101,242)\n * @property {number} DarkAqua 0x11806A | rgb(17,128,106)\n * @property {number} DarkBlue 0x206694 | rgb(32,102,148)\n * @property {number} DarkButNotBlack 0x2C2F33 | rgb(44,47,51)\n * @property {number} DarkerGrey 0x7F8C8D | rgb(127,140,141)\n * @property {number} DarkGold 0xC27C0E | rgb(194,124,14)\n * @property {number} DarkGreen 0x1F8B4C | rgb(31,139,76)\n * @property {number} DarkGrey 0x979C9F | rgb(151,156,159)\n * @property {number} DarkNavy 0x2C3E50 | rgb(44,62,80)\n * @property {number} DarkOrange 0xA84300 | rgb(168,67,0)\n * @property {number} DarkPurple 0x71368A | rgb(113,54,138)\n * @property {number} DarkRed 0x992D22 | rgb(153,45,34)\n * @property {number} DarkVividPink 0xAD1457 | rgb(173,20,87)\n * @property {number} Default 0x000000 | rgb(0,0,0)\n * @property {number} Fuchsia 0xEB459E | rgb(235,69,158)\n * @property {number} Gold 0xF1C40F | rgb(241,196,15)\n * @property {number} Green 0x57F287 | rgb(87,242,135)\n * @property {number} Grey 0x95A5A6 | rgb(149,165,166)\n * @property {number} Greyple 0x99AAb5 | rgb(153,170,181)\n * @property {number} LightGrey 0xBCC0C0 | rgb(188,192,192)\n * @property {number} LuminousVividPink 0xE91E63 | rgb(233,30,99)\n * @property {number} Navy 0x34495E | rgb(52,73,94)\n * @property {number} NotQuiteBlack 0x23272A | rgb(35,39,42)\n * @property {number} Orange 0xE67E22 | rgb(230,126,34)\n * @property {number} Purple 0x9B59B6 | rgb(155,89,182)\n * @property {number} Red 0xED4245 | rgb(237,66,69)\n * @property {number} White 0xFFFFFF | rgb(255,255,255)\n * @property {number} Yellow 0xFEE75C | rgb(254,231,92)\n */\n\n// JSDoc for IntelliSense purposes\n/**\n * @type {Colors}\n * @ignore\n */\nexports.Colors = {\n  Aqua: 0x1abc9c,\n  Blue: 0x3498db,\n  Blurple: 0x5865f2,\n  DarkAqua: 0x11806a,\n  DarkBlue: 0x206694,\n  DarkButNotBlack: 0x2c2f33,\n  DarkerGrey: 0x7f8c8d,\n  DarkGold: 0xc27c0e,\n  DarkGreen: 0x1f8b4c,\n  DarkGrey: 0x979c9f,\n  DarkNavy: 0x2c3e50,\n  DarkOrange: 0xa84300,\n  DarkPurple: 0x71368a,\n  DarkRed: 0x992d22,\n  DarkVividPink: 0xad1457,\n  Default: 0x000000,\n  Fuchsia: 0xeb459e,\n  Gold: 0xf1c40f,\n  Green: 0x57f287,\n  Grey: 0x95a5a6,\n  Greyple: 0x99aab5,\n  LightGrey: 0xbcc0c0,\n  LuminousVividPink: 0xe91e63,\n  Navy: 0x34495e,\n  NotQuiteBlack: 0x23272a,\n  Orange: 0xe67e22,\n  Purple: 0x9b59b6,\n  Red: 0xed4245,\n  White: 0xffffff,\n  Yellow: 0xfee75c,\n};\n"
  },
  {
    "path": "packages/discord.js/src/util/Components.js",
    "content": "'use strict';\n\nconst { lazy } = require('@discordjs/util');\nconst { ComponentType } = require('discord-api-types/v10');\n\n// Fixes circular dependencies.\nconst getActionRow = lazy(() => require('../structures/ActionRow.js').ActionRow);\nconst getButtonComponent = lazy(() => require('../structures/ButtonComponent.js').ButtonComponent);\nconst getChannelSelectMenuComponent = lazy(\n  () => require('../structures/ChannelSelectMenuComponent.js').ChannelSelectMenuComponent,\n);\nconst getComponent = lazy(() => require('../structures/Component.js').Component);\nconst getContainerComponent = lazy(() => require('../structures/ContainerComponent.js').ContainerComponent);\nconst getFileComponent = lazy(() => require('../structures/FileComponent.js').FileComponent);\nconst getLabelComponent = lazy(() => require('../structures/LabelComponent.js').LabelComponent);\nconst getMediaGalleryComponent = lazy(() => require('../structures/MediaGalleryComponent.js').MediaGalleryComponent);\nconst getMentionableSelectMenuComponent = lazy(\n  () => require('../structures/MentionableSelectMenuComponent.js').MentionableSelectMenuComponent,\n);\nconst getRoleSelectMenuComponent = lazy(\n  () => require('../structures/RoleSelectMenuComponent.js').RoleSelectMenuComponent,\n);\nconst getSectionComponent = lazy(() => require('../structures/SectionComponent.js').SectionComponent);\nconst getSeparatorComponent = lazy(() => require('../structures/SeparatorComponent.js').SeparatorComponent);\nconst getStringSelectMenuComponent = lazy(\n  () => require('../structures/StringSelectMenuComponent.js').StringSelectMenuComponent,\n);\nconst getTextDisplayComponent = lazy(() => require('../structures/TextDisplayComponent.js').TextDisplayComponent);\nconst getTextInputComponent = lazy(() => require('../structures/TextInputComponent.js').TextInputComponent);\nconst getThumbnailComponent = lazy(() => require('../structures/ThumbnailComponent.js').ThumbnailComponent);\nconst getUserSelectMenuComponent = lazy(\n  () => require('../structures/UserSelectMenuComponent.js').UserSelectMenuComponent,\n);\n\n/**\n * @typedef {Object} BaseComponentData\n * @property {number} [id] the id of this component\n * @property {ComponentType} type The type of component\n */\n\n/**\n * @typedef {BaseComponentData} ActionRowData\n * @property {ComponentData[]} components The components in this action row\n */\n\n/**\n * @typedef {Object} ModalComponentData\n * @property {string} title The title of the modal\n * @property {string} customId The custom id of the modal\n * @property {Array<TextDisplayComponentData|LabelData>} components The components within this modal\n */\n\n/**\n * @typedef {StringSelectMenuComponentData|TextInputComponentData|UserSelectMenuComponentData|\n * RoleSelectMenuComponentData|MentionableSelectMenuComponentData|ChannelSelectMenuComponentData|FileUploadComponentData|\n * RadioGroupComponentData|CheckboxGroupComponentData|CheckboxComponentData} ComponentInLabelData\n */\n\n/**\n * @typedef {BaseComponentData} LabelData\n * @property {string} label The label to use\n * @property {string} [description] The optional description for the label\n * @property {ComponentInLabelData} component The component within the label\n */\n\n/**\n * @typedef {BaseComponentData} ButtonComponentData\n * @property {ButtonStyle} style The style of the button\n * @property {boolean} [disabled] Whether this button is disabled\n * @property {string} label The label of this button\n * @property {APIMessageComponentEmoji} [emoji] The emoji on this button\n * @property {string} [customId] The custom id of the button\n * @property {string} [url] The URL of the button\n */\n\n/**\n * @typedef {BaseComponentData} FileUploadComponentData\n * @property {string} customId The custom id of the file upload\n * @property {number} [minValues] The minimum number of files that must be uploaded (0-10)\n * @property {number} [maxValues] The maximum number of files that can be uploaded (1-10)\n * @property {boolean} [required] Whether this component is required in modals\n */\n\n/**\n * @typedef {Object} RadioGroupOption\n * @property {string} value The value of the radio group option\n * @property {string} label The label to use\n * @property {string} [description] The optional description for the radio group option\n * @property {boolean} [default] Whether this option is default selected\n */\n\n/**\n * @typedef {BaseComponentData} RadioGroupComponentData\n * @property {string} customId The custom id of the radio group\n * @property {RadioGroupOption[]} options The options in this radio group (2-10)\n * @property {boolean} [required] Whether this component is required in modals\n */\n\n/**\n * @typedef {Object} CheckboxGroupOption\n * @property {string} value The value of the checkbox group option\n * @property {string} label The label to use\n * @property {string} [description] The optional description for the checkbox group option\n * @property {boolean} [default] Whether this option is default selected\n */\n\n/**\n * @typedef {BaseComponentData} CheckboxGroupComponentData\n * @property {string} customId The custom id of the checkbox group\n * @property {CheckboxGroupOption[]} options The options in this checkbox group\n * @property {number} [minValues] The minimum number of options that must be selected (0-10)\n * @property {number} [maxValues] The maximum number of options that can be selected (defaults to options length)\n * @property {boolean} [required] Whether this component is required in modals\n */\n\n/**\n * @typedef {BaseComponentData} CheckboxComponentData\n * @property {string} customId The custom id of the checkbox\n * @property {boolean} [default] Whether this component is default selected in modals\n */\n\n/**\n * @typedef {BaseComponentData} BaseSelectMenuComponentData\n * @property {string} customId The custom id of the select menu\n * @property {boolean} [disabled] Whether the select menu is disabled or not\n * @property {number} [maxValues] The maximum amount of options that can be selected\n * @property {number} [minValues] The minimum amount of options that must be selected\n * @property {string} [placeholder] The placeholder of the select menu\n * @property {boolean} [required] Whether this component is required in modals\n */\n\n/**\n * @typedef {BaseSelectMenuComponentData} StringSelectMenuComponentData\n * @property {SelectMenuComponentOptionData[]} [options] The options in this select menu\n */\n\n/**\n * @typedef {BaseSelectMenuComponentData} UserSelectMenuComponentData\n * @property {APISelectMenuDefaultValue[]} [defaultValues] The default selected values in this select menu\n */\n\n/**\n * @typedef {BaseSelectMenuComponentData} RoleSelectMenuComponentData\n * @property {APISelectMenuDefaultValue[]} [defaultValues] The default selected values in this select menu\n */\n\n/**\n * @typedef {BaseSelectMenuComponentData} MentionableSelectMenuComponentData\n * @property {APISelectMenuDefaultValue[]} [defaultValues] The default selected values in this select menu\n */\n\n/**\n * @typedef {BaseSelectMenuComponentData} ChannelSelectMenuComponentData\n * @property {APISelectMenuDefaultValue[]} [defaultValues] The default selected values in this select menu\n * @property {ChannelType[]} [channelTypes] The types of channels that can be selected\n */\n\n/**\n * @typedef {Object} SelectMenuComponentOptionData\n * @property {string} label The label of the option\n * @property {string} value The value of the option\n * @property {string} [description] The description of the option\n * @property {APIMessageComponentEmoji} [emoji] The emoji on the option\n * @property {boolean} [default] Whether this option is selected by default\n */\n\n/**\n * @typedef {BaseComponentData} SelectMenuComponentData\n * @property {string} customId The custom id of the select menu\n * @property {boolean} [disabled] Whether the select menu is disabled or not\n * @property {number} [maxValues] The maximum amount of options that can be selected\n * @property {number} [minValues] The minimum amount of options that can be selected\n * @property {SelectMenuComponentOptionData[]} [options] The options in this select menu\n * @property {string} [placeholder] The placeholder of the select menu\n */\n\n/**\n * @typedef {ActionRowData|ButtonComponentData|SelectMenuComponentData} MessageComponentData\n */\n\n/**\n * @typedef {BaseComponentData} TextInputComponentData\n * @property {string} customId The custom id of the text input\n * @property {TextInputStyle} style The style of the text input\n * @property {number} [minLength] The minimum number of characters that can be entered in the text input\n * @property {number} [maxLength] The maximum number of characters that can be entered in the text input\n * @property {boolean} [required] Whether or not the text input is required or not\n * @property {string} [value] The pre-filled text in the text input\n * @property {string} [placeholder] Placeholder for the text input\n */\n\n/**\n * @typedef {Object} UnfurledMediaItemData\n * @property {string} url The url of this media item. Accepts either http:, https: or attachment: protocol\n */\n\n/**\n * @typedef {BaseComponentData} ThumbnailComponentData\n * @property {UnfurledMediaItemData} media The media for the thumbnail\n * @property {string} [description] The description of the thumbnail\n * @property {boolean} [spoiler] Whether the thumbnail should be spoilered\n */\n\n/**\n * @typedef {BaseComponentData} FileComponentData\n * @property {UnfurledMediaItemData} file The file media in this component\n * @property {boolean} [spoiler] Whether the file should be spoilered\n */\n\n/**\n * @typedef {Object} MediaGalleryItemData\n * @property {UnfurledMediaItemData} media The media for the media gallery item\n * @property {string} [description] The description of the media gallery item\n * @property {boolean} [spoiler] Whether the media gallery item should be spoilered\n */\n\n/**\n * @typedef {BaseComponentData} MediaGalleryComponentData\n * @property {MediaGalleryItemData[]} items The media gallery items in this media gallery component\n */\n\n/**\n * @typedef {BaseComponentData} SeparatorComponentData\n * @property {SeparatorSpacingSize} [spacing] The spacing size of this component\n * @property {boolean} [divider] Whether the separator shows as a divider\n */\n\n/**\n * @typedef {BaseComponentData} SectionComponentData\n * @property {Components[]} components The components in this section\n * @property {ButtonComponentData|ThumbnailComponentData} accessory The accessory shown next to this section\n */\n\n/**\n * @typedef {BaseComponentData} TextDisplayComponentData\n * @property {string} content The content displayed in this component\n */\n\n/**\n * @typedef {ActionRowData|FileComponentData|MediaGalleryComponentData|SectionComponentData|\n * SeparatorComponentData|TextDisplayComponentData} ComponentInContainerData\n */\n\n/**\n * @typedef {BaseComponentData} ContainerComponentData\n * @property {ComponentInContainerData} components The components in this container\n * @property {?number} [accentColor] The accent color of this container\n * @property {boolean} [spoiler] Whether the container should be spoilered\n */\n\n/**\n * @typedef {ActionRowData|ButtonComponentData|SelectMenuComponentData|TextInputComponentData|\n * ThumbnailComponentData|FileComponentData|MediaGalleryComponentData|SeparatorComponentData|\n * SectionComponentData|TextDisplayComponentData|ContainerComponentData} ComponentData\n */\n\n/**\n * @typedef {ActionRow|ContainerComponent|FileComponent|MediaGalleryComponent|\n * SectionComponent|SeparatorComponent|TextDisplayComponent} MessageTopLevelComponent\n */\n\nconst ComponentTypeToClass = {\n  [ComponentType.ActionRow]: getActionRow,\n  [ComponentType.Button]: getButtonComponent,\n  [ComponentType.StringSelect]: getStringSelectMenuComponent,\n  [ComponentType.TextInput]: getTextInputComponent,\n  [ComponentType.UserSelect]: getUserSelectMenuComponent,\n  [ComponentType.RoleSelect]: getRoleSelectMenuComponent,\n  [ComponentType.MentionableSelect]: getMentionableSelectMenuComponent,\n  [ComponentType.ChannelSelect]: getChannelSelectMenuComponent,\n  [ComponentType.Container]: getContainerComponent,\n  [ComponentType.TextDisplay]: getTextDisplayComponent,\n  [ComponentType.File]: getFileComponent,\n  [ComponentType.MediaGallery]: getMediaGalleryComponent,\n  [ComponentType.Section]: getSectionComponent,\n  [ComponentType.Separator]: getSeparatorComponent,\n  [ComponentType.Thumbnail]: getThumbnailComponent,\n  [ComponentType.Label]: getLabelComponent,\n};\n\n/**\n * Transforms API data into a component\n *\n * @param {APIMessageComponent|Component} data The data to create the component from\n * @returns {Component}\n * @ignore\n */\nfunction createComponent(data) {\n  return data instanceof getComponent() ? data : new (ComponentTypeToClass[data.type]?.() ?? getComponent())(data);\n}\n\n/**\n * Extracts all interactive components from the component tree\n *\n * @param {Component|APIMessageComponent} component The component to find all interactive components in\n * @returns {Array<Component|APIMessageComponent>}\n * @ignore\n */\nfunction extractInteractiveComponents(component) {\n  switch (component.type) {\n    case ComponentType.ActionRow:\n      return component.components;\n    case ComponentType.Section:\n      return [...component.components, component.accessory];\n    case ComponentType.Container:\n      return component.components.flatMap(extractInteractiveComponents);\n    default:\n      return [component];\n  }\n}\n\n/**\n * Finds a component by customId in nested components\n *\n * @param {Array<Component|APIMessageComponent>} components The components to search in\n * @param {string} customId The customId to search for\n * @returns {Component|APIMessageComponent}\n * @ignore\n */\nfunction findComponentByCustomId(components, customId) {\n  return (\n    components\n      .flatMap(extractInteractiveComponents)\n      .find(component => (component.customId ?? component.custom_id) === customId) ?? null\n  );\n}\n\nexports.createComponent = createComponent;\nexports.findComponentByCustomId = findComponentByCustomId;\n"
  },
  {
    "path": "packages/discord.js/src/util/Constants.js",
    "content": "'use strict';\n\nconst { ChannelType, MessageType, ComponentType, ImageFormat, StickerFormatType } = require('discord-api-types/v10');\n\n/**\n * Max bulk deletable message age\n *\n * @typedef {number} MaxBulkDeletableMessageAge\n */\nexports.MaxBulkDeletableMessageAge = 1_209_600_000;\n\n/**\n * The name of an item to be swept in Sweepers\n * - `autoModerationRules`\n * - `applicationCommands` - both global and guild commands\n * - `bans`\n * - `emojis`\n * - `entitlements`\n * - `invites` - accepts the `lifetime` property, using it will sweep based on expires timestamp\n * - `guildMembers`\n * - `messages` - accepts the `lifetime` property, using it will sweep based on edited or created timestamp\n * - `presences`\n * - `reactions`\n * - `stageInstances`\n * - `stickers`\n * - `threadMembers`\n * - `threads` - accepts the `lifetime` property, using it will sweep archived threads based on archived timestamp\n * - `users`\n * - `voiceStates`\n *\n * @typedef {string} SweeperKey\n */\nexports.SweeperKeys = [\n  'autoModerationRules',\n  'applicationCommands',\n  'bans',\n  'emojis',\n  'entitlements',\n  'invites',\n  'guildMembers',\n  'messages',\n  'presences',\n  'reactions',\n  'stageInstances',\n  'stickers',\n  'threadMembers',\n  'threads',\n  'users',\n  'voiceStates',\n];\n\n/**\n * The types of messages that are not `System`. The available types are:\n * - {@link MessageType.Default}\n * - {@link MessageType.Reply}\n * - {@link MessageType.ChatInputCommand}\n * - {@link MessageType.ContextMenuCommand}\n *\n * @typedef {MessageType[]} NonSystemMessageTypes\n */\nexports.NonSystemMessageTypes = [\n  MessageType.Default,\n  MessageType.Reply,\n  MessageType.ChatInputCommand,\n  MessageType.ContextMenuCommand,\n];\n\n/**\n * The guild channels that are text-based.\n * - TextChannel\n * - AnnouncementChannel\n * - ThreadChannel\n * - VoiceChannel\n * - StageChannel\n *\n * @typedef {TextChannel|AnnouncementChannel|ThreadChannel|VoiceChannel|StageChannel} GuildTextBasedChannel\n */\n\n/**\n * The types of guild channels that are text-based. The available types are:\n * - {@link ChannelType.GuildText}\n * - {@link ChannelType.GuildAnnouncement}\n * - {@link ChannelType.AnnouncementThread}\n * - {@link ChannelType.PublicThread}\n * - {@link ChannelType.PrivateThread}\n * - {@link ChannelType.GuildVoice}\n * - {@link ChannelType.GuildStageVoice}\n *\n * @typedef {ChannelType[]} GuildTextBasedChannelTypes\n */\nexports.GuildTextBasedChannelTypes = [\n  ChannelType.GuildText,\n  ChannelType.GuildAnnouncement,\n  ChannelType.AnnouncementThread,\n  ChannelType.PublicThread,\n  ChannelType.PrivateThread,\n  ChannelType.GuildVoice,\n  ChannelType.GuildStageVoice,\n];\n\n/**\n * The channels that are text-based.\n * - {@link DMChannel}\n * - {@link GuildTextBasedChannel}\n *\n * @typedef {DMChannel|GuildTextBasedChannel} TextBasedChannels\n */\n\n/**\n * Data that resolves to give a text-based channel. This can be:\n * - A {@link TextBasedChannel}\n * - A {@link Snowflake}\n *\n * @typedef {TextBasedChannels|Snowflake} TextBasedChannelsResolvable\n */\n\n/**\n * The types of channels that are text-based. The available types are:\n * - {@link ChannelType.DM}\n * - {@link ChannelType.GuildText}\n * - {@link ChannelType.GuildAnnouncement}\n * - {@link ChannelType.AnnouncementThread}\n * - {@link ChannelType.PublicThread}\n * - {@link ChannelType.PrivateThread}\n * - {@link ChannelType.GuildVoice}\n * - {@link ChannelType.GuildStageVoice}\n * - {@link ChannelType.GroupDM}\n *\n * @typedef {ChannelType[]} TextBasedChannelTypes\n */\nexports.TextBasedChannelTypes = [...exports.GuildTextBasedChannelTypes, ChannelType.DM, ChannelType.GroupDM];\n\n/**\n * The types of channels that are text-based and can have messages sent into. The available types are:\n * - {@link ChannelType.DM}\n * - {@link ChannelType.GuildText}\n * - {@link ChannelType.GuildAnnouncement}\n * - {@link ChannelType.AnnouncementThread}\n * - {@link ChannelType.PublicThread}\n * - {@link ChannelType.PrivateThread}\n * - {@link ChannelType.GuildVoice}\n * - {@link ChannelType.GuildStageVoice}\n *\n * @typedef {ChannelType[]} SendableChannels\n */\nexports.SendableChannels = [...exports.GuildTextBasedChannelTypes, ChannelType.DM];\n\n/**\n * The types of channels that are threads. The available types are:\n * - {@link ChannelType.AnnouncementThread}\n * - {@link ChannelType.PublicThread}\n * - {@link ChannelType.PrivateThread}\n *\n * @typedef {ChannelType[]} ThreadChannelTypes\n */\nexports.ThreadChannelTypes = [ChannelType.AnnouncementThread, ChannelType.PublicThread, ChannelType.PrivateThread];\n\n/**\n * The types of channels that are voice-based. The available types are:\n * - {@link ChannelType.GuildVoice}\n * - {@link ChannelType.GuildStageVoice}\n *\n * @typedef {ChannelType[]} VoiceBasedChannelTypes\n */\nexports.VoiceBasedChannelTypes = [ChannelType.GuildVoice, ChannelType.GuildStageVoice];\n\n/**\n * The types of select menus. The available types are:\n * - {@link ComponentType.StringSelect}\n * - {@link ComponentType.UserSelect}\n * - {@link ComponentType.RoleSelect}\n * - {@link ComponentType.MentionableSelect}\n * - {@link ComponentType.ChannelSelect}\n *\n * @typedef {ComponentType[]} SelectMenuTypes\n */\nexports.SelectMenuTypes = [\n  ComponentType.StringSelect,\n  ComponentType.UserSelect,\n  ComponentType.RoleSelect,\n  ComponentType.MentionableSelect,\n  ComponentType.ChannelSelect,\n];\n\n/**\n * The types of messages that cannot be deleted. The available types are:\n * - {@link MessageType.RecipientAdd}\n * - {@link MessageType.RecipientRemove}\n * - {@link MessageType.Call}\n * - {@link MessageType.ChannelNameChange}\n * - {@link MessageType.ChannelIconChange}\n * - {@link MessageType.ThreadStarterMessage}\n *\n * @typedef {MessageType[]} UndeletableMessageTypes\n */\nexports.UndeletableMessageTypes = [\n  MessageType.RecipientAdd,\n  MessageType.RecipientRemove,\n  MessageType.Call,\n  MessageType.ChannelNameChange,\n  MessageType.ChannelIconChange,\n  MessageType.ThreadStarterMessage,\n];\n\n/* eslint-disable jsdoc/valid-types */\n/**\n * A mapping between sticker formats and their respective image formats.\n * - {@link StickerFormatType.PNG} -> {@link ImageFormat.PNG}\n * - {@link StickerFormatType.APNG} -> {@link ImageFormat.PNG}\n * - {@link StickerFormatType.Lottie} -> {@link ImageFormat.Lottie}\n * - {@link StickerFormatType.GIF} -> {@link ImageFormat.GIF}\n *\n * @typedef {Object} StickerFormatExtensionMap\n * @property {\"png\"} 1 PNG\n * @property {\"png\"} 2 APNG\n * @property {\"json\"} 3 Lottie\n * @property {\"gif\"} 4 GIF\n */\nexports.StickerFormatExtensionMap = {\n  [StickerFormatType.PNG]: ImageFormat.PNG,\n  [StickerFormatType.APNG]: ImageFormat.PNG,\n  [StickerFormatType.Lottie]: ImageFormat.Lottie,\n  [StickerFormatType.GIF]: ImageFormat.GIF,\n};\n/* eslint-enable jsdoc/valid-types */\n\n/**\n * Holographic color values for role styling.\n * When using `tertiaryColor`, the API enforces these specific values for holographic effect.\n *\n * @typedef {Object} HolographicStyle\n * @property {number} Primary 11127295 (0xA9FFFF)\n * @property {number} Secondary 16759788 (0xFFCCCC)\n * @property {number} Tertiary 16761760 (0xFFE0A0)\n */\nexports.HolographicStyle = {\n  Primary: 11_127_295,\n  Secondary: 16_759_788,\n  Tertiary: 16_761_760,\n};\n\n/**\n * @typedef {Object} Constants Constants that can be used in an enum or object-like way.\n * @property {number} MaxBulkDeletableMessageAge Max bulk deletable message age\n * @property {SweeperKey[]} SweeperKeys The possible names of items that can be swept in sweepers\n * @property {NonSystemMessageTypes} NonSystemMessageTypes The types of messages that are not deemed a system type\n * @property {TextBasedChannelTypes} TextBasedChannelTypes The types of channels that are text-based\n * @property {ThreadChannelTypes} ThreadChannelTypes The types of channels that are threads\n * @property {VoiceBasedChannelTypes} VoiceBasedChannelTypes The types of channels that are voice-based\n * @property {SelectMenuTypes} SelectMenuTypes The types of components that are select menus.\n * @property {Object} StickerFormatExtensionMap A mapping between sticker formats and their respective image formats.\n * @property {HolographicStyle} HolographicStyle Holographic color values for role styling.\n */\n"
  },
  {
    "path": "packages/discord.js/src/util/DataResolver.js",
    "content": "'use strict';\n\nconst { Buffer } = require('node:buffer');\nconst fs = require('node:fs/promises');\nconst path = require('node:path');\nconst { lazy } = require('@discordjs/util');\nconst { fetch } = require('undici');\nconst { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { BaseInvite } = require('../structures/BaseInvite.js');\n\n// Fixes circular dependencies.\nconst getGuildTemplate = lazy(() => require('../structures/GuildTemplate.js').GuildTemplate);\n\n/**\n * Data that can be resolved to give an invite code. This can be:\n * - An invite code\n * - An invite URL\n *\n * @typedef {string} InviteResolvable\n */\n\n/**\n * Data that can be resolved to give a template code. This can be:\n * - A template code\n * - A template URL\n *\n * @typedef {string} GuildTemplateResolvable\n */\n\n/**\n * Resolves the string to a code based on the passed regex.\n *\n * @param {string} data The string to resolve\n * @param {RegExp} regex The RegExp used to extract the code\n * @returns {string}\n * @private\n */\nfunction resolveCode(data, regex) {\n  return regex.exec(data)?.[1] ?? data;\n}\n\n/**\n * Resolves InviteResolvable to an invite code.\n *\n * @param {InviteResolvable} data The invite resolvable to resolve\n * @returns {string}\n * @private\n */\nfunction resolveInviteCode(data) {\n  return resolveCode(data, BaseInvite.InvitesPattern);\n}\n\n/**\n * Resolves GuildTemplateResolvable to a template code.\n *\n * @param {GuildTemplateResolvable} data The template resolvable to resolve\n * @returns {string}\n * @private\n */\nfunction resolveGuildTemplateCode(data) {\n  return resolveCode(data, getGuildTemplate().GuildTemplatesPattern);\n}\n\n/**\n * Data that can be resolved to give a Buffer. This can be:\n * - A Buffer\n * - The path to a local file\n * - A URL <warn>When provided a URL, discord.js will fetch the URL internally in order to create a Buffer.\n *   This can pose a security risk when the URL has not been sanitized</warn>\n *\n * @typedef {string|Buffer} BufferResolvable\n */\n\n/**\n * @external Stream\n * @see {@link https://nodejs.org/api/stream.html}\n */\n\n/**\n * @typedef {Object} ResolvedFile\n * @property {Buffer} data Buffer containing the file data\n * @property {string} [contentType] Content-Type of the file\n * @private\n */\n\n/**\n * Resolves a BufferResolvable to a Buffer.\n *\n * @param {BufferResolvable|Stream} resource The buffer or stream resolvable to resolve\n * @returns {Promise<ResolvedFile>}\n * @private\n */\nasync function resolveFile(resource) {\n  if (Buffer.isBuffer(resource)) return { data: resource };\n\n  if (typeof resource[Symbol.asyncIterator] === 'function') {\n    const buffers = [];\n    for await (const data of resource) buffers.push(Buffer.from(data));\n    return { data: Buffer.concat(buffers) };\n  }\n\n  if (typeof resource === 'string') {\n    if (/^https?:\\/\\//.test(resource)) {\n      const res = await fetch(resource);\n      return { data: Buffer.from(await res.arrayBuffer()), contentType: res.headers.get('content-type') };\n    }\n\n    const file = path.resolve(resource);\n\n    const stats = await fs.stat(file);\n    if (!stats.isFile()) throw new DiscordjsError(ErrorCodes.FileNotFound, file);\n    return { data: await fs.readFile(file) };\n  }\n\n  throw new DiscordjsTypeError(ErrorCodes.ReqResourceType);\n}\n\n/**\n * Data that resolves to give a Base64 string, typically for image uploading. This can be:\n * - A Buffer\n * - A base64 string\n *\n * @typedef {Buffer|string} Base64Resolvable\n */\n\n/**\n * Resolves a Base64Resolvable to a Base 64 string.\n *\n * @param {Base64Resolvable} data The base 64 resolvable you want to resolve\n * @param {string} [contentType='image/jpg'] The content type of the data\n * @returns {string}\n * @private\n */\nfunction resolveBase64(data, contentType = 'image/jpg') {\n  if (Buffer.isBuffer(data)) return `data:${contentType};base64,${data.toString('base64')}`;\n  return data;\n}\n\n/**\n * Resolves a Base64Resolvable, a string, or a BufferResolvable to a Base 64 image.\n *\n * @param {BufferResolvable|Base64Resolvable} image The image to be resolved\n * @returns {Promise<?string>}\n * @private\n */\nasync function resolveImage(image) {\n  if (!image) return null;\n  if (typeof image === 'string' && image.startsWith('data:')) {\n    return image;\n  }\n\n  const file = await resolveFile(image);\n  return resolveBase64(file.data);\n}\n\nexports.resolveCode = resolveCode;\nexports.resolveInviteCode = resolveInviteCode;\nexports.resolveGuildTemplateCode = resolveGuildTemplateCode;\nexports.resolveImage = resolveImage;\nexports.resolveBase64 = resolveBase64;\nexports.resolveFile = resolveFile;\n"
  },
  {
    "path": "packages/discord.js/src/util/Enums.js",
    "content": "'use strict';\n\nfunction createEnum(keys) {\n  const obj = {};\n  for (const [index, key] of keys.entries()) {\n    if (key === null) continue;\n    obj[key] = index;\n    obj[index] = key;\n  }\n\n  return obj;\n}\n\nexports.createEnum = createEnum;\n"
  },
  {
    "path": "packages/discord.js/src/util/Events.js",
    "content": "'use strict';\n\n/**\n * @typedef {Object} Events\n * @property {string} ApplicationCommandPermissionsUpdate applicationCommandPermissionsUpdate\n * @property {string} AutoModerationActionExecution autoModerationActionExecution\n * @property {string} AutoModerationRuleCreate autoModerationRuleCreate\n * @property {string} AutoModerationRuleDelete autoModerationRuleDelete\n * @property {string} AutoModerationRuleUpdate autoModerationRuleUpdate\n * @property {string} CacheSweep cacheSweep\n * @property {string} ChannelCreate channelCreate\n * @property {string} ChannelDelete channelDelete\n * @property {string} ChannelPinsUpdate channelPinsUpdate\n * @property {string} ChannelUpdate channelUpdate\n * @property {string} ClientReady clientReady\n * @property {string} Debug debug\n * @property {string} EntitlementCreate entitlementCreate\n * @property {string} EntitlementUpdate entitlementUpdate\n * @property {string} EntitlementDelete entitlementDelete\n * @property {string} Error error\n * @property {string} GuildAuditLogEntryCreate guildAuditLogEntryCreate\n * @property {string} GuildAvailable guildAvailable\n * @property {string} GuildBanAdd guildBanAdd\n * @property {string} GuildBanRemove guildBanRemove\n * @property {string} GuildCreate guildCreate\n * @property {string} GuildDelete guildDelete\n * @property {string} GuildEmojiCreate emojiCreate\n * @property {string} GuildEmojiDelete emojiDelete\n * @property {string} GuildEmojiUpdate emojiUpdate\n * @property {string} GuildIntegrationsUpdate guildIntegrationsUpdate\n * @property {string} GuildMemberAdd guildMemberAdd\n * @property {string} GuildMemberAvailable guildMemberAvailable\n * @property {string} GuildMemberRemove guildMemberRemove\n * @property {string} GuildMembersChunk guildMembersChunk\n * @property {string} GuildMemberUpdate guildMemberUpdate\n * @property {string} GuildRoleCreate roleCreate\n * @property {string} GuildRoleDelete roleDelete\n * @property {string} GuildRoleUpdate roleUpdate\n * @property {string} GuildScheduledEventCreate guildScheduledEventCreate\n * @property {string} GuildScheduledEventDelete guildScheduledEventDelete\n * @property {string} GuildScheduledEventUpdate guildScheduledEventUpdate\n * @property {string} GuildScheduledEventUserAdd guildScheduledEventUserAdd\n * @property {string} GuildScheduledEventUserRemove guildScheduledEventUserRemove\n * @property {string} GuildSoundboardSoundCreate guildSoundboardSoundCreate\n * @property {string} GuildSoundboardSoundDelete guildSoundboardSoundDelete\n * @property {string} GuildSoundboardSoundsUpdate guildSoundboardSoundsUpdate\n * @property {string} GuildSoundboardSoundUpdate guildSoundboardSoundUpdate\n * @property {string} GuildStickerCreate stickerCreate\n * @property {string} GuildStickerDelete stickerDelete\n * @property {string} GuildStickerUpdate stickerUpdate\n * @property {string} GuildUnavailable guildUnavailable\n * @property {string} GuildUpdate guildUpdate\n * @property {string} InteractionCreate interactionCreate\n * @property {string} Invalidated invalidated\n * @property {string} InviteCreate inviteCreate\n * @property {string} InviteDelete inviteDelete\n * @property {string} MessageBulkDelete messageDeleteBulk\n * @property {string} MessageCreate messageCreate\n * @property {string} MessageDelete messageDelete\n * @property {string} MessagePollVoteAdd messagePollVoteAdd\n * @property {string} MessagePollVoteRemove messagePollVoteRemove\n * @property {string} MessageReactionAdd messageReactionAdd\n * @property {string} MessageReactionRemove messageReactionRemove\n * @property {string} MessageReactionRemoveAll messageReactionRemoveAll\n * @property {string} MessageReactionRemoveEmoji messageReactionRemoveEmoji\n * @property {string} MessageUpdate messageUpdate\n * @property {string} PresenceUpdate presenceUpdate\n * @property {string} SoundboardSounds soundboardSounds\n * @property {string} StageInstanceCreate stageInstanceCreate\n * @property {string} StageInstanceDelete stageInstanceDelete\n * @property {string} StageInstanceUpdate stageInstanceUpdate\n * @property {string} SubscriptionCreate subscriptionCreate\n * @property {string} SubscriptionUpdate subscriptionUpdate\n * @property {string} SubscriptionDelete subscriptionDelete\n * @property {string} ThreadCreate threadCreate\n * @property {string} ThreadDelete threadDelete\n * @property {string} ThreadListSync threadListSync\n * @property {string} ThreadMembersUpdate threadMembersUpdate\n * @property {string} ThreadMemberUpdate threadMemberUpdate\n * @property {string} ThreadUpdate threadUpdate\n * @property {string} TypingStart typingStart\n * @property {string} UserUpdate userUpdate\n * @property {string} VoiceChannelEffectSend voiceChannelEffectSend\n * @property {string} VoiceServerUpdate voiceServerUpdate\n * @property {string} VoiceStateUpdate voiceStateUpdate\n * @property {string} Warn warn\n * @property {string} WebhooksUpdate webhooksUpdate\n */\n\n// JSDoc for IntelliSense purposes\n/**\n * @type {Events}\n * @ignore\n */\nexports.Events = {\n  ApplicationCommandPermissionsUpdate: 'applicationCommandPermissionsUpdate',\n  AutoModerationActionExecution: 'autoModerationActionExecution',\n  AutoModerationRuleCreate: 'autoModerationRuleCreate',\n  AutoModerationRuleDelete: 'autoModerationRuleDelete',\n  AutoModerationRuleUpdate: 'autoModerationRuleUpdate',\n  CacheSweep: 'cacheSweep',\n  ChannelCreate: 'channelCreate',\n  ChannelDelete: 'channelDelete',\n  ChannelPinsUpdate: 'channelPinsUpdate',\n  ChannelUpdate: 'channelUpdate',\n  ClientReady: 'clientReady',\n  Debug: 'debug',\n  EntitlementCreate: 'entitlementCreate',\n  EntitlementDelete: 'entitlementDelete',\n  EntitlementUpdate: 'entitlementUpdate',\n  Error: 'error',\n  GuildAuditLogEntryCreate: 'guildAuditLogEntryCreate',\n  GuildAvailable: 'guildAvailable',\n  GuildBanAdd: 'guildBanAdd',\n  GuildBanRemove: 'guildBanRemove',\n  GuildCreate: 'guildCreate',\n  GuildDelete: 'guildDelete',\n  GuildEmojiCreate: 'emojiCreate',\n  GuildEmojiDelete: 'emojiDelete',\n  GuildEmojiUpdate: 'emojiUpdate',\n  GuildIntegrationsUpdate: 'guildIntegrationsUpdate',\n  GuildMemberAdd: 'guildMemberAdd',\n  GuildMemberAvailable: 'guildMemberAvailable',\n  GuildMemberRemove: 'guildMemberRemove',\n  GuildMembersChunk: 'guildMembersChunk',\n  GuildMemberUpdate: 'guildMemberUpdate',\n  GuildRoleCreate: 'roleCreate',\n  GuildRoleDelete: 'roleDelete',\n  GuildRoleUpdate: 'roleUpdate',\n  GuildScheduledEventCreate: 'guildScheduledEventCreate',\n  GuildScheduledEventDelete: 'guildScheduledEventDelete',\n  GuildScheduledEventUpdate: 'guildScheduledEventUpdate',\n  GuildScheduledEventUserAdd: 'guildScheduledEventUserAdd',\n  GuildScheduledEventUserRemove: 'guildScheduledEventUserRemove',\n  GuildSoundboardSoundCreate: 'guildSoundboardSoundCreate',\n  GuildSoundboardSoundDelete: 'guildSoundboardSoundDelete',\n  GuildSoundboardSoundsUpdate: 'guildSoundboardSoundsUpdate',\n  GuildSoundboardSoundUpdate: 'guildSoundboardSoundUpdate',\n  GuildStickerCreate: 'stickerCreate',\n  GuildStickerDelete: 'stickerDelete',\n  GuildStickerUpdate: 'stickerUpdate',\n  GuildUnavailable: 'guildUnavailable',\n  GuildUpdate: 'guildUpdate',\n  InteractionCreate: 'interactionCreate',\n  Invalidated: 'invalidated',\n  InviteCreate: 'inviteCreate',\n  InviteDelete: 'inviteDelete',\n  MessageBulkDelete: 'messageDeleteBulk',\n  MessageCreate: 'messageCreate',\n  MessageDelete: 'messageDelete',\n  MessagePollVoteAdd: 'messagePollVoteAdd',\n  MessagePollVoteRemove: 'messagePollVoteRemove',\n  MessageReactionAdd: 'messageReactionAdd',\n  MessageReactionRemove: 'messageReactionRemove',\n  MessageReactionRemoveAll: 'messageReactionRemoveAll',\n  MessageReactionRemoveEmoji: 'messageReactionRemoveEmoji',\n  MessageUpdate: 'messageUpdate',\n  PresenceUpdate: 'presenceUpdate',\n  SoundboardSounds: 'soundboardSounds',\n  StageInstanceCreate: 'stageInstanceCreate',\n  StageInstanceDelete: 'stageInstanceDelete',\n  StageInstanceUpdate: 'stageInstanceUpdate',\n  SubscriptionCreate: 'subscriptionCreate',\n  SubscriptionDelete: 'subscriptionDelete',\n  SubscriptionUpdate: 'subscriptionUpdate',\n  ThreadCreate: 'threadCreate',\n  ThreadDelete: 'threadDelete',\n  ThreadListSync: 'threadListSync',\n  ThreadMembersUpdate: 'threadMembersUpdate',\n  ThreadMemberUpdate: 'threadMemberUpdate',\n  ThreadUpdate: 'threadUpdate',\n  TypingStart: 'typingStart',\n  UserUpdate: 'userUpdate',\n  VoiceChannelEffectSend: 'voiceChannelEffectSend',\n  VoiceServerUpdate: 'voiceServerUpdate',\n  VoiceStateUpdate: 'voiceStateUpdate',\n  Warn: 'warn',\n  WebhooksUpdate: 'webhooksUpdate',\n};\n"
  },
  {
    "path": "packages/discord.js/src/util/GuildMemberFlagsBitField.js",
    "content": "/* eslint-disable jsdoc/check-values */\n'use strict';\n\nconst { GuildMemberFlags } = require('discord-api-types/v10');\nconst { BitField } = require('./BitField.js');\n\n/**\n * Data structure that makes it easy to interact with a {@link GuildMember#flags} bitfield.\n *\n * @extends {BitField}\n */\nclass GuildMemberFlagsBitField extends BitField {\n  /**\n   * Numeric guild member flags.\n   *\n   * @type {GuildMemberFlags}\n   * @memberof GuildMemberFlagsBitField\n   */\n  static Flags = GuildMemberFlags;\n}\n\n/**\n * @name GuildMemberFlagsBitField\n * @kind constructor\n * @memberof GuildMemberFlagsBitField\n * @param {BitFieldResolvable} [bits=0] Bit(s) to read from\n */\n\n/**\n * Bitfield of the packed bits\n *\n * @type {number}\n * @name GuildMemberFlagsBitField#bitfield\n */\n\n/**\n * Data that can be resolved to give a guild member flag bitfield. This can be:\n * - A string (see {@link GuildMemberFlagsBitField.Flags})\n * - A guild member flag\n * - An instance of GuildMemberFlagsBitField\n * - An Array of GuildMemberFlagsResolvable\n *\n * @typedef {string|number|GuildMemberFlagsBitField|GuildMemberFlagsResolvable[]} GuildMemberFlagsResolvable\n */\n\nexports.GuildMemberFlagsBitField = GuildMemberFlagsBitField;\n"
  },
  {
    "path": "packages/discord.js/src/util/IntentsBitField.js",
    "content": "/* eslint-disable jsdoc/check-values */\n'use strict';\nconst { GatewayIntentBits } = require('discord-api-types/v10');\nconst { BitField } = require('./BitField.js');\n\n/**\n * Data structure that makes it easy to calculate intents.\n *\n * @extends {BitField}\n */\nclass IntentsBitField extends BitField {\n  /**\n   * Numeric WebSocket intents\n   *\n   * @type {GatewayIntentBits}\n   * @memberof IntentsBitField\n   */\n  static Flags = GatewayIntentBits;\n}\n\n/**\n * @name IntentsBitField\n * @kind constructor\n * @memberof IntentsBitField\n * @param {IntentsResolvable} [bits=0] Bit(s) to read from\n */\n\n/**\n * Data that can be resolved to give a permission number. This can be:\n * - A string (see {@link IntentsBitField.Flags})\n * - An intents flag\n * - An instance of {@link IntentsBitField}\n * - An array of IntentsResolvable\n *\n * @typedef {string|number|IntentsBitField|IntentsResolvable[]} IntentsResolvable\n */\n\nexports.IntentsBitField = IntentsBitField;\n"
  },
  {
    "path": "packages/discord.js/src/util/InviteFlagsBitField.js",
    "content": "/* eslint-disable jsdoc/check-values */\n'use strict';\n\nconst { InviteFlags } = require('discord-api-types/v10');\nconst { BitField } = require('./BitField.js');\n\n/**\n * Data structure that makes it easy to interact with a {@link GuildInvite#flags} bit field.\n *\n * @extends {BitField}\n */\nclass InviteFlagsBitField extends BitField {\n  /**\n   * Numeric invite flags.\n   *\n   * @type {InviteFlags}\n   * @memberof InviteFlagsBitField\n   */\n  static Flags = InviteFlags;\n}\n\n/**\n * @name InviteFlagsBitField\n * @kind constructor\n * @memberof InviteFlagsBitField\n * @param {BitFieldResolvable} [bits=0] Bit(s) to read from\n */\n\nexports.InviteFlagsBitField = InviteFlagsBitField;\n"
  },
  {
    "path": "packages/discord.js/src/util/Invites.js",
    "content": "'use strict';\n\nconst { InviteType } = require('discord-api-types/v10');\nconst { BaseInvite } = require('../structures/BaseInvite.js');\nconst { GroupDMInvite } = require('../structures/GroupDMInvite.js');\nconst { GuildInvite } = require('../structures/GuildInvite.js');\n\n/**\n * Any invite.\n *\n * @typedef {GuildInvite|GroupDMInvite} Invite\n */\n\nconst InviteTypeToClass = {\n  [InviteType.Guild]: GuildInvite,\n  [InviteType.GroupDM]: GroupDMInvite,\n};\n\n/**\n * Creates an invite.\n *\n * @param {Client} client The client\n * @param {Object} data The data\n * @returns {BaseInvite}\n * @ignore\n */\nfunction createInvite(client, data) {\n  return new (InviteTypeToClass[data.type] ?? BaseInvite)(client, data);\n}\n\nexports.createInvite = createInvite;\n"
  },
  {
    "path": "packages/discord.js/src/util/LimitedCollection.js",
    "content": "'use strict';\n\nconst { Collection } = require('@discordjs/collection');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\n\n/**\n * Options for defining the behavior of a LimitedCollection\n *\n * @typedef {Object} LimitedCollectionOptions\n * @property {?number} [maxSize=Infinity] The maximum size of the Collection\n * @property {?Function} [keepOverLimit=null] A function, which is passed the value and key of an entry, ran to decide\n * to keep an entry past the maximum size\n */\n\n/**\n * A Collection which holds a max amount of entries.\n *\n * @extends {Collection}\n * @param {LimitedCollectionOptions} [options={}] Options for constructing the Collection.\n * @param {Iterable} [iterable=null] Optional entries passed to the Map constructor.\n */\nclass LimitedCollection extends Collection {\n  constructor(options = {}, iterable = undefined) {\n    if (typeof options !== 'object' || options === null) {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options', 'object', true);\n    }\n\n    const { maxSize = Infinity, keepOverLimit = null } = options;\n\n    if (typeof maxSize !== 'number') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'maxSize', 'number');\n    }\n\n    if (keepOverLimit !== null && typeof keepOverLimit !== 'function') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'keepOverLimit', 'function');\n    }\n\n    super(iterable);\n\n    /**\n     * The max size of the Collection.\n     *\n     * @type {number}\n     */\n    this.maxSize = maxSize;\n\n    /**\n     * A function called to check if an entry should be kept when the Collection is at max size.\n     *\n     * @type {?Function}\n     */\n    this.keepOverLimit = keepOverLimit;\n  }\n\n  set(key, value) {\n    if (this.maxSize === 0 && !this.keepOverLimit?.(value, key, this)) return this;\n    if (this.size >= this.maxSize && !this.has(key)) {\n      for (const [iteratedKey, iteratedValue] of this.entries()) {\n        const keep = this.keepOverLimit?.(iteratedValue, iteratedKey, this) ?? false;\n        if (!keep) {\n          this.delete(iteratedKey);\n          break;\n        }\n      }\n    }\n\n    return super.set(key, value);\n  }\n\n  static get [Symbol.species]() {\n    return Collection;\n  }\n}\n\nexports.LimitedCollection = LimitedCollection;\n"
  },
  {
    "path": "packages/discord.js/src/util/MessageFlagsBitField.js",
    "content": "/* eslint-disable jsdoc/check-values */\n'use strict';\n\nconst { MessageFlags } = require('discord-api-types/v10');\nconst { BitField } = require('./BitField.js');\n\n/**\n * Data structure that makes it easy to interact with a {@link Message#flags} bitfield.\n *\n * @extends {BitField}\n */\nclass MessageFlagsBitField extends BitField {\n  /**\n   * Numeric message flags.\n   *\n   * @type {MessageFlags}\n   * @memberof MessageFlagsBitField\n   */\n  static Flags = MessageFlags;\n}\n\n/**\n * @name MessageFlagsBitField\n * @kind constructor\n * @memberof MessageFlagsBitField\n * @param {BitFieldResolvable} [bits=0] Bit(s) to read from\n */\n\n/**\n * Data that can be resolved to give a message flags bit field. This can be:\n * - A string (see {@link MessageFlagsBitField.Flags})\n * - A message flag\n * - An instance of {@link MessageFlagsBitField}\n * - An array of `MessageFlagsResolvable`\n *\n * @typedef {string|number|MessageFlagsBitField|MessageFlagsResolvable[]} MessageFlagsResolvable\n */\n\n/**\n * Bitfield of the packed bits\n *\n * @type {number}\n * @name MessageFlagsBitField#bitfield\n */\n\nexports.MessageFlagsBitField = MessageFlagsBitField;\n"
  },
  {
    "path": "packages/discord.js/src/util/Options.js",
    "content": "'use strict';\n\nconst { DefaultRestOptions, DefaultUserAgentAppendix } = require('@discordjs/rest');\nconst { DefaultWebSocketManagerOptions } = require('@discordjs/ws');\nconst { version } = require('../../package.json');\nconst { toSnakeCase } = require('./Transformers.js');\n\n/**\n * @typedef {Object} CacheFactoryParams\n * @property {Function} holds The class that the cache will hold.\n * @property {Function} manager The fully extended manager class the cache is being requested from.\n * @property {Function} managerType The base manager class the cache is being requested from.\n */\n\n/**\n * @typedef {Function} CacheFactory\n * @param {CacheFactoryParams} params The parameters\n * @returns {Collection} A Collection used to store the cache of the manager.\n */\n\n/**\n * Options for a client.\n *\n * @typedef {Object} ClientOptions\n * @property {number} [closeTimeout=5_000] The amount of time in milliseconds to wait for the close frame to be received\n * from the WebSocket. Don't have this too high/low. It's best to have it between 2_000-6_000 ms.\n * @property {CacheFactory} [makeCache] Function to create a cache.\n * You can use your own function, or the {@link Options} class to customize the Collection used for the cache.\n * <warn>Overriding the cache used in `GuildManager`, `ChannelManager`, `GuildChannelManager`, `RoleManager`,\n * and `PermissionOverwriteManager` is unsupported and **will** break functionality</warn>\n * @property {MessageMentionOptions} [allowedMentions] The default value for {@link BaseMessageOptions#allowedMentions}\n * @property {Partials[]} [partials] Structures allowed to be partial. This means events can be emitted even when\n * they're missing all the data for a particular structure. See the \"Partial Structures\" topic on the\n * {@link https://discordjs.guide/popular-topics/partials.html guide} for some\n * important usage information, as partials require you to put checks in place when handling data.\n * @property {boolean} [failIfNotExists=true] The default value for {@link MessageReplyOptions#failIfNotExists}\n * @property {PresenceData} [presence] Presence data to use upon login\n * @property {IntentsResolvable} intents Intents to enable for this connection\n * @property {number} [waitGuildTimeout=15_000] Time in milliseconds that clients with the\n * {@link GatewayIntentBits.Guilds} gateway intent should wait for missing guilds to be received before being ready.\n * @property {SweeperOptions} [sweepers=this.DefaultSweeperSettings] Options for cache sweeping\n * @property {WebSocketManagerOptions} [ws] Options for the WebSocketManager\n * @property {RESTOptions} [rest] Options for the REST manager\n * @property {Function} [jsonTransformer] A function used to transform outgoing json data\n * @property {boolean} [enforceNonce=false] The default value for {@link MessageCreateOptions#enforceNonce}\n */\n\n/**\n * Options for {@link Sweepers} defining the behavior of cache sweeping\n *\n * @typedef {Object<SweeperKey, SweepOptions>} SweeperOptions\n */\n\n/**\n * Options for sweeping a single type of item from cache\n *\n * @typedef {Object} SweepOptions\n * @property {number} interval The interval (in seconds) at which to perform sweeping of the item\n * @property {number} [lifetime] How long an item should stay in cache until it is considered sweepable.\n * <warn>This property is only valid for the `invites`, `messages`, and `threads` keys. The `filter` property\n * is mutually exclusive to this property and takes priority</warn>\n * @property {GlobalSweepFilter} filter The function used to determine the function passed to the sweep method\n * <info>This property is optional when the key is `invites`, `messages`, or `threads` and `lifetime` is set</info>\n */\n\n/**\n * Contains various utilities for client options.\n */\nclass Options extends null {\n  /**\n   * The default user agent appendix.\n   *\n   * @type {string}\n   * @memberof Options\n   * @private\n   */\n  static userAgentAppendix = `discord.js/${version} ${DefaultUserAgentAppendix}`.trimEnd();\n\n  /**\n   * The default client options.\n   *\n   * @returns {ClientOptions}\n   */\n  static createDefault() {\n    return {\n      closeTimeout: 5_000,\n      waitGuildTimeout: 15_000,\n      makeCache: this.cacheWithLimits(this.DefaultMakeCacheSettings),\n      partials: [],\n      failIfNotExists: true,\n      enforceNonce: false,\n      sweepers: this.DefaultSweeperSettings,\n      ws: {\n        ...DefaultWebSocketManagerOptions,\n        largeThreshold: 50,\n        version: 10,\n      },\n      rest: {\n        ...DefaultRestOptions,\n        userAgentAppendix: this.userAgentAppendix,\n      },\n      jsonTransformer: toSnakeCase,\n    };\n  }\n\n  /**\n   * Create a cache factory using predefined settings to sweep or limit.\n   *\n   * @param {Object<string, LimitedCollectionOptions|number>} [settings={}] Settings passed to the relevant constructor.\n   * If no setting is provided for a manager, it uses Collection.\n   * If a number is provided for a manager, it uses that number as the max size for a LimitedCollection.\n   * If LimitedCollectionOptions are provided for a manager, it uses those settings to form a LimitedCollection.\n   * @returns {CacheFactory}\n   * @example\n   * // Store up to 200 messages per channel and 200 members per guild, always keeping the client member.\n   * Options.cacheWithLimits({\n   *    MessageManager: 200,\n   *    GuildMemberManager: {\n   *      maxSize: 200,\n   *      keepOverLimit: (member) => member.id === client.user.id,\n   *    },\n   *  });\n   */\n  static cacheWithLimits(settings = {}) {\n    const { Collection } = require('@discordjs/collection');\n    const { LimitedCollection } = require('./LimitedCollection.js');\n\n    return ({ managerType, manager }) => {\n      const setting = settings[manager.name] ?? settings[managerType.name];\n      /* eslint-disable-next-line eqeqeq */\n      if (setting == null) {\n        return new Collection();\n      }\n\n      if (typeof setting === 'number') {\n        if (setting === Infinity) {\n          return new Collection();\n        }\n\n        return new LimitedCollection({ maxSize: setting });\n      }\n\n      /* eslint-disable-next-line eqeqeq */\n      const noLimit = setting.maxSize == null || setting.maxSize === Infinity;\n      if (noLimit) {\n        return new Collection();\n      }\n\n      return new LimitedCollection(setting);\n    };\n  }\n\n  /**\n   * Create a cache factory that always caches everything.\n   *\n   * @returns {CacheFactory}\n   */\n  static cacheEverything() {\n    const { Collection } = require('@discordjs/collection');\n    return () => new Collection();\n  }\n\n  /**\n   * The default settings passed to {@link ClientOptions.makeCache}.\n   * The caches that this changes are:\n   * - `MessageManager` - Limit to 200 messages\n   * <info>If you want to keep default behavior and add on top of it you can use this object and add on to it, e.g.\n   * `makeCache: Options.cacheWithLimits({ ...Options.DefaultMakeCacheSettings, ReactionManager: 0 })`</info>\n   *\n   * @type {Object<string, LimitedCollectionOptions|number>}\n   */\n  static get DefaultMakeCacheSettings() {\n    return {\n      MessageManager: 200,\n    };\n  }\n\n  /**\n   * The default settings passed to {@link ClientOptions.sweepers}.\n   * The sweepers that this changes are:\n   * - `threads` - Sweep archived threads every hour, removing those archived more than 4 hours ago\n   * <info>If you want to keep default behavior and add on top of it you can use this object and add on to it, e.g.\n   * `sweepers: { ...Options.DefaultSweeperSettings, messages: { interval: 300, lifetime: 600 } }`</info>\n   *\n   * @type {SweeperOptions}\n   */\n  static get DefaultSweeperSettings() {\n    return {\n      threads: {\n        interval: 3_600,\n        lifetime: 14_400,\n      },\n    };\n  }\n}\n\nexports.Options = Options;\n\n/**\n * @external RESTOptions\n * @see {@link https://discord.js.org/docs/packages/rest/stable/RESTOptions:Interface}\n */\n\n/**\n * @external WebSocketManager\n * @see {@link https://discord.js.org/docs/packages/ws/stable/WebSocketManager:Class}\n */\n\n/**\n * @external IShardingStrategy\n * @see {@link https://discord.js.org/docs/packages/ws/stable/IShardingStrategy:Interface}\n */\n\n/**\n * @external IIdentifyThrottler\n * @see {@link https://discord.js.org/docs/packages/ws/stable/IIdentifyThrottler:Interface}\n */\n"
  },
  {
    "path": "packages/discord.js/src/util/Partials.js",
    "content": "'use strict';\n\nconst { createEnum } = require('./Enums.js');\n\n/**\n * The enumeration for partials.\n * ```js\n * import { Client, Partials } from 'discord.js';\n *\n * const client = new Client({\n *   intents: [\n *     // Intents...\n *   ],\n *   partials: [\n *     Partials.User, // We want to receive uncached users!\n *     Partials.Message // We want to receive uncached messages!\n *   ]\n * });\n * ```\n *\n * @typedef {Object} Partials\n * @property {number} User The partial to receive uncached users.\n * @property {number} Channel The partial to receive uncached channels.\n * <info>This is required to receive direct messages!</info>\n * @property {number} GuildMember The partial to receive uncached guild members.\n * @property {number} Message The partial to receive uncached messages.\n * @property {number} Reaction The partial to receive uncached reactions.\n * @property {number} GuildScheduledEvent The partial to receive uncached guild scheduled events.\n * @property {number} ThreadMember The partial to receive uncached thread members.\n * @property {number} Poll The partial to receive uncached polls.\n * @property {number} PollAnswer The partial to receive uncached poll answers.\n * @property {number} SoundboardSound The partial to receive uncached soundboard sounds.\n */\n\n// JSDoc for IntelliSense purposes\n/**\n * @type {Partials}\n * @ignore\n */\nexports.Partials = createEnum([\n  'User',\n  'Channel',\n  'GuildMember',\n  'Message',\n  'Reaction',\n  'GuildScheduledEvent',\n  'ThreadMember',\n  'Poll',\n  'PollAnswer',\n  'SoundboardSound',\n]);\n"
  },
  {
    "path": "packages/discord.js/src/util/PermissionsBitField.js",
    "content": "'use strict';\n\nconst { PermissionFlagsBits } = require('discord-api-types/v10');\nconst { BitField } = require('./BitField.js');\n\n/**\n * Data structure that makes it easy to interact with a permission bitfield. All {@link GuildMember}s have a set of\n * permissions in their guild, and each channel in the guild may also have {@link PermissionOverwrites} for the member\n * that override their default permissions.\n *\n * @extends {BitField}\n */\nclass PermissionsBitField extends BitField {\n  /**\n   * Numeric permission flags.\n   *\n   * @type {PermissionFlagsBits}\n   * @memberof PermissionsBitField\n   * @see {@link https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags}\n   */\n  static Flags = PermissionFlagsBits;\n\n  /**\n   * Bitfield representing every permission combined\n   *\n   * @type {bigint}\n   * @memberof PermissionsBitField\n   */\n\n  // eslint-disable-next-line unicorn/consistent-function-scoping\n  static All = Object.values(PermissionFlagsBits).reduce((all, perm) => all | perm, 0n);\n\n  /**\n   * Bitfield representing the default permissions for users\n   *\n   * @type {bigint}\n   * @memberof PermissionsBitField\n   */\n  static Default = BigInt(104_324_673);\n\n  /**\n   * Bitfield representing the permissions required for moderators of stage channels\n   *\n   * @type {bigint}\n   * @memberof PermissionsBitField\n   */\n  static StageModerator =\n    PermissionFlagsBits.ManageChannels | PermissionFlagsBits.MuteMembers | PermissionFlagsBits.MoveMembers;\n\n  /**\n   * @type {bigint}\n   * @memberof PermissionsBitField\n   * @private\n   */\n  static DefaultBit = BigInt(0);\n\n  /**\n   * Bitfield of the packed bits\n   *\n   * @type {bigint}\n   * @name PermissionsBitField#bitfield\n   */\n\n  /**\n   * Data that can be resolved to give a permission number. This can be:\n   * - A string (see {@link PermissionsBitField.Flags})\n   * - A permission number\n   * - An instance of {@link PermissionsBitField}\n   * - An Array of PermissionResolvable\n   *\n   * @typedef {string|bigint|PermissionsBitField|PermissionResolvable[]} PermissionResolvable\n   */\n\n  /**\n   * Gets all given bits that are missing from the bitfield.\n   *\n   * @param {BitFieldResolvable} bits Bit(s) to check for\n   * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override\n   * @returns {string[]}\n   */\n  missing(bits, checkAdmin = true) {\n    return checkAdmin && this.has(PermissionFlagsBits.Administrator) ? [] : super.missing(bits);\n  }\n\n  /**\n   * Checks whether the bitfield has a permission, or any of multiple permissions.\n   *\n   * @param {PermissionResolvable} permission Permission(s) to check for\n   * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override\n   * @returns {boolean}\n   */\n  any(permission, checkAdmin = true) {\n    return (checkAdmin && super.has(PermissionFlagsBits.Administrator)) || super.any(permission);\n  }\n\n  /**\n   * Checks whether the bitfield has a permission, or multiple permissions.\n   *\n   * @param {PermissionResolvable} permission Permission(s) to check for\n   * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override\n   * @returns {boolean}\n   */\n  has(permission, checkAdmin = true) {\n    return (checkAdmin && super.has(PermissionFlagsBits.Administrator)) || super.has(permission);\n  }\n\n  /**\n   * Gets an {@link Array} of bitfield names based on the permissions available.\n   *\n   * @returns {string[]}\n   */\n  toArray() {\n    return super.toArray(false);\n  }\n}\n\nexports.PermissionsBitField = PermissionsBitField;\n"
  },
  {
    "path": "packages/discord.js/src/util/RoleFlagsBitField.js",
    "content": "/* eslint-disable jsdoc/check-values */\n'use strict';\n\nconst { RoleFlags } = require('discord-api-types/v10');\nconst { BitField } = require('./BitField.js');\n\n/**\n * Data structure that makes it easy to interact with a {@link Role#flags} bitfield.\n *\n * @extends {BitField}\n */\nclass RoleFlagsBitField extends BitField {\n  /**\n   * Numeric role flags.\n   *\n   * @type {RoleFlags}\n   * @memberof RoleFlagsBitField\n   */\n  static Flags = RoleFlags;\n}\n\n/**\n * @name RoleFlagsBitField\n * @kind constructor\n * @memberof RoleFlagsBitField\n * @param {BitFieldResolvable} [bits=0] Bit(s) to read from\n */\n\nexports.RoleFlagsBitField = RoleFlagsBitField;\n"
  },
  {
    "path": "packages/discord.js/src/util/SKUFlagsBitField.js",
    "content": "/* eslint-disable jsdoc/check-values */\n'use strict';\n\nconst { SKUFlags } = require('discord-api-types/v10');\nconst { BitField } = require('./BitField.js');\n\n/**\n * Data structure that makes it easy to interact with an {@link SKU#flags} bitfield.\n *\n * @extends {BitField}\n */\nclass SKUFlagsBitField extends BitField {\n  /**\n   * Numeric SKU flags.\n   *\n   * @type {SKUFlags}\n   * @memberof SKUFlagsBitField\n   */\n  static Flags = SKUFlags;\n}\n\n/**\n * @name SKUFlagsBitField\n * @kind constructor\n * @memberof SKUFlagsBitField\n * @param {BitFieldResolvable} [bits=0] Bit(s) to read from\n */\n\nexports.SKUFlagsBitField = SKUFlagsBitField;\n"
  },
  {
    "path": "packages/discord.js/src/util/ShardEvents.js",
    "content": "'use strict';\n\n/**\n * @typedef {Object} ShardEvents\n * @property {string} Death death\n * @property {string} Disconnect disconnect\n * @property {string} Error error\n * @property {string} Message message\n * @property {string} Ready ready\n * @property {string} Resume resume\n * @property {string} Spawn spawn\n */\n\n// JSDoc for IntelliSense purposes\n/**\n * @type {ShardEvents}\n * @ignore\n */\nexports.ShardEvents = {\n  Death: 'death',\n  Disconnect: 'disconnect',\n  Error: 'error',\n  Message: 'message',\n  Ready: 'ready',\n  Resume: 'resume',\n  Spawn: 'spawn',\n};\n"
  },
  {
    "path": "packages/discord.js/src/util/Status.js",
    "content": "'use strict';\n\nconst { createEnum } = require('./Enums.js');\n\n/**\n * @typedef {Object} Status\n * @property {number} Ready ready\n * @property {number} Idle idle\n * @property {number} WaitingForGuilds waiting for guilds\n */\n\n// JSDoc for IntelliSense purposes\n/**\n * @type {Status}\n * @ignore\n */\nexports.Status = createEnum(['Ready', 'Idle', 'WaitingForGuilds']);\n"
  },
  {
    "path": "packages/discord.js/src/util/Sweepers.js",
    "content": "'use strict';\n\nconst { setInterval, clearInterval } = require('node:timers');\nconst { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\nconst { ThreadChannelTypes, SweeperKeys } = require('./Constants.js');\nconst { Events } = require('./Events.js');\n\n/**\n * @typedef {Function} GlobalSweepFilter\n * @returns {?Function} Return `null` to skip sweeping, otherwise a function passed to `sweep()`,\n * See {@link https://discord.js.org/docs/packages/collection/stable/Collection:Class#sweep Collection#sweep}\n * for the definition of this function.\n */\n\n/**\n * A container for all cache sweeping intervals and their associated sweep methods.\n */\nclass Sweepers {\n  constructor(client, options) {\n    /**\n     * The client that instantiated this\n     *\n     * @type {Client}\n     * @readonly\n     */\n    Object.defineProperty(this, 'client', { value: client });\n\n    /**\n     * The options the sweepers were instantiated with\n     *\n     * @type {SweeperOptions}\n     */\n    this.options = options;\n\n    /**\n     * A record of interval timeout that is used to sweep the indicated items, or null if not being swept\n     *\n     * @type {Object<SweeperKey, ?Timeout>}\n     */\n    this.intervals = Object.fromEntries(SweeperKeys.map(key => [key, null]));\n\n    for (const key of SweeperKeys) {\n      if (!(key in options)) continue;\n\n      this._validateProperties(key);\n\n      const clonedOptions = { ...this.options[key] };\n\n      // Handle cases that have a \"lifetime\"\n      if (!('filter' in clonedOptions)) {\n        switch (key) {\n          case 'invites':\n            clonedOptions.filter = this.constructor.expiredInviteSweepFilter(clonedOptions.lifetime);\n            break;\n          case 'messages':\n            clonedOptions.filter = this.constructor.outdatedMessageSweepFilter(clonedOptions.lifetime);\n            break;\n          case 'threads':\n            clonedOptions.filter = this.constructor.archivedThreadSweepFilter(clonedOptions.lifetime);\n            break;\n          default:\n            break;\n        }\n      }\n\n      this._initInterval(key, `sweep${key[0].toUpperCase()}${key.slice(1)}`, clonedOptions);\n    }\n  }\n\n  /**\n   * Sweeps all guild and global application commands and removes the ones which are indicated by the filter.\n   *\n   * @param {Function} filter The function used to determine which commands will be removed from the caches.\n   * @returns {number} Amount of commands that were removed from the caches\n   */\n  sweepApplicationCommands(filter) {\n    const { guilds, items: guildCommands } = this._sweepGuildDirectProp('commands', filter, { emit: false });\n\n    const globalCommands = this.client.application?.commands.cache.sweep(filter) ?? 0;\n\n    this.client.emit(\n      Events.CacheSweep,\n      `Swept ${globalCommands} global application commands and ${guildCommands} guild commands in ${guilds} guilds.`,\n    );\n    return guildCommands + globalCommands;\n  }\n\n  /**\n   * Sweeps all auto moderation rules and removes the ones which are indicated by the filter.\n   *\n   * @param {Function} filter The function used to determine\n   * which auto moderation rules will be removed from the caches\n   * @returns {number} Amount of auto moderation rules that were removed from the caches\n   */\n  sweepAutoModerationRules(filter) {\n    return this._sweepGuildDirectProp('autoModerationRules', filter).items;\n  }\n\n  /**\n   * Sweeps all guild bans and removes the ones which are indicated by the filter.\n   *\n   * @param {Function} filter The function used to determine which bans will be removed from the caches.\n   * @returns {number} Amount of bans that were removed from the caches\n   */\n  sweepBans(filter) {\n    return this._sweepGuildDirectProp('bans', filter).items;\n  }\n\n  /**\n   * Sweeps all guild emojis and removes the ones which are indicated by the filter.\n   *\n   * @param {Function} filter The function used to determine which emojis will be removed from the caches.\n   * @returns {number} Amount of emojis that were removed from the caches\n   */\n  sweepEmojis(filter) {\n    return this._sweepGuildDirectProp('emojis', filter).items;\n  }\n\n  /**\n   * Sweeps all client application entitlements and removes the ones which are indicated by the filter.\n   *\n   * @param {Function} filter The function used to determine which entitlements will be removed from the caches.\n   * @returns {number} Amount of entitlements that were removed from the caches\n   */\n  sweepEntitlements(filter) {\n    if (typeof filter !== 'function') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function');\n    }\n\n    const entitlements = this.client.application.entitlements.cache.sweep(filter);\n\n    this.client.emit(Events.CacheSweep, `Swept ${entitlements} entitlements.`);\n\n    return entitlements;\n  }\n\n  /**\n   * Sweeps all guild invites and removes the ones which are indicated by the filter.\n   *\n   * @param {Function} filter The function used to determine which invites will be removed from the caches.\n   * @returns {number} Amount of invites that were removed from the caches\n   */\n  sweepInvites(filter) {\n    return this._sweepGuildDirectProp('invites', filter).items;\n  }\n\n  /**\n   * Sweeps all guild members and removes the ones which are indicated by the filter.\n   * <info>It is highly recommended to keep the client guild member cached</info>\n   *\n   * @param {Function} filter The function used to determine which guild members will be removed from the caches.\n   * @returns {number} Amount of guild members that were removed from the caches\n   */\n  sweepGuildMembers(filter) {\n    return this._sweepGuildDirectProp('members', filter, { outputName: 'guild members' }).items;\n  }\n\n  /**\n   * Sweeps all text-based channels' messages and removes the ones which are indicated by the filter.\n   *\n   * @param {Function} filter The function used to determine which messages will be removed from the caches.\n   * @returns {number} Amount of messages that were removed from the caches\n   * @example\n   * // Remove all messages older than 1800 seconds from the messages cache\n   * const amount = sweepers.sweepMessages(\n   *   Sweepers.filterByLifetime({\n   *     lifetime: 1800,\n   *     getComparisonTimestamp: m => m.editedTimestamp ?? m.createdTimestamp,\n   *   })(),\n   * );\n   * console.log(`Successfully removed ${amount} messages from the cache.`);\n   */\n  sweepMessages(filter) {\n    if (typeof filter !== 'function') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function');\n    }\n\n    let channels = 0;\n    let messages = 0;\n\n    for (const channel of this.client.channels.cache.values()) {\n      if (!channel.isTextBased()) continue;\n\n      channels++;\n      messages += channel.messages.cache.sweep(filter);\n    }\n\n    this.client.emit(Events.CacheSweep, `Swept ${messages} messages in ${channels} text-based channels.`);\n    return messages;\n  }\n\n  /**\n   * Sweeps all presences and removes the ones which are indicated by the filter.\n   *\n   * @param {Function} filter The function used to determine which presences will be removed from the caches.\n   * @returns {number} Amount of presences that were removed from the caches\n   */\n  sweepPresences(filter) {\n    return this._sweepGuildDirectProp('presences', filter).items;\n  }\n\n  /**\n   * Sweeps all message reactions and removes the ones which are indicated by the filter.\n   *\n   * @param {Function} filter The function used to determine which reactions will be removed from the caches.\n   * @returns {number} Amount of reactions that were removed from the caches\n   */\n  sweepReactions(filter) {\n    if (typeof filter !== 'function') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function');\n    }\n\n    let channels = 0;\n    let messages = 0;\n    let reactions = 0;\n\n    for (const channel of this.client.channels.cache.values()) {\n      if (!channel.isTextBased()) continue;\n      channels++;\n\n      for (const message of channel.messages.cache.values()) {\n        messages++;\n        reactions += message.reactions.cache.sweep(filter);\n      }\n    }\n\n    this.client.emit(\n      Events.CacheSweep,\n      `Swept ${reactions} reactions on ${messages} messages in ${channels} text-based channels.`,\n    );\n    return reactions;\n  }\n\n  /**\n   * Sweeps all guild stage instances and removes the ones which are indicated by the filter.\n   *\n   * @param {Function} filter The function used to determine which stage instances will be removed from the caches.\n   * @returns {number} Amount of stage instances that were removed from the caches\n   */\n  sweepStageInstances(filter) {\n    return this._sweepGuildDirectProp('stageInstances', filter, { outputName: 'stage instances' }).items;\n  }\n\n  /**\n   * Sweeps all guild stickers and removes the ones which are indicated by the filter.\n   *\n   * @param {Function} filter The function used to determine which stickers will be removed from the caches.\n   * @returns {number} Amount of stickers that were removed from the caches\n   */\n  sweepStickers(filter) {\n    return this._sweepGuildDirectProp('stickers', filter).items;\n  }\n\n  /**\n   * Sweeps all thread members and removes the ones which are indicated by the filter.\n   * <info>It is highly recommended to keep the client thread member cached</info>\n   *\n   * @param {Function} filter The function used to determine which thread members will be removed from the caches.\n   * @returns {number} Amount of thread members that were removed from the caches\n   */\n  sweepThreadMembers(filter) {\n    if (typeof filter !== 'function') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function');\n    }\n\n    let threads = 0;\n    let members = 0;\n    for (const channel of this.client.channels.cache.values()) {\n      if (!ThreadChannelTypes.includes(channel.type)) continue;\n      threads++;\n      members += channel.members.cache.sweep(filter);\n    }\n\n    this.client.emit(Events.CacheSweep, `Swept ${members} thread members in ${threads} threads.`);\n    return members;\n  }\n\n  /**\n   * Sweeps all threads and removes the ones which are indicated by the filter.\n   *\n   * @param {Function} filter The function used to determine which threads will be removed from the caches.\n   * @returns {number} filter Amount of threads that were removed from the caches\n   * @example\n   * // Remove all threads archived greater than 1 day ago from all the channel caches\n   * const amount = sweepers.sweepThreads(\n   *   Sweepers.filterByLifetime({\n   *     getComparisonTimestamp: t => t.archivedTimestamp,\n   *     excludeFromSweep: t => !t.archived,\n   *   })(),\n   * );\n   * console.log(`Successfully removed ${amount} threads from the cache.`);\n   */\n  sweepThreads(filter) {\n    if (typeof filter !== 'function') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function');\n    }\n\n    let threads = 0;\n    for (const [key, val] of this.client.channels.cache.entries()) {\n      if (!ThreadChannelTypes.includes(val.type)) continue;\n      if (filter(val, key, this.client.channels.cache)) {\n        threads++;\n        this.client.channels._remove(key);\n      }\n    }\n\n    this.client.emit(Events.CacheSweep, `Swept ${threads} threads.`);\n    return threads;\n  }\n\n  /**\n   * Sweeps all users and removes the ones which are indicated by the filter.\n   *\n   * @param {Function} filter The function used to determine which users will be removed from the caches.\n   * @returns {number} Amount of users that were removed from the caches\n   */\n  sweepUsers(filter) {\n    if (typeof filter !== 'function') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function');\n    }\n\n    const users = this.client.users.cache.sweep(filter);\n\n    this.client.emit(Events.CacheSweep, `Swept ${users} users.`);\n\n    return users;\n  }\n\n  /**\n   * Sweeps all guild voice states and removes the ones which are indicated by the filter.\n   *\n   * @param {Function} filter The function used to determine which voice states will be removed from the caches.\n   * @returns {number} Amount of voice states that were removed from the caches\n   */\n  sweepVoiceStates(filter) {\n    return this._sweepGuildDirectProp('voiceStates', filter, { outputName: 'voice states' }).items;\n  }\n\n  /**\n   * Cancels all sweeping intervals\n   *\n   * @returns {void}\n   */\n  destroy() {\n    for (const key of SweeperKeys) {\n      if (this.intervals[key]) clearInterval(this.intervals[key]);\n    }\n  }\n\n  /**\n   * Options for generating a filter function based on lifetime\n   *\n   * @typedef {Object} LifetimeFilterOptions\n   * @property {number} [lifetime=14400] How long, in seconds, an entry should stay in the collection\n   * before it is considered sweepable.\n   * @property {Function} [getComparisonTimestamp=e => e?.createdTimestamp] A function that takes an entry, key,\n   * and the collection and returns a timestamp to compare against in order to determine the lifetime of the entry.\n   * @property {Function} [excludeFromSweep=() => false] A function that takes an entry, key, and the collection\n   * and returns a boolean, `true` when the entry should not be checked for sweepability.\n   */\n\n  /**\n   * Create a sweepFilter function that uses a lifetime to determine sweepability.\n   *\n   * @param {LifetimeFilterOptions} [options={}] The options used to generate the filter function\n   * @returns {GlobalSweepFilter}\n   */\n  static filterByLifetime({\n    lifetime = 14_400,\n    getComparisonTimestamp = item => item?.createdTimestamp,\n    excludeFromSweep = () => false,\n  } = {}) {\n    if (typeof lifetime !== 'number') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'lifetime', 'number');\n    }\n\n    if (typeof getComparisonTimestamp !== 'function') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'getComparisonTimestamp', 'function');\n    }\n\n    if (typeof excludeFromSweep !== 'function') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'excludeFromSweep', 'function');\n    }\n\n    return () => {\n      if (lifetime <= 0) return null;\n      const lifetimeMs = lifetime * 1_000;\n      const now = Date.now();\n      return (entry, key, coll) => {\n        if (excludeFromSweep(entry, key, coll)) {\n          return false;\n        }\n\n        const comparisonTimestamp = getComparisonTimestamp(entry, key, coll);\n        if (!comparisonTimestamp || typeof comparisonTimestamp !== 'number') return false;\n        return now - comparisonTimestamp > lifetimeMs;\n      };\n    };\n  }\n\n  /**\n   * Creates a sweep filter that sweeps archived threads\n   *\n   * @param {number} [lifetime=14400] How long a thread has to be archived to be valid for sweeping\n   * @returns {GlobalSweepFilter}\n   */\n  static archivedThreadSweepFilter(lifetime = 14_400) {\n    return this.filterByLifetime({\n      lifetime,\n      getComparisonTimestamp: thread => thread.archiveTimestamp,\n      excludeFromSweep: thread => !thread.archived,\n    });\n  }\n\n  /**\n   * Creates a sweep filter that sweeps expired invites\n   *\n   * @param {number} [lifetime=14400] How long ago an invite has to have expired to be valid for sweeping\n   * @returns {GlobalSweepFilter}\n   */\n  static expiredInviteSweepFilter(lifetime = 14_400) {\n    return this.filterByLifetime({\n      lifetime,\n      getComparisonTimestamp: invite => invite.expiresTimestamp,\n    });\n  }\n\n  /**\n   * Creates a sweep filter that sweeps outdated messages (edits taken into account)\n   *\n   * @param {number} [lifetime=3600] How long ago a message has to have been sent or edited to be valid for sweeping\n   * @returns {GlobalSweepFilter}\n   */\n  static outdatedMessageSweepFilter(lifetime = 3_600) {\n    return this.filterByLifetime({\n      lifetime,\n      getComparisonTimestamp: message => message.editedTimestamp ?? message.createdTimestamp,\n    });\n  }\n\n  /**\n   * Configuration options for emitting the cache sweep client event\n   *\n   * @typedef {Object} SweepEventOptions\n   * @property {boolean} [emit=true] Whether to emit the client event in this method\n   * @property {string} [outputName] A name to output in the client event if it should differ from the key\n   * @private\n   */\n\n  /**\n   * Sweep a direct sub property of all guilds\n   *\n   * @param {string} key The name of the property\n   * @param {Function} filter Filter function passed to sweep\n   * @param {SweepEventOptions} [eventOptions={}] Options for the Client event emitted here\n   * @returns {Object} Object containing the number of guilds swept and the number of items swept\n   * @private\n   */\n  _sweepGuildDirectProp(key, filter, { emit = true, outputName } = {}) {\n    if (typeof filter !== 'function') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'filter', 'function');\n    }\n\n    let guilds = 0;\n    let items = 0;\n\n    for (const guild of this.client.guilds.cache.values()) {\n      // We may be unable to sweep the cache if the guild is unavailable and was never patched\n      if (!guild.available) continue;\n\n      const { cache } = guild[key];\n\n      guilds++;\n      items += cache.sweep(filter);\n    }\n\n    if (emit) {\n      this.client.emit(Events.CacheSweep, `Swept ${items} ${outputName ?? key} in ${guilds} guilds.`);\n    }\n\n    return { guilds, items };\n  }\n\n  /**\n   * Validates a set of properties\n   *\n   * @param {string} key Key of the options object to check\n   * @private\n   */\n  _validateProperties(key) {\n    const props = this.options[key];\n    if (typeof props !== 'object') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, `sweepers.${key}`, 'object', true);\n    }\n\n    if (typeof props.interval !== 'number') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, `sweepers.${key}.interval`, 'number');\n    }\n\n    // Invites, Messages, and Threads can be provided a lifetime parameter, which we use to generate the filter\n    if (['invites', 'messages', 'threads'].includes(key) && !('filter' in props)) {\n      if (typeof props.lifetime !== 'number') {\n        throw new DiscordjsTypeError(ErrorCodes.InvalidType, `sweepers.${key}.lifetime`, 'number');\n      }\n\n      return;\n    }\n\n    if (typeof props.filter !== 'function') {\n      throw new DiscordjsTypeError(ErrorCodes.InvalidType, `sweepers.${key}.filter`, 'function');\n    }\n  }\n\n  /**\n   * Initialize an interval for sweeping\n   *\n   * @param {string} intervalKey The name of the property that stores the interval for this sweeper\n   * @param {string} sweepKey The name of the function that sweeps the desired caches\n   * @param {Object} opts Validated options for a sweep\n   * @private\n   */\n  _initInterval(intervalKey, sweepKey, opts) {\n    if (opts.interval <= 0 || opts.interval === Infinity) return;\n    this.intervals[intervalKey] = setInterval(() => {\n      const sweepFn = opts.filter();\n      if (sweepFn === null) return;\n      if (typeof sweepFn !== 'function') throw new DiscordjsTypeError(ErrorCodes.SweepFilterReturn);\n      this[sweepKey](sweepFn);\n    }, opts.interval * 1_000).unref();\n  }\n}\n\nexports.Sweepers = Sweepers;\n"
  },
  {
    "path": "packages/discord.js/src/util/Symbols.js",
    "content": "'use strict';\n\nexports.MakeCacheOverrideSymbol = Symbol('djs.managers.makeCacheOverride');\n"
  },
  {
    "path": "packages/discord.js/src/util/SystemChannelFlagsBitField.js",
    "content": "/* eslint-disable jsdoc/check-values */\n'use strict';\n\nconst { GuildSystemChannelFlags } = require('discord-api-types/v10');\nconst { BitField } = require('./BitField.js');\n\n/**\n * Data structure that makes it easy to interact with a {@link Guild#systemChannelFlags} bitfield.\n * <info>Note that all event message types are enabled by default,\n * and by setting their corresponding flags you are disabling them</info>\n *\n * @extends {BitField}\n */\nclass SystemChannelFlagsBitField extends BitField {\n  /**\n   * Numeric system channel flags.\n   *\n   * @type {GuildSystemChannelFlags}\n   * @memberof SystemChannelFlagsBitField\n   */\n  static Flags = GuildSystemChannelFlags;\n}\n\n/**\n * @name SystemChannelFlagsBitField\n * @kind constructor\n * @memberof SystemChannelFlagsBitField\n * @param {SystemChannelFlagsResolvable} [bits=0] Bit(s) to read from\n */\n\n/**\n * Bitfield of the packed bits\n *\n * @type {number}\n * @name SystemChannelFlagsBitField#bitfield\n */\n\n/**\n * Data that can be resolved to give a system channel flag bitfield. This can be:\n * - A string (see {@link SystemChannelFlagsBitField.Flags})\n * - A system channel flag\n * - An instance of SystemChannelFlagsBitField\n * - An Array of SystemChannelFlagsResolvable\n *\n * @typedef {string|number|SystemChannelFlagsBitField|SystemChannelFlagsResolvable[]} SystemChannelFlagsResolvable\n */\n\nexports.SystemChannelFlagsBitField = SystemChannelFlagsBitField;\n"
  },
  {
    "path": "packages/discord.js/src/util/ThreadMemberFlagsBitField.js",
    "content": "/* eslint-disable jsdoc/check-values */\n'use strict';\n\nconst { ThreadMemberFlags } = require('discord-api-types/v10');\nconst { BitField } = require('./BitField.js');\n\n/**\n * Data structure that makes it easy to interact with a {@link ThreadMember#flags} bitfield.\n *\n * @extends {BitField}\n */\nclass ThreadMemberFlagsBitField extends BitField {\n  /**\n   * Numeric thread member flags. There are currently no bitflags relevant to bots for this.\n   *\n   * @type {ThreadMemberFlags}\n   * @memberof ThreadMemberFlagsBitField\n   */\n  static Flags = ThreadMemberFlags;\n}\n\n/**\n * @name ThreadMemberFlagsBitField\n * @kind constructor\n * @memberof ThreadMemberFlagsBitField\n * @param {BitFieldResolvable} [bits=0] Bit(s) to read from\n */\n\n/**\n * Bitfield of the packed bits\n *\n * @type {number}\n * @name ThreadMemberFlagsBitField#bitfield\n */\n\nexports.ThreadMemberFlagsBitField = ThreadMemberFlagsBitField;\n"
  },
  {
    "path": "packages/discord.js/src/util/Transformers.js",
    "content": "'use strict';\n\nconst { isJSONEncodable } = require('@discordjs/util');\nconst snakeCase = require('lodash.snakecase');\nconst { AuthorizingIntegrationOwners } = require('../structures/AuthorizingIntegrationOwners.js');\n\n/**\n * Transforms camel-cased keys into snake cased keys\n *\n * @param {*} obj The object to transform\n * @returns {*}\n */\nfunction toSnakeCase(obj) {\n  if (typeof obj !== 'object' || !obj) return obj;\n  if (obj instanceof Date) return obj;\n  if (isJSONEncodable(obj)) return toSnakeCase(obj.toJSON());\n  if (Array.isArray(obj)) return obj.map(toSnakeCase);\n  return Object.fromEntries(Object.entries(obj).map(([key, value]) => [snakeCase(key), toSnakeCase(value)]));\n}\n\n/**\n * Transforms an API auto moderation action object to a camel-cased variant.\n *\n * @param {APIAutoModerationAction} autoModerationAction The action to transform\n * @returns {AutoModerationAction}\n * @ignore\n */\nfunction _transformAPIAutoModerationAction(autoModerationAction) {\n  return {\n    type: autoModerationAction.type,\n    metadata: {\n      durationSeconds: autoModerationAction.metadata.duration_seconds ?? null,\n      channelId: autoModerationAction.metadata.channel_id ?? null,\n      customMessage: autoModerationAction.metadata.custom_message ?? null,\n    },\n  };\n}\n\n/**\n * Transforms an API message interaction metadata object to a camel-cased variant.\n *\n * @param {Client} client The client\n * @param {APIMessageInteractionMetadata} messageInteractionMetadata The metadata to transform\n * @returns {MessageInteractionMetadata}\n * @ignore\n */\nfunction _transformAPIMessageInteractionMetadata(client, messageInteractionMetadata) {\n  return {\n    id: messageInteractionMetadata.id,\n    type: messageInteractionMetadata.type,\n    user: client.users._add(messageInteractionMetadata.user),\n    authorizingIntegrationOwners: new AuthorizingIntegrationOwners(\n      client,\n      messageInteractionMetadata.authorizing_integration_owners,\n    ),\n    originalResponseMessageId: messageInteractionMetadata.original_response_message_id ?? null,\n    interactedMessageId: messageInteractionMetadata.interacted_message_id ?? null,\n    triggeringInteractionMetadata: messageInteractionMetadata.triggering_interaction_metadata\n      ? _transformAPIMessageInteractionMetadata(client, messageInteractionMetadata.triggering_interaction_metadata)\n      : null,\n  };\n}\n\n/**\n * Transforms a guild scheduled event recurrence rule object to a snake-cased variant.\n *\n * @param {GuildScheduledEventRecurrenceRuleOptions} recurrenceRule The recurrence rule to transform\n * @returns {APIGuildScheduledEventRecurrenceRule}\n * @ignore\n */\nfunction _transformGuildScheduledEventRecurrenceRule(recurrenceRule) {\n  return {\n    start: new Date(recurrenceRule.startAt).toISOString(),\n    frequency: recurrenceRule.frequency,\n    interval: recurrenceRule.interval,\n    by_weekday: recurrenceRule.byWeekday,\n    by_n_weekday: recurrenceRule.byNWeekday,\n    by_month: recurrenceRule.byMonth,\n    by_month_day: recurrenceRule.byMonthDay,\n  };\n}\n\n/**\n * Transforms API incidents data to a camel-cased variant.\n *\n * @param {APIIncidentsData} data The incidents data to transform\n * @returns {IncidentActions}\n * @ignore\n */\nfunction _transformAPIIncidentsData(data) {\n  return {\n    invitesDisabledUntil: data.invites_disabled_until ? new Date(data.invites_disabled_until) : null,\n    dmsDisabledUntil: data.dms_disabled_until ? new Date(data.dms_disabled_until) : null,\n    dmSpamDetectedAt: data.dm_spam_detected_at ? new Date(data.dm_spam_detected_at) : null,\n    raidDetectedAt: data.raid_detected_at ? new Date(data.raid_detected_at) : null,\n  };\n}\n\n/**\n * Transforms a collectibles object to a camel-cased variant.\n *\n * @param {APICollectibles} collectibles The collectibles to transform\n * @returns {Collectibles}\n * @ignore\n */\nfunction _transformCollectibles(collectibles) {\n  if (!collectibles.nameplate) return { nameplate: null };\n\n  return {\n    nameplate: {\n      skuId: collectibles.nameplate.sku_id,\n      asset: collectibles.nameplate.asset,\n      label: collectibles.nameplate.label,\n      palette: collectibles.nameplate.palette,\n    },\n  };\n}\n\nexports.toSnakeCase = toSnakeCase;\nexports._transformAPIAutoModerationAction = _transformAPIAutoModerationAction;\nexports._transformAPIMessageInteractionMetadata = _transformAPIMessageInteractionMetadata;\nexports._transformGuildScheduledEventRecurrenceRule = _transformGuildScheduledEventRecurrenceRule;\nexports._transformAPIIncidentsData = _transformAPIIncidentsData;\nexports._transformCollectibles = _transformCollectibles;\n"
  },
  {
    "path": "packages/discord.js/src/util/UserFlagsBitField.js",
    "content": "/* eslint-disable jsdoc/check-values */\n'use strict';\n\nconst { UserFlags } = require('discord-api-types/v10');\nconst { BitField } = require('./BitField.js');\n\n/**\n * Data structure that makes it easy to interact with a {@link User#flags} bitfield.\n *\n * @extends {BitField}\n */\nclass UserFlagsBitField extends BitField {\n  /**\n   * Numeric user flags.\n   *\n   * @type {UserFlags}\n   * @memberof UserFlagsBitField\n   */\n  static Flags = UserFlags;\n}\n\n/**\n * @name UserFlagsBitField\n * @kind constructor\n * @memberof UserFlagsBitField\n * @param {BitFieldResolvable} [bits=0] Bit(s) to read from\n */\n\n/**\n * Bitfield of the packed bits\n *\n * @type {number}\n * @name UserFlagsBitField#bitfield\n */\n\nexports.UserFlagsBitField = UserFlagsBitField;\n"
  },
  {
    "path": "packages/discord.js/src/util/Util.js",
    "content": "'use strict';\n\nconst { parse } = require('node:path');\nconst { Collection } = require('@discordjs/collection');\nconst { lazy } = require('@discordjs/util');\nconst { ChannelType, RouteBases, Routes } = require('discord-api-types/v10');\nconst { fetch } = require('undici');\nconst { Colors } = require('./Colors.js');\n// eslint-disable-next-line import-x/order\nconst { DiscordjsError, DiscordjsRangeError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');\n\n// Fixes circular dependencies.\nconst getAttachment = lazy(() => require('../structures/Attachment.js').Attachment);\nconst getGuildChannel = lazy(() => require('../structures/GuildChannel.js').GuildChannel);\nconst getSKU = lazy(() => require('../structures/SKU.js').SKU);\n\nconst isObject = data => typeof data === 'object' && data !== null;\n\n/**\n * Flatten an object. Any properties that are collections will get converted to an array of keys.\n *\n * @param {Object} obj The object to flatten.\n * @param {...Object<string, boolean|string>} [props] Specific properties to include/exclude.\n * @returns {Object}\n */\nfunction flatten(obj, ...props) {\n  if (!isObject(obj)) return obj;\n\n  const objProps = Object.keys(obj)\n    .filter(key => !key.startsWith('_'))\n    .map(key => ({ [key]: true }));\n\n  const mergedProps = objProps.length ? Object.assign(...objProps, ...props) : Object.assign({}, ...props);\n\n  const out = {};\n\n  // eslint-disable-next-line prefer-const\n  for (let [prop, newProp] of Object.entries(mergedProps)) {\n    if (!newProp) continue;\n    newProp = newProp === true ? prop : newProp;\n\n    const element = obj[prop];\n    const elemIsObj = isObject(element);\n    const valueOf = elemIsObj && typeof element.valueOf === 'function' ? element.valueOf() : null;\n    const hasToJSON = elemIsObj && typeof element.toJSON === 'function';\n\n    // If it's a Collection, make the array of keys\n    if (element instanceof Collection) out[newProp] = Array.from(element.keys());\n    // If the valueOf is a Collection, use its array of keys\n    else if (valueOf instanceof Collection) out[newProp] = Array.from(valueOf.keys());\n    // If it's an array, call toJSON function on each element if present, otherwise flatten each element\n    else if (Array.isArray(element)) out[newProp] = element.map(elm => elm.toJSON?.() ?? flatten(elm));\n    // If it's an object with a primitive `valueOf`, use that value\n    else if (typeof valueOf !== 'object') out[newProp] = valueOf;\n    // If it's an object with a toJSON function, use the return value of it\n    else if (hasToJSON) out[newProp] = element.toJSON();\n    // If element is an object, use the flattened version of it\n    else if (typeof element === 'object') out[newProp] = flatten(element);\n    // If it's a primitive\n    else if (!elemIsObj) out[newProp] = element;\n  }\n\n  return out;\n}\n\n/**\n * @typedef {Object} FetchRecommendedShardCountOptions\n * @property {number} [guildsPerShard=1000] Number of guilds assigned per shard\n * @property {number} [multipleOf=1] The multiple the shard count should round up to. (16 for large bot sharding)\n */\n\n/**\n * Gets the recommended shard count from Discord.\n *\n * @param {string} token Discord auth token\n * @param {FetchRecommendedShardCountOptions} [options] Options for fetching the recommended shard count\n * @returns {Promise<number>} The recommended number of shards\n */\nasync function fetchRecommendedShardCount(token, { guildsPerShard = 1_000, multipleOf = 1 } = {}) {\n  if (!token) throw new DiscordjsError(ErrorCodes.TokenMissing);\n  const response = await fetch(RouteBases.api + Routes.gatewayBot(), {\n    method: 'GET',\n    headers: { Authorization: `Bot ${token.replace(/^bot\\s*/i, '')}` },\n  });\n  if (!response.ok) {\n    if (response.status === 401) throw new DiscordjsError(ErrorCodes.TokenInvalid);\n    throw response;\n  }\n\n  const { shards } = await response.json();\n  return Math.ceil((shards * (1_000 / guildsPerShard)) / multipleOf) * multipleOf;\n}\n\n/**\n * A partial emoji object.\n *\n * @typedef {Object} PartialEmoji\n * @property {boolean} animated Whether the emoji is animated\n * @property {Snowflake|undefined} id The id of the emoji\n * @property {string} name The name of the emoji\n */\n\n/**\n * Parses emoji info out of a string. The string must be one of:\n * - A UTF-8 emoji (no id)\n * - A URL-encoded UTF-8 emoji (no id)\n * - A Discord custom emoji (`<:name:id>` or `<a:name:id>`)\n *\n * @param {string} text Emoji string to parse\n * @returns {?PartialEmoji}\n */\nfunction parseEmoji(text) {\n  const decodedText = text.includes('%') ? decodeURIComponent(text) : text;\n  if (!decodedText.includes(':')) return { animated: false, name: decodedText, id: undefined };\n  const match = /<?(?:(?<animated>a):)?(?<name>\\w{2,32}):(?<id>\\d{17,19})?>?/.exec(decodedText);\n  return match && { animated: Boolean(match.groups.animated), name: match.groups.name, id: match.groups.id };\n}\n\n/**\n * A partial emoji object with only an id.\n *\n * @typedef {Object} PartialEmojiOnlyId\n * @property {Snowflake} id The id of the emoji\n */\n\n/**\n * Resolves a partial emoji object from an {@link EmojiIdentifierResolvable}, without checking a Client.\n *\n * @param {Emoji|EmojiIdentifierResolvable} emoji Emoji identifier to resolve\n * @returns {?(PartialEmoji|PartialEmojiOnlyId)} Supplying a snowflake yields `PartialEmojiOnlyId`.\n */\nfunction resolvePartialEmoji(emoji) {\n  if (!emoji) return null;\n  if (typeof emoji === 'string') return /^\\d{17,19}$/.test(emoji) ? { id: emoji } : parseEmoji(emoji);\n  const { id, name, animated } = emoji;\n  if (!id && !name) return null;\n  return { id, name, animated: Boolean(animated) };\n}\n\n/**\n * Resolves a {@link GuildEmoji} from an emoji id.\n *\n * @param {Client} client The client to use to resolve the emoji\n * @param {Snowflake} emojiId The emoji id to resolve\n * @returns {?GuildEmoji}\n * @private\n */\nfunction resolveGuildEmoji(client, emojiId) {\n  for (const guild of client.guilds.cache.values()) {\n    if (!guild.available) {\n      continue;\n    }\n\n    const emoji = guild.emojis.cache.get(emojiId);\n\n    if (emoji) {\n      return emoji;\n    }\n  }\n\n  return null;\n}\n\n/**\n * Options used to make an error object.\n *\n * @typedef {Object} MakeErrorOptions\n * @property {string} name Error type\n * @property {string} message Message for the error\n * @property {string} stack Stack for the error\n * @private\n */\n\n/**\n * Makes an Error from a plain info object.\n *\n * @param {MakeErrorOptions} obj Error info\n * @returns {Error}\n * @private\n */\nfunction makeError(obj) {\n  const err = new Error(obj.message);\n  err.name = obj.name;\n  err.stack = obj.stack;\n  return err;\n}\n\n/**\n * Makes a plain error info object from an Error.\n *\n * @param {Error} err Error to get info from\n * @returns {MakeErrorOptions}\n * @private\n */\nfunction makePlainError(err) {\n  return {\n    name: err.name,\n    message: err.message,\n    stack: err.stack,\n  };\n}\n\nconst TextSortableGroupTypes = [\n  ChannelType.GuildText,\n  ChannelType.GuildAnnouncement,\n  ChannelType.GuildForum,\n  ChannelType.GuildMedia,\n];\n\nconst VoiceSortableGroupTypes = [ChannelType.GuildVoice, ChannelType.GuildStageVoice];\nconst CategorySortableGroupTypes = [ChannelType.GuildCategory];\n\n/**\n * Gets an array of the channel types that can be moved in the channel group. For example, a GuildText channel would\n * return an array containing the types that can be ordered within the text channels (always at the top), and a voice\n * channel would return an array containing the types that can be ordered within the voice channels (always at the\n * bottom).\n *\n * @param {ChannelType} type The type of the channel\n * @returns {ChannelType[]}\n * @private\n */\nfunction getSortableGroupTypes(type) {\n  switch (type) {\n    case ChannelType.GuildText:\n    case ChannelType.GuildAnnouncement:\n    case ChannelType.GuildForum:\n    case ChannelType.GuildMedia:\n      return TextSortableGroupTypes;\n    case ChannelType.GuildVoice:\n    case ChannelType.GuildStageVoice:\n      return VoiceSortableGroupTypes;\n    case ChannelType.GuildCategory:\n      return CategorySortableGroupTypes;\n    default:\n      return [type];\n  }\n}\n\n/**\n * Moves an element in an array *in place*.\n *\n * @param {Array<*>} array Array to modify\n * @param {*} element Element to move\n * @param {number} newIndex Index or offset to move the element to\n * @param {boolean} [offset=false] Move the element by an offset amount rather than to a set index\n * @returns {number}\n * @private\n */\nfunction moveElementInArray(array, element, newIndex, offset = false) {\n  const index = array.indexOf(element);\n  const targetIndex = (offset ? index : 0) + newIndex;\n  if (targetIndex > -1 && targetIndex < array.length) {\n    const removedElement = array.splice(index, 1)[0];\n    array.splice(targetIndex, 0, removedElement);\n  }\n\n  return array.indexOf(element);\n}\n\n/**\n * Verifies the provided data is a string, otherwise throws provided error.\n *\n * @param {string} data The string resolvable to resolve\n * @param {Function} [error=Error] The Error constructor to instantiate. Defaults to Error\n * @param {string} [errorMessage=\"Expected string, got <data> instead.\"] The error message to throw with. Defaults to \"Expected string, got <data> instead.\"\n * @param {boolean} [allowEmpty=true] Whether an empty string should be allowed\n * @returns {string}\n */\nfunction verifyString(\n  data,\n  error = Error,\n  errorMessage = `Expected a string, got ${data} instead.`,\n  allowEmpty = true,\n) {\n  if (typeof data !== 'string') throw new error(errorMessage);\n  if (!allowEmpty && data.length === 0) throw new error(errorMessage);\n  return data;\n}\n\n/**\n * Can be a number, hex string, an RGB array like:\n * ```js\n * [255, 0, 255] // purple\n * ```\n * or one of the following strings:\n * - `Default`\n * - `White`\n * - `Aqua`\n * - `Green`\n * - `Blue`\n * - `Yellow`\n * - `Purple`\n * - `LuminousVividPink`\n * - `Fuchsia`\n * - `Gold`\n * - `Orange`\n * - `Red`\n * - `Grey`\n * - `Navy`\n * - `DarkAqua`\n * - `DarkGreen`\n * - `DarkBlue`\n * - `DarkPurple`\n * - `DarkVividPink`\n * - `DarkGold`\n * - `DarkOrange`\n * - `DarkRed`\n * - `DarkGrey`\n * - `DarkerGrey`\n * - `LightGrey`\n * - `DarkNavy`\n * - `Blurple`\n * - `Greyple`\n * - `DarkButNotBlack`\n * - `NotQuiteBlack`\n * - `Random`\n *\n * @typedef {string|number|number[]} ColorResolvable\n */\n\n/**\n * Resolves a ColorResolvable into a color number.\n *\n * @param {ColorResolvable} color Color to resolve\n * @returns {number} A color\n */\nfunction resolveColor(color) {\n  let resolvedColor;\n\n  if (typeof color === 'string') {\n    if (color === 'Random') return Math.floor(Math.random() * (0xffffff + 1));\n    if (color === 'Default') return 0;\n    if (/^#?[\\da-f]{6}$/i.test(color)) return Number.parseInt(color.replace('#', ''), 16);\n    resolvedColor = Colors[color];\n  } else if (Array.isArray(color)) {\n    resolvedColor = (color[0] << 16) + (color[1] << 8) + color[2];\n  } else {\n    resolvedColor = color;\n  }\n\n  if (!Number.isInteger(resolvedColor)) {\n    throw new DiscordjsTypeError(ErrorCodes.ColorConvert, color);\n  }\n\n  if (resolvedColor < 0 || resolvedColor > 0xffffff) {\n    throw new DiscordjsRangeError(ErrorCodes.ColorRange);\n  }\n\n  return resolvedColor;\n}\n\n/**\n * Sorts by Discord's position and id.\n *\n * @param {Collection} collection Collection of objects to sort\n * @returns {Collection}\n */\nfunction discordSort(collection) {\n  const isGuildChannel = collection.first() instanceof getGuildChannel();\n  return collection.toSorted(\n    isGuildChannel\n      ? (a, b) => a.rawPosition - b.rawPosition || Number(BigInt(a.id) - BigInt(b.id))\n      : (a, b) => a.rawPosition - b.rawPosition || Number(BigInt(b.id) - BigInt(a.id)),\n  );\n}\n\n/**\n * Sets the position of a Channel or Role.\n *\n * @param {BaseChannel|Role} item Object to set the position of\n * @param {number} position New position for the object\n * @param {boolean} relative Whether `position` is relative to its current position\n * @param {Collection<string, BaseChannel|Role>} sorted A collection of the objects sorted properly\n * @param {Client} client The client to use to patch the data\n * @param {string} route Route to call PATCH on\n * @param {string} [reason] Reason for the change\n * @returns {Promise<BaseChannel[]|Role[]>} Updated item list, with `id` and `position` properties\n * @private\n */\nasync function setPosition(item, position, relative, sorted, client, route, reason) {\n  let updatedItems = [...sorted.values()];\n  moveElementInArray(updatedItems, item, position, relative);\n  updatedItems = updatedItems.map((innerItem, index) => ({ id: innerItem.id, position: index }));\n  await client.rest.patch(route, { body: updatedItems, reason });\n  return updatedItems;\n}\n\n/**\n * Alternative to Node's `path.basename`, removing query string after the extension if it exists.\n *\n * @param {string} path Path to get the basename of\n * @param {string} [ext] File extension to remove\n * @returns {string} Basename of the path\n * @private\n */\nfunction basename(path, ext) {\n  const res = parse(path);\n  return ext && res.ext.startsWith(ext) ? res.name : res.base.split('?')[0];\n}\n\n/**\n * Find the filename to use for attachments.\n *\n * @param {BufferResolvable|Stream} thing The thing to attach as attachment\n * @returns {string} filename to use\n */\nfunction findName(thing) {\n  if (typeof thing === 'string') {\n    return basename(thing);\n  }\n\n  if (thing.path) {\n    return basename(thing.path);\n  }\n\n  return 'file.jpg';\n}\n\n/**\n * The content to have all mentions replaced by the equivalent text.\n *\n * @param {string} str The string to be converted\n * @param {TextBasedChannels} channel The channel the string was sent in\n * @returns {string}\n */\nfunction cleanContent(str, channel) {\n  return str.replaceAll(\n    /<(?:(?<type>@[!&]?|#)|(?:\\/(?<commandName>[-_\\p{L}\\p{N}\\p{sc=Deva}\\p{sc=Thai} ]+):)|(?:a?:(?<emojiName>[\\w]+):))(?<id>\\d{17,19})>/gu,\n    (match, type, commandName, emojiName, id) => {\n      if (commandName) return `/${commandName}`;\n\n      if (emojiName) return `:${emojiName}:`;\n\n      switch (type) {\n        case '@':\n        case '@!': {\n          const member = channel.guild?.members.cache.get(id);\n          if (member) {\n            return `@${member.displayName}`;\n          }\n\n          const user = channel.client.users.cache.get(id);\n          return user ? `@${user.displayName}` : match;\n        }\n\n        case '@&': {\n          if (channel.type === ChannelType.DM) return match;\n          const role = channel.guild.roles.cache.get(id);\n          return role ? `@${role.name}` : match;\n        }\n\n        case '#': {\n          const mentionedChannel = channel.client.channels.cache.get(id);\n          return mentionedChannel ? `#${mentionedChannel.name}` : match;\n        }\n\n        default: {\n          return match;\n        }\n      }\n    },\n  );\n}\n\n/**\n * The content to put in a code block with all code block fences replaced by the equivalent backticks.\n *\n * @param {string} text The string to be converted\n * @returns {string}\n */\nfunction cleanCodeBlockContent(text) {\n  return text.replaceAll('```', '`\\u200B``');\n}\n\n/**\n * Represents the credentials used for a webhook in the form of its id and token.\n *\n * @typedef {Object} WebhookDataIdWithToken\n * @property {Snowflake} id The webhook's id\n * @property {string} token The webhook's token\n */\n\n/**\n * Parses a webhook URL for the id and token.\n *\n * @param {string} url The URL to parse\n * @returns {?WebhookDataIdWithToken} `null` if the URL is invalid, otherwise the id and the token\n */\nfunction parseWebhookURL(url) {\n  const matches =\n    /https?:\\/\\/(?:ptb\\.|canary\\.)?discord\\.com\\/api(?:\\/v\\d{1,2})?\\/webhooks\\/(?<id>\\d{17,19})\\/(?<token>[\\w-]{68})/i.exec(\n      url,\n    );\n\n  return matches && { id: matches.groups.id, token: matches.groups.token };\n}\n\n/**\n * Supportive data for interaction resolved data.\n *\n * @typedef {Object} SupportingInteractionResolvedData\n * @property {Client} client The client\n * @property {Guild} [guild] A guild\n * @property {GuildTextBasedChannel} [channel] A channel\n * @private\n */\n\n/**\n * Transforms the resolved data received from the API.\n *\n * @param {SupportingInteractionResolvedData} supportingData Data to support the transformation\n * @param {APIInteractionDataResolved} [data] The received resolved objects\n * @returns {CommandInteractionResolvedData}\n * @private\n */\nfunction transformResolved(\n  { client, guild, channel },\n  { members, users, channels, roles, messages, attachments } = {},\n) {\n  const result = {};\n\n  if (members) {\n    result.members = new Collection();\n    for (const [id, member] of Object.entries(members)) {\n      const user = users[id];\n      result.members.set(id, guild?.members._add({ user, ...member }) ?? member);\n    }\n  }\n\n  if (users) {\n    result.users = new Collection();\n    for (const user of Object.values(users)) {\n      result.users.set(user.id, client.users._add(user));\n    }\n  }\n\n  if (roles) {\n    result.roles = new Collection();\n    for (const role of Object.values(roles)) {\n      result.roles.set(role.id, guild?.roles._add(role) ?? role);\n    }\n  }\n\n  if (channels) {\n    result.channels = new Collection();\n    for (const apiChannel of Object.values(channels)) {\n      result.channels.set(apiChannel.id, client.channels._add(apiChannel, guild) ?? apiChannel);\n    }\n  }\n\n  if (messages) {\n    result.messages = new Collection();\n    for (const message of Object.values(messages)) {\n      result.messages.set(message.id, channel?.messages?._add(message) ?? message);\n    }\n  }\n\n  if (attachments) {\n    result.attachments = new Collection();\n    for (const attachment of Object.values(attachments)) {\n      const patched = new (getAttachment())(attachment);\n      result.attachments.set(attachment.id, patched);\n    }\n  }\n\n  return result;\n}\n\n/**\n * Resolves a SKU id from a SKU resolvable.\n *\n * @param {SKUResolvable} resolvable The SKU resolvable to resolve\n * @returns {?Snowflake} The resolved SKU id, or `null` if the resolvable was invalid\n */\nfunction resolveSKUId(resolvable) {\n  if (typeof resolvable === 'string') return resolvable;\n  if (resolvable instanceof getSKU()) return resolvable.id;\n  return null;\n}\n\n// Public\nexports.cleanCodeBlockContent = cleanCodeBlockContent;\nexports.cleanContent = cleanContent;\nexports.discordSort = discordSort;\nexports.fetchRecommendedShardCount = fetchRecommendedShardCount;\nexports.flatten = flatten;\nexports.parseEmoji = parseEmoji;\nexports.parseWebhookURL = parseWebhookURL;\nexports.resolveColor = resolveColor;\nexports.resolveSKUId = resolveSKUId;\nexports.verifyString = verifyString;\n\n// Private\nexports.resolvePartialEmoji = resolvePartialEmoji;\nexports.resolveGuildEmoji = resolveGuildEmoji;\nexports.makeError = makeError;\nexports.makePlainError = makePlainError;\nexports.getSortableGroupTypes = getSortableGroupTypes;\nexports.moveElementInArray = moveElementInArray;\nexports.setPosition = setPosition;\nexports.basename = basename;\nexports.findName = findName;\nexports.transformResolved = transformResolved;\n"
  },
  {
    "path": "packages/discord.js/test/createGuild.js",
    "content": "'use strict';\n\nconst assert = require('node:assert');\nconst { ChannelType, GatewayIntentBits } = require('discord-api-types/v10');\nconst { token } = require('./auth.js');\nconst { Client, Events } = require('../src/index.js');\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages] });\n\nclient.on(Events.ClientReady, async readyClient => {\n  try {\n    const guild = await readyClient.guilds.create('testing', {\n      channels: [\n        { name: 'afk channel', type: ChannelType.GuildVoice, id: 0 },\n        { name: 'system-channel', id: 1 },\n      ],\n      afkChannelId: 0,\n      afkTimeout: 60,\n      systemChannelId: 1,\n    });\n    console.log(guild.id);\n    assert.strictEqual(guild.afkChannel.name, 'afk channel');\n    assert.strictEqual(guild.afkTimeout, 60);\n    assert.strictEqual(guild.systemChannel.name, 'system-channel');\n    await guild.delete();\n  } catch (error) {\n    console.error(error);\n  } finally {\n    await readyClient.destroy();\n  }\n});\n\nclient.login(token).catch(console.error);\n"
  },
  {
    "path": "packages/discord.js/test/messages.js",
    "content": "'use strict';\n\nconst { Buffer } = require('node:buffer');\nconst { createReadStream } = require('node:fs');\nconst { readFile } = require('node:fs/promises');\nconst path = require('node:path');\nconst process = require('node:process');\nconst { setTimeout: sleep } = require('node:timers/promises');\nconst { fetch } = require('undici');\nconst {\n  Client,\n  GatewayIntentBits,\n  AttachmentBuilder,\n  EmbedBuilder,\n  MessageFlags,\n  ComponentType,\n} = require('../src/index.js');\n\nconst client = new Client({\n  intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent],\n});\n\nconst buffer = l =>\n  fetch(l)\n    .then(res => res.arrayBuffer())\n    .then(Buffer.from);\n\nconst linkA = 'https://discord.js.org/static/logo.svg';\nconst fileA = path.join(__dirname, 'blobReach.png');\n\nconst embed = () => new EmbedBuilder();\nconst attach = (attachment, name) => new AttachmentBuilder(attachment, { name });\n\nconst tests = [\n  m => m.channel.send('x'),\n\n  m => m.channel.send({ content: 'x', embeds: [{ description: 'a' }] }),\n  m => m.channel.send({ embeds: [{ description: 'a' }] }),\n  m => m.channel.send({ files: [{ attachment: fileA }] }),\n  m =>\n    m.channel.send({\n      embeds: [{ description: 'a' }],\n      files: [{ attachment: fileA, name: 'xyz.png' }],\n    }),\n\n  m => m.channel.send({ content: 'x', embeds: [embed().setDescription('a')] }),\n  m => m.channel.send({ embeds: [embed().setDescription('a')] }),\n  m => m.channel.send({ embeds: [embed().setDescription('a'), embed().setDescription('b')] }),\n\n  m => m.channel.send({ content: 'x', files: [attach(fileA)] }),\n  m => m.channel.send({ files: [fileA] }),\n  m => m.channel.send({ files: [attach(fileA)] }),\n  async m => m.channel.send({ files: [await buffer(linkA)] }),\n  async m => m.channel.send({ files: [{ attachment: await buffer(linkA) }] }),\n  m => m.channel.send({ files: [attach(fileA), attach(fileA)] }),\n\n  m => m.channel.send({ embeds: [{ description: 'a' }] }).then(m2 => m2.edit('x')),\n  m => m.channel.send({ embeds: [embed().setDescription('a')] }).then(m2 => m2.edit('x')),\n\n  m => m.channel.send('x').then(m2 => m2.edit({ embeds: [{ description: 'a' }] })),\n  m => m.channel.send('x').then(m2 => m2.edit({ embeds: [embed().setDescription('a')] })),\n\n  m => m.channel.send({ embeds: [{ description: 'a' }] }).then(m2 => m2.edit({ content: 'x', embeds: [] })),\n  m => m.channel.send({ embeds: [embed().setDescription('a')] }).then(m2 => m2.edit({ content: 'x', embeds: [] })),\n\n  m => m.channel.send({ content: 'x', embeds: [embed().setDescription('a')], files: [attach(fileA)] }),\n  m => m.channel.send({ content: 'x', files: [attach(fileA), attach(fileA)] }),\n\n  m => m.channel.send({ embeds: [embed().setDescription('a')], files: [attach(fileA)] }),\n  m =>\n    m.channel.send({\n      embeds: [embed().setImage('attachment://two.png')],\n      files: [attach(fileA, 'two.png')],\n    }),\n  m => m.channel.send({ content: 'x', files: [attach(fileA)] }),\n  m => m.channel.send({ files: [fileA] }),\n  m => m.channel.send({ files: [attach(fileA)] }),\n  async m => m.channel.send({ files: [await readFile(fileA)] }),\n\n  m => m.channel.send({ content: 'x', files: [attach(createReadStream(fileA))] }),\n  m => m.channel.send({ files: [createReadStream(fileA)] }),\n  m => m.channel.send({ files: [{ attachment: createReadStream(fileA) }] }),\n\n  m => m.reply({ content: 'x', allowedMentions: { repliedUser: false } }),\n  m => m.reply({ content: 'x', allowedMentions: { repliedUser: true } }),\n  m => m.reply({ content: 'x' }),\n  m => m.reply({ content: `${m.author}`, allowedMentions: { repliedUser: false } }),\n  m => m.reply({ content: `${m.author}`, allowedMentions: { parse: ['users'], repliedUser: false } }),\n  m => m.reply({ content: `${m.author}`, allowedMentions: { parse: ['users'], repliedUser: true } }),\n  m => m.reply({ content: `${m.author}` }),\n\n  m => m.edit({ flags: MessageFlags.SuppressEmbeds }),\n  m => m.edit({ flags: MessageFlags.SuppressEmbeds, allowedMentions: { repliedUser: false } }),\n\n  m =>\n    m\n      .reply({ content: 'x', allowedMentions: { repliedUser: false } })\n      .then(msg => msg.edit({ content: 'a', allowedMentions: { repliedUser: true } })),\n\n  m =>\n    m.channel.send({\n      components: [{ type: ComponentType.TextDisplay, content: `${m.author}` }],\n      flags: MessageFlags.IsComponentsV2,\n    }),\n  m =>\n    m.channel.send({\n      components: [{ type: ComponentType.TextDisplay, content: `${m.author}` }],\n      flags: MessageFlags.IsComponentsV2,\n      allowedMentions: { parse: ['users'] },\n    }),\n  m =>\n    m.channel.send({\n      components: [{ type: ComponentType.TextDisplay, content: `${m.author}` }],\n      flags: MessageFlags.IsComponentsV2,\n      allowedMentions: { parse: [] },\n    }),\n  m =>\n    m.reply({\n      components: [{ type: ComponentType.TextDisplay, content: `${m.author}` }],\n      flags: MessageFlags.IsComponentsV2,\n      allowedMentions: { parse: [], repliedUser: true },\n    }),\n  m =>\n    m.reply({\n      components: [{ type: ComponentType.TextDisplay, content: `${m.author}` }],\n      flags: MessageFlags.IsComponentsV2,\n      allowedMentions: { parse: [], repliedUser: false },\n    }),\n\n  m => m.channel.send('Done!'),\n];\n\nclient.on('messageCreate', async message => {\n  if (message.author.id !== process.env.OWNER) return;\n  const match = message.content.match(/^do (.+)$/);\n  if (match?.[1] === 'it') {\n    /* eslint-disable no-await-in-loop */\n    for (const [i, test] of tests.entries()) {\n      await message.channel.send(`**#${i}**\\n\\`\\`\\`js\\n${test.toString()}\\`\\`\\``);\n      await test(message).catch(e => message.channel.send(`Error!\\n\\`\\`\\`\\n${e}\\`\\`\\``));\n      await sleep(1_000);\n    }\n    /* eslint-enable no-await-in-loop */\n  } else if (match) {\n    const n = parseInt(match[1]) || 0;\n    const test = tests.slice(n)[0];\n    const i = tests.indexOf(test);\n    await message.channel.send(`**#${i}**\\n\\`\\`\\`js\\n${test.toString()}\\`\\`\\``);\n    await test(message).catch(e => message.channel.send(`Error!\\n\\`\\`\\`\\n${e}\\`\\`\\``));\n  }\n});\n\nclient.login();\n\n// eslint-disable-next-line no-console\nprocess.on('unhandledRejection', console.error);\n"
  },
  {
    "path": "packages/discord.js/test/monetization.js",
    "content": "'use strict';\n\nconst { ButtonStyle } = require('discord-api-types/v10');\nconst { token, owner, skuId } = require('./auth.js');\nconst { Client, Events, codeBlock, GatewayIntentBits, ActionRowBuilder, ButtonBuilder } = require('../src/index.js');\n\nconst client = new Client({ intents: GatewayIntentBits.Guilds | GatewayIntentBits.GuildMessages });\n\nclient.on('raw', console.log);\n\nclient.on(Events.ClientReady, async () => {\n  const commands = await client.application.commands.fetch();\n  if (!commands.size) {\n    await client.application.commands.set([\n      {\n        name: 'test',\n        description: 'yeet',\n      },\n    ]);\n  }\n\n  const skus = await client.application.fetchSKUs();\n  console.log('skus', skus);\n\n  const entitlements = await client.application.entitlements.fetch();\n  console.log('entitlements', entitlements);\n});\n\nclient.on(Events.EntitlementCreate, entitlement => console.log('EntitlementCreate', entitlement));\nclient.on(Events.EntitlementDelete, entitlement => console.log('EntitlementDelete', entitlement));\nclient.on(Events.EntitlementUpdate, (oldEntitlement, newEntitlement) =>\n  console.log('EntitlementUpdate', oldEntitlement, newEntitlement),\n);\n\nclient.on(Events.InteractionCreate, async interaction => {\n  console.log('interaction.entitlements', interaction.entitlements);\n\n  if (interaction.commandName === 'test') {\n    await interaction.reply({\n      content: ':3:3:3',\n      components: [\n        new ActionRowBuilder().setComponents(\n          new ButtonBuilder().setCustomId('test').setLabel('test').setStyle(ButtonStyle.Premium).setSKUId(skuId),\n        ),\n      ],\n    });\n  }\n});\n\nclient.on(Events.MessageCreate, async message => {\n  const prefix = `<@${client.user.id}> `;\n\n  if (message.author.id !== owner || !message.content.startsWith(prefix)) return;\n  let res;\n  try {\n    res = await eval(message.content.slice(prefix.length));\n    if (typeof res !== 'string') res = require('node:util').inspect(res);\n  } catch (err) {\n    // eslint-disable-next-line no-console\n    console.error(err.stack);\n    res = err.message;\n  }\n\n  await message.channel.send(codeBlock('js', res));\n});\n\nclient.login(token);\n"
  },
  {
    "path": "packages/discord.js/test/polls.js",
    "content": "'use strict';\n\nconst { token, owner } = require('./auth.js');\nconst { Client, Events, codeBlock, GatewayIntentBits } = require('../src/index.js');\n\nconst client = new Client({\n  intents: GatewayIntentBits.Guilds | GatewayIntentBits.GuildMessages | GatewayIntentBits.GuildMessagePolls,\n});\n\nclient.on('raw', console.log);\n\nclient.on(Events.ClientReady, async () => {\n  const channel = client.channels.cache.get('1220510756286631968');\n\n  // const message = await channel.messages.fetch('1220680560414818325');\n  // console.dir(message.poll, { depth: Infinity });\n\n  // const answer = message.poll.answers.first();\n  // const voters = await answer.voters.fetch();\n  // console.dir(voters);\n\n  const message = await channel.send({\n    poll: {\n      question: {\n        text: 'What is your favorite color?',\n      },\n      answers: [{ text: 'Red' }, { text: 'Green' }, { text: 'Blue' }, { text: 'Yellow' }],\n      duration: 8,\n      allowMultiselect: false,\n    },\n  });\n\n  console.log(message.poll);\n});\n\nclient.on(Events.MessagePollVoteAdd, (answer, userId) => {\n  console.log(`User ${userId} voted for answer ${answer.id}`);\n});\n\nclient.on(Events.MessagePollVoteRemove, (answer, userId) => {\n  console.log(`User ${userId} removed their vote for answer ${answer.id}`);\n});\n\nclient.on(Events.MessageUpdate, async (_oldMessage, newMessage) => {\n  if (!newMessage.poll) return;\n\n  console.log('Poll was updated', newMessage.poll);\n});\n\nclient.on(Events.MessageCreate, async message => {\n  const prefix = `<@${client.user.id}> `;\n\n  if (message.author.id !== owner || !message.content.startsWith(prefix)) return;\n  let res;\n  try {\n    res = await eval(message.content.slice(prefix.length));\n    if (typeof res !== 'string') res = require('node:util').inspect(res);\n  } catch (err) {\n    // eslint-disable-next-line no-console\n    console.error(err.stack);\n    res = err.message;\n  }\n\n  if (res.length > 2000) {\n    console.log(res);\n    res = 'Output too long, check the console.';\n  }\n  await message.channel.send(codeBlock('js', res));\n});\n\nclient.login(token);\n"
  },
  {
    "path": "packages/discord.js/test/random.js",
    "content": "/* eslint-disable */\n\n'use strict';\n\nconst { token, owner } = require('./auth.js');\nconst { Client, Events } = require('../src/index.js');\nconst { ChannelType, GatewayIntentBits } = require('discord-api-types/v10');\n\nconsole.time('magic');\n\nconst client = new Client({\n  intents: [\n    GatewayIntentBits.Guilds,\n    GatewayIntentBits.GuildMessages,\n    GatewayIntentBits.GuildMessageReactions,\n    GatewayIntentBits.GuildMembers,\n    GatewayIntentBits.MessageContent,\n  ],\n});\n\nclient\n  .login(token)\n  .then(() => console.log('logged in'))\n  .catch(console.error);\n\n// Fetch all members in a new guild\nclient.on(Events.GuildCreate, guild =>\n  guild.members.fetch().catch(err => console.log(`Failed to fetch all members: ${err}\\n${err.stack}`)),\n);\n\n// Fetch all members in a newly available guild\nclient.on(Events.GuildUpdate, (oldGuild, newGuild) =>\n  !oldGuild.available && newGuild.available\n    ? newGuild.members.fetch().catch(err => console.log(`Failed to fetch all members: ${err}\\n${err.stack}`))\n    : Promise.resolve(),\n);\n\nclient.on(Events.ClientReady, async () => {\n  // Fetch all members for initially available guilds\n  try {\n    const promises = client.guilds.cache.map(guild => (guild.available ? guild.members.fetch() : Promise.resolve()));\n    await Promise.all(promises);\n  } catch (err) {\n    console.log(`Failed to fetch all members before ready! ${err}\\n${err.stack}`);\n  }\n\n  console.log(`ready with ${client.users.cache.size} users`);\n  console.timeEnd('magic');\n});\n\nclient.on(Events.Debug, console.log);\n\nclient.on(Events.Error, m => console.log('debug', new Error(m).stack));\n\nclient.on(Events.MessageCreate, message => {\n  if (true) {\n    if (message.content === 'makechann') {\n      if (message.channel.guild) {\n        message.channel.guild.channels.create('hi', { type: ChannelType.GuildText }).then(console.log);\n      }\n    }\n\n    if (message.content === 'imma queue pls') {\n      let count = 0;\n      let ecount = 0;\n      for (let x = 0; x < 4_000; x++) {\n        message.channel\n          .send(`this is message ${x} of 3999`)\n          .then(m => {\n            count++;\n            console.log('reached', count, ecount);\n          })\n          .catch(e => {\n            console.error(e);\n            ecount++;\n            console.log('reached', count, ecount);\n          });\n      }\n    }\n\n    if (message.content === 'myperms?') {\n      message.channel.send(\n        `Your permissions are:\\n${JSON.stringify(message.channel.permissionsFor(message.author).serialize(), null, 4)}`,\n      );\n    }\n\n    if (message.content === 'delchann') {\n      message.channel.delete().then(chan => console.log('selfDelChann', chan.name));\n    }\n\n    if (message.content.startsWith('setname')) {\n      message.channel.setName(message.content.substr(8));\n    }\n\n    if (message.content.startsWith('botname')) {\n      client.user.setUsername(message.content.substr(8));\n    }\n\n    if (message.content.startsWith('botavatar')) {\n      fetch('url')\n        .then(result => result.arrayBuffer())\n        .then(buffer => client.user.setAvatar(buffer))\n        .then(() => message.channel.send('Done!'), console.error);\n    }\n\n    if (message.content.startsWith('gn')) {\n      message.guild\n        .setName(message.content.substr(3))\n        .then(guild => console.log('guild updated to', guild.name))\n        .catch(console.error);\n    }\n\n    if (message.content === 'leave') {\n      message.guild\n        .leave()\n        .then(guild => console.log('left guild', guild.name))\n        .catch(console.error);\n    }\n\n    if (message.content === 'stats') {\n      let m = '';\n      m += `I am aware of ${message.guild.channels.cache.size} channels\\n`;\n      m += `I am aware of ${message.guild.members.cache.size} members\\n`;\n      m += `I am aware of ${client.channels.cache.size} channels overall\\n`;\n      m += `I am aware of ${client.guilds.cache.size} guilds overall\\n`;\n      m += `I am aware of ${client.users.cache.size} users overall\\n`;\n      message.channel\n        .send(m)\n        .then(msg => msg.edit('nah'))\n        .catch(console.error);\n    }\n\n    if (message.content === 'messageme!') {\n      message.author.send('oh, hi there!').catch(e => console.log(e.stack));\n    }\n\n    if (message.content === \"don't dm me\") {\n      message.author.deleteDM();\n    }\n\n    if (message.content.startsWith('kick')) {\n      const user = message.mentions.users.first();\n      message.guild.members\n        .resolve(user)\n        .kick()\n        .then(() => {\n          console.log(user.id);\n          message.channel.send(`Kicked ${user.username}!`);\n        })\n        .catch(console.error);\n    }\n\n    if (message.content === 'ratelimittest') {\n      let i = 1;\n      const start = Date.now();\n      while (i <= 20) {\n        message.channel.send(`Testing my rates, item ${i} of 20`);\n        i++;\n      }\n      message.channel.send('last one...').then(m => {\n        const diff = Date.now() - start;\n        m.channel.send(`Each message took ${diff / 21}ms to send`);\n      });\n    }\n\n    if (message.content === 'makerole') {\n      message.guild.roles\n        .create()\n        .then(role => {\n          message.channel.send(`Made role ${role.name}`);\n        })\n        .catch(console.error);\n    }\n  }\n});\n\nfunction nameLoop(user) {\n  // user.setUsername(user.username + 'a').then(nameLoop).catch(console.error);\n}\n\nfunction chanLoop(channel) {\n  channel.setName(`${channel.name}a`).then(chanLoop).catch(console.error);\n}\n\nclient.on(Events.MessageCreate, msg => {\n  if (msg.content.startsWith('?raw')) {\n    msg.channel.send(`\\`\\`\\`${msg.content}\\`\\`\\``);\n  }\n\n  if (msg.content.startsWith('#eval') && msg.author.id === owner) {\n    try {\n      const com = eval(msg.content.split(' ').slice(1).join(' '));\n      msg.channel.send(`\\`\\`\\`\\n${com}\\`\\`\\``);\n    } catch (e) {\n      msg.channel.send(`\\`\\`\\`\\n${e}\\`\\`\\``);\n    }\n  }\n});\n\nclient.on(Events.MessageReactionAdd, (reaction, user) => {\n  if (reaction.message.channelId !== '222086648706498562') return;\n  reaction.message.channel.send(`${user.username} added reaction ${reaction.emoji}, count is now ${reaction.count}`);\n});\n\nclient.on(Events.MessageReactionRemove, (reaction, user) => {\n  if (reaction.message.channelId !== '222086648706498562') return;\n  reaction.message.channel.send(`${user.username} removed reaction ${reaction.emoji}, count is now ${reaction.count}`);\n});\n\nclient.on(Events.MessageCreate, m => {\n  if (m.content.startsWith('#reactions')) {\n    const mId = m.content.split(' ')[1];\n    m.channel.messages.fetch(mId).then(rM => {\n      for (const reaction of rM.reactions.cache.values()) {\n        reaction.users.fetch().then(users => {\n          m.channel.send(\n            `The following gave that message ${reaction.emoji}:\\n` +\n              `${users\n                .map(u => u.username)\n                .map(t => `- ${t}`)\n                .join('\\n')}`,\n          );\n        });\n      }\n    });\n  }\n});\n"
  },
  {
    "path": "packages/discord.js/test/reactionCollectorCreated.test.js",
    "content": "'use strict';\n\nconst { GatewayIntentBits } = require('discord-api-types/v10');\nconst { token, guildId, channelId, messageId } = require('./auth.js');\nconst { Client, Events, ReactionCollector } = require('../src/index.js');\n\nconst client = new Client({\n  intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessageReactions],\n});\n\nclient.on(Events.ClientReady, async readyClient => {\n  const guild = readyClient.guilds.cache.get(guildId);\n\n  const channel = guild.channels.cache.get(channelId);\n\n  const message = await channel.messages.fetch(messageId);\n\n  await message.react('🔔');\n  // Await message.reactions.removeAll();\n\n  const collector = new ReactionCollector(message, () => true, { dispose: true });\n\n  collector.on('collect', () => {\n    console.log('collected');\n  });\n\n  collector.on('create', () => {\n    console.log('created');\n  });\n\n  collector.on('remove', () => {\n    console.log('removed');\n  });\n\n  collector.on('dispose', () => {\n    console.log('disposed');\n  });\n});\n\nclient.login(token);\n"
  },
  {
    "path": "packages/discord.js/test/resolveGuildTemplateCode.test.js",
    "content": "'use strict';\n\nconst { strictEqual } = require('node:assert/strict');\nconst { resolveGuildTemplateCode } = require('../src/index.js');\n\nstrictEqual(resolveGuildTemplateCode('https://discord.new/abc'), 'abc');\n"
  },
  {
    "path": "packages/discord.js/test/sendtest.js",
    "content": "'use strict';\n\nconst { Buffer } = require('node:buffer');\nconst fs = require('node:fs');\nconst path = require('node:path');\nconst process = require('node:process');\nconst { setTimeout: sleep } = require('node:timers/promises');\nconst util = require('node:util');\nconst { GatewayIntentBits } = require('discord-api-types/v10');\nconst { fetch } = require('undici');\nconst { owner, token } = require('./auth.js');\nconst { Client, MessageAttachment, Embed, Events } = require('../src/index.js');\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages] });\n\nconst buffer = l =>\n  fetch(l)\n    .then(res => res.arrayBuffer())\n    .then(Buffer.from);\nconst read = util.promisify(fs.readFile);\nconst readStream = fs.createReadStream;\n\nconst linkA = 'https://lolisafe.moe/iiDMtAXA.png';\nconst linkB = 'https://lolisafe.moe/9hSpedPh.png';\nconst fileA = path.join(__dirname, 'blobReach.png');\n\nconst embed = () => new Embed();\nconst attach = (attachment, name) => new MessageAttachment(attachment, name);\n\nconst tests = [\n  m => m.channel.send('x'),\n\n  m => m.channel.send('x', { code: true }),\n  m => m.channel.send('1', { code: 'js' }),\n  m => m.channel.send('x', { code: '' }),\n\n  m => m.channel.send('x', { embed: { description: 'a' } }),\n  m => m.channel.send({ embed: { description: 'a' } }),\n  m => m.channel.send({ files: [{ attachment: linkA }] }),\n  m =>\n    m.channel.send({\n      embed: { description: 'a' },\n      files: [{ attachment: linkA, name: 'xyz.png' }],\n    }),\n\n  m => m.channel.send('x', embed().setDescription('a')),\n  m => m.channel.send(embed().setDescription('a')),\n  m => m.channel.send({ embed: embed().setDescription('a') }),\n  m => m.channel.send([embed().setDescription('a'), embed().setDescription('b')]),\n\n  m => m.channel.send('x', attach(linkA)),\n  m => m.channel.send(attach(linkA)),\n  m => m.channel.send({ files: [linkA] }),\n  m => m.channel.send({ files: [attach(linkA)] }),\n  async m => m.channel.send(attach(await buffer(linkA))),\n  async m => m.channel.send({ files: [await buffer(linkA)] }),\n  async m => m.channel.send({ files: [{ attachment: await buffer(linkA) }] }),\n  m => m.channel.send([attach(linkA), attach(linkB)]),\n\n  m => m.channel.send({ embed: { description: 'a' } }).then(m2 => m2.edit('x')),\n  m => m.channel.send(embed().setDescription('a')).then(m2 => m2.edit('x')),\n  m => m.channel.send({ embed: embed().setDescription('a') }).then(m2 => m2.edit('x')),\n\n  m => m.channel.send('x').then(m2 => m2.edit({ embed: { description: 'a' } })),\n  m => m.channel.send('x').then(m2 => m2.edit(embed().setDescription('a'))),\n  m => m.channel.send('x').then(m2 => m2.edit({ embed: embed().setDescription('a') })),\n\n  m => m.channel.send({ embed: { description: 'a' } }).then(m2 => m2.edit({ embed: null })),\n  m => m.channel.send(embed().setDescription('a')).then(m2 => m2.edit({ embed: null })),\n\n  m => m.channel.send('x', [embed().setDescription('a'), attach(linkB)]),\n  m => m.channel.send('x', [attach(linkA), attach(linkB)]),\n\n  m => m.channel.send([embed().setDescription('a'), attach(linkB)]),\n  m =>\n    m.channel.send({\n      embed: embed().setImage('attachment://two.png'),\n      files: [attach(linkB, 'two.png')],\n    }),\n  m => m.channel.send('x', attach(fileA)),\n  m => m.channel.send({ files: [fileA] }),\n  m => m.channel.send(attach(fileA)),\n  async m => m.channel.send({ files: [await read(fileA)] }),\n\n  m => m.channel.send('x', attach(readStream(fileA))),\n  m => m.channel.send({ files: [readStream(fileA)] }),\n  m => m.channel.send({ files: [{ attachment: readStream(fileA) }] }),\n\n  m => m.channel.send('Done!'),\n];\n\nclient.on(Events.MessageCreate, async message => {\n  if (message.author.id !== owner) return;\n  const match = message.content.match(/^do (.+)$/);\n  if (match?.[1] === 'it') {\n    /* eslint-disable no-await-in-loop */\n    for (const [i, test] of tests.entries()) {\n      await message.channel.send(`**#${i}**\\n\\`\\`\\`js\\n${test.toString()}\\`\\`\\``);\n      await test(message).catch(e => message.channel.send(`Error!\\n\\`\\`\\`\\n${e}\\`\\`\\``));\n      await sleep(1_000);\n    }\n    /* eslint-enable no-await-in-loop */\n  } else if (match) {\n    const n = parseInt(match[1]) || 0;\n    const test = tests.slice(n)[0];\n    const i = tests.indexOf(test);\n    await message.channel.send(`**#${i}**\\n\\`\\`\\`js\\n${test.toString()}\\`\\`\\``);\n    await test(message).catch(e => message.channel.send(`Error!\\n\\`\\`\\`\\n${e}\\`\\`\\``));\n  }\n});\n\nclient.login(token);\n\n// eslint-disable-next-line no-console\nprocess.on('unhandledRejection', console.error);\n"
  },
  {
    "path": "packages/discord.js/test/shard.js",
    "content": "'use strict';\n\nconst process = require('node:process');\nconst { setTimeout } = require('node:timers');\nconst { GatewayIntentBits } = require('discord-api-types/v10');\nconst { token } = require('./auth.json');\nconst { Client, Events } = require('../src/index.js');\n\nconst client = new Client({\n  intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],\n  shards: process.argv[2],\n  shardCount: process.argv[3],\n});\n\nclient.on(Events.ClientReady, msg => {\n  if (msg.content.startsWith('?eval') && msg.author.id === '66564597481480192') {\n    try {\n      const com = eval(msg.content.split(' ').slice(1).join(' '));\n      msg.channel.send(com, { code: true });\n    } catch (e) {\n      msg.channel.send(e, { code: true });\n    }\n  }\n});\n\nprocess.send(123);\n\nclient.on(Events.ClientReady, readyClient => {\n  console.log('Ready', readyClient.options.shards);\n  if (readyClient.options.shards === 0) {\n    setTimeout(async () => {\n      console.log('kek dying');\n      await client.destroy();\n    }, 5_000);\n  }\n});\n\nclient.login(token).catch(console.error);\n"
  },
  {
    "path": "packages/discord.js/test/sharder.js",
    "content": "'use strict';\n\nconst process = require('node:process');\nconst { token } = require('./auth.js');\nconst { ShardingManager } = require('../src/index.js');\n\nconst sharder = new ShardingManager(`${process.cwd()}/test/shard.js`, { token, respawn: false });\n\nsharder.on('launch', shard => console.log(`launched ${shard.id}`));\n\nsharder.spawn();\n"
  },
  {
    "path": "packages/discord.js/test/templateCreateGuild.js",
    "content": "'use strict';\n\nconst { token } = require('./auth.js');\nconst { Client, Events, GatewayIntentBits } = require('../src/index.js');\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages] });\n\nclient\n  .on(Events.ClientReady, () => console.log('ready'))\n  .on(Events.MessageCreate, async message => {\n    try {\n      const templates = await message.guild.fetchTemplates();\n      if (!templates.size) {\n        console.log('no templates');\n      } else {\n        const guild = await templates.first().createGuild('guild name');\n        console.log(`created guild with id ${guild.id}`);\n        await guild.delete();\n        console.log('deleted guild');\n      }\n    } catch (error) {\n      console.error(error);\n    } finally {\n      await client.destroy();\n    }\n  })\n  .login(token)\n  .catch(console.error);\n"
  },
  {
    "path": "packages/discord.js/test/tester1000.js",
    "content": "'use strict';\n\nconst process = require('node:process');\nconst { GatewayIntentBits } = require('discord-api-types/v10');\nconst { token, prefix, owner } = require('./auth.js');\nconst { Client, Events, RESTEvents } = require('../src/index.js');\n\n// eslint-disable-next-line no-console\nconst log = (...args) => console.log(process.uptime().toFixed(3), ...args);\n\nconst client = new Client({\n  intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],\n  shardCount: 2,\n});\n\nclient.on(Events.Debug, log);\nclient.on(Events.ClientReady, () => {\n  log('READY', client.user.tag, client.user.id);\n});\nclient.rest.on(RESTEvents.RateLimited, log);\nclient.on(Events.Error, console.error);\n\nconst commands = {\n  eval: message => {\n    if (message.author.id !== owner) return;\n    let res;\n    try {\n      res = eval(message.content);\n      if (typeof res !== 'string') res = require('node:util').inspect(res);\n    } catch (err) {\n      // eslint-disable-next-line no-console\n      console.error(err.stack);\n      res = err.message;\n    }\n    message.channel.send(res, { code: 'js' });\n  },\n  ping: message => message.channel.send('pong'),\n};\n\nclient.on(Events.MessageCreate, message => {\n  if (!message.content.startsWith(prefix) || message.author.bot) return;\n\n  message.content = message.content.replace(prefix, '').trim().split(' ');\n  const command = message.content.shift();\n  message.content = message.content.join(' ');\n\n  // eslint-disable-next-line no-console\n  console.log('COMMAND', command, message.content);\n\n  if (command in commands) commands[command](message);\n});\n\nclient.login(token);\n\n// eslint-disable-next-line no-console\nprocess.on('unhandledRejection', console.error);\n"
  },
  {
    "path": "packages/discord.js/test/tester2000.js",
    "content": "'use strict';\n\nconst process = require('node:process');\nconst { GatewayIntentBits } = require('discord-api-types/v10');\nconst { token, prefix, owner } = require('./auth.js');\nconst { Client, Events, Options, RESTEvents, codeBlock } = require('../src/index.js');\n\n// eslint-disable-next-line no-console\nconst log = (...args) => console.log(process.uptime().toFixed(3), ...args);\n\nconst client = new Client({\n  // 😏\n  intents: Object.values(GatewayIntentBits).reduce((acc, p) => acc | p, 0),\n  makeCache: Options.cacheWithLimits({\n    MessageManager: 10,\n    PresenceManager: 10,\n    UserManager: {\n      maxSize: 1,\n      keepOverLimit: v => v.id === client.user.id,\n    },\n    GuildMemberManager: {\n      maxSize: 1,\n      keepOverLimit: v => v.id === client.user.id,\n    },\n  }),\n});\n\nclient.on(Events.Debug, log);\nclient.on(Events.ClientReady, () => {\n  log('READY', client.user.tag, client.user.id);\n});\nclient.rest.on(RESTEvents.RateLimited, log);\nclient.on(Events.Error, console.error);\n\nconst commands = {\n  eval: message => {\n    if (message.author.id !== owner) return;\n    let res;\n    try {\n      res = eval(message.content);\n      if (typeof res !== 'string') res = require('node:util').inspect(res);\n    } catch (err) {\n      // eslint-disable-next-line no-console\n      console.error(err.stack);\n      res = err.message;\n    }\n    message.channel.send(codeBlock(res));\n  },\n  ping: message => message.channel.send('pong'),\n};\n\nclient.on(Events.MessageCreate, message => {\n  if (!message.content.startsWith(prefix) || message.author.bot) return;\n\n  message.content = message.content.replace(prefix, '').trim().split(' ');\n  const command = message.content.shift();\n  message.content = message.content.join(' ');\n\n  // eslint-disable-next-line no-console\n  console.log('COMMAND', command, message.content);\n\n  if (command in commands) commands[command](message);\n});\n\nclient.login(token);\n\n// eslint-disable-next-line no-console\nprocess.on('unhandledRejection', console.error);\n"
  },
  {
    "path": "packages/discord.js/test/webhooktest.js",
    "content": "'use strict';\n\nconst { Buffer } = require('node:buffer');\nconst fs = require('node:fs');\nconst path = require('node:path');\nconst { setTimeout: sleep } = require('node:timers/promises');\nconst util = require('node:util');\nconst { GatewayIntentBits } = require('discord-api-types/v10');\nconst { fetch } = require('undici');\nconst { Client, MessageAttachment, Embed } = require('../src/index.js');\nconst { owner, token, webhookChannel, webhookToken } = require('./auth.js');\n\nconst client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages] });\n\nconst buffer = l =>\n  fetch(l)\n    .then(res => res.arrayBuffer())\n    .then(Buffer.from);\nconst read = util.promisify(fs.readFile);\nconst readStream = fs.createReadStream;\n\nconst linkA = 'https://lolisafe.moe/iiDMtAXA.png';\nconst linkB = 'https://lolisafe.moe/9hSpedPh.png';\nconst fileA = path.join(__dirname, 'blobReach.png');\n\nconst embed = () => new Embed();\nconst attach = (attachment, name) => new MessageAttachment(attachment, name);\n\nconst tests = [\n  (m, hook) => hook.send('x'),\n  (m, hook) => hook.send('x', { code: true }),\n  (m, hook) => hook.send('1', { code: 'js' }),\n  (m, hook) => hook.send('x', { code: '' }),\n\n  (m, hook) => hook.send({ embeds: [{ description: 'a' }] }),\n  (m, hook) => hook.send({ files: [{ attachment: linkA }] }),\n  (m, hook) =>\n    hook.send({\n      embeds: [{ description: 'a' }],\n      files: [{ attachment: linkA, name: 'xyz.png' }],\n    }),\n\n  (m, hook) => hook.send('x', embed().setDescription('a')),\n  (m, hook) => hook.send(embed().setDescription('a')),\n  (m, hook) => hook.send({ embeds: [embed().setDescription('a')] }),\n  (m, hook) => hook.send([embed().setDescription('a'), embed().setDescription('b')]),\n\n  (m, hook) => hook.send('x', attach(linkA)),\n  (m, hook) => hook.send(attach(linkA)),\n  (m, hook) => hook.send({ files: [linkA] }),\n  (m, hook) => hook.send({ files: [attach(linkA)] }),\n  async (m, hook) => hook.send(attach(await buffer(linkA))),\n  async (m, hook) => hook.send({ files: [await buffer(linkA)] }),\n  async (m, hook) => hook.send({ files: [{ attachment: await buffer(linkA) }] }),\n  (m, hook) => hook.send([attach(linkA), attach(linkB)]),\n\n  (m, hook) => hook.send(embed().setDescription('a')),\n\n  (m, hook) => hook.send({ embeds: [{ description: 'a' }] }),\n  (m, hook) => hook.send(embed().setDescription('a')),\n\n  (m, hook) => hook.send('x', [embed().setDescription('a'), attach(linkB)]),\n  (m, hook) => hook.send('x', [attach(linkA), attach(linkB)]),\n\n  (m, hook) => hook.send([embed().setDescription('a'), attach(linkB)]),\n  (m, hook) =>\n    hook.send({\n      embeds: [embed().setImage('attachment://two.png')],\n      files: [attach(linkB, 'two.png')],\n    }),\n\n  (m, hook) => hook.send('x', attach(fileA)),\n  (m, hook) => hook.send({ files: [fileA] }),\n  (m, hook) => hook.send(attach(fileA)),\n  async (m, hook) => hook.send({ files: [await read(fileA)] }),\n\n  (m, hook) => hook.send('x', attach(readStream(fileA))),\n  (m, hook) => hook.send({ files: [readStream(fileA)] }),\n  (m, hook) => hook.send({ files: [{ attachment: readStream(fileA) }] }),\n  (m, hook) => hook.send('Done!'),\n];\n\nclient.on('messageCreate', async message => {\n  if (message.author.id !== owner) return;\n  const match = message.content.match(/^do (.+)$/);\n  const hooks = [\n    { type: 'TextChannel#fetchWebhooks', hook: await message.channel.fetchWebhooks().then(x => x.first()) },\n    { type: 'Guild#fetchWebhooks', hook: await message.guild.fetchWebhooks().then(x => x.first()) },\n  ];\n  if (match?.[1] === 'it') {\n    for (const { type, hook } of hooks) {\n      for (const [i, test] of tests.entries()) {\n        await message.channel.send(`**#${i}-Hook: ${type}**\\n\\`\\`\\`js\\n${test.toString()}\\`\\`\\``);\n        await test(message, hook).catch(error => message.channel.send(`Error!\\n\\`\\`\\`\\n${error}\\`\\`\\``));\n        await sleep(1_000);\n      }\n    }\n  } else if (match) {\n    const n = Number.parseInt(match[1]) || 0;\n    const test = tests.slice(n)[0];\n    const i = tests.indexOf(test);\n\n    for (const { type, hook } of hooks) {\n      await message.channel.send(`**#${i}-Hook: ${type}**\\n\\`\\`\\`js\\n${test.toString()}\\`\\`\\``);\n      await test(message, hook).catch(error => message.channel.send(`Error!\\n\\`\\`\\`\\n${error}\\`\\`\\``));\n    }\n  }\n});\n\nclient.login(token);\n"
  },
  {
    "path": "packages/discord.js/tsconfig.eslint.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"allowJs\": true\n  },\n  \"include\": [\n    \"*.ts\",\n    \"src/**/*.ts\",\n    \"typings/**/*.d.ts\",\n    \"typings/**/*.d.mts\",\n    \"typings/**/*.test-d.ts\",\n    \"typings/**/*.test-d.mts\",\n    \"bin\",\n    \"scripts\",\n    \"__tests__\",\n    \"__mocks__\"\n  ],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/discord.js/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    // Output Formatting\n    \"pretty\": false,\n\n    // Completeness\n    \"skipDefaultLibCheck\": true,\n\n    \"types\": [\n      \"@discordjs/builders\",\n      \"@discordjs/util\",\n      \"@discordjs/collection\",\n      \"@discordjs/rest\",\n      \"@discordjs/ws\",\n      \"discord-api-types/v10\",\n      \"node\",\n      \"tsd\",\n      \"undici\",\n      \"@sapphire/snowflake\"\n    ]\n  }\n}\n"
  },
  {
    "path": "packages/discord.js/tsdoc.json",
    "content": "{\n  \"$schema\": \"https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json\",\n  \"extends\": [\"@discordjs/api-extractor/extends/tsdoc-base.json\"],\n  \"tagDefinitions\": [\n    {\n      \"tagName\": \"@unstable\",\n      \"syntaxKind\": \"modifier\"\n    }\n  ],\n  \"supportForTags\": {\n    \"@unstable\": true\n  }\n}\n"
  },
  {
    "path": "packages/discord.js/typings/index.d.ts",
    "content": "import { Buffer } from 'node:buffer';\nimport { ChildProcess } from 'node:child_process';\nimport { Stream } from 'node:stream';\nimport { MessagePort, Worker } from 'node:worker_threads';\nimport { Collection, ReadonlyCollection } from '@discordjs/collection';\nimport { BaseImageURLOptions, ImageURLOptions, RawFile, REST, RESTOptions, EmojiURLOptions } from '@discordjs/rest';\nimport { Awaitable, FileBodyEncodable, JSONEncodable } from '@discordjs/util';\nimport { WebSocketManager, WebSocketManagerOptions } from '@discordjs/ws';\nimport { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';\nimport {\n  ActivityFlags,\n  ActivityType,\n  APIActionRowComponent,\n  APIApplicationCommand,\n  APIApplicationCommandInteractionData,\n  APIApplicationCommandOption,\n  APIApplicationRoleConnectionMetadata,\n  APIAttachment,\n  APIAuditLog,\n  APIAuditLogChange,\n  APIAuditLogEntry,\n  APIAuthorizingIntegrationOwnersMap,\n  APIAutoModerationRule,\n  APIButtonComponent,\n  APIChannel,\n  APIChannelSelectComponent,\n  APIComponentInActionRow,\n  APIComponentInContainer,\n  APIComponentInMessageActionRow,\n  APIComponentInModalActionRow,\n  APIContainerComponent,\n  APIEmbed,\n  APIEmbedField,\n  APIEmbedProvider,\n  APIEmoji,\n  APIEntitlement,\n  APIFileComponent,\n  APIGuild,\n  APIGuildIntegration,\n  APIGuildMember,\n  APIGuildOnboardingPrompt,\n  APIGuildOnboardingPromptOption,\n  APIGuildPreview,\n  APIGuildScheduledEvent,\n  APIGuildWelcomeScreen,\n  APIGuildWelcomeScreenChannel,\n  APIGuildWidget,\n  APIGuildWidgetMember,\n  APIInteractionDataResolvedChannel,\n  APIInteractionDataResolvedGuildMember,\n  APIInteractionGuildMember,\n  APILabelComponent,\n  APIMediaGalleryComponent,\n  APIMediaGalleryItem,\n  APIMentionableSelectComponent,\n  APIMessage,\n  APIMessageButtonInteractionData,\n  APIMessageChannelSelectInteractionData,\n  APIMessageComponent,\n  APIMessageComponentEmoji,\n  APIMessageComponentInteraction,\n  APIMessageMentionableSelectInteractionData,\n  APIMessageRoleSelectInteractionData,\n  APIMessageStringSelectInteractionData,\n  APIMessageTopLevelComponent,\n  APIMessageUserSelectInteractionData,\n  APIModalComponent,\n  APIModalInteractionResponseCallbackData,\n  APIModalSubmitInteraction,\n  APIOverwrite,\n  APIPartialChannel,\n  APIPartialEmoji,\n  APIPartialGuild,\n  APIPoll,\n  APIPollAnswer,\n  APIRole,\n  APIRoleSelectComponent,\n  APISectionComponent,\n  APISelectMenuComponent,\n  APISelectMenuDefaultValue,\n  APISelectMenuOption,\n  APISeparatorComponent,\n  APISKU,\n  APISoundboardSound,\n  APIStickerPack,\n  APIStringSelectComponent,\n  APISubscription,\n  APITeam,\n  APITeamMember,\n  APITemplate,\n  APITemplateSerializedSourceGuild,\n  APITextDisplayComponent,\n  APITextInputComponent,\n  APIThreadMember,\n  APIThumbnailComponent,\n  APIUnavailableGuild,\n  APIUnfurledMediaItem,\n  APIUser,\n  APIUserSelectComponent,\n  APIVoiceRegion,\n  ApplicationCommandOptionAllowedChannelType,\n  ApplicationCommandOptionType,\n  ApplicationCommandPermissionType,\n  ApplicationCommandType,\n  ApplicationFlags,\n  ApplicationIntegrationType,\n  ApplicationRoleConnectionMetadataType,\n  ApplicationWebhookEventStatus,\n  ApplicationWebhookEventType,\n  AttachmentFlags,\n  AuditLogEvent,\n  AuditLogOptionsType,\n  AuditLogRuleTriggerType,\n  AutoModerationActionType,\n  AutoModerationRuleEventType,\n  AutoModerationRuleKeywordPresetType,\n  AutoModerationRuleTriggerType,\n  ButtonStyle,\n  ChannelFlags,\n  ChannelType,\n  ComponentType,\n  EmbedType,\n  EntitlementType,\n  EntryPointCommandHandlerType,\n  FormattingPatterns,\n  ForumLayoutType,\n  GatewayActivity,\n  GatewayActivityAssets,\n  GatewayAutoModerationActionExecutionDispatchData,\n  GatewayDispatchPayload,\n  GatewayIntentBits,\n  GatewayInteractionCreateDispatchData,\n  GatewayMessageUpdateDispatchData,\n  GatewayPresenceUpdate,\n  GatewaySendPayload,\n  GatewayTypingStartDispatchData,\n  GatewayVoiceChannelEffectSendDispatchData,\n  GatewayVoiceServerUpdateDispatchData,\n  GatewayVoiceStateUpdateDispatchData,\n  GuildDefaultMessageNotifications,\n  GuildExplicitContentFilter,\n  GuildFeature,\n  GuildMemberFlags,\n  GuildMFALevel,\n  GuildNSFWLevel,\n  GuildOnboardingMode,\n  GuildOnboardingPromptType,\n  GuildPremiumTier,\n  GuildScheduledEventEntityType,\n  GuildScheduledEventPrivacyLevel,\n  GuildScheduledEventRecurrenceRuleFrequency,\n  GuildScheduledEventRecurrenceRuleMonth,\n  GuildScheduledEventRecurrenceRuleWeekday,\n  GuildScheduledEventStatus,\n  GuildSystemChannelFlags,\n  GuildVerificationLevel,\n  GuildWidgetStyle,\n  ImageFormat,\n  IntegrationExpireBehavior,\n  InteractionContextType,\n  InteractionResponseType,\n  InteractionType,\n  InviteFlags,\n  InviteTargetType,\n  InviteType,\n  Locale,\n  LocalizationMap,\n  MessageActivityType,\n  MessageFlags,\n  MessageReferenceType,\n  MessageType,\n  NameplatePalette,\n  OAuth2Scopes,\n  OverwriteType,\n  PermissionFlagsBits,\n  PollLayoutType,\n  ReactionType,\n  RESTAPIInteractionCallbackActivityInstanceResource,\n  RESTAPIInteractionCallbackObject,\n  RESTAPIInteractionCallbackResourceObject,\n  RESTAPIPartialCurrentUserGuild,\n  RESTAPIPoll,\n  RESTGetAPIGuildOnboardingResult,\n  RESTGetAPIGuildThreadsResult,\n  RESTPatchAPIChannelMessageJSONBody,\n  RESTPatchAPIInteractionFollowupJSONBody,\n  RESTPatchAPIInteractionOriginalResponseJSONBody,\n  RESTPatchAPIWebhookWithTokenJSONBody,\n  RESTPostAPIApplicationCommandsJSONBody,\n  RESTPostAPIChannelMessageJSONBody,\n  RESTPostAPIInteractionCallbackFormDataBody,\n  RESTPostAPIInteractionCallbackWithResponseResult,\n  RESTPostAPIInteractionFollowupJSONBody,\n  RESTPostAPIWebhookWithTokenJSONBody,\n  RoleFlags,\n  SelectMenuDefaultValueType,\n  SeparatorSpacingSize,\n  SKUFlags,\n  SKUType,\n  Snowflake,\n  SortOrderType,\n  StageInstancePrivacyLevel,\n  StickerFormatType,\n  StickerType,\n  SubscriptionStatus,\n  TeamMemberMembershipState,\n  TeamMemberRole,\n  TextChannelType,\n  TextInputStyle,\n  ThreadAutoArchiveDuration,\n  ThreadChannelType,\n  ThreadMemberFlags,\n  UserFlags,\n  VideoQualityMode,\n  VoiceChannelEffectSendAnimationType,\n  WebhookType,\n} from 'discord-api-types/v10';\n\n// #region Classes\n\nexport class Activity {\n  private constructor(presence: Presence, data?: GatewayActivity);\n  public readonly presence: Presence;\n  public applicationId: Snowflake | null;\n  public assets: RichPresenceAssets | null;\n  public buttons: string[];\n  public get createdAt(): Date;\n  public createdTimestamp: number;\n  public details: string | null;\n  public emoji: Emoji | null;\n  public flags: Readonly<ActivityFlagsBitField>;\n  public name: string;\n  public party: {\n    id: string | null;\n    size: [number, number];\n  } | null;\n  public state: string | null;\n  public syncId: string | null;\n  public timestamps: {\n    end: Date | null;\n    start: Date | null;\n  } | null;\n  public type: ActivityType;\n  public url: string | null;\n  public equals(activity: Activity): boolean;\n  public toString(): string;\n}\n\nexport type ActivityFlagsString = keyof typeof ActivityFlags;\n\nexport interface BaseComponentData {\n  id?: number;\n  type: ComponentType;\n}\n\nexport type MessageActionRowComponentData =\n  | ButtonComponentData\n  | ChannelSelectMenuComponentData\n  | JSONEncodable<APIComponentInMessageActionRow>\n  | MentionableSelectMenuComponentData\n  | RoleSelectMenuComponentData\n  | StringSelectMenuComponentData\n  | UserSelectMenuComponentData;\n\nexport type ActionRowComponentData = MessageActionRowComponentData;\n\nexport type ActionRowComponent = MessageActionRowComponent;\n\nexport interface ActionRowData<\n  ComponentType extends ActionRowComponentData | JSONEncodable<APIComponentInActionRow>,\n> extends BaseComponentData {\n  components: readonly ComponentType[];\n}\n\nexport type ComponentInLabelData =\n  | ChannelSelectMenuComponentData\n  | CheckboxComponentData\n  | CheckboxGroupComponentData\n  | FileUploadComponentData\n  | MentionableSelectMenuComponentData\n  | RadioGroupComponentData\n  | RoleSelectMenuComponentData\n  | StringSelectMenuComponentData\n  | TextInputComponentData\n  | UserSelectMenuComponentData;\n\nexport interface LabelData extends BaseComponentData {\n  component: ComponentInLabelData;\n  description?: string;\n  label: string;\n}\n\nexport type MessageActionRowComponent =\n  | ButtonComponent\n  | ChannelSelectMenuComponent\n  | MentionableSelectMenuComponent\n  | RoleSelectMenuComponent\n  | StringSelectMenuComponent\n  | UserSelectMenuComponent;\n\nexport class ActionRow<ComponentType extends MessageActionRowComponent> extends Component<\n  APIActionRowComponent<APIComponentInMessageActionRow>\n> {\n  private constructor(data: APIActionRowComponent<APIComponentInMessageActionRow>);\n  public readonly components: ComponentType[];\n  public toJSON(): APIActionRowComponent<ReturnType<ComponentType['toJSON']>>;\n}\n\nexport class ActivityFlagsBitField extends BitField<ActivityFlagsString> {\n  public static Flags: typeof ActivityFlags;\n  public static resolve(bit?: BitFieldResolvable<ActivityFlagsString, number>): number;\n}\n\nexport abstract class AnonymousGuild extends BaseGuild {\n  protected constructor(client: Client<true>, data: unknown, immediatePatch?: boolean);\n  public banner: string | null;\n  public description: string | null;\n  public nsfwLevel: GuildNSFWLevel;\n  public premiumSubscriptionCount: number | null;\n  public splash: string | null;\n  public vanityURLCode: string | null;\n  public verificationLevel: GuildVerificationLevel;\n  public bannerURL(options?: ImageURLOptions): string | null;\n  public splashURL(options?: ImageURLOptions): string | null;\n}\n\nexport class AutoModerationActionExecution {\n  private constructor(data: GatewayAutoModerationActionExecutionDispatchData, guild: Guild);\n  public guild: Guild;\n  public action: AutoModerationAction;\n  public ruleId: Snowflake;\n  public ruleTriggerType: AutoModerationRuleTriggerType;\n  public get user(): User | null;\n  public userId: Snowflake;\n  public get channel(): ForumChannel | GuildTextBasedChannel | MediaChannel | null;\n  public channelId: Snowflake | null;\n  public get member(): GuildMember | null;\n  public messageId: Snowflake | null;\n  public alertSystemMessageId: Snowflake | null;\n  public content: string;\n  public matchedKeyword: string | null;\n  public matchedContent: string | null;\n  public get autoModerationRule(): AutoModerationRule | null;\n}\n\nexport class AutoModerationRule extends Base {\n  private constructor(client: Client<true>, data: APIAutoModerationRule, guild: Guild);\n  public id: Snowflake;\n  public guild: Guild;\n  public name: string;\n  public creatorId: Snowflake;\n  public eventType: AutoModerationRuleEventType;\n  public triggerType: AutoModerationRuleTriggerType;\n  public triggerMetadata: AutoModerationTriggerMetadata;\n  public actions: AutoModerationAction[];\n  public enabled: boolean;\n  public exemptRoles: Collection<Snowflake, Role>;\n  public exemptChannels: Collection<Snowflake, GuildBasedChannel>;\n  public edit(options: AutoModerationRuleEditOptions): Promise<AutoModerationRule>;\n  public delete(reason?: string): Promise<void>;\n  public setName(name: string, reason?: string): Promise<AutoModerationRule>;\n  public setEventType(eventType: AutoModerationRuleEventType, reason?: string): Promise<AutoModerationRule>;\n  public setKeywordFilter(keywordFilter: readonly string[], reason?: string): Promise<AutoModerationRule>;\n  public setRegexPatterns(regexPatterns: readonly string[], reason?: string): Promise<AutoModerationRule>;\n  public setPresets(\n    presets: readonly AutoModerationRuleKeywordPresetType[],\n    reason?: string,\n  ): Promise<AutoModerationRule>;\n  public setAllowList(allowList: readonly string[], reason?: string): Promise<AutoModerationRule>;\n  public setMentionTotalLimit(mentionTotalLimit: number, reason?: string): Promise<AutoModerationRule>;\n  public setMentionRaidProtectionEnabled(\n    mentionRaidProtectionEnabled: boolean,\n    reason?: string,\n  ): Promise<AutoModerationRule>;\n  public setActions(actions: readonly AutoModerationActionOptions[], reason?: string): Promise<AutoModerationRule>;\n  public setEnabled(enabled?: boolean, reason?: string): Promise<AutoModerationRule>;\n  public setExemptRoles(\n    roles: ReadonlyCollection<Snowflake, Role> | readonly RoleResolvable[],\n    reason?: string,\n  ): Promise<AutoModerationRule>;\n  public setExemptChannels(\n    channels: ReadonlyCollection<Snowflake, GuildBasedChannel> | readonly GuildChannelResolvable[],\n    reason?: string,\n  ): Promise<AutoModerationRule>;\n}\n\nexport abstract class Application extends Base {\n  protected constructor(client: Client<true>, data: unknown);\n  public get createdAt(): Date;\n  public get createdTimestamp(): number;\n  public description: string | null;\n  public icon: string | null;\n  public id: Snowflake;\n  public name: string | null;\n  public termsOfServiceURL: string | null;\n  public privacyPolicyURL: string | null;\n  public rpcOrigins: string[];\n  public cover: string | null;\n  public verifyKey: string | null;\n  public coverURL(options?: ImageURLOptions): string | null;\n  public iconURL(options?: ImageURLOptions): string | null;\n  public toJSON(): unknown;\n  public toString(): string | null;\n}\n\nexport class ApplicationCommand<PermissionsFetchType = {}> extends Base {\n  private constructor(client: Client<true>, data: APIApplicationCommand, guild?: Guild, guildId?: Snowflake);\n  public applicationId: Snowflake;\n  public contexts: InteractionContextType[] | null;\n  public get createdAt(): Date;\n  public get createdTimestamp(): number;\n  public defaultMemberPermissions: Readonly<PermissionsBitField> | null;\n  public description: string;\n  public descriptionLocalizations: LocalizationMap | null;\n  public descriptionLocalized: string | null;\n  public guild: Guild | null;\n  public guildId: Snowflake | null;\n  public get manager(): ApplicationCommandManager;\n  public id: Snowflake;\n  public integrationTypes: ApplicationIntegrationType[] | null;\n  public handler: EntryPointCommandHandlerType | null;\n  public name: string;\n  public nameLocalizations: LocalizationMap | null;\n  public nameLocalized: string | null;\n  public options: (ApplicationCommandOption & { descriptionLocalized?: string; nameLocalized?: string })[] | null;\n  public permissions: ApplicationCommandPermissionsManager<\n    PermissionsFetchType,\n    PermissionsFetchType,\n    Guild | null,\n    Snowflake\n  >;\n  public type: ApplicationCommandType;\n  public version: Snowflake;\n  public nsfw: boolean;\n  public delete(): Promise<ApplicationCommand<PermissionsFetchType>>;\n  public edit(data: Partial<ApplicationCommandData>): Promise<ApplicationCommand<PermissionsFetchType>>;\n  public setName(name: string): Promise<ApplicationCommand<PermissionsFetchType>>;\n  public setNameLocalizations(nameLocalizations: LocalizationMap): Promise<ApplicationCommand<PermissionsFetchType>>;\n  public setDescription(description: string): Promise<ApplicationCommand<PermissionsFetchType>>;\n  public setDescriptionLocalizations(\n    descriptionLocalizations: LocalizationMap,\n  ): Promise<ApplicationCommand<PermissionsFetchType>>;\n  public setDefaultMemberPermissions(\n    defaultMemberPermissions: PermissionResolvable | null,\n  ): Promise<ApplicationCommand<PermissionsFetchType>>;\n  public setOptions(\n    options: readonly ApplicationCommandOptionData[],\n  ): Promise<ApplicationCommand<PermissionsFetchType>>;\n  public equals(\n    command: APIApplicationCommand | ApplicationCommand | ApplicationCommandData,\n    enforceOptionOrder?: boolean,\n  ): boolean;\n  public static optionsEqual(\n    existing: readonly ApplicationCommandOption[],\n    options:\n      | readonly APIApplicationCommandOption[]\n      | readonly ApplicationCommandOption[]\n      | readonly ApplicationCommandOptionData[],\n    enforceOptionOrder?: boolean,\n  ): boolean;\n  private static _optionEquals(\n    existing: ApplicationCommandOption,\n    options: APIApplicationCommandOption | ApplicationCommandOption | ApplicationCommandOptionData,\n    enforceOptionOrder?: boolean,\n  ): boolean;\n  private static transformOption(option: ApplicationCommandOptionData, received?: boolean): unknown;\n  private static transformCommand(command: ApplicationCommandData): RESTPostAPIApplicationCommandsJSONBody;\n  private static isAPICommandData(command: object): command is RESTPostAPIApplicationCommandsJSONBody;\n}\n\nexport class ApplicationRoleConnectionMetadata {\n  private constructor(data: APIApplicationRoleConnectionMetadata);\n  public name: string;\n  public nameLocalizations: LocalizationMap | null;\n  public description: string;\n  public descriptionLocalizations: LocalizationMap | null;\n  public key: string;\n  public type: ApplicationRoleConnectionMetadataType;\n}\n\nexport type ApplicationResolvable = Activity | Application | Snowflake;\n\nexport class ApplicationFlagsBitField extends BitField<ApplicationFlagsString> {\n  public static Flags: typeof ApplicationFlags;\n  public static resolve(bit?: BitFieldResolvable<ApplicationFlagsString, number>): number;\n}\n\nexport type ApplicationFlagsResolvable = BitFieldResolvable<ApplicationFlagsString, number>;\n\nexport type AutoModerationRuleResolvable = AutoModerationRule | Snowflake;\n\nexport abstract class Base {\n  public constructor(client: Client<true>);\n  public readonly client: Client<true>;\n  public toJSON(...props: Record<string, boolean | string>[]): unknown;\n  public valueOf(): string;\n}\n\nexport type GuildCacheMessage<Cached extends CacheType> = CacheTypeReducer<\n  Cached,\n  Message<true>,\n  APIMessage,\n  APIMessage | Message,\n  APIMessage | Message\n>;\n\nexport type BooleanCache<Cached extends CacheType> = Cached extends 'cached' ? true : false;\n\nexport abstract class CommandInteraction<Cached extends CacheType = CacheType> extends BaseInteraction<Cached> {\n  public type: InteractionType.ApplicationCommand;\n  public get command(): ApplicationCommand | ApplicationCommand<{ guild: GuildResolvable }> | null;\n  public channelId: Snowflake;\n  public commandId: Snowflake;\n  public commandName: string;\n  public commandType: ApplicationCommandType;\n  public commandGuildId: Snowflake | null;\n  public deferred: boolean;\n  public ephemeral: boolean | null;\n  public replied: boolean;\n  public webhook: InteractionWebhook;\n  public inGuild(): this is CommandInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is CommandInteraction<'cached'>;\n  public inRawGuild(): this is CommandInteraction<'raw'>;\n  public deferReply(\n    options: InteractionDeferReplyOptions & { withResponse: true },\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>>>;\n  public deferReply(options?: InteractionDeferReplyOptions & { withResponse: false }): Promise<undefined>;\n  public deferReply(\n    options?: InteractionDeferReplyOptions,\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>> | undefined>;\n  public deleteReply(message?: MessageResolvable | '@original'): Promise<void>;\n  public editReply(\n    options: InteractionEditReplyOptions | MessagePayload | string,\n  ): Promise<Message<BooleanCache<Cached>>>;\n  public fetchReply(message?: Snowflake | '@original'): Promise<Message<BooleanCache<Cached>>>;\n  public followUp(options: InteractionReplyOptions | MessagePayload | string): Promise<Message<BooleanCache<Cached>>>;\n  public reply(\n    options: InteractionReplyOptions & { withResponse: true },\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>>>;\n  public reply(options: InteractionReplyOptions & { withResponse: false }): Promise<undefined>;\n  public reply(\n    options: InteractionReplyOptions | MessagePayload | string,\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>> | undefined>;\n  public launchActivity(\n    options: LaunchActivityOptions & { withResponse: true },\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>>>;\n  public launchActivity(options?: LaunchActivityOptions & { withResponse?: false }): Promise<undefined>;\n  public launchActivity(\n    options?: LaunchActivityOptions,\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>> | undefined>;\n  public showModal(\n    modal:\n      | APIModalInteractionResponseCallbackData\n      | JSONEncodable<APIModalInteractionResponseCallbackData>\n      | ModalComponentData,\n    options: ShowModalOptions & { withResponse: true },\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>>>;\n  public showModal(\n    modal:\n      | APIModalInteractionResponseCallbackData\n      | JSONEncodable<APIModalInteractionResponseCallbackData>\n      | ModalComponentData,\n    options?: ShowModalOptions & { withResponse: false },\n  ): Promise<undefined>;\n  public showModal(\n    modal:\n      | APIModalInteractionResponseCallbackData\n      | JSONEncodable<APIModalInteractionResponseCallbackData>\n      | ModalComponentData,\n    options?: ShowModalOptions,\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>> | undefined>;\n  public awaitModalSubmit(options: AwaitModalSubmitOptions): Promise<ModalSubmitInteraction<Cached>>;\n  private transformOption(\n    option: APIApplicationCommandOption,\n    resolved: Extract<APIApplicationCommandInteractionData, { resolved: any }>['resolved'],\n  ): CommandInteractionOption<Cached>;\n}\n\nexport abstract class BaseGuild extends Base {\n  protected constructor(client: Client<true>, data: unknown);\n  public get createdAt(): Date;\n  public get createdTimestamp(): number;\n  public features: `${GuildFeature}`[];\n  public icon: string | null;\n  public id: Snowflake;\n  public name: string;\n  public get nameAcronym(): string;\n  public get partnered(): boolean;\n  public get verified(): boolean;\n  public fetch(): Promise<Guild>;\n  public iconURL(options?: ImageURLOptions): string | null;\n  public toString(): string;\n}\n\nexport class BaseGuildEmoji extends Emoji {\n  protected constructor(client: Client<true>, data: APIEmoji, guild: Guild | GuildPreview);\n  public imageURL(options?: EmojiURLOptions): string;\n  public available: boolean | null;\n  public get createdAt(): Date;\n  public get createdTimestamp(): number;\n  public guild: Guild | GuildPreview;\n  public id: Snowflake;\n  public name: string;\n  public animated: boolean;\n  public managed: boolean;\n  public requiresColons: boolean | null;\n}\n\nexport interface BaseGuildTextChannel\n  extends\n    TextBasedChannelFields<true>,\n    PinnableChannelFields,\n    WebhookChannelFields,\n    BulkDeleteMethod,\n    SetRateLimitPerUserMethod,\n    MessageChannelFields,\n    SendMethod<true> {}\nexport class BaseGuildTextChannel extends GuildChannel {\n  protected constructor(guild: Guild, data?: RawGuildChannelData, client?: Client<true>, immediatePatch?: boolean);\n  public defaultAutoArchiveDuration?: ThreadAutoArchiveDuration;\n  public defaultThreadRateLimitPerUser: number | null;\n  public rateLimitPerUser: number | null;\n  public nsfw: boolean;\n  public threads: GuildTextThreadManager<AllowedThreadTypeForAnnouncementChannel | AllowedThreadTypeForTextChannel>;\n  public topic: string | null;\n  public createInvite(options?: InviteCreateOptions): Promise<GuildInvite>;\n  public fetchInvites(cache?: boolean): Promise<Collection<string, GuildInvite>>;\n  public setDefaultAutoArchiveDuration(\n    defaultAutoArchiveDuration: ThreadAutoArchiveDuration,\n    reason?: string,\n  ): Promise<this>;\n  public setTopic(topic: string | null, reason?: string): Promise<this>;\n  public setType(type: ChannelType.GuildText, reason?: string): Promise<TextChannel>;\n  public setType(type: ChannelType.GuildAnnouncement, reason?: string): Promise<AnnouncementChannel>;\n}\n\nexport interface BaseGuildVoiceChannel\n  extends\n    TextBasedChannelFields<true>,\n    WebhookChannelFields,\n    BulkDeleteMethod,\n    SetRateLimitPerUserMethod,\n    MessageChannelFields,\n    SendMethod<true> {}\nexport class BaseGuildVoiceChannel extends GuildChannel {\n  public constructor(guild: Guild, data?: RawGuildChannelData);\n  public bitrate: number;\n  public get full(): boolean;\n  public get joinable(): boolean;\n  public get members(): Collection<Snowflake, GuildMember>;\n  public nsfw: boolean;\n  public rateLimitPerUser: number | null;\n  public rtcRegion: string | null;\n  public userLimit: number;\n  public videoQualityMode: VideoQualityMode | null;\n  public createInvite(options?: InviteCreateOptions): Promise<GuildInvite>;\n  public fetchInvites(cache?: boolean): Promise<Collection<string, GuildInvite>>;\n  public setBitrate(bitrate: number, reason?: string): Promise<this>;\n  public setRTCRegion(rtcRegion: string | null, reason?: string): Promise<this>;\n  public setUserLimit(userLimit: number, reason?: string): Promise<this>;\n  public setVideoQualityMode(videoQualityMode: VideoQualityMode, reason?: string): Promise<this>;\n}\n\nexport type EnumLike<Enum, Value> = Record<keyof Enum, Value>;\n\nexport class BitField<Flags extends string, Type extends bigint | number = number> {\n  public constructor(bits?: BitFieldResolvable<Flags, Type>);\n  public bitfield: Type;\n  public add(...bits: BitFieldResolvable<Flags, Type>[]): BitField<Flags, Type>;\n  public any(bit: BitFieldResolvable<Flags, Type>): boolean;\n  public equals(bit: BitFieldResolvable<Flags, Type>): boolean;\n  public freeze(): Readonly<BitField<Flags, Type>>;\n  public has(bit: BitFieldResolvable<Flags, Type>): boolean;\n  public missing(bits: BitFieldResolvable<Flags, Type>, ...hasParams: readonly unknown[]): Flags[];\n  public remove(...bits: BitFieldResolvable<Flags, Type>[]): BitField<Flags, Type>;\n  public serialize(...hasParams: readonly unknown[]): Record<Flags, boolean>;\n  public toArray(...hasParams: readonly unknown[]): Flags[];\n  public toJSON(): Type extends number ? number : string;\n  public valueOf(): Type;\n  public [Symbol.iterator](): IterableIterator<Flags>;\n  public static Flags: EnumLike<unknown, bigint | number>;\n  public static resolve(bit?: BitFieldResolvable<string, bigint | number>): bigint | number;\n}\n\nexport class ButtonInteraction<Cached extends CacheType = CacheType> extends MessageComponentInteraction<Cached> {\n  private constructor(client: Client<true>, data: APIMessageButtonInteractionData);\n  public componentType: ComponentType.Button;\n  public get component(): CacheTypeReducer<\n    Cached,\n    ButtonComponent,\n    APIButtonComponent,\n    APIButtonComponent | ButtonComponent,\n    APIButtonComponent | ButtonComponent\n  >;\n  public inGuild(): this is ButtonInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is ButtonInteraction<'cached'>;\n  public inRawGuild(): this is ButtonInteraction<'raw'>;\n}\n\nexport type AnyComponent =\n  | AnyComponentV2\n  | APIActionRowComponent<APIComponentInMessageActionRow | APIComponentInModalActionRow>\n  | APIMessageComponent\n  | APIModalComponent;\n\nexport class Component<RawComponentData extends AnyComponent = AnyComponent> {\n  public readonly data: Readonly<RawComponentData>;\n  public get id(): RawComponentData['id'];\n  public get type(): RawComponentData['type'];\n  public toJSON(): RawComponentData;\n  public equals(other: RawComponentData | this): boolean;\n}\n\nexport type AnyComponentV2 = APIComponentInContainer | APIContainerComponent | APIThumbnailComponent;\n\nexport type TopLevelComponent =\n  | ActionRow<MessageActionRowComponent>\n  | ContainerComponent\n  | FileComponent\n  | MediaGalleryComponent\n  | SectionComponent\n  | SeparatorComponent\n  | TextDisplayComponent;\n\nexport type TopLevelComponentData =\n  | ActionRowData<MessageActionRowComponentData>\n  | ContainerComponentData\n  | FileComponentData\n  | MediaGalleryComponentData\n  | SectionComponentData\n  | SeparatorComponentData\n  | TextDisplayComponentData;\n\nexport class ButtonComponent extends Component<APIButtonComponent> {\n  private constructor(data: APIButtonComponent);\n  public get style(): ButtonStyle;\n  public get label(): string | null;\n  public get emoji(): APIMessageComponentEmoji | null;\n  public get disabled(): boolean;\n  public get customId(): string | null;\n  public get url(): string | null;\n}\n\nexport type ComponentEmojiResolvable = APIMessageComponentEmoji | string;\n\nexport class TextInputComponent extends Component<APITextInputComponent> {\n  public get customId(): string;\n  public get value(): string;\n}\n\nexport class LabelComponent extends Component<APILabelComponent> {\n  public component: StringSelectMenuComponent | TextInputComponent;\n  public get label(): string;\n  public get description(): string | null;\n}\n\nexport class BaseSelectMenuComponent<Data extends APISelectMenuComponent> extends Component<Data> {\n  protected constructor(data: Data);\n  public get placeholder(): string | null;\n  public get maxValues(): number | null;\n  public get minValues(): number | null;\n  public get customId(): string;\n  public get disabled(): boolean;\n}\n\nexport class StringSelectMenuComponent extends BaseSelectMenuComponent<APIStringSelectComponent> {\n  public get options(): APISelectMenuOption[];\n}\n\nexport class UserSelectMenuComponent extends BaseSelectMenuComponent<APIUserSelectComponent> {}\n\nexport class RoleSelectMenuComponent extends BaseSelectMenuComponent<APIRoleSelectComponent> {}\n\nexport class MentionableSelectMenuComponent extends BaseSelectMenuComponent<APIMentionableSelectComponent> {}\n\nexport class ChannelSelectMenuComponent extends BaseSelectMenuComponent<APIChannelSelectComponent> {\n  public getChannelTypes(): ChannelType[] | null;\n}\n\nexport interface EmbedData {\n  author?: EmbedAuthorData;\n  color?: number;\n  description?: string;\n  fields?: readonly APIEmbedField[];\n  footer?: EmbedFooterData;\n  image?: EmbedAssetData;\n  provider?: APIEmbedProvider;\n  thumbnail?: EmbedAssetData;\n  timestamp?: Date | number | string;\n  title?: string;\n  type?: EmbedType;\n  url?: string;\n  video?: EmbedAssetData;\n}\n\nexport interface IconData {\n  iconURL?: string;\n  proxyIconURL?: string;\n}\n\nexport interface EmbedAuthorData extends IconData {\n  name: string;\n  url?: string;\n}\n\nexport interface EmbedFooterData extends IconData {\n  text: string;\n}\n\nexport interface EmbedAssetData {\n  height?: number;\n  proxyURL?: string;\n  url: string;\n  width?: number;\n}\n\nexport class Embed {\n  private constructor(data: APIEmbed);\n  public readonly data: Readonly<APIEmbed>;\n  public get fields(): APIEmbedField[];\n  public get footer(): EmbedFooterData | null;\n  public get title(): string | null;\n  public get description(): string | null;\n  public get url(): string | null;\n  public get color(): number | null;\n  public get hexColor(): string | null;\n  public get timestamp(): string | null;\n  public get thumbnail(): EmbedAssetData | null;\n  public get image(): EmbedAssetData | null;\n  public get author(): EmbedAuthorData | null;\n  public get provider(): APIEmbedProvider | null;\n  public get video(): EmbedAssetData | null;\n  public get length(): number;\n  public equals(other: APIEmbed | Embed): boolean;\n  public toJSON(): APIEmbed;\n}\n\nexport interface MappedChannelCategoryTypes {\n  [ChannelType.GuildAnnouncement]: AnnouncementChannel;\n  [ChannelType.GuildVoice]: VoiceChannel;\n  [ChannelType.GuildText]: TextChannel;\n  [ChannelType.GuildStageVoice]: StageChannel;\n  [ChannelType.GuildForum]: ForumChannel;\n  [ChannelType.GuildMedia]: MediaChannel;\n}\n\nexport type CategoryChannelChildTypes =\n  | ChannelType.GuildAnnouncement\n  | ChannelType.GuildForum\n  | ChannelType.GuildMedia\n  | ChannelType.GuildStageVoice\n  | ChannelType.GuildText\n  | ChannelType.GuildVoice;\n\nexport class CategoryChannel extends GuildChannel {\n  public get children(): CategoryChannelChildManager;\n  public type: ChannelType.GuildCategory;\n  public get parent(): null;\n  public parentId: null;\n}\n\nexport type CategoryChannelResolvable = CategoryChannel | Snowflake;\n\nexport type ChannelFlagsString = keyof typeof ChannelFlags;\n\nexport type ChannelFlagsResolvable = BitFieldResolvable<ChannelFlagsString, number>;\n\nexport class ChannelFlagsBitField extends BitField<ChannelFlagsString> {\n  public static Flags: typeof ChannelFlags;\n  public static resolve(bit?: BitFieldResolvable<ChannelFlagsString, ChannelFlags>): number;\n}\n\nexport abstract class BaseChannel extends Base {\n  public constructor(client: Client<true>, data?: RawChannelData, immediatePatch?: boolean);\n  public get createdAt(): Date | null;\n  public get createdTimestamp(): number | null;\n  public id: Snowflake;\n  public flags: Readonly<ChannelFlagsBitField> | null;\n  public get partial(): false;\n  public type: ChannelType;\n  public get url(): string;\n  public delete(): Promise<this>;\n  public fetch(force?: boolean): Promise<this>;\n  public isThread(): this is AnyThreadChannel;\n  public isTextBased(): this is TextBasedChannel;\n  public isDMBased(): this is DMChannel | PartialDMChannel | PartialGroupDMChannel;\n  public isVoiceBased(): this is VoiceBasedChannel;\n  public isThreadOnly(): this is ThreadOnlyChannel;\n  public isSendable(): this is SendableChannels;\n  public toString(): ChannelMention | UserMention;\n}\n\nexport type RawChannelData =\n  | RawDMChannelData\n  | RawGuildChannelData\n  | RawPartialGroupDMChannelData\n  | RawThreadChannelData;\n\nexport type RawGuildChannelData = APIChannel | APIInteractionDataResolvedChannel | Required<APIPartialChannel>;\nexport type RawThreadChannelData = APIChannel | APIInteractionDataResolvedChannel;\nexport type RawDMChannelData = APIChannel | APIInteractionDataResolvedChannel;\nexport type RawPartialGroupDMChannelData = APIChannel | Required<APIPartialChannel>;\n\nexport type If<Value extends boolean, TrueResult, FalseResult = null> = Value extends true\n  ? TrueResult\n  : Value extends false\n    ? FalseResult\n    : FalseResult | TrueResult;\n\nexport class Client<Ready extends boolean = boolean>\n  extends AsyncEventEmitter<ClientEventTypes>\n  implements AsyncDisposable\n{\n  public constructor(options: ClientOptions);\n  private readonly actions: unknown;\n  private readonly expectedGuilds: Set<Snowflake>;\n  private readonly packetQueue: unknown[];\n  private readonly presence: ClientPresence;\n  private readonly pings: Collection<number, number>;\n  private readonly readyTimeout: NodeJS.Timeout | null;\n  private _broadcast(packet: GatewaySendPayload): void;\n  private _eval(script: string): unknown;\n  private _handlePacket(packet?: GatewayDispatchPayload, shardId?: number): boolean;\n  private _checkReady(): void;\n  private _triggerClientReady(): void;\n  private _validateOptions(options: ClientOptions): void;\n  private get _censoredToken(): string | null;\n  private decrementMaxListeners(): void;\n  private incrementMaxListeners(): void;\n  // This a technique used to brand the ready state. Or else we'll get `never` errors on typeguard checks.\n  private readonly _ready: Ready;\n\n  public application: If<Ready, ClientApplication>;\n  public channels: ChannelManager;\n  public guilds: GuildManager;\n  public lastPingTimestamps: ReadonlyCollection<number, number>;\n  public options: ClientOptions & { intents: IntentsBitField };\n  public get ping(): number | null;\n  public get readyAt(): If<Ready, Date>;\n  public readyTimestamp: If<Ready, number>;\n  public rest: REST;\n  public sweepers: Sweepers;\n  public shard: ShardClientUtil | null;\n  public status: Status;\n  public token: If<Ready, string, string | null>;\n  public get uptime(): If<Ready, number>;\n  public user: If<Ready, ClientUser>;\n  public users: UserManager;\n  public voice: ClientVoiceManager;\n  public ws: WebSocketManager;\n\n  public destroy(): Promise<void>;\n  public deleteWebhook(id: Snowflake, options?: WebhookDeleteOptions): Promise<void>;\n  public fetchGuildPreview(guild: GuildResolvable): Promise<GuildPreview>;\n  public fetchInvite(\n    invite: InviteResolvable,\n    options: ClientFetchInviteOptions & { withCounts: true },\n  ): Promise<Invite<true>>;\n  public fetchInvite(invite: InviteResolvable, options?: ClientFetchInviteOptions): Promise<Invite>;\n  public fetchGuildTemplate(template: GuildTemplateResolvable): Promise<GuildTemplate>;\n  public fetchVoiceRegions(): Promise<Collection<string, VoiceRegion>>;\n  public fetchSticker(id: Snowflake): Promise<Sticker>;\n  public fetchStickerPacks(options: { packId: Snowflake }): Promise<StickerPack>;\n  public fetchStickerPacks(options?: StickerPackFetchOptions): Promise<Collection<Snowflake, StickerPack>>;\n  public fetchDefaultSoundboardSounds(): Promise<Collection<string, DefaultSoundboardSound>>;\n  public fetchWebhook(id: Snowflake, token?: string): Promise<Webhook>;\n  public fetchGuildWidget(guild: GuildResolvable): Promise<Widget>;\n  public generateInvite(options?: InviteGenerationOptions): string;\n  public login(token?: string): Promise<string>;\n  public isReady(): this is Client<true>;\n  public toJSON(): unknown;\n  public [Symbol.asyncDispose](): Promise<void>;\n}\n\nexport interface StickerPackFetchOptions {\n  packId?: Snowflake;\n}\n\nexport class ClientApplication extends Application {\n  private constructor(client: Client<true>, data: unknown);\n  public botPublic: boolean | null;\n  public botRequireCodeGrant: boolean | null;\n  public bot: User | null;\n  public commands: ApplicationCommandManager;\n  public emojis: ApplicationEmojiManager;\n  public entitlements: EntitlementManager;\n  public subscriptions: SubscriptionManager;\n  public guildId: Snowflake | null;\n  public get guild(): Guild | null;\n  public flags: Readonly<ApplicationFlagsBitField>;\n  public approximateGuildCount: number | null;\n  public approximateUserInstallCount: number | null;\n  public approximateUserAuthorizationCount: number | null;\n  public tags: string[];\n  public installParams: ClientApplicationInstallParams | null;\n  public integrationTypesConfig: IntegrationTypesConfiguration | null;\n  public customInstallURL: string | null;\n  public owner: Team | User | null;\n  public get partial(): boolean;\n  public interactionsEndpointURL: string | null;\n  public eventWebhooksURL: string | null;\n  public eventWebhooksStatus: ApplicationWebhookEventStatus | null;\n  public eventWebhooksTypes: ApplicationWebhookEventType[] | null;\n  public roleConnectionsVerificationURL: string | null;\n  public edit(options: ClientApplicationEditOptions): Promise<ClientApplication>;\n  public fetch(): Promise<ClientApplication>;\n  public fetchRoleConnectionMetadataRecords(): Promise<ApplicationRoleConnectionMetadata[]>;\n  public fetchSKUs(): Promise<Collection<Snowflake, SKU>>;\n  public editRoleConnectionMetadataRecords(\n    records: readonly ApplicationRoleConnectionMetadataEditOptions[],\n  ): Promise<ApplicationRoleConnectionMetadata[]>;\n}\n\nexport class ClientPresence extends Presence {\n  private constructor(client: Client<true>, data: GatewayPresenceUpdate);\n  private _parse(data: PresenceData): GatewayPresenceUpdate;\n\n  public set(presence: PresenceData): ClientPresence;\n}\n\nexport class ClientUser extends User {\n  public mfaEnabled: boolean;\n  public get presence(): ClientPresence;\n  public verified: boolean;\n  public edit(options: ClientUserEditOptions): Promise<this>;\n  public setActivity(options?: ActivityOptions): ClientPresence;\n  public setActivity(name: string, options?: Omit<ActivityOptions, 'name'>): ClientPresence;\n  public setAFK(afk?: boolean, shardId?: number | readonly number[]): ClientPresence;\n  public setAvatar(avatar: Base64Resolvable | BufferResolvable | null): Promise<this>;\n  public setBanner(banner: Base64Resolvable | BufferResolvable | null): Promise<this>;\n  public setPresence(data: PresenceData): ClientPresence;\n  public setStatus(status: PresenceStatusData, shardId?: number | readonly number[]): ClientPresence;\n  public setUsername(username: string): Promise<this>;\n}\n\nexport class Options extends null {\n  private constructor();\n  private static readonly userAgentAppendix: string;\n  public static get DefaultMakeCacheSettings(): CacheWithLimitsOptions;\n  public static get DefaultSweeperSettings(): SweeperOptions;\n  public static createDefault(): ClientOptions;\n  public static cacheWithLimits(settings?: CacheWithLimitsOptions): CacheFactory;\n  public static cacheEverything(): CacheFactory;\n}\n\nexport class ClientVoiceManager {\n  private constructor(client: Client);\n  public readonly client: Client;\n  public adapters: Map<Snowflake, InternalDiscordGatewayAdapterLibraryMethods>;\n}\n\nexport type ComponentInContainer =\n  | ActionRow<MessageActionRowComponent>\n  | FileComponent\n  | MediaGalleryComponent\n  | SectionComponent\n  | SeparatorComponent\n  | TextDisplayComponent;\n\nexport type ComponentInContainerData =\n  | ActionRowData<ActionRowComponentData>\n  | FileComponentData\n  | MediaGalleryComponentData\n  | SectionComponentData\n  | SeparatorComponentData\n  | TextDisplayComponentData;\n\nexport interface ContainerComponentData<\n  ComponentType extends ComponentInContainerData | JSONEncodable<APIComponentInContainer> =\n    | ComponentInContainerData\n    | JSONEncodable<APIComponentInContainer>,\n> extends BaseComponentData {\n  accentColor?: number;\n  components: readonly ComponentType[];\n  spoiler?: boolean;\n}\n\nexport class ContainerComponent extends Component<APIContainerComponent> {\n  private constructor(data: APIContainerComponent);\n  public get accentColor(): number;\n  public get hexAccentColor(): HexColorString;\n  public get spoiler(): boolean;\n  public readonly components: ComponentInContainer[];\n}\n\nexport { Collection, type ReadonlyCollection } from '@discordjs/collection';\n\nexport interface CollectorEventTypes<Key, Value, Extras extends unknown[] = []> {\n  collect: [Value, ...Extras];\n  dispose: [Value, ...Extras];\n  end: [collected: ReadonlyCollection<Key, Value>, reason: string];\n  ignore: [Value, ...Extras];\n}\n\nexport abstract class Collector<\n  Key,\n  Value,\n  Extras extends unknown[] = [],\n  EventTypes extends {} = CollectorEventTypes<Key, Value, Extras>,\n> extends AsyncEventEmitter<EventTypes> {\n  protected constructor(client: Client<true>, options?: CollectorOptions<[Value, ...Extras]>);\n  private readonly _timeout: NodeJS.Timeout | null;\n  private readonly _idletimeout: NodeJS.Timeout | null;\n  private readonly _endReason: string | null;\n\n  public readonly client: Client;\n  public collected: Collection<Key, Value>;\n  public lastCollectedTimestamp: number | null;\n  public get lastCollectedAt(): Date | null;\n  public ended: boolean;\n  public get endReason(): string | null;\n  public filter: CollectorFilter<[Value, ...Extras]>;\n  public get next(): Promise<Value>;\n  public options: CollectorOptions<[Value, ...Extras]>;\n  public checkEnd(): boolean;\n  public handleCollect(...args: unknown[]): Promise<void>;\n  public handleDispose(...args: unknown[]): Promise<void>;\n  public stop(reason?: string): void;\n  public resetTimer(options?: CollectorResetTimerOptions): void;\n  public [Symbol.asyncIterator](): AsyncIterableIterator<[Value, ...Extras]>;\n  public toJSON(): unknown;\n\n  protected listener: (...args: any[]) => void;\n  public abstract collect(...args: unknown[]): Awaitable<Key | null>;\n  public abstract dispose(...args: unknown[]): Key | null;\n}\n\nexport class ChatInputCommandInteraction<Cached extends CacheType = CacheType> extends CommandInteraction<Cached> {\n  public commandType: ApplicationCommandType.ChatInput;\n  public options: Omit<CommandInteractionOptionResolver<Cached>, 'getFocused' | 'getMessage'>;\n  public inGuild(): this is ChatInputCommandInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is ChatInputCommandInteraction<'cached'>;\n  public inRawGuild(): this is ChatInputCommandInteraction<'raw'>;\n  public toString(): string;\n}\n\nexport class AutocompleteInteraction<Cached extends CacheType = CacheType> extends BaseInteraction<Cached> {\n  public type: InteractionType.ApplicationCommandAutocomplete;\n  public get command(): ApplicationCommand | ApplicationCommand<{ guild: GuildResolvable }> | null;\n  public channelId: Snowflake;\n  public commandId: Snowflake;\n  public commandName: string;\n  public commandType: ApplicationCommandType.ChatInput;\n  public commandGuildId: Snowflake | null;\n  public responded: boolean;\n  public options: Omit<\n    CommandInteractionOptionResolver<Cached>,\n    'getAttachment' | 'getChannel' | 'getMember' | 'getMentionable' | 'getMessage' | 'getRole' | 'getUser'\n  >;\n  public inGuild(): this is AutocompleteInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is AutocompleteInteraction<'cached'>;\n  public inRawGuild(): this is AutocompleteInteraction<'raw'>;\n  public respond(options: readonly ApplicationCommandOptionChoiceData[]): Promise<void>;\n}\n\nexport class CommandInteractionOptionResolver<Cached extends CacheType = CacheType> {\n  private constructor(\n    client: Client<true>,\n    options: readonly CommandInteractionOption[],\n    resolved: CommandInteractionResolvedData,\n  );\n  public readonly client: Client;\n  public readonly data: readonly CommandInteractionOption<Cached>[];\n  public readonly resolved: Readonly<CommandInteractionResolvedData<Cached>> | null;\n  private readonly _group: string | null;\n  private readonly _hoistedOptions: CommandInteractionOption<Cached>[];\n  private readonly _subcommand: string | null;\n  private _getTypedOption(\n    name: string,\n    allowedTypes: readonly ApplicationCommandOptionType[],\n    properties: readonly (keyof ApplicationCommandOption)[],\n    required: true,\n  ): CommandInteractionOption<Cached>;\n  private _getTypedOption(\n    name: string,\n    allowedTypes: readonly ApplicationCommandOptionType[],\n    properties: readonly (keyof ApplicationCommandOption)[],\n    required: boolean,\n  ): CommandInteractionOption<Cached> | null;\n\n  public get(name: string, required: true): CommandInteractionOption<Cached>;\n  public get(name: string, required?: boolean): CommandInteractionOption<Cached> | null;\n\n  public getSubcommand(required?: true): string;\n  public getSubcommand(required: boolean): string | null;\n  public getSubcommandGroup(required: true): string;\n  public getSubcommandGroup(required?: boolean): string | null;\n  public getBoolean(name: string, required: true): boolean;\n  public getBoolean(name: string, required?: boolean): boolean | null;\n  /**\n   * @privateRemarks\n   * The ternary in the return type is required.\n   * The `type` property of the {@link PublicThreadChannel} interface is typed as `ChannelType.PublicThread | ChannelType.AnnouncementThread`.\n   * If the user were to pass only one of those channel types, the `Extract<>` would resolve to `never`.\n   */\n  public getChannel<const Type extends ChannelType = ChannelType>(\n    name: string,\n    required: true,\n    channelTypes?: readonly Type[],\n  ): Extract<\n    NonNullable<CommandInteractionOption<Cached>['channel']>,\n    {\n      type: Type extends ChannelType.AnnouncementThread | ChannelType.PublicThread\n        ? ChannelType.AnnouncementThread | ChannelType.PublicThread\n        : Type;\n    }\n  >;\n  /**\n   * @privateRemarks\n   * The ternary in the return type is required.\n   * The `type` property of the {@link PublicThreadChannel} interface is typed as `ChannelType.PublicThread | ChannelType.AnnouncementThread`.\n   * If the user were to pass only one of those channel types, the `Extract<>` would resolve to `never`.\n   */\n  public getChannel<const Type extends ChannelType = ChannelType>(\n    name: string,\n    required?: boolean,\n    channelTypes?: readonly Type[],\n  ): Extract<\n    NonNullable<CommandInteractionOption<Cached>['channel']>,\n    {\n      type: Type extends ChannelType.AnnouncementThread | ChannelType.PublicThread\n        ? ChannelType.AnnouncementThread | ChannelType.PublicThread\n        : Type;\n    }\n  > | null;\n  public getString(name: string, required: true): string;\n  public getString(name: string, required?: boolean): string | null;\n  public getInteger(name: string, required: true): number;\n  public getInteger(name: string, required?: boolean): number | null;\n  public getNumber(name: string, required: true): number;\n  public getNumber(name: string, required?: boolean): number | null;\n  public getUser(name: string, required: true): NonNullable<CommandInteractionOption<Cached>['user']>;\n  public getUser(name: string, required?: boolean): NonNullable<CommandInteractionOption<Cached>['user']> | null;\n  public getMember(name: string): NonNullable<CommandInteractionOption<Cached>['member']> | null;\n  public getRole(name: string, required: true): NonNullable<CommandInteractionOption<Cached>['role']>;\n  public getRole(name: string, required?: boolean): NonNullable<CommandInteractionOption<Cached>['role']> | null;\n  public getAttachment(name: string, required: true): NonNullable<CommandInteractionOption<Cached>['attachment']>;\n  public getAttachment(\n    name: string,\n    required?: boolean,\n  ): NonNullable<CommandInteractionOption<Cached>['attachment']> | null;\n  public getMentionable(\n    name: string,\n    required: true,\n  ): NonNullable<CommandInteractionOption<Cached>['member' | 'role' | 'user']>;\n  public getMentionable(\n    name: string,\n    required?: boolean,\n  ): NonNullable<CommandInteractionOption<Cached>['member' | 'role' | 'user']> | null;\n  public getMessage(name: string, required: true): NonNullable<CommandInteractionOption<Cached>['message']>;\n  public getMessage(name: string, required?: boolean): NonNullable<CommandInteractionOption<Cached>['message']> | null;\n  public getFocused(): AutocompleteFocusedOption;\n}\n\nexport class ContextMenuCommandInteraction<Cached extends CacheType = CacheType> extends CommandInteraction<Cached> {\n  public options: Omit<\n    CommandInteractionOptionResolver<Cached>,\n    | 'getAttachment'\n    | 'getBoolean'\n    | 'getChannel'\n    | 'getFocused'\n    | 'getInteger'\n    | 'getMember'\n    | 'getMentionable'\n    | 'getMessage'\n    | 'getNumber'\n    | 'getRole'\n    | 'getString'\n    | 'getSubcommand'\n    | 'getSubcommandGroup'\n    | 'getUser'\n  >;\n  public commandType: ApplicationCommandType.Message | ApplicationCommandType.User;\n  public targetId: Snowflake;\n  public inGuild(): this is ContextMenuCommandInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is ContextMenuCommandInteraction<'cached'>;\n  public inRawGuild(): this is ContextMenuCommandInteraction<'raw'>;\n  private resolveContextMenuOptions(data: APIApplicationCommandInteractionData): CommandInteractionOption<Cached>[];\n}\n\nexport class PrimaryEntryPointCommandInteraction<\n  Cached extends CacheType = CacheType,\n> extends CommandInteraction<Cached> {\n  public commandType: ApplicationCommandType.PrimaryEntryPoint;\n  public inGuild(): this is PrimaryEntryPointCommandInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is PrimaryEntryPointCommandInteraction<'cached'>;\n  public inRawGuild(): this is PrimaryEntryPointCommandInteraction<'raw'>;\n}\n\nexport interface DMChannel\n  extends TextBasedChannelFields<false, true>, PinnableChannelFields, MessageChannelFields, SendMethod<false> {}\nexport class DMChannel extends BaseChannel {\n  private constructor(client: Client<true>, data?: RawDMChannelData);\n  public flags: Readonly<ChannelFlagsBitField>;\n  public recipientId: Snowflake;\n  public get recipient(): User | null;\n  public type: ChannelType.DM;\n  public fetch(force?: boolean): Promise<this>;\n  public toString(): UserMention;\n}\n\nexport class Emoji extends Base {\n  protected constructor(client: Client<true>, emoji: unknown);\n  public animated: boolean | null;\n  public get createdAt(): Date | null;\n  public get createdTimestamp(): number | null;\n  public id: Snowflake | null;\n  public name: string | null;\n  public get identifier(): string;\n  public imageURL(options?: EmojiURLOptions): string | null;\n  public toJSON(): unknown;\n  public toString(): string;\n}\n\nexport interface ApplicationEmojiCreateOptions {\n  attachment: Base64Resolvable | BufferResolvable;\n  name: string;\n}\n\nexport interface ApplicationEmojiEditOptions {\n  name?: string;\n}\n\nexport class ApplicationEmoji extends Emoji {\n  private constructor(client: Client<true>, data: APIEmoji, application: ClientApplication);\n\n  public application: ClientApplication;\n  public author: User;\n  public id: Snowflake;\n  public managed: false;\n  public requiresColons: true;\n  public name: string;\n  public animated: boolean;\n  public available: true;\n  public get createdAt(): Date;\n  public get createdTimestamp(): number;\n  public imageURL(options?: EmojiURLOptions): string;\n  public delete(): Promise<ApplicationEmoji>;\n  public edit(options: ApplicationEmojiEditOptions): Promise<ApplicationEmoji>;\n  public equals(other: ApplicationEmoji | unknown): boolean;\n  public fetchAuthor(): Promise<User>;\n  public setName(name: string): Promise<ApplicationEmoji>;\n}\n\nexport class ApplicationEmojiManager extends CachedManager<Snowflake, ApplicationEmoji, EmojiResolvable> {\n  private constructor(application: ClientApplication, iterable?: Iterable<APIEmoji>);\n  public application: ClientApplication;\n  public create(options: ApplicationEmojiCreateOptions): Promise<ApplicationEmoji>;\n  public fetch(id: Snowflake, options?: BaseFetchOptions): Promise<ApplicationEmoji>;\n  public fetch(id?: undefined, options?: BaseFetchOptions): Promise<Collection<Snowflake, ApplicationEmoji>>;\n  public fetchAuthor(emoji: EmojiResolvable): Promise<User>;\n  public delete(emoji: EmojiResolvable): Promise<void>;\n  public edit(emoji: EmojiResolvable, options: ApplicationEmojiEditOptions): Promise<ApplicationEmoji>;\n}\n\nexport class Entitlement extends Base {\n  private constructor(client: Client<true>, data: APIEntitlement);\n  public id: Snowflake;\n  public skuId: Snowflake;\n  public userId: Snowflake;\n  public guildId: Snowflake | null;\n  public applicationId: Snowflake;\n  public type: EntitlementType;\n  public consumed: boolean;\n  public deleted: boolean;\n  public startsTimestamp: number | null;\n  public endsTimestamp: number | null;\n  public get guild(): Guild | null;\n  public get startsAt(): Date | null;\n  public get endsAt(): Date | null;\n  public consume(): Promise<void>;\n  public fetchUser(): Promise<User>;\n  public isActive(): boolean;\n  public isTest(): this is this & {\n    get endsAt(): null;\n    endsTimestamp: null;\n    get startsAt(): null;\n    startsTimestamp: null;\n  };\n  public isUserSubscription(): this is this & { get guild(): null; guildId: null };\n  public isGuildSubscription(): this is this & { guild: Guild; guildId: Snowflake };\n}\n\nexport interface FileComponentData extends BaseComponentData {\n  file: UnfurledMediaItemData;\n  spoiler?: boolean;\n}\nexport class FileComponent extends Component<APIFileComponent> {\n  private constructor(data: APIFileComponent);\n  public readonly file: UnfurledMediaItem;\n  public get spoiler(): boolean;\n}\n\nexport class Guild extends AnonymousGuild {\n  private constructor(client: Client<true>, data: APIGuild | APIUnavailableGuild);\n  private _sortedRoles(): Collection<Snowflake, Role>;\n  private _sortedChannels(channel: NonThreadGuildBasedChannel): Collection<Snowflake, NonThreadGuildBasedChannel>;\n\n  public get afkChannel(): VoiceChannel | null;\n  public afkChannelId: Snowflake | null;\n  public afkTimeout: number;\n  public applicationId: Snowflake | null;\n  public maxVideoChannelUsers: number | null;\n  public approximateMemberCount: number | null;\n  public approximatePresenceCount: number | null;\n  public autoModerationRules: AutoModerationRuleManager;\n  public available: boolean;\n  public bans: GuildBanManager;\n  public channels: GuildChannelManager;\n  public commands: GuildApplicationCommandManager;\n  public defaultMessageNotifications: GuildDefaultMessageNotifications;\n  public discoverySplash: string | null;\n  public emojis: GuildEmojiManager;\n  public explicitContentFilter: GuildExplicitContentFilter;\n  public invites: GuildInviteManager;\n  public get joinedAt(): Date;\n  public joinedTimestamp: number;\n  public large: boolean;\n  public maximumMembers: number | null;\n  public maximumPresences: number | null;\n  public maxStageVideoChannelUsers: number | null;\n  public memberCount: number;\n  public members: GuildMemberManager;\n  public mfaLevel: GuildMFALevel;\n  public ownerId: Snowflake;\n  public preferredLocale: Locale;\n  public premiumProgressBarEnabled: boolean;\n  public premiumTier: GuildPremiumTier;\n  public presences: PresenceManager;\n  public get publicUpdatesChannel(): TextChannel | null;\n  public publicUpdatesChannelId: Snowflake | null;\n  public roles: RoleManager;\n  public get rulesChannel(): TextChannel | null;\n  public rulesChannelId: Snowflake | null;\n  public get safetyAlertsChannel(): TextChannel | null;\n  public safetyAlertsChannelId: Snowflake | null;\n  public scheduledEvents: GuildScheduledEventManager;\n  public shardId: number;\n  public soundboardSounds: GuildSoundboardSoundManager;\n  public stageInstances: StageInstanceManager;\n  public stickers: GuildStickerManager;\n  public incidentsData: IncidentActions | null;\n  public get systemChannel(): TextChannel | null;\n  public systemChannelFlags: Readonly<SystemChannelFlagsBitField>;\n  public systemChannelId: Snowflake | null;\n  public vanityURLUses: number | null;\n  public get voiceAdapterCreator(): InternalDiscordGatewayAdapterCreator;\n  public voiceStates: VoiceStateManager;\n  public get widgetChannel():\n    | AnnouncementChannel\n    | ForumChannel\n    | MediaChannel\n    | TextChannel\n    | VoiceBasedChannel\n    | null;\n  public widgetChannelId: Snowflake | null;\n  public widgetEnabled: boolean | null;\n  public get maximumBitrate(): number;\n  public get maximumStageBitrate(): number;\n  public createTemplate(name: string, description?: string): Promise<GuildTemplate>;\n  public discoverySplashURL(options?: ImageURLOptions): string | null;\n  public edit(options: GuildEditOptions): Promise<Guild>;\n  public editOnboarding(options: GuildOnboardingEditOptions): Promise<GuildOnboarding>;\n  public editWelcomeScreen(options: WelcomeScreenEditOptions): Promise<WelcomeScreen>;\n  public equals(guild: Guild): boolean;\n  public fetchAuditLogs<Event extends GuildAuditLogsResolvable = AuditLogEvent>(\n    options?: GuildAuditLogsFetchOptions<Event>,\n  ): Promise<GuildAuditLogs<Event extends null ? AuditLogEvent : Event>>;\n  public fetchIntegrations(): Promise<Collection<Snowflake | string, Integration>>;\n  public fetchOnboarding(): Promise<GuildOnboarding>;\n  public fetchOwner(options?: BaseFetchOptions): Promise<GuildMember>;\n  public fetchPreview(): Promise<GuildPreview>;\n  public fetchTemplates(): Promise<Collection<GuildTemplate['code'], GuildTemplate>>;\n  public fetchVanityData(): Promise<Vanity>;\n  public fetchWebhooks(): Promise<Collection<Snowflake, Webhook<WebhookType.ChannelFollower | WebhookType.Incoming>>>;\n  public fetchWelcomeScreen(): Promise<WelcomeScreen>;\n  public fetchWidget(): Promise<Widget>;\n  public fetchWidgetSettings(): Promise<GuildWidgetSettings>;\n  public widgetImageURL(style?: GuildWidgetStyle): string;\n  public leave(): Promise<Guild>;\n  public disableInvites(disabled?: boolean): Promise<Guild>;\n  public setIncidentActions(incidentActions: IncidentActionsEditOptions): Promise<IncidentActions>;\n  public setAFKChannel(afkChannel: VoiceChannelResolvable | null, reason?: string): Promise<Guild>;\n  public setAFKTimeout(afkTimeout: number, reason?: string): Promise<Guild>;\n  public setBanner(banner: Base64Resolvable | BufferResolvable | null, reason?: string): Promise<Guild>;\n  public setDefaultMessageNotifications(\n    defaultMessageNotifications: GuildDefaultMessageNotifications | null,\n    reason?: string,\n  ): Promise<Guild>;\n  public setDiscoverySplash(\n    discoverySplash: Base64Resolvable | BufferResolvable | null,\n    reason?: string,\n  ): Promise<Guild>;\n  public setExplicitContentFilter(\n    explicitContentFilter: GuildExplicitContentFilter | null,\n    reason?: string,\n  ): Promise<Guild>;\n  public setIcon(icon: Base64Resolvable | BufferResolvable | null, reason?: string): Promise<Guild>;\n  public setName(name: string, reason?: string): Promise<Guild>;\n  public setPreferredLocale(preferredLocale: Locale | null, reason?: string): Promise<Guild>;\n  public setPublicUpdatesChannel(publicUpdatesChannel: TextChannelResolvable | null, reason?: string): Promise<Guild>;\n  public setRulesChannel(rulesChannel: TextChannelResolvable | null, reason?: string): Promise<Guild>;\n  public setSafetyAlertsChannel(safetyAlertsChannel: TextChannelResolvable | null, reason?: string): Promise<Guild>;\n  public setSplash(splash: Base64Resolvable | BufferResolvable | null, reason?: string): Promise<Guild>;\n  public setSystemChannel(systemChannel: TextChannelResolvable | null, reason?: string): Promise<Guild>;\n  public setSystemChannelFlags(systemChannelFlags: SystemChannelFlagsResolvable, reason?: string): Promise<Guild>;\n  public setVerificationLevel(verificationLevel: GuildVerificationLevel | null, reason?: string): Promise<Guild>;\n  public setPremiumProgressBarEnabled(enabled?: boolean, reason?: string): Promise<Guild>;\n  public setWidgetSettings(settings: GuildWidgetSettingsData, reason?: string): Promise<Guild>;\n  public toJSON(): unknown;\n}\n\nexport class GuildAuditLogs<Event extends AuditLogEvent = AuditLogEvent> {\n  private constructor(guild: Guild, data: APIAuditLog);\n  private readonly applicationCommands: Collection<Snowflake, ApplicationCommand>;\n  private readonly webhooks: Collection<Snowflake, Webhook<WebhookType.ChannelFollower | WebhookType.Incoming>>;\n  private readonly integrations: Collection<Snowflake | string, Integration>;\n  private readonly guildScheduledEvents: Collection<Snowflake, GuildScheduledEvent>;\n  private readonly autoModerationRules: Collection<Snowflake, AutoModerationRule>;\n  public entries: Collection<Snowflake, GuildAuditLogsEntry<Event>>;\n  public toJSON(): unknown;\n}\n\nexport class GuildAuditLogsEntry<\n  TAction extends AuditLogEvent = AuditLogEvent,\n  TActionType extends GuildAuditLogsActionType = TAction extends keyof GuildAuditLogsTypes\n    ? GuildAuditLogsTypes[TAction][1]\n    : 'All',\n  TTargetType extends GuildAuditLogsTargetType = TAction extends keyof GuildAuditLogsTypes\n    ? GuildAuditLogsTypes[TAction][0]\n    : 'Unknown',\n> {\n  private constructor(guild: Guild, data: APIAuditLogEntry, logs?: GuildAuditLogs);\n  public static Targets: GuildAuditLogsTargets;\n  public action: TAction;\n  public actionType: TActionType;\n  public changes: AuditLogChange[];\n  public get createdAt(): Date;\n  public get createdTimestamp(): number;\n  public executorId: Snowflake | null;\n  public executor: PartialUser | User | null;\n  public extra: TAction extends keyof GuildAuditLogsEntryExtraField ? GuildAuditLogsEntryExtraField[TAction] : null;\n  public id: Snowflake;\n  public reason: string | null;\n  public targetId: Snowflake | null;\n  public target: TTargetType extends keyof GuildAuditLogsEntryTargetField<TAction>\n    ? GuildAuditLogsEntryTargetField<TAction>[TTargetType]\n    : { [x: string]: unknown; id: Snowflake | undefined } | null;\n  public targetType: TTargetType;\n  public static actionType(action: AuditLogEvent): GuildAuditLogsActionType;\n  public static targetType(target: AuditLogEvent): GuildAuditLogsTargetType;\n  public isAction<TCheckAction extends TAction>(\n    action: TCheckAction,\n  ): this is GuildAuditLogsEntry<\n    TCheckAction,\n    TCheckAction extends keyof GuildAuditLogsTypes ? GuildAuditLogsTypes[TCheckAction][1] : 'All',\n    TCheckAction extends keyof GuildAuditLogsTypes ? GuildAuditLogsTypes[TCheckAction][0] : 'Unknown'\n  >;\n  public toJSON(): unknown;\n}\n\nexport class GuildBan extends Base {\n  private constructor(client: Client<true>, data: unknown, guild: Guild);\n  public guild: Guild;\n  public user: User;\n  public get partial(): boolean;\n  public reason?: string | null;\n  public fetch(force?: boolean): Promise<GuildBan>;\n}\n\nexport abstract class GuildChannel extends BaseChannel {\n  public constructor(guild: Guild, data?: RawGuildChannelData, client?: Client<true>, immediatePatch?: boolean);\n  private memberPermissions(member: GuildMember, checkAdmin: boolean): Readonly<PermissionsBitField>;\n  private rolePermissions(role: Role, checkAdmin: boolean): Readonly<PermissionsBitField>;\n  public get createdAt(): Date;\n  public get createdTimestamp(): number;\n  public get deletable(): boolean;\n  public flags: Readonly<ChannelFlagsBitField>;\n  public guild: Guild;\n  public guildId: Snowflake;\n  public get manageable(): boolean;\n  public get members(): Collection<Snowflake, GuildMember>;\n  public name: string;\n  public get parent(): CategoryChannel | null;\n  public parentId: Snowflake | null;\n  public permissionOverwrites: PermissionOverwriteManager;\n  public get permissionsLocked(): boolean | null;\n  public get position(): number;\n  public rawPosition: number;\n  public type: GuildChannelTypes;\n  public get viewable(): boolean;\n  public clone(options?: GuildChannelCloneOptions): Promise<this>;\n  public delete(reason?: string): Promise<this>;\n  public edit(options: GuildChannelEditOptions): Promise<this>;\n  public equals(channel: GuildChannel): boolean;\n  public lockPermissions(): Promise<this>;\n  public permissionsFor(memberOrRole: GuildMember | Role, checkAdmin?: boolean): Readonly<PermissionsBitField>;\n  public permissionsFor(\n    memberOrRole: RoleResolvable | UserResolvable,\n    checkAdmin?: boolean,\n  ): Readonly<PermissionsBitField> | null;\n  public setName(name: string, reason?: string): Promise<this>;\n  public setParent(channel: CategoryChannelResolvable | null, options?: SetParentOptions): Promise<this>;\n  public setPosition(position: number, options?: SetChannelPositionOptions): Promise<this>;\n  public isTextBased(): this is GuildBasedChannel & TextBasedChannel;\n  public toString(): ChannelMention;\n}\n\nexport class GuildEmoji extends BaseGuildEmoji {\n  private constructor(client: Client<true>, data: APIEmoji, guild: Guild);\n  private readonly _roles: Snowflake[];\n\n  public get deletable(): boolean;\n  public guild: Guild;\n  public author: User | null;\n  public get roles(): GuildEmojiRoleManager;\n  public delete(reason?: string): Promise<GuildEmoji>;\n  public edit(options: GuildEmojiEditOptions): Promise<GuildEmoji>;\n  public equals(other: GuildEmoji | unknown): boolean;\n  public fetchAuthor(): Promise<User>;\n  public setName(name: string, reason?: string): Promise<GuildEmoji>;\n}\n\nexport type GuildMemberFlagsString = keyof typeof GuildMemberFlags;\n\nexport type GuildMemberFlagsResolvable = BitFieldResolvable<GuildMemberFlagsString, number>;\n\nexport class GuildMemberFlagsBitField extends BitField<GuildMemberFlagsString> {\n  public static Flags: GuildMemberFlags;\n  public static resolve(bit?: BitFieldResolvable<GuildMemberFlagsString, GuildMemberFlags>): number;\n}\n\nexport interface GuildMember extends SendMethod<false> {}\nexport class GuildMember extends Base {\n  private constructor(client: Client<true>, data: unknown, guild: Guild);\n  private readonly _roles: Snowflake[];\n  public avatar: string | null;\n  public avatarDecorationData: AvatarDecorationData | null;\n  public banner: string | null;\n  public get bannable(): boolean;\n  public get dmChannel(): DMChannel | null;\n  public get displayColor(): number;\n  public get displayHexColor(): HexColorString;\n  public get displayName(): string;\n  public guild: Guild;\n  public get id(): Snowflake;\n  public pending: boolean;\n  public get communicationDisabledUntil(): Date | null;\n  public communicationDisabledUntilTimestamp: number | null;\n  public flags: Readonly<GuildMemberFlagsBitField>;\n  public get joinedAt(): Date | null;\n  public joinedTimestamp: number | null;\n  public get kickable(): boolean;\n  public get manageable(): boolean;\n  public get moderatable(): boolean;\n  public nickname: string | null;\n  public get partial(): false;\n  public get permissions(): Readonly<PermissionsBitField>;\n  public get premiumSince(): Date | null;\n  public premiumSinceTimestamp: number | null;\n  public get presence(): Presence | null;\n  public get roles(): GuildMemberRoleManager;\n  public user: User;\n  public get voice(): VoiceState;\n  public avatarURL(options?: ImageURLOptions): string | null;\n  public avatarDecorationURL(): string | null;\n  public bannerURL(options?: ImageURLOptions): string | null;\n  public ban(options?: BanOptions): Promise<void>;\n  public disableCommunicationUntil(timeout: DateResolvable | null, reason?: string): Promise<GuildMember>;\n  public timeout(timeout: number | null, reason?: string): Promise<GuildMember>;\n  public fetch(force?: boolean): Promise<GuildMember>;\n  public createDM(force?: boolean): Promise<DMChannel>;\n  public deleteDM(): Promise<DMChannel>;\n  public displayAvatarURL(options?: ImageURLOptions): string;\n  public displayBannerURL(options?: ImageURLOptions): string | null;\n  public displayAvatarDecorationURL(): string | null;\n  public edit(options: GuildMemberEditOptions): Promise<GuildMember>;\n  public isCommunicationDisabled(): this is GuildMember & {\n    readonly communicationDisabledUntil: Date;\n    communicationDisabledUntilTimestamp: number;\n  };\n  public kick(reason?: string): Promise<void>;\n  public permissionsIn(channel: GuildChannelResolvable): Readonly<PermissionsBitField>;\n  public setFlags(flags: GuildMemberFlagsResolvable, reason?: string): Promise<GuildMember>;\n  public setNickname(nickname: string | null, reason?: string): Promise<GuildMember>;\n  public toJSON(): unknown;\n  public toString(): UserMention;\n  public valueOf(): string;\n}\n\nexport class GuildOnboarding extends Base {\n  private constructor(client: Client, data: RESTGetAPIGuildOnboardingResult);\n  public get guild(): Guild;\n  public guildId: Snowflake;\n  public prompts: Collection<Snowflake, GuildOnboardingPrompt>;\n  public defaultChannels: Collection<Snowflake, GuildChannel>;\n  public enabled: boolean;\n  public mode: GuildOnboardingMode;\n}\n\nexport class GuildOnboardingPrompt extends Base {\n  private constructor(client: Client, data: APIGuildOnboardingPrompt, guildId: Snowflake);\n  public id: Snowflake;\n  public get guild(): Guild;\n  public guildId: Snowflake;\n  public options: Collection<Snowflake, GuildOnboardingPromptOption>;\n  public title: string;\n  public singleSelect: boolean;\n  public required: boolean;\n  public inOnboarding: boolean;\n  public type: GuildOnboardingPromptType;\n}\n\nexport class GuildOnboardingPromptOption extends Base {\n  private constructor(client: Client, data: APIGuildOnboardingPromptOption, guildId: Snowflake);\n  private readonly _emoji: APIPartialEmoji;\n\n  public id: Snowflake;\n  public get emoji(): Emoji | GuildEmoji | null;\n  public get guild(): Guild;\n  public guildId: Snowflake;\n  public channels: Collection<Snowflake, GuildChannel>;\n  public roles: Collection<Snowflake, Role>;\n  public title: string;\n  public description: string | null;\n}\n\nexport class GuildPreview extends Base {\n  private constructor(client: Client<true>, data: APIGuildPreview);\n  public approximateMemberCount: number;\n  public approximatePresenceCount: number;\n  public get createdAt(): Date;\n  public get createdTimestamp(): number;\n  public description: string | null;\n  public discoverySplash: string | null;\n  public emojis: Collection<Snowflake, GuildPreviewEmoji>;\n  public stickers: Collection<Snowflake, Sticker>;\n  public features: `${GuildFeature}`[];\n  public icon: string | null;\n  public id: Snowflake;\n  public name: string;\n  public splash: string | null;\n  public discoverySplashURL(options?: ImageURLOptions): string | null;\n  public iconURL(options?: ImageURLOptions): string | null;\n  public splashURL(options?: ImageURLOptions): string | null;\n  public fetch(): Promise<GuildPreview>;\n  public toJSON(): unknown;\n  public toString(): string;\n}\n\nexport class GuildScheduledEvent<Status extends GuildScheduledEventStatus = GuildScheduledEventStatus> extends Base {\n  private constructor(client: Client<true>, data: APIGuildScheduledEvent);\n  public id: Snowflake;\n  public guildId: Snowflake;\n  public channelId: Snowflake | null;\n  public creatorId: Snowflake | null;\n  public name: string;\n  public description: string | null;\n  public scheduledStartTimestamp: number | null;\n  public scheduledEndTimestamp: number | null;\n  public privacyLevel: GuildScheduledEventPrivacyLevel;\n  public status: Status;\n  public entityType: GuildScheduledEventEntityType;\n  public entityId: Snowflake | null;\n  public entityMetadata: GuildScheduledEventEntityMetadata | null;\n  public userCount: number | null;\n  public creator: User | null;\n  public recurrenceRule: GuildScheduledEventRecurrenceRule | null;\n  public get createdTimestamp(): number;\n  public get createdAt(): Date;\n  public get scheduledStartAt(): Date | null;\n  public get scheduledEndAt(): Date | null;\n  public get channel(): StageChannel | VoiceChannel | null;\n  public get guild(): Guild | null;\n  public get url(): string;\n  public image: string | null;\n  public get partial(): false;\n  public coverImageURL(options?: Readonly<BaseImageURLOptions>): string | null;\n  public createInviteURL(options?: GuildScheduledEventInviteURLCreateOptions): Promise<string>;\n  public edit<AcceptableStatus extends GuildScheduledEventSetStatusArg<Status>>(\n    options: GuildScheduledEventEditOptions<Status, AcceptableStatus>,\n  ): Promise<GuildScheduledEvent<AcceptableStatus>>;\n  public fetch(force?: boolean): Promise<GuildScheduledEvent<Status>>;\n  public delete(): Promise<GuildScheduledEvent<Status>>;\n  public setName(name: string, reason?: string): Promise<GuildScheduledEvent<Status>>;\n  public setScheduledStartTime(\n    scheduledStartTime: DateResolvable,\n    reason?: string,\n  ): Promise<GuildScheduledEvent<Status>>;\n  public setScheduledEndTime(scheduledEndTime: DateResolvable, reason?: string): Promise<GuildScheduledEvent<Status>>;\n  public setDescription(description: string, reason?: string): Promise<GuildScheduledEvent<Status>>;\n  public setStatus<AcceptableStatus extends GuildScheduledEventSetStatusArg<Status>>(\n    status: AcceptableStatus,\n    reason?: string,\n  ): Promise<GuildScheduledEvent<AcceptableStatus>>;\n  public setLocation(location: string, reason?: string): Promise<GuildScheduledEvent<Status>>;\n  public fetchSubscribers<Options extends FetchGuildScheduledEventSubscribersOptions>(\n    options?: Options,\n  ): Promise<GuildScheduledEventManagerFetchSubscribersResult<Options>>;\n  public toString(): string;\n  public isActive(): this is GuildScheduledEvent<GuildScheduledEventStatus.Active>;\n  public isCanceled(): this is GuildScheduledEvent<GuildScheduledEventStatus.Canceled>;\n  public isCompleted(): this is GuildScheduledEvent<GuildScheduledEventStatus.Completed>;\n  public isScheduled(): this is GuildScheduledEvent<GuildScheduledEventStatus.Scheduled>;\n}\n\nexport interface GuildScheduledEventRecurrenceRule {\n  byMonth: readonly GuildScheduledEventRecurrenceRuleMonth[] | null;\n  byMonthDay: readonly number[] | null;\n  byNWeekday: readonly GuildScheduledEventRecurrenceRuleNWeekday[] | null;\n  byWeekday: readonly GuildScheduledEventRecurrenceRuleWeekday[] | null;\n  byYearDay: readonly number[] | null;\n  count: number | null;\n  get endAt(): Date | null;\n  endTimestamp: number | null;\n  frequency: GuildScheduledEventRecurrenceRuleFrequency;\n  interval: number;\n  get startAt(): Date;\n  startTimestamp: number;\n}\n\nexport interface GuildScheduledEventRecurrenceRuleNWeekday {\n  day: GuildScheduledEventRecurrenceRuleWeekday;\n  n: number;\n}\n\nexport class GuildTemplate extends Base {\n  private constructor(client: Client<true>, data: APITemplate);\n  public createdTimestamp: number;\n  public updatedTimestamp: number;\n  public get url(): string;\n  public code: string;\n  public name: string;\n  public description: string | null;\n  public usageCount: number;\n  public creator: User;\n  public creatorId: Snowflake;\n  public get createdAt(): Date;\n  public get updatedAt(): Date;\n  public get guild(): Guild | null;\n  public guildId: Snowflake;\n  public serializedGuild: APITemplateSerializedSourceGuild;\n  public unSynced: boolean | null;\n  public delete(): Promise<GuildTemplate>;\n  public edit(options?: GuildTemplateEditOptions): Promise<GuildTemplate>;\n  public sync(): Promise<GuildTemplate>;\n  public static GuildTemplatesPattern: RegExp;\n}\n\nexport class GuildPreviewEmoji extends BaseGuildEmoji {\n  private constructor(client: Client<true>, data: APIEmoji, guild: GuildPreview);\n  public guild: GuildPreview;\n  public roles: Snowflake[];\n}\n\nexport class Integration extends Base {\n  private constructor(client: Client<true>, data: APIGuildIntegration, guild: Guild);\n  public account: IntegrationAccount;\n  public application: IntegrationApplication | null;\n  public enabled: boolean | null;\n  public expireBehavior: IntegrationExpireBehavior | null;\n  public expireGracePeriod: number | null;\n  public guild: Guild;\n  public id: Snowflake | string;\n  public name: string;\n  public role: Role | null;\n  public enableEmoticons: boolean | null;\n  public get roles(): Collection<Snowflake, Role>;\n  public scopes: OAuth2Scopes[];\n  public get syncedAt(): Date | null;\n  public syncedTimestamp: number | null;\n  public syncing: boolean | null;\n  public type: IntegrationType;\n  public user: User | null;\n  public subscriberCount: number | null;\n  public revoked: boolean | null;\n  public delete(reason?: string): Promise<Integration>;\n}\n\nexport class IntegrationApplication extends Application {\n  private constructor(client: Client<true>, data: unknown);\n  public bot: User | null;\n  public termsOfServiceURL: string | null;\n  public privacyPolicyURL: string | null;\n  public rpcOrigins: string[];\n  public cover: string | null;\n  public verifyKey: string | null;\n}\n\nexport type GatewayIntentsString = keyof typeof GatewayIntentBits;\n\nexport class IntentsBitField extends BitField<GatewayIntentsString> {\n  public static Flags: typeof GatewayIntentBits;\n  public static resolve(bit?: BitFieldResolvable<GatewayIntentsString, number>): number;\n}\n\nexport type CacheType = 'cached' | 'raw' | undefined;\n\nexport type CacheTypeReducer<\n  State extends CacheType,\n  CachedType,\n  RawType = CachedType,\n  PresentType = CachedType | RawType,\n  Fallback = PresentType | null,\n> = [State] extends ['cached']\n  ? CachedType\n  : [State] extends ['raw']\n    ? RawType\n    : [State] extends ['cached' | 'raw']\n      ? PresentType\n      : Fallback;\n\nexport type Interaction<Cached extends CacheType = CacheType> =\n  | AutocompleteInteraction<Cached>\n  | ButtonInteraction<Cached>\n  | ChatInputCommandInteraction<Cached>\n  | MessageContextMenuCommandInteraction<Cached>\n  | ModalSubmitInteraction<Cached>\n  | PrimaryEntryPointCommandInteraction<Cached>\n  | SelectMenuInteraction<Cached>\n  | UserContextMenuCommandInteraction<Cached>;\n\nexport type RepliableInteraction<Cached extends CacheType = CacheType> = Exclude<\n  Interaction<Cached>,\n  AutocompleteInteraction<Cached>\n>;\n\nexport class BaseInteraction<Cached extends CacheType = CacheType> extends Base {\n  // This a technique used to brand different cached types. Or else we'll get `never` errors on typeguard checks.\n  private readonly _cacheType: Cached;\n  protected constructor(client: Client<true>, data: GatewayInteractionCreateDispatchData);\n  public applicationId: Snowflake;\n  public authorizingIntegrationOwners: AuthorizingIntegrationOwners;\n  public get channel(): CacheTypeReducer<\n    Cached,\n    GuildTextBasedChannel | null,\n    GuildTextBasedChannel | null,\n    GuildTextBasedChannel | null,\n    TextBasedChannel | null\n  >;\n  public channelId: Snowflake | null;\n  public context: InteractionContextType | null;\n  public get createdAt(): Date;\n  public get createdTimestamp(): number;\n  public get guild(): CacheTypeReducer<Cached, Guild, null>;\n  public guildId: CacheTypeReducer<Cached, Snowflake>;\n  public id: Snowflake;\n  public member: CacheTypeReducer<Cached, GuildMember, APIInteractionGuildMember>;\n  public readonly token: string;\n  public type: InteractionType;\n  public user: User;\n  public version: number;\n  public appPermissions: Readonly<PermissionsBitField>;\n  public memberPermissions: CacheTypeReducer<Cached, Readonly<PermissionsBitField>>;\n  public locale: Locale;\n  public guildLocale: CacheTypeReducer<Cached, Locale>;\n  public entitlements: Collection<Snowflake, Entitlement>;\n  public attachmentSizeLimit: number;\n  public inGuild(): this is BaseInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is BaseInteraction<'cached'>;\n  public inRawGuild(): this is BaseInteraction<'raw'>;\n  public isButton(): this is ButtonInteraction<Cached>;\n  public isAutocomplete(): this is AutocompleteInteraction<Cached>;\n  public isChatInputCommand(): this is ChatInputCommandInteraction<Cached>;\n  public isCommand(): this is CommandInteraction<Cached>;\n  public isContextMenuCommand(): this is ContextMenuCommandInteraction<Cached>;\n  public isPrimaryEntryPointCommand(): this is PrimaryEntryPointCommandInteraction<Cached>;\n  public isMessageComponent(): this is MessageComponentInteraction<Cached>;\n  public isMessageContextMenuCommand(): this is MessageContextMenuCommandInteraction<Cached>;\n  public isModalSubmit(): this is ModalSubmitInteraction<Cached>;\n  public isUserContextMenuCommand(): this is UserContextMenuCommandInteraction<Cached>;\n  public isSelectMenu(): this is SelectMenuInteraction<Cached>;\n  public isStringSelectMenu(): this is StringSelectMenuInteraction<Cached>;\n  public isUserSelectMenu(): this is UserSelectMenuInteraction<Cached>;\n  public isRoleSelectMenu(): this is RoleSelectMenuInteraction<Cached>;\n  public isMentionableSelectMenu(): this is MentionableSelectMenuInteraction<Cached>;\n  public isChannelSelectMenu(): this is ChannelSelectMenuInteraction<Cached>;\n  public isRepliable(): this is RepliableInteraction<Cached>;\n}\n\nexport class InteractionCallback {\n  private constructor(client: Client<true>, data: RESTAPIInteractionCallbackObject);\n  public activityInstanceId: string | null;\n  public readonly client: Client<true>;\n  public get createdAt(): Date;\n  public get createdTimestamp(): number;\n  public id: Snowflake;\n  public responseMessageEphemeral: boolean | null;\n  public responseMessageId: Snowflake | null;\n  public responseMessageLoading: boolean | null;\n  public type: InteractionType;\n}\n\nexport class InteractionCallbackResponse<InGuild extends boolean = boolean> {\n  private constructor(client: Client<true>, data: RESTPostAPIInteractionCallbackWithResponseResult);\n  public readonly client: Client<true>;\n  public interaction: InteractionCallback;\n  public resource: InteractionCallbackResource<InGuild> | null;\n}\n\nexport class InteractionCallbackResource<InGuild extends boolean = boolean> {\n  private constructor(client: Client<true>, data: RESTAPIInteractionCallbackResourceObject);\n  public activityInstance: RESTAPIInteractionCallbackActivityInstanceResource | null;\n  public message: Message<InGuild> | null;\n  public type: InteractionResponseType;\n}\n\nexport class InteractionCollector<Interaction extends CollectedInteraction> extends Collector<Snowflake, Interaction> {\n  public constructor(client: Client<true>, options?: InteractionCollectorOptions<Interaction>);\n  private _handleMessageDeletion(message: Message): void;\n  private _handleChannelDeletion(channel: NonThreadGuildBasedChannel): void;\n  private _handleGuildDeletion(guild: Guild): void;\n\n  public channelId: Snowflake | null;\n  public componentType: ComponentType | null;\n  public guildId: Snowflake | null;\n  public interactionType: InteractionType | null;\n  public messageId: Snowflake | null;\n  public options: InteractionCollectorOptions<Interaction>;\n  public total: number;\n  public users: Collection<Snowflake, User>;\n\n  public collect(interaction: Interaction): Snowflake;\n  public empty(): void;\n  public dispose(interaction: Interaction): Snowflake;\n}\n\nexport interface InteractionWebhook extends PartialWebhookFields {}\nexport class InteractionWebhook {\n  public constructor(client: Client<true>, id: Snowflake, token: string);\n  public readonly client: Client<true>;\n  public token: string;\n  public send(options: InteractionReplyOptions | MessagePayload | string): Promise<Message>;\n  public editMessage(\n    message: MessageResolvable | '@original',\n    options: MessagePayload | WebhookMessageEditOptions | string,\n  ): Promise<Message>;\n  public fetchMessage(message: Snowflake | '@original'): Promise<Message>;\n}\n\nexport class BaseInvite<WithCounts extends boolean = boolean> extends Base {\n  protected constructor(client: Client<true>, data: unknown);\n  public readonly type: InviteType;\n  public readonly code: string;\n  public readonly inviterId: Snowflake | null;\n  public get inviter(): User | null;\n  public maxAge: number | null;\n  public get createdAt(): Date | null;\n  public createdTimestamp: number | null;\n  public get expiresAt(): Date | null;\n  public get expiresTimestamp(): number | null;\n  public readonly channelId: Snowflake | null;\n  public approximateMemberCount: WithCounts extends true ? number : null;\n  public get url(): string;\n  public static InvitesPattern: RegExp;\n  public toString(): string;\n  public toJSON(): unknown;\n}\n\nexport class GuildInvite<WithCounts extends boolean = boolean> extends BaseInvite<WithCounts> {\n  public readonly type: InviteType.Guild;\n  public flags: Readonly<InviteFlagsBitField>;\n  public guild: Guild | InviteGuild | null;\n  public readonly guildId: Snowflake;\n  public channel: NonThreadGuildBasedChannel | null;\n  public targetType: InviteTargetType | null;\n  public targetUser: User | null;\n  public targetApplication: IntegrationApplication | null;\n  public guildScheduledEvent: GuildScheduledEvent | null;\n  public uses: number | null;\n  public maxUses: number | null;\n  public temporary: boolean | null;\n  public approximatePresenceCount: WithCounts extends true ? number : null;\n  public get deletable(): boolean;\n  public delete(reason?: string): Promise<void>;\n}\n\nexport type InviteFlagsString = keyof typeof InviteFlags;\n\nexport class InviteFlagsBitField extends BitField<InviteFlagsString> {\n  public static Flags: typeof InviteFlags;\n  public static resolve(bit?: BitFieldResolvable<InviteFlagsString, number>): number;\n}\n\nexport class GroupDMInvite<WithCounts extends boolean = boolean> extends BaseInvite<WithCounts> {\n  public readonly type: InviteType.GroupDM;\n  public channel: PartialGroupDMChannel | null;\n}\n\nexport type Invite<WithCounts extends boolean = boolean> = GroupDMInvite<WithCounts> | GuildInvite<WithCounts>;\n\nexport class InviteGuild extends AnonymousGuild {\n  private constructor(client: Client<true>, data: APIPartialGuild);\n  public welcomeScreen: WelcomeScreen | null;\n}\n\nexport class LimitedCollection<Key, Value> extends Collection<Key, Value> {\n  public constructor(options?: LimitedCollectionOptions<Key, Value>, iterable?: Iterable<readonly [Key, Value]>);\n  public maxSize: number;\n  public keepOverLimit: ((value: Value, key: Key, collection: this) => boolean) | null;\n}\n\nexport interface MediaGalleryComponentData extends BaseComponentData {\n  items: readonly MediaGalleryItemData[];\n}\nexport class MediaGalleryComponent extends Component<APIMediaGalleryComponent> {\n  private constructor(data: APIMediaGalleryComponent);\n  public readonly items: MediaGalleryItem[];\n}\n\nexport interface MediaGalleryItemData {\n  description?: string;\n  media: UnfurledMediaItemData;\n  spoiler?: boolean;\n}\nexport class MediaGalleryItem {\n  private constructor(data: APIMediaGalleryItem);\n  public readonly data: APIMediaGalleryItem;\n  public readonly media: UnfurledMediaItem;\n  public get description(): string | null;\n  public get spoiler(): boolean;\n}\n\nexport interface MessageCall {\n  get endedAt(): Date | null;\n  endedTimestamp: number | null;\n  participants: readonly Snowflake[];\n}\n\nexport type MessageComponentType =\n  | ComponentType.Button\n  | ComponentType.ChannelSelect\n  | ComponentType.MentionableSelect\n  | ComponentType.RoleSelect\n  | ComponentType.StringSelect\n  | ComponentType.UserSelect;\n\nexport interface MessageCollectorOptionsParams<\n  ComponentType extends MessageComponentType,\n  Cached extends boolean = boolean,\n> extends MessageComponentCollectorOptions<MappedInteractionTypes<Cached>[ComponentType]> {\n  componentType?: ComponentType;\n}\n\nexport interface MessageChannelCollectorOptionsParams<\n  ComponentType extends MessageComponentType,\n  Cached extends boolean = boolean,\n> extends MessageChannelComponentCollectorOptions<MappedInteractionTypes<Cached>[ComponentType]> {\n  componentType?: ComponentType;\n}\n\nexport interface AwaitMessageCollectorOptionsParams<\n  ComponentType extends MessageComponentType,\n  Cached extends boolean = boolean,\n> extends AwaitMessageComponentOptions<MappedInteractionTypes<Cached>[ComponentType]> {\n  componentType?: ComponentType;\n}\n\nexport interface StringMappedInteractionTypes<Cached extends CacheType = CacheType> {\n  ActionRow: MessageComponentInteraction<Cached>;\n  Button: ButtonInteraction<Cached>;\n  ChannelSelectMenu: ChannelSelectMenuInteraction<Cached>;\n  MentionableSelectMenu: MentionableSelectMenuInteraction<Cached>;\n  RoleSelectMenu: RoleSelectMenuInteraction<Cached>;\n  StringSelectMenu: StringSelectMenuInteraction<Cached>;\n  UserSelectMenu: UserSelectMenuInteraction<Cached>;\n}\n\nexport type WrapBooleanCache<Cached extends boolean> = If<Cached, 'cached', CacheType>;\n\nexport interface MappedInteractionTypes<Cached extends boolean = boolean> {\n  [ComponentType.Button]: ButtonInteraction<WrapBooleanCache<Cached>>;\n  [ComponentType.StringSelect]: StringSelectMenuInteraction<WrapBooleanCache<Cached>>;\n  [ComponentType.UserSelect]: UserSelectMenuInteraction<WrapBooleanCache<Cached>>;\n  [ComponentType.RoleSelect]: RoleSelectMenuInteraction<WrapBooleanCache<Cached>>;\n  [ComponentType.MentionableSelect]: MentionableSelectMenuInteraction<WrapBooleanCache<Cached>>;\n  [ComponentType.ChannelSelect]: ChannelSelectMenuInteraction<WrapBooleanCache<Cached>>;\n}\n\nexport class Message<InGuild extends boolean = boolean> extends Base {\n  private readonly _cacheType: InGuild;\n  private constructor(client: Client<true>, data: APIMessage);\n  private _patch(data: APIMessage | GatewayMessageUpdateDispatchData): void;\n\n  public activity: MessageActivity | null;\n  public applicationId: Snowflake | null;\n  public attachments: Collection<Snowflake, Attachment>;\n  public author: User;\n  public get bulkDeletable(): boolean;\n  public get channel(): If<InGuild, GuildTextBasedChannel, TextBasedChannel>;\n  public channelId: Snowflake;\n  public get cleanContent(): string;\n  public components: TopLevelComponent[];\n  public content: string;\n  public get createdAt(): Date;\n  public createdTimestamp: number;\n  public get crosspostable(): boolean;\n  public get deletable(): boolean;\n  public get editable(): boolean;\n  public get editedAt(): Date | null;\n  public editedTimestamp: number | null;\n  public embeds: Embed[];\n  public groupActivityApplication: ClientApplication | null;\n  public guildId: If<InGuild, Snowflake>;\n  public get guild(): If<InGuild, Guild>;\n  public get hasThread(): boolean;\n  public id: Snowflake;\n  public interactionMetadata: MessageInteractionMetadata | null;\n  public get member(): GuildMember | null;\n  public mentions: MessageMentions<InGuild>;\n  public nonce: number | string | null;\n  public get partial(): false;\n  public get pinnable(): boolean;\n  public pinned: boolean;\n  public reactions: ReactionManager;\n  public stickers: Collection<Snowflake, Sticker>;\n  public position: number | null;\n  public roleSubscriptionData: RoleSubscriptionData | null;\n  public resolved: CommandInteractionResolvedData | null;\n  public system: boolean;\n  public get thread(): AnyThreadChannel | null;\n  public tts: boolean;\n  public poll: Poll | null;\n  public call: MessageCall | null;\n  public type: MessageType;\n  public get url(): string;\n  public webhookId: Snowflake | null;\n  public flags: Readonly<MessageFlagsBitField>;\n  public reference: MessageReference | null;\n  public messageSnapshots: Collection<Snowflake, MessageSnapshot>;\n  public awaitMessageComponent<ComponentType extends MessageComponentType>(\n    options?: AwaitMessageCollectorOptionsParams<ComponentType, InGuild>,\n  ): Promise<MappedInteractionTypes<InGuild>[ComponentType]>;\n  public awaitReactions(options?: AwaitReactionsOptions): Promise<Collection<Snowflake | string, MessageReaction>>;\n  public createReactionCollector(options?: ReactionCollectorOptions): ReactionCollector;\n  public createMessageComponentCollector<ComponentType extends MessageComponentType>(\n    options?: MessageCollectorOptionsParams<ComponentType, InGuild>,\n  ): InteractionCollector<MappedInteractionTypes<InGuild>[ComponentType]>;\n  public delete(): Promise<OmitPartialGroupDMChannel<Message<InGuild>>>;\n  public edit(\n    content:\n      | FileBodyEncodable<RESTPatchAPIChannelMessageJSONBody>\n      | JSONEncodable<RESTPatchAPIChannelMessageJSONBody>\n      | MessageEditOptions\n      | MessagePayload\n      | string,\n  ): Promise<OmitPartialGroupDMChannel<Message<InGuild>>>;\n  public equals(message: Message, rawData?: APIMessage): boolean;\n  public fetchReference(): Promise<OmitPartialGroupDMChannel<Message<InGuild>>>;\n  public fetchWebhook(): Promise<Webhook>;\n  public crosspost(): Promise<OmitPartialGroupDMChannel<Message<InGuild>>>;\n  public fetch(force?: boolean): Promise<OmitPartialGroupDMChannel<Message<InGuild>>>;\n  public pin(reason?: string): Promise<OmitPartialGroupDMChannel<Message<InGuild>>>;\n  public react(emoji: EmojiIdentifierResolvable): Promise<MessageReaction>;\n  public removeAttachments(): Promise<OmitPartialGroupDMChannel<Message<InGuild>>>;\n  public reply(\n    options: MessagePayload | MessageReplyOptions | string,\n  ): Promise<OmitPartialGroupDMChannel<Message<InGuild>>>;\n  public forward(\n    channel: Exclude<TextBasedChannelResolvable, PartialGroupDMChannel>,\n  ): Promise<OmitPartialGroupDMChannel<Message>>;\n  public resolveComponent(customId: string): MessageActionRowComponent | null;\n  public startThread(options: StartThreadOptions): Promise<PublicThreadChannel<false>>;\n  public suppressEmbeds(suppress?: boolean): Promise<OmitPartialGroupDMChannel<Message<InGuild>>>;\n  public toJSON(): unknown;\n  public toString(): string;\n  public unpin(reason?: string): Promise<OmitPartialGroupDMChannel<Message<InGuild>>>;\n  public inGuild(): this is Message<true>;\n}\n\nexport class AuthorizingIntegrationOwners extends Base {\n  private constructor(client: Client<true>, data: APIAuthorizingIntegrationOwnersMap);\n  private readonly data: APIAuthorizingIntegrationOwnersMap;\n\n  // Getters from types\n  public readonly [ApplicationIntegrationType.GuildInstall]?: Snowflake;\n  public readonly [ApplicationIntegrationType.UserInstall]?: Snowflake;\n\n  public readonly guildId: Snowflake | null;\n  public get guild(): Guild | null;\n  public readonly userId: Snowflake | null;\n  public get user(): User | null;\n\n  public toJSON(): APIAuthorizingIntegrationOwnersMap;\n}\n\nexport class Attachment {\n  private constructor(data: APIAttachment);\n  private readonly attachment: BufferResolvable | Stream;\n  public contentType: string | null;\n  public description: string | null;\n  public duration: number | null;\n  public ephemeral: boolean;\n  public flags: AttachmentFlagsBitField;\n  public height: number | null;\n  public id: Snowflake;\n  public name: string;\n  public proxyURL: string;\n  public size: number;\n  public get spoiler(): boolean;\n  public title: string | null;\n  public url: string;\n  public waveform: string | null;\n  public width: number | null;\n  public toJSON(): unknown;\n}\n\nexport type AttachmentFlagsString = keyof typeof AttachmentFlags;\n\nexport class AttachmentFlagsBitField extends BitField<AttachmentFlagsString> {\n  public static Flags: Record<AttachmentFlagsString, number>;\n  public static resolve(bit?: BitFieldResolvable<AttachmentFlagsString, number>): number;\n}\n\nexport class MessageCollector extends Collector<Snowflake, Message, [Collection<Snowflake, Message>]> {\n  public constructor(channel: TextBasedChannel, options?: MessageCollectorOptions);\n  private _handleChannelDeletion(channel: NonThreadGuildBasedChannel): void;\n  private _handleGuildDeletion(guild: Guild): void;\n\n  public channel: TextBasedChannel;\n  public options: MessageCollectorOptions;\n  public received: number;\n\n  public collect(message: Message): Snowflake | null;\n  public dispose(message: Message): Snowflake | null;\n}\n\nexport class MessageComponentInteraction<Cached extends CacheType = CacheType> extends BaseInteraction<Cached> {\n  protected constructor(client: Client<true>, data: APIMessageComponentInteraction);\n  public type: InteractionType.MessageComponent;\n  public get component(): CacheTypeReducer<\n    Cached,\n    MessageActionRowComponent,\n    APIComponentInMessageActionRow,\n    APIComponentInMessageActionRow | MessageActionRowComponent,\n    APIComponentInMessageActionRow | MessageActionRowComponent\n  >;\n  public componentType: MessageComponentType;\n  public customId: string;\n  public channelId: Snowflake;\n  public deferred: boolean;\n  public ephemeral: boolean | null;\n  public message: Message<BooleanCache<Cached>>;\n  public replied: boolean;\n  public webhook: InteractionWebhook;\n  public inGuild(): this is MessageComponentInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is MessageComponentInteraction<'cached'>;\n  public inRawGuild(): this is MessageComponentInteraction<'raw'>;\n  public deferReply(\n    options: InteractionDeferReplyOptions & { withResponse: true },\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>>>;\n  public deferReply(options?: InteractionDeferReplyOptions & { withResponse: false }): Promise<undefined>;\n  public deferReply(\n    options?: InteractionDeferReplyOptions,\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>> | undefined>;\n  public deferUpdate(\n    options: InteractionDeferUpdateOptions & { withResponse: true },\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>>>;\n  public deferUpdate(options?: InteractionDeferUpdateOptions & { withResponse: false }): Promise<undefined>;\n  public deferUpdate(\n    options?: InteractionDeferUpdateOptions,\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>> | undefined>;\n  public deleteReply(message?: MessageResolvable | '@original'): Promise<void>;\n  public editReply(\n    options: InteractionEditReplyOptions | MessagePayload | string,\n  ): Promise<Message<BooleanCache<Cached>>>;\n  public fetchReply(message?: Snowflake | '@original'): Promise<Message<BooleanCache<Cached>>>;\n  public followUp(options: InteractionReplyOptions | MessagePayload | string): Promise<Message<BooleanCache<Cached>>>;\n  public reply(\n    options: InteractionReplyOptions & { withResponse: true },\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>>>;\n  public reply(options: InteractionReplyOptions & { withResponse: false }): Promise<undefined>;\n  public reply(\n    options: InteractionReplyOptions | MessagePayload | string,\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>> | undefined>;\n  public update(\n    options: InteractionUpdateOptions & { withResponse: true },\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>>>;\n  public update(options?: InteractionUpdateOptions & { withResponse: false }): Promise<undefined>;\n  public update(\n    options?: InteractionUpdateOptions | MessagePayload | string,\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>> | undefined>;\n  public launchActivity(\n    options: LaunchActivityOptions & { withResponse: true },\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>>>;\n  public launchActivity(options?: LaunchActivityOptions & { withResponse?: false }): Promise<undefined>;\n  public launchActivity(\n    options?: LaunchActivityOptions,\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>> | undefined>;\n  public showModal(\n    modal:\n      | APIModalInteractionResponseCallbackData\n      | JSONEncodable<APIModalInteractionResponseCallbackData>\n      | ModalComponentData,\n    options: ShowModalOptions & { withResponse: true },\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>>>;\n  public showModal(\n    modal:\n      | APIModalInteractionResponseCallbackData\n      | JSONEncodable<APIModalInteractionResponseCallbackData>\n      | ModalComponentData,\n    options?: ShowModalOptions & { withResponse: false },\n  ): Promise<undefined>;\n  public showModal(\n    modal:\n      | APIModalInteractionResponseCallbackData\n      | JSONEncodable<APIModalInteractionResponseCallbackData>\n      | ModalComponentData,\n    options?: ShowModalOptions,\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>> | undefined>;\n  public awaitModalSubmit(options: AwaitModalSubmitOptions): Promise<ModalSubmitInteraction<Cached>>;\n}\n\nexport class MessageContextMenuCommandInteraction<\n  Cached extends CacheType = CacheType,\n> extends ContextMenuCommandInteraction<Cached> {\n  public commandType: ApplicationCommandType.Message;\n  public options: Omit<\n    CommandInteractionOptionResolver<Cached>,\n    | 'getAttachment'\n    | 'getBoolean'\n    | 'getChannel'\n    | 'getFocused'\n    | 'getInteger'\n    | 'getMentionable'\n    | 'getNumber'\n    | 'getRole'\n    | 'getString'\n    | 'getSubcommand'\n    | 'getSubcommandGroup'\n    | 'getUser'\n  >;\n  public get targetMessage(): NonNullable<CommandInteractionOption<Cached>['message']>;\n  public inGuild(): this is MessageContextMenuCommandInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is MessageContextMenuCommandInteraction<'cached'>;\n  public inRawGuild(): this is MessageContextMenuCommandInteraction<'raw'>;\n}\n\nexport type MessageFlagsString = keyof typeof MessageFlags;\n\nexport class MessageFlagsBitField extends BitField<MessageFlagsString> {\n  public static Flags: typeof MessageFlags;\n  public static resolve(bit?: BitFieldResolvable<MessageFlagsString, number>): number;\n}\n\nexport class MessageMentions<InGuild extends boolean = boolean> {\n  private constructor(\n    message: Message,\n    users: ReadonlyCollection<Snowflake, User> | readonly APIUser[],\n    roles: ReadonlyCollection<Snowflake, Role> | readonly Snowflake[],\n    everyone: boolean,\n    repliedUser?: APIUser | User,\n  );\n  private readonly _channels: Collection<Snowflake, Channel> | null;\n  private readonly _content: string;\n  private readonly _members: Collection<Snowflake, GuildMember> | null;\n  private readonly _parsedUsers: Collection<Snowflake, User> | null;\n\n  public get channels(): Collection<Snowflake, Channel>;\n  public readonly client: Client;\n  public everyone: boolean;\n  public readonly guild: If<InGuild, Guild>;\n  public has(data: ChannelResolvable | RoleResolvable | UserResolvable, options?: MessageMentionsHasOptions): boolean;\n  public get members(): If<InGuild, Collection<Snowflake, GuildMember>>;\n  public get parsedUsers(): Collection<Snowflake, User>;\n  public repliedUser: User | null;\n  public roles: Collection<Snowflake, Role>;\n  public users: Collection<Snowflake, User>;\n  public crosspostedChannels: Collection<Snowflake, CrosspostedChannel>;\n  public toJSON(): unknown;\n\n  private static readonly GlobalChannelsPattern: RegExp;\n  private static readonly GlobalUsersPattern: RegExp;\n  public static ChannelsPattern: typeof FormattingPatterns.Channel;\n  public static EveryonePattern: RegExp;\n  public static RolesPattern: typeof FormattingPatterns.Role;\n  public static UsersPattern: typeof FormattingPatterns.User;\n}\n\nexport type MessagePayloadOption =\n  | InteractionReplyOptions\n  | InteractionUpdateOptions\n  | MessageCreateOptions\n  | MessageEditOptions\n  | WebhookMessageCreateOptions\n  | WebhookMessageEditOptions;\n\nexport class MessagePayload {\n  public constructor(target: MessageTarget, options: MessagePayloadOption);\n  public body: RawMessagePayloadData | null;\n  public get isUser(): boolean;\n  public get isWebhook(): boolean;\n  public get isMessage(): boolean;\n  public get isMessageManager(): boolean;\n  public files: RawFile[] | null;\n  public options: MessagePayloadOption;\n  public target: MessageTarget;\n\n  public static create(\n    target: MessageTarget,\n    options: MessagePayloadOption | string,\n    extra?: MessagePayloadOption,\n  ): MessagePayload;\n  public static resolveFile(\n    fileLike: AttachmentPayload | BufferResolvable | JSONEncodable<AttachmentPayload> | Stream,\n  ): Promise<RawFile>;\n\n  public makeContent(): string | undefined;\n  public resolveBody(): this;\n  public resolveFiles(): Promise<this>;\n}\n\nexport type RawMessagePayloadData =\n  | RESTPatchAPIChannelMessageJSONBody\n  | RESTPatchAPIInteractionFollowupJSONBody\n  | RESTPatchAPIInteractionOriginalResponseJSONBody\n  | RESTPatchAPIWebhookWithTokenJSONBody\n  | RESTPostAPIChannelMessageJSONBody\n  | RESTPostAPIInteractionCallbackFormDataBody\n  | RESTPostAPIInteractionFollowupJSONBody\n  | RESTPostAPIWebhookWithTokenJSONBody;\n\nexport class MessageReaction {\n  private constructor(client: Client<true>, data: unknown, message: Message);\n  private readonly _emoji: ApplicationEmoji | GuildEmoji | ReactionEmoji;\n\n  public burstColors: string[] | null;\n  public readonly client: Client<true>;\n  public count: number;\n  public countDetails: ReactionCountDetailsData;\n  public get emoji(): ApplicationEmoji | GuildEmoji | ReactionEmoji;\n  public me: boolean;\n  public meBurst: boolean;\n  public message: Message | PartialMessage;\n  public get partial(): false;\n  public users: ReactionUserManager;\n  public react(): Promise<MessageReaction>;\n  public remove(): Promise<MessageReaction>;\n  public fetch(): Promise<MessageReaction>;\n  public toJSON(): unknown;\n  public valueOf(): Snowflake | string;\n}\n\nexport interface MessageReactionEventDetails {\n  burst: boolean;\n  type: ReactionType;\n}\n\nexport interface ModalComponentData {\n  components: readonly (LabelData | TextDisplayComponentData)[];\n  customId: string;\n  title: string;\n}\n\nexport interface BaseModalData<Type extends ComponentType> {\n  id: number;\n  type: Type;\n}\n\nexport interface TextInputModalData extends BaseModalData<ComponentType.TextInput> {\n  customId: string;\n  value: string;\n}\n\nexport interface SelectMenuModalData<Cached extends CacheType = CacheType> extends BaseModalData<\n  | ComponentType.ChannelSelect\n  | ComponentType.MentionableSelect\n  | ComponentType.RoleSelect\n  | ComponentType.StringSelect\n  | ComponentType.UserSelect\n> {\n  channels?: ReadonlyCollection<\n    Snowflake,\n    CacheTypeReducer<Cached, GuildBasedChannel, APIInteractionDataResolvedChannel>\n  >;\n  customId: string;\n  members?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, GuildMember, APIInteractionDataResolvedGuildMember>>;\n  roles?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Role, APIRole>>;\n  users?: ReadonlyCollection<Snowflake, User>;\n  values: readonly string[];\n}\n\nexport interface FileUploadModalData extends BaseModalData<ComponentType.FileUpload> {\n  attachments: ReadonlyCollection<Snowflake, Attachment>;\n  customId: string;\n  values: readonly Snowflake[];\n}\n\nexport interface RadioGroupModalData extends BaseModalData<ComponentType.RadioGroup> {\n  customId: string;\n  value: string | null;\n}\n\nexport interface CheckboxGroupModalData extends BaseModalData<ComponentType.CheckboxGroup> {\n  customId: string;\n  values: readonly string[];\n}\n\nexport interface CheckboxModalData extends BaseModalData<ComponentType.Checkbox> {\n  customId: string;\n  value: boolean;\n}\n\nexport type ModalData =\n  | CheckboxGroupModalData\n  | CheckboxModalData\n  | FileUploadModalData\n  | RadioGroupModalData\n  | SelectMenuModalData\n  | TextInputModalData;\n\nexport interface LabelModalData extends BaseModalData<ComponentType.Label> {\n  component: ModalData;\n}\nexport interface ActionRowModalData extends BaseModalData<ComponentType.ActionRow> {\n  components: readonly TextInputModalData[];\n}\n\nexport interface TextDisplayModalData extends BaseModalData<ComponentType.TextDisplay> {}\n\nexport interface ModalSelectedMentionables<Cached extends CacheType = CacheType> {\n  members: NonNullable<SelectMenuModalData<Cached>['members']>;\n  roles: NonNullable<SelectMenuModalData<Cached>['roles']>;\n  users: NonNullable<SelectMenuModalData<Cached>['users']>;\n}\nexport class ModalComponentResolver<Cached extends CacheType = CacheType> {\n  private constructor(client: Client<true>, components: readonly ModalData[], resolved: BaseInteractionResolvedData);\n  public readonly client: Client<true>;\n  public readonly data: readonly (ActionRowModalData | LabelModalData | TextDisplayModalData)[];\n  public readonly resolved: Readonly<BaseInteractionResolvedData<Cached>> | null;\n  public readonly hoistedComponents: ReadonlyCollection<string, ModalData>;\n  public getComponent(customId: string): ModalData;\n  private _getTypedComponent(\n    customId: string,\n    allowedTypes: readonly ComponentType[],\n    properties: string,\n    required: boolean,\n  ): ModalData;\n  public getTextInputValue(customId: string): string;\n  public getStringSelectValues(customId: string): readonly string[];\n  public getSelectedUsers(customId: string, required: true): ReadonlyCollection<Snowflake, User>;\n  public getSelectedUsers(customId: string, required?: boolean): ReadonlyCollection<Snowflake, User> | null;\n  public getSelectedMembers(customId: string): NonNullable<SelectMenuModalData<Cached>['members']> | null;\n  public getSelectedChannels<const Type extends ChannelType = ChannelType>(\n    customId: string,\n    required: true,\n    channelTypes?: readonly Type[],\n  ): ReadonlyCollection<\n    Snowflake,\n    Extract<\n      NonNullable<CommandInteractionOption<Cached>['channel']>,\n      {\n        type: Type extends ChannelType.AnnouncementThread | ChannelType.PublicThread\n          ? ChannelType.AnnouncementThread | ChannelType.PublicThread\n          : Type;\n      }\n    >\n  >;\n  public getSelectedChannels<const Type extends ChannelType = ChannelType>(\n    customId: string,\n    required?: boolean,\n    channelTypes?: readonly Type[],\n  ): ReadonlyCollection<\n    Snowflake,\n    Extract<\n      NonNullable<CommandInteractionOption<Cached>['channel']>,\n      {\n        type: Type extends ChannelType.AnnouncementThread | ChannelType.PublicThread\n          ? ChannelType.AnnouncementThread | ChannelType.PublicThread\n          : Type;\n      }\n    >\n  > | null;\n\n  public getSelectedRoles(customId: string, required: true): NonNullable<SelectMenuModalData<Cached>['roles']>;\n  public getSelectedRoles(\n    customId: string,\n    required?: boolean,\n  ): NonNullable<SelectMenuModalData<Cached>['roles']> | null;\n\n  public getSelectedMentionables(customId: string, required: true): ModalSelectedMentionables<Cached>;\n  public getSelectedMentionables(customId: string, required?: boolean): ModalSelectedMentionables<Cached> | null;\n  public getUploadedFiles(customId: string, required: true): ReadonlyCollection<Snowflake, Attachment>;\n  public getUploadedFiles(customId: string, required?: boolean): ReadonlyCollection<Snowflake, Attachment> | null;\n  public getRadioGroup(customId: string, required: true): string;\n  public getRadioGroup(customId: string, required?: boolean): string | null;\n  public getCheckboxGroup(customId: string): readonly string[];\n  public getCheckbox(customId: string): boolean;\n}\n\nexport interface ModalMessageModalSubmitInteraction<\n  Cached extends CacheType = CacheType,\n> extends ModalSubmitInteraction<Cached> {\n  channelId: Snowflake;\n  inCachedGuild(): this is ModalMessageModalSubmitInteraction<'cached'>;\n  inGuild(): this is ModalMessageModalSubmitInteraction<'cached' | 'raw'>;\n  inRawGuild(): this is ModalMessageModalSubmitInteraction<'raw'>;\n  message: Message<BooleanCache<Cached>>;\n  update(\n    options: InteractionUpdateOptions & { withResponse: true },\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>>>;\n  update(\n    options: InteractionUpdateOptions | MessagePayload | string,\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>> | undefined>;\n  update(options: InteractionUpdateOptions & { withResponse: false }): Promise<undefined>;\n}\n\nexport class ModalSubmitInteraction<Cached extends CacheType = CacheType> extends BaseInteraction<Cached> {\n  private constructor(client: Client<true>, data: APIModalSubmitInteraction);\n  public type: InteractionType.ModalSubmit;\n  public readonly customId: string;\n  public readonly components: ModalComponentResolver<Cached>;\n  public deferred: boolean;\n  public ephemeral: boolean | null;\n  public message: Message<BooleanCache<Cached>> | null;\n  public replied: boolean;\n  public readonly webhook: InteractionWebhook;\n  public reply(\n    options: InteractionReplyOptions & { withResponse: true },\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>>>;\n  public reply(options: InteractionReplyOptions & { withResponse: false }): Promise<undefined>;\n  public reply(\n    options: InteractionReplyOptions | MessagePayload | string,\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>> | undefined>;\n  public deleteReply(message?: MessageResolvable | '@original'): Promise<void>;\n  public editReply(\n    options: InteractionEditReplyOptions | MessagePayload | string,\n  ): Promise<Message<BooleanCache<Cached>>>;\n  public deferReply(\n    options: InteractionDeferReplyOptions & { withResponse: true },\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>>>;\n  public deferReply(options?: InteractionDeferReplyOptions & { withResponse: false }): Promise<undefined>;\n  public deferReply(\n    options?: InteractionDeferReplyOptions,\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>> | undefined>;\n  public fetchReply(message?: Snowflake | '@original'): Promise<Message<BooleanCache<Cached>>>;\n  public followUp(options: InteractionReplyOptions | MessagePayload | string): Promise<Message<BooleanCache<Cached>>>;\n  public deferUpdate(\n    options: InteractionDeferUpdateOptions & { withResponse: true },\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>>>;\n  public deferUpdate(options?: InteractionDeferUpdateOptions & { withResponse: false }): Promise<undefined>;\n  public deferUpdate(\n    options?: InteractionDeferUpdateOptions,\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>> | undefined>;\n  public launchActivity(\n    options: LaunchActivityOptions & { withResponse: true },\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>>>;\n  public launchActivity(options?: LaunchActivityOptions & { withResponse?: false }): Promise<undefined>;\n  public launchActivity(\n    options?: LaunchActivityOptions,\n  ): Promise<InteractionCallbackResponse<BooleanCache<Cached>> | undefined>;\n  public inGuild(): this is ModalSubmitInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is ModalSubmitInteraction<'cached'>;\n  public inRawGuild(): this is ModalSubmitInteraction<'raw'>;\n  public isFromMessage(): this is ModalMessageModalSubmitInteraction<Cached>;\n}\n\nexport class AnnouncementChannel extends BaseGuildTextChannel {\n  public threads: GuildTextThreadManager<AllowedThreadTypeForAnnouncementChannel>;\n  public type: ChannelType.GuildAnnouncement;\n  public addFollower(channel: TextChannelResolvable, reason?: string): Promise<FollowedChannelData>;\n}\n\nexport type AnnouncementChannelResolvable = AnnouncementChannel | Snowflake;\n\nexport class OAuth2Guild extends BaseGuild {\n  private constructor(client: Client<true>, data: RESTAPIPartialCurrentUserGuild);\n  public owner: boolean;\n  public permissions: Readonly<PermissionsBitField>;\n}\n\nexport interface PartialGroupDMChannel extends TextBasedChannelFields<false, false>, PinnableChannelFields {}\nexport class PartialGroupDMChannel extends BaseChannel {\n  private constructor(client: Client<true>, data: RawPartialGroupDMChannelData);\n  public type: ChannelType.GroupDM;\n  public flags: null;\n  public name: string | null;\n  public icon: string | null;\n  public recipients: PartialRecipient[];\n  public ownerId: Snowflake | null;\n  public iconURL(options?: ImageURLOptions): string | null;\n  public fetchOwner(options?: BaseFetchOptions): Promise<User>;\n  public toString(): ChannelMention;\n}\n\nexport interface GuildForumTagEmoji {\n  id: Snowflake | null;\n  name: string | null;\n}\n\nexport interface GuildForumTag {\n  emoji: GuildForumTagEmoji | null;\n  id: Snowflake;\n  moderated: boolean;\n  name: string;\n}\n\nexport interface GuildForumTagData extends Partial<GuildForumTag> {\n  name: string;\n}\n\nexport interface DefaultReactionEmoji {\n  id: Snowflake | null;\n  name: string | null;\n}\n\nexport interface ThreadOnlyChannel extends WebhookChannelFields, SetRateLimitPerUserMethod {}\nexport abstract class ThreadOnlyChannel extends GuildChannel {\n  public type: ChannelType.GuildForum | ChannelType.GuildMedia;\n  public threads: GuildForumThreadManager;\n  public availableTags: GuildForumTag[];\n  public defaultReactionEmoji: DefaultReactionEmoji | null;\n  public defaultThreadRateLimitPerUser: number | null;\n  public rateLimitPerUser: number | null;\n  public defaultAutoArchiveDuration: ThreadAutoArchiveDuration | null;\n  public nsfw: boolean;\n  public topic: string | null;\n  public defaultSortOrder: SortOrderType | null;\n  public setAvailableTags(tags: readonly GuildForumTagData[], reason?: string): Promise<this>;\n  public setDefaultReactionEmoji(emojiId: DefaultReactionEmoji | null, reason?: string): Promise<this>;\n  public setDefaultThreadRateLimitPerUser(rateLimit: number, reason?: string): Promise<this>;\n  public createInvite(options?: InviteCreateOptions): Promise<GuildInvite>;\n  public fetchInvites(cache?: boolean): Promise<Collection<string, GuildInvite>>;\n  public setDefaultAutoArchiveDuration(\n    defaultAutoArchiveDuration: ThreadAutoArchiveDuration,\n    reason?: string,\n  ): Promise<this>;\n  public setTopic(topic: string | null, reason?: string): Promise<this>;\n  public setDefaultSortOrder(defaultSortOrder: SortOrderType | null, reason?: string): Promise<this>;\n}\n\nexport class ForumChannel extends ThreadOnlyChannel {\n  public type: ChannelType.GuildForum;\n  public defaultForumLayout: ForumLayoutType;\n  public setDefaultForumLayout(defaultForumLayout: ForumLayoutType, reason?: string): Promise<this>;\n}\n\nexport class MediaChannel extends ThreadOnlyChannel {\n  public type: ChannelType.GuildMedia;\n}\n\nexport class PermissionOverwrites extends Base {\n  private constructor(client: Client<true>, data: unknown, channel: NonThreadGuildBasedChannel);\n  public allow: Readonly<PermissionsBitField>;\n  public readonly channel: NonThreadGuildBasedChannel;\n  public deny: Readonly<PermissionsBitField>;\n  public id: Snowflake;\n  public type: OverwriteType;\n  public edit(options: PermissionOverwriteOptions, reason?: string): Promise<PermissionOverwrites>;\n  public delete(reason?: string): Promise<PermissionOverwrites>;\n  public toJSON(): unknown;\n  public static resolveOverwriteOptions(\n    options: PermissionOverwriteOptions,\n    initialPermissions: { allow?: PermissionResolvable; deny?: PermissionResolvable },\n  ): ResolvedOverwriteOptions;\n  public static resolve(overwrite: OverwriteResolvable, guild: Guild): APIOverwrite;\n}\n\nexport type PermissionsString = keyof typeof PermissionFlagsBits;\n\nexport class PermissionsBitField extends BitField<PermissionsString, bigint> {\n  public any(permission: PermissionResolvable, checkAdmin?: boolean): boolean;\n  public has(permission: PermissionResolvable, checkAdmin?: boolean): boolean;\n  public missing(bits: BitFieldResolvable<PermissionsString, bigint>, checkAdmin?: boolean): PermissionsString[];\n  public serialize(checkAdmin?: boolean): Record<PermissionsString, boolean>;\n  public toArray(): PermissionsString[];\n\n  public static All: bigint;\n  public static Default: bigint;\n  public static StageModerator: bigint;\n  public static Flags: typeof PermissionFlagsBits;\n  public static resolve(permission?: PermissionResolvable): bigint;\n}\n\nexport class Presence extends Base {\n  protected constructor(client: Client<true>, data?: GatewayPresenceUpdate);\n  public activities: Activity[];\n  public clientStatus: ClientPresenceStatusData | null;\n  public guild: Guild | null;\n  public get member(): GuildMember | null;\n  public status: PresenceStatus;\n  public get user(): User | null;\n  public userId: Snowflake;\n  public equals(presence: Presence): boolean;\n}\n\nexport interface PollQuestionMedia {\n  text: string | null;\n}\n\nexport interface BaseFetchPollAnswerVotersOptions {\n  after?: Snowflake;\n  limit?: number;\n}\n\nexport class PollAnswerVoterManager extends CachedManager<Snowflake, User, UserResolvable> {\n  private constructor(answer: PollAnswer);\n  public answer: PollAnswer;\n  public fetch(options?: BaseFetchPollAnswerVotersOptions): Promise<Collection<Snowflake, User>>;\n}\n\nexport class Poll extends Base {\n  private constructor(client: Client<true>, data: APIPoll, message: Message, channel: TextBasedChannel);\n  public readonly channel: TextBasedChannel;\n  public channelId: Snowflake;\n  public readonly message: Message;\n  public messageId: Snowflake;\n  public question: PollQuestionMedia;\n  public answers: Collection<number, PartialPollAnswer | PollAnswer>;\n  public expiresTimestamp: number | null;\n  public get expiresAt(): Date | null;\n  public allowMultiselect: boolean;\n  public layoutType: PollLayoutType;\n  public resultsFinalized: boolean;\n  public get partial(): false;\n  public fetch(): Promise<this>;\n  public end(): Promise<Message>;\n}\n\nexport class PollAnswer extends Base {\n  private constructor(client: Client<true>, data: APIPollAnswer & { count?: number }, poll: Poll);\n  private readonly _emoji: APIPartialEmoji | null;\n  public readonly poll: PartialPoll | Poll;\n  public id: number;\n  public text: string | null;\n  public voteCount: number;\n  public voters: PollAnswerVoterManager;\n  public get emoji(): Emoji | GuildEmoji | null;\n  public get partial(): false;\n}\n\nexport interface ReactionCollectorEventTypes extends CollectorEventTypes<Snowflake | string, MessageReaction, [User]> {\n  remove: [reaction: MessageReaction, user: User];\n}\n\nexport class ReactionCollector extends Collector<\n  Snowflake | string,\n  MessageReaction,\n  [User],\n  ReactionCollectorEventTypes\n> {\n  public constructor(message: Message, options?: ReactionCollectorOptions);\n  private _handleChannelDeletion(channel: NonThreadGuildBasedChannel): void;\n  private _handleGuildDeletion(guild: Guild): void;\n  private _handleMessageDeletion(message: Message): void;\n\n  public message: Message;\n  public options: ReactionCollectorOptions;\n  public total: number;\n  public users: Collection<Snowflake, User>;\n\n  public static key(reaction: MessageReaction): Snowflake | string;\n\n  public collect(reaction: MessageReaction, user: User): Snowflake | string | null;\n  public dispose(reaction: MessageReaction, user: User): Snowflake | string | null;\n  public empty(): void;\n}\n\nexport class ReactionEmoji extends Emoji {\n  private constructor(reaction: MessageReaction, emoji: unknown);\n  public reaction: MessageReaction;\n  public toJSON(): unknown;\n}\n\nexport class RichPresenceAssets {\n  private constructor(activity: Activity, assets: GatewayActivityAssets);\n  public readonly activity: Activity;\n  public largeImage: Snowflake | null;\n  public largeText: string | null;\n  public smallImage: Snowflake | null;\n  public smallText: string | null;\n  public largeImageURL(options?: ImageURLOptions): string | null;\n  public smallImageURL(options?: ImageURLOptions): string | null;\n}\n\nexport interface RoleColors {\n  primaryColor: number;\n  secondaryColor: number | null;\n  tertiaryColor: number | null;\n}\n\nexport interface RoleColorsResolvable {\n  primaryColor: ColorResolvable;\n  secondaryColor?: ColorResolvable;\n  tertiaryColor?: ColorResolvable;\n}\n\nexport class Role extends Base {\n  private constructor(client: Client<true>, data: APIRole, guild: Guild);\n  public colors: RoleColors;\n  public get createdAt(): Date;\n  public get createdTimestamp(): number;\n  public get editable(): boolean;\n  public flags: RoleFlagsBitField;\n  public guild: Guild;\n  public get hexColor(): HexColorString;\n  public hoist: boolean;\n  public id: Snowflake;\n  public managed: boolean;\n  public get members(): Collection<Snowflake, GuildMember>;\n  public mentionable: boolean;\n  public name: string;\n  public permissions: Readonly<PermissionsBitField>;\n  public get position(): number;\n  public rawPosition: number;\n  public tags: RoleTagData | null;\n  public comparePositionTo(role: RoleResolvable): number;\n  public icon: string | null;\n  public unicodeEmoji: string | null;\n  public delete(reason?: string): Promise<Role>;\n  public edit(options: RoleEditOptions): Promise<Role>;\n  public equals(role: Role): boolean;\n  public iconURL(options?: ImageURLOptions): string | null;\n  public permissionsIn(\n    channel: NonThreadGuildBasedChannel | Snowflake,\n    checkAdmin?: boolean,\n  ): Readonly<PermissionsBitField>;\n  public setColors(colors: RoleColorsResolvable, reason?: string): Promise<Role>;\n  public setHoist(hoist?: boolean, reason?: string): Promise<Role>;\n  public setMentionable(mentionable?: boolean, reason?: string): Promise<Role>;\n  public setName(name: string, reason?: string): Promise<Role>;\n  public setPermissions(permissions: PermissionResolvable, reason?: string): Promise<Role>;\n  public setIcon(icon: Base64Resolvable | BufferResolvable | EmojiResolvable | null, reason?: string): Promise<Role>;\n  public setPosition(position: number, options?: SetRolePositionOptions): Promise<Role>;\n  public setUnicodeEmoji(unicodeEmoji: string | null, reason?: string): Promise<Role>;\n  public toJSON(): unknown;\n  public toString(): RoleMention;\n}\n\nexport type RoleFlagsString = keyof typeof RoleFlags;\n\nexport class RoleFlagsBitField extends BitField<RoleFlagsString> {\n  public static Flags: typeof RoleFlags;\n  public static resolve(bit?: BitFieldResolvable<RoleFlagsString, number>): number;\n}\n\nexport interface SectionComponentData extends BaseComponentData {\n  accessory: ButtonComponentData | ThumbnailComponentData;\n  components: readonly TextDisplayComponentData[];\n}\n\nexport class SectionComponent<\n  AccessoryType extends ButtonComponent | ThumbnailComponent = ButtonComponent | ThumbnailComponent,\n> extends Component<APISectionComponent> {\n  private constructor(data: APISectionComponent);\n  public readonly accessory: AccessoryType;\n  public readonly components: TextDisplayComponent[];\n  public toJSON(): APISectionComponent;\n}\n\nexport class StringSelectMenuInteraction<\n  Cached extends CacheType = CacheType,\n> extends MessageComponentInteraction<Cached> {\n  public constructor(client: Client<true>, data: APIMessageStringSelectInteractionData);\n  public get component(): CacheTypeReducer<\n    Cached,\n    StringSelectMenuComponent,\n    APIStringSelectComponent,\n    APIStringSelectComponent | StringSelectMenuComponent,\n    APIStringSelectComponent | StringSelectMenuComponent\n  >;\n  public componentType: ComponentType.StringSelect;\n  public values: string[];\n  public inGuild(): this is StringSelectMenuInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is StringSelectMenuInteraction<'cached'>;\n  public inRawGuild(): this is StringSelectMenuInteraction<'raw'>;\n}\n\nexport class UserSelectMenuInteraction<\n  Cached extends CacheType = CacheType,\n> extends MessageComponentInteraction<Cached> {\n  public constructor(client: Client<true>, data: APIMessageUserSelectInteractionData);\n  public get component(): CacheTypeReducer<\n    Cached,\n    UserSelectMenuComponent,\n    APIUserSelectComponent,\n    APIUserSelectComponent | UserSelectMenuComponent,\n    APIUserSelectComponent | UserSelectMenuComponent\n  >;\n  public componentType: ComponentType.UserSelect;\n  public values: Snowflake[];\n  public users: Collection<Snowflake, User>;\n  public members: Collection<\n    Snowflake,\n    CacheTypeReducer<Cached, GuildMember, APIGuildMember, APIGuildMember | GuildMember, APIGuildMember | GuildMember>\n  >;\n  public inGuild(): this is UserSelectMenuInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is UserSelectMenuInteraction<'cached'>;\n  public inRawGuild(): this is UserSelectMenuInteraction<'raw'>;\n}\n\nexport class RoleSelectMenuInteraction<\n  Cached extends CacheType = CacheType,\n> extends MessageComponentInteraction<Cached> {\n  public constructor(client: Client<true>, data: APIMessageRoleSelectInteractionData);\n  public get component(): CacheTypeReducer<\n    Cached,\n    RoleSelectMenuComponent,\n    APIRoleSelectComponent,\n    APIRoleSelectComponent | RoleSelectMenuComponent,\n    APIRoleSelectComponent | RoleSelectMenuComponent\n  >;\n  public componentType: ComponentType.RoleSelect;\n  public values: Snowflake[];\n  public roles: Collection<Snowflake, CacheTypeReducer<Cached, Role, APIRole, APIRole | Role, APIRole | Role>>;\n  public inGuild(): this is RoleSelectMenuInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is RoleSelectMenuInteraction<'cached'>;\n  public inRawGuild(): this is RoleSelectMenuInteraction<'raw'>;\n}\n\nexport class MentionableSelectMenuInteraction<\n  Cached extends CacheType = CacheType,\n> extends MessageComponentInteraction<Cached> {\n  public constructor(client: Client<true>, data: APIMessageMentionableSelectInteractionData);\n  public get component(): CacheTypeReducer<\n    Cached,\n    MentionableSelectMenuComponent,\n    APIMentionableSelectComponent,\n    APIMentionableSelectComponent | MentionableSelectMenuComponent,\n    APIMentionableSelectComponent | MentionableSelectMenuComponent\n  >;\n  public componentType: ComponentType.MentionableSelect;\n  public values: Snowflake[];\n  public users: Collection<Snowflake, User>;\n  public members: Collection<\n    Snowflake,\n    CacheTypeReducer<Cached, GuildMember, APIGuildMember, APIGuildMember | GuildMember, APIGuildMember | GuildMember>\n  >;\n  public roles: Collection<Snowflake, CacheTypeReducer<Cached, Role, APIRole, APIRole | Role, APIRole | Role>>;\n  public inGuild(): this is MentionableSelectMenuInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is MentionableSelectMenuInteraction<'cached'>;\n  public inRawGuild(): this is MentionableSelectMenuInteraction<'raw'>;\n}\n\nexport class ChannelSelectMenuInteraction<\n  Cached extends CacheType = CacheType,\n> extends MessageComponentInteraction<Cached> {\n  public constructor(client: Client<true>, data: APIMessageChannelSelectInteractionData);\n  public get component(): CacheTypeReducer<\n    Cached,\n    ChannelSelectMenuComponent,\n    APIChannelSelectComponent,\n    APIChannelSelectComponent | ChannelSelectMenuComponent,\n    APIChannelSelectComponent | ChannelSelectMenuComponent\n  >;\n  public componentType: ComponentType.ChannelSelect;\n  public values: Snowflake[];\n  public channels: Collection<\n    Snowflake,\n    CacheTypeReducer<Cached, Channel, APIChannel, APIChannel | Channel, APIChannel | Channel>\n  >;\n  public inGuild(): this is ChannelSelectMenuInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is ChannelSelectMenuInteraction<'cached'>;\n  public inRawGuild(): this is ChannelSelectMenuInteraction<'raw'>;\n}\n\nexport type SelectMenuInteraction<Cached extends CacheType = CacheType> =\n  | ChannelSelectMenuInteraction<Cached>\n  | MentionableSelectMenuInteraction<Cached>\n  | RoleSelectMenuInteraction<Cached>\n  | StringSelectMenuInteraction<Cached>\n  | UserSelectMenuInteraction<Cached>;\n\nexport type SelectMenuType = APISelectMenuComponent['type'];\n\nexport interface SeparatorComponentData extends BaseComponentData {\n  divider?: boolean;\n  spacing?: SeparatorSpacingSize;\n}\nexport class SeparatorComponent extends Component<APISeparatorComponent> {\n  private constructor(data: APISeparatorComponent);\n  public get spacing(): SeparatorSpacingSize;\n  public get divider(): boolean;\n}\n\nexport interface ShardEventTypes {\n  death: [process: ChildProcess | Worker];\n  disconnect: [];\n  error: [error: Error];\n  message: [message: any];\n  ready: [];\n  reconnecting: [];\n  resume: [];\n  spawn: [process: ChildProcess | Worker];\n}\n\nexport class Shard extends AsyncEventEmitter<ShardEventTypes> {\n  private constructor(manager: ShardingManager, id: number);\n  private readonly _evals: Map<string, Promise<unknown>>;\n  private readonly _exitListener: (...args: any[]) => void;\n  private readonly _fetches: Map<string, Promise<unknown>>;\n  private _handleExit(respawn?: boolean, timeout?: number): void;\n  private _handleMessage(message: unknown): void;\n  private incrementMaxListeners(emitter: ChildProcess | Worker): void;\n  private decrementMaxListeners(emitter: ChildProcess | Worker): void;\n\n  public args: string[];\n  public execArgv: string[];\n  public env: unknown;\n  public id: number;\n  public manager: ShardingManager;\n  public process: ChildProcess | null;\n  public ready: boolean;\n  public silent: boolean;\n  public worker: Worker | null;\n  public eval(script: string): Promise<unknown>;\n  public eval<Result>(fn: (client: Client) => Result): Promise<Result>;\n  public eval<Result, Context>(\n    fn: (client: Client<true>, context: Serialized<Context>) => Result,\n    context: Context,\n  ): Promise<Result>;\n  public fetchClientValue(prop: string): Promise<unknown>;\n  public kill(): void;\n  public respawn(options?: { delay?: number; timeout?: number }): Promise<ChildProcess>;\n  public send(message: unknown): Promise<Shard>;\n  public spawn(timeout?: number): Promise<ChildProcess>;\n}\n\nexport class ShardClientUtil {\n  private constructor(client: Client<true>, mode: ShardingManagerMode);\n  private _handleMessage(message: unknown): void;\n  private _respond(type: string, message: unknown): void;\n  private incrementMaxListeners(emitter: ChildProcess | Worker): void;\n  private decrementMaxListeners(emitter: ChildProcess | Worker): void;\n\n  public client: Client;\n  public mode: ShardingManagerMode;\n  public parentPort: MessagePort | null;\n  public broadcastEval<Result>(fn: (client: Client) => Awaitable<Result>): Promise<Serialized<Result>[]>;\n  public broadcastEval<Result, Context>(\n    fn: (client: Client<true>, context: Serialized<Context>) => Awaitable<Result>,\n    options: { context: Context; shard: number },\n  ): Promise<Serialized<Result>>;\n  public broadcastEval<Result, Context>(\n    fn: (client: Client<true>, context: Serialized<Context>) => Awaitable<Result>,\n    options: { context: Context },\n  ): Promise<Serialized<Result>[]>;\n  public broadcastEval<Result>(\n    fn: (client: Client) => Awaitable<Result>,\n    options: { shard: number },\n  ): Promise<Serialized<Result>>;\n  public fetchClientValues(prop: string): Promise<unknown[]>;\n  public fetchClientValues(prop: string, shard: number): Promise<unknown>;\n  public respawnAll(options?: MultipleShardRespawnOptions): Promise<void>;\n  public send(message: unknown): Promise<void>;\n\n  public static singleton(client: Client<true>, mode: ShardingManagerMode): ShardClientUtil;\n  public static shardIdForGuildId(guildId: Snowflake, shardCount: number): number;\n}\n\nexport interface ShardingManagerEventTypes {\n  shardCreate: [shard: Shard];\n}\n\nexport class ShardingManager extends AsyncEventEmitter<ShardingManagerEventTypes> {\n  public constructor(file: string, options?: ShardingManagerOptions);\n  private _performOnShards(method: string, args: readonly unknown[]): Promise<unknown[]>;\n  private _performOnShards(method: string, args: readonly unknown[], shard: number): Promise<unknown>;\n\n  public file: string;\n  public respawn: boolean;\n  public silent: boolean;\n  public shardArgs: string[];\n  public shards: Collection<number, Shard>;\n  public token: string | null;\n  public totalShards: number | 'auto';\n  public shardList: number[] | 'auto';\n  public broadcast(message: unknown): Promise<Shard[]>;\n  public broadcastEval<Result>(fn: (client: Client) => Awaitable<Result>): Promise<Serialized<Result>[]>;\n  public broadcastEval<Result, Context>(\n    fn: (client: Client<true>, context: Serialized<Context>) => Awaitable<Result>,\n    options: { context: Context; shard: number },\n  ): Promise<Serialized<Result>>;\n  public broadcastEval<Result, Context>(\n    fn: (client: Client<true>, context: Serialized<Context>) => Awaitable<Result>,\n    options: { context: Context },\n  ): Promise<Serialized<Result>[]>;\n  public broadcastEval<Result>(\n    fn: (client: Client) => Awaitable<Result>,\n    options: { shard: number },\n  ): Promise<Serialized<Result>>;\n  public createShard(id: number): Shard;\n  public fetchClientValues(prop: string): Promise<unknown[]>;\n  public fetchClientValues(prop: string, shard: number): Promise<unknown>;\n  public respawnAll(options?: MultipleShardRespawnOptions): Promise<Collection<number, Shard>>;\n  public spawn(options?: MultipleShardSpawnOptions): Promise<Collection<number, Shard>>;\n}\n\nexport interface FetchRecommendedShardCountOptions {\n  guildsPerShard?: number;\n  multipleOf?: number;\n}\n\nexport {\n  DiscordSnowflake as SnowflakeUtil,\n  type SnowflakeGenerateOptions,\n  type DeconstructedSnowflake,\n} from '@sapphire/snowflake';\n\nexport class SKU extends Base {\n  private constructor(client: Client<true>, data: APISKU);\n  public id: Snowflake;\n  public type: SKUType;\n  public applicationId: Snowflake;\n  public name: string;\n  public slug: string;\n  public flags: Readonly<SKUFlagsBitField>;\n}\n\nexport type SKUFlagsString = keyof typeof SKUFlags;\n\nexport class SKUFlagsBitField extends BitField<SKUFlagsString> {\n  public static FLAGS: typeof SKUFlags;\n  public static resolve(bit?: BitFieldResolvable<SKUFlagsString, number>): number;\n}\n\nexport class Subscription extends Base {\n  private constructor(client: Client<true>, data: APISubscription);\n  public id: Snowflake;\n  public userId: Snowflake;\n  public skuIds: Snowflake[];\n  public entitlementIds: Snowflake[];\n  public renewalSkuIds: Snowflake[] | null;\n  public currentPeriodStartTimestamp: number;\n  public currentPeriodEndTimestamp: number;\n  public status: SubscriptionStatus;\n  public canceledTimestamp: number | null;\n  public country: string | null;\n  public get canceledAt(): Date | null;\n  public get currentPeriodStartAt(): Date;\n  public get currentPeriodEndAt(): Date;\n}\n\nexport class StageChannel extends BaseGuildVoiceChannel {\n  public get stageInstance(): StageInstance | null;\n  public topic: string | null;\n  public type: ChannelType.GuildStageVoice;\n  public createStageInstance(options: StageInstanceCreateOptions): Promise<StageInstance>;\n  public setTopic(topic: string): Promise<StageChannel>;\n}\n\nexport class DirectoryChannel extends BaseChannel {\n  public flags: Readonly<ChannelFlagsBitField>;\n  public guild: InviteGuild;\n  public guildId: Snowflake;\n  public name: string;\n  public toString(): ChannelMention;\n}\n\nexport class StageInstance extends Base {\n  private constructor(client: Client<true>, data: unknown, channel: StageChannel);\n  public id: Snowflake;\n  public guildId: Snowflake;\n  public channelId: Snowflake;\n  public topic: string;\n  public privacyLevel: StageInstancePrivacyLevel;\n  public guildScheduledEventId?: Snowflake;\n  public get channel(): StageChannel | null;\n  public get guild(): Guild | null;\n  public get guildScheduledEvent(): GuildScheduledEvent | null;\n  public edit(options: StageInstanceEditOptions): Promise<StageInstance>;\n  public delete(): Promise<StageInstance>;\n  public setTopic(topic: string): Promise<StageInstance>;\n  public get createdTimestamp(): number;\n  public get createdAt(): Date;\n}\n\nexport class Sticker extends Base {\n  private constructor(client: Client<true>, data: unknown);\n  public get createdTimestamp(): number;\n  public get createdAt(): Date;\n  public available: boolean | null;\n  public description: string | null;\n  public format: StickerFormatType;\n  public get guild(): Guild | null;\n  public guildId: Snowflake | null;\n  public id: Snowflake;\n  public name: string;\n  public packId: Snowflake | null;\n  public get partial(): boolean;\n  public sortValue: number | null;\n  public tags: string | null;\n  public type: StickerType | null;\n  public user: User | null;\n  public get url(): string;\n  public fetch(): Promise<Sticker>;\n  public fetchPack(): Promise<StickerPack | null>;\n  public fetchUser(): Promise<User | null>;\n  public edit(options?: GuildStickerEditOptions): Promise<Sticker>;\n  public delete(reason?: string): Promise<Sticker>;\n  public equals(other: Sticker | unknown): boolean;\n}\n\nexport class StickerPack extends Base {\n  private constructor(client: Client<true>, data: APIStickerPack);\n  public get createdTimestamp(): number;\n  public get createdAt(): Date;\n  public bannerId: Snowflake | null;\n  public get coverSticker(): Sticker | null;\n  public coverStickerId: Snowflake | null;\n  public description: string;\n  public id: Snowflake;\n  public name: string;\n  public skuId: Snowflake;\n  public stickers: Collection<Snowflake, Sticker>;\n  public bannerURL(options?: ImageURLOptions): string | null;\n}\n\nexport class Sweepers {\n  public constructor(client: Client<true>, options: SweeperOptions);\n  public readonly client: Client;\n  public intervals: Record<SweeperKey, NodeJS.Timeout | null>;\n  public options: SweeperOptions;\n\n  public sweepApplicationCommands(\n    filter: CollectionSweepFilter<\n      SweeperDefinitions['applicationCommands'][0],\n      SweeperDefinitions['applicationCommands'][1]\n    >,\n  ): number;\n  public sweepAutoModerationRules(\n    filter: CollectionSweepFilter<\n      SweeperDefinitions['autoModerationRules'][0],\n      SweeperDefinitions['autoModerationRules'][1]\n    >,\n  ): number;\n  public sweepBans(filter: CollectionSweepFilter<SweeperDefinitions['bans'][0], SweeperDefinitions['bans'][1]>): number;\n  public sweepEmojis(\n    filter: CollectionSweepFilter<SweeperDefinitions['emojis'][0], SweeperDefinitions['emojis'][1]>,\n  ): number;\n  public sweepEntitlements(\n    filter: CollectionSweepFilter<SweeperDefinitions['entitlements'][0], SweeperDefinitions['entitlements'][1]>,\n  ): number;\n  public sweepInvites(\n    filter: CollectionSweepFilter<SweeperDefinitions['invites'][0], SweeperDefinitions['invites'][1]>,\n  ): number;\n  public sweepGuildMembers(\n    filter: CollectionSweepFilter<SweeperDefinitions['guildMembers'][0], SweeperDefinitions['guildMembers'][1]>,\n  ): number;\n  public sweepMessages(\n    filter: CollectionSweepFilter<SweeperDefinitions['messages'][0], SweeperDefinitions['messages'][1]>,\n  ): number;\n  public sweepPresences(\n    filter: CollectionSweepFilter<SweeperDefinitions['presences'][0], SweeperDefinitions['presences'][1]>,\n  ): number;\n  public sweepReactions(\n    filter: CollectionSweepFilter<SweeperDefinitions['reactions'][0], SweeperDefinitions['reactions'][1]>,\n  ): number;\n  public sweepStageInstances(\n    filter: CollectionSweepFilter<SweeperDefinitions['stageInstances'][0], SweeperDefinitions['stageInstances'][1]>,\n  ): number;\n  public sweepStickers(\n    filter: CollectionSweepFilter<SweeperDefinitions['stickers'][0], SweeperDefinitions['stickers'][1]>,\n  ): number;\n  public sweepThreadMembers(\n    filter: CollectionSweepFilter<SweeperDefinitions['threadMembers'][0], SweeperDefinitions['threadMembers'][1]>,\n  ): number;\n  public sweepThreads(\n    filter: CollectionSweepFilter<SweeperDefinitions['threads'][0], SweeperDefinitions['threads'][1]>,\n  ): number;\n  public sweepUsers(\n    filter: CollectionSweepFilter<SweeperDefinitions['users'][0], SweeperDefinitions['users'][1]>,\n  ): number;\n  public sweepVoiceStates(\n    filter: CollectionSweepFilter<SweeperDefinitions['voiceStates'][0], SweeperDefinitions['voiceStates'][1]>,\n  ): number;\n\n  public static archivedThreadSweepFilter(\n    lifetime?: number,\n  ): GlobalSweepFilter<SweeperDefinitions['threads'][0], SweeperDefinitions['threads'][1]>;\n  public static expiredInviteSweepFilter(\n    lifetime?: number,\n  ): GlobalSweepFilter<SweeperDefinitions['invites'][0], SweeperDefinitions['invites'][1]>;\n  public static filterByLifetime<Key, Value>(\n    options?: LifetimeFilterOptions<Key, Value>,\n  ): GlobalSweepFilter<Key, Value>;\n  public static outdatedMessageSweepFilter(\n    lifetime?: number,\n  ): GlobalSweepFilter<SweeperDefinitions['messages'][0], SweeperDefinitions['messages'][1]>;\n}\n\nexport type SystemChannelFlagsString = keyof typeof GuildSystemChannelFlags;\n\nexport class SystemChannelFlagsBitField extends BitField<SystemChannelFlagsString> {\n  public static Flags: typeof GuildSystemChannelFlags;\n  public static resolve(bit?: BitFieldResolvable<SystemChannelFlagsString, number>): number;\n}\n\nexport class Team extends Base {\n  private constructor(client: Client<true>, data: APITeam);\n  public id: Snowflake;\n  public name: string;\n  public icon: string | null;\n  public ownerId: Snowflake | null;\n  public members: Collection<Snowflake, TeamMember>;\n  public get owner(): TeamMember | null;\n  public get createdAt(): Date;\n  public get createdTimestamp(): number;\n\n  public iconURL(options?: ImageURLOptions): string | null;\n  public toJSON(): unknown;\n  public toString(): string;\n}\n\nexport class TeamMember extends Base {\n  private constructor(team: Team, data: APITeamMember);\n  public team: Team;\n  public get id(): Snowflake;\n  public membershipState: TeamMemberMembershipState;\n  public user: User;\n  public role: TeamMemberRole;\n\n  public toString(): UserMention;\n}\n\nexport class TextChannel extends BaseGuildTextChannel {\n  public rateLimitPerUser: number;\n  public threads: GuildTextThreadManager<AllowedThreadTypeForTextChannel>;\n  public type: ChannelType.GuildText;\n}\n\nexport interface TextDisplayComponentData extends BaseComponentData {\n  content: string;\n}\n\nexport class TextDisplayComponent extends Component<APITextDisplayComponent> {\n  private constructor(data: APITextDisplayComponent);\n  public get content(): string;\n}\n\nexport type ForumThreadChannel = PublicThreadChannel<true>;\nexport type TextThreadChannel = PrivateThreadChannel | PublicThreadChannel<false>;\nexport type AnyThreadChannel = ForumThreadChannel | TextThreadChannel;\n\nexport interface PublicThreadChannel<Forum extends boolean = boolean> extends ThreadChannel<Forum> {\n  type: ChannelType.AnnouncementThread | ChannelType.PublicThread;\n}\n\nexport interface PrivateThreadChannel extends ThreadChannel<false> {\n  get createdAt(): Date;\n  get createdTimestamp(): number;\n  type: ChannelType.PrivateThread;\n}\n\nexport interface ThreadChannel<ThreadOnly extends boolean = boolean>\n  extends\n    TextBasedChannelFields<true>,\n    PinnableChannelFields,\n    BulkDeleteMethod,\n    SetRateLimitPerUserMethod,\n    MessageChannelFields,\n    SendMethod<true> {}\nexport class ThreadChannel<ThreadOnly extends boolean = boolean> extends BaseChannel {\n  private constructor(guild: Guild, data: RawThreadChannelData, client?: Client<true>);\n  public archived: boolean | null;\n  public get archivedAt(): Date | null;\n  public archiveTimestamp: number | null;\n  public get createdAt(): Date | null;\n  private readonly _createdTimestamp: number | null;\n  public get createdTimestamp(): number | null;\n  public autoArchiveDuration: ThreadAutoArchiveDuration | null;\n  public get editable(): boolean;\n  public flags: Readonly<ChannelFlagsBitField>;\n  public guild: Guild;\n  public guildId: Snowflake;\n  public get guildMembers(): Collection<Snowflake, GuildMember>;\n  public invitable: boolean | null;\n  public get joinable(): boolean;\n  public get joined(): boolean;\n  public locked: boolean | null;\n  public get manageable(): boolean;\n  public get viewable(): boolean;\n  public get sendable(): boolean;\n  public memberCount: number | null;\n  public messageCount: number | null;\n  public appliedTags: Snowflake[];\n  public totalMessageSent: number | null;\n  public members: ThreadMemberManager;\n  public name: string;\n  public ownerId: Snowflake;\n  public get parent(): If<ThreadOnly, ForumChannel | MediaChannel, AnnouncementChannel | TextChannel> | null;\n  public parentId: Snowflake | null;\n  public rateLimitPerUser: number | null;\n  public type: ThreadChannelType;\n  public get unarchivable(): boolean;\n  public delete(reason?: string): Promise<this>;\n  public edit(options: ThreadEditOptions): Promise<this>;\n  public join(): Promise<this>;\n  public leave(): Promise<this>;\n  public permissionsFor(memberOrRole: GuildMember | Role, checkAdmin?: boolean): Readonly<PermissionsBitField>;\n  public permissionsFor(\n    memberOrRole: RoleResolvable | UserResolvable,\n    checkAdmin?: boolean,\n  ): Readonly<PermissionsBitField> | null;\n  public fetchOwner(options?: FetchThreadOwnerOptions): Promise<ThreadMember>;\n  public fetchStarterMessage(options?: BaseFetchOptions): Promise<Message<true> | null>;\n  public setArchived(archived?: boolean, reason?: string): Promise<this>;\n  public setAutoArchiveDuration(autoArchiveDuration: ThreadAutoArchiveDuration, reason?: string): Promise<this>;\n  public setInvitable(invitable?: boolean, reason?: string): Promise<this>;\n  public setLocked(locked?: boolean, reason?: string): Promise<this>;\n  public setName(name: string, reason?: string): Promise<this>;\n  // The following 3 methods can only be run on forum threads.\n  public setAppliedTags(appliedTags: readonly Snowflake[], reason?: string): Promise<If<ThreadOnly, this, never>>;\n  public pin(reason?: string): Promise<If<ThreadOnly, this, never>>;\n  public unpin(reason?: string): Promise<If<ThreadOnly, this, never>>;\n  public toString(): ChannelMention;\n}\n\nexport class ThreadMember<HasMemberData extends boolean = boolean> extends Base {\n  private constructor(thread: ThreadChannel, data: APIThreadMember, extra?: unknown);\n  public flags: ThreadMemberFlagsBitField;\n  private readonly member: If<HasMemberData, GuildMember>;\n  public get guildMember(): HasMemberData extends true ? GuildMember : GuildMember | null;\n  public id: Snowflake;\n  public get joinedAt(): Date | null;\n  public joinedTimestamp: number | null;\n  public get manageable(): boolean;\n  public thread: AnyThreadChannel;\n  public get user(): User | null;\n  public get partial(): false;\n  public remove(): Promise<ThreadMember>;\n}\n\nexport type ThreadMemberFlagsString = keyof typeof ThreadMemberFlags;\n\nexport class ThreadMemberFlagsBitField extends BitField<ThreadMemberFlagsString> {\n  public static Flags: typeof ThreadMemberFlags;\n  public static resolve(bit?: BitFieldResolvable<ThreadMemberFlagsString, number>): number;\n}\n\nexport interface ThumbnailComponentData extends BaseComponentData {\n  description?: string;\n  media: UnfurledMediaItemData;\n  spoiler?: boolean;\n}\n\nexport class ThumbnailComponent extends Component<APIThumbnailComponent> {\n  private constructor(data: APIThumbnailComponent);\n  public readonly media: UnfurledMediaItem;\n  public get description(): string | null;\n  public get spoiler(): boolean;\n}\n\nexport class Typing extends Base {\n  private constructor(channel: TextBasedChannel, user: PartialUser, data?: GatewayTypingStartDispatchData);\n  public channel: TextBasedChannel;\n  public user: PartialUser | User;\n  public startedTimestamp: number;\n  public get startedAt(): Date;\n  public get guild(): Guild | null;\n  public get member(): GuildMember | null;\n  public inGuild(): this is this & {\n    channel: AnnouncementChannel | TextChannel | ThreadChannel;\n    get guild(): Guild;\n  };\n}\n\nexport interface AvatarDecorationData {\n  asset: string;\n  skuId: Snowflake;\n}\n\nexport interface Collectibles {\n  nameplate: NameplateData | null;\n}\n\nexport interface UserPrimaryGuild {\n  badge: string | null;\n  identityEnabled: boolean | null;\n  identityGuildId: Snowflake | null;\n  tag: string | null;\n}\n\nexport interface NameplateData {\n  asset: string;\n  label: string;\n  palette: NameplatePalette;\n  skuId: Snowflake;\n}\n\nexport interface UnfurledMediaItemData {\n  url: string;\n}\n\nexport class UnfurledMediaItem {\n  private constructor(data: APIUnfurledMediaItem);\n  public readonly data: APIUnfurledMediaItem;\n  public get url(): string;\n}\n\nexport interface User extends SendMethod<false> {}\nexport class User extends Base {\n  protected constructor(client: Client<true>, data: unknown);\n  private _equals(user: APIUser): boolean;\n\n  public accentColor: number | null | undefined;\n  public avatar: string | null;\n  public avatarDecorationData: AvatarDecorationData | null;\n  public banner: string | null | undefined;\n  public bot: boolean;\n  public get createdAt(): Date;\n  public get createdTimestamp(): number;\n  public collectibles: Collectibles | null;\n  public discriminator: string;\n  public get displayName(): string;\n  public get defaultAvatarURL(): string;\n  public get dmChannel(): DMChannel | null;\n  public flags: Readonly<UserFlagsBitField> | null;\n  public globalName: string | null;\n  public get hexAccentColor(): HexColorString | null | undefined;\n  public id: Snowflake;\n  public get partial(): false;\n  public primaryGuild: UserPrimaryGuild | null;\n  public system: boolean;\n  public get tag(): string;\n  public username: string;\n  public avatarURL(options?: ImageURLOptions): string | null;\n  public avatarDecorationURL(): string | null;\n  public bannerURL(options?: ImageURLOptions): string | null | undefined;\n  public guildTagBadgeURL(options?: ImageURLOptions): string | null;\n  public createDM(force?: boolean): Promise<DMChannel>;\n  public deleteDM(): Promise<DMChannel>;\n  public displayAvatarURL(options?: ImageURLOptions): string;\n  public equals(user: User): boolean;\n  public fetch(force?: boolean): Promise<User>;\n  public toString(): UserMention;\n}\n\nexport class UserContextMenuCommandInteraction<\n  Cached extends CacheType = CacheType,\n> extends ContextMenuCommandInteraction<Cached> {\n  public commandType: ApplicationCommandType.User;\n  public options: Omit<\n    CommandInteractionOptionResolver<Cached>,\n    | 'getAttachment'\n    | 'getBoolean'\n    | 'getChannel'\n    | 'getFocused'\n    | 'getInteger'\n    | 'getMentionable'\n    | 'getMessage'\n    | 'getNumber'\n    | 'getRole'\n    | 'getString'\n    | 'getSubcommand'\n    | 'getSubcommandGroup'\n  >;\n  public get targetUser(): User;\n  public get targetMember(): CacheTypeReducer<Cached, GuildMember, APIInteractionGuildMember> | null;\n  public inGuild(): this is UserContextMenuCommandInteraction<'cached' | 'raw'>;\n  public inCachedGuild(): this is UserContextMenuCommandInteraction<'cached'>;\n  public inRawGuild(): this is UserContextMenuCommandInteraction<'raw'>;\n}\n\nexport type UserFlagsString = keyof typeof UserFlags;\n\nexport class UserFlagsBitField extends BitField<UserFlagsString> {\n  public static Flags: typeof UserFlags;\n  public static resolve(bit?: BitFieldResolvable<UserFlagsString, number>): number;\n}\n\nexport function cleanCodeBlockContent(text: string): string;\nexport function cleanContent(str: string, channel: TextBasedChannel): string;\nexport function discordSort<Key, Value extends { id: Snowflake; rawPosition: number }>(\n  collection: ReadonlyCollection<Key, Value>,\n): Collection<Key, Value>;\nexport function fetchRecommendedShardCount(token: string, options?: FetchRecommendedShardCountOptions): Promise<number>;\nexport function flatten(obj: unknown, ...props: Record<string, boolean | string>[]): unknown;\n\nexport function parseEmoji(text: string): PartialEmoji | null;\nexport function parseWebhookURL(url: string): WebhookDataIdWithToken | null;\nexport function resolveColor(color: ColorResolvable): number;\nexport function resolveSKUId(resolvable: SKUResolvable): Snowflake | null;\nexport function verifyString(data: string, error?: typeof Error, errorMessage?: string, allowEmpty?: boolean): string;\n\nexport type ComponentData =\n  | ComponentInContainerData\n  | ComponentInLabelData\n  | ContainerComponentData\n  | LabelData\n  | MessageActionRowComponentData\n  | ThumbnailComponentData;\n\nexport interface SendSoundboardSoundOptions {\n  guildId?: Snowflake;\n  soundId: Snowflake;\n}\n\nexport class VoiceChannel extends BaseGuildVoiceChannel {\n  public get speakable(): boolean;\n  public type: ChannelType.GuildVoice;\n  public sendSoundboardSound(sound: SendSoundboardSoundOptions | SoundboardSound): Promise<void>;\n}\n\nexport class VoiceChannelEffect {\n  private constructor(data: GatewayVoiceChannelEffectSendDispatchData, guild: Guild);\n  public guild: Guild;\n  public channelId: Snowflake;\n  public userId: Snowflake;\n  public emoji: Emoji | null;\n  public animationType: VoiceChannelEffectSendAnimationType | null;\n  public animationId: number | null;\n  public soundId: Snowflake | number | null;\n  public soundVolume: number | null;\n  public get channel(): VoiceChannel | null;\n  public get soundboardSound(): GuildSoundboardSound | null;\n}\n\nexport class VoiceRegion {\n  private constructor(data: APIVoiceRegion);\n  public custom: boolean;\n  public deprecated: boolean;\n  public id: string;\n  public name: string;\n  public optimal: boolean;\n  public toJSON(): unknown;\n}\n\nexport class VoiceState extends Base {\n  private constructor(guild: Guild, data: unknown);\n  public get channel(): VoiceBasedChannel | null;\n  public channelId: Snowflake | null;\n  public get deaf(): boolean | null;\n  public guild: Guild;\n  public id: Snowflake;\n  public get member(): GuildMember | null;\n  public get mute(): boolean | null;\n  public selfDeaf: boolean | null;\n  public selfMute: boolean | null;\n  public serverDeaf: boolean | null;\n  public serverMute: boolean | null;\n  public sessionId: string | null;\n  public streaming: boolean | null;\n  public selfVideo: boolean | null;\n  public suppress: boolean | null;\n  public requestToSpeakTimestamp: number | null;\n\n  public setDeaf(deaf?: boolean, reason?: string): Promise<GuildMember>;\n  public setMute(mute?: boolean, reason?: string): Promise<GuildMember>;\n  public disconnect(reason?: string): Promise<GuildMember>;\n  public setChannel(channel: GuildVoiceChannelResolvable | null, reason?: string): Promise<GuildMember>;\n  public setRequestToSpeak(request?: boolean): Promise<this>;\n  public setSuppressed(suppressed?: boolean): Promise<this>;\n  public edit(options: VoiceStateEditOptions): Promise<this>;\n  public fetch(force?: boolean): Promise<VoiceState>;\n}\n\nexport interface Webhook<Type extends WebhookType = WebhookType> extends WebhookFields {}\nexport class Webhook<Type extends WebhookType = WebhookType> {\n  private constructor(client: Client<true>, data: unknown);\n  public avatar: string | null;\n  public avatarURL(options?: ImageURLOptions): string | null;\n  public channelId: Snowflake;\n  public readonly client: Client;\n  public guildId: Snowflake;\n  public name: string;\n  public owner: Type extends WebhookType.Incoming ? User | null : User;\n  public sourceGuild: Type extends WebhookType.ChannelFollower ? APIPartialGuild | Guild : null;\n  public sourceChannel: Type extends WebhookType.ChannelFollower ? AnnouncementChannel | APIPartialChannel : null;\n  public token: Type extends WebhookType.Incoming\n    ? string\n    : Type extends WebhookType.ChannelFollower\n      ? null\n      : string | null;\n  public type: Type;\n  public applicationId: Type extends WebhookType.Application ? Snowflake : null;\n  public get channel():\n    | AnnouncementChannel\n    | ForumChannel\n    | MediaChannel\n    | StageChannel\n    | TextChannel\n    | VoiceChannel\n    | null;\n  public isUserCreated(): this is Webhook<WebhookType.Incoming> & {\n    owner: User;\n  };\n  public isApplicationCreated(): this is Webhook<WebhookType.Application>;\n  public isIncoming(): this is Webhook<WebhookType.Incoming>;\n  public isChannelFollower(): this is Webhook<WebhookType.ChannelFollower>;\n\n  public editMessage(\n    message: MessageResolvable,\n    options: MessagePayload | WebhookMessageEditOptions | string,\n  ): Promise<Message<true>>;\n  public fetchMessage(message: Snowflake, options?: WebhookFetchMessageOptions): Promise<Message<true>>;\n  public send(options: MessagePayload | WebhookMessageCreateOptions | string): Promise<Message<true>>;\n}\n\nexport class Widget extends Base {\n  private constructor(client: Client<true>, data: APIGuildWidget);\n  private _patch(data: APIGuildWidget): void;\n  public fetch(): Promise<Widget>;\n  public imageURL(style?: GuildWidgetStyle): string;\n  public id: Snowflake;\n  public name: string;\n  public instantInvite?: string;\n  public channels: Collection<Snowflake, WidgetChannel>;\n  public members: Collection<string, WidgetMember>;\n  public presenceCount: number;\n}\n\nexport class WidgetMember extends Base {\n  private constructor(client: Client<true>, data: APIGuildWidgetMember);\n  public id: string;\n  public username: string;\n  public discriminator: string;\n  public avatar: string | null;\n  public status: PresenceStatus;\n  public deaf: boolean | null;\n  public mute: boolean | null;\n  public selfDeaf: boolean | null;\n  public selfMute: boolean | null;\n  public suppress: boolean | null;\n  public channelId: Snowflake | null;\n  public avatarURL: string;\n  public activity: WidgetActivity | null;\n}\n\nexport type SoundboardSoundResolvable = Snowflake | SoundboardSound | string;\n\nexport class SoundboardSound extends Base {\n  private constructor(client: Client<true>, data: APISoundboardSound);\n  public name: string;\n  public soundId: Snowflake | string;\n  public volume: number;\n  private readonly _emoji: Omit<APIEmoji, 'animated'> | null;\n  public guildId: Snowflake | null;\n  public available: boolean;\n  public user: User | null;\n  public get createdAt(): Date;\n  public get createdTimestamp(): number;\n  public get emoji(): Emoji | null;\n  public get guild(): Guild | null;\n  public get url(): string;\n  public edit(options?: GuildSoundboardSoundEditOptions): Promise<GuildSoundboardSound>;\n  public delete(reason?: string): Promise<GuildSoundboardSound>;\n  public equals(other: APISoundboardSound | SoundboardSound): boolean;\n}\n\nexport type DefaultSoundboardSound = SoundboardSound & { get guild(): null; guildId: null; soundId: string };\nexport type GuildSoundboardSound = SoundboardSound & { get guild(): Guild; guildId: Snowflake; soundId: Snowflake };\n\nexport class WelcomeChannel extends Base {\n  private constructor(guild: Guild, data: APIGuildWelcomeScreenChannel);\n  private readonly _emoji: Omit<APIEmoji, 'animated'>;\n  public channelId: Snowflake;\n  public guild: Guild | InviteGuild;\n  public description: string;\n  public get channel(): AnnouncementChannel | ForumChannel | MediaChannel | TextChannel | null;\n  public get emoji(): Emoji | GuildEmoji;\n}\n\nexport class WelcomeScreen extends Base {\n  private constructor(guild: Guild, data: APIGuildWelcomeScreen);\n  public get enabled(): boolean;\n  public guild: Guild | InviteGuild;\n  public description: string | null;\n  public welcomeChannels: Collection<Snowflake, WelcomeChannel>;\n}\n\n// #endregion\n\n// #region Constants\n\nexport type NonSystemMessageType =\n  | MessageType.ChatInputCommand\n  | MessageType.ContextMenuCommand\n  | MessageType.Default\n  | MessageType.Reply;\n\nexport type UndeletableMessageType =\n  | MessageType.Call\n  | MessageType.ChannelIconChange\n  | MessageType.ChannelNameChange\n  | MessageType.RecipientAdd\n  | MessageType.RecipientRemove\n  | MessageType.ThreadStarterMessage;\n\nexport const Constants: {\n  GuildTextBasedChannelTypes: GuildTextBasedChannelTypes[];\n  HolographicStyle: {\n    Primary: 11_127_295;\n    Secondary: 16_759_788;\n    Tertiary: 16_761_760;\n  };\n  MaxBulkDeletableMessageAge: 1_209_600_000;\n  NonSystemMessageTypes: NonSystemMessageType[];\n  SelectMenuTypes: SelectMenuType[];\n  SendableChannels: SendableChannelTypes[];\n  StickerFormatExtensionMap: Record<StickerFormatType, ImageFormat>;\n  SweeperKeys: SweeperKey[];\n  TextBasedChannelTypes: TextBasedChannelTypes[];\n  ThreadChannelTypes: ThreadChannelType[];\n  UndeletableMessageTypes: UndeletableMessageType[];\n  VoiceBasedChannelTypes: VoiceBasedChannelTypes[];\n};\n\nexport const version: string;\n\n// #endregion\n\n// #region Errors\n/* eslint-disable typescript-sort-keys/string-enum */\nexport enum DiscordjsErrorCodes {\n  ClientInvalidOption = 'ClientInvalidOption',\n  ClientInvalidProvidedShards = 'ClientInvalidProvidedShards',\n  ClientMissingIntents = 'ClientMissingIntents',\n  ClientNotReady = 'ClientNotReady',\n\n  TokenInvalid = 'TokenInvalid',\n  TokenMissing = 'TokenMissing',\n  ApplicationCommandPermissionsTokenMissing = 'ApplicationCommandPermissionsTokenMissing',\n\n  BitFieldInvalid = 'BitFieldInvalid',\n\n  ShardingNoShards = 'ShardingNoShards',\n  ShardingInProcess = 'ShardingInProcess',\n  ShardingInvalidEvalBroadcast = 'ShardingInvalidEvalBroadcast',\n  ShardingShardNotFound = 'ShardingShardNotFound',\n  ShardingAlreadySpawned = 'ShardingAlreadySpawned',\n  ShardingProcessExists = 'ShardingProcessExists',\n  ShardingWorkerExists = 'ShardingWorkerExists',\n  ShardingReadyTimeout = 'ShardingReadyTimeout',\n  ShardingReadyDisconnected = 'ShardingReadyDisconnected',\n  ShardingReadyDied = 'ShardingReadyDied',\n  ShardingNoChildExists = 'ShardingNoChildExists',\n  ShardingShardMiscalculation = 'ShardingShardMiscalculation',\n\n  ColorRange = 'ColorRange',\n  ColorConvert = 'ColorConvert',\n\n  InviteOptionsMissingChannel = 'InviteOptionsMissingChannel',\n\n  InteractionCollectorError = 'InteractionCollectorError',\n\n  FileNotFound = 'FileNotFound',\n\n  UserNoDMChannel = 'UserNoDMChannel',\n\n  VoiceNotStageChannel = 'VoiceNotStageChannel',\n\n  VoiceStateNotOwn = 'VoiceStateNotOwn',\n  VoiceStateInvalidType = 'VoiceStateInvalidType',\n\n  ReqResourceType = 'ReqResourceType',\n\n  MessageBulkDeleteType = 'MessageBulkDeleteType',\n  MessageContentType = 'MessageContentType',\n  MessageNonceRequired = 'MessageNonceRequired',\n  MessageNonceType = 'MessageNonceType',\n\n  BanResolveId = 'BanResolveId',\n  FetchBanResolveId = 'FetchBanResolveId',\n\n  PruneDaysType = 'PruneDaysType',\n\n  GuildChannelResolve = 'GuildChannelResolve',\n  GuildVoiceChannelResolve = 'GuildVoiceChannelResolve',\n  GuildChannelOrphan = 'GuildChannelOrphan',\n  GuildChannelUnowned = 'GuildChannelUnowned',\n  GuildMembersTimeout = 'GuildMembersTimeout',\n  GuildSoundboardSoundsTimeout = 'GuildSoundboardSoundsTimeout',\n  GuildUncachedMe = 'GuildUncachedMe',\n  ChannelNotCached = 'ChannelNotCached',\n  StageChannelResolve = 'StageChannelResolve',\n  GuildScheduledEventResolve = 'GuildScheduledEventResolve',\n  FetchOwnerId = 'FetchOwnerId',\n\n  InvalidType = 'InvalidType',\n  InvalidElement = 'InvalidElement',\n\n  MessageThreadParent = 'MessageThreadParent',\n  MessageExistingThread = 'MessageExistingThread',\n  ThreadInvitableType = 'ThreadInvitableType',\n\n  WebhookMessage = 'WebhookMessage',\n  WebhookTokenUnavailable = 'WebhookTokenUnavailable',\n  WebhookApplication = 'WebhookApplication',\n\n  MessageReferenceMissing = 'MessageReferenceMissing',\n\n  EmojiType = 'EmojiType',\n  EmojiManaged = 'EmojiManaged',\n  MissingGuildExpressionsPermission = 'MissingGuildExpressionsPermission',\n\n  NotGuildSoundboardSound = 'NotGuildSoundboardSound',\n  NotGuildSticker = 'NotGuildSticker',\n\n  ReactionResolveUser = 'ReactionResolveUser',\n\n  InviteResolveCode = 'InviteResolveCode',\n  InviteNotFound = 'InviteNotFound',\n\n  DeleteGroupDMChannel = 'DeleteGroupDMChannel',\n  FetchGroupDMChannel = 'FetchGroupDMChannel',\n\n  MemberFetchNonceLength = 'MemberFetchNonceLength',\n\n  GlobalCommandPermissions = 'GlobalCommandPermissions',\n  GuildUncachedEntityResolve = 'GuildUncachedEntityResolve',\n\n  InteractionAlreadyReplied = 'InteractionAlreadyReplied',\n  InteractionNotReplied = 'InteractionNotReplied',\n\n  CommandInteractionOptionNotFound = 'CommandInteractionOptionNotFound',\n  CommandInteractionOptionType = 'CommandInteractionOptionType',\n  CommandInteractionOptionEmpty = 'CommandInteractionOptionEmpty',\n  CommandInteractionOptionNoSubcommand = 'CommandInteractionOptionNoSubcommand',\n  CommandInteractionOptionNoSubcommandGroup = 'CommandInteractionOptionNoSubcommandGroup',\n  AutocompleteInteractionOptionNoFocusedOption = 'AutocompleteInteractionOptionNoFocusedOption',\n\n  ModalSubmitInteractionComponentNotFound = 'ModalSubmitInteractionComponentNotFound',\n  ModalSubmitInteractionComponentType = 'ModalSubmitInteractionComponentType',\n  ModalSubmitInteractionComponentEmpty = 'ModalSubmitInteractionComponentEmpty',\n  ModalSubmitInteractionComponentInvalidChannelType = 'ModalSubmitInteractionComponentInvalidChannelType',\n\n  InvalidMissingScopes = 'InvalidMissingScopes',\n  InvalidScopesWithPermissions = 'InvalidScopesWithPermissions',\n\n  NotImplemented = 'NotImplemented',\n\n  SweepFilterReturn = 'SweepFilterReturn',\n\n  GuildForumMessageRequired = 'GuildForumMessageRequired',\n\n  EntitlementCreateInvalidOwner = 'EntitlementCreateInvalidOwner',\n\n  BulkBanUsersOptionEmpty = 'BulkBanUsersOptionEmpty',\n\n  PollAlreadyExpired = 'PollAlreadyExpired',\n\n  PermissionOverwritesTypeMandatory = 'PermissionOverwritesTypeMandatory',\n  PermissionOverwritesTypeMismatch = 'PermissionOverwritesTypeMismatch',\n}\n/* eslint-enable typescript-sort-keys/string-enum */\n\nexport class DiscordjsError extends Error {\n  private constructor(code: DiscordjsErrorCodes, ...args: unknown[]);\n  public readonly code: DiscordjsErrorCodes;\n  public get name(): `Error [${DiscordjsErrorCodes}]`;\n}\n\nexport class DiscordjsTypeError extends TypeError {\n  private constructor(code: DiscordjsErrorCodes, ...args: unknown[]);\n  public readonly code: DiscordjsErrorCodes;\n  public get name(): `TypeError [${DiscordjsErrorCodes}]`;\n}\n\nexport class DiscordjsRangeError extends RangeError {\n  private constructor(code: DiscordjsErrorCodes, ...args: unknown[]);\n  public readonly code: DiscordjsErrorCodes;\n  public get name(): `RangeError [${DiscordjsErrorCodes}]`;\n}\n\n// #endregion\n\n// #region Managers\n\nexport abstract class BaseManager {\n  protected constructor(client: Client);\n  public readonly client: Client;\n}\n\nexport abstract class DataManager<Key, Holds, Resolvable> extends BaseManager {\n  protected constructor(client: Client<true>, holds: Constructable<Holds>);\n  public readonly holds: Constructable<Holds>;\n  public get cache(): Collection<Key, Holds>;\n  public resolve(resolvable: Holds): Holds;\n  public resolve(resolvable: Resolvable): Holds | null;\n  public resolveId(resolvable: Holds | Key): Key;\n  public resolveId(resolvable: Resolvable): Key | null;\n  public valueOf(): Collection<Key, Holds>;\n}\n\nexport abstract class CachedManager<Key, Holds, Resolvable> extends DataManager<Key, Holds, Resolvable> {\n  protected constructor(client: Client<true>, holds: Constructable<Holds>, iterable?: Iterable<Holds>);\n  private readonly _cache: Collection<Key, Holds>;\n  private _add(data: unknown, cache?: boolean, { id, extras }?: { extras: unknown[]; id: Key }): Holds;\n}\n\nexport type ApplicationCommandDataResolvable =\n  | ApplicationCommandData\n  | JSONEncodable<RESTPostAPIApplicationCommandsJSONBody>\n  | RESTPostAPIApplicationCommandsJSONBody;\n\nexport class ApplicationCommandManager<\n  ApplicationCommandScope = ApplicationCommand<{ guild: GuildResolvable }>,\n  PermissionsOptionsExtras = { guild: GuildResolvable },\n  PermissionsGuildType = null,\n> extends CachedManager<Snowflake, ApplicationCommandScope, ApplicationCommandResolvable> {\n  protected constructor(client: Client<true>, iterable?: Iterable<unknown>);\n  public permissions: ApplicationCommandPermissionsManager<\n    PermissionsOptionsExtras & { command?: ApplicationCommandResolvable },\n    PermissionsOptionsExtras & { command: ApplicationCommandResolvable },\n    PermissionsGuildType,\n    null\n  >;\n  private commandPath({ id, guildId }: { guildId?: Snowflake; id?: Snowflake }): string;\n  public create(command: ApplicationCommandDataResolvable, guildId?: Snowflake): Promise<ApplicationCommandScope>;\n  public delete(command: ApplicationCommandResolvable, guildId?: Snowflake): Promise<ApplicationCommandScope | null>;\n  public edit(\n    command: ApplicationCommandResolvable,\n    data: Partial<ApplicationCommandDataResolvable>,\n  ): Promise<ApplicationCommandScope>;\n  public edit(\n    command: ApplicationCommandResolvable,\n    data: Partial<ApplicationCommandDataResolvable>,\n    guildId: Snowflake,\n  ): Promise<ApplicationCommand>;\n  public fetch(\n    options: Snowflake | (FetchGuildApplicationCommandFetchOptions & { id: Snowflake }),\n  ): Promise<ApplicationCommandScope>;\n  public fetch(\n    options: FetchApplicationCommandOptions & { guildId: Snowflake; id: Snowflake },\n  ): Promise<ApplicationCommand>;\n  public fetch(\n    options?: Omit<FetchApplicationCommandOptions, 'id'>,\n  ): Promise<Collection<Snowflake, ApplicationCommandScope>>;\n  public set(\n    commands: readonly ApplicationCommandDataResolvable[],\n  ): Promise<Collection<Snowflake, ApplicationCommandScope>>;\n  public set(\n    commands: readonly ApplicationCommandDataResolvable[],\n    guildId: Snowflake,\n  ): Promise<Collection<Snowflake, ApplicationCommand>>;\n  private static transformCommand(command: ApplicationCommandDataResolvable): RESTPostAPIApplicationCommandsJSONBody;\n}\n\nexport class ApplicationCommandPermissionsManager<\n  BaseOptions,\n  FetchSingleOptions,\n  GuildType,\n  CommandIdType,\n> extends BaseManager {\n  private constructor(manager: ApplicationCommand | ApplicationCommandManager | GuildApplicationCommandManager);\n  private readonly manager: ApplicationCommand | ApplicationCommandManager | GuildApplicationCommandManager;\n\n  public commandId: CommandIdType;\n  public guild: GuildType;\n  public guildId: Snowflake | null;\n  public add(\n    options: EditApplicationCommandPermissionsMixin & FetchSingleOptions,\n  ): Promise<ApplicationCommandPermissions[]>;\n  public has(\n    options: FetchSingleOptions & {\n      permissionId: ApplicationCommandPermissionIdResolvable;\n      permissionType?: ApplicationCommandPermissionType;\n    },\n  ): Promise<boolean>;\n  public fetch(options: FetchSingleOptions): Promise<ApplicationCommandPermissions[]>;\n  public fetch(options: BaseOptions): Promise<Collection<Snowflake, ApplicationCommandPermissions[]>>;\n  public remove(\n    options:\n      | (FetchSingleOptions & {\n          channels: readonly (ChannelPermissionConstant | GuildChannelResolvable)[];\n          roles?: readonly (RolePermissionConstant | RoleResolvable)[];\n          token: string;\n          users?: readonly UserResolvable[];\n        })\n      | (FetchSingleOptions & {\n          channels?: readonly (ChannelPermissionConstant | GuildChannelResolvable)[];\n          roles: readonly (RolePermissionConstant | RoleResolvable)[];\n          token: string;\n          users?: readonly UserResolvable[];\n        })\n      | (FetchSingleOptions & {\n          channels?: readonly (ChannelPermissionConstant | GuildChannelResolvable)[];\n          roles?: readonly (RolePermissionConstant | RoleResolvable)[];\n          token: string;\n          users: readonly UserResolvable[];\n        }),\n  ): Promise<ApplicationCommandPermissions[]>;\n  public set(\n    options: EditApplicationCommandPermissionsMixin & FetchSingleOptions,\n  ): Promise<ApplicationCommandPermissions[]>;\n  private permissionsPath(guildId: Snowflake, commandId?: Snowflake): string;\n}\n\nexport class AutoModerationRuleManager extends CachedManager<\n  Snowflake,\n  AutoModerationRule,\n  AutoModerationRuleResolvable\n> {\n  private constructor(guild: Guild, iterable: unknown);\n  public guild: Guild;\n  public create(options: AutoModerationRuleCreateOptions): Promise<AutoModerationRule>;\n  public edit(\n    autoModerationRule: AutoModerationRuleResolvable,\n    options: AutoModerationRuleEditOptions,\n  ): Promise<AutoModerationRule>;\n  public fetch(options: AutoModerationRuleResolvable | FetchAutoModerationRuleOptions): Promise<AutoModerationRule>;\n  public fetch(options?: FetchAutoModerationRulesOptions): Promise<Collection<Snowflake, AutoModerationRule>>;\n  public delete(autoModerationRule: AutoModerationRuleResolvable, reason?: string): Promise<void>;\n}\n\nexport class CategoryChannelChildManager extends DataManager<Snowflake, CategoryChildChannel, GuildChannelResolvable> {\n  private constructor(channel: CategoryChannel);\n\n  public channel: CategoryChannel;\n  public get guild(): Guild;\n  public create<Type extends CategoryChannelChildTypes>(\n    options: CategoryCreateChannelOptions & { type: Type },\n  ): Promise<MappedChannelCategoryTypes[Type]>;\n  public create(options: CategoryCreateChannelOptions): Promise<TextChannel>;\n}\n\nexport class ChannelManager extends CachedManager<Snowflake, Channel, ChannelResolvable> {\n  private constructor(client: Client<true>, iterable: Iterable<RawChannelData>);\n  public createMessage(\n    channel: Exclude<TextBasedChannelResolvable, PartialGroupDMChannel>,\n    options:\n      | FileBodyEncodable<RESTPostAPIChannelMessageJSONBody>\n      | JSONEncodable<RESTPostAPIChannelMessageJSONBody>\n      | MessageCreateOptions\n      | MessagePayload\n      | string,\n  ): Promise<OmitPartialGroupDMChannel<Message>>;\n  public fetch(id: Snowflake, options?: FetchChannelOptions): Promise<Channel | null>;\n}\n\nexport type EntitlementResolvable = Entitlement | Snowflake;\nexport type SKUResolvable = SKU | Snowflake;\nexport type SubscriptionResolvable = Snowflake | Subscription;\n\nexport interface GuildEntitlementCreateOptions {\n  guild: GuildResolvable;\n  sku: SKUResolvable;\n}\n\nexport interface UserEntitlementCreateOptions {\n  sku: SKUResolvable;\n  user: UserResolvable;\n}\n\nexport interface FetchEntitlementOptions extends BaseFetchOptions {\n  entitlement: EntitlementResolvable;\n}\n\nexport interface FetchEntitlementsOptions {\n  after?: Snowflake;\n  before?: Snowflake;\n  cache?: boolean;\n  excludeDeleted?: boolean;\n  excludeEnded?: boolean;\n  guild?: GuildResolvable;\n  limit?: number;\n  skus?: readonly SKUResolvable[];\n  user?: UserResolvable;\n}\n\nexport class EntitlementManager extends CachedManager<Snowflake, Entitlement, EntitlementResolvable> {\n  private constructor(client: Client<true>, iterable: Iterable<APIEntitlement>);\n  public fetch(options: EntitlementResolvable | FetchEntitlementOptions): Promise<Entitlement>;\n  public fetch(options?: FetchEntitlementsOptions): Promise<Collection<Snowflake, Entitlement>>;\n  public createTest(options: GuildEntitlementCreateOptions | UserEntitlementCreateOptions): Promise<Entitlement>;\n  public deleteTest(entitlement: EntitlementResolvable): Promise<void>;\n  public consume(entitlementId: Snowflake): Promise<void>;\n}\n\nexport interface FetchSubscriptionOptions extends BaseFetchOptions {\n  sku: SKUResolvable;\n  subscriptionId: Snowflake;\n}\n\nexport interface FetchSubscriptionsOptions {\n  after?: Snowflake;\n  before?: Snowflake;\n  limit?: number;\n  sku: SKUResolvable;\n  user: UserResolvable;\n}\n\nexport class SubscriptionManager extends CachedManager<Snowflake, Subscription, SubscriptionResolvable> {\n  private constructor(client: Client<true>, iterable?: Iterable<APISubscription>);\n  public fetch(options: FetchSubscriptionOptions): Promise<Subscription>;\n  public fetch(options: FetchSubscriptionsOptions): Promise<Collection<Snowflake, Subscription>>;\n}\n\nexport interface FetchGuildApplicationCommandFetchOptions extends BaseFetchOptions {\n  id?: Snowflake;\n  locale?: Locale;\n  withLocalizations?: boolean;\n}\n\nexport class GuildApplicationCommandManager extends ApplicationCommandManager<ApplicationCommand, {}, Guild> {\n  private constructor(guild: Guild, iterable?: Iterable<APIApplicationCommand>);\n  public guild: Guild;\n  public create(command: ApplicationCommandDataResolvable): Promise<ApplicationCommand>;\n  public delete(command: ApplicationCommandResolvable): Promise<ApplicationCommand | null>;\n  public edit(\n    command: ApplicationCommandResolvable,\n    data: Partial<ApplicationCommandDataResolvable>,\n  ): Promise<ApplicationCommand>;\n  public fetch(\n    options: Snowflake | (FetchGuildApplicationCommandFetchOptions & { id: Snowflake }),\n  ): Promise<ApplicationCommand>;\n  public fetch(\n    options?: Omit<FetchGuildApplicationCommandFetchOptions, 'id'>,\n  ): Promise<Collection<Snowflake, ApplicationCommand>>;\n  public set(commands: readonly ApplicationCommandDataResolvable[]): Promise<Collection<Snowflake, ApplicationCommand>>;\n}\n\nexport interface FollowedChannelData {\n  channelId: Snowflake;\n  webhookId: Snowflake;\n}\n\nexport type MappedGuildChannelTypes = MappedChannelCategoryTypes & {\n  [ChannelType.GuildCategory]: CategoryChannel;\n};\n\nexport type GuildChannelTypes = CategoryChannelChildTypes | ChannelType.GuildCategory;\n\nexport class GuildChannelManager extends CachedManager<Snowflake, GuildBasedChannel, GuildChannelResolvable> {\n  private constructor(guild: Guild, iterable?: Iterable<RawGuildChannelData>);\n  public get channelCountWithoutThreads(): number;\n  public guild: Guild;\n\n  public addFollower(\n    channel: AnnouncementChannelResolvable,\n    targetChannel: TextChannelResolvable,\n    reason?: string,\n  ): Promise<FollowedChannelData>;\n  public create<Type extends GuildChannelTypes>(\n    options: GuildChannelCreateOptions & { type: Type },\n  ): Promise<MappedGuildChannelTypes[Type]>;\n  public create(options: GuildChannelCreateOptions): Promise<TextChannel>;\n  public createWebhook(options: WebhookCreateOptions): Promise<Webhook<WebhookType.Incoming>>;\n  public edit(channel: GuildChannelResolvable, data: GuildChannelEditOptions): Promise<GuildChannel>;\n  public fetch(id: Snowflake, options?: BaseFetchOptions): Promise<GuildBasedChannel | null>;\n  public fetch(\n    id?: undefined,\n    options?: BaseFetchOptions,\n  ): Promise<Collection<Snowflake, NonThreadGuildBasedChannel | null>>;\n  public fetchWebhooks(\n    channel: GuildChannelResolvable,\n  ): Promise<Collection<Snowflake, Webhook<WebhookType.ChannelFollower | WebhookType.Incoming>>>;\n  public setPosition(\n    channel: GuildChannelResolvable,\n    position: number,\n    options?: SetChannelPositionOptions,\n  ): Promise<GuildChannel>;\n  public setPositions(channelPositions: readonly ChannelPosition[]): Promise<Guild>;\n  public fetchActiveThreads(cache?: boolean): Promise<FetchedThreads>;\n  private rawFetchGuildActiveThreads(): Promise<RESTGetAPIGuildThreadsResult>;\n  public delete(channel: GuildChannelResolvable, reason?: string): Promise<void>;\n}\n\nexport class GuildEmojiManager extends CachedManager<Snowflake, GuildEmoji, EmojiResolvable> {\n  private constructor(guild: Guild, iterable?: Iterable<APIEmoji>);\n  public guild: Guild;\n  public create(options: GuildEmojiCreateOptions): Promise<GuildEmoji>;\n  public fetch(id: Snowflake, options?: BaseFetchOptions): Promise<GuildEmoji>;\n  public fetch(id?: undefined, options?: BaseFetchOptions): Promise<Collection<Snowflake, GuildEmoji>>;\n  public fetchAuthor(emoji: EmojiResolvable): Promise<User>;\n  public delete(emoji: EmojiResolvable, reason?: string): Promise<void>;\n  public edit(emoji: EmojiResolvable, options: GuildEmojiEditOptions): Promise<GuildEmoji>;\n  public resolveIdentifier(emoji: EmojiIdentifierResolvable): string | null;\n}\n\nexport class GuildEmojiRoleManager extends DataManager<Snowflake, Role, RoleResolvable> {\n  private constructor(emoji: GuildEmoji);\n  public emoji: GuildEmoji;\n  public guild: Guild;\n  public add(\n    roleOrRoles: ReadonlyCollection<Snowflake, Role> | RoleResolvable | readonly RoleResolvable[],\n  ): Promise<GuildEmoji>;\n  public set(roles: ReadonlyCollection<Snowflake, Role> | readonly RoleResolvable[]): Promise<GuildEmoji>;\n  public remove(\n    roleOrRoles: ReadonlyCollection<Snowflake, Role> | RoleResolvable | readonly RoleResolvable[],\n  ): Promise<GuildEmoji>;\n}\n\nexport interface FetchSoundboardSoundsOptions {\n  guildIds: readonly Snowflake[];\n  time?: number;\n}\n\nexport class GuildManager extends CachedManager<Snowflake, Guild, GuildResolvable> {\n  private constructor(client: Client<true>, iterable?: Iterable<APIGuild | APIUnavailableGuild>);\n  public fetch(options: FetchGuildOptions | Snowflake): Promise<Guild>;\n  public fetch(options?: FetchGuildsOptions): Promise<Collection<Snowflake, OAuth2Guild>>;\n  public fetchSoundboardSounds(\n    options: FetchSoundboardSoundsOptions,\n  ): Promise<Collection<Snowflake, Collection<Snowflake, GuildSoundboardSound>>>;\n  public setIncidentActions(\n    guild: GuildResolvable,\n    incidentActions: IncidentActionsEditOptions,\n  ): Promise<IncidentActions>;\n  public widgetImageURL(guild: GuildResolvable, style?: GuildWidgetStyle): string;\n}\n\nexport interface AddOrRemoveGuildMemberRoleOptions {\n  reason?: string;\n  role: RoleResolvable;\n  user: UserResolvable;\n}\n\nexport class GuildMemberManager extends CachedManager<Snowflake, GuildMember, UserResolvable> {\n  private constructor(guild: Guild, iterable?: Iterable<unknown>);\n  public guild: Guild;\n  public get me(): GuildMember | null;\n  public add(\n    user: UserResolvable,\n    options: AddGuildMemberOptions & { fetchWhenExisting: false },\n  ): Promise<GuildMember | null>;\n  public add(user: UserResolvable, options: AddGuildMemberOptions): Promise<GuildMember>;\n  public ban(user: UserResolvable, options?: BanOptions): Promise<void>;\n  public bulkBan(\n    users: ReadonlyCollection<Snowflake, UserResolvable> | readonly UserResolvable[],\n    options?: BanOptions,\n  ): Promise<BulkBanResult>;\n  public edit(user: UserResolvable, options: GuildMemberEditOptions): Promise<GuildMember>;\n  public editMe(options: GuildMemberEditMeOptions): Promise<GuildMember>;\n  public fetch(\n    options: FetchMemberOptions | UserResolvable | (FetchMembersOptions & { user: UserResolvable }),\n  ): Promise<GuildMember>;\n  public fetch(options?: FetchMembersOptions): Promise<Collection<Snowflake, GuildMember>>;\n  public fetchMe(options?: BaseFetchOptions): Promise<GuildMember>;\n  public kick(user: UserResolvable, reason?: string): Promise<void>;\n  public list(options?: GuildListMembersOptions): Promise<Collection<Snowflake, GuildMember>>;\n  public prune(options: GuildPruneMembersOptions & { count: false; dry?: false }): Promise<null>;\n  public prune(options?: GuildPruneMembersOptions): Promise<number>;\n  public search(options: GuildSearchMembersOptions): Promise<Collection<Snowflake, GuildMember>>;\n  public unban(user: UserResolvable, reason?: string): Promise<void>;\n  public addRole(options: AddOrRemoveGuildMemberRoleOptions): Promise<void>;\n  public removeRole(options: AddOrRemoveGuildMemberRoleOptions): Promise<void>;\n}\n\nexport class GuildBanManager extends CachedManager<Snowflake, GuildBan, GuildBanResolvable> {\n  private constructor(guild: Guild, iterable?: Iterable<unknown>);\n  public guild: Guild;\n  public create(user: UserResolvable, options?: BanOptions): Promise<void>;\n  public fetch(options: FetchBanOptions | UserResolvable): Promise<GuildBan>;\n  public fetch(options?: FetchBansOptions): Promise<Collection<Snowflake, GuildBan>>;\n  public remove(user: UserResolvable, reason?: string): Promise<void>;\n  public bulkCreate(\n    users: ReadonlyCollection<Snowflake, UserResolvable> | readonly UserResolvable[],\n    options?: BanOptions,\n  ): Promise<BulkBanResult>;\n}\n\nexport class GuildInviteManager extends DataManager<string, GuildInvite, GuildInviteResolvable> {\n  private constructor(guild: Guild, iterable?: Iterable<unknown>);\n  public guild: Guild;\n  public create(channel: GuildInvitableChannelResolvable, options?: InviteCreateOptions): Promise<GuildInvite>;\n  public fetch(options: FetchInviteOptions | InviteResolvable): Promise<GuildInvite>;\n  public fetch(options?: FetchInvitesOptions): Promise<Collection<string, GuildInvite>>;\n  public delete(invite: InviteResolvable, reason?: string): Promise<void>;\n}\n\nexport class GuildScheduledEventManager extends CachedManager<\n  Snowflake,\n  GuildScheduledEvent,\n  GuildScheduledEventResolvable\n> {\n  private constructor(guild: Guild, iterable?: Iterable<APIGuildScheduledEvent>);\n  public guild: Guild;\n  public create(options: GuildScheduledEventCreateOptions): Promise<GuildScheduledEvent>;\n  public fetch(): Promise<Collection<Snowflake, GuildScheduledEvent>>;\n  public fetch<\n    Options extends FetchGuildScheduledEventOptions | FetchGuildScheduledEventsOptions | GuildScheduledEventResolvable,\n  >(options?: Options): Promise<GuildScheduledEventManagerFetchResult<Options>>;\n  public edit<\n    Status extends GuildScheduledEventStatus,\n    AcceptableStatus extends GuildScheduledEventSetStatusArg<Status>,\n  >(\n    guildScheduledEvent: GuildScheduledEventResolvable,\n    options: GuildScheduledEventEditOptions<Status, AcceptableStatus>,\n  ): Promise<GuildScheduledEvent<AcceptableStatus>>;\n  public delete(guildScheduledEvent: GuildScheduledEventResolvable): Promise<void>;\n  public fetchSubscribers<Options extends FetchGuildScheduledEventSubscribersOptions>(\n    guildScheduledEvent: GuildScheduledEventResolvable,\n    options?: Options,\n  ): Promise<GuildScheduledEventManagerFetchSubscribersResult<Options>>;\n}\n\nexport interface GuildSoundboardSoundCreateOptions {\n  contentType?: string;\n  emojiId?: Snowflake;\n  emojiName?: string;\n  file: BufferResolvable | Stream;\n  name: string;\n  reason?: string;\n  volume?: number;\n}\n\nexport interface GuildSoundboardSoundEditOptions {\n  emojiId?: Snowflake | null;\n  emojiName?: string | null;\n  name?: string;\n  reason?: string;\n  volume?: number | null;\n}\n\nexport interface FetchGuildSoundboardSoundOptions extends BaseFetchOptions {\n  soundboardSound: SoundboardSoundResolvable;\n}\n\nexport interface FetchGuildSoundboardSoundsOptions {\n  cache?: boolean;\n}\n\nexport class GuildSoundboardSoundManager extends CachedManager<Snowflake, SoundboardSound, SoundboardSoundResolvable> {\n  private constructor(guild: Guild, iterable?: Iterable<APISoundboardSound>);\n  public guild: Guild;\n  public create(options: GuildSoundboardSoundCreateOptions): Promise<GuildSoundboardSound>;\n  public edit(\n    soundboardSound: SoundboardSoundResolvable,\n    options: GuildSoundboardSoundEditOptions,\n  ): Promise<GuildSoundboardSound>;\n  public delete(soundboardSound: SoundboardSoundResolvable): Promise<void>;\n  public fetch(id: Snowflake, options?: BaseFetchOptions): Promise<GuildSoundboardSound>;\n  public fetch(options?: BaseFetchOptions): Promise<Collection<Snowflake, GuildSoundboardSound>>;\n}\n\nexport class GuildStickerManager extends CachedManager<Snowflake, Sticker, StickerResolvable> {\n  private constructor(guild: Guild, iterable?: Iterable<unknown>);\n  public guild: Guild;\n  public create(options: GuildStickerCreateOptions): Promise<Sticker>;\n  public edit(sticker: StickerResolvable, data?: GuildStickerEditOptions): Promise<Sticker>;\n  public delete(sticker: StickerResolvable, reason?: string): Promise<void>;\n  public fetch(id: Snowflake, options?: BaseFetchOptions): Promise<Sticker>;\n  public fetch(id?: Snowflake, options?: BaseFetchOptions): Promise<Collection<Snowflake, Sticker>>;\n  public fetchUser(sticker: StickerResolvable): Promise<User | null>;\n}\n\nexport class GuildMemberRoleManager extends DataManager<Snowflake, Role, RoleResolvable> {\n  private constructor(member: GuildMember);\n  public get hoist(): Role | null;\n  public get icon(): Role | null;\n  public get color(): Role | null;\n  public get highest(): Role;\n  public get premiumSubscriberRole(): Role | null;\n  public get botRole(): Role | null;\n  public member: GuildMember;\n  public guild: Guild;\n\n  public add(\n    roleOrRoles: ReadonlyCollection<Snowflake, Role> | RoleResolvable | readonly RoleResolvable[],\n    reason?: string,\n  ): Promise<GuildMember>;\n  public set(\n    roles: ReadonlyCollection<Snowflake, Role> | readonly RoleResolvable[],\n    reason?: string,\n  ): Promise<GuildMember>;\n  public remove(\n    roleOrRoles: ReadonlyCollection<Snowflake, Role> | RoleResolvable | readonly RoleResolvable[],\n    reason?: string,\n  ): Promise<GuildMember>;\n}\n\nexport interface FetchPollAnswerVotersOptions extends BaseFetchPollAnswerVotersOptions {\n  answerId: number;\n  messageId: Snowflake;\n}\n\nexport abstract class MessageManager<InGuild extends boolean = boolean> extends CachedManager<\n  Snowflake,\n  Message<InGuild>,\n  MessageResolvable\n> {\n  protected constructor(channel: TextBasedChannel, iterable?: Iterable<APIMessage>);\n  public channel: TextBasedChannel;\n  public delete(message: MessageResolvable): Promise<void>;\n  public edit(\n    message: MessageResolvable,\n    options:\n      | FileBodyEncodable<RESTPatchAPIChannelMessageJSONBody>\n      | JSONEncodable<RESTPatchAPIChannelMessageJSONBody>\n      | MessageEditOptions\n      | MessagePayload\n      | string,\n  ): Promise<Message<InGuild>>;\n  public fetch(options: FetchMessageOptions | MessageResolvable): Promise<Message<InGuild>>;\n  public fetch(options?: FetchMessagesOptions): Promise<Collection<Snowflake, Message<InGuild>>>;\n  public fetchPins(options?: FetchPinnedMessagesOptions): Promise<FetchPinnedMessagesResponse<InGuild>>;\n  public react(message: MessageResolvable, emoji: EmojiIdentifierResolvable): Promise<void>;\n  public pin(message: MessageResolvable, reason?: string): Promise<void>;\n  public unpin(message: MessageResolvable, reason?: string): Promise<void>;\n  public endPoll(messageId: Snowflake): Promise<Message>;\n  public fetchPollAnswerVoters(options: FetchPollAnswerVotersOptions): Promise<Collection<Snowflake, User>>;\n}\n\nexport class DMMessageManager extends MessageManager {\n  public channel: DMChannel;\n}\n\nexport class PartialGroupDMMessageManager extends MessageManager {\n  public channel: PartialGroupDMChannel;\n}\n\nexport class GuildMessageManager extends MessageManager<true> {\n  public channel: GuildTextBasedChannel;\n  public crosspost(message: MessageResolvable): Promise<Message<true>>;\n}\n\nexport class PermissionOverwriteManager extends CachedManager<\n  Snowflake,\n  PermissionOverwrites,\n  PermissionOverwriteResolvable\n> {\n  private constructor(client: Client<true>, iterable?: Iterable<unknown>);\n  public set(\n    overwrites: ReadonlyCollection<Snowflake, OverwriteResolvable> | readonly OverwriteResolvable[],\n    reason?: string,\n  ): Promise<NonThreadGuildBasedChannel>;\n  private upsert(\n    userOrRole: RoleResolvable | UserResolvable,\n    options: PermissionOverwriteOptions,\n    overwriteOptions?: GuildChannelOverwriteOptions,\n    existing?: PermissionOverwrites,\n  ): Promise<NonThreadGuildBasedChannel>;\n  public create(\n    userOrRole: RoleResolvable | UserResolvable,\n    options: PermissionOverwriteOptions,\n    overwriteOptions?: GuildChannelOverwriteOptions,\n  ): Promise<NonThreadGuildBasedChannel>;\n  public edit(\n    userOrRole: RoleResolvable | UserResolvable,\n    options: PermissionOverwriteOptions,\n    overwriteOptions?: GuildChannelOverwriteOptions,\n  ): Promise<NonThreadGuildBasedChannel>;\n  public delete(userOrRole: RoleResolvable | UserResolvable, reason?: string): Promise<NonThreadGuildBasedChannel>;\n}\n\nexport class PresenceManager extends CachedManager<Snowflake, Presence, PresenceResolvable> {\n  private constructor(client: Client<true>, iterable?: Iterable<GatewayPresenceUpdate>);\n}\n\nexport class ReactionManager extends CachedManager<Snowflake | string, MessageReaction, MessageReactionResolvable> {\n  private constructor(message: Message, iterable?: Iterable<unknown>);\n  public message: Message;\n  public removeAll(): Promise<Message>;\n}\n\nexport class ReactionUserManager extends CachedManager<Snowflake, User, UserResolvable> {\n  private constructor(reaction: MessageReaction, iterable?: Iterable<unknown>);\n  public reaction: MessageReaction;\n  public fetch(options?: FetchReactionUsersOptions): Promise<Collection<Snowflake, User>>;\n  public remove(user?: UserResolvable): Promise<MessageReaction>;\n}\n\nexport class RoleManager extends CachedManager<Snowflake, Role, RoleResolvable> {\n  private constructor(guild: Guild, iterable?: Iterable<APIRole>);\n  public get everyone(): Role;\n  public get highest(): Role;\n  public guild: Guild;\n  public get premiumSubscriberRole(): Role | null;\n  public botRoleFor(user: UserResolvable): Role | null;\n  public fetch(id: Snowflake, options?: BaseFetchOptions): Promise<Role>;\n  public fetch(id?: undefined, options?: BaseFetchOptions): Promise<Collection<Snowflake, Role>>;\n  public fetchMemberCounts(): Promise<Collection<Snowflake, number>>;\n  public create(options?: RoleCreateOptions): Promise<Role>;\n  public edit(role: RoleResolvable, options: RoleEditOptions): Promise<Role>;\n  public delete(role: RoleResolvable, reason?: string): Promise<void>;\n  public setPosition(role: RoleResolvable, position: number, options?: SetRolePositionOptions): Promise<Role>;\n  public setPositions(rolePositions: readonly RolePosition[]): Promise<Guild>;\n  public comparePositions(role1: RoleResolvable, role2: RoleResolvable): number;\n}\n\nexport class StageInstanceManager extends CachedManager<Snowflake, StageInstance, StageInstanceResolvable> {\n  private constructor(guild: Guild, iterable?: Iterable<unknown>);\n  public guild: Guild;\n  public create(channel: StageChannelResolvable, options: StageInstanceCreateOptions): Promise<StageInstance>;\n  public fetch(channel: StageChannelResolvable, options?: BaseFetchOptions): Promise<StageInstance>;\n  public edit(channel: StageChannelResolvable, options: StageInstanceEditOptions): Promise<StageInstance>;\n  public delete(channel: StageChannelResolvable): Promise<void>;\n}\n\nexport class ThreadManager<ThreadOnly extends boolean = boolean> extends CachedManager<\n  Snowflake,\n  If<ThreadOnly, ForumThreadChannel, TextThreadChannel>,\n  ThreadChannelResolvable\n> {\n  protected constructor(\n    channel: AnnouncementChannel | ForumChannel | MediaChannel | TextChannel,\n    iterable?: Iterable<RawThreadChannelData>,\n  );\n  public channel: If<ThreadOnly, ForumChannel | MediaChannel, AnnouncementChannel | TextChannel>;\n  public fetch(\n    options: ThreadChannelResolvable,\n    cacheOptions?: BaseFetchOptions,\n  ): Promise<If<ThreadOnly, ForumThreadChannel, TextThreadChannel> | null>;\n  public fetch(\n    options: FetchThreadsOptions & { archived: FetchArchivedThreadOptions },\n    cacheOptions?: { cache?: boolean },\n  ): Promise<FetchedThreadsMore>;\n  public fetch(options?: FetchThreadsOptions, cacheOptions?: { cache?: boolean }): Promise<FetchedThreads>;\n  public fetchArchived(options?: FetchArchivedThreadOptions, cache?: boolean): Promise<FetchedThreadsMore>;\n  public fetchActive(cache?: boolean): Promise<FetchedThreads>;\n}\n\nexport class GuildTextThreadManager<AllowedThreadType> extends ThreadManager<false> {\n  public create(\n    options: GuildTextThreadCreateOptions<AllowedThreadType>,\n  ): Promise<AllowedThreadType extends ChannelType.PrivateThread ? PrivateThreadChannel : PublicThreadChannel<false>>;\n}\n\nexport class GuildForumThreadManager extends ThreadManager<true> {\n  public create(options: GuildForumThreadCreateOptions): Promise<ForumThreadChannel>;\n}\n\nexport class ThreadMemberManager extends CachedManager<Snowflake, ThreadMember, ThreadMemberResolvable> {\n  private constructor(thread: ThreadChannel, iterable?: Iterable<APIThreadMember>);\n  public thread: AnyThreadChannel;\n  public get me(): ThreadMember | null;\n  public add(member: UserResolvable | '@me'): Promise<Snowflake>;\n\n  public fetch(\n    options: ThreadMember<true> | ({ member: ThreadMember<true> } | (FetchThreadMemberOptions & { withMember: true })),\n  ): Promise<ThreadMember<true>>;\n\n  public fetch(options: FetchThreadMemberOptions | ThreadMemberResolvable): Promise<ThreadMember>;\n\n  public fetch(\n    options: FetchThreadMembersWithGuildMemberDataOptions,\n  ): Promise<Collection<Snowflake, ThreadMember<true>>>;\n\n  public fetch(options?: FetchThreadMembersWithoutGuildMemberDataOptions): Promise<Collection<Snowflake, ThreadMember>>;\n  public fetchMe(options?: BaseFetchOptions): Promise<ThreadMember>;\n  public remove(member: UserResolvable | '@me'): Promise<Snowflake>;\n}\n\nexport class UserManager extends CachedManager<Snowflake, User, UserResolvable> {\n  private constructor(client: Client<true>, iterable?: Iterable<unknown>);\n  private dmChannel(userId: Snowflake): DMChannel | null;\n  public createDM(user: UserResolvable, options?: BaseFetchOptions): Promise<DMChannel>;\n  public deleteDM(user: UserResolvable): Promise<DMChannel>;\n  public fetch(user: UserResolvable, options?: BaseFetchOptions): Promise<User>;\n  public send(user: UserResolvable, options: MessageCreateOptions | MessagePayload | string): Promise<Message<false>>;\n}\n\nexport class VoiceStateManager extends CachedManager<Snowflake, VoiceState, typeof VoiceState> {\n  private constructor(guild: Guild, iterable?: Iterable<unknown>);\n  public guild: Guild;\n  public fetch(member: UserResolvable | '@me', options?: BaseFetchOptions): Promise<VoiceState>;\n}\n\n// #endregion\n\n// #region Mixins\n\n// Model the TextBasedChannel mixin system, allowing application of these fields\n// to the classes that use these methods without having to manually add them\n// to each of those classes\n\nexport type Constructable<Entity> = abstract new (...args: any[]) => Entity;\n\nexport interface SendMethod<InGuild extends boolean = boolean> {\n  send(\n    options:\n      | FileBodyEncodable<RESTPostAPIChannelMessageJSONBody>\n      | JSONEncodable<RESTPostAPIChannelMessageJSONBody>\n      | MessageCreateOptions\n      | MessagePayload\n      | string,\n  ): Promise<Message<InGuild>>;\n}\n\nexport interface PinnableChannelFields {\n  get lastPinAt(): Date | null;\n  lastPinTimestamp: number | null;\n}\n\nexport interface BulkDeleteMethod {\n  bulkDelete(\n    messages: Collection<Snowflake, Message> | number | readonly MessageResolvable[],\n    filterOld?: boolean,\n  ): Promise<Snowflake[]>;\n}\n\nexport interface SetRateLimitPerUserMethod {\n  setRateLimitPerUser(rateLimitPerUser: number, reason?: string): Promise<this>;\n}\n\nexport interface WebhookChannelFields {\n  createWebhook(options: ChannelWebhookCreateOptions): Promise<Webhook<WebhookType.Incoming>>;\n  fetchWebhooks(): Promise<Collection<Snowflake, Webhook<WebhookType.ChannelFollower | WebhookType.Incoming>>>;\n  setNSFW(nsfw?: boolean, reason?: string): Promise<this>;\n}\n\nexport interface MessageChannelFields {\n  awaitMessages(options?: AwaitMessagesOptions): Promise<Collection<Snowflake, Message>>;\n  createMessageCollector(options?: MessageCollectorOptions): MessageCollector;\n  sendTyping(): Promise<void>;\n}\n\nexport interface TextBasedChannelFields<InGuild extends boolean = boolean, InDM extends boolean = boolean> {\n  awaitMessageComponent<ComponentType extends MessageComponentType>(\n    options?: AwaitMessageCollectorOptionsParams<ComponentType, true>,\n  ): Promise<MappedInteractionTypes[ComponentType]>;\n  createMessageComponentCollector<ComponentType extends MessageComponentType>(\n    options?: MessageChannelCollectorOptionsParams<ComponentType, true>,\n  ): InteractionCollector<MappedInteractionTypes[ComponentType]>;\n  get lastMessage(): Message | null;\n  lastMessageId: Snowflake | null;\n  messages: If<InGuild, GuildMessageManager, If<InDM, DMMessageManager, PartialGroupDMMessageManager>>;\n}\n\nexport interface PartialWebhookFields {\n  deleteMessage(message: APIMessage | MessageResolvable | '@original', threadId?: Snowflake): Promise<void>;\n  editMessage(\n    message: MessageResolvable | '@original',\n    options: MessagePayload | WebhookMessageEditOptions | string,\n  ): Promise<APIMessage | Message>;\n  fetchMessage(message: Snowflake | '@original', options?: WebhookFetchMessageOptions): Promise<APIMessage | Message>;\n  id: Snowflake;\n  send(\n    options: InteractionReplyOptions | MessagePayload | WebhookMessageCreateOptions | string,\n  ): Promise<APIMessage | Message>;\n  get url(): string;\n}\n\nexport interface WebhookFields extends PartialWebhookFields {\n  get createdAt(): Date;\n  get createdTimestamp(): number;\n  delete(reason?: string): Promise<void>;\n  edit(options: WebhookEditOptions): Promise<this>;\n  sendSlackMessage(body: unknown): Promise<boolean>;\n}\n\n// #endregion\n\n// #region Typedefs\n\nexport interface ActivitiesOptions {\n  name: string;\n  state?: string;\n  type?: ActivityType;\n  url?: string;\n}\n\nexport interface ActivityOptions extends ActivitiesOptions {\n  shardId?: number | readonly number[];\n}\n\nexport interface AddGuildMemberOptions {\n  accessToken: string;\n  deaf?: boolean;\n  fetchWhenExisting?: boolean;\n  force?: boolean;\n  mute?: boolean;\n  nick?: string;\n  roles?: ReadonlyCollection<Snowflake, Role> | readonly RoleResolvable[];\n}\n\nexport type AllowedPartial =\n  | Channel\n  | GuildMember\n  | GuildScheduledEvent\n  | Message\n  | MessageReaction\n  | Poll\n  | PollAnswer\n  | SoundboardSound\n  | ThreadMember\n  | User;\n\nexport type AllowedThreadTypeForAnnouncementChannel = ChannelType.AnnouncementThread;\n\nexport type AllowedThreadTypeForTextChannel = ChannelType.PrivateThread | ChannelType.PublicThread;\n\nexport interface BaseApplicationCommandData {\n  contexts?: readonly InteractionContextType[];\n  defaultMemberPermissions?: PermissionResolvable | null;\n  integrationTypes?: readonly ApplicationIntegrationType[];\n  name: string;\n  nameLocalizations?: LocalizationMap;\n  nsfw?: boolean;\n}\n\nexport interface AttachmentData {\n  description?: string;\n  duration?: number;\n  name?: string;\n  title?: string;\n  waveform?: string;\n}\n\nexport type CommandOptionDataTypeResolvable = ApplicationCommandOptionType;\n\nexport type CommandOptionChannelResolvableType = ApplicationCommandOptionType.Channel;\n\nexport type CommandOptionChoiceResolvableType =\n  | ApplicationCommandOptionType.String\n  | CommandOptionNumericResolvableType;\n\nexport type CommandOptionNumericResolvableType =\n  | ApplicationCommandOptionType.Integer\n  | ApplicationCommandOptionType.Number;\n\nexport type CommandOptionSubOptionResolvableType =\n  | ApplicationCommandOptionType.Subcommand\n  | ApplicationCommandOptionType.SubcommandGroup;\n\nexport type CommandOptionNonChoiceResolvableType = Exclude<\n  CommandOptionDataTypeResolvable,\n  CommandOptionChannelResolvableType | CommandOptionChoiceResolvableType | CommandOptionSubOptionResolvableType\n>;\n\nexport interface CommonBaseApplicationCommandOptionsData {\n  description: string;\n  descriptionLocalizations?: LocalizationMap;\n  name: string;\n  nameLocalizations?: LocalizationMap;\n}\nexport interface BaseApplicationCommandOptionsData extends CommonBaseApplicationCommandOptionsData {\n  required?: boolean;\n}\n\nexport interface UserApplicationCommandData extends BaseApplicationCommandData {\n  type: ApplicationCommandType.User;\n}\n\nexport interface MessageApplicationCommandData extends BaseApplicationCommandData {\n  type: ApplicationCommandType.Message;\n}\n\nexport interface ChatInputApplicationCommandData extends BaseApplicationCommandData {\n  description: string;\n  descriptionLocalizations?: LocalizationMap;\n  options?: readonly ApplicationCommandOptionData[];\n  type?: ApplicationCommandType.ChatInput;\n}\n\nexport interface PrimaryEntryPointCommandData extends BaseApplicationCommandData {\n  description?: string;\n  descriptionLocalizations?: LocalizationMap;\n  handler?: EntryPointCommandHandlerType;\n  type: ApplicationCommandType.PrimaryEntryPoint;\n}\n\nexport type ApplicationCommandData =\n  | ChatInputApplicationCommandData\n  | MessageApplicationCommandData\n  | PrimaryEntryPointCommandData\n  | UserApplicationCommandData;\n\nexport interface ApplicationCommandChannelOptionData extends BaseApplicationCommandOptionsData {\n  channelTypes?: readonly ApplicationCommandOptionAllowedChannelType[];\n  channel_types?: readonly ApplicationCommandOptionAllowedChannelType[];\n  type: CommandOptionChannelResolvableType;\n}\n\nexport interface ApplicationCommandChannelOption extends BaseApplicationCommandOptionsData {\n  channelTypes?: readonly ApplicationCommandOptionAllowedChannelType[];\n  type: ApplicationCommandOptionType.Channel;\n}\n\nexport interface ApplicationCommandRoleOptionData extends BaseApplicationCommandOptionsData {\n  type: ApplicationCommandOptionType.Role;\n}\n\nexport interface ApplicationCommandRoleOption extends BaseApplicationCommandOptionsData {\n  type: ApplicationCommandOptionType.Role;\n}\n\nexport interface ApplicationCommandUserOptionData extends BaseApplicationCommandOptionsData {\n  type: ApplicationCommandOptionType.User;\n}\n\nexport interface ApplicationCommandUserOption extends BaseApplicationCommandOptionsData {\n  type: ApplicationCommandOptionType.User;\n}\n\nexport interface ApplicationCommandMentionableOptionData extends BaseApplicationCommandOptionsData {\n  type: ApplicationCommandOptionType.Mentionable;\n}\n\nexport interface ApplicationCommandMentionableOption extends BaseApplicationCommandOptionsData {\n  type: ApplicationCommandOptionType.Mentionable;\n}\n\nexport interface ApplicationCommandAttachmentOption extends BaseApplicationCommandOptionsData {\n  type: ApplicationCommandOptionType.Attachment;\n}\n\nexport interface ApplicationCommandAutocompleteNumericOption extends BaseApplicationCommandOptionsData {\n  autocomplete: true;\n  maxValue?: number;\n  minValue?: number;\n  type: CommandOptionNumericResolvableType;\n}\n\nexport interface ApplicationCommandAutocompleteStringOption extends BaseApplicationCommandOptionsData {\n  autocomplete: true;\n  maxLength?: number;\n  minLength?: number;\n  type: ApplicationCommandOptionType.String;\n}\n\nexport interface ApplicationCommandAutocompleteNumericOptionData extends BaseApplicationCommandOptionsData {\n  autocomplete: true;\n  maxValue?: number;\n  max_value?: number;\n  minValue?: number;\n  min_value?: number;\n  type: CommandOptionNumericResolvableType;\n}\n\nexport interface ApplicationCommandAutocompleteStringOptionData extends BaseApplicationCommandOptionsData {\n  autocomplete: true;\n  maxLength?: number;\n  max_length?: number;\n  minLength?: number;\n  min_length?: number;\n  type: ApplicationCommandOptionType.String;\n}\n\nexport interface ApplicationCommandChoicesData<\n  Type extends number | string = number | string,\n> extends BaseApplicationCommandOptionsData {\n  autocomplete?: false;\n  choices?: readonly ApplicationCommandOptionChoiceData<Type>[];\n  type: CommandOptionChoiceResolvableType;\n}\n\nexport interface ApplicationCommandChoicesOption<\n  Type extends number | string = number | string,\n> extends BaseApplicationCommandOptionsData {\n  autocomplete?: false;\n  choices?: readonly ApplicationCommandOptionChoiceData<Type>[];\n  type: CommandOptionChoiceResolvableType;\n}\n\nexport interface ApplicationCommandNumericOptionData extends ApplicationCommandChoicesData<number> {\n  maxValue?: number;\n  max_value?: number;\n  minValue?: number;\n  min_value?: number;\n  type: CommandOptionNumericResolvableType;\n}\n\nexport interface ApplicationCommandStringOptionData extends ApplicationCommandChoicesData<string> {\n  maxLength?: number;\n  max_length?: number;\n  minLength?: number;\n  min_length?: number;\n  type: ApplicationCommandOptionType.String;\n}\n\nexport interface ApplicationCommandBooleanOptionData extends BaseApplicationCommandOptionsData {\n  type: ApplicationCommandOptionType.Boolean;\n}\n\nexport interface ApplicationCommandNumericOption extends ApplicationCommandChoicesOption<number> {\n  maxValue?: number;\n  minValue?: number;\n  type: CommandOptionNumericResolvableType;\n}\n\nexport interface ApplicationCommandStringOption extends ApplicationCommandChoicesOption<string> {\n  maxLength?: number;\n  minLength?: number;\n  type: ApplicationCommandOptionType.String;\n}\n\nexport interface ApplicationCommandBooleanOption extends BaseApplicationCommandOptionsData {\n  type: ApplicationCommandOptionType.Boolean;\n}\n\nexport interface ApplicationCommandSubGroupData extends CommonBaseApplicationCommandOptionsData {\n  options: readonly ApplicationCommandSubCommandData[];\n  type: ApplicationCommandOptionType.SubcommandGroup;\n}\n\nexport interface ApplicationCommandSubGroup extends CommonBaseApplicationCommandOptionsData {\n  options?: readonly ApplicationCommandSubCommand[];\n  type: ApplicationCommandOptionType.SubcommandGroup;\n}\n\nexport interface ApplicationCommandSubCommandData extends CommonBaseApplicationCommandOptionsData {\n  options?: readonly Exclude<\n    ApplicationCommandOptionData,\n    ApplicationCommandSubCommandData | ApplicationCommandSubGroupData\n  >[];\n  type: ApplicationCommandOptionType.Subcommand;\n}\n\nexport interface ApplicationCommandSubCommand extends CommonBaseApplicationCommandOptionsData {\n  options?: readonly Exclude<ApplicationCommandOption, ApplicationCommandSubCommand | ApplicationCommandSubGroup>[];\n  type: ApplicationCommandOptionType.Subcommand;\n}\n\nexport interface ApplicationCommandNonOptionsData extends BaseApplicationCommandOptionsData {\n  type: CommandOptionNonChoiceResolvableType;\n}\n\nexport interface ApplicationCommandNonOptions extends BaseApplicationCommandOptionsData {\n  type: Exclude<CommandOptionNonChoiceResolvableType, ApplicationCommandOptionType>;\n}\n\nexport type ApplicationCommandOptionData =\n  | ApplicationCommandAutocompleteNumericOptionData\n  | ApplicationCommandAutocompleteStringOptionData\n  | ApplicationCommandBooleanOptionData\n  | ApplicationCommandChannelOptionData\n  | ApplicationCommandMentionableOptionData\n  | ApplicationCommandNonOptionsData\n  | ApplicationCommandNumericOptionData\n  | ApplicationCommandRoleOptionData\n  | ApplicationCommandStringOptionData\n  | ApplicationCommandSubCommandData\n  | ApplicationCommandSubGroupData\n  | ApplicationCommandUserOptionData;\n\nexport type ApplicationCommandOption =\n  | ApplicationCommandAttachmentOption\n  | ApplicationCommandAutocompleteNumericOption\n  | ApplicationCommandAutocompleteStringOption\n  | ApplicationCommandBooleanOption\n  | ApplicationCommandChannelOption\n  | ApplicationCommandMentionableOption\n  | ApplicationCommandNonOptions\n  | ApplicationCommandNumericOption\n  | ApplicationCommandRoleOption\n  | ApplicationCommandStringOption\n  | ApplicationCommandSubCommand\n  | ApplicationCommandSubGroup\n  | ApplicationCommandUserOption;\n\nexport interface ApplicationCommandOptionChoiceData<Value extends number | string = number | string> {\n  name: string;\n  nameLocalizations?: LocalizationMap;\n  value: Value;\n}\n\nexport interface ApplicationCommandPermissions {\n  id: Snowflake;\n  permission: boolean;\n  type: ApplicationCommandPermissionType;\n}\n\nexport interface ApplicationCommandPermissionsUpdateData {\n  applicationId: Snowflake;\n  guildId: Snowflake;\n  id: Snowflake;\n  permissions: readonly ApplicationCommandPermissions[];\n}\n\nexport interface EditApplicationCommandPermissionsMixin {\n  permissions: readonly ApplicationCommandPermissions[];\n  token: string;\n}\n\nexport type ChannelPermissionConstant = Snowflake;\n\nexport type RolePermissionConstant = Snowflake;\n\nexport type ApplicationCommandPermissionIdResolvable =\n  | ChannelPermissionConstant\n  | GuildChannelResolvable\n  | RolePermissionConstant\n  | RoleResolvable\n  | UserResolvable;\n\nexport type ApplicationCommandResolvable = ApplicationCommand | Snowflake;\n\nexport type ApplicationFlagsString = keyof typeof ApplicationFlags;\n\nexport interface ApplicationRoleConnectionMetadataEditOptions {\n  description: string;\n  descriptionLocalizations?: LocalizationMap | null;\n  key: string;\n  name: string;\n  nameLocalizations?: LocalizationMap | null;\n  type: ApplicationRoleConnectionMetadataType;\n}\n\nexport type AuditLogChange = {\n  [SourceElement in APIAuditLogChange as SourceElement['key']]: {\n    key: SourceElement['key'];\n    new?: SourceElement['new_value'];\n    old?: SourceElement['old_value'];\n  };\n}[APIAuditLogChange['key']];\n\nexport interface AutoModerationAction {\n  metadata: AutoModerationActionMetadata;\n  type: AutoModerationActionType;\n}\n\nexport interface BaseAutoModerationActionMetadata {\n  customMessage?: string | null;\n  durationSeconds?: number | null;\n}\n\nexport interface AutoModerationActionMetadata extends BaseAutoModerationActionMetadata {\n  channelId: Snowflake | null;\n  customMessage: string | null;\n  durationSeconds: number | null;\n}\n\nexport interface AutoModerationTriggerMetadata {\n  allowList: readonly string[];\n  keywordFilter: readonly string[];\n  mentionRaidProtectionEnabled: boolean;\n  mentionTotalLimit: number | null;\n  presets: readonly AutoModerationRuleKeywordPresetType[];\n  regexPatterns: readonly string[];\n}\n\nexport interface AwaitMessageComponentOptions<Interaction extends CollectedMessageInteraction> extends CollectorOptions<\n  [Interaction, Collection<Snowflake, Interaction>]\n> {\n  componentType?: ComponentType;\n}\n\nexport interface AwaitModalSubmitOptions extends CollectorOptions<\n  [ModalSubmitInteraction, Collection<Snowflake, ModalSubmitInteraction>]\n> {\n  time: number;\n}\n\nexport interface AwaitMessagesOptions extends MessageCollectorOptions {\n  errors?: readonly string[];\n}\n\nexport interface AwaitReactionsOptions extends ReactionCollectorOptions {\n  errors?: readonly string[];\n}\n\nexport interface BanOptions {\n  deleteMessageSeconds?: number;\n  reason?: string;\n}\n\nexport interface BulkBanResult {\n  bannedUsers: readonly Snowflake[];\n  failedUsers: readonly Snowflake[];\n}\n\nexport interface PollData {\n  allowMultiselect: boolean;\n  answers: readonly PollAnswerData[];\n  duration: number;\n  layoutType?: PollLayoutType;\n  question: PollQuestionMedia;\n}\n\nexport interface PollAnswerData {\n  emoji?: EmojiIdentifierResolvable;\n  text: string;\n}\n\nexport type Base64Resolvable = Base64String | Buffer;\n\nexport type Base64String = string;\n\nexport interface BaseFetchOptions {\n  cache?: boolean;\n  force?: boolean;\n}\n\nexport type BitFieldResolvable<Flags extends string, Type extends bigint | number> =\n  | Flags\n  | Readonly<BitField<Flags, Type>>\n  | RecursiveReadonlyArray<Flags | Readonly<BitField<Flags, Type>> | Type | `${bigint}`>\n  | Type\n  | `${bigint}`;\n\nexport type BufferResolvable = Buffer | string;\n\nexport interface Caches {\n  ApplicationCommandManager: [manager: typeof ApplicationCommandManager, holds: typeof ApplicationCommand];\n  ApplicationEmojiManager: [manager: typeof ApplicationEmojiManager, holds: typeof ApplicationEmoji];\n  AutoModerationRuleManager: [manager: typeof AutoModerationRuleManager, holds: typeof AutoModerationRule];\n  // TODO: ChannelManager: [manager: typeof ChannelManager, holds: typeof Channel];\n  DMMessageManager: [manager: typeof MessageManager, holds: typeof Message<false>];\n  EntitlementManager: [manager: typeof EntitlementManager, holds: typeof Entitlement];\n  GuildBanManager: [manager: typeof GuildBanManager, holds: typeof GuildBan];\n  // TODO: GuildChannelManager: [manager: typeof GuildChannelManager, holds: typeof GuildChannel];\n  GuildEmojiManager: [manager: typeof GuildEmojiManager, holds: typeof GuildEmoji];\n  GuildForumThreadManager: [manager: typeof GuildForumThreadManager, holds: typeof ThreadChannel<true>];\n  GuildInviteManager: [manager: typeof GuildInviteManager, holds: typeof GuildInvite];\n  // TODO: GuildManager: [manager: typeof GuildManager, holds: typeof Guild];\n  GuildMemberManager: [manager: typeof GuildMemberManager, holds: typeof GuildMember];\n  GuildMessageManager: [manager: typeof GuildMessageManager, holds: typeof Message<true>];\n  GuildScheduledEventManager: [manager: typeof GuildScheduledEventManager, holds: typeof GuildScheduledEvent];\n  GuildStickerManager: [manager: typeof GuildStickerManager, holds: typeof Sticker];\n  GuildTextThreadManager: [manager: typeof GuildTextThreadManager, holds: typeof ThreadChannel<false>];\n  MessageManager: [manager: typeof MessageManager, holds: typeof Message];\n  // TODO: PermissionOverwriteManager: [manager: typeof PermissionOverwriteManager, holds: typeof PermissionOverwrites];\n  PresenceManager: [manager: typeof PresenceManager, holds: typeof Presence];\n  ReactionManager: [manager: typeof ReactionManager, holds: typeof MessageReaction];\n  ReactionUserManager: [manager: typeof ReactionUserManager, holds: typeof User];\n  // TODO: RoleManager: [manager: typeof RoleManager, holds: typeof Role];\n  StageInstanceManager: [manager: typeof StageInstanceManager, holds: typeof StageInstance];\n  ThreadManager: [manager: typeof ThreadManager, holds: typeof ThreadChannel];\n  ThreadMemberManager: [manager: typeof ThreadMemberManager, holds: typeof ThreadMember];\n  UserManager: [manager: typeof UserManager, holds: typeof User];\n  VoiceStateManager: [manager: typeof VoiceStateManager, holds: typeof VoiceState];\n}\n\nexport type CacheConstructors = {\n  [Cache in keyof Caches]: Caches[Cache][0] & { name: Cache };\n};\n\nexport type OverriddenCaches =\n  | 'DMMessageManager'\n  | 'GuildForumThreadManager'\n  | 'GuildMessageManager'\n  | 'GuildTextThreadManager';\n\nexport interface CacheFactoryParams<Manager extends keyof Caches> {\n  holds: Caches[Manager][1];\n  manager: CacheConstructors[keyof Caches];\n  managerType: CacheConstructors[Exclude<keyof Caches, OverriddenCaches>];\n}\n\n// This doesn't actually work the way it looks 😢.\n// Narrowing the type of `manager.name` doesn't propagate type information to `holds` and the return type.\nexport type CacheFactory = ({\n  holds,\n  manager,\n  managerType,\n}: CacheFactoryParams<keyof Caches>) => (typeof manager)['prototype'] extends DataManager<infer Key, infer Value, any>\n  ? Collection<Key, Value>\n  : never;\n\nexport type CacheWithLimitsOptions = {\n  [K in keyof Caches]?: Caches[K][0]['prototype'] extends DataManager<infer Key, infer Value, any>\n    ? LimitedCollectionOptions<Key, Value> | number\n    : never;\n};\n\nexport interface BaseCategoryCreateChannelOptions {\n  availableTags?: readonly GuildForumTagData[];\n  bitrate?: number;\n  defaultAutoArchiveDuration?: ThreadAutoArchiveDuration;\n  defaultForumLayout?: ForumLayoutType;\n  defaultReactionEmoji?: DefaultReactionEmoji;\n  defaultSortOrder?: SortOrderType;\n  defaultThreadRateLimitPerUser?: number;\n  name?: string;\n  nsfw?: boolean;\n  permissionOverwrites?: ReadonlyCollection<Snowflake, OverwriteResolvable> | readonly OverwriteResolvable[];\n  position?: number;\n  rateLimitPerUser?: number;\n  reason?: string;\n  rtcRegion?: string;\n  topic?: string;\n  type?: GuildChannelTypes;\n  userLimit?: number;\n  videoQualityMode?: VideoQualityMode;\n}\n\nexport interface CategoryCreateChannelOptions extends BaseCategoryCreateChannelOptions {\n  name: string;\n  type?: CategoryChannelChildTypes;\n}\n\nexport interface ChannelCreationOverwrites {\n  allow?: PermissionResolvable;\n  deny?: PermissionResolvable;\n  id: RoleResolvable | UserResolvable;\n}\n\nexport type ChannelMention = `<#${Snowflake}>`;\n\nexport interface ChannelPosition {\n  channel: NonThreadGuildBasedChannel | Snowflake;\n  lockPermissions?: boolean;\n  parent?: CategoryChannelResolvable | null;\n  position?: number;\n}\n\nexport type GuildTextChannelResolvable = AnnouncementChannel | Snowflake | TextChannel;\nexport type ChannelResolvable = Channel | Snowflake;\n\nexport interface ChannelWebhookCreateOptions {\n  avatar?: Base64Resolvable | BufferResolvable | null;\n  name: string;\n  reason?: string;\n}\n\nexport interface WebhookCreateOptions extends ChannelWebhookCreateOptions {\n  channel: AnnouncementChannel | ForumChannel | MediaChannel | Snowflake | StageChannel | TextChannel | VoiceChannel;\n}\n\nexport interface GuildMembersChunk {\n  count: number;\n  index: number;\n  nonce: string | undefined;\n  notFound: readonly unknown[];\n}\n\nexport type OmitPartialGroupDMChannel<Structure extends { channel: Channel }> = Structure & {\n  channel: Exclude<Structure['channel'], PartialGroupDMChannel>;\n};\n\nexport interface VoiceServerUpdateData {\n  endpoint: string | null;\n  guildId: Snowflake;\n  token: string;\n}\n\nexport interface ClientEventTypes {\n  applicationCommandPermissionsUpdate: [data: ApplicationCommandPermissionsUpdateData];\n  autoModerationActionExecution: [autoModerationActionExecution: AutoModerationActionExecution];\n  autoModerationRuleCreate: [autoModerationRule: AutoModerationRule];\n  autoModerationRuleDelete: [autoModerationRule: AutoModerationRule];\n  autoModerationRuleUpdate: [\n    oldAutoModerationRule: AutoModerationRule | null,\n    newAutoModerationRule: AutoModerationRule,\n  ];\n  cacheSweep: [message: string];\n  channelCreate: [channel: NonThreadGuildBasedChannel];\n  channelDelete: [channel: DMChannel | NonThreadGuildBasedChannel];\n  channelPinsUpdate: [channel: TextBasedChannel, date: Date];\n  channelUpdate: [\n    oldChannel: DMChannel | NonThreadGuildBasedChannel,\n    newChannel: DMChannel | NonThreadGuildBasedChannel,\n  ];\n  clientReady: [client: Client<true>];\n  debug: [message: string];\n  emojiCreate: [emoji: GuildEmoji];\n  emojiDelete: [emoji: GuildEmoji];\n  emojiUpdate: [oldEmoji: GuildEmoji, newEmoji: GuildEmoji];\n  entitlementCreate: [entitlement: Entitlement];\n  entitlementDelete: [entitlement: Entitlement];\n  entitlementUpdate: [oldEntitlement: Entitlement | null, newEntitlement: Entitlement];\n  error: [error: Error];\n  guildAuditLogEntryCreate: [auditLogEntry: GuildAuditLogsEntry, guild: Guild];\n  guildAvailable: [guild: Guild];\n  guildBanAdd: [ban: GuildBan];\n  guildBanRemove: [ban: GuildBan];\n  guildCreate: [guild: Guild];\n  guildDelete: [guild: Guild];\n  guildIntegrationsUpdate: [guild: Guild];\n  guildMemberAdd: [member: GuildMember];\n  guildMemberAvailable: [member: GuildMember | PartialGuildMember];\n  guildMemberRemove: [member: GuildMember | PartialGuildMember];\n  guildMemberUpdate: [oldMember: GuildMember | PartialGuildMember, newMember: GuildMember];\n  guildMembersChunk: [members: ReadonlyCollection<Snowflake, GuildMember>, guild: Guild, data: GuildMembersChunk];\n  guildScheduledEventCreate: [guildScheduledEvent: GuildScheduledEvent];\n  guildScheduledEventDelete: [guildScheduledEvent: GuildScheduledEvent | PartialGuildScheduledEvent];\n  guildScheduledEventUpdate: [\n    oldGuildScheduledEvent: GuildScheduledEvent | PartialGuildScheduledEvent | null,\n    newGuildScheduledEvent: GuildScheduledEvent,\n  ];\n  guildScheduledEventUserAdd: [guildScheduledEvent: GuildScheduledEvent | PartialGuildScheduledEvent, user: User];\n  guildScheduledEventUserRemove: [guildScheduledEvent: GuildScheduledEvent | PartialGuildScheduledEvent, user: User];\n  guildSoundboardSoundCreate: [soundboardSound: GuildSoundboardSound];\n  guildSoundboardSoundDelete: [soundboardSound: GuildSoundboardSound | PartialSoundboardSound];\n  guildSoundboardSoundUpdate: [\n    oldSoundboardSound: GuildSoundboardSound | null,\n    newSoundboardSound: GuildSoundboardSound,\n  ];\n  guildSoundboardSoundsUpdate: [soundboardSounds: ReadonlyCollection<Snowflake, GuildSoundboardSound>, guild: Guild];\n  guildUnavailable: [guild: Guild];\n  guildUpdate: [oldGuild: Guild, newGuild: Guild];\n  interactionCreate: [interaction: Interaction];\n  invalidated: [];\n  inviteCreate: [invite: GuildInvite];\n  inviteDelete: [invite: GuildInvite];\n  messageCreate: [message: OmitPartialGroupDMChannel<Message>];\n  messageDelete: [message: OmitPartialGroupDMChannel<Message | PartialMessage>];\n  messageDeleteBulk: [\n    messages: ReadonlyCollection<Snowflake, Message<true> | PartialMessage<true>>,\n    channel: GuildTextBasedChannel,\n  ];\n  messagePollVoteAdd: [pollAnswer: PartialPollAnswer | PollAnswer, userId: Snowflake];\n  messagePollVoteRemove: [pollAnswer: PartialPollAnswer | PollAnswer, userId: Snowflake];\n  messageReactionAdd: [\n    reaction: MessageReaction | PartialMessageReaction,\n    user: PartialUser | User,\n    details: MessageReactionEventDetails,\n  ];\n  messageReactionRemove: [\n    reaction: MessageReaction | PartialMessageReaction,\n    user: PartialUser | User,\n    details: MessageReactionEventDetails,\n  ];\n  messageReactionRemoveAll: [\n    message: OmitPartialGroupDMChannel<Message | PartialMessage>,\n    reactions: ReadonlyCollection<Snowflake | string, MessageReaction>,\n  ];\n  messageReactionRemoveEmoji: [reaction: MessageReaction | PartialMessageReaction];\n  messageUpdate: [\n    oldMessage: OmitPartialGroupDMChannel<Message | PartialMessage>,\n    newMessage: OmitPartialGroupDMChannel<Message>,\n  ];\n  presenceUpdate: [oldPresence: Presence | null, newPresence: Presence];\n  roleCreate: [role: Role];\n  roleDelete: [role: Role];\n  roleUpdate: [oldRole: Role, newRole: Role];\n  soundboardSounds: [soundboardSounds: ReadonlyCollection<Snowflake, GuildSoundboardSound>, guild: Guild];\n  stageInstanceCreate: [stageInstance: StageInstance];\n  stageInstanceDelete: [stageInstance: StageInstance];\n  stageInstanceUpdate: [oldStageInstance: StageInstance | null, newStageInstance: StageInstance];\n  stickerCreate: [sticker: Sticker];\n  stickerDelete: [sticker: Sticker];\n  stickerUpdate: [oldSticker: Sticker, newSticker: Sticker];\n  subscriptionCreate: [subscription: Subscription];\n  subscriptionDelete: [subscription: Subscription];\n  subscriptionUpdate: [oldSubscription: Subscription | null, newSubscription: Subscription];\n  threadCreate: [thread: AnyThreadChannel, newlyCreated: boolean];\n  threadDelete: [thread: AnyThreadChannel];\n  threadListSync: [threads: ReadonlyCollection<Snowflake, AnyThreadChannel>, guild: Guild];\n  threadMemberUpdate: [oldMember: ThreadMember, newMember: ThreadMember];\n  threadMembersUpdate: [\n    addedMembers: ReadonlyCollection<Snowflake, ThreadMember>,\n    removedMembers: ReadonlyCollection<Snowflake, PartialThreadMember | ThreadMember>,\n    thread: AnyThreadChannel,\n  ];\n  threadUpdate: [oldThread: AnyThreadChannel, newThread: AnyThreadChannel];\n  typingStart: [typing: Typing];\n  userUpdate: [oldUser: PartialUser | User, newUser: User];\n  voiceChannelEffectSend: [voiceChannelEffect: VoiceChannelEffect];\n  voiceServerUpdate: [data: VoiceServerUpdateData];\n  voiceStateUpdate: [oldState: VoiceState, newState: VoiceState];\n  warn: [message: string];\n  webhooksUpdate: [channel: AnnouncementChannel | ForumChannel | MediaChannel | TextChannel | VoiceChannel];\n}\n\nexport interface ClientFetchInviteOptions {\n  guildScheduledEventId?: Snowflake;\n  withCounts?: boolean;\n}\n\nexport interface ClientOptions {\n  allowedMentions?: MessageMentionOptions;\n  closeTimeout?: number;\n  enforceNonce?: boolean;\n  failIfNotExists?: boolean;\n  intents: BitFieldResolvable<GatewayIntentsString, number>;\n  jsonTransformer?(obj: unknown): unknown;\n  makeCache?: CacheFactory;\n  partials?: readonly Partials[];\n  presence?: PresenceData;\n  rest?: Partial<RESTOptions>;\n  sweepers?: SweeperOptions;\n  waitGuildTimeout?: number;\n  ws?: Partial<WebSocketManagerOptions>;\n}\n\nexport type ClientPresenceStatus = 'dnd' | 'idle' | 'online';\n\nexport interface ClientPresenceStatusData {\n  desktop?: ClientPresenceStatus;\n  mobile?: ClientPresenceStatus;\n  web?: ClientPresenceStatus;\n}\n\nexport interface ClientUserEditOptions {\n  avatar?: Base64Resolvable | BufferResolvable | null;\n  banner?: Base64Resolvable | BufferResolvable | null;\n  username?: string;\n}\n\nexport type CollectorFilter<Arguments extends unknown[]> = (...args: Arguments) => Awaitable<boolean>;\n\nexport interface CollectorOptions<FilterArguments extends unknown[]> {\n  dispose?: boolean;\n  filter?: CollectorFilter<FilterArguments>;\n  idle?: number;\n  time?: number;\n}\n\nexport interface CollectorResetTimerOptions {\n  idle?: number;\n  time?: number;\n}\n\nexport type ColorResolvable =\n  | HexColorString\n  | number\n  | keyof typeof Colors\n  | readonly [red: number, green: number, blue: number]\n  | 'Random';\n\nexport interface CommandInteractionOption<Cached extends CacheType = CacheType> {\n  attachment?: Attachment;\n  autocomplete?: boolean;\n  channel?: CacheTypeReducer<Cached, GuildBasedChannel, APIInteractionDataResolvedChannel>;\n  focused?: boolean;\n  member?: CacheTypeReducer<Cached, GuildMember, APIInteractionDataResolvedGuildMember>;\n  message?: Message<BooleanCache<Cached>>;\n  name: string;\n  options?: readonly CommandInteractionOption[];\n  role?: CacheTypeReducer<Cached, Role, APIRole>;\n  type: ApplicationCommandOptionType;\n  user?: User;\n  value?: boolean | number | string;\n}\n\nexport interface BaseInteractionResolvedData<Cached extends CacheType = CacheType> {\n  attachments?: ReadonlyCollection<Snowflake, Attachment>;\n  channels?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Channel, APIInteractionDataResolvedChannel>>;\n  members?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, GuildMember, APIInteractionDataResolvedGuildMember>>;\n  roles?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Role, APIRole>>;\n  users?: ReadonlyCollection<Snowflake, User>;\n}\n\nexport interface CommandInteractionResolvedData<\n  Cached extends CacheType = CacheType,\n> extends BaseInteractionResolvedData<Cached> {\n  messages?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Message, APIMessage>>;\n}\n\nexport interface AutocompleteFocusedOption {\n  focused: true;\n  name: string;\n  type:\n    | ApplicationCommandOptionType.Integer\n    | ApplicationCommandOptionType.Number\n    | ApplicationCommandOptionType.String;\n  value: string;\n}\n\nexport declare const Colors: {\n  Aqua: 0x1abc9c;\n  Blue: 0x3498db;\n  Blurple: 0x5865f2;\n  DarkAqua: 0x11806a;\n  DarkBlue: 0x206694;\n  DarkButNotBlack: 0x2c2f33;\n  DarkGold: 0xc27c0e;\n  DarkGreen: 0x1f8b4c;\n  DarkGrey: 0x979c9f;\n  DarkNavy: 0x2c3e50;\n  DarkOrange: 0xa84300;\n  DarkPurple: 0x71368a;\n  DarkRed: 0x992d22;\n  DarkVividPink: 0xad1457;\n  DarkerGrey: 0x7f8c8d;\n  Default: 0x000000;\n  Fuchsia: 0xeb459e;\n  Gold: 0xf1c40f;\n  Green: 0x57f287;\n  Grey: 0x95a5a6;\n  Greyple: 0x99aab5;\n  LightGrey: 0xbcc0c0;\n  LuminousVividPink: 0xe91e63;\n  Navy: 0x34495e;\n  NotQuiteBlack: 0x23272a;\n  Orange: 0xe67e22;\n  Purple: 0x9b59b6;\n  Red: 0xed4245;\n  White: 0xffffff;\n  Yellow: 0xfee75c;\n};\n\nexport enum Events {\n  ApplicationCommandPermissionsUpdate = 'applicationCommandPermissionsUpdate',\n  AutoModerationActionExecution = 'autoModerationActionExecution',\n  AutoModerationRuleCreate = 'autoModerationRuleCreate',\n  AutoModerationRuleDelete = 'autoModerationRuleDelete',\n  AutoModerationRuleUpdate = 'autoModerationRuleUpdate',\n  CacheSweep = 'cacheSweep',\n  ChannelCreate = 'channelCreate',\n  ChannelDelete = 'channelDelete',\n  ChannelPinsUpdate = 'channelPinsUpdate',\n  ChannelUpdate = 'channelUpdate',\n  ClientReady = 'clientReady',\n  Debug = 'debug',\n  EntitlementCreate = 'entitlementCreate',\n  EntitlementDelete = 'entitlementDelete',\n  EntitlementUpdate = 'entitlementUpdate',\n  Error = 'error',\n  GuildAuditLogEntryCreate = 'guildAuditLogEntryCreate',\n  GuildAvailable = 'guildAvailable',\n  GuildBanAdd = 'guildBanAdd',\n  GuildBanRemove = 'guildBanRemove',\n  GuildCreate = 'guildCreate',\n  GuildDelete = 'guildDelete',\n  GuildEmojiCreate = 'emojiCreate',\n  GuildEmojiDelete = 'emojiDelete',\n  GuildEmojiUpdate = 'emojiUpdate',\n  GuildIntegrationsUpdate = 'guildIntegrationsUpdate',\n  GuildMemberAdd = 'guildMemberAdd',\n  GuildMemberAvailable = 'guildMemberAvailable',\n  GuildMemberRemove = 'guildMemberRemove',\n  GuildMemberUpdate = 'guildMemberUpdate',\n  GuildMembersChunk = 'guildMembersChunk',\n  GuildRoleCreate = 'roleCreate',\n  GuildRoleDelete = 'roleDelete',\n  GuildRoleUpdate = 'roleUpdate',\n  GuildScheduledEventCreate = 'guildScheduledEventCreate',\n  GuildScheduledEventDelete = 'guildScheduledEventDelete',\n  GuildScheduledEventUpdate = 'guildScheduledEventUpdate',\n  GuildScheduledEventUserAdd = 'guildScheduledEventUserAdd',\n  GuildScheduledEventUserRemove = 'guildScheduledEventUserRemove',\n  GuildSoundboardSoundCreate = 'guildSoundboardSoundCreate',\n  GuildSoundboardSoundDelete = 'guildSoundboardSoundDelete',\n  GuildSoundboardSoundUpdate = 'guildSoundboardSoundUpdate',\n  GuildSoundboardSoundsUpdate = 'guildSoundboardSoundsUpdate',\n  GuildStickerCreate = 'stickerCreate',\n  GuildStickerDelete = 'stickerDelete',\n  GuildStickerUpdate = 'stickerUpdate',\n  GuildUnavailable = 'guildUnavailable',\n  GuildUpdate = 'guildUpdate',\n  InteractionCreate = 'interactionCreate',\n  Invalidated = 'invalidated',\n  InviteCreate = 'inviteCreate',\n  InviteDelete = 'inviteDelete',\n  MessageBulkDelete = 'messageDeleteBulk',\n  MessageCreate = 'messageCreate',\n  MessageDelete = 'messageDelete',\n  MessagePollVoteAdd = 'messagePollVoteAdd',\n  MessagePollVoteRemove = 'messagePollVoteRemove',\n  MessageReactionAdd = 'messageReactionAdd',\n  MessageReactionRemove = 'messageReactionRemove',\n  MessageReactionRemoveAll = 'messageReactionRemoveAll',\n  MessageReactionRemoveEmoji = 'messageReactionRemoveEmoji',\n  MessageUpdate = 'messageUpdate',\n  PresenceUpdate = 'presenceUpdate',\n  SoundboardSounds = 'soundboardSounds',\n  StageInstanceCreate = 'stageInstanceCreate',\n  StageInstanceDelete = 'stageInstanceDelete',\n  StageInstanceUpdate = 'stageInstanceUpdate',\n  SubscriptionCreate = 'subscriptionCreate',\n  SubscriptionDelete = 'subscriptionDelete',\n  SubscriptionUpdate = 'subscriptionUpdate',\n  ThreadCreate = 'threadCreate',\n  ThreadDelete = 'threadDelete',\n  ThreadListSync = 'threadListSync',\n  ThreadMemberUpdate = 'threadMemberUpdate',\n  ThreadMembersUpdate = 'threadMembersUpdate',\n  ThreadUpdate = 'threadUpdate',\n  TypingStart = 'typingStart',\n  UserUpdate = 'userUpdate',\n  VoiceChannelEffectSend = 'voiceChannelEffectSend',\n  VoiceServerUpdate = 'voiceServerUpdate',\n  VoiceStateUpdate = 'voiceStateUpdate',\n  Warn = 'warn',\n  WebhooksUpdate = 'webhooksUpdate',\n}\n\nexport enum ShardEvents {\n  Death = 'death',\n  Disconnect = 'disconnect',\n  Error = 'error',\n  Message = 'message',\n  Ready = 'ready',\n  Resume = 'resume',\n  Spawn = 'spawn',\n}\n\nexport enum Status {\n  Ready = 0,\n  Connecting = 1,\n  Reconnecting = 2,\n  Idle = 3,\n  Nearly = 4,\n  Disconnected = 5,\n  WaitingForGuilds = 6,\n  Identifying = 7,\n  Resuming = 8,\n}\n\nexport interface GuildScheduledEventInviteURLCreateOptions extends InviteCreateOptions {\n  channel?: GuildInvitableChannelResolvable;\n}\n\nexport interface RoleCreateOptions extends RoleData {\n  reason?: string;\n}\n\nexport interface RoleEditOptions extends RoleData {\n  reason?: string;\n}\n\nexport interface StageInstanceCreateOptions {\n  guildScheduledEvent?: GuildScheduledEventResolvable;\n  privacyLevel?: StageInstancePrivacyLevel;\n  sendStartNotification?: boolean;\n  topic: string;\n}\n\nexport interface CrosspostedChannel {\n  channelId: Snowflake;\n  guildId: Snowflake;\n  name: string;\n  type: ChannelType;\n}\n\nexport type DateResolvable = Date | number | string;\n\nexport interface GuildTemplateEditOptions {\n  description?: string;\n  name?: string;\n}\n\nexport interface EmbedField {\n  inline: boolean;\n  name: string;\n  value: string;\n}\n\nexport type EmojiIdentifierResolvable =\n  | EmojiResolvable\n  | string\n  | `<${'' | 'a'}:${string}:${Snowflake}>`\n  | `${'' | 'a:'}${string}:${Snowflake}`;\n\nexport type EmojiResolvable = ApplicationEmoji | GuildEmoji | ReactionEmoji | Snowflake;\n\nexport interface FetchApplicationCommandOptions extends FetchGuildApplicationCommandFetchOptions {\n  guildId?: Snowflake;\n}\n\nexport interface FetchArchivedThreadOptions {\n  before?: DateResolvable | ThreadChannelResolvable;\n  fetchAll?: boolean;\n  limit?: number;\n  type?: 'private' | 'public';\n}\n\nexport interface FetchAutoModerationRuleOptions extends BaseFetchOptions {\n  autoModerationRule: AutoModerationRuleResolvable;\n}\n\nexport interface FetchAutoModerationRulesOptions {\n  cache?: boolean;\n}\n\nexport interface FetchBanOptions extends BaseFetchOptions {\n  user: UserResolvable;\n}\n\nexport interface FetchBansOptions {\n  after?: Snowflake;\n  before?: Snowflake;\n  cache?: boolean;\n  limit?: number;\n}\n\nexport interface FetchChannelOptions extends BaseFetchOptions {\n  allowUnknownGuild?: boolean;\n}\n\nexport interface FetchedThreads {\n  members: ReadonlyCollection<Snowflake, ThreadMember>;\n  threads: ReadonlyCollection<Snowflake, AnyThreadChannel>;\n}\n\nexport interface FetchedThreadsMore extends FetchedThreads {\n  hasMore: boolean;\n}\n\nexport interface FetchGuildOptions extends BaseFetchOptions {\n  guild: GuildResolvable;\n  withCounts?: boolean;\n}\n\nexport interface FetchGuildsOptions {\n  after?: Snowflake;\n  before?: Snowflake;\n  limit?: number;\n}\n\nexport interface FetchGuildScheduledEventOptions extends BaseFetchOptions {\n  guildScheduledEvent: GuildScheduledEventResolvable;\n  withUserCount?: boolean;\n}\n\nexport interface FetchGuildScheduledEventsOptions {\n  cache?: boolean;\n  withUserCount?: boolean;\n}\n\nexport interface FetchGuildScheduledEventSubscribersOptions {\n  limit?: number;\n  withMember?: boolean;\n}\n\nexport interface FetchInviteOptions extends BaseFetchOptions {\n  code: string;\n}\n\nexport interface FetchInvitesOptions {\n  cache?: boolean;\n  channelId?: GuildInvitableChannelResolvable;\n}\n\nexport interface FetchMemberOptions extends BaseFetchOptions {\n  user: UserResolvable;\n}\n\nexport interface FetchMembersOptions {\n  limit?: number;\n  nonce?: string;\n  query?: string;\n  time?: number;\n  user?: UserResolvable | readonly UserResolvable[];\n  withPresences?: boolean;\n}\n\nexport interface FetchMessageOptions extends BaseFetchOptions {\n  message: MessageResolvable;\n}\n\nexport interface FetchMessagesOptions {\n  after?: Snowflake;\n  around?: Snowflake;\n  before?: Snowflake;\n  cache?: boolean;\n  limit?: number;\n}\n\nexport interface FetchPinnedMessagesOptions {\n  before?: DateResolvable;\n  cache?: boolean;\n  limit?: number;\n}\n\nexport interface FetchPinnedMessagesResponse<InGuild extends boolean = boolean> {\n  hasMore: boolean;\n  items: readonly MessagePin<InGuild>[];\n}\n\nexport interface MessagePin<InGuild extends boolean = boolean> {\n  message: Message<InGuild>;\n  get pinnedAt(): Date;\n  pinnedTimestamp: number;\n}\n\nexport interface FetchReactionUsersOptions {\n  after?: Snowflake;\n  limit?: number;\n  type?: ReactionType;\n}\n\nexport interface FetchThreadMemberOptions extends BaseFetchOptions {\n  member: ThreadMemberResolvable;\n  withMember?: boolean;\n}\n\nexport interface FetchThreadOwnerOptions extends BaseFetchOptions {\n  withMember?: boolean;\n}\n\nexport interface FetchThreadMembersWithGuildMemberDataOptions {\n  after?: Snowflake;\n  cache?: boolean;\n  limit?: number;\n  withMember: true;\n}\n\nexport interface FetchThreadMembersWithoutGuildMemberDataOptions {\n  cache?: boolean;\n  withMember?: false;\n}\n\nexport type FetchThreadMembersOptions =\n  | FetchThreadMembersWithGuildMemberDataOptions\n  | FetchThreadMembersWithoutGuildMemberDataOptions;\n\nexport interface FetchThreadsOptions {\n  archived?: FetchArchivedThreadOptions;\n}\n\nexport interface AttachmentPayload {\n  attachment: BufferResolvable | Stream;\n  description?: string;\n  duration?: number;\n  name?: string;\n  title?: string;\n  waveform?: string;\n}\n\nexport type GlobalSweepFilter<Key, Value> = () =>\n  | ((value: Value, key: Key, collection: Collection<Key, Value>) => boolean)\n  | null;\n\nexport interface GuildAuditLogsTypes {\n  [AuditLogEvent.GuildUpdate]: ['Guild', 'Update'];\n  [AuditLogEvent.ChannelCreate]: ['Channel', 'Create'];\n  [AuditLogEvent.ChannelUpdate]: ['Channel', 'Update'];\n  [AuditLogEvent.ChannelDelete]: ['Channel', 'Delete'];\n  [AuditLogEvent.ChannelOverwriteCreate]: ['Channel', 'Create'];\n  [AuditLogEvent.ChannelOverwriteUpdate]: ['Channel', 'Update'];\n  [AuditLogEvent.ChannelOverwriteDelete]: ['Channel', 'Delete'];\n  [AuditLogEvent.MemberKick]: ['User', 'Delete'];\n  [AuditLogEvent.MemberPrune]: ['User', 'Delete'];\n  [AuditLogEvent.MemberBanAdd]: ['User', 'Delete'];\n  [AuditLogEvent.MemberBanRemove]: ['User', 'Create'];\n  [AuditLogEvent.MemberUpdate]: ['User', 'Update'];\n  [AuditLogEvent.MemberRoleUpdate]: ['User', 'Update'];\n  [AuditLogEvent.MemberMove]: ['User', 'Update'];\n  [AuditLogEvent.MemberDisconnect]: ['User', 'Delete'];\n  [AuditLogEvent.BotAdd]: ['User', 'Create'];\n  [AuditLogEvent.RoleCreate]: ['Role', 'Create'];\n  [AuditLogEvent.RoleUpdate]: ['Role', 'Update'];\n  [AuditLogEvent.RoleDelete]: ['Role', 'Delete'];\n  [AuditLogEvent.InviteCreate]: ['Invite', 'Create'];\n  [AuditLogEvent.InviteUpdate]: ['Invite', 'Update'];\n  [AuditLogEvent.InviteDelete]: ['Invite', 'Delete'];\n  [AuditLogEvent.WebhookCreate]: ['Webhook', 'Create'];\n  [AuditLogEvent.WebhookUpdate]: ['Webhook', 'Update'];\n  [AuditLogEvent.WebhookDelete]: ['Webhook', 'Delete'];\n  [AuditLogEvent.EmojiCreate]: ['Emoji', 'Create'];\n  [AuditLogEvent.EmojiUpdate]: ['Emoji', 'Update'];\n  [AuditLogEvent.EmojiDelete]: ['Emoji', 'Delete'];\n  [AuditLogEvent.MessageDelete]: ['Message', 'Delete'];\n  [AuditLogEvent.MessageBulkDelete]: ['Message', 'Delete'];\n  [AuditLogEvent.MessagePin]: ['Message', 'Create'];\n  [AuditLogEvent.MessageUnpin]: ['Message', 'Delete'];\n  [AuditLogEvent.IntegrationCreate]: ['Integration', 'Create'];\n  [AuditLogEvent.IntegrationUpdate]: ['Integration', 'Update'];\n  [AuditLogEvent.IntegrationDelete]: ['Integration', 'Delete'];\n  [AuditLogEvent.StageInstanceCreate]: ['StageInstance', 'Create'];\n  [AuditLogEvent.StageInstanceUpdate]: ['StageInstance', 'Update'];\n  [AuditLogEvent.StageInstanceDelete]: ['StageInstance', 'Delete'];\n  [AuditLogEvent.StickerCreate]: ['Sticker', 'Create'];\n  [AuditLogEvent.StickerUpdate]: ['Sticker', 'Update'];\n  [AuditLogEvent.StickerDelete]: ['Sticker', 'Delete'];\n  [AuditLogEvent.GuildScheduledEventCreate]: ['GuildScheduledEvent', 'Create'];\n  [AuditLogEvent.GuildScheduledEventUpdate]: ['GuildScheduledEvent', 'Update'];\n  [AuditLogEvent.GuildScheduledEventDelete]: ['GuildScheduledEvent', 'Delete'];\n  [AuditLogEvent.ThreadCreate]: ['Thread', 'Create'];\n  [AuditLogEvent.ThreadUpdate]: ['Thread', 'Update'];\n  [AuditLogEvent.ThreadDelete]: ['Thread', 'Delete'];\n  [AuditLogEvent.ApplicationCommandPermissionUpdate]: ['ApplicationCommand', 'Update'];\n  [AuditLogEvent.SoundboardSoundCreate]: ['SoundboardSound', 'Create'];\n  [AuditLogEvent.SoundboardSoundUpdate]: ['SoundboardSound', 'Update'];\n  [AuditLogEvent.SoundboardSoundDelete]: ['SoundboardSound', 'Delete'];\n  [AuditLogEvent.AutoModerationRuleCreate]: ['AutoModeration', 'Create'];\n  [AuditLogEvent.AutoModerationRuleUpdate]: ['AutoModeration', 'Update'];\n  [AuditLogEvent.AutoModerationRuleDelete]: ['AutoModeration', 'Delete'];\n  [AuditLogEvent.AutoModerationBlockMessage]: ['User', 'Update'];\n  [AuditLogEvent.AutoModerationFlagToChannel]: ['User', 'Update'];\n  [AuditLogEvent.AutoModerationUserCommunicationDisabled]: ['User', 'Update'];\n  [AuditLogEvent.OnboardingPromptCreate]: ['GuildOnboardingPrompt', 'Create'];\n  [AuditLogEvent.OnboardingPromptUpdate]: ['GuildOnboardingPrompt', 'Update'];\n  [AuditLogEvent.OnboardingPromptDelete]: ['GuildOnboardingPrompt', 'Delete'];\n  // Never have a target: CreatorMonetizationRequestCreated, CreatorMonetizationTermsAccepted, OnboardingCreate, OnboardingUpdate, HomeSettingsCreate, HomeSettingsUpdate\n}\n\nexport type GuildAuditLogsActionType = GuildAuditLogsTypes[keyof GuildAuditLogsTypes][1] | 'All';\n\nexport interface GuildAuditLogsEntryExtraField {\n  [AuditLogEvent.MemberKick]: { integrationType: string } | null;\n  [AuditLogEvent.MemberRoleUpdate]: { integrationType: string } | null;\n  [AuditLogEvent.MemberPrune]: { days: number; removed: number };\n  [AuditLogEvent.MemberMove]: { channel: VoiceBasedChannel | { id: Snowflake }; count: number };\n  [AuditLogEvent.MessageDelete]: { channel: GuildTextBasedChannel | { id: Snowflake }; count: number };\n  [AuditLogEvent.MessageBulkDelete]: { count: number };\n  [AuditLogEvent.MessagePin]: { channel: GuildTextBasedChannel | { id: Snowflake }; messageId: Snowflake };\n  [AuditLogEvent.MessageUnpin]: { channel: GuildTextBasedChannel | { id: Snowflake }; messageId: Snowflake };\n  [AuditLogEvent.MemberDisconnect]: { count: number };\n  [AuditLogEvent.ChannelOverwriteCreate]:\n    | GuildMember\n    | Role\n    | { id: Snowflake; name: string; type: AuditLogOptionsType.Role }\n    | { id: Snowflake; type: AuditLogOptionsType.Member };\n  [AuditLogEvent.ChannelOverwriteUpdate]:\n    | GuildMember\n    | Role\n    | { id: Snowflake; name: string; type: AuditLogOptionsType.Role }\n    | { id: Snowflake; type: AuditLogOptionsType.Member };\n  [AuditLogEvent.ChannelOverwriteDelete]:\n    | GuildMember\n    | Role\n    | { id: Snowflake; name: string; type: AuditLogOptionsType.Role }\n    | { id: Snowflake; type: AuditLogOptionsType.Member };\n  [AuditLogEvent.StageInstanceCreate]: StageChannel | { id: Snowflake };\n  [AuditLogEvent.StageInstanceDelete]: StageChannel | { id: Snowflake };\n  [AuditLogEvent.StageInstanceUpdate]: StageChannel | { id: Snowflake };\n  [AuditLogEvent.ApplicationCommandPermissionUpdate]: { applicationId: Snowflake };\n  [AuditLogEvent.AutoModerationBlockMessage]: {\n    autoModerationRuleName: string;\n    autoModerationRuleTriggerType: AuditLogRuleTriggerType;\n    channel: GuildTextBasedChannel | { id: Snowflake };\n  };\n  [AuditLogEvent.AutoModerationFlagToChannel]: {\n    autoModerationRuleName: string;\n    autoModerationRuleTriggerType: AuditLogRuleTriggerType;\n    channel: GuildTextBasedChannel | { id: Snowflake };\n  };\n  [AuditLogEvent.AutoModerationUserCommunicationDisabled]: {\n    autoModerationRuleName: string;\n    autoModerationRuleTriggerType: AuditLogRuleTriggerType;\n    channel: GuildTextBasedChannel | { id: Snowflake };\n  };\n}\n\nexport interface GuildAuditLogsEntryTargetField<TAction extends AuditLogEvent> {\n  ApplicationCommand: ApplicationCommand | { id: Snowflake };\n  AutoModeration: AutoModerationRule;\n  Channel: NonThreadGuildBasedChannel | { [x: string]: unknown; id: Snowflake };\n  Emoji: GuildEmoji | { id: Snowflake };\n  Guild: Guild;\n  GuildOnboardingPrompt: GuildOnboardingPrompt | { [x: string]: unknown; id: Snowflake };\n  GuildScheduledEvent: GuildScheduledEvent;\n  Integration: Integration;\n  Invite: GuildInvite;\n  Message: TAction extends AuditLogEvent.MessageBulkDelete ? GuildTextBasedChannel | { id: Snowflake } : User | null;\n  Role: Role | { id: Snowflake };\n  SoundboardSound: SoundboardSound | { id: Snowflake };\n  StageInstance: StageInstance;\n  Sticker: Sticker;\n  Thread: AnyThreadChannel | { [x: string]: unknown; id: Snowflake };\n  User: PartialUser | User | null;\n  Webhook: Webhook<WebhookType.ChannelFollower | WebhookType.Incoming>;\n}\n\nexport interface GuildAuditLogsFetchOptions<Event extends GuildAuditLogsResolvable> {\n  after?: GuildAuditLogsEntry | Snowflake;\n  before?: GuildAuditLogsEntry | Snowflake;\n  limit?: number;\n  type?: Event;\n  user?: UserResolvable;\n}\n\nexport type GuildAuditLogsResolvable = AuditLogEvent | null;\n\nexport type GuildAuditLogsTargetType = GuildAuditLogsTypes[keyof GuildAuditLogsTypes][0] | 'Unknown';\n\nexport type GuildAuditLogsTargets = {\n  [Key in GuildAuditLogsTargetType]: Key;\n};\n\nexport type GuildBanResolvable = GuildBan | UserResolvable;\n\nexport type GuildChannelResolvable = GuildBasedChannel | Snowflake;\n\nexport interface AutoModerationRuleCreateOptions extends AutoModerationRuleEditOptions {\n  actions: readonly AutoModerationActionOptions[];\n  eventType: AutoModerationRuleEventType;\n  name: string;\n  triggerType: AutoModerationRuleTriggerType;\n}\n\nexport interface AutoModerationRuleEditOptions {\n  actions?: readonly AutoModerationActionOptions[];\n  enabled?: boolean;\n  eventType?: AutoModerationRuleEventType;\n  exemptChannels?: ReadonlyCollection<Snowflake, GuildBasedChannel> | readonly GuildChannelResolvable[];\n  exemptRoles?: ReadonlyCollection<Snowflake, Role> | readonly RoleResolvable[];\n  name?: string;\n  reason?: string;\n  triggerMetadata?: AutoModerationTriggerMetadataOptions;\n}\n\nexport interface AutoModerationTriggerMetadataOptions extends AutoModerationTriggerMetadata {}\n\nexport interface AutoModerationActionOptions {\n  metadata?: AutoModerationActionMetadataOptions;\n  type: AutoModerationActionType;\n}\n\nexport interface AutoModerationActionMetadataOptions extends BaseAutoModerationActionMetadata {\n  channel?: GuildTextChannelResolvable | ThreadChannel;\n}\n\nexport interface GuildChannelCreateOptions extends BaseCategoryCreateChannelOptions {\n  name: string;\n}\n\nexport interface GuildChannelCloneOptions extends BaseCategoryCreateChannelOptions {\n  parent?: CategoryChannelResolvable | null;\n}\n\nexport interface GuildChannelEditOptions {\n  availableTags?: readonly GuildForumTagData[];\n  bitrate?: number;\n  defaultAutoArchiveDuration?: ThreadAutoArchiveDuration;\n  defaultForumLayout?: ForumLayoutType;\n  defaultReactionEmoji?: DefaultReactionEmoji | null;\n  defaultSortOrder?: SortOrderType | null;\n  defaultThreadRateLimitPerUser?: number;\n  flags?: ChannelFlagsResolvable;\n  lockPermissions?: boolean;\n  name?: string;\n  nsfw?: boolean;\n  parent?: CategoryChannelResolvable | null;\n  permissionOverwrites?: ReadonlyCollection<Snowflake, OverwriteResolvable> | readonly OverwriteResolvable[];\n  position?: number;\n  rateLimitPerUser?: number;\n  reason?: string;\n  rtcRegion?: string | null;\n  topic?: string | null;\n  type?: ChannelType.GuildAnnouncement | ChannelType.GuildText;\n  userLimit?: number;\n  videoQualityMode?: VideoQualityMode | null;\n}\n\nexport interface GuildChannelOverwriteOptions {\n  reason?: string;\n  type?: OverwriteType;\n}\n\nexport interface GuildWidgetSettings {\n  channel: AnnouncementChannel | ForumChannel | MediaChannel | TextChannel | VoiceBasedChannel | null;\n  enabled: boolean;\n}\n\nexport interface GuildEditOptions {\n  afkChannel?: VoiceChannelResolvable | null;\n  afkTimeout?: number;\n  banner?: Base64Resolvable | BufferResolvable | null;\n  defaultMessageNotifications?: GuildDefaultMessageNotifications | null;\n  description?: string | null;\n  discoverySplash?: Base64Resolvable | BufferResolvable | null;\n  explicitContentFilter?: GuildExplicitContentFilter | null;\n  features?: readonly `${GuildFeature}`[];\n  icon?: Base64Resolvable | BufferResolvable | null;\n  name?: string;\n  preferredLocale?: Locale | null;\n  premiumProgressBarEnabled?: boolean;\n  publicUpdatesChannel?: TextChannelResolvable | null;\n  reason?: string;\n  rulesChannel?: TextChannelResolvable | null;\n  safetyAlertsChannel?: TextChannelResolvable | null;\n  splash?: Base64Resolvable | BufferResolvable | null;\n  systemChannel?: TextChannelResolvable | null;\n  systemChannelFlags?: SystemChannelFlagsResolvable;\n  verificationLevel?: GuildVerificationLevel | null;\n}\n\nexport interface GuildEmojiCreateOptions {\n  attachment: Base64Resolvable | BufferResolvable;\n  name: string;\n  reason?: string;\n  roles?: ReadonlyCollection<Snowflake, Role> | readonly RoleResolvable[];\n}\n\nexport interface GuildEmojiEditOptions {\n  name?: string;\n  reason?: string;\n  roles?: ReadonlyCollection<Snowflake, Role> | readonly RoleResolvable[];\n}\n\nexport interface GuildStickerCreateOptions {\n  description?: string | null;\n  file: AttachmentPayload | BufferResolvable | Stream;\n  name: string;\n  reason?: string;\n  tags: string;\n}\n\nexport interface GuildStickerEditOptions {\n  description?: string | null;\n  name?: string;\n  reason?: string;\n  tags?: string;\n}\n\nexport interface GuildMemberEditOptions {\n  channel?: GuildVoiceChannelResolvable | null;\n  communicationDisabledUntil?: DateResolvable | null;\n  deaf?: boolean;\n  flags?: GuildMemberFlagsResolvable;\n  mute?: boolean;\n  nick?: string | null;\n  reason?: string;\n  roles?: ReadonlyCollection<Snowflake, Role> | readonly RoleResolvable[];\n}\n\nexport interface GuildMemberEditMeOptions {\n  avatar?: Base64Resolvable | BufferResolvable | null;\n  banner?: Base64Resolvable | BufferResolvable | null;\n  bio?: string | null;\n  nick?: string | null;\n  reason?: string;\n}\n\nexport type GuildResolvable =\n  | Guild\n  | GuildEmoji\n  | GuildInvite\n  | GuildMember\n  | NonThreadGuildBasedChannel\n  | Role\n  | Snowflake;\n\nexport interface GuildPruneMembersOptions {\n  count?: boolean;\n  days?: number;\n  dry?: boolean;\n  reason?: string;\n  roles?: readonly RoleResolvable[];\n}\n\nexport interface GuildWidgetSettingsData {\n  channel: AnnouncementChannel | ForumChannel | MediaChannel | Snowflake | TextChannel | VoiceBasedChannel | null;\n  enabled: boolean;\n}\n\nexport interface GuildSearchMembersOptions {\n  cache?: boolean;\n  limit?: number;\n  query: string;\n}\n\nexport interface GuildListMembersOptions {\n  after?: Snowflake;\n  cache?: boolean;\n  limit?: number;\n}\n\nexport interface BaseGuildScheduledEventOptions {\n  channel?: GuildVoiceChannelResolvable | null;\n  description?: string;\n  entityMetadata?: GuildScheduledEventEntityMetadataOptions;\n  entityType?: GuildScheduledEventEntityType;\n  image?: Base64Resolvable | BufferResolvable | null;\n  name?: string;\n  privacyLevel?: GuildScheduledEventPrivacyLevel;\n  reason?: string;\n  recurrenceRule?: GuildScheduledEventRecurrenceRuleOptions | null;\n  scheduledEndTime?: DateResolvable;\n  scheduledStartTime?: DateResolvable;\n}\n\n// TODO: use conditional types for better TS support\nexport interface GuildScheduledEventCreateOptions extends BaseGuildScheduledEventOptions {\n  channel?: GuildVoiceChannelResolvable;\n  entityType: GuildScheduledEventEntityType;\n  name: string;\n  privacyLevel: GuildScheduledEventPrivacyLevel;\n  recurrenceRule?: GuildScheduledEventRecurrenceRuleOptions;\n  scheduledStartTime: DateResolvable;\n}\n\nexport type GuildScheduledEventRecurrenceRuleOptions =\n  | BaseGuildScheduledEventRecurrenceRuleOptions<\n      GuildScheduledEventRecurrenceRuleFrequency.Daily | GuildScheduledEventRecurrenceRuleFrequency.Weekly,\n      {\n        byWeekday: readonly GuildScheduledEventRecurrenceRuleWeekday[];\n      }\n    >\n  | BaseGuildScheduledEventRecurrenceRuleOptions<\n      GuildScheduledEventRecurrenceRuleFrequency.Monthly,\n      {\n        byNWeekday: readonly GuildScheduledEventRecurrenceRuleNWeekday[];\n      }\n    >\n  | BaseGuildScheduledEventRecurrenceRuleOptions<\n      GuildScheduledEventRecurrenceRuleFrequency.Yearly,\n      {\n        byMonth: readonly GuildScheduledEventRecurrenceRuleMonth[];\n        byMonthDay: readonly number[];\n      }\n    >;\n\nexport type BaseGuildScheduledEventRecurrenceRuleOptions<\n  Frequency extends GuildScheduledEventRecurrenceRuleFrequency,\n  Extra extends {},\n> = Extra & {\n  frequency: Frequency;\n  interval: number;\n  startAt: DateResolvable;\n};\n\nexport interface GuildScheduledEventEditOptions<\n  Status extends GuildScheduledEventStatus,\n  AcceptableStatus extends GuildScheduledEventSetStatusArg<Status>,\n> extends BaseGuildScheduledEventOptions {\n  status?: AcceptableStatus;\n}\n\nexport interface GuildScheduledEventEntityMetadata {\n  location: string | null;\n}\n\nexport interface GuildScheduledEventEntityMetadataOptions {\n  location?: string;\n}\n\nexport type GuildScheduledEventManagerFetchResult<\n  Options extends FetchGuildScheduledEventOptions | FetchGuildScheduledEventsOptions | GuildScheduledEventResolvable,\n> = Options extends FetchGuildScheduledEventOptions | GuildScheduledEventResolvable\n  ? GuildScheduledEvent\n  : Collection<Snowflake, GuildScheduledEvent>;\n\nexport type GuildScheduledEventManagerFetchSubscribersResult<\n  Options extends FetchGuildScheduledEventSubscribersOptions,\n> = Options extends { withMember: true }\n  ? Collection<Snowflake, GuildScheduledEventUser<true>>\n  : Collection<Snowflake, GuildScheduledEventUser<false>>;\n\nexport type GuildScheduledEventResolvable = GuildScheduledEvent | Snowflake;\n\nexport type GuildScheduledEventSetStatusArg<Status extends GuildScheduledEventStatus> =\n  Status extends GuildScheduledEventStatus.Scheduled\n    ? GuildScheduledEventStatus.Active | GuildScheduledEventStatus.Canceled\n    : Status extends GuildScheduledEventStatus.Active\n      ? GuildScheduledEventStatus.Completed\n      : never;\n\nexport interface GuildScheduledEventUser<WithMember> {\n  guildScheduledEventId: Snowflake;\n  member: WithMember extends true ? GuildMember : null;\n  user: User;\n}\n\nexport type GuildTemplateResolvable = string;\n\nexport type GuildVoiceChannelResolvable = Snowflake | VoiceBasedChannel;\n\nexport interface GuildOnboardingEditOptions {\n  defaultChannels?: ReadonlyCollection<Snowflake, GuildChannel> | readonly ChannelResolvable[];\n  enabled?: boolean;\n  mode?: GuildOnboardingMode;\n  prompts?: ReadonlyCollection<Snowflake, GuildOnboardingPrompt> | readonly GuildOnboardingPromptData[];\n  reason?: string;\n}\n\nexport interface GuildOnboardingPromptData {\n  id?: Snowflake;\n  inOnboarding?: boolean;\n  options: ReadonlyCollection<Snowflake, GuildOnboardingPromptOption> | readonly GuildOnboardingPromptOptionData[];\n  required?: boolean;\n  singleSelect?: boolean;\n  title: string;\n  type?: GuildOnboardingPromptType;\n}\n\nexport interface GuildOnboardingPromptOptionData {\n  channels?: ReadonlyCollection<Snowflake, GuildChannel> | readonly ChannelResolvable[];\n  description?: string | null;\n  emoji?: Emoji | EmojiIdentifierResolvable | null;\n  id?: Snowflake | null;\n  roles?: ReadonlyCollection<Snowflake, Role> | readonly RoleResolvable[];\n  title: string;\n}\n\nexport type HexColorString = `#${string}`;\n\nexport interface IncidentActions {\n  dmSpamDetectedAt: Date | null;\n  dmsDisabledUntil: Date | null;\n  invitesDisabledUntil: Date | null;\n  raidDetectedAt: Date | null;\n}\n\nexport interface IncidentActionsEditOptions {\n  dmsDisabledUntil?: DateResolvable | null | undefined;\n  invitesDisabledUntil?: DateResolvable | null | undefined;\n}\n\nexport interface IntegrationAccount {\n  id: Snowflake | string;\n  name: string;\n}\n\nexport type IntegrationType = 'discord' | 'guild_subscription' | 'twitch' | 'youtube';\n\nexport type IntegrationTypesConfigurationParameters = ClientApplicationInstallParams;\n\nexport interface IntegrationTypesConfigurationContext {\n  oauth2InstallParams: IntegrationTypesConfigurationParameters | null;\n}\n\nexport type IntegrationTypesConfiguration = Partial<\n  Record<ApplicationIntegrationType, IntegrationTypesConfigurationContext>\n>;\n\nexport type CollectedInteraction<Cached extends CacheType = CacheType> =\n  | ButtonInteraction<Cached>\n  | ChannelSelectMenuInteraction<Cached>\n  | MentionableSelectMenuInteraction<Cached>\n  | ModalSubmitInteraction<Cached>\n  | RoleSelectMenuInteraction<Cached>\n  | StringSelectMenuInteraction<Cached>\n  | UserSelectMenuInteraction<Cached>;\n\nexport interface InteractionCollectorOptions<\n  Interaction extends CollectedInteraction,\n  Cached extends CacheType = CacheType,\n> extends CollectorOptions<[Interaction]> {\n  channel?: TextBasedChannelResolvable;\n  componentType?: ComponentType;\n  guild?: GuildResolvable;\n  interactionType?: InteractionType;\n  max?: number;\n  maxComponents?: number;\n  maxUsers?: number;\n  message?: CacheTypeReducer<Cached, Message, APIMessage>;\n}\n\nexport interface InteractionDeferReplyOptions {\n  flags?: BitFieldResolvable<Extract<MessageFlagsString, 'Ephemeral'>, MessageFlags.Ephemeral> | undefined;\n  withResponse?: boolean;\n}\n\nexport interface InteractionDeferUpdateOptions {\n  withResponse?: boolean;\n}\n\nexport interface InteractionReplyOptions extends BaseMessageSendOptions, MessageOptionsPoll {\n  flags?:\n    | BitFieldResolvable<\n        Extract<\n          MessageFlagsString,\n          'Ephemeral' | 'IsComponentsV2' | 'IsVoiceMessage' | 'SuppressEmbeds' | 'SuppressNotifications'\n        >,\n        | MessageFlags.Ephemeral\n        | MessageFlags.IsComponentsV2\n        | MessageFlags.IsVoiceMessage\n        | MessageFlags.SuppressEmbeds\n        | MessageFlags.SuppressNotifications\n      >\n    | undefined;\n  tts?: boolean;\n  withResponse?: boolean;\n}\n\nexport interface InteractionUpdateOptions extends MessageEditOptions {\n  withResponse?: boolean;\n}\n\nexport interface InviteGenerationOptions {\n  disableGuildSelect?: boolean;\n  guild?: GuildResolvable;\n  permissions?: PermissionResolvable;\n  scopes: readonly OAuth2Scopes[];\n}\n\nexport type GuildInvitableChannel = AnnouncementChannel | ForumChannel | MediaChannel | TextChannel | VoiceChannel;\n\nexport type GuildInvitableChannelResolvable = GuildInvitableChannel | Snowflake;\n\nexport interface InviteCreateOptions {\n  maxAge?: number;\n  maxUses?: number;\n  reason?: string;\n  targetApplication?: ApplicationResolvable;\n  targetType?: InviteTargetType;\n  targetUser?: UserResolvable;\n  temporary?: boolean;\n  unique?: boolean;\n}\n\nexport type InviteResolvable = string;\nexport type GuildInviteResolvable = string;\n\nexport interface LifetimeFilterOptions<Key, Value> {\n  excludeFromSweep?(value: Value, key: Key, collection: LimitedCollection<Key, Value>): boolean;\n  getComparisonTimestamp?(value: Value, key: Key, collection: LimitedCollection<Key, Value>): number;\n  lifetime?: number;\n}\n\nexport type ActionRowComponentOptions =\n  | ButtonComponentData\n  | ChannelSelectMenuComponentData\n  | MentionableSelectMenuComponentData\n  | RoleSelectMenuComponentData\n  | StringSelectMenuComponentData\n  | UserSelectMenuComponentData;\n\nexport type MessageActionRowComponentResolvable = ActionRowComponentOptions | MessageActionRowComponent;\n\nexport interface MessageActivity {\n  partyId?: string;\n  type: MessageActivityType;\n}\n\nexport interface BaseButtonComponentData extends BaseComponentData {\n  disabled?: boolean;\n  emoji?: ComponentEmojiResolvable;\n  label?: string;\n  style: ButtonStyle;\n  type: ComponentType.Button;\n}\n\nexport interface LinkButtonComponentData extends BaseButtonComponentData {\n  style: ButtonStyle.Link;\n  url: string;\n}\n\nexport interface InteractionButtonComponentData extends BaseButtonComponentData {\n  customId: string;\n  style: Exclude<ButtonStyle, ButtonStyle.Link>;\n}\n\nexport type ButtonComponentData = InteractionButtonComponentData | LinkButtonComponentData;\n\nexport interface MessageCollectorOptions extends CollectorOptions<[Message, Collection<Snowflake, Message>]> {\n  max?: number;\n  maxProcessed?: number;\n}\n\nexport type CollectedMessageInteraction<Cached extends CacheType = CacheType> = Exclude<\n  CollectedInteraction<Cached>,\n  ModalSubmitInteraction\n>;\n\nexport interface MessageComponentCollectorOptions<\n  Interaction extends CollectedMessageInteraction,\n> extends AwaitMessageComponentOptions<Interaction> {\n  max?: number;\n  maxComponents?: number;\n  maxUsers?: number;\n}\n\nexport interface MessageChannelComponentCollectorOptions<\n  Interaction extends CollectedMessageInteraction,\n  Cached extends CacheType = CacheType,\n> extends MessageComponentCollectorOptions<Interaction> {\n  message?: CacheTypeReducer<Cached, Message, APIMessage>;\n}\n\nexport interface MessageInteractionMetadata {\n  authorizingIntegrationOwners: AuthorizingIntegrationOwners;\n  id: Snowflake;\n  interactedMessageId: Snowflake | null;\n  originalResponseMessageId: Snowflake | null;\n  triggeringInteractionMetadata: MessageInteractionMetadata | null;\n  type: InteractionType;\n  user: User;\n}\n\nexport interface MessageMentionsHasOptions {\n  ignoreDirect?: boolean;\n  ignoreEveryone?: boolean;\n  ignoreRepliedUser?: boolean;\n  ignoreRoles?: boolean;\n}\n\nexport interface MessageMentionOptions {\n  parse?: readonly MessageMentionTypes[];\n  repliedUser?: boolean;\n  roles?: readonly Snowflake[];\n  users?: readonly Snowflake[];\n}\n\nexport type MessageMentionTypes = 'everyone' | 'roles' | 'users';\n\nexport interface MessageSnapshot extends Partialize<\n  Message,\n  null,\n  Exclude<\n    keyof Message,\n    | 'attachments'\n    | 'client'\n    | 'components'\n    | 'content'\n    | 'createdTimestamp'\n    | 'editedTimestamp'\n    | 'embeds'\n    | 'flags'\n    | 'mentions'\n    | 'stickers'\n    | 'type'\n  >\n> {}\n\nexport interface BaseMessageOptions {\n  allowedMentions?: MessageMentionOptions;\n  components?: readonly (\n    | ActionRowData<JSONEncodable<APIComponentInMessageActionRow> | MessageActionRowComponentData>\n    | APIMessageTopLevelComponent\n    | JSONEncodable<APIActionRowComponent<APIComponentInActionRow>>\n    | JSONEncodable<APIMessageTopLevelComponent>\n    | TopLevelComponentData\n  )[];\n  content?: string | null;\n  embeds?: readonly (APIEmbed | JSONEncodable<APIEmbed>)[];\n  files?: readonly (Attachment | AttachmentPayload | BufferResolvable | FileBodyEncodable<APIAttachment> | Stream)[];\n}\n\nexport interface BaseMessageSendOptions extends BaseMessageOptions {\n  content?: string;\n}\n\nexport interface MessageOptionsPoll {\n  poll?: JSONEncodable<RESTAPIPoll> | PollData;\n}\n\nexport interface MessageOptionsFlags {\n  flags?:\n    | BitFieldResolvable<\n        Extract<MessageFlagsString, 'IsComponentsV2' | 'IsVoiceMessage' | 'SuppressEmbeds' | 'SuppressNotifications'>,\n        | MessageFlags.IsComponentsV2\n        | MessageFlags.IsVoiceMessage\n        | MessageFlags.SuppressEmbeds\n        | MessageFlags.SuppressNotifications\n      >\n    | undefined;\n}\n\nexport interface MessageOptionsTTS {\n  tts?: boolean;\n}\n\nexport interface MessageOptionsStickers {\n  stickers?: readonly StickerResolvable[];\n}\n\nexport interface BaseMessageCreateOptions\n  extends BaseMessageSendOptions, MessageOptionsPoll, MessageOptionsFlags, MessageOptionsTTS, MessageOptionsStickers {\n  enforceNonce?: boolean;\n  nonce?: number | string;\n}\n\nexport interface MessageCreateOptions extends BaseMessageCreateOptions {\n  messageReference?: MessageReferenceOptions;\n}\n\nexport interface GuildForumThreadMessageCreateOptions\n  extends BaseMessageSendOptions, MessageOptionsFlags, MessageOptionsStickers {}\n\nexport interface MessageEditOptions extends BaseMessageOptions {\n  attachments?: readonly (Attachment | JSONEncodable<APIAttachment>)[];\n  flags?:\n    | BitFieldResolvable<\n        Extract<MessageFlagsString, 'IsComponentsV2' | 'SuppressEmbeds'>,\n        MessageFlags.IsComponentsV2 | MessageFlags.SuppressEmbeds\n      >\n    | undefined;\n}\n\nexport type MessageReactionResolvable = MessageReaction | Snowflake | string;\n\nexport interface MessageReference {\n  channelId: Snowflake;\n  guildId: Snowflake | undefined;\n  messageId: Snowflake | undefined;\n  type: MessageReferenceType;\n}\n\nexport interface MessageReferenceOptions extends MessageReference {\n  failIfNotExists?: boolean;\n}\n\nexport type MessageResolvable = Message | Snowflake;\n\nexport interface BaseSelectMenuComponentData extends BaseComponentData {\n  customId: string;\n  disabled?: boolean;\n  maxValues?: number;\n  minValues?: number;\n  placeholder?: string;\n  required?: boolean;\n}\n\nexport interface StringSelectMenuComponentData extends BaseSelectMenuComponentData {\n  options: readonly SelectMenuComponentOptionData[];\n  type: ComponentType.StringSelect;\n}\n\nexport interface UserSelectMenuComponentData extends BaseSelectMenuComponentData {\n  defaultValues?: readonly APISelectMenuDefaultValue<SelectMenuDefaultValueType.User>[];\n  type: ComponentType.UserSelect;\n}\n\nexport interface RoleSelectMenuComponentData extends BaseSelectMenuComponentData {\n  defaultValues?: readonly APISelectMenuDefaultValue<SelectMenuDefaultValueType.Role>[];\n  type: ComponentType.RoleSelect;\n}\n\nexport interface MentionableSelectMenuComponentData extends BaseSelectMenuComponentData {\n  defaultValues?: readonly APISelectMenuDefaultValue<\n    SelectMenuDefaultValueType.Role | SelectMenuDefaultValueType.User\n  >[];\n  type: ComponentType.MentionableSelect;\n}\n\nexport interface ChannelSelectMenuComponentData extends BaseSelectMenuComponentData {\n  channelTypes?: readonly ChannelType[];\n  defaultValues?: readonly APISelectMenuDefaultValue<SelectMenuDefaultValueType.Channel>[];\n  type: ComponentType.ChannelSelect;\n}\n\nexport interface MessageSelectOption {\n  default: boolean;\n  description: string | null;\n  emoji: APIPartialEmoji | null;\n  label: string;\n  value: string;\n}\n\nexport interface ReactionCountDetailsData {\n  burst: number;\n  normal: number;\n}\n\nexport interface SelectMenuComponentOptionData {\n  default?: boolean;\n  description?: string;\n  emoji?: ComponentEmojiResolvable;\n  label: string;\n  value: string;\n}\n\nexport interface TextInputComponentData extends BaseComponentData {\n  customId: string;\n  maxLength?: number;\n  minLength?: number;\n  placeholder?: string;\n  required?: boolean;\n  style: TextInputStyle;\n  type: ComponentType.TextInput;\n  value?: string;\n}\n\nexport interface FileUploadComponentData extends BaseComponentData {\n  customId: string;\n  maxValues?: number;\n  minValues?: number;\n  required?: boolean;\n  type: ComponentType.FileUpload;\n}\n\nexport interface RadioGroupOption {\n  default?: boolean;\n  description?: string;\n  label: string;\n  value: string;\n}\nexport interface RadioGroupComponentData extends BaseComponentData {\n  customId: string;\n  options: readonly RadioGroupOption[];\n  required?: boolean;\n  type: ComponentType.RadioGroup;\n}\n\nexport interface CheckboxGroupOption {\n  default?: boolean;\n  description?: string;\n  label: string;\n  value: string;\n}\nexport interface CheckboxGroupComponentData extends BaseComponentData {\n  customId: string;\n  maxValues?: number;\n  minValues?: number;\n  options: readonly CheckboxGroupOption[];\n  required?: boolean;\n  type: ComponentType.CheckboxGroup;\n}\n\nexport interface CheckboxComponentData extends BaseComponentData {\n  customId: string;\n  default?: boolean;\n  type: ComponentType.Checkbox;\n}\n\nexport type MessageTarget =\n  | ChannelManager\n  | Interaction\n  | InteractionWebhook\n  | Message\n  | MessageManager\n  | TextBasedChannel\n  | Webhook<WebhookType.Incoming>;\n\nexport interface MultipleShardRespawnOptions {\n  respawnDelay?: number;\n  shardDelay?: number;\n  timeout?: number;\n}\n\nexport interface MultipleShardSpawnOptions {\n  amount?: number | 'auto';\n  delay?: number;\n  timeout?: number;\n}\n\nexport interface BaseOverwriteData {\n  allow?: PermissionResolvable;\n  deny?: PermissionResolvable;\n  id: RoleResolvable | UserResolvable;\n  type?: OverwriteType;\n}\n\nexport interface OverwriteDataWithMandatoryType extends BaseOverwriteData {\n  type: OverwriteType;\n}\n\nexport interface OverwriteDataWithOptionalType extends BaseOverwriteData {\n  id: Exclude<RoleResolvable | UserResolvable, Snowflake>;\n}\n\nexport type OverwriteData = OverwriteDataWithMandatoryType | OverwriteDataWithOptionalType;\n\nexport type OverwriteResolvable = OverwriteData | PermissionOverwrites;\n\nexport type PermissionFlags = Record<keyof typeof PermissionFlagsBits, bigint>;\n\nexport type PermissionOverwriteOptions = Partial<Record<keyof typeof PermissionFlagsBits, boolean | null>>;\n\nexport type PermissionResolvable = BitFieldResolvable<keyof typeof PermissionFlagsBits, bigint>;\n\nexport type PermissionOverwriteResolvable = PermissionOverwrites | RoleResolvable | UserResolvable;\n\nexport interface RecursiveReadonlyArray<ItemType> extends ReadonlyArray<ItemType | RecursiveReadonlyArray<ItemType>> {}\n\nexport interface PartialRecipient {\n  username: string;\n}\n\nexport interface PresenceData {\n  activities?: readonly ActivitiesOptions[];\n  afk?: boolean;\n  shardId?: number | readonly number[];\n  status?: PresenceStatusData;\n}\n\nexport type PresenceResolvable = Presence | Snowflake | UserResolvable;\n\nexport interface PartialEmoji {\n  animated: boolean;\n  id: Snowflake | undefined;\n  name: string;\n}\n\nexport interface PartialEmojiOnlyId {\n  id: Snowflake;\n}\n\nexport type Partialize<\n  PartialType extends AllowedPartial,\n  NulledKeys extends keyof PartialType | null = null,\n  NullableKeys extends keyof PartialType | null = null,\n  OverridableKeys extends keyof PartialType | '' = '',\n> = {\n  [K in keyof Omit<PartialType, OverridableKeys>]: K extends 'partial'\n    ? true\n    : K extends NulledKeys\n      ? null\n      : K extends NullableKeys\n        ? PartialType[K] | null\n        : PartialType[K];\n};\n\nexport interface PartialDMChannel extends Partialize<DMChannel, null, null, 'lastMessageId'> {\n  lastMessageId: undefined;\n}\n\nexport interface PartialGuildMember extends Partialize<GuildMember, 'joinedAt' | 'joinedTimestamp' | 'pending'> {}\n\nexport interface PartialMessage<InGuild extends boolean = boolean> extends Partialize<\n  Message<InGuild>,\n  'pinned' | 'system' | 'tts' | 'type',\n  'author' | 'cleanContent' | 'content'\n> {}\n\nexport interface PartialMessageReaction extends Partialize<MessageReaction, 'count'> {}\n\nexport interface PartialPoll extends Partialize<\n  Poll,\n  'allowMultiselect' | 'expiresTimestamp' | 'layoutType',\n  null,\n  'answers' | 'message' | 'question'\n> {\n  // eslint-disable-next-line no-restricted-syntax\n  answers: Collection<number, PartialPollAnswer>;\n  message: PartialMessage;\n  question: { text: null };\n}\n\nexport interface PartialPollAnswer extends Partialize<PollAnswer, 'emoji' | 'text', null, 'poll'> {\n  readonly poll: PartialPoll;\n}\n\nexport interface PartialGuildScheduledEvent extends Partialize<\n  GuildScheduledEvent,\n  'userCount',\n  'entityType' | 'name' | 'privacyLevel' | 'status'\n> {}\n\nexport interface PartialThreadMember extends Partialize<ThreadMember, 'flags' | 'joinedAt' | 'joinedTimestamp'> {}\n\nexport interface PartialSoundboardSound extends Partialize<SoundboardSound, 'available' | 'name' | 'volume'> {}\n\nexport enum Partials {\n  User,\n  Channel,\n  GuildMember,\n  Message,\n  Reaction,\n  GuildScheduledEvent,\n  ThreadMember,\n  Poll,\n  PollAnswer,\n  SoundboardSound,\n}\n\nexport interface PartialUser extends Partialize<User, 'discriminator' | 'tag' | 'username'> {}\n\nexport type PresenceStatusData = ClientPresenceStatus | 'invisible';\n\nexport type PresenceStatus = PresenceStatusData | 'offline';\n\nexport interface ReactionCollectorOptions extends CollectorOptions<[MessageReaction, User]> {\n  max?: number;\n  maxEmojis?: number;\n  maxUsers?: number;\n}\n\nexport interface MessageReplyOptions extends BaseMessageCreateOptions {\n  failIfNotExists?: boolean;\n}\n\nexport interface ResolvedOverwriteOptions {\n  allow: PermissionsBitField;\n  deny: PermissionsBitField;\n}\n\nexport interface RoleData {\n  colors?: RoleColorsResolvable;\n  hoist?: boolean;\n  icon?: Base64Resolvable | BufferResolvable | EmojiResolvable | null;\n  mentionable?: boolean;\n  name?: string;\n  permissions?: PermissionResolvable;\n  position?: number;\n  unicodeEmoji?: string | null;\n}\n\nexport type RoleMention = '@everyone' | `<@&${Snowflake}>`;\n\nexport interface RolePosition {\n  position: number;\n  role: RoleResolvable;\n}\n\nexport type RoleResolvable = Role | Snowflake;\n\nexport interface RoleSubscriptionData {\n  isRenewal: boolean;\n  roleSubscriptionListingId: Snowflake;\n  tierName: string;\n  totalMonthsSubscribed: number;\n}\n\nexport interface RoleTagData {\n  availableForPurchase?: true;\n  botId?: Snowflake;\n  guildConnections?: true;\n  integrationId?: Snowflake;\n  premiumSubscriberRole?: true;\n  subscriptionListingId?: Snowflake;\n}\n\nexport interface SetChannelPositionOptions {\n  reason?: string;\n  relative?: boolean;\n}\n\nexport interface SetParentOptions {\n  lockPermissions?: boolean;\n  reason?: string;\n}\n\nexport interface SetRolePositionOptions {\n  reason?: string;\n  relative?: boolean;\n}\n\nexport type ShardingManagerMode = 'process' | 'worker';\n\nexport interface ShardingManagerOptions {\n  execArgv?: readonly string[];\n  mode?: ShardingManagerMode;\n  respawn?: boolean;\n  shardArgs?: readonly string[];\n  shardList?: readonly number[] | 'auto';\n  silent?: boolean;\n  token?: string;\n  totalShards?: number | 'auto';\n}\n\nexport interface ShowModalOptions {\n  withResponse?: boolean;\n}\n\nexport interface LaunchActivityOptions {\n  withResponse?: boolean;\n}\n\nexport type StageInstanceResolvable = Snowflake | StageInstance;\n\nexport interface StartThreadOptions {\n  autoArchiveDuration?: ThreadAutoArchiveDuration;\n  name: string;\n  rateLimitPerUser?: number;\n  reason?: string;\n}\n\nexport type ClientStatus = number;\n\nexport type StickerResolvable = Snowflake | Sticker;\n\nexport type SystemChannelFlagsResolvable = BitFieldResolvable<SystemChannelFlagsString, number>;\n\nexport type StageChannelResolvable = Snowflake | StageChannel;\n\nexport interface StageInstanceEditOptions {\n  privacyLevel?: StageInstancePrivacyLevel;\n  topic?: string;\n}\n\nexport type SweeperKey = keyof SweeperDefinitions;\n\nexport type CollectionSweepFilter<Key, Value> = (value: Value, key: Key, collection: Collection<Key, Value>) => boolean;\n\nexport interface SweepOptions<Key, Value> {\n  filter: GlobalSweepFilter<Key, Value>;\n  interval: number;\n}\n\nexport interface LifetimeSweepOptions {\n  filter?: never;\n  interval: number;\n  lifetime: number;\n}\n\nexport interface SweeperDefinitions {\n  applicationCommands: [Snowflake, ApplicationCommand];\n  autoModerationRules: [Snowflake, AutoModerationRule];\n  bans: [Snowflake, GuildBan];\n  emojis: [Snowflake, GuildEmoji];\n  entitlements: [Snowflake, Entitlement];\n  guildMembers: [Snowflake, GuildMember];\n  invites: [string, GuildInvite, true];\n  messages: [Snowflake, Message, true];\n  presences: [Snowflake, Presence];\n  reactions: [Snowflake | string, MessageReaction];\n  stageInstances: [Snowflake, StageInstance];\n  stickers: [Snowflake, Sticker];\n  threadMembers: [Snowflake, ThreadMember];\n  threads: [Snowflake, AnyThreadChannel, true];\n  users: [Snowflake, User];\n  voiceStates: [Snowflake, VoiceState];\n}\n\nexport type SweeperOptions = {\n  [Key in keyof SweeperDefinitions]?: SweeperDefinitions[Key][2] extends true\n    ? LifetimeSweepOptions | SweepOptions<SweeperDefinitions[Key][0], SweeperDefinitions[Key][1]>\n    : SweepOptions<SweeperDefinitions[Key][0], SweeperDefinitions[Key][1]>;\n};\n\nexport interface LimitedCollectionOptions<Key, Value> {\n  keepOverLimit?(value: Value, key: Key, collection: LimitedCollection<Key, Value>): boolean;\n  maxSize?: number;\n}\n\nexport type Channel =\n  | AnnouncementChannel\n  | CategoryChannel\n  | DMChannel\n  | ForumChannel\n  | MediaChannel\n  | PartialDMChannel\n  | PartialGroupDMChannel\n  | PrivateThreadChannel\n  | PublicThreadChannel\n  | StageChannel\n  | TextChannel\n  | VoiceChannel;\n\nexport type TextBasedChannel = Exclude<Extract<Channel, { type: TextChannelType }>, ForumChannel | MediaChannel>;\n\nexport type TextBasedChannels = TextBasedChannel;\n\nexport type TextBasedChannelTypes = TextBasedChannel['type'];\n\nexport type GuildTextBasedChannelTypes = Exclude<TextBasedChannelTypes, ChannelType.DM | ChannelType.GroupDM>;\n\nexport type VoiceBasedChannel = Extract<Channel, { bitrate: number }>;\n\nexport type GuildBasedChannel = Extract<Channel, { guild: Guild }>;\n\nexport type SendableChannels = Extract<Channel, { send(...args: any[]): any }>;\n\nexport type CategoryChildChannel = Exclude<Extract<Channel, { parent: CategoryChannel | null }>, CategoryChannel>;\n\nexport type NonThreadGuildBasedChannel = Exclude<GuildBasedChannel, AnyThreadChannel>;\n\nexport type GuildTextBasedChannel = Extract<GuildBasedChannel, TextBasedChannel>;\n\nexport type SendableChannelTypes = SendableChannels['type'];\n\nexport type TextChannelResolvable = Snowflake | TextChannel;\n\nexport type TextBasedChannelResolvable = Snowflake | TextBasedChannel;\n\nexport type ThreadChannelResolvable = Snowflake | ThreadChannel;\n\nexport interface GuildTextThreadCreateOptions<AllowedThreadType> extends StartThreadOptions {\n  invitable?: AllowedThreadType extends ChannelType.PrivateThread ? boolean : never;\n  startMessage?: MessageResolvable;\n  type?: AllowedThreadType;\n}\n\nexport interface GuildForumThreadCreateOptions extends StartThreadOptions {\n  appliedTags?: readonly Snowflake[];\n  message: GuildForumThreadMessageCreateOptions | MessagePayload;\n}\n\nexport interface ThreadEditOptions {\n  appliedTags?: readonly Snowflake[];\n  archived?: boolean;\n  autoArchiveDuration?: ThreadAutoArchiveDuration;\n  flags?: ChannelFlagsResolvable;\n  invitable?: boolean;\n  locked?: boolean;\n  name?: string;\n  rateLimitPerUser?: number;\n  reason?: string;\n}\n\nexport type ThreadMemberResolvable = ThreadMember | UserResolvable;\n\nexport type UserMention = `<@${Snowflake}>`;\n\nexport type UserResolvable = GuildMember | Message | Snowflake | ThreadMember | User;\n\nexport interface Vanity {\n  code: string | null;\n  uses: number;\n}\n\nexport type VoiceBasedChannelTypes = VoiceBasedChannel['type'];\n\nexport type VoiceChannelResolvable = Snowflake | VoiceChannel;\n\nexport interface VoiceStateEditOptions {\n  requestToSpeak?: boolean;\n  suppressed?: boolean;\n}\n\nexport interface WebhookDataIdWithToken {\n  id: Snowflake;\n  token: string;\n}\n\nexport interface WebhookDeleteOptions {\n  reason?: string;\n  token?: string;\n}\n\nexport interface WebhookEditOptions {\n  avatar?: BufferResolvable | null;\n  channel?: ForumChannel | GuildTextChannelResolvable | MediaChannel | StageChannel | VoiceChannel;\n  name?: string;\n  reason?: string;\n}\n\nexport interface WebhookMessageEditOptions extends MessageEditOptions {\n  threadId?: Snowflake;\n  withComponents?: boolean;\n}\n\nexport interface InteractionEditReplyOptions extends WebhookMessageEditOptions, MessageOptionsPoll {\n  message?: MessageResolvable | '@original';\n}\n\nexport interface WebhookFetchMessageOptions {\n  threadId?: Snowflake;\n}\n\nexport interface WebhookMessageCreateOptions\n  extends BaseMessageSendOptions, MessageOptionsPoll, MessageOptionsFlags, MessageOptionsTTS {\n  appliedTags?: readonly Snowflake[];\n  avatarURL?: string;\n  threadId?: Snowflake;\n  threadName?: string;\n  username?: string;\n  withComponents?: boolean;\n}\n\nexport interface WidgetActivity {\n  name: string;\n}\n\nexport interface WidgetChannel {\n  id: Snowflake;\n  name: string;\n  position: number;\n}\n\nexport interface WelcomeChannelData {\n  channel: AnnouncementChannel | ForumChannel | MediaChannel | Snowflake | TextChannel;\n  description: string;\n  emoji?: EmojiIdentifierResolvable;\n}\n\nexport interface WelcomeScreenEditOptions {\n  description?: string;\n  enabled?: boolean;\n  welcomeChannels?: readonly WelcomeChannelData[];\n}\n\nexport interface ClientApplicationEditOptions {\n  coverImage?: Base64Resolvable | BufferResolvable | null;\n  customInstallURL?: string;\n  description?: string;\n  eventWebhooksStatus?: ApplicationWebhookEventStatus.Disabled | ApplicationWebhookEventStatus.Enabled;\n  eventWebhooksTypes?: readonly ApplicationWebhookEventType[];\n  eventWebhooksURL?: string;\n  flags?: ApplicationFlagsResolvable;\n  icon?: Base64Resolvable | BufferResolvable | null;\n  installParams?: ClientApplicationInstallParams;\n  interactionsEndpointURL?: string;\n  roleConnectionsVerificationURL?: string;\n  tags?: readonly string[];\n}\n\nexport interface ClientApplicationInstallParams {\n  permissions: Readonly<PermissionsBitField>;\n  scopes: readonly OAuth2Scopes[];\n}\n\nexport type Serialized<Value> = Value extends bigint | symbol | (() => any)\n  ? never\n  : Value extends boolean | number | string | undefined\n    ? Value\n    : Value extends JSONEncodable<infer JSONResult>\n      ? JSONResult\n      : Value extends readonly (infer ItemType)[]\n        ? Serialized<ItemType>[]\n        : Value extends ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>\n          ? {}\n          : { [K in keyof Value]: Serialized<Value[K]> };\n\n// #endregion\n\n// #region Voice\n\n/**\n * @remarks\n * Use `DiscordGatewayAdapterLibraryMethods` from `@discordjs/voice` instead.\n */\nexport interface InternalDiscordGatewayAdapterLibraryMethods {\n  destroy(): void;\n  onVoiceServerUpdate(data: GatewayVoiceServerUpdateDispatchData): void;\n  onVoiceStateUpdate(data: GatewayVoiceStateUpdateDispatchData): void;\n}\n\n/**\n * @remarks\n * Use `DiscordGatewayAdapterImplementerMethods` from `@discordjs/voice` instead.\n */\nexport interface InternalDiscordGatewayAdapterImplementerMethods {\n  destroy(): void;\n  sendPayload(payload: unknown): boolean;\n}\n\n/**\n * @remarks\n * Use `DiscordGatewayAdapterCreator` from `@discordjs/voice` instead.\n */\nexport type InternalDiscordGatewayAdapterCreator = (\n  methods: InternalDiscordGatewayAdapterLibraryMethods,\n) => InternalDiscordGatewayAdapterImplementerMethods;\n\n// #endregion\n\n// External\nexport * from '@discordjs/rest';\nexport * from '@discordjs/util';\nexport * from '@discordjs/ws';\nexport * from 'discord-api-types/v10';\n"
  },
  {
    "path": "packages/discord.js/typings/index.test-d.ts",
    "content": "/* eslint-disable no-lone-blocks, @typescript-eslint/unbound-method, @typescript-eslint/ban-ts-comment, no-param-reassign, id-length */\nimport type { ChildProcess } from 'node:child_process';\nimport type { Worker } from 'node:worker_threads';\nimport {\n  ActionRowBuilder,\n  ButtonBuilder,\n  ChannelSelectMenuBuilder,\n  createComponentBuilder,\n  EmbedBuilder,\n  MentionableSelectMenuBuilder,\n  MessageBuilder,\n  ModalBuilder,\n  PrimaryButtonBuilder,\n  RoleSelectMenuBuilder,\n  StringSelectMenuBuilder,\n  TextInputBuilder,\n  UserSelectMenuBuilder,\n  type ChatInputCommandBuilder,\n  type ContextMenuCommandBuilder,\n} from '@discordjs/builders';\nimport type { ReadonlyCollection } from '@discordjs/collection';\nimport type {\n  APIButtonComponent,\n  APIButtonComponentWithCustomId,\n  APIEmbed,\n  APIInteractionDataResolvedChannel,\n  APIInteractionDataResolvedGuildMember,\n  APIInteractionGuildMember,\n  APIPartialChannel,\n  APIPartialGuild,\n  APIRole,\n  APISelectMenuComponent,\n  APIStringSelectComponent,\n  APITextInputComponent,\n  Locale,\n  ThreadChannelType,\n  WebhookType,\n} from 'discord-api-types/v10';\nimport {\n  ApplicationCommandOptionType,\n  ApplicationCommandPermissionType,\n  ApplicationCommandType,\n  ApplicationIntegrationType,\n  AuditLogEvent,\n  ButtonStyle,\n  ChannelType,\n  ComponentType,\n  GatewayIntentBits,\n  GuildScheduledEventRecurrenceRuleFrequency,\n  GuildScheduledEventRecurrenceRuleMonth,\n  GuildScheduledEventRecurrenceRuleWeekday,\n  InteractionType,\n  MessageFlags,\n  PermissionFlagsBits,\n  TextInputStyle,\n} from 'discord-api-types/v10';\nimport { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd';\nimport type {\n  ActionRow,\n  ActionRowComponent,\n  ActionRowData,\n  AnnouncementChannel,\n  AnyThreadChannel,\n  ApplicationCommand,\n  ApplicationCommandChannelOption,\n  ApplicationCommandChannelOptionData,\n  ApplicationCommandChoicesData,\n  ApplicationCommandChoicesOption,\n  ApplicationCommandData,\n  ApplicationCommandManager,\n  ApplicationCommandOptionData,\n  ApplicationCommandPermissionsManager,\n  ApplicationCommandResolvable,\n  ApplicationCommandSubCommand,\n  ApplicationCommandSubCommandData,\n  ApplicationCommandSubGroup,\n  ApplicationCommandSubGroupData,\n  ApplicationEmoji,\n  ApplicationEmojiManager,\n  Attachment,\n  AuditLogChange,\n  AutoModerationActionExecution,\n  AutoModerationRule,\n  AutoModerationRuleManager,\n  Awaitable,\n  ButtonComponent,\n  ButtonComponentData,\n  ButtonInteraction,\n  CacheType,\n  CategoryChannel,\n  CategoryChannelChildManager,\n  Channel,\n  ChannelFlagsBitField,\n  ChannelMention,\n  ChannelSelectMenuComponent,\n  ChannelSelectMenuInteraction,\n  ChatInputApplicationCommandData,\n  ChatInputCommandInteraction,\n  ClientApplication,\n  ClientUser,\n  CollectedMessageInteraction,\n  Collector,\n  CommandInteraction,\n  CommandInteractionOption,\n  CommandInteractionOptionResolver,\n  CommandOptionNonChoiceResolvableType,\n  ContainerComponentData,\n  ContextMenuCommandInteraction,\n  DirectoryChannel,\n  DMChannel,\n  DMMessageManager,\n  Embed,\n  Emoji,\n  Entitlement,\n  FetchedThreads,\n  FetchedThreadsMore,\n  FetchPinnedMessagesResponse,\n  FileComponentData,\n  ForumChannel,\n  Guild,\n  GuildApplicationCommandManager,\n  GuildAuditLogs,\n  GuildAuditLogsActionType,\n  GuildAuditLogsEntry,\n  GuildAuditLogsTargetType,\n  GuildBan,\n  GuildBanManager,\n  GuildBasedChannel,\n  GuildChannelManager,\n  GuildEmoji,\n  GuildEmojiManager,\n  GuildForumThreadManager,\n  GuildMember,\n  GuildMemberFlagsBitField,\n  GuildMemberManager,\n  GuildMessageManager,\n  GuildOnboarding,\n  GuildResolvable,\n  GuildScheduledEventManager,\n  GuildScheduledEventRecurrenceRuleOptions,\n  GuildTextBasedChannel,\n  GuildTextThreadManager,\n  Interaction,\n  InteractionCallbackResponse,\n  InteractionCollector,\n  InteractionWebhook,\n  MediaChannel,\n  MediaGalleryComponentData,\n  MediaGalleryItemData,\n  MentionableSelectMenuComponent,\n  MentionableSelectMenuInteraction,\n  Message,\n  MessageActionRowComponent,\n  MessageActionRowComponentData,\n  MessageCollector,\n  MessageComponentInteraction,\n  MessageContextMenuCommandInteraction,\n  MessageManager,\n  MessageMentions,\n  MessageReaction,\n  ModalSubmitInteraction,\n  NonThreadGuildBasedChannel,\n  PartialDMChannel,\n  PartialGroupDMChannel,\n  PartialGuildMember,\n  PartialMessage,\n  PartialMessageReaction,\n  PartialPoll,\n  PartialPollAnswer,\n  PartialThreadMember,\n  PartialUser,\n  Poll,\n  PollAnswer,\n  PollAnswerVoterManager,\n  PollData,\n  PrimaryEntryPointCommandInteraction,\n  PrivateThreadChannel,\n  PublicThreadChannel,\n  ReactionCollector,\n  RepliableInteraction,\n  Role,\n  RoleManager,\n  RoleSelectMenuComponent,\n  RoleSelectMenuInteraction,\n  SectionComponentData,\n  SelectMenuInteraction,\n  SendableChannels,\n  SendMethod,\n  SeparatorComponentData,\n  Serialized,\n  Shard,\n  ShardClientUtil,\n  ShardingManager,\n  SKU,\n  Snowflake,\n  StageChannel,\n  StageInstance,\n  StickerPack,\n  StringSelectMenuComponent,\n  StringSelectMenuComponentData,\n  StringSelectMenuInteraction,\n  TextBasedChannel,\n  TextBasedChannelTypes,\n  ThreadManager,\n  TextChannel,\n  TextInputComponent,\n  ThreadChannel,\n  ThreadMember,\n  ThreadMemberFlagsBitField,\n  ThreadMemberManager,\n  ThreadOnlyChannel,\n  Typing,\n  User,\n  VoiceBasedChannel,\n  VoiceChannel,\n  Invite,\n  GuildInvite,\n  AuthorizingIntegrationOwners,\n  VoiceServerUpdateData,\n} from './index.js';\nimport {\n  Client,\n  Collection,\n  Events,\n  IntentsBitField,\n  Options,\n  PermissionsBitField,\n  Status,\n  resolveColor,\n  ShardEvents,\n  TextDisplayComponentData,\n  ThumbnailComponentData,\n  UnfurledMediaItemData,\n  UserContextMenuCommandInteraction,\n  UserMention,\n  UserSelectMenuComponent,\n  UserSelectMenuInteraction,\n  Webhook,\n} from './index.js';\n\n// Test type transformation:\ndeclare const serialize: <Value>(value: Value) => Serialized<Value>;\ndeclare const notPropertyOf: <Value, Property extends PropertyKey>(\n  value: Value,\n  property: Exclude<Property, keyof Value> & Property,\n) => void;\n\nconst client: Client = new Client({\n  intents: GatewayIntentBits.Guilds,\n  makeCache: Options.cacheWithLimits({\n    MessageManager: 200,\n    // @ts-expect-error doesn't exist\n    Message: 100,\n    GuildMemberManager: {\n      maxSize: 200,\n      keepOverLimit: member => member.id === client.user?.id,\n    },\n    ThreadManager: {\n      maxSize: 200,\n      keepOverLimit: value => !value.archived,\n    },\n  }),\n});\n\nif (client.isReady()) {\n  expectType<Client<true>>(client);\n} else {\n  expectType<Client>(client);\n}\n\nexpectType<Promise<Invite>>(client.fetchInvite('https://discord.gg/djs'));\nexpectType<Promise<Invite<true>>>(client.fetchInvite('https://discord.gg/djs', { withCounts: true }));\nexpectNotType<Promise<Invite<true>>>(client.fetchInvite('https://discord.gg/djs', { withCounts: false }));\n\nconst testGuildId = '222078108977594368'; // DJS\nconst testUserId = '987654321098765432'; // example id\nconst globalCommandId = '123456789012345678'; // example id\nconst guildCommandId = '234567890123456789'; // example id\n\nclient.on('autoModerationActionExecution', autoModerationActionExecution =>\n  expectType<AutoModerationActionExecution>(autoModerationActionExecution),\n);\n\nclient.on('autoModerationRuleCreate', ({ client }) => expectType<Client<true>>(client));\nclient.on('autoModerationRuleDelete', ({ client }) => expectType<Client<true>>(client));\n\nclient.on('autoModerationRuleUpdate', (oldAutoModerationRule, { client: newClient }) => {\n  expectType<Client<true>>(oldAutoModerationRule!.client);\n  expectType<Client<true>>(newClient);\n});\n\nclient.on('channelCreate', ({ client }) => expectType<Client<true>>(client));\nclient.on('channelDelete', ({ client }) => expectType<Client<true>>(client));\nclient.on('channelPinsUpdate', ({ client }) => expectType<Client<true>>(client));\n\nclient.on('channelUpdate', ({ client: oldClient }, { client: newClient }) => {\n  expectType<Client<true>>(oldClient);\n  expectType<Client<true>>(newClient);\n});\n\nclient.on('emojiCreate', ({ client }) => expectType<Client<true>>(client));\nclient.on('emojiDelete', ({ client }) => expectType<Client<true>>(client));\n\nclient.on('emojiUpdate', ({ client: oldClient }, { client: newClient }) => {\n  expectType<Client<true>>(oldClient);\n  expectType<Client<true>>(newClient);\n});\n\nclient.on('guildBanAdd', ({ client }) => expectType<Client<true>>(client));\nclient.on('guildBanRemove', ({ client }) => expectType<Client<true>>(client));\nclient.on('guildDelete', ({ client }) => expectType<Client<true>>(client));\nclient.on('guildIntegrationsUpdate', ({ client }) => expectType<Client<true>>(client));\nclient.on('guildMemberAdd', ({ client }) => expectType<Client<true>>(client));\nclient.on('guildMemberAvailable', ({ client }) => expectType<Client<true>>(client));\n\nclient.on('guildMemberRemove', member => {\n  expectType<Client<true>>(member.client);\n  if (member.partial) {\n    expectType<null>(member.joinedAt);\n    return;\n  }\n\n  expectType<Date | null>(member.joinedAt);\n});\n\nclient.on('guildMembersChunk', (members, { client }) => {\n  expectType<Client<true>>(members.first()!.client);\n  expectType<Client<true>>(client);\n});\n\nclient.on('guildMemberUpdate', ({ client: oldClient }, { client: newClient }) => {\n  expectType<Client<true>>(oldClient);\n  expectType<Client<true>>(newClient);\n});\n\nclient.on('guildScheduledEventCreate', ({ client }) => expectType<Client<true>>(client));\nclient.on('guildScheduledEventDelete', ({ client }) => expectType<Client<true>>(client));\n\nclient.on('guildScheduledEventUpdate', (oldGuildScheduledEvent, { client }) => {\n  expectType<Client<true>>(oldGuildScheduledEvent!.client);\n  expectType<Client<true>>(client);\n});\n\nclient.on('guildScheduledEventUserAdd', ({ client: oldClient }, { client: newClient }) => {\n  expectType<Client<true>>(oldClient);\n  expectType<Client<true>>(newClient);\n});\n\nclient.on('guildScheduledEventUserRemove', ({ client: oldClient }, { client: newClient }) => {\n  expectType<Client<true>>(oldClient);\n  expectType<Client<true>>(newClient);\n});\n\nclient.on('guildUnavailable', ({ client }) => expectType<Client<true>>(client));\n\nclient.on('guildUpdate', ({ client: oldClient }, { client: newClient }) => {\n  expectType<Client<true>>(oldClient);\n  expectType<Client<true>>(newClient);\n});\n\nclient.on('interactionCreate', async interaction => {\n  expectType<Client<true>>(interaction.client);\n  expectType<Snowflake | null>(interaction.guildId);\n  expectType<Snowflake | null>(interaction.channelId);\n  expectType<APIInteractionGuildMember | GuildMember | null>(interaction.member);\n\n  if (interaction.type === InteractionType.MessageComponent) {\n    expectType<Snowflake>(interaction.channelId);\n  }\n\n  if (interaction.type !== InteractionType.ApplicationCommand) return;\n\n  const actionRow = new ActionRowBuilder({\n    type: ComponentType.ActionRow,\n    components: [{ custom_id: '123', label: 'test', style: ButtonStyle.Primary, type: ComponentType.Button }],\n  });\n\n  await interaction.reply({ content: 'Hi!', components: [actionRow] });\n\n  // @ts-expect-error double nested components array\n  await interaction.reply({ content: 'Hi!', components: [[button]] });\n\n  void new ActionRowBuilder({});\n\n  // @ts-expect-error button as top-level component\n  await interaction.reply({ content: 'Hi!', components: [button] });\n\n  await interaction.reply({\n    content: 'test',\n    components: [\n      {\n        components: [\n          {\n            custom_id: 'abc',\n            label: 'abc',\n            style: ButtonStyle.Primary,\n            type: ComponentType.Button,\n          },\n        ],\n        type: ComponentType.ActionRow,\n      },\n    ],\n  });\n\n  // This is for testing never type resolution\n  if (!interaction.inGuild()) {\n    return;\n  }\n\n  if (interaction.inRawGuild()) {\n    expectNotType<never>(interaction);\n    return;\n  }\n\n  if (interaction.inCachedGuild()) {\n    expectNotType<never>(interaction);\n  }\n});\n\nclient.on('inviteCreate', invite => {\n  expectType<GuildInvite>(invite);\n  expectType<Client<true>>(invite.client);\n});\n\nclient.on('inviteDelete', invite => {\n  expectType<GuildInvite>(invite);\n  expectType<Client<true>>(invite.client);\n});\n\n// This is to check that stuff is the right type\ndeclare const assertIsMessage: (m: Promise<Message>) => void;\n\nclient.on('messageCreate', async message => {\n  const { client, channel } = message;\n\n  // https://github.com/discordjs/discord.js/issues/8545\n  {\n    // These should not throw any errors when comparing messages from any source.\n    channel.messages.cache.filter(Boolean);\n    (await channel.messages.fetch()).filter(({ author }) => author.id === message.author.id);\n\n    if (channel.isDMBased()) {\n      expectType<DMMessageManager>(channel.messages.channel.messages);\n    } else {\n      expectType<GuildMessageManager>(channel.messages.channel.messages);\n    }\n  }\n\n  if (!message.inGuild() && message.partial) {\n    expectNotType<never>(message);\n  }\n\n  expectType<Client<true>>(client);\n  assertIsMessage(channel.send('string'));\n  assertIsMessage(channel.send({}));\n  assertIsMessage(channel.send({ embeds: [] }));\n\n  assertIsMessage(client.channels.createMessage(channel, 'string'));\n  assertIsMessage(client.channels.createMessage(channel, {}));\n  assertIsMessage(client.channels.createMessage(channel, { embeds: [] }));\n\n  const embed = new EmbedBuilder();\n  assertIsMessage(channel.send({ embeds: [embed] }));\n  assertIsMessage(client.channels.createMessage(channel, { embeds: [embed] }));\n\n  if (message.inGuild()) {\n    expectAssignable<Message<true>>(message);\n    const component = await message.awaitMessageComponent({ componentType: ComponentType.Button });\n    expectType<ButtonInteraction<'cached'>>(component);\n    expectType<InteractionCallbackResponse<true>>(await component.reply({ withResponse: true }));\n\n    const buttonCollector = message.createMessageComponentCollector({ componentType: ComponentType.Button });\n    expectType<InteractionCollector<ButtonInteraction<'cached'>>>(buttonCollector);\n    expectAssignable<\n      (\n        test: ButtonInteraction<'cached'>,\n        items: Collection<Snowflake, ButtonInteraction<'cached'>>,\n      ) => Awaitable<boolean>\n    >(buttonCollector.filter);\n    expectType<GuildTextBasedChannel>(message.channel);\n    expectType<Guild>(message.guild);\n    expectType<GuildMember | null>(message.member);\n\n    expectType<MessageMentions<true>>(message.mentions);\n    expectType<Guild>(message.guild);\n    expectType<Collection<Snowflake, GuildMember>>(message.mentions.members);\n  }\n\n  expectType<Exclude<TextBasedChannel, PartialGroupDMChannel>>(message.channel);\n  expectNotType<GuildTextBasedChannel>(message.channel);\n\n  // @ts-expect-error empty message\n  await channel.send();\n  // @ts-expect-error empty message\n  await client.channels.createMessage();\n  // @ts-expect-error unknown property\n  await channel.send({ another: 'property' });\n  // @ts-expect-error unknown property\n  await client.channels.createMessage({ another: 'property' });\n  // @ts-expect-error plain string\n  await client.channels.createMessage('string');\n  // Check collector creations.\n\n  // Verify that buttons interactions are inferred.\n  const buttonCollector = message.createMessageComponentCollector({ componentType: ComponentType.Button });\n  expectAssignable<Promise<ButtonInteraction>>(message.awaitMessageComponent({ componentType: ComponentType.Button }));\n  expectAssignable<Promise<ButtonInteraction>>(channel.awaitMessageComponent({ componentType: ComponentType.Button }));\n  expectAssignable<InteractionCollector<ButtonInteraction>>(buttonCollector);\n\n  buttonCollector.on('collect', (...args) => expectType<[ButtonInteraction]>(args));\n  buttonCollector.on('dispose', (...args) => expectType<[ButtonInteraction]>(args));\n  buttonCollector.on('end', (...args) => expectType<[ReadonlyCollection<Snowflake, ButtonInteraction>, string]>(args));\n\n  // Verify that select menus interaction are inferred.\n  const stringSelectMenuCollector = message.createMessageComponentCollector({\n    componentType: ComponentType.StringSelect,\n  });\n  expectAssignable<Promise<StringSelectMenuInteraction>>(\n    message.awaitMessageComponent({ componentType: ComponentType.StringSelect }),\n  );\n  expectAssignable<Promise<StringSelectMenuInteraction>>(\n    channel.awaitMessageComponent({ componentType: ComponentType.StringSelect }),\n  );\n  expectAssignable<InteractionCollector<StringSelectMenuInteraction>>(stringSelectMenuCollector);\n\n  stringSelectMenuCollector.on('collect', (...args) => expectType<[StringSelectMenuInteraction]>(args));\n  stringSelectMenuCollector.on('dispose', (...args) => expectType<[StringSelectMenuInteraction]>(args));\n  stringSelectMenuCollector.on('end', (...args) =>\n    expectType<[ReadonlyCollection<Snowflake, StringSelectMenuInteraction>, string]>(args),\n  );\n\n  // Verify that message component interactions are default collected types.\n  const defaultCollector = message.createMessageComponentCollector();\n  expectAssignable<Promise<MessageComponentInteraction>>(message.awaitMessageComponent());\n  expectAssignable<Promise<MessageComponentInteraction>>(channel.awaitMessageComponent());\n  expectAssignable<InteractionCollector<CollectedMessageInteraction>>(defaultCollector);\n\n  defaultCollector.on('collect', (...args) => expectType<[ButtonInteraction | SelectMenuInteraction]>(args));\n  defaultCollector.on('dispose', (...args) => expectType<[ButtonInteraction | SelectMenuInteraction]>(args));\n  defaultCollector.on('end', (...args) =>\n    expectType<[ReadonlyCollection<Snowflake, ButtonInteraction | SelectMenuInteraction>, string]>(args),\n  );\n\n  // Verify that additional options don't affect default collector types.\n  const semiDefaultCollector = message.createMessageComponentCollector({ time: 10_000 });\n  expectType<InteractionCollector<CollectedMessageInteraction>>(semiDefaultCollector);\n  const semiDefaultCollectorChannel = message.createMessageComponentCollector({ time: 10_000 });\n  expectType<InteractionCollector<CollectedMessageInteraction>>(semiDefaultCollectorChannel);\n\n  // Verify that interaction collector options can't be used.\n  message.createMessageComponentCollector({\n    // @ts-expect-error not a component\n    interactionType: InteractionType.ApplicationCommand,\n  });\n\n  // Make sure filter parameters are properly inferred.\n  message.createMessageComponentCollector({\n    filter: i => {\n      expectType<CollectedMessageInteraction>(i);\n      return true;\n    },\n  });\n\n  message.createMessageComponentCollector({\n    componentType: ComponentType.Button,\n    filter: i => {\n      expectType<ButtonInteraction>(i);\n      return true;\n    },\n  });\n\n  message.createMessageComponentCollector({\n    componentType: ComponentType.StringSelect,\n    filter: i => {\n      expectType<StringSelectMenuInteraction>(i);\n      return true;\n    },\n  });\n\n  await message.awaitMessageComponent({\n    filter: i => {\n      expectType<CollectedMessageInteraction>(i);\n      return true;\n    },\n  });\n\n  await message.awaitMessageComponent({\n    componentType: ComponentType.Button,\n    filter: i => {\n      expectType<ButtonInteraction>(i);\n      return true;\n    },\n  });\n\n  await message.awaitMessageComponent({\n    componentType: ComponentType.StringSelect,\n    filter: i => {\n      expectType<StringSelectMenuInteraction>(i);\n      return true;\n    },\n  });\n\n  const webhook = await message.fetchWebhook();\n\n  if (webhook.isChannelFollower()) {\n    expectAssignable<APIPartialGuild | Guild>(webhook.sourceGuild);\n    expectAssignable<AnnouncementChannel | APIPartialChannel>(webhook.sourceChannel);\n    expectType<Webhook<WebhookType.ChannelFollower>>(webhook);\n  } else if (webhook.isIncoming()) {\n    expectType<string>(webhook.token);\n    expectType<Webhook<WebhookType.Incoming>>(webhook);\n  }\n\n  expectNotType<APIPartialGuild | Guild>(webhook.sourceGuild);\n  expectNotType<AnnouncementChannel | APIPartialChannel>(webhook.sourceChannel);\n  expectNotType<string>(webhook.token);\n\n  await channel.awaitMessageComponent({\n    filter: i => {\n      expectType<CollectedMessageInteraction<'cached'>>(i);\n      return true;\n    },\n  });\n\n  await channel.awaitMessageComponent({\n    componentType: ComponentType.Button,\n    filter: i => {\n      expectType<ButtonInteraction<'cached'>>(i);\n      return true;\n    },\n  });\n\n  await channel.awaitMessageComponent({\n    componentType: ComponentType.StringSelect,\n    filter: i => {\n      expectType<StringSelectMenuInteraction<'cached'>>(i);\n      return true;\n    },\n  });\n\n  // Check that both builders and builder data can be sent in messages\n  const row = new ActionRowBuilder();\n\n  const rawButtonsRow: ActionRowData<ButtonComponentData> = {\n    type: ComponentType.ActionRow,\n    components: [\n      { type: ComponentType.Button, label: 'test', style: ButtonStyle.Primary, customId: 'test' },\n      {\n        type: ComponentType.Button,\n        label: 'another test',\n        style: ButtonStyle.Link,\n        url: 'https://discord.js.org',\n      },\n    ],\n  };\n\n  const buttonsRow: ActionRowData<ButtonBuilder> = {\n    type: ComponentType.ActionRow,\n    components: [new PrimaryButtonBuilder()],\n  };\n\n  const rawStringSelectMenuRow: ActionRowData<StringSelectMenuComponentData> = {\n    type: ComponentType.ActionRow,\n    components: [\n      {\n        type: ComponentType.StringSelect,\n        options: [{ label: 'test', value: 'test' }],\n        customId: 'test',\n      },\n    ],\n  };\n\n  const stringSelectRow: ActionRowData<StringSelectMenuBuilder> = {\n    type: ComponentType.ActionRow,\n    components: [new StringSelectMenuBuilder()],\n  };\n\n  const embedData = { description: 'test', color: 0xff0000 };\n\n  await client.channels.createMessage(channel, {\n    components: [row, rawButtonsRow, buttonsRow, rawStringSelectMenuRow, stringSelectRow],\n    embeds: [embed, embedData],\n  });\n\n  const rawTextDisplay: TextDisplayComponentData = {\n    type: ComponentType.TextDisplay,\n    content: 'test',\n  };\n\n  const rawMedia: UnfurledMediaItemData = { url: 'https://discord.js.org' };\n\n  const rawThumbnail: ThumbnailComponentData = {\n    type: ComponentType.Thumbnail,\n    media: rawMedia,\n    spoiler: true,\n    description: 'test',\n  };\n\n  const rawSection: SectionComponentData = {\n    type: ComponentType.Section,\n    components: [rawTextDisplay],\n    accessory: rawThumbnail,\n  };\n\n  const rawMediaGalleryItem: MediaGalleryItemData = {\n    media: rawMedia,\n    description: 'test',\n    spoiler: false,\n  };\n\n  const rawMediaGallery: MediaGalleryComponentData = {\n    type: ComponentType.MediaGallery,\n    items: [rawMediaGalleryItem, rawMediaGalleryItem, rawMediaGalleryItem],\n  };\n\n  const rawSeparator: SeparatorComponentData = {\n    type: ComponentType.Separator,\n    spacing: 1,\n    divider: false,\n  };\n\n  const rawFile: FileComponentData = {\n    type: ComponentType.File,\n    file: rawMedia,\n  };\n\n  const rawContainer: ContainerComponentData = {\n    type: ComponentType.Container,\n    components: [rawSection, rawSeparator, rawMediaGallery, rawFile],\n    accentColor: 0xff00ff,\n    spoiler: true,\n  };\n\n  await channel.send({ flags: MessageFlags.IsComponentsV2, components: [rawContainer] });\n});\n\nclient.on('messageDelete', ({ client }) => expectType<Client<true>>(client));\n\nclient.on('messageDeleteBulk', (messages, { client }) => {\n  expectType<Client<true>>(messages.first()!.client);\n  expectType<Client<true>>(client);\n});\n\nclient.on('messagePollVoteAdd', async (answer, userId) => {\n  expectType<Client<true>>(answer.client);\n  expectType<Snowflake>(userId);\n\n  if (answer.partial) {\n    expectType<null>(answer.emoji);\n    expectType<null>(answer.text);\n    expectNotType<null>(answer.id);\n    expectNotType<null>(answer.poll);\n\n    await answer.poll.fetch();\n    const response = answer.poll.answers?.get(answer.id) ?? answer;\n\n    expectType<User>(response.voters.cache.get(userId)!);\n  }\n\n  expectType<string | null>(answer.text);\n  expectType<Emoji | GuildEmoji | null>(answer.emoji);\n  expectType<number>(answer.id);\n  expectType<number>(answer.voteCount!);\n});\n\nclient.on('messagePollVoteRemove', async (answer, userId) => {\n  expectType<Client<true>>(answer.client);\n  expectType<Snowflake>(userId);\n\n  if (answer.partial) {\n    expectType<null>(answer.emoji);\n    expectType<null>(answer.text);\n    expectNotType<null>(answer.id);\n    expectNotType<null>(answer.poll);\n\n    await answer.poll.fetch();\n    answer = answer.poll.answers?.get(answer.id) ?? answer;\n  }\n\n  expectType<string | null>(answer.text);\n  expectType<Emoji | GuildEmoji | null>(answer.emoji);\n  expectType<number>(answer.id);\n  expectType<number>(answer.voteCount!);\n});\n\nclient.on('messageReactionAdd', async (reaction, { client }) => {\n  expectType<Client<true>>(reaction.client);\n  expectType<Client<true>>(client);\n\n  if (reaction.partial) {\n    expectType<null>(reaction.count);\n    reaction = await reaction.fetch();\n  }\n\n  expectType<number>(reaction.count);\n  if (reaction.message.partial) {\n    expectType<string | null>(reaction.message.content);\n    return;\n  }\n\n  expectType<string>(reaction.message.content);\n});\n\nclient.on('messageReactionRemove', ({ client: oldClient }, { client: newClient }) => {\n  expectType<Client<true>>(oldClient);\n  expectType<Client<true>>(newClient);\n});\n\nclient.on('messageReactionRemoveAll', async (message, reactions) => {\n  console.log(`messageReactionRemoveAll - id: ${message.id} (${message.id.length})`);\n  if (message.partial) message = await message.fetch();\n  console.log(`messageReactionRemoveAll - content: ${message.content}`);\n  expectType<Client<true>>(message.client);\n  expectType<Client<true>>(reactions.first()!.client);\n});\n\nclient.on('messageReactionRemoveEmoji', ({ client }) => expectType<Client<true>>(client));\n\nclient.on('messageUpdate', ({ client: oldClient }, { client: newClient }) => {\n  expectType<Client<true>>(oldClient);\n  expectType<Client<true>>(newClient);\n});\n\nclient.on('presenceUpdate', (oldPresence, { client }) => {\n  expectType<Client<true>>(oldPresence!.client);\n  expectType<Client<true>>(client);\n});\n\ndeclare const slashCommandBuilder: ChatInputCommandBuilder;\ndeclare const contextMenuCommandBuilder: ContextMenuCommandBuilder;\ndeclare const guild: Guild;\n\nclient.on('clientReady', async client => {\n  expectType<Client<true>>(client);\n  console.log(`Client is logged in as ${client.user.tag} and ready!`);\n\n  // Test fetching all global commands and ones from one guild\n  expectType<Collection<string, ApplicationCommand<{ guild: GuildResolvable }>>>(\n    await client.application!.commands.fetch(),\n  );\n  expectType<Collection<string, ApplicationCommand<{ guild: GuildResolvable }>>>(\n    await client.application!.commands.fetch({ guildId: testGuildId }),\n  );\n\n  // Test command manager methods\n  const globalCommand = await client.application?.commands.fetch(globalCommandId);\n  const guildCommandFromGlobal = await client.application?.commands.fetch({ id: guildCommandId, guildId: testGuildId });\n  const guildCommandFromGuild = await client.guilds.cache.get(testGuildId)?.commands.fetch({ id: guildCommandId });\n\n  await client.application?.commands.create(slashCommandBuilder);\n  await client.application?.commands.create(contextMenuCommandBuilder);\n  await guild.commands.create(slashCommandBuilder);\n  await guild.commands.create(contextMenuCommandBuilder);\n\n  await client.application?.commands.edit(globalCommandId, slashCommandBuilder);\n  await client.application?.commands.edit(globalCommandId, contextMenuCommandBuilder);\n  await guild.commands.edit(guildCommandId, slashCommandBuilder);\n  await guild.commands.edit(guildCommandId, contextMenuCommandBuilder);\n\n  await client.application?.commands.edit(globalCommandId, { defaultMemberPermissions: null });\n  await globalCommand?.edit({ defaultMemberPermissions: null });\n  await globalCommand?.setDefaultMemberPermissions(null);\n\n  // @ts-expect-error passing guildId on guild commands\n  await client.guilds.cache.get(testGuildId)?.commands.fetch(guildCommandId, { guildId: testGuildId });\n\n  // Test command permissions\n  const globalPermissionsManager = client.application?.commands.permissions;\n  const guildPermissionsManager = client.guilds.cache.get(testGuildId)?.commands.permissions;\n\n  // Permissions from global manager\n  await globalPermissionsManager?.add({\n    command: globalCommandId,\n    guild: testGuildId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n  await globalPermissionsManager?.has({ command: globalCommandId, guild: testGuildId, permissionId: testGuildId });\n  await globalPermissionsManager?.fetch({ guild: testGuildId });\n  await globalPermissionsManager?.fetch({ command: globalCommandId, guild: testGuildId });\n  await globalPermissionsManager?.remove({\n    command: globalCommandId,\n    guild: testGuildId,\n    roles: [testGuildId],\n    token: 'VeryRealToken',\n  });\n  await globalPermissionsManager?.remove({\n    command: globalCommandId,\n    guild: testGuildId,\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  await globalPermissionsManager?.remove({\n    command: globalCommandId,\n    guild: testGuildId,\n    channels: [testGuildId],\n    token: 'VeryRealToken',\n  });\n  await globalPermissionsManager?.remove({\n    command: globalCommandId,\n    guild: testGuildId,\n    roles: [testGuildId],\n    users: [testUserId],\n    channels: [testGuildId],\n    token: 'VeryRealToken',\n  });\n  await globalPermissionsManager?.set({\n    command: globalCommandId,\n    guild: testGuildId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n\n  // @ts-expect-error id on add\n  await globalPermissionsManager?.add({\n    command: globalCommandId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n  // @ts-expect-error guild permission on global manager\n  await globalPermissionsManager?.has({ command: globalCommandId, permissionId: testGuildId });\n  // @ts-expect-error fetch all from global\n  await globalPermissionsManager?.fetch();\n  // @ts-expect-error fetch global permissions\n  await globalPermissionsManager?.fetch({ command: globalCommandId });\n  // @ts-expect-error remove permission from global\n  await globalPermissionsManager?.remove({ command: globalCommandId, roles: [testGuildId], token: 'VeryRealToken' });\n  // @ts-expect-error remove permission from global\n  await globalPermissionsManager?.remove({ command: globalCommandId, users: [testUserId], token: 'VeryRealToken' });\n  // @ts-expect-error remove permission from global\n  await globalPermissionsManager?.remove({\n    command: globalCommandId,\n    roles: [testGuildId],\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  // @ts-expect-error set permission from global\n  await globalPermissionsManager?.set({\n    command: globalCommandId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n\n  // @ts-expect-error add permission from global\n  await globalPermissionsManager?.add({\n    guild: testGuildId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n  // @ts-expect-error check permissions from global\n  await globalPermissionsManager?.has({ guild: testGuildId, permissionId: testGuildId });\n  // @ts-expect-error\n  await globalPermissionsManager?.remove({ guild: testGuildId, roles: [testGuildId], token: 'VeryRealToken' });\n  // @ts-expect-error\n  await globalPermissionsManager?.remove({ guild: testGuildId, users: [testUserId], token: 'VeryRealToken' });\n  // @ts-expect-error\n  await globalPermissionsManager?.remove({\n    guild: testGuildId,\n    roles: [testGuildId],\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  // @ts-expect-error\n  await globalPermissionsManager?.set({\n    guild: testGuildId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n\n  // Permissions from guild manager\n  await guildPermissionsManager?.add({\n    command: globalCommandId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n  await guildPermissionsManager?.has({ command: globalCommandId, permissionId: testGuildId });\n  await guildPermissionsManager?.fetch({});\n  await guildPermissionsManager?.fetch({ command: globalCommandId });\n  await guildPermissionsManager?.remove({ command: globalCommandId, roles: [testGuildId], token: 'VeryRealToken' });\n  await guildPermissionsManager?.remove({ command: globalCommandId, users: [testUserId], token: 'VeryRealToken' });\n  await guildPermissionsManager?.remove({ command: globalCommandId, channels: [testGuildId], token: 'VeryRealToken' });\n  await guildPermissionsManager?.remove({\n    command: globalCommandId,\n    roles: [testGuildId],\n    users: [testUserId],\n    channels: [testGuildId],\n    token: 'VeryRealToken',\n  });\n  await guildPermissionsManager?.set({\n    command: globalCommandId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n\n  await guildPermissionsManager?.add({\n    command: globalCommandId,\n    // @ts-expect-error\n    guild: testGuildId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n  // @ts-expect-error\n  await guildPermissionsManager?.has({ command: globalCommandId, guild: testGuildId, permissionId: testGuildId });\n  // @ts-expect-error\n  await guildPermissionsManager?.fetch({ guild: testGuildId });\n  // @ts-expect-error\n  await guildPermissionsManager?.fetch({ command: globalCommandId, guild: testGuildId });\n  await guildPermissionsManager?.remove({\n    command: globalCommandId,\n    // @ts-expect-error\n    guild: testGuildId,\n    roles: [testGuildId],\n    token: 'VeryRealToken',\n  });\n  await guildPermissionsManager?.remove({\n    command: globalCommandId,\n    // @ts-expect-error\n    guild: testGuildId,\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  await guildPermissionsManager?.remove({\n    command: globalCommandId,\n    // @ts-expect-error\n    guild: testGuildId,\n    roles: [testGuildId],\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  await guildPermissionsManager?.set({\n    command: globalCommandId,\n    // @ts-expect-error\n    guild: testGuildId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n\n  // @ts-expect-error\n  await guildPermissionsManager?.add({\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n  // @ts-expect-error\n  await guildPermissionsManager?.has({ permissionId: testGuildId });\n  // @ts-expect-error\n  await guildPermissionsManager?.remove({ roles: [testGuildId], token: 'VeryRealToken' });\n  // @ts-expect-error\n  await guildPermissionsManager?.remove({ users: [testUserId], token: 'VeryRealToken' });\n  // @ts-expect-error\n  await guildPermissionsManager?.remove({ roles: [testGuildId], users: [testUserId], token: 'VeryRealToken' });\n  // @ts-expect-error\n  await guildPermissionsManager?.set({\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n\n  // Permissions from cached global ApplicationCommand\n  await globalCommand?.permissions.add({\n    guild: testGuildId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n  await globalCommand?.permissions.has({ guild: testGuildId, permissionId: testGuildId });\n  await globalCommand?.permissions.fetch({ guild: testGuildId });\n  await globalCommand?.permissions.remove({ guild: testGuildId, roles: [testGuildId], token: 'VeryRealToken' });\n  await globalCommand?.permissions.remove({ guild: testGuildId, users: [testUserId], token: 'VeryRealToken' });\n  await globalCommand?.permissions.remove({\n    guild: testGuildId,\n    roles: [testGuildId],\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  await globalCommand?.permissions.set({\n    guild: testGuildId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n\n  await globalCommand?.permissions.add({\n    // @ts-expect-error\n    command: globalCommandId,\n    guild: testGuildId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n  await globalCommand?.permissions.has({\n    // @ts-expect-error\n    command: globalCommandId,\n    guild: testGuildId,\n    permissionId: testGuildId,\n    token: 'VeryRealToken',\n  });\n  // @ts-expect-error\n  await globalCommand?.permissions.fetch({ command: globalCommandId, guild: testGuildId, token: 'VeryRealToken' });\n  await globalCommand?.permissions.remove({\n    // @ts-expect-error\n    command: globalCommandId,\n    guild: testGuildId,\n    roles: [testGuildId],\n    token: 'VeryRealToken',\n  });\n  await globalCommand?.permissions.remove({\n    // @ts-expect-error\n    command: globalCommandId,\n    guild: testGuildId,\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  await globalCommand?.permissions.remove({\n    // @ts-expect-error\n    command: globalCommandId,\n    guild: testGuildId,\n    roles: [testGuildId],\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  await globalCommand?.permissions.set({\n    // @ts-expect-error\n    command: globalCommandId,\n    guild: testGuildId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n\n  // @ts-expect-error\n  await globalCommand?.permissions.add({\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n  // @ts-expect-error\n  await globalCommand?.permissions.has({ permissionId: testGuildId });\n  // @ts-expect-error\n  await globalCommand?.permissions.fetch({});\n  // @ts-expect-error\n  await globalCommand?.permissions.remove({ roles: [testGuildId], token: 'VeryRealToken' });\n  // @ts-expect-error\n  await globalCommand?.permissions.remove({ users: [testUserId], token: 'VeryRealToken' });\n  // @ts-expect-error\n  await globalCommand?.permissions.remove({ roles: [testGuildId], users: [testUserId], token: 'VeryRealToken' });\n  // @ts-expect-error\n  await globalCommand?.permissions.set({\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n  });\n\n  // Permissions from cached guild ApplicationCommand\n  await guildCommandFromGlobal?.permissions.add({\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n  await guildCommandFromGlobal?.permissions.has({ permissionId: testGuildId });\n  await guildCommandFromGlobal?.permissions.fetch({});\n  await guildCommandFromGlobal?.permissions.remove({ roles: [testGuildId], token: 'VeryRealToken' });\n  await guildCommandFromGlobal?.permissions.remove({ users: [testUserId], token: 'VeryRealToken' });\n  await guildCommandFromGlobal?.permissions.remove({\n    roles: [testGuildId],\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  await guildCommandFromGlobal?.permissions.set({\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n\n  await guildCommandFromGlobal?.permissions.add({\n    // @ts-expect-error\n    command: globalCommandId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n  // @ts-expect-error\n  await guildCommandFromGlobal?.permissions.has({ command: guildCommandId, permissionId: testGuildId });\n  await guildCommandFromGlobal?.permissions.remove({\n    // @ts-expect-error\n    command: guildCommandId,\n    roles: [testGuildId],\n    token: 'VeryRealToken',\n  });\n  await guildCommandFromGlobal?.permissions.remove({\n    // @ts-expect-error\n    command: guildCommandId,\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  await guildCommandFromGlobal?.permissions.remove({\n    // @ts-expect-error\n    command: guildCommandId,\n    roles: [testGuildId],\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  await guildCommandFromGlobal?.permissions.set({\n    // @ts-expect-error\n    command: guildCommandId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n\n  await guildCommandFromGlobal?.permissions.add({\n    // @ts-expect-error\n    guild: testGuildId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n  // @ts-expect-error\n  await guildCommandFromGlobal?.permissions.has({ guild: testGuildId, permissionId: testGuildId });\n  await guildCommandFromGlobal?.permissions.remove({\n    // @ts-expect-error\n    guild: testGuildId,\n    roles: [testGuildId],\n    token: 'VeryRealToken',\n  });\n  // @ts-expect-error\n  await guildCommandFromGlobal?.permissions.remove({ guild: testGuildId, users: [testUserId], token: 'VeryRealToken' });\n  await guildCommandFromGlobal?.permissions.remove({\n    // @ts-expect-error\n    guild: testGuildId,\n    roles: [testGuildId],\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  await guildCommandFromGlobal?.permissions.set({\n    // @ts-expect-error\n    guild: testGuildId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n\n  await guildCommandFromGuild?.permissions.add({\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n  await guildCommandFromGuild?.permissions.has({ permissionId: testGuildId });\n  await guildCommandFromGuild?.permissions.fetch({});\n  await guildCommandFromGuild?.permissions.remove({ roles: [testGuildId], token: 'VeryRealToken' });\n  await guildCommandFromGuild?.permissions.remove({ users: [testUserId], token: 'VeryRealToken' });\n  await guildCommandFromGuild?.permissions.remove({\n    roles: [testGuildId],\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  await guildCommandFromGuild?.permissions.set({\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n\n  await guildCommandFromGuild?.permissions.add({\n    // @ts-expect-error\n    command: globalCommandId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n  // @ts-expect-error\n  await guildCommandFromGuild?.permissions.has({ command: guildCommandId, permissionId: testGuildId });\n  await guildCommandFromGuild?.permissions.remove({\n    // @ts-expect-error\n    command: guildCommandId,\n    roles: [testGuildId],\n    token: 'VeryRealToken',\n  });\n  await guildCommandFromGuild?.permissions.remove({\n    // @ts-expect-error\n    command: guildCommandId,\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  await guildCommandFromGuild?.permissions.remove({\n    // @ts-expect-error\n    command: guildCommandId,\n    roles: [testGuildId],\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  await guildCommandFromGuild?.permissions.set({\n    // @ts-expect-error\n    command: guildCommandId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n\n  await guildCommandFromGuild?.permissions.add({\n    // @ts-expect-error\n    guild: testGuildId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n  // @ts-expect-error\n  await guildCommandFromGuild?.permissions.has({ guild: testGuildId, permissionId: testGuildId });\n  // @ts-expect-error\n  await guildCommandFromGuild?.permissions.remove({ guild: testGuildId, roles: [testGuildId], token: 'VeryRealToken' });\n  // @ts-expect-error\n  await guildCommandFromGuild?.permissions.remove({ guild: testGuildId, users: [testUserId], token: 'VeryRealToken' });\n  await guildCommandFromGuild?.permissions.remove({\n    // @ts-expect-error\n    guild: testGuildId,\n    roles: [testGuildId],\n    users: [testUserId],\n    token: 'VeryRealToken',\n  });\n  await guildCommandFromGuild?.permissions.set({\n    // @ts-expect-error\n    guild: testGuildId,\n    permissions: [{ type: ApplicationCommandPermissionType.Role, id: testGuildId, permission: true }],\n    token: 'VeryRealToken',\n  });\n});\n\nclient.on('roleCreate', ({ client }) => expectType<Client<true>>(client));\nclient.on('roleDelete', ({ client }) => expectType<Client<true>>(client));\n\nclient.on('roleUpdate', ({ client: oldClient }, { client: newClient }) => {\n  expectType<Client<true>>(oldClient);\n  expectType<Client<true>>(newClient);\n});\n\nclient.on('stageInstanceCreate', ({ client }) => expectType<Client<true>>(client));\nclient.on('stageInstanceDelete', ({ client }) => expectType<Client<true>>(client));\n\nclient.on('stageInstanceUpdate', (oldStageInstance, { client }) => {\n  expectType<Client<true>>(oldStageInstance!.client);\n  expectType<Client<true>>(client);\n});\n\nclient.on('stickerCreate', ({ client }) => expectType<Client<true>>(client));\nclient.on('stickerDelete', ({ client }) => expectType<Client<true>>(client));\n\nclient.on('stickerUpdate', ({ client: oldClient }, { client: newClient }) => {\n  expectType<Client<true>>(oldClient);\n  expectType<Client<true>>(newClient);\n});\n\nclient.on('threadCreate', thread => {\n  expectType<Client<true>>(thread.client);\n\n  if (thread.type === ChannelType.PrivateThread) {\n    expectType<number>(thread.createdTimestamp);\n    expectType<Date>(thread.createdAt);\n  } else {\n    expectType<number | null>(thread.createdTimestamp);\n    expectType<Date | null>(thread.createdAt);\n  }\n});\n\nclient.on('threadDelete', ({ client }) => expectType<Client<true>>(client));\n\nclient.on('threadListSync', (threads, { client }) => {\n  expectType<Client<true>>(threads.first()!.client);\n  expectType<Client<true>>(client);\n});\n\nclient.on('threadMembersUpdate', (addedMembers, removedMembers, thread) => {\n  expectType<Client<true>>(addedMembers.first()!.client);\n  expectType<Client<true>>(removedMembers.first()!.client);\n  expectType<Client<true>>(thread.client);\n  expectType<ReadonlyCollection<Snowflake, ThreadMember>>(addedMembers);\n  expectType<ReadonlyCollection<Snowflake, PartialThreadMember | ThreadMember>>(removedMembers);\n  expectType<AnyThreadChannel>(thread);\n  const left = removedMembers.first();\n  if (!left) return;\n\n  if (left.partial) {\n    expectType<PartialThreadMember>(left);\n    expectType<null>(left.flags);\n  } else {\n    expectType<ThreadMember>(left);\n    expectType<ThreadMemberFlagsBitField>(left.flags);\n  }\n});\n\nclient.on('threadMemberUpdate', ({ client: oldClient }, { client: newClient }) => {\n  expectType<Client<true>>(oldClient);\n  expectType<Client<true>>(newClient);\n});\n\nclient.on('threadUpdate', ({ client: oldClient }, { client: newClient }) => {\n  expectType<Client<true>>(oldClient);\n  expectType<Client<true>>(newClient);\n});\n\nclient.on('typingStart', ({ client }) => expectType<Client<true>>(client));\n\nclient.on('userUpdate', ({ client: oldClient }, { client: newClient }) => {\n  expectType<Client<true>>(oldClient);\n  expectType<Client<true>>(newClient);\n});\n\nclient.on('voiceServerUpdate', data => {\n  expectType<VoiceServerUpdateData>(data);\n});\n\nclient.on('voiceStateUpdate', ({ client: oldClient }, { client: newClient }) => {\n  expectType<Client<true>>(oldClient);\n  expectType<Client<true>>(newClient);\n});\n\nclient.on('webhooksUpdate', ({ client }) => expectType<Client<true>>(client));\n\nclient.on('guildCreate', async g => {\n  expectType<Client<true>>(g.client);\n  const channel = g.channels.cache.random();\n  if (!channel) return;\n\n  if (channel.type === ChannelType.GuildText) {\n    const row: ActionRowData<MessageActionRowComponentData> = {\n      type: ComponentType.ActionRow,\n      components: [\n        new PrimaryButtonBuilder(),\n        { type: ComponentType.Button, style: ButtonStyle.Primary, label: 'string', customId: 'foo' },\n        { type: ComponentType.Button, style: ButtonStyle.Link, label: 'test', url: 'test' },\n        { type: ComponentType.StringSelect, customId: 'foo', options: [{ label: 'label', value: 'value' }] },\n        new StringSelectMenuBuilder(),\n        // @ts-expect-error\n        { type: ComponentType.TextInput, style: TextInputStyle.Paragraph, customId: 'foo', label: 'test' },\n        // @ts-expect-error\n        new TextInputBuilder(),\n      ],\n    };\n\n    const row2 = new ActionRowBuilder({\n      type: ComponentType.ActionRow,\n      components: [\n        { type: ComponentType.Button, style: ButtonStyle.Primary, label: 'string', custom_id: 'foo' },\n        { type: ComponentType.Button, style: ButtonStyle.Link, label: 'test', url: 'test' },\n        { type: ComponentType.StringSelect, custom_id: 'foo', options: [{ label: 'label', value: 'value' }] },\n      ],\n    });\n\n    await client.channels.createMessage(channel, { components: [row, row2] });\n  }\n\n  await channel.setName('foo').then(updatedChannel => {\n    console.log(`New channel name: ${updatedChannel.name}`);\n  });\n\n  // @ts-expect-error no options\n  expectNotType<Promise<GuildMember>>(g.members.add(testUserId));\n\n  // @ts-expect-error no access token\n  expectNotType<Promise<GuildMember>>(g.members.add(testUserId, {}));\n\n  expectNotType<Promise<GuildMember>>(\n    // @ts-expect-error invalid role resolvable\n    g.members.add(testUserId, { accessToken: 'totallyRealAccessToken', roles: [g.roles.cache] }),\n  );\n\n  expectType<Promise<GuildMember | null>>(\n    g.members.add(testUserId, { accessToken: 'totallyRealAccessToken', fetchWhenExisting: false }),\n  );\n\n  expectType<Promise<GuildMember>>(g.members.add(testUserId, { accessToken: 'totallyRealAccessToken' }));\n\n  expectType<Promise<GuildMember>>(\n    g.members.add(testUserId, {\n      accessToken: 'totallyRealAccessToken',\n      mute: true,\n      deaf: false,\n      roles: [g.roles.cache.first()!],\n      force: true,\n      fetchWhenExisting: true,\n    }),\n  );\n});\n\n// Event emitter static method overrides\nexpectType<Promise<[Client<true>]>>(Client.once(client, 'clientReady'));\nexpectAssignable<AsyncIterableIterator<[Client<true>]>>(Client.on(client, 'clientReady'));\n\nawait client.login('absolutely-valid-token');\n\ndeclare const loggedInClient: Client<true>;\nexpectType<ClientApplication>(loggedInClient.application);\nexpectType<Date>(loggedInClient.readyAt);\nexpectType<number>(loggedInClient.readyTimestamp);\nexpectType<string>(loggedInClient.token);\nexpectType<number>(loggedInClient.uptime);\nexpectType<ClientUser>(loggedInClient.user);\n\ndeclare const loggedOutClient: Client<false>;\nexpectType<null>(loggedOutClient.application);\nexpectType<null>(loggedOutClient.readyAt);\nexpectType<null>(loggedOutClient.readyTimestamp);\nexpectType<string | null>(loggedOutClient.token);\nexpectType<null>(loggedOutClient.uptime);\nexpectType<null>(loggedOutClient.user);\n\n// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression\nexpectType<undefined>(serialize(undefined));\nexpectType<null>(serialize(null));\nexpectType<number[]>(serialize([1, 2, 3]));\nexpectType<{}>(serialize(new Set([1, 2, 3])));\nexpectType<{}>(\n  serialize(\n    new Map([\n      [1, '2'],\n      [2, '4'],\n    ]),\n  ),\n);\nexpectType<string>(serialize(new PermissionsBitField(PermissionFlagsBits.AttachFiles)));\nexpectType<number>(serialize(new IntentsBitField(GatewayIntentBits.Guilds)));\nexpectAssignable<unknown>(\n  serialize(\n    new Collection([\n      [1, '2'],\n      [2, '4'],\n    ]),\n  ),\n);\nexpectType<never>(serialize(Symbol('a')));\nexpectType<never>(serialize(() => {}));\nexpectType<never>(serialize(BigInt(42)));\n\n// Test type return of broadcastEval:\ndeclare const shardClientUtil: ShardClientUtil;\ndeclare const shardingManager: ShardingManager;\n\nexpectType<Promise<number[]>>(shardingManager.broadcastEval(() => 1));\nexpectType<Promise<number[]>>(shardClientUtil.broadcastEval(() => 1));\nexpectType<Promise<number[]>>(shardingManager.broadcastEval(async () => 1));\nexpectType<Promise<number[]>>(shardClientUtil.broadcastEval(async () => 1));\n\ndeclare const dmChannel: DMChannel;\ndeclare const threadChannel: ThreadChannel;\ndeclare const threadChannelFromForum: ThreadChannel<true>;\ndeclare const threadChannelNotFromForum: ThreadChannel<false>;\ndeclare const announcementChannel: AnnouncementChannel;\ndeclare const textChannel: TextChannel;\ndeclare const voiceChannel: VoiceChannel;\ndeclare const user: User;\ndeclare const guildMember: GuildMember;\n\n// Test thread channels' parent inference\nexpectType<AnnouncementChannel | ForumChannel | MediaChannel | TextChannel | null>(threadChannel.parent);\nexpectType<ForumChannel | MediaChannel | null>(threadChannelFromForum.parent);\nexpectType<AnnouncementChannel | TextChannel | null>(threadChannelNotFromForum.parent);\n\n// Test whether the structures implement send\nexpectType<SendMethod<false>['send']>(dmChannel.send);\nexpectType<SendMethod<true>['send']>(threadChannel.send);\nexpectType<SendMethod<true>['send']>(announcementChannel.send);\nexpectType<SendMethod<true>['send']>(textChannel.send);\nexpectType<SendMethod<true>['send']>(voiceChannel.send);\nexpectAssignable<SendMethod>(user);\nexpectAssignable<SendMethod>(guildMember);\n\nexpectType<Promise<Message<false>>>(client.users.send(user, 'test'));\n\nexpectType<Promise<AnnouncementChannel>>(textChannel.setType(ChannelType.GuildAnnouncement));\nexpectType<Promise<TextChannel>>(announcementChannel.setType(ChannelType.GuildText));\n\nexpectType<Message | null>(dmChannel.lastMessage);\nexpectType<Message | null>(threadChannel.lastMessage);\nexpectType<Message | null>(announcementChannel.lastMessage);\nexpectType<Message | null>(textChannel.lastMessage);\nexpectType<Message | null>(voiceChannel.lastMessage);\n\nnotPropertyOf(user, 'lastMessage');\nnotPropertyOf(user, 'lastMessageId');\nnotPropertyOf(guildMember, 'lastMessage');\nnotPropertyOf(guildMember, 'lastMessageId');\n\n// Test collector event parameters\ndeclare const messageCollector: MessageCollector;\nmessageCollector.on('collect', (...args) => {\n  expectType<[Message, Collection<Snowflake, Message>]>(args);\n});\n\n(async () => {\n  for await (const value of messageCollector) {\n    expectType<[Message<boolean>, Collection<Snowflake, Message>]>(value);\n  }\n})();\n\ndeclare const reactionCollector: ReactionCollector;\nreactionCollector.on('dispose', (...args) => {\n  expectType<[MessageReaction, User]>(args);\n});\n\nreactionCollector.on('collect', (...args) => expectType<[MessageReaction, User]>(args));\nreactionCollector.on('dispose', (...args) => expectType<[MessageReaction, User]>(args));\nreactionCollector.on('remove', (...args) => expectType<[MessageReaction, User]>(args));\nreactionCollector.on('end', (...args) => expectType<[ReadonlyCollection<string, MessageReaction>, string]>(args));\n\n(async () => {\n  for await (const value of reactionCollector) {\n    expectType<[MessageReaction, User]>(value);\n  }\n})();\n\n// Make sure the properties are typed correctly, and that no backwards properties\n// (K -> V and V -> K) exist:\nexpectAssignable<'messageCreate'>(Events.MessageCreate);\nexpectAssignable<'death'>(ShardEvents.Death);\nexpectAssignable<1>(Status.Connecting);\n\ndeclare const applicationCommandData: ApplicationCommandData;\ndeclare const applicationCommandOptionData: ApplicationCommandOptionData;\ndeclare const applicationCommandResolvable: ApplicationCommandResolvable;\ndeclare const applicationCommandManager: ApplicationCommandManager;\n{\n  type ApplicationCommandScope = ApplicationCommand<{ guild: GuildResolvable }>;\n\n  expectType<Promise<ApplicationCommandScope>>(applicationCommandManager.create(applicationCommandData));\n  expectAssignable<Promise<ApplicationCommand>>(applicationCommandManager.create(applicationCommandData, '0'));\n  expectType<Promise<ApplicationCommandScope>>(\n    applicationCommandManager.edit(applicationCommandResolvable, applicationCommandData),\n  );\n  expectType<Promise<ApplicationCommand>>(\n    applicationCommandManager.edit(applicationCommandResolvable, applicationCommandData, '0'),\n  );\n  expectType<Promise<Collection<Snowflake, ApplicationCommandScope>>>(\n    applicationCommandManager.set([applicationCommandData]),\n  );\n  expectType<Promise<Collection<Snowflake, ApplicationCommand>>>(\n    applicationCommandManager.set([applicationCommandData] as const, '0'),\n  );\n\n  // Test inference of choice values.\n  if ('choices' in applicationCommandOptionData) {\n    if (applicationCommandOptionData.type === ApplicationCommandOptionType.String) {\n      expectType<string>(applicationCommandOptionData.choices[0]!.value);\n      expectNotType<number>(applicationCommandOptionData.choices[0]!.value);\n    }\n\n    if (applicationCommandOptionData.type === ApplicationCommandOptionType.Integer) {\n      expectType<number>(applicationCommandOptionData.choices[0]!.value);\n      expectNotType<string>(applicationCommandOptionData.choices[0]!.value);\n    }\n\n    if (applicationCommandOptionData.type === ApplicationCommandOptionType.Number) {\n      expectType<number>(applicationCommandOptionData.choices[0]!.value);\n      expectNotType<string>(applicationCommandOptionData.choices[0]!.value);\n    }\n  }\n}\n\ndeclare const applicationCommandPermissionsManager: ApplicationCommandPermissionsManager<\n  {},\n  {},\n  Guild | null,\n  Snowflake\n>;\n{\n  await applicationCommandPermissionsManager.add({ permissions: [], token: '' });\n  await applicationCommandPermissionsManager.add({ permissions: [] as const, token: '' });\n  await applicationCommandPermissionsManager.set({ permissions: [], token: '' });\n  await applicationCommandPermissionsManager.set({ permissions: [] as const, token: '' });\n  await applicationCommandPermissionsManager.remove({ channels: [], roles: [], users: [], token: '' });\n\n  await applicationCommandPermissionsManager.remove({\n    channels: [] as const,\n    roles: [] as const,\n    users: [] as const,\n    token: '',\n  });\n}\n\ndeclare const chatInputApplicationCommandData: ChatInputApplicationCommandData;\n{\n  chatInputApplicationCommandData.options = [];\n  chatInputApplicationCommandData.options = [] as const;\n}\n\ndeclare const applicationCommandChannelOptionData: ApplicationCommandChannelOptionData;\ndeclare const applicationCommandChannelOption: ApplicationCommandChannelOption;\n{\n  applicationCommandChannelOptionData.channelTypes = [] as const;\n  applicationCommandChannelOptionData.channel_types = [] as const;\n  applicationCommandChannelOption.channelTypes = [] as const;\n}\n\ndeclare const applicationNonChoiceOptionData: ApplicationCommandOptionData & {\n  type: CommandOptionNonChoiceResolvableType;\n};\n{\n  // Options aren't allowed on this command type.\n\n  // @ts-expect-error\n  applicationNonChoiceOptionData.choices = [];\n}\n\ndeclare const applicationCommandChoicesData: ApplicationCommandChoicesData;\ndeclare const applicationCommandChoicesOption: ApplicationCommandChoicesOption;\n{\n  applicationCommandChoicesData.choices = [];\n  applicationCommandChoicesData.choices = [] as const;\n  applicationCommandChoicesOption.choices = [];\n  applicationCommandChoicesOption.choices = [] as const;\n}\n\ndeclare const applicationCommandSubCommandData: ApplicationCommandSubCommandData;\ndeclare const applicationCommandSubCommand: ApplicationCommandSubCommand;\n{\n  applicationCommandSubCommandData.options = [];\n  applicationCommandSubCommandData.options = [] as const;\n  applicationCommandSubCommand.options = [];\n  applicationCommandSubCommand.options = [] as const;\n}\n\ndeclare const applicationSubGroupCommandData: ApplicationCommandSubGroupData;\ndeclare const applicationCommandSubGroup: ApplicationCommandSubGroup;\n{\n  expectType<ApplicationCommandOptionType.SubcommandGroup>(applicationSubGroupCommandData.type);\n  applicationSubGroupCommandData.options = [];\n  applicationSubGroupCommandData.options = [] as const;\n  applicationCommandSubGroup.options = [];\n  applicationCommandSubGroup.options = [] as const;\n}\n\ndeclare const autoModerationRuleManager: AutoModerationRuleManager;\n{\n  expectType<Promise<AutoModerationRule>>(autoModerationRuleManager.fetch('1234567890'));\n  expectType<Promise<AutoModerationRule>>(autoModerationRuleManager.fetch({ autoModerationRule: '1234567890' }));\n  expectType<Promise<AutoModerationRule>>(\n    autoModerationRuleManager.fetch({ autoModerationRule: '1234567890', cache: false }),\n  );\n  expectType<Promise<AutoModerationRule>>(\n    autoModerationRuleManager.fetch({ autoModerationRule: '1234567890', force: true }),\n  );\n  expectType<Promise<AutoModerationRule>>(\n    autoModerationRuleManager.fetch({ autoModerationRule: '1234567890', cache: false, force: true }),\n  );\n  expectType<Promise<Collection<Snowflake, AutoModerationRule>>>(autoModerationRuleManager.fetch());\n  expectType<Promise<Collection<Snowflake, AutoModerationRule>>>(autoModerationRuleManager.fetch({}));\n  expectType<Promise<Collection<Snowflake, AutoModerationRule>>>(autoModerationRuleManager.fetch({ cache: false }));\n  // @ts-expect-error The `force` option cannot be used alongside fetching all auto moderation rules.\n  await autoModerationRuleManager.fetch({ force: false });\n}\n\ndeclare const guildApplicationCommandManager: GuildApplicationCommandManager;\nexpectType<Promise<ApplicationCommand>>(guildApplicationCommandManager.fetch('0'));\nexpectType<Promise<ApplicationCommand>>(guildApplicationCommandManager.fetch({ id: '0' }));\nexpectType<Promise<Collection<Snowflake, ApplicationCommand>>>(guildApplicationCommandManager.fetch());\n\ndeclare const categoryChannelChildManager: CategoryChannelChildManager;\n{\n  expectType<Promise<VoiceChannel>>(categoryChannelChildManager.create({ name: 'name', type: ChannelType.GuildVoice }));\n  expectType<Promise<TextChannel>>(categoryChannelChildManager.create({ name: 'name', type: ChannelType.GuildText }));\n  expectType<Promise<AnnouncementChannel>>(\n    categoryChannelChildManager.create({ name: 'name', type: ChannelType.GuildAnnouncement }),\n  );\n  expectType<Promise<StageChannel>>(\n    categoryChannelChildManager.create({ name: 'name', type: ChannelType.GuildStageVoice }),\n  );\n  expectType<Promise<TextChannel>>(categoryChannelChildManager.create({ name: 'name' }));\n  expectType<Promise<TextChannel>>(categoryChannelChildManager.create({ name: 'name' }));\n}\n\ndeclare const guildChannelManager: GuildChannelManager;\n{\n  expectType<Promise<TextChannel>>(guildChannelManager.create({ name: 'name' }));\n  expectType<Promise<TextChannel>>(guildChannelManager.create({ name: 'name' }));\n  expectType<Promise<VoiceChannel>>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildVoice }));\n  expectType<Promise<CategoryChannel>>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildCategory }));\n  expectType<Promise<TextChannel>>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildText }));\n  expectType<Promise<AnnouncementChannel>>(\n    guildChannelManager.create({ name: 'name', type: ChannelType.GuildAnnouncement }),\n  );\n  expectType<Promise<StageChannel>>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildStageVoice }));\n  expectType<Promise<ForumChannel>>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildForum }));\n  expectType<Promise<MediaChannel>>(guildChannelManager.create({ name: 'name', type: ChannelType.GuildMedia }));\n\n  expectType<Promise<Collection<Snowflake, NonThreadGuildBasedChannel | null>>>(guildChannelManager.fetch());\n  expectType<Promise<Collection<Snowflake, NonThreadGuildBasedChannel | null>>>(\n    guildChannelManager.fetch(undefined, {}),\n  );\n  expectType<Promise<GuildBasedChannel | null>>(guildChannelManager.fetch('0'));\n\n  const channel = guildChannelManager.cache.first()!;\n\n  if (channel.isTextBased()) {\n    const { messages } = channel;\n    const message = await messages.fetch('123');\n    expectType<GuildMessageManager>(messages);\n    expectType<Promise<Message<true>>>(messages.crosspost('1234567890'));\n    expectType<Promise<Message<true>>>(messages.edit('1234567890', 'text'));\n    expectType<Promise<Message<true>>>(messages.fetch('1234567890'));\n    expectType<Promise<FetchPinnedMessagesResponse<true>>>(messages.fetchPins());\n    expectType<Guild>(message.guild);\n    expectType<Snowflake>(message.guildId);\n    expectType<GuildTextBasedChannel>(message.channel.messages.channel);\n  }\n}\n\n{\n  const { messages } = dmChannel;\n  const message = await messages.fetch('123');\n  expectType<DMMessageManager>(messages);\n  expectType<Promise<Message>>(messages.edit('1234567890', 'text'));\n  expectType<Promise<Message>>(messages.fetch('1234567890'));\n  expectType<Promise<FetchPinnedMessagesResponse>>(messages.fetchPins());\n  expectType<Guild | null>(message.guild);\n  expectType<Snowflake | null>(message.guildId);\n  expectType<DMChannel | GuildTextBasedChannel | PartialGroupDMChannel>(message.channel.messages.channel);\n  expectType<MessageMentions>(message.mentions);\n  expectType<Guild | null>(message.mentions.guild);\n  expectType<Collection<Snowflake, GuildMember> | null>(message.mentions.members);\n\n  if (messages.channel.isDMBased()) {\n    expectType<DMChannel>(messages.channel);\n    expectType<DMChannel>(messages.channel.messages.channel);\n  }\n\n  // @ts-expect-error Crossposting is not possible in direct messages.\n  messages.crosspost('1234567890');\n}\n\ndeclare const threadManager: ThreadManager;\n{\n  expectType<Promise<AnyThreadChannel | null>>(threadManager.fetch('12345678901234567'));\n  expectType<Promise<AnyThreadChannel | null>>(threadManager.fetch('12345678901234567', { cache: true, force: false }));\n  expectType<Promise<FetchedThreads>>(threadManager.fetch());\n  expectType<Promise<FetchedThreads>>(threadManager.fetch({}));\n  expectType<Promise<FetchedThreadsMore>>(threadManager.fetch({ archived: { limit: 4 } }));\n\n  // @ts-expect-error The force option has no effect here.\n  await threadManager.fetch({ archived: {} }, { force: true });\n}\n\ndeclare const guildForumThreadManager: GuildForumThreadManager;\nexpectType<ForumChannel | MediaChannel>(guildForumThreadManager.channel);\n\ndeclare const guildTextThreadManager: GuildTextThreadManager<\n  ChannelType.AnnouncementThread | ChannelType.PrivateThread | ChannelType.PublicThread\n>;\nexpectType<AnnouncementChannel | TextChannel>(guildTextThreadManager.channel);\n\ndeclare const guildMemberManager: GuildMemberManager;\n{\n  expectType<Promise<GuildMember>>(guildMemberManager.fetch('12345678901234567'));\n  expectType<Promise<GuildMember>>(guildMemberManager.fetch({ user: '12345678901234567' }));\n  expectType<Promise<GuildMember>>(guildMemberManager.fetch({ user: '12345678901234567', cache: true, force: false }));\n  expectType<Promise<GuildMember>>(guildMemberManager.fetch({ user: '12345678901234567', cache: true, force: false }));\n  expectType<Promise<Collection<Snowflake, GuildMember>>>(guildMemberManager.fetch());\n  expectType<Promise<Collection<Snowflake, GuildMember>>>(guildMemberManager.fetch({}));\n  expectType<Promise<Collection<Snowflake, GuildMember>>>(guildMemberManager.fetch({ user: ['12345678901234567'] }));\n  expectType<Promise<Collection<Snowflake, GuildMember>>>(guildMemberManager.fetch({ withPresences: false }));\n  expectType<Promise<GuildMember>>(guildMemberManager.fetch({ user: '12345678901234567', withPresences: true }));\n\n  expectType<Promise<Collection<Snowflake, GuildMember>>>(\n    guildMemberManager.fetch({ query: 'test', user: ['12345678901234567'], nonce: 'test' }),\n  );\n\n  // @ts-expect-error The cache & force options have no effect here.\n  await guildMemberManager.fetch({ cache: true, force: false });\n  // @ts-expect-error The force option has no effect here.\n  await guildMemberManager.fetch({ user: ['12345678901234567'], cache: true, force: false });\n}\n\ndeclare const messageManager: MessageManager;\n{\n  expectType<Promise<Message>>(messageManager.fetch('1234567890'));\n  expectType<Promise<Message>>(messageManager.fetch({ message: '1234567890' }));\n  expectType<Promise<Message>>(messageManager.fetch({ message: '1234567890', cache: true, force: false }));\n  expectType<Promise<Collection<Snowflake, Message>>>(messageManager.fetch());\n  expectType<Promise<Collection<Snowflake, Message>>>(messageManager.fetch({}));\n  expectType<Promise<Collection<Snowflake, Message>>>(\n    messageManager.fetch({ limit: 100, before: '1234567890', cache: false }),\n  );\n  // @ts-expect-error\n  await messageManager.fetch({ cache: true, force: false });\n  // @ts-expect-error\n  await messageManager.fetch({ message: '1234567890', after: '1234567890', cache: true, force: false });\n}\n\ndeclare const pollAnswerVoterManager: PollAnswerVoterManager;\n{\n  expectType<Promise<Collection<Snowflake, User>>>(pollAnswerVoterManager.fetch());\n  expectType<PollAnswer>(pollAnswerVoterManager.answer);\n}\n\ndeclare const roleManager: RoleManager;\nexpectType<Promise<Collection<Snowflake, Role>>>(roleManager.fetch());\nexpectType<Promise<Collection<Snowflake, Role>>>(roleManager.fetch(undefined, {}));\nexpectType<Promise<Role>>(roleManager.fetch('0'));\n\ndeclare const guildEmojiManager: GuildEmojiManager;\nexpectType<Promise<Collection<Snowflake, GuildEmoji>>>(guildEmojiManager.fetch());\nexpectType<Promise<Collection<Snowflake, GuildEmoji>>>(guildEmojiManager.fetch(undefined, {}));\nexpectType<Promise<GuildEmoji>>(guildEmojiManager.fetch('0'));\n\ndeclare const applicationEmojiManager: ApplicationEmojiManager;\nexpectType<Promise<Collection<Snowflake, ApplicationEmoji>>>(applicationEmojiManager.fetch());\nexpectType<Promise<Collection<Snowflake, ApplicationEmoji>>>(applicationEmojiManager.fetch(undefined, {}));\nexpectType<Promise<ApplicationEmoji>>(applicationEmojiManager.fetch('0'));\n\ndeclare const guildBanManager: GuildBanManager;\n{\n  expectType<Promise<GuildBan>>(guildBanManager.fetch('1234567890'));\n  expectType<Promise<GuildBan>>(guildBanManager.fetch({ user: '1234567890' }));\n  expectType<Promise<GuildBan>>(guildBanManager.fetch({ user: '1234567890', cache: true, force: false }));\n  expectType<Promise<Collection<Snowflake, GuildBan>>>(guildBanManager.fetch());\n  expectType<Promise<Collection<Snowflake, GuildBan>>>(guildBanManager.fetch({}));\n  expectType<Promise<Collection<Snowflake, GuildBan>>>(guildBanManager.fetch({ limit: 100, before: '1234567890' }));\n  // @ts-expect-error\n  await guildBanManager.fetch({ cache: true, force: false });\n  // @ts-expect-error\n  await guildBanManager.fetch({ user: '1234567890', after: '1234567890', cache: true, force: false });\n}\n\ndeclare const threadMemberWithGuildMember: ThreadMember<true>;\ndeclare const threadMemberManager: ThreadMemberManager;\n{\n  expectType<Promise<ThreadMember>>(threadMemberManager.fetch('12345678'));\n  expectType<Promise<ThreadMember>>(threadMemberManager.fetch({ member: '12345678', cache: false }));\n  expectType<Promise<ThreadMember>>(threadMemberManager.fetch({ member: '12345678', force: true }));\n  expectType<Promise<ThreadMember<true>>>(threadMemberManager.fetch({ member: threadMemberWithGuildMember }));\n  expectType<Promise<ThreadMember<true>>>(threadMemberManager.fetch({ member: '12345678901234567', withMember: true }));\n  expectType<Promise<Collection<Snowflake, ThreadMember>>>(threadMemberManager.fetch());\n  expectType<Promise<Collection<Snowflake, ThreadMember>>>(threadMemberManager.fetch({}));\n\n  expectType<Promise<Collection<Snowflake, ThreadMember<true>>>>(\n    threadMemberManager.fetch({ cache: true, limit: 50, withMember: true, after: '12345678901234567' }),\n  );\n\n  expectType<Promise<Collection<Snowflake, ThreadMember>>>(\n    threadMemberManager.fetch({ cache: true, withMember: false }),\n  );\n\n  // @ts-expect-error The `force` option cannot be used alongside fetching all thread members.\n  await threadMemberManager.fetch({ cache: true, force: false });\n  // @ts-expect-error `withMember` needs to be `true` to receive paginated results.\n  await threadMemberManager.fetch({ withMember: false, limit: 5, after: '12345678901234567' });\n}\n\ndeclare const typing: Typing;\nexpectType<PartialUser | User>(typing.user);\nif (typing.user.partial) expectType<null>(typing.user.username);\nif (!typing.user.partial) expectType<string>(typing.user.tag);\n\nexpectType<TextBasedChannel>(typing.channel);\nif (typing.channel.partial) expectType<undefined>(typing.channel.lastMessageId);\n\nexpectType<GuildMember | null>(typing.member);\nexpectType<Guild | null>(typing.guild);\n\nif (typing.inGuild()) {\n  expectType<Guild>(typing.channel.guild);\n  expectType<Guild>(typing.guild);\n}\n\n// Test interactions\ndeclare const interaction: Interaction;\ndeclare const booleanValue: boolean;\nif (interaction.inGuild()) {\n  expectType<Snowflake>(interaction.guildId);\n} else {\n  expectType<Snowflake | null>(interaction.guildId);\n}\n\nclient.on('interactionCreate', async interaction => {\n  if (interaction.type === InteractionType.MessageComponent) {\n    expectType<ButtonInteraction | SelectMenuInteraction>(interaction);\n    expectType<APIButtonComponent | APISelectMenuComponent | MessageActionRowComponent>(interaction.component);\n    expectType<Message>(interaction.message);\n    if (interaction.inCachedGuild()) {\n      expectAssignable<MessageComponentInteraction>(interaction);\n      expectType<MessageActionRowComponent>(interaction.component);\n      expectType<Message<true>>(interaction.message);\n      expectType<Guild>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.reply({ content: 'a', withResponse: true }));\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.deferReply({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferReply());\n      expectType<Promise<undefined>>(interaction.reply({ content: 'a', withResponse: false }));\n      expectType<Promise<undefined>>(interaction.deferReply({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse<true> | undefined>>(\n        interaction.reply({ content: 'a', withResponse: booleanValue }),\n      );\n      expectType<Promise<InteractionCallbackResponse<true> | undefined>>(\n        interaction.deferReply({ withResponse: booleanValue }),\n      );\n      expectType<Promise<Message<true>>>(interaction.editReply({ content: 'a' }));\n      expectType<Promise<Message<true>>>(interaction.fetchReply());\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.update({ content: 'a', withResponse: true }));\n      expectType<Promise<undefined>>(interaction.update());\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.deferUpdate({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferUpdate());\n      expectType<Promise<Message<true>>>(interaction.followUp({ content: 'a' }));\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.launchActivity({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.launchActivity({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse<true> | undefined>>(\n        interaction.launchActivity({ withResponse: booleanValue }),\n      );\n    } else if (interaction.inRawGuild()) {\n      expectAssignable<MessageComponentInteraction>(interaction);\n      expectType<APIButtonComponent | APISelectMenuComponent>(interaction.component);\n      expectType<Message<false>>(interaction.message);\n      expectType<null>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.reply({ content: 'a', withResponse: true }));\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.deferReply({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.reply({ content: 'a', withResponse: false }));\n      expectType<Promise<undefined>>(interaction.deferReply({ withResponse: false }));\n      expectType<Promise<undefined>>(interaction.deferReply());\n      expectType<Promise<InteractionCallbackResponse<false> | undefined>>(\n        interaction.reply({ content: 'a', withResponse: booleanValue }),\n      );\n      expectType<Promise<InteractionCallbackResponse<false> | undefined>>(\n        interaction.deferReply({ withResponse: booleanValue }),\n      );\n      expectType<Promise<Message<false>>>(interaction.editReply({ content: 'a' }));\n      expectType<Promise<Message<false>>>(interaction.fetchReply());\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.update({ content: 'a', withResponse: true }));\n      expectType<Promise<undefined>>(interaction.update({ content: 'a', withResponse: false }));\n      expectType<Promise<undefined>>(interaction.update());\n      expectType<Promise<InteractionCallbackResponse<false> | undefined>>(\n        interaction.update({ content: 'a', withResponse: booleanValue }),\n      );\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.deferUpdate({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferUpdate());\n      expectType<Promise<Message<false>>>(interaction.followUp({ content: 'a' }));\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.launchActivity({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.launchActivity({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse<false> | undefined>>(\n        interaction.launchActivity({ withResponse: booleanValue }),\n      );\n    } else if (interaction.inGuild()) {\n      expectAssignable<MessageComponentInteraction>(interaction);\n      expectType<APIButtonComponent | APISelectMenuComponent | MessageActionRowComponent>(interaction.component);\n      expectType<Message>(interaction.message);\n      expectType<Guild | null>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ content: 'a', withResponse: true }));\n      expectType<Promise<InteractionCallbackResponse>>(interaction.deferReply({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.reply({ content: 'a', withResponse: false }));\n      expectType<Promise<undefined>>(interaction.deferReply({ withResponse: false }));\n      expectType<Promise<undefined>>(interaction.deferReply());\n      expectType<Promise<InteractionCallbackResponse | undefined>>(\n        interaction.reply({ content: 'a', withResponse: booleanValue }),\n      );\n      expectType<Promise<InteractionCallbackResponse | undefined>>(\n        interaction.deferReply({ withResponse: booleanValue }),\n      );\n      expectType<Promise<Message>>(interaction.editReply({ content: 'a' }));\n      expectType<Promise<Message>>(interaction.fetchReply());\n      expectType<Promise<InteractionCallbackResponse>>(interaction.update({ content: 'a', withResponse: true }));\n      expectType<Promise<undefined>>(interaction.update({ content: 'a', withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse | undefined>>(\n        interaction.update({ content: 'a', withResponse: booleanValue }),\n      );\n      expectType<Promise<undefined>>(interaction.update());\n      expectType<Promise<InteractionCallbackResponse>>(interaction.deferUpdate({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferUpdate());\n      expectType<Promise<Message>>(interaction.followUp({ content: 'a' }));\n      expectType<Promise<InteractionCallbackResponse>>(interaction.launchActivity({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.launchActivity({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse | undefined>>(\n        interaction.launchActivity({ withResponse: booleanValue }),\n      );\n    }\n  }\n\n  if (interaction.inCachedGuild()) {\n    expectAssignable<GuildMember>(interaction.member);\n    expectNotType<ChatInputCommandInteraction<'cached'>>(interaction);\n    expectAssignable<Interaction>(interaction);\n    expectType<Locale>(interaction.guildLocale);\n  } else if (interaction.inRawGuild()) {\n    expectAssignable<APIInteractionGuildMember>(interaction.member);\n    expectNotAssignable<Interaction<'cached'>>(interaction);\n    expectType<Locale>(interaction.guildLocale);\n  } else if (interaction.inGuild()) {\n    expectType<Locale>(interaction.guildLocale);\n  } else {\n    expectType<APIInteractionGuildMember | GuildMember | null>(interaction.member);\n    expectNotAssignable<Interaction<'cached'>>(interaction);\n    expectType<string | null>(interaction.guildId);\n  }\n\n  if (\n    interaction.type === InteractionType.ApplicationCommand &&\n    (interaction.commandType === ApplicationCommandType.User ||\n      interaction.commandType === ApplicationCommandType.Message)\n  ) {\n    expectType<MessageContextMenuCommandInteraction | UserContextMenuCommandInteraction>(interaction);\n    // @ts-expect-error No attachment options on contextmenu commands\n    interaction.options.getAttachment('name');\n    if (interaction.inCachedGuild()) {\n      expectAssignable<ContextMenuCommandInteraction>(interaction);\n      expectAssignable<Guild>(interaction.guild);\n      expectAssignable<CommandInteraction<'cached'>>(interaction);\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.reply({ content: 'a', withResponse: true }));\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.deferReply({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferReply());\n      expectType<Promise<undefined>>(interaction.reply({ content: 'a', withResponse: false }));\n      expectType<Promise<undefined>>(interaction.deferReply({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse<true> | undefined>>(\n        interaction.reply({ content: 'a', withResponse: booleanValue }),\n      );\n      expectType<Promise<InteractionCallbackResponse<true> | undefined>>(\n        interaction.deferReply({ withResponse: booleanValue }),\n      );\n      expectType<Promise<Message<true>>>(interaction.editReply({ content: 'a' }));\n      expectType<Promise<Message<true>>>(interaction.fetchReply());\n      expectType<Promise<Message<true>>>(interaction.followUp({ content: 'a' }));\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.launchActivity({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.launchActivity({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse<true> | undefined>>(\n        interaction.launchActivity({ withResponse: booleanValue }),\n      );\n    } else if (interaction.inRawGuild()) {\n      expectAssignable<ContextMenuCommandInteraction>(interaction);\n      expectType<null>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.reply({ content: 'a', withResponse: true }));\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.deferReply({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferReply());\n      expectType<Promise<undefined>>(interaction.reply({ content: 'a', withResponse: false }));\n      expectType<Promise<undefined>>(interaction.deferReply({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse<false> | undefined>>(\n        interaction.reply({ content: 'a', withResponse: booleanValue }),\n      );\n      expectType<Promise<InteractionCallbackResponse<false> | undefined>>(\n        interaction.deferReply({ withResponse: booleanValue }),\n      );\n      expectType<Promise<Message<false>>>(interaction.editReply({ content: 'a' }));\n      expectType<Promise<Message<false>>>(interaction.fetchReply());\n      expectType<Promise<Message<false>>>(interaction.followUp({ content: 'a' }));\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.launchActivity({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.launchActivity({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse<false> | undefined>>(\n        interaction.launchActivity({ withResponse: booleanValue }),\n      );\n    } else if (interaction.inGuild()) {\n      expectAssignable<ContextMenuCommandInteraction>(interaction);\n      expectType<Guild | null>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ content: 'a', withResponse: true }));\n      expectType<Promise<InteractionCallbackResponse>>(interaction.deferReply({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferReply());\n      expectType<Promise<undefined>>(interaction.reply({ content: 'a', withResponse: false }));\n      expectType<Promise<undefined>>(interaction.deferReply({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse | undefined>>(\n        interaction.reply({ content: 'a', withResponse: booleanValue }),\n      );\n      expectType<Promise<InteractionCallbackResponse | undefined>>(\n        interaction.deferReply({ withResponse: booleanValue }),\n      );\n      expectType<Promise<Message>>(interaction.editReply({ content: 'a' }));\n      expectType<Promise<Message>>(interaction.fetchReply());\n      expectType<Promise<Message>>(interaction.followUp({ content: 'a' }));\n      expectType<Promise<InteractionCallbackResponse>>(interaction.launchActivity({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.launchActivity({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse | undefined>>(\n        interaction.launchActivity({ withResponse: booleanValue }),\n      );\n    }\n  }\n\n  if (\n    interaction.type === InteractionType.ApplicationCommand &&\n    interaction.commandType === ApplicationCommandType.Message\n  ) {\n    expectType<Message>(interaction.targetMessage);\n    expectType<Message | null>(interaction.options.getMessage('_MESSAGE'));\n    if (interaction.inCachedGuild()) {\n      expectType<Message<true>>(interaction.targetMessage);\n      expectType<Message<true> | null>(interaction.options.getMessage('_MESSAGE'));\n    } else if (interaction.inRawGuild()) {\n      expectType<Message<false>>(interaction.targetMessage);\n      expectType<Message<false> | null>(interaction.options.getMessage('_MESSAGE'));\n    } else if (interaction.inGuild()) {\n      expectType<Message>(interaction.targetMessage);\n      expectType<Message | null>(interaction.options.getMessage('_MESSAGE'));\n    }\n  }\n\n  if (\n    interaction.type === InteractionType.ApplicationCommand &&\n    interaction.commandType === ApplicationCommandType.User\n  ) {\n    expectType<User>(interaction.targetUser);\n    expectType<APIInteractionGuildMember | GuildMember | null>(interaction.targetMember);\n    expectType<User | null>(interaction.options.getUser('user'));\n    expectType<APIInteractionDataResolvedGuildMember | GuildMember | null>(interaction.options.getMember('user'));\n    if (interaction.inCachedGuild()) {\n      expectType<GuildMember | null>(interaction.targetMember);\n      expectType<GuildMember | null>(interaction.options.getMember('user'));\n    } else if (interaction.inRawGuild()) {\n      expectType<APIInteractionGuildMember | null>(interaction.targetMember);\n      expectType<APIInteractionDataResolvedGuildMember | null>(interaction.options.getMember('user'));\n    } else if (interaction.inGuild()) {\n      expectType<APIInteractionGuildMember | GuildMember | null>(interaction.targetMember);\n      expectType<APIInteractionDataResolvedGuildMember | GuildMember | null>(interaction.options.getMember('user'));\n    }\n  }\n\n  if (interaction.type === InteractionType.MessageComponent && interaction.componentType === ComponentType.Button) {\n    expectType<ButtonInteraction>(interaction);\n    expectType<APIButtonComponent | ButtonComponent>(interaction.component);\n    expectType<Message>(interaction.message);\n    if (interaction.inCachedGuild()) {\n      expectAssignable<ButtonInteraction>(interaction);\n      expectType<ButtonComponent>(interaction.component);\n      expectType<Message<true>>(interaction.message);\n      expectType<Guild>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.reply({ withResponse: true }));\n    } else if (interaction.inRawGuild()) {\n      expectAssignable<ButtonInteraction>(interaction);\n      expectType<APIButtonComponent>(interaction.component);\n      expectType<Message<false>>(interaction.message);\n      expectType<null>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.reply({ withResponse: true }));\n    } else if (interaction.inGuild()) {\n      expectAssignable<ButtonInteraction>(interaction);\n      expectType<APIButtonComponent | ButtonComponent>(interaction.component);\n      expectType<Message>(interaction.message);\n      expectAssignable<Guild | null>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ withResponse: true }));\n    }\n  }\n\n  if (\n    interaction.type === InteractionType.MessageComponent &&\n    interaction.componentType === ComponentType.StringSelect\n  ) {\n    expectType<StringSelectMenuInteraction>(interaction);\n    expectType<APIStringSelectComponent | StringSelectMenuComponent>(interaction.component);\n    expectType<Message>(interaction.message);\n    if (interaction.inCachedGuild()) {\n      expectAssignable<StringSelectMenuInteraction>(interaction);\n      expectType<StringSelectMenuComponent>(interaction.component);\n      expectType<Message<true>>(interaction.message);\n      expectType<Guild>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.reply({ withResponse: true }));\n    } else if (interaction.inRawGuild()) {\n      expectAssignable<StringSelectMenuInteraction>(interaction);\n      expectType<APIStringSelectComponent>(interaction.component);\n      expectType<Message<false>>(interaction.message);\n      expectType<null>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.reply({ withResponse: true }));\n    } else if (interaction.inGuild()) {\n      expectAssignable<StringSelectMenuInteraction>(interaction);\n      expectType<APIStringSelectComponent | StringSelectMenuComponent>(interaction.component);\n      expectType<Message>(interaction.message);\n      expectType<Guild | null>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ withResponse: true }));\n    }\n  }\n\n  if (\n    interaction.type === InteractionType.ApplicationCommand &&\n    interaction.commandType === ApplicationCommandType.ChatInput\n  ) {\n    if (interaction.inRawGuild()) {\n      expectNotAssignable<Interaction<'cached'>>(interaction);\n      expectAssignable<ChatInputCommandInteraction>(interaction);\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.reply({ withResponse: true }));\n      expectType<APIInteractionDataResolvedGuildMember | null>(interaction.options.getMember('test'));\n\n      expectType<APIInteractionDataResolvedChannel>(interaction.options.getChannel('test', true));\n      expectType<APIRole>(interaction.options.getRole('test', true));\n    } else if (interaction.inCachedGuild()) {\n      expectType<GuildMember | null>(interaction.options.getMember('test'));\n      expectAssignable<ChatInputCommandInteraction>(interaction);\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.reply({ withResponse: true }));\n\n      expectType<GuildBasedChannel>(interaction.options.getChannel('test', true));\n      expectType<Role>(interaction.options.getRole('test', true));\n\n      expectType<PublicThreadChannel>(interaction.options.getChannel('test', true, [ChannelType.PublicThread]));\n      expectType<PublicThreadChannel>(interaction.options.getChannel('test', true, [ChannelType.AnnouncementThread]));\n      expectType<PublicThreadChannel>(\n        interaction.options.getChannel('test', true, [ChannelType.PublicThread, ChannelType.AnnouncementThread]),\n      );\n      expectType<PrivateThreadChannel>(interaction.options.getChannel('test', true, [ChannelType.PrivateThread]));\n\n      expectType<TextChannel>(interaction.options.getChannel('test', true, [ChannelType.GuildText]));\n      expectType<TextChannel | null>(interaction.options.getChannel('test', false, [ChannelType.GuildText]));\n      expectType<ForumChannel | VoiceChannel>(\n        interaction.options.getChannel('test', true, [ChannelType.GuildForum, ChannelType.GuildVoice]),\n      );\n      expectType<TextChannel>(interaction.options.getChannel('test', true, [ChannelType.GuildText] as const));\n      expectType<ForumChannel | VoiceChannel | null>(\n        interaction.options.getChannel('test', false, [ChannelType.GuildForum, ChannelType.GuildVoice]),\n      );\n      expectType<MediaChannel>(interaction.options.getChannel('test', true, [ChannelType.GuildMedia]));\n    } else {\n      expectType<ChatInputCommandInteraction>(interaction);\n      expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ withResponse: true }));\n      expectType<APIInteractionDataResolvedGuildMember | GuildMember | null>(interaction.options.getMember('test'));\n\n      expectType<APIInteractionDataResolvedChannel | GuildBasedChannel>(interaction.options.getChannel('test', true));\n      expectType<APIRole | Role>(interaction.options.getRole('test', true));\n    }\n\n    expectType<ChatInputCommandInteraction>(interaction);\n    expectType<Omit<CommandInteractionOptionResolver<CacheType>, 'getFocused' | 'getMessage'>>(interaction.options);\n    expectType<readonly CommandInteractionOption[]>(interaction.options.data);\n\n    const optionalOption = interaction.options.get('name');\n    const requiredOption = interaction.options.get('name', true);\n    expectType<CommandInteractionOption | null>(optionalOption);\n    expectType<CommandInteractionOption>(requiredOption);\n    expectType<readonly CommandInteractionOption[] | undefined>(requiredOption.options);\n\n    expectType<string | null>(interaction.options.getString('name', booleanValue));\n    expectType<string | null>(interaction.options.getString('name', false));\n    expectType<string>(interaction.options.getString('name', true));\n\n    expectType<string>(interaction.options.getSubcommand());\n    expectType<string>(interaction.options.getSubcommand(true));\n    expectType<string | null>(interaction.options.getSubcommand(booleanValue));\n    expectType<string | null>(interaction.options.getSubcommand(false));\n\n    expectType<string>(interaction.options.getSubcommandGroup(true));\n    expectType<string | null>(interaction.options.getSubcommandGroup());\n    expectType<string | null>(interaction.options.getSubcommandGroup(booleanValue));\n    expectType<string | null>(interaction.options.getSubcommandGroup(false));\n\n    // @ts-expect-error\n    interaction.options.getMessage('name');\n  }\n\n  if (\n    interaction.type === InteractionType.ApplicationCommand &&\n    interaction.commandType === ApplicationCommandType.PrimaryEntryPoint\n  ) {\n    expectType<PrimaryEntryPointCommandInteraction>(interaction);\n\n    // @ts-expect-error No options on primary entry point commands\n    interaction.options = [];\n    if (interaction.inCachedGuild()) {\n      expectAssignable<PrimaryEntryPointCommandInteraction>(interaction);\n      expectAssignable<Guild>(interaction.guild);\n      expectAssignable<CommandInteraction<'cached'>>(interaction);\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.reply({ content: 'a', withResponse: true }));\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.deferReply({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferReply());\n      expectType<Promise<undefined>>(interaction.reply({ content: 'a', withResponse: false }));\n      expectType<Promise<undefined>>(interaction.deferReply({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse<true> | undefined>>(\n        interaction.reply({ content: 'a', withResponse: booleanValue }),\n      );\n      expectType<Promise<InteractionCallbackResponse<true> | undefined>>(\n        interaction.deferReply({ withResponse: booleanValue }),\n      );\n      expectType<Promise<Message<true>>>(interaction.editReply({ content: 'a' }));\n      expectType<Promise<Message<true>>>(interaction.fetchReply());\n      expectType<Promise<Message<true>>>(interaction.followUp({ content: 'a' }));\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.launchActivity({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.launchActivity({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse<true> | undefined>>(\n        interaction.launchActivity({ withResponse: booleanValue }),\n      );\n    } else if (interaction.inRawGuild()) {\n      expectAssignable<PrimaryEntryPointCommandInteraction>(interaction);\n      expectType<null>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.reply({ content: 'a', withResponse: true }));\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.deferReply({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferReply());\n      expectType<Promise<undefined>>(interaction.reply({ content: 'a', withResponse: false }));\n      expectType<Promise<undefined>>(interaction.deferReply({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse<false> | undefined>>(\n        interaction.reply({ content: 'a', withResponse: booleanValue }),\n      );\n      expectType<Promise<InteractionCallbackResponse<false> | undefined>>(\n        interaction.deferReply({ withResponse: booleanValue }),\n      );\n      expectType<Promise<Message<false>>>(interaction.editReply({ content: 'a' }));\n      expectType<Promise<Message<false>>>(interaction.fetchReply());\n      expectType<Promise<Message<false>>>(interaction.followUp({ content: 'a' }));\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.launchActivity({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.launchActivity({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse<false> | undefined>>(\n        interaction.launchActivity({ withResponse: booleanValue }),\n      );\n    } else if (interaction.inGuild()) {\n      expectAssignable<PrimaryEntryPointCommandInteraction>(interaction);\n      expectType<Guild | null>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ content: 'a', withResponse: true }));\n      expectType<Promise<InteractionCallbackResponse>>(interaction.deferReply({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferReply());\n      expectType<Promise<undefined>>(interaction.reply({ content: 'a', withResponse: false }));\n      expectType<Promise<undefined>>(interaction.deferReply({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse | undefined>>(\n        interaction.reply({ content: 'a', withResponse: booleanValue }),\n      );\n      expectType<Promise<InteractionCallbackResponse | undefined>>(\n        interaction.deferReply({ withResponse: booleanValue }),\n      );\n      expectType<Promise<Message>>(interaction.editReply({ content: 'a' }));\n      expectType<Promise<Message>>(interaction.fetchReply());\n      expectType<Promise<Message>>(interaction.followUp({ content: 'a' }));\n      expectType<Promise<InteractionCallbackResponse>>(interaction.launchActivity({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.launchActivity({ withResponse: false }));\n      expectType<Promise<InteractionCallbackResponse | undefined>>(\n        interaction.launchActivity({ withResponse: booleanValue }),\n      );\n    }\n  }\n\n  if (interaction.isRepliable()) {\n    expectAssignable<RepliableInteraction>(interaction);\n    await interaction.reply('test');\n    await interaction.reply({ withResponse: false });\n  }\n\n  if (\n    interaction.type === InteractionType.ApplicationCommand &&\n    interaction.commandType === ApplicationCommandType.ChatInput &&\n    interaction.isRepliable()\n  ) {\n    expectAssignable<CommandInteraction>(interaction);\n    expectAssignable<RepliableInteraction>(interaction);\n  }\n\n  if (interaction.type === InteractionType.ModalSubmit && interaction.isRepliable()) {\n    expectType<ModalSubmitInteraction>(interaction);\n    if (interaction.inCachedGuild()) {\n      expectAssignable<ModalSubmitInteraction>(interaction);\n      expectType<Guild>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.reply({ content: 'a', withResponse: true }));\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.deferReply({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferReply());\n      expectType<Promise<Message<true>>>(interaction.editReply({ content: 'a' }));\n      expectType<Promise<Message<true>>>(interaction.fetchReply());\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.deferUpdate({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferUpdate());\n      expectType<Promise<Message<true>>>(interaction.followUp({ content: 'a' }));\n      expectType<Promise<InteractionCallbackResponse<true>>>(interaction.launchActivity({ withResponse: true }));\n    } else if (interaction.inRawGuild()) {\n      expectAssignable<ModalSubmitInteraction>(interaction);\n      expectType<null>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.reply({ content: 'a', withResponse: true }));\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.deferReply({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferReply());\n      expectType<Promise<Message<false>>>(interaction.editReply({ content: 'a' }));\n      expectType<Promise<Message<false>>>(interaction.fetchReply());\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.deferUpdate({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferUpdate());\n      expectType<Promise<Message<false>>>(interaction.followUp({ content: 'a' }));\n      expectType<Promise<InteractionCallbackResponse<false>>>(interaction.launchActivity({ withResponse: true }));\n    } else if (interaction.inGuild()) {\n      expectAssignable<ModalSubmitInteraction>(interaction);\n      expectType<Guild | null>(interaction.guild);\n      expectType<Promise<InteractionCallbackResponse>>(interaction.reply({ content: 'a', withResponse: true }));\n      expectType<Promise<InteractionCallbackResponse>>(interaction.deferReply({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferReply());\n      expectType<Promise<Message>>(interaction.editReply({ content: 'a' }));\n      expectType<Promise<Message>>(interaction.fetchReply());\n      expectType<Promise<InteractionCallbackResponse>>(interaction.deferUpdate({ withResponse: true }));\n      expectType<Promise<undefined>>(interaction.deferUpdate());\n      expectType<Promise<Message>>(interaction.followUp({ content: 'a' }));\n      expectType<Promise<InteractionCallbackResponse>>(interaction.launchActivity({ withResponse: true }));\n    }\n  }\n});\n\ndeclare const shard: Shard;\n\nshard.on('death', process => {\n  expectType<ChildProcess | Worker>(process);\n});\n\ndeclare const collector: Collector<string, Interaction, string[]>;\n\ncollector.on('collect', (collected, ...other) => {\n  expectType<Interaction>(collected);\n  expectType<string[]>(other);\n});\n\ncollector.on('dispose', (vals, ...other) => {\n  expectType<Interaction>(vals);\n  expectType<string[]>(other);\n});\n\ncollector.on('end', (collection, reason) => {\n  expectType<ReadonlyCollection<string, Interaction>>(collection);\n  expectType<string>(reason);\n});\n\n(async () => {\n  for await (const value of collector) {\n    expectType<[Interaction, ...string[]]>(value);\n  }\n})();\n\nexpectType<Promise<number | null>>(shard.eval(client => client.readyTimestamp));\n\n// Test audit logs\nexpectType<Promise<GuildAuditLogs<AuditLogEvent.MemberKick>>>(guild.fetchAuditLogs({ type: AuditLogEvent.MemberKick }));\n\nexpectType<Promise<GuildAuditLogs<AuditLogEvent.ChannelCreate>>>(\n  guild.fetchAuditLogs({ type: AuditLogEvent.ChannelCreate }),\n);\n\nexpectType<Promise<GuildAuditLogs<AuditLogEvent.IntegrationUpdate>>>(\n  guild.fetchAuditLogs({ type: AuditLogEvent.IntegrationUpdate }),\n);\n\nexpectType<Promise<GuildAuditLogs<AuditLogEvent>>>(guild.fetchAuditLogs({ type: null }));\nexpectType<Promise<GuildAuditLogs<AuditLogEvent>>>(guild.fetchAuditLogs());\n\nexpectType<Promise<GuildAuditLogsEntry<AuditLogEvent.MemberKick, 'Delete', 'User'> | undefined>>(\n  guild.fetchAuditLogs({ type: AuditLogEvent.MemberKick }).then(al => al.entries.first()),\n);\nexpectAssignable<Promise<GuildAuditLogsEntry<AuditLogEvent.MemberKick, 'Delete', 'User'> | undefined>>(\n  guild.fetchAuditLogs({ type: AuditLogEvent.MemberKick }).then(al => al.entries.first()),\n);\n\nexpectType<Promise<GuildAuditLogsEntry<AuditLogEvent, GuildAuditLogsActionType, GuildAuditLogsTargetType> | undefined>>(\n  guild.fetchAuditLogs({ type: null }).then(al => al.entries.first()),\n);\nexpectType<Promise<GuildAuditLogsEntry<AuditLogEvent, GuildAuditLogsActionType, GuildAuditLogsTargetType> | undefined>>(\n  guild.fetchAuditLogs().then(al => al.entries.first()),\n);\n\nexpectType<Promise<{ integrationType: string } | null | undefined>>(\n  guild.fetchAuditLogs({ type: AuditLogEvent.MemberKick }).then(al => al.entries.first()?.extra),\n);\n\nexpectType<Promise<{ integrationType: string } | null | undefined>>(\n  guild.fetchAuditLogs({ type: AuditLogEvent.MemberRoleUpdate }).then(al => al.entries.first()?.extra),\n);\n\nexpectType<Promise<StageChannel | { id: Snowflake } | undefined>>(\n  guild.fetchAuditLogs({ type: AuditLogEvent.StageInstanceCreate }).then(al => al.entries.first()?.extra),\n);\nexpectType<Promise<{ channel: GuildTextBasedChannel | { id: Snowflake }; count: number } | undefined>>(\n  guild.fetchAuditLogs({ type: AuditLogEvent.MessageDelete }).then(al => al.entries.first()?.extra),\n);\n\nexpectType<Promise<PartialUser | User | null | undefined>>(\n  guild.fetchAuditLogs({ type: AuditLogEvent.MemberKick }).then(al => al.entries.first()?.target),\n);\nexpectType<Promise<StageInstance | undefined>>(\n  guild.fetchAuditLogs({ type: AuditLogEvent.StageInstanceCreate }).then(al => al.entries.first()?.target),\n);\nexpectType<Promise<User | null | undefined>>(\n  guild.fetchAuditLogs({ type: AuditLogEvent.MessageDelete }).then(al => al.entries.first()?.target),\n);\nexpectType<Promise<GuildTextBasedChannel | { id: string } | undefined>>(\n  guild.fetchAuditLogs({ type: AuditLogEvent.MessageBulkDelete }).then(al => al.entries.first()?.target),\n);\n\ndeclare const AuditLogChange: AuditLogChange;\n// @ts-expect-error\nexpectType<boolean | undefined>(AuditLogChange.old);\n// @ts-expect-error\nexpectType<boolean | undefined>(AuditLogChange.new);\nif (AuditLogChange.key === 'available') {\n  expectType<boolean | undefined>(AuditLogChange.old);\n  expectType<boolean | undefined>(AuditLogChange.new);\n}\n\ndeclare const TextBasedChannel: TextBasedChannel;\ndeclare const TextBasedChannelTypes: TextBasedChannelTypes;\ndeclare const VoiceBasedChannel: VoiceBasedChannel;\ndeclare const GuildBasedChannel: GuildBasedChannel;\ndeclare const NonThreadGuildBasedChannel: NonThreadGuildBasedChannel;\ndeclare const GuildTextBasedChannel: GuildTextBasedChannel;\n\nexpectType<TextBasedChannel>(TextBasedChannel);\nexpectType<\n  | ChannelType.DM\n  | ChannelType.GroupDM\n  | ChannelType.GuildAnnouncement\n  | ChannelType.GuildStageVoice\n  | ChannelType.GuildText\n  | ChannelType.GuildVoice\n  | ThreadChannelType\n>(TextBasedChannelTypes);\nexpectType<StageChannel | VoiceChannel>(VoiceBasedChannel);\nexpectType<GuildBasedChannel>(GuildBasedChannel);\nexpectType<\n  AnnouncementChannel | CategoryChannel | ForumChannel | MediaChannel | StageChannel | TextChannel | VoiceChannel\n>(NonThreadGuildBasedChannel);\nexpectType<GuildTextBasedChannel>(GuildTextBasedChannel);\n\nnew EmbedBuilder().setColor(resolveColor('#ffffff'));\n\nexpectNotAssignable<ActionRowData<MessageActionRowComponentData>>({\n  type: ComponentType.ActionRow,\n  components: [\n    {\n      type: ComponentType.Button,\n    },\n  ],\n});\n\ndeclare const chatInputInteraction: ChatInputCommandInteraction;\n\nexpectType<Attachment>(chatInputInteraction.options.getAttachment('attachment', true));\nexpectType<Attachment | null>(chatInputInteraction.options.getAttachment('attachment'));\n\ndeclare const modal: ModalBuilder;\n\nawait chatInputInteraction.showModal(modal);\n\nawait chatInputInteraction.showModal({\n  title: 'abc',\n  custom_id: 'abc',\n  components: [\n    {\n      component: {\n        type: ComponentType.StringSelect,\n        id: 2,\n        custom_id: 'aa',\n        options: [{ label: 'a', value: 'b' }],\n      },\n      type: ComponentType.Label,\n      label: 'yo',\n    },\n  ],\n});\n\nawait chatInputInteraction.showModal({\n  title: 'abc',\n  customId: 'abc',\n  components: [\n    {\n      type: ComponentType.Label,\n      component: {\n        type: ComponentType.TextInput,\n        style: TextInputStyle.Short,\n        customId: 'aa',\n      },\n      label: 'yo',\n    },\n    {\n      type: ComponentType.Label,\n      component: {\n        type: ComponentType.UserSelect,\n        customId: 'user',\n      },\n      label: 'aa',\n    },\n    {\n      type: ComponentType.Label,\n      component: {\n        type: ComponentType.RoleSelect,\n        customId: 'role',\n      },\n      label: 'bb',\n    },\n    {\n      type: ComponentType.Label,\n      component: {\n        type: ComponentType.ChannelSelect,\n        customId: 'channel',\n        channelTypes: [ChannelType.GuildText, ChannelType.GuildVoice],\n      },\n      label: 'cc',\n    },\n  ],\n});\n\ndeclare const stringSelectMenuComp: StringSelectMenuComponent;\nnew StringSelectMenuBuilder(stringSelectMenuComp.toJSON());\n\ndeclare const userSelectMenuComp: UserSelectMenuComponent;\nnew UserSelectMenuBuilder(userSelectMenuComp.toJSON());\n\ndeclare const roleSelectMenuComp: RoleSelectMenuComponent;\nnew RoleSelectMenuBuilder(roleSelectMenuComp.toJSON());\n\ndeclare const channelSelectMenuComp: ChannelSelectMenuComponent;\nnew ChannelSelectMenuBuilder(channelSelectMenuComp.toJSON());\n\ndeclare const mentionableSelectMenuComp: MentionableSelectMenuComponent;\nnew MentionableSelectMenuBuilder(mentionableSelectMenuComp.toJSON());\n\ndeclare const buttonData: APIButtonComponentWithCustomId;\nnew PrimaryButtonBuilder(buttonData);\n\ndeclare const buttonComp: ButtonComponent;\ncreateComponentBuilder(buttonComp.toJSON());\n\ndeclare const textInputData: APITextInputComponent;\nnew TextInputBuilder(textInputData);\n\ndeclare const textInputComp: TextInputComponent;\nnew TextInputBuilder(textInputComp.toJSON());\n\ndeclare const embedData: APIEmbed;\nnew EmbedBuilder(embedData);\n\ndeclare const embedComp: Embed;\nnew EmbedBuilder(embedComp.toJSON());\n\ndeclare const actionRowComp: ActionRow<ActionRowComponent>;\nnew ActionRowBuilder(actionRowComp.toJSON());\n\ntype UserMentionChannels = DMChannel | PartialDMChannel;\ndeclare const channelMentionChannels: Exclude<Channel | DirectoryChannel, UserMentionChannels>;\ndeclare const userMentionChannels: UserMentionChannels;\n\nexpectType<ChannelMention>(channelMentionChannels.toString());\nexpectType<UserMention>(userMentionChannels.toString());\nexpectType<UserMention>(user.toString());\nexpectType<UserMention>(guildMember.toString());\n\ndeclare const webhook: Webhook;\ndeclare const interactionWebhook: InteractionWebhook;\ndeclare const snowflake: Snowflake;\n\nexpectType<Promise<Message<true>>>(webhook.send('content'));\nexpectType<Promise<Message<true>>>(webhook.editMessage(snowflake, 'content'));\nexpectType<Promise<Message<true>>>(webhook.fetchMessage(snowflake));\nexpectType<Promise<Webhook>>(webhook.edit({ name: 'name' }));\n\nexpectType<Client<true>>(interactionWebhook.client);\nexpectType<Promise<Message>>(interactionWebhook.send('content'));\nexpectType<Promise<Message>>(interactionWebhook.editMessage(snowflake, 'content'));\nexpectType<Promise<Message>>(interactionWebhook.fetchMessage(snowflake));\n\ndeclare const partialGroupDMChannel: PartialGroupDMChannel;\ndeclare const categoryChannel: CategoryChannel;\ndeclare const stageChannel: StageChannel;\ndeclare const forumChannel: ForumChannel;\ndeclare const mediaChannel: MediaChannel;\ndeclare const threadOnlyChannel: ThreadOnlyChannel;\n\n// Threads have messages.\nexpectType<GuildMessageManager>(threadChannel.messages);\n\n// Thread-only channels have threads—not messages.\nnotPropertyOf(threadOnlyChannel, 'messages');\nnotPropertyOf(forumChannel, 'messages');\nnotPropertyOf(mediaChannel, 'messages');\n\nawait forumChannel.edit({\n  availableTags: [...forumChannel.availableTags, { name: 'tag' }],\n});\n\nawait forumChannel.setAvailableTags([{ ...forumChannel.availableTags, name: 'tag' }]);\nawait forumChannel.setAvailableTags([{ name: 'tag' }]);\n\nexpectType<Readonly<ChannelFlagsBitField>>(textChannel.flags);\nexpectType<Readonly<ChannelFlagsBitField>>(voiceChannel.flags);\nexpectType<Readonly<ChannelFlagsBitField>>(stageChannel.flags);\nexpectType<Readonly<ChannelFlagsBitField>>(forumChannel.flags);\nexpectType<Readonly<ChannelFlagsBitField>>(dmChannel.flags);\nexpectType<Readonly<ChannelFlagsBitField>>(categoryChannel.flags);\nexpectType<Readonly<ChannelFlagsBitField>>(announcementChannel.flags);\nexpectType<Readonly<ChannelFlagsBitField>>(categoryChannel.flags);\nexpectType<Readonly<ChannelFlagsBitField>>(threadChannel.flags);\n\nexpectType<null>(partialGroupDMChannel.flags);\n\n// Select menu type narrowing\nif (interaction.isSelectMenu()) {\n  expectType<SelectMenuInteraction>(interaction);\n}\n\ndeclare const anySelectMenu: SelectMenuInteraction;\n\nif (anySelectMenu.isStringSelectMenu()) {\n  expectType<StringSelectMenuInteraction>(anySelectMenu);\n} else if (anySelectMenu.isUserSelectMenu()) {\n  expectType<UserSelectMenuInteraction>(anySelectMenu);\n} else if (anySelectMenu.isRoleSelectMenu()) {\n  expectType<RoleSelectMenuInteraction>(anySelectMenu);\n} else if (anySelectMenu.isChannelSelectMenu()) {\n  expectType<ChannelSelectMenuInteraction>(anySelectMenu);\n} else if (anySelectMenu.isMentionableSelectMenu()) {\n  expectType<MentionableSelectMenuInteraction>(anySelectMenu);\n}\n\nclient.on('guildAuditLogEntryCreate', (auditLogEntry, guild) => {\n  expectType<GuildAuditLogsEntry>(auditLogEntry);\n  expectType<Guild>(guild);\n});\n\nexpectType<Readonly<GuildMemberFlagsBitField>>(guildMember.flags);\n\ndeclare const emojiResolvable: Emoji | GuildEmoji | string;\n\n{\n  const onboarding = await guild.fetchOnboarding();\n  expectType<GuildOnboarding>(onboarding);\n\n  expectType<GuildOnboarding>(await guild.editOnboarding(onboarding));\n\n  await guild.editOnboarding({\n    defaultChannels: onboarding.defaultChannels,\n    enabled: onboarding.enabled,\n    mode: onboarding.mode,\n    prompts: onboarding.prompts,\n  });\n\n  const prompt = onboarding.prompts.first()!;\n  const option = prompt.options.first()!;\n\n  await guild.editOnboarding({ prompts: [prompt] });\n  await guild.editOnboarding({ prompts: [{ ...prompt, options: [option] }] });\n\n  await guild.editOnboarding({ prompts: [{ ...prompt, options: [{ ...option, emoji: emojiResolvable }] }] });\n}\n\ndeclare const partialDMChannel: PartialDMChannel;\nexpectType<true>(partialDMChannel.partial);\nexpectType<undefined>(partialDMChannel.lastMessageId);\n\ndeclare const partialGuildMember: PartialGuildMember;\nexpectType<true>(partialGuildMember.partial);\nexpectType<null>(partialGuildMember.joinedAt);\nexpectType<null>(partialGuildMember.joinedTimestamp);\nexpectType<null>(partialGuildMember.pending);\n\ndeclare const partialMessage: PartialMessage;\nexpectType<true>(partialMessage.partial);\nexpectType<null>(partialMessage.type);\nexpectType<null>(partialMessage.system);\nexpectType<null>(partialMessage.pinned);\nexpectType<null>(partialMessage.tts);\nexpectAssignable<Message['content'] | null>(partialMessage.content);\nexpectAssignable<Message['cleanContent'] | null>(partialMessage.cleanContent);\nexpectAssignable<Message['author'] | null>(partialMessage.author);\n\ndeclare const partialMessageReaction: PartialMessageReaction;\nexpectType<true>(partialMessageReaction.partial);\nexpectType<null>(partialMessageReaction.count);\n\ndeclare const partialThreadMember: PartialThreadMember;\nexpectType<true>(partialThreadMember.partial);\nexpectType<null>(partialThreadMember.flags);\nexpectType<null>(partialThreadMember.joinedAt);\nexpectType<null>(partialThreadMember.joinedTimestamp);\n\ndeclare const partialUser: PartialUser;\nexpectType<true>(partialUser.partial);\nexpectType<null>(partialUser.username);\nexpectType<null>(partialUser.tag);\nexpectType<null>(partialUser.discriminator);\n\ndeclare const application: ClientApplication;\ndeclare const entitlement: Entitlement;\ndeclare const sku: SKU;\n{\n  expectType<Collection<Snowflake, SKU>>(await application.fetchSKUs());\n  expectType<Collection<Snowflake, Entitlement>>(await application.entitlements.fetch());\n\n  await application.entitlements.fetch({\n    guild,\n    skus: ['12345678901234567', sku],\n    user,\n    excludeEnded: true,\n    limit: 10,\n  });\n\n  await application.entitlements.createTest({ sku: '12345678901234567', user });\n  await application.entitlements.createTest({ sku, guild });\n\n  await application.entitlements.deleteTest(entitlement);\n\n  await application.entitlements.consume(snowflake);\n\n  expectType<boolean>(entitlement.isActive());\n\n  if (entitlement.isUserSubscription()) {\n    expectType<Snowflake>(entitlement.userId);\n    expectType<User>(await entitlement.fetchUser());\n    expectType<null>(entitlement.guildId);\n    expectType<null>(entitlement.guild);\n\n    await application.entitlements.deleteTest(entitlement);\n  } else if (entitlement.isGuildSubscription()) {\n    expectType<Snowflake>(entitlement.guildId);\n    expectType<Guild>(entitlement.guild);\n\n    await application.entitlements.deleteTest(entitlement);\n  }\n\n  if (entitlement.isTest()) {\n    expectType<null>(entitlement.startsTimestamp);\n    expectType<null>(entitlement.endsTimestamp);\n    expectType<null>(entitlement.startsAt);\n    expectType<null>(entitlement.endsAt);\n  }\n\n  client.on(Events.InteractionCreate, async interaction => {\n    expectType<Collection<Snowflake, Entitlement>>(interaction.entitlements);\n  });\n}\n\nawait client.channels.createMessage('123', {\n  poll: {\n    question: {\n      text: 'Question',\n    },\n    duration: 60,\n    answers: [{ text: 'Answer 1' }, { text: 'Answer 2', emoji: '<:1blade:874989932983238726>' }],\n    allowMultiselect: false,\n  },\n});\n\ndeclare const partialPoll: PartialPoll;\n{\n  if (partialPoll.partial) {\n    expectType<null>(partialPoll.question.text);\n    expectType<PartialMessage>(partialPoll.message);\n    expectType<null>(partialPoll.allowMultiselect);\n    expectType<null>(partialPoll.layoutType);\n    expectType<null>(partialPoll.expiresTimestamp);\n    expectType<Collection<number, PartialPollAnswer>>(partialPoll.answers);\n  }\n}\n\ndeclare const partialPollAnswer: PartialPollAnswer;\n{\n  if (partialPollAnswer.partial) {\n    expectType<PartialPoll>(partialPollAnswer.poll);\n    expectType<null>(partialPollAnswer.emoji);\n    expectType<null>(partialPollAnswer.text);\n  }\n}\n\ndeclare const poll: Poll;\ndeclare const message: Message;\ndeclare const pollData: PollData;\n{\n  expectType<Message>(await poll.end());\n  expectType<false>(poll.partial);\n  expectNotType<Collection<number, PartialPollAnswer>>(poll.answers);\n\n  const answer = poll.answers.first()!;\n\n  if (!answer.partial) {\n    expectType<number>(answer.voteCount);\n    expectType<number>(answer.id);\n    expectType<PollAnswerVoterManager>(answer.voters);\n    expectType<Collection<Snowflake, User>>(await answer.voters.fetch({ after: snowflake, limit: 10 }));\n  }\n\n  await messageManager.endPoll(snowflake);\n  await messageManager.fetchPollAnswerVoters({\n    messageId: snowflake,\n    answerId: 1,\n  });\n\n  await message.edit({\n    // @ts-expect-error\n    poll: pollData,\n  });\n\n  await chatInputInteraction.editReply({ poll: pollData });\n}\n\nexpectType<Collection<Snowflake, StickerPack>>(await client.fetchStickerPacks());\nexpectType<Collection<Snowflake, StickerPack>>(await client.fetchStickerPacks({}));\nexpectType<StickerPack>(await client.fetchStickerPacks({ packId: snowflake }));\n\nclient.on('interactionCreate', async interaction => {\n  if (!interaction.channel) {\n    return;\n  }\n\n  // @ts-expect-error\n  interaction.channel.send();\n\n  if (interaction.channel.isSendable()) {\n    expectType<SendableChannels>(interaction.channel);\n    await interaction.channel.send({ embeds: [] });\n  }\n});\n\ndeclare const guildScheduledEventManager: GuildScheduledEventManager;\nawait guildScheduledEventManager.edit(snowflake, { recurrenceRule: null });\n\n{\n  expectNotAssignable<GuildScheduledEventRecurrenceRuleOptions>({\n    startAt: new Date(),\n    frequency: GuildScheduledEventRecurrenceRuleFrequency.Yearly,\n    interval: 1,\n    byMonth: [GuildScheduledEventRecurrenceRuleMonth.May],\n    byMonthDay: [4],\n    // Invalid property\n    byWeekday: [GuildScheduledEventRecurrenceRuleWeekday.Monday],\n  });\n\n  expectNotAssignable<GuildScheduledEventRecurrenceRuleOptions>({\n    startAt: new Date(),\n    frequency: GuildScheduledEventRecurrenceRuleFrequency.Yearly,\n    interval: 1,\n    byMonth: [GuildScheduledEventRecurrenceRuleMonth.May],\n    byMonthDay: [4],\n    // Invalid property\n    byNWeekday: [{ n: 1, day: GuildScheduledEventRecurrenceRuleWeekday.Monday }],\n  });\n\n  expectAssignable<GuildScheduledEventRecurrenceRuleOptions>({\n    startAt: new Date(),\n    frequency: GuildScheduledEventRecurrenceRuleFrequency.Yearly,\n    interval: 1,\n    byMonth: [GuildScheduledEventRecurrenceRuleMonth.May],\n    byMonthDay: [4],\n  });\n}\n\n{\n  expectAssignable<GuildScheduledEventRecurrenceRuleOptions>({\n    startAt: new Date(),\n    frequency: GuildScheduledEventRecurrenceRuleFrequency.Monthly,\n    interval: 1,\n    byNWeekday: [{ n: 1, day: GuildScheduledEventRecurrenceRuleWeekday.Monday }],\n  });\n\n  expectNotAssignable<GuildScheduledEventRecurrenceRuleOptions>({\n    startAt: new Date(),\n    frequency: GuildScheduledEventRecurrenceRuleFrequency.Monthly,\n    interval: 1,\n    byNWeekday: [{ n: 1, day: GuildScheduledEventRecurrenceRuleWeekday.Monday }],\n    // Invalid property\n    byWeekday: [GuildScheduledEventRecurrenceRuleWeekday.Monday],\n  });\n}\n\n{\n  expectAssignable<GuildScheduledEventRecurrenceRuleOptions>({\n    startAt: new Date(),\n    frequency: GuildScheduledEventRecurrenceRuleFrequency.Weekly,\n    interval: 1,\n    byWeekday: [GuildScheduledEventRecurrenceRuleWeekday.Monday],\n  });\n\n  expectNotAssignable<GuildScheduledEventRecurrenceRuleOptions>({\n    startAt: new Date(),\n    frequency: GuildScheduledEventRecurrenceRuleFrequency.Weekly,\n    interval: 1,\n    byWeekday: [GuildScheduledEventRecurrenceRuleWeekday.Monday],\n    // Invalid property\n    byNWeekday: [{ n: 1, day: GuildScheduledEventRecurrenceRuleWeekday.Monday }],\n  });\n}\n\n{\n  expectNotAssignable<GuildScheduledEventRecurrenceRuleOptions>({\n    startAt: new Date(),\n    frequency: GuildScheduledEventRecurrenceRuleFrequency.Daily,\n    interval: 1,\n    byWeekday: [GuildScheduledEventRecurrenceRuleWeekday.Monday],\n    // Invalid property\n    byNWeekday: [{ n: 1, day: GuildScheduledEventRecurrenceRuleWeekday.Monday }],\n  });\n\n  expectNotAssignable<GuildScheduledEventRecurrenceRuleOptions>({\n    startAt: new Date(),\n    frequency: GuildScheduledEventRecurrenceRuleFrequency.Daily,\n    interval: 1,\n    byWeekday: [GuildScheduledEventRecurrenceRuleWeekday.Monday],\n    // Invalid property\n    byMonth: [GuildScheduledEventRecurrenceRuleMonth.May],\n  });\n}\n\nawait textChannel.send(\n  new MessageBuilder()\n    .setContent(':)')\n    .addAttachments(attachment => attachment.setId(1).setFileData(':)').setFilename('smiley.txt')),\n);\n\nawait textChannel.send({\n  files: [\n    {\n      attachment: 'https://example.com/voice-message.ogg',\n      duration: 2,\n      waveform: 'AFUqPDw3Eg2hh4+gopOYj4xthU4=',\n    },\n  ],\n  flags: MessageFlags.IsVoiceMessage,\n});\n\ndeclare const authorizingIntegrationOwners: AuthorizingIntegrationOwners;\n{\n  expectType<Snowflake | null>(authorizingIntegrationOwners.guildId);\n  expectType<Guild | null>(authorizingIntegrationOwners.guild);\n  expectType<Snowflake | null>(authorizingIntegrationOwners.userId);\n  expectType<User | null>(authorizingIntegrationOwners.user);\n  expectType<Snowflake | undefined>(authorizingIntegrationOwners[ApplicationIntegrationType.GuildInstall]);\n}\n"
  },
  {
    "path": "packages/discord.js/typings/tsdoc-metadata.json",
    "content": "// This file is read by tools that parse documentation comments conforming to the TSDoc standard.\n// It should be published with your NPM package.  It should not be tracked by Git.\n{\n  \"tsdocVersion\": \"0.12\",\n  \"toolPackages\": [\n    {\n      \"packageName\": \"@discordjs/api-extractor\",\n      \"packageVersion\": \"7.52.7\"\n    }\n  ]\n}\n"
  },
  {
    "path": "packages/docgen/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\n\n# Miscellaneous\n.turbo\n.tmp\n"
  },
  {
    "path": "packages/docgen/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/docgen/.prettierignore",
    "content": ".turbo\ndist\ncoverage\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/docgen/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/docgen/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2022 Noel Buechler\n   Copyright 2015 Amish Shah\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/docgen/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [npm][npm]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested.  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/docgen\n[npm]: https://www.npmjs.com/package/@discordjs/docgen\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/docgen/bin/index.js",
    "content": "#!/usr/bin/env node\nrequire('../dist/bin/index.js');\n"
  },
  {
    "path": "packages/docgen/bin/index.ts",
    "content": "#!/usr/bin/env node\n\nimport process from 'node:process';\nimport { createCommand } from 'commander';\nimport packageFile from '../package.json';\nimport { build } from '../src/index.js';\n\nexport interface CLIOptions {\n\tcustom: string;\n\tinput: string[];\n\tnewOutput: string;\n\toutput: string;\n\troot: string;\n\ttypescript: boolean;\n}\n\nconst command = createCommand()\n\t.version(packageFile.version)\n\t.option('-i, --input <string...>', 'Source directories to parse JSDocs in')\n\t.option('-c, --custom <string>', 'Custom docs definition file to use')\n\t.option('-r, --root [string]', 'Root directory of the project', '.')\n\t.option('-o, --output <string>', 'Path to output file')\n\t.option('--typescript', '', false);\n\nconst program = command.parse(process.argv);\nconst options = program.opts<CLIOptions>();\n\nvoid build(options);\n"
  },
  {
    "path": "packages/docgen/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/docgen\",\n\t\"version\": \"0.12.1\",\n\t\"description\": \"The docs.json generator for discord.js and its related projects\",\n\t\"private\": true,\n\t\"scripts\": {\n\t\t\"build\": \"tsup\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src\",\n\t\t\"fmt\": \"pnpm run format\",\n\t\t\"prepack\": \"pnpm run format && pnpm run build\"\n\t},\n\t\"bin\": \"./bin/index.js\",\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/src/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/src/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/src/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/src/index.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"main\": \"./dist/src/index.js\",\n\t\"module\": \"./dist/src/index.mjs\",\n\t\"types\": \"./dist/src/index.d.ts\",\n\t\"directories\": {\n\t\t\"bin\": \"bin\",\n\t\t\"lib\": \"src\"\n\t},\n\t\"files\": [\n\t\t\"bin/index.js\",\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"Amish Shah <amishshah.2k@gmail.com>\",\n\t\t\"Schuyler Cebulskie <Gawdl3y@Gawdl3y.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"documentation\",\n\t\t\"docs\",\n\t\t\"generator\",\n\t\t\"docgen\",\n\t\t\"docsgen\",\n\t\t\"node\",\n\t\t\"discordjs\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/docgen\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"commander\": \"^14.0.3\",\n\t\t\"jsdoc-to-markdown\": \"^8.0.3\",\n\t\t\"tslib\": \"^2.8.1\",\n\t\t\"typedoc\": \"^0.25.13\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@types/jsdoc-to-markdown\": \"^7.0.6\",\n\t\t\"@types/node\": \"^24.10.13\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"terser\": \"^5.46.0\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/docgen/src/documentation.ts",
    "content": "import { dirname, join, relative } from 'node:path';\nimport type { DeclarationReflection } from 'typedoc';\nimport packageFile from '../package.json';\nimport type { ChildTypes, Class, Config, CustomDocs, RootTypes } from './interfaces/index.js';\nimport { DocumentedClass } from './types/class.js';\nimport { DocumentedConstructor } from './types/constructor.js';\nimport { DocumentedEvent } from './types/event.js';\nimport { DocumentedExternal } from './types/external.js';\nimport { DocumentedInterface } from './types/interface.js';\nimport { DocumentedMember } from './types/member.js';\nimport { DocumentedMethod } from './types/method.js';\nimport { DocumentedTypeDef } from './types/typedef.js';\n\nexport class Documentation {\n\tpublic readonly classes = new Map<string, DocumentedClass>();\n\n\tpublic readonly functions = new Map<string, DocumentedMethod>();\n\n\tpublic readonly interfaces = new Map<string, DocumentedInterface>();\n\n\tpublic readonly typedefs = new Map<string, DocumentedTypeDef>();\n\n\tpublic readonly externals = new Map<string, DocumentedExternal>();\n\n\tpublic constructor(\n\t\tdata: DeclarationReflection[] | RootTypes[],\n\t\tprivate readonly config: Config,\n\t\tprivate readonly custom?: Record<string, CustomDocs>,\n\t) {\n\t\tif (config.typescript) {\n\t\t\tconst items = data as DeclarationReflection[];\n\n\t\t\tfor (const item of items) {\n\t\t\t\tswitch (item.kindString) {\n\t\t\t\t\tcase 'Class': {\n\t\t\t\t\t\tthis.classes.set(item.name, new DocumentedClass(item, config));\n\t\t\t\t\t\tif (item.children) {\n\t\t\t\t\t\t\tthis.parse(item.children, item);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 'Function': {\n\t\t\t\t\t\tthis.functions.set(item.name, new DocumentedMethod(item, config));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 'Interface':\n\t\t\t\t\tcase 'Type alias':\n\t\t\t\t\tcase 'Enumeration':\n\t\t\t\t\t\tthis.typedefs.set(item.name, new DocumentedTypeDef(item, config));\n\t\t\t\t\t\tif (item.children) {\n\t\t\t\t\t\t\tthis.parse(item.children, item);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tlet items = data as RootTypes[];\n\t\t\titems = items.filter((item) => !item.ignore);\n\n\t\t\tfor (const item of items) {\n\t\t\t\tswitch (item.kind) {\n\t\t\t\t\tcase 'class': {\n\t\t\t\t\t\tthis.classes.set(item.name, new DocumentedClass(item, config));\n\t\t\t\t\t\titems = items.filter((otherItem) => otherItem.longname !== item.longname || otherItem.kind !== item.kind);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 'function': {\n\t\t\t\t\t\tif (item.scope === 'global' || !item.memberof) {\n\t\t\t\t\t\t\tthis.functions.set(item.name, new DocumentedMethod(item, config));\n\t\t\t\t\t\t\titems = items.filter((otherItem) => otherItem.longname !== item.longname);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 'interface': {\n\t\t\t\t\t\tthis.interfaces.set(item.name, new DocumentedInterface(item as unknown as Class, config));\n\t\t\t\t\t\titems = items.filter((otherItem) => otherItem.longname !== item.longname);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 'typedef': {\n\t\t\t\t\t\tthis.typedefs.set(item.name, new DocumentedTypeDef(item, config));\n\t\t\t\t\t\titems = items.filter((otherItem) => otherItem.longname !== item.longname);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 'external': {\n\t\t\t\t\t\tthis.externals.set(item.name, new DocumentedExternal(item, config));\n\t\t\t\t\t\titems = items.filter((otherItem) => otherItem.longname !== item.longname);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.parse(items as ChildTypes[]);\n\t\t}\n\t}\n\n\tpublic parse(items: ChildTypes[] | DeclarationReflection[], prop?: DeclarationReflection) {\n\t\tif (this.config.typescript) {\n\t\t\tconst it = items as DeclarationReflection[];\n\n\t\t\tfor (const member of it) {\n\t\t\t\tlet item: DocumentedConstructor | DocumentedEvent | DocumentedMember | DocumentedMethod | null = null;\n\n\t\t\t\tswitch (member.kindString) {\n\t\t\t\t\tcase 'Constructor': {\n\t\t\t\t\t\titem = new DocumentedConstructor(member, this.config);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 'Method': {\n\t\t\t\t\t\tconst event = prop?.groups?.find((group) => group.title === 'Events');\n\t\t\t\t\t\tif ((event?.children as unknown as number[])?.includes(member.id)) {\n\t\t\t\t\t\t\titem = new DocumentedEvent(member, this.config);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\titem = new DocumentedMethod(member, this.config);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 'Property': {\n\t\t\t\t\t\titem = new DocumentedMember(member, this.config);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tconsole.warn(`- Unknown documentation kind \"${member.kindString}\" - \\n${JSON.stringify(member)}\\n`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst parent = this.classes.get(prop!.name) ?? this.interfaces.get(prop!.name);\n\t\t\t\tif (parent) {\n\t\t\t\t\tif (item) {\n\t\t\t\t\t\tparent.add(item);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`- Documentation item could not be constructed for \"${member.name}\" - \\n${JSON.stringify(member)}\\n`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst info = [];\n\t\t\t\tconst name = (member.name || item?.data.name) ?? 'UNKNOWN';\n\t\t\t\tconst meta =\n\t\t\t\t\tmember.kindString === 'constructor'\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\tfile: member.sources?.[0]?.fileName,\n\t\t\t\t\t\t\t\tline: member.sources?.[0]?.line,\n\t\t\t\t\t\t\t\tpath: dirname(member.sources?.[0]?.fileName ?? ''),\n\t\t\t\t\t\t\t};\n\n\t\t\t\tif (prop!.name) {\n\t\t\t\t\tinfo.push(`member of \"${prop!.name}\"`);\n\t\t\t\t}\n\n\t\t\t\tif (meta) {\n\t\t\t\t\tinfo.push(\n\t\t\t\t\t\t`${relative(this.config.root, join(meta.path, meta.file ?? ''))}${meta.line ? `:${meta.line}` : ''}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconsole.warn(`- \"${name}\"${info.length ? ` (${info.join(', ')})` : ''} has no accessible parent.`);\n\t\t\t\tif (!name && !info.length) {\n\t\t\t\t\tconsole.warn('Raw object:', member);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst it = items as ChildTypes[];\n\n\t\t\tfor (const member of it) {\n\t\t\t\tlet item: DocumentedConstructor | DocumentedEvent | DocumentedMember | DocumentedMethod | null = null;\n\n\t\t\t\tswitch (member.kind) {\n\t\t\t\t\tcase 'constructor': {\n\t\t\t\t\t\titem = new DocumentedConstructor(member, this.config);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 'function': {\n\t\t\t\t\t\titem = new DocumentedMethod(member, this.config);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 'member': {\n\t\t\t\t\t\titem = new DocumentedMember(member, this.config);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase 'event': {\n\t\t\t\t\t\titem = new DocumentedEvent(member, this.config);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\t// @ts-expect-error: This is a valid case\n\t\t\t\t\t\tconsole.warn(`- Unknown documentation kind \"${member.kind}\" - \\n${JSON.stringify(member)}\\n`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst parent = this.classes.get(member.memberof ?? '') ?? this.interfaces.get(member.memberof ?? '');\n\t\t\t\tif (parent) {\n\t\t\t\t\tif (item) {\n\t\t\t\t\t\tparent.add(item);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`- Documentation item could not be constructed for \"${member.name}\" - \\n${JSON.stringify(member)}\\n`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst info = [];\n\t\t\t\tconst name = (member.name || item?.data.name) ?? 'UNKNOWN';\n\t\t\t\t// @ts-expect-error: Typescript can't infer this\n\t\t\t\tconst memberof = member.memberof ?? item?.data?.memberof;\n\t\t\t\tconst meta =\n\t\t\t\t\tmember.kind === 'constructor'\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: { file: member.meta.filename, line: member.meta.lineno, path: member.meta.path };\n\n\t\t\t\tif (memberof) {\n\t\t\t\t\tinfo.push(`member of \"${memberof as string}\"`);\n\t\t\t\t}\n\n\t\t\t\tif (meta) {\n\t\t\t\t\tinfo.push(`${relative(this.config.root, join(meta.path, meta.file))}${meta.line ? `:${meta.line}` : ''}`);\n\t\t\t\t}\n\n\t\t\t\tconsole.warn(`- \"${name}\"${info.length ? ` (${info.join(', ')})` : ''} has no accessible parent.`);\n\t\t\t\tif (!name && !info.length) {\n\t\t\t\t\tconsole.warn('Raw object:', member);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic serialize() {\n\t\treturn {\n\t\t\tmeta: {\n\t\t\t\tgenerator: packageFile.version,\n\t\t\t\tformat: Documentation.FORMAT_VERSION,\n\t\t\t\tdate: Date.now(),\n\t\t\t},\n\t\t\tclasses: [...this.classes.values()].map((_class) => _class.serialize()),\n\t\t\tfunctions: [...this.functions.values()].map((_function) => _function.serialize()),\n\t\t\tinterfaces: [...this.interfaces.values()].map((_interface) => _interface.serialize()),\n\t\t\ttypedefs: [...this.typedefs.values()].map((_typedef) => _typedef.serialize()),\n\t\t\texternals: [...this.externals.values()].map((_external) => _external.serialize()),\n\t\t\tcustom: this.custom,\n\t\t};\n\t}\n\n\tpublic serializeNew() {\n\t\treturn {\n\t\t\tmetadata: {\n\t\t\t\ttoolPackage: '@discordjs/docgen',\n\t\t\t\ttoolVersion: Documentation.FORMAT_VERSION,\n\t\t\t\tschemaVersion: 1_011,\n\t\t\t\toldestForwardsCompatibleVersion: 1_001,\n\t\t\t\ttsdocConfig: {\n\t\t\t\t\t$schema: 'https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json',\n\t\t\t\t\tnoStandardTags: true,\n\t\t\t\t\ttagDefinitions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@alpha',\n\t\t\t\t\t\t\tsyntaxKind: 'modifier',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@beta',\n\t\t\t\t\t\t\tsyntaxKind: 'modifier',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@defaultValue',\n\t\t\t\t\t\t\tsyntaxKind: 'block',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@decorator',\n\t\t\t\t\t\t\tsyntaxKind: 'block',\n\t\t\t\t\t\t\tallowMultiple: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@deprecated',\n\t\t\t\t\t\t\tsyntaxKind: 'block',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@eventProperty',\n\t\t\t\t\t\t\tsyntaxKind: 'modifier',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@example',\n\t\t\t\t\t\t\tsyntaxKind: 'block',\n\t\t\t\t\t\t\tallowMultiple: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@experimental',\n\t\t\t\t\t\t\tsyntaxKind: 'modifier',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@inheritDoc',\n\t\t\t\t\t\t\tsyntaxKind: 'inline',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@internal',\n\t\t\t\t\t\t\tsyntaxKind: 'modifier',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@label',\n\t\t\t\t\t\t\tsyntaxKind: 'inline',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@link',\n\t\t\t\t\t\t\tsyntaxKind: 'inline',\n\t\t\t\t\t\t\tallowMultiple: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@override',\n\t\t\t\t\t\t\tsyntaxKind: 'modifier',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@packageDocumentation',\n\t\t\t\t\t\t\tsyntaxKind: 'modifier',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@param',\n\t\t\t\t\t\t\tsyntaxKind: 'block',\n\t\t\t\t\t\t\tallowMultiple: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@privateRemarks',\n\t\t\t\t\t\t\tsyntaxKind: 'block',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@public',\n\t\t\t\t\t\t\tsyntaxKind: 'modifier',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@readonly',\n\t\t\t\t\t\t\tsyntaxKind: 'modifier',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@remarks',\n\t\t\t\t\t\t\tsyntaxKind: 'block',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@returns',\n\t\t\t\t\t\t\tsyntaxKind: 'block',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@sealed',\n\t\t\t\t\t\t\tsyntaxKind: 'modifier',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@see',\n\t\t\t\t\t\t\tsyntaxKind: 'block',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@throws',\n\t\t\t\t\t\t\tsyntaxKind: 'block',\n\t\t\t\t\t\t\tallowMultiple: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@typeParam',\n\t\t\t\t\t\t\tsyntaxKind: 'block',\n\t\t\t\t\t\t\tallowMultiple: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@virtual',\n\t\t\t\t\t\t\tsyntaxKind: 'modifier',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@betaDocumentation',\n\t\t\t\t\t\t\tsyntaxKind: 'modifier',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@internalRemarks',\n\t\t\t\t\t\t\tsyntaxKind: 'block',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttagName: '@preapproved',\n\t\t\t\t\t\t\tsyntaxKind: 'modifier',\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tsupportForTags: {\n\t\t\t\t\t\t'@alpha': true,\n\t\t\t\t\t\t'@beta': true,\n\t\t\t\t\t\t'@defaultValue': true,\n\t\t\t\t\t\t'@decorator': true,\n\t\t\t\t\t\t'@deprecated': true,\n\t\t\t\t\t\t'@eventProperty': true,\n\t\t\t\t\t\t'@example': true,\n\t\t\t\t\t\t'@experimental': true,\n\t\t\t\t\t\t'@inheritDoc': true,\n\t\t\t\t\t\t'@internal': true,\n\t\t\t\t\t\t'@label': true,\n\t\t\t\t\t\t'@link': true,\n\t\t\t\t\t\t'@override': true,\n\t\t\t\t\t\t'@packageDocumentation': true,\n\t\t\t\t\t\t'@param': true,\n\t\t\t\t\t\t'@privateRemarks': true,\n\t\t\t\t\t\t'@public': true,\n\t\t\t\t\t\t'@readonly': true,\n\t\t\t\t\t\t'@remarks': true,\n\t\t\t\t\t\t'@returns': true,\n\t\t\t\t\t\t'@sealed': true,\n\t\t\t\t\t\t'@see': true,\n\t\t\t\t\t\t'@throws': true,\n\t\t\t\t\t\t'@typeParam': true,\n\t\t\t\t\t\t'@virtual': true,\n\t\t\t\t\t\t'@betaDocumentation': true,\n\t\t\t\t\t\t'@internalRemarks': true,\n\t\t\t\t\t\t'@preapproved': true,\n\t\t\t\t\t},\n\t\t\t\t\treportUnsupportedHtmlElements: false,\n\t\t\t\t},\n\t\t\t},\n\t\t\tprojectFolderUrl: 'https://github.com/discordjs/discord.js/tree/main/packages/discord.js',\n\t\t\tkind: 'Package',\n\t\t\tcanonicalReference: 'discord.js!',\n\t\t\tdocComment: '',\n\t\t\tname: 'discord.js',\n\t\t\tpreserveMemberOrder: false,\n\t\t\tmembers: [\n\t\t\t\t...[...this.classes.values()].map((_class) => _class.serialize()),\n\t\t\t\t...[...this.functions.values()].map((_function) => _function.serialize()),\n\t\t\t\t...[...this.interfaces.values()].map((_interface) => _interface.serialize()),\n\t\t\t\t...[...this.typedefs.values()].map((_typedef) => _typedef.serialize()),\n\t\t\t\t...[...this.externals.values()].map((_external) => _external.serialize()),\n\t\t\t],\n\t\t\tcustom: this.custom,\n\t\t};\n\t}\n\n\tpublic static readonly FORMAT_VERSION = 30;\n}\n"
  },
  {
    "path": "packages/docgen/src/index.ts",
    "content": "import { readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join, extname, basename, relative } from 'node:path';\nimport jsdoc2md from 'jsdoc-to-markdown';\nimport { type DeclarationReflection, Application, TSConfigReader } from 'typedoc';\nimport type { CLIOptions } from '../bin/index.js';\nimport { Documentation } from './documentation.js';\nimport type { RootTypes, ChildTypes, CustomDocs } from './interfaces/index.js';\n\ninterface CustomFiles {\n\tfiles: {\n\t\tid?: string;\n\t\tname: string;\n\t\tpath: string;\n\t}[];\n\tid?: string;\n\tname: string;\n\tpath?: string;\n}\n\nexport async function build({ input, custom: customDocs, root, output, newOutput, typescript }: CLIOptions) {\n\tlet data: (ChildTypes & RootTypes)[] | DeclarationReflection[] = [];\n\tif (typescript) {\n\t\tconsole.log('Parsing Typescript in source files...');\n\t\tconst app = await Application.bootstrap({ entryPoints: input }, [new TSConfigReader()]);\n\t\tconst project = await app.convert();\n\t\tif (project) {\n\t\t\t// @ts-expect-error: Types are lost with this method\n\t\t\tdata = app.serializer.toObject(project).children!;\n\t\t\tconsole.log(`${data.length} items parsed.`);\n\t\t}\n\t} else {\n\t\tconsole.log('Parsing JSDocs in source files...');\n\n\t\tdata = jsdoc2md.getTemplateDataSync({ files: input }) as (ChildTypes & RootTypes)[];\n\t\tconsole.log(`${data.length} JSDoc items parsed.`);\n\t}\n\n\tconst custom: Record<string, CustomDocs> = {};\n\tif (customDocs) {\n\t\tconsole.log('Loading custom docs files...');\n\t\tconst customDir = dirname(customDocs);\n\t\tconst file = readFileSync(customDocs, 'utf8');\n\t\tconst data = JSON.parse(file) as CustomFiles[];\n\n\t\tfor (const category of data) {\n\t\t\tconst categoryId = category.id ?? category.name.toLowerCase();\n\t\t\tconst dir = join(customDir, category.path ?? categoryId);\n\t\t\tcustom[categoryId] = {\n\t\t\t\tname: category.name || category.id!,\n\t\t\t\tfiles: {},\n\t\t\t};\n\n\t\t\tfor (const file of category.files) {\n\t\t\t\tconst fileRootPath = join(dir, file.path);\n\t\t\t\tconst extension = extname(file.path);\n\t\t\t\tconst fileId = file.id ?? basename(file.path, extension);\n\t\t\t\tconst fileData = readFileSync(fileRootPath, 'utf8');\n\t\t\t\tcustom[categoryId]!.files[fileId] = {\n\t\t\t\t\tname: file.name,\n\t\t\t\t\ttype: extension.toLowerCase().replace(/^\\./, ''),\n\t\t\t\t\tcontent: fileData,\n\t\t\t\t\tpath: relative(root, fileRootPath).replaceAll('\\\\', '/'),\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tconst fileCount = Object.keys(custom)\n\t\t\t.map((key) => Object.keys(custom[key]!))\n\t\t\t.reduce((prev, content) => prev + content.length, 0);\n\t\tconst categoryCount = Object.keys(custom).length;\n\t\tconsole.log(\n\t\t\t`${fileCount} custom docs file${fileCount === 1 ? '' : 's'} in ` +\n\t\t\t\t`${categoryCount} categor${categoryCount === 1 ? 'y' : 'ies'} loaded.`,\n\t\t);\n\t}\n\n\tconsole.log(`Serializing documentation with format version ${Documentation.FORMAT_VERSION}...`);\n\tconst docs = new Documentation(data, { input, custom: customDocs, root, output, typescript }, custom);\n\n\tif (output) {\n\t\tconsole.log(`Writing to ${output}...`);\n\t\twriteFileSync(output, JSON.stringify(docs.serialize()));\n\t}\n\n\tif (newOutput) {\n\t\tconsole.log(`Writing to ${newOutput}...`);\n\t\twriteFileSync(newOutput, JSON.stringify(docs.serializeNew()));\n\t}\n\n\tconsole.log('Done!');\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/access.type.ts",
    "content": "export type Access = 'private' | 'protected' | 'public';\n"
  },
  {
    "path": "packages/docgen/src/interfaces/childTypes.type.ts",
    "content": "import type { Constructor, Event, Member, Method } from './index.js';\n\nexport type ChildTypes = Constructor | Event | Member | Method;\n"
  },
  {
    "path": "packages/docgen/src/interfaces/class.interface.ts",
    "content": "import type { Access, Item, Meta, Scope } from './index.js';\n\nexport interface Class extends Item {\n\taccess?: Access;\n\taugments?: string[];\n\tdeprecated?: boolean | string;\n\timplements?: string[];\n\tkind: 'class';\n\tmeta: Meta;\n\tscope: Scope;\n\tsee?: string[];\n\tvirtual?: boolean;\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/config.interface.ts",
    "content": "export interface Config {\n\tcustom: string;\n\tinput: string[];\n\toutput: string;\n\troot: string;\n\ttypescript: boolean;\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/constructor.interface.ts",
    "content": "import type { Access, Item, Param } from './index.js';\n\nexport interface Constructor extends Item {\n\taccess?: Access;\n\tkind: 'constructor';\n\tmemberof: string;\n\tparams?: Param[];\n\tsee?: string[];\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/customDocs.interface.ts",
    "content": "export interface CustomDocs {\n\tfiles: Record<\n\t\tstring,\n\t\t{\n\t\t\tcontent?: string;\n\t\t\tname?: string;\n\t\t\tpath?: string;\n\t\t\ttype?: string;\n\t\t}\n\t>;\n\tname?: string;\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/event.interface.ts",
    "content": "import type { Item, Meta, Param, Scope } from './index.js';\n\nexport interface Event extends Item {\n\tdeprecated?: boolean | string;\n\tkind: 'event';\n\tmemberof: string;\n\tmeta: Meta;\n\tparams?: Param[];\n\tscope: Scope;\n\tsee?: string[];\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/exception.interface.ts",
    "content": "import type { Type } from './index.js';\n\nexport interface Exception {\n\tdescription?: string;\n\tnullable?: boolean;\n\ttype: Type;\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/external.interface.ts",
    "content": "import type { Item, Meta } from './index.js';\n\nexport interface External extends Item {\n\tkind: 'external';\n\tmeta: Meta;\n\tsee?: string[];\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/index.ts",
    "content": "export type * from './access.type.js';\nexport type * from './childTypes.type';\nexport type * from './class.interface.js';\nexport type * from './config.interface.js';\nexport type * from './constructor.interface.js';\nexport type * from './customDocs.interface.js';\nexport type * from './event.interface.js';\nexport type * from './exception.interface.js';\nexport type * from './external.interface.js';\nexport type * from './interface.interface.js';\nexport type * from './item.interface.js';\nexport type * from './member.interface.js';\nexport type * from './meta.interface.js';\nexport type * from './method.interface.js';\nexport type * from './param.interface.js';\nexport type * from './return.interface.js';\nexport type * from './rootTypes.type.js';\nexport type * from './scope.type.js';\nexport type * from './type.interface.js';\nexport type * from './typedef.interface.js';\nexport type * from './var-type.interface';\n"
  },
  {
    "path": "packages/docgen/src/interfaces/interface.interface.ts",
    "content": "import type { Class } from './index.js';\n\n// @ts-expect-error: Inheritance type error\nexport interface Interface extends Class {\n\tclassdesc: string;\n\tkind: 'interface';\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/item.interface.ts",
    "content": "export interface Item {\n\tdescription: string;\n\tid: string;\n\tignore?: boolean;\n\tkind: string;\n\tlongname: string;\n\tname: string;\n\torder: number;\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/member.interface.ts",
    "content": "import type { Access, Item, Meta, Param, Scope, Type } from './index.js';\n\nexport interface Member extends Item {\n\taccess?: Access;\n\tdefault?: string;\n\tdeprecated?: boolean | string;\n\tkind: 'member';\n\tmemberof: string;\n\tmeta: Meta;\n\tnullable?: boolean;\n\tproperties?: Param[];\n\treadonly?: boolean;\n\tscope: Scope;\n\tsee?: string[];\n\ttype: Type;\n\tvirtual?: boolean;\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/meta.interface.ts",
    "content": "export interface Meta {\n\tfilename: string;\n\tlineno: number;\n\tpath: string;\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/method.interface.ts",
    "content": "import type { Access, Exception, Item, Meta, Param, Return, Scope } from './index.js';\n\nexport interface Method extends Item {\n\taccess?: Access;\n\tasync?: boolean;\n\tdeprecated?: boolean | string;\n\texamples?: string[];\n\texceptions?: Exception[];\n\tfires?: string[];\n\tgenerator?: boolean;\n\timplements?: string[];\n\tinherited?: boolean;\n\tinherits?: string;\n\tkind: 'function';\n\tmemberof?: string;\n\tmeta: Meta;\n\tparams?: Param[];\n\treturns?: Return[];\n\tscope: Scope;\n\tsee?: string[];\n\tvirtual?: boolean;\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/param.interface.ts",
    "content": "import type { Type } from './index.js';\n\nexport interface Param {\n\tdefaultvalue?: string;\n\tdescription: string;\n\tname: string;\n\tnullable?: boolean;\n\toptional?: boolean;\n\ttype: Type;\n\tvariable?: string;\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/return.interface.ts",
    "content": "import type { Type } from './index.js';\n\nexport interface Return {\n\tdescription?: string;\n\tnullable?: boolean;\n\ttype: Required<Type>;\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/rootTypes.type.ts",
    "content": "import type { Class, External, Interface, Method, Typedef } from './index.js';\n\nexport type RootTypes = Class | External | Interface | Method | Typedef;\n"
  },
  {
    "path": "packages/docgen/src/interfaces/scope.type.ts",
    "content": "export type Scope = 'global' | 'instance' | 'static';\n"
  },
  {
    "path": "packages/docgen/src/interfaces/type.interface.ts",
    "content": "export interface Type {\n\tnames?: string[] | undefined;\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/typedef.interface.ts",
    "content": "import type { Access, Item, Meta, Param, Return, Scope, Type } from './index.js';\n\nexport interface Typedef extends Item {\n\taccess?: Access;\n\tdeprecated?: boolean | string;\n\tkind: 'typedef';\n\tmeta: Meta;\n\tparams?: Param[];\n\tproperties?: Param[];\n\treturns?: Return[];\n\tscope: Scope;\n\tsee?: string[];\n\ttype: Type;\n}\n"
  },
  {
    "path": "packages/docgen/src/interfaces/var-type.interface.ts",
    "content": "import type { Type } from './index.js';\n\nexport interface VarType extends Type {\n\tdescription?: string | undefined;\n\tnullable?: boolean | undefined;\n\ttype?: Required<Type> | undefined;\n}\n"
  },
  {
    "path": "packages/docgen/src/types/class.ts",
    "content": "import { parse } from 'node:path';\nimport type { DeclarationReflection } from 'typedoc';\nimport type { Class, Config } from '../interfaces/index.js';\nimport { parseType } from '../util/parseType.js';\nimport { DocumentedConstructor } from './constructor.js';\nimport { DocumentedEvent } from './event.js';\nimport { DocumentedItemMeta } from './item-meta.js';\nimport { DocumentedItem } from './item.js';\nimport { DocumentedMember } from './member.js';\nimport { DocumentedMethod } from './method.js';\nimport { DocumentedVarType } from './var-type.js';\n\nexport class DocumentedClass extends DocumentedItem<Class | DeclarationReflection> {\n\tpublic readonly props = new Map<string, DocumentedMember>();\n\n\tpublic readonly methods = new Map<string, DocumentedMethod>();\n\n\tpublic readonly events = new Map<string, DocumentedEvent>();\n\n\tpublic construct: DocumentedConstructor | null = null;\n\n\tpublic extends: DocumentedVarType | null = null;\n\n\tpublic implements: DocumentedVarType | null = null;\n\n\tpublic constructor(data: Class | DeclarationReflection, config: Config) {\n\t\tsuper(data, config);\n\n\t\tif (config.typescript) {\n\t\t\tconst newData = data as DeclarationReflection;\n\t\t\tconst extended = newData.extendedTypes?.[0];\n\t\t\tif (extended) {\n\t\t\t\tthis.extends = new DocumentedVarType({ names: [parseType(extended)] }, this.config);\n\t\t\t}\n\n\t\t\tconst implemented = newData.implementedTypes?.[0];\n\t\t\tif (implemented) {\n\t\t\t\tthis.implements = new DocumentedVarType({ names: [parseType(implemented)] }, this.config);\n\t\t\t}\n\t\t} else {\n\t\t\tconst newData = data as Class;\n\t\t\tif (newData.augments) {\n\t\t\t\tthis.extends = new DocumentedVarType({ names: newData.augments }, this.config);\n\t\t\t}\n\n\t\t\tif (newData.implements) {\n\t\t\t\tthis.implements = new DocumentedVarType({ names: newData.implements }, this.config);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic add(item: DocumentedConstructor | DocumentedEvent | DocumentedMember | DocumentedMethod) {\n\t\tif (item instanceof DocumentedConstructor) {\n\t\t\tif (this.construct) {\n\t\t\t\tthrow new Error(`Doc ${this.data.name} already has constructor`);\n\t\t\t}\n\n\t\t\tthis.construct = item;\n\t\t} else if (item instanceof DocumentedMethod) {\n\t\t\t// @ts-expect-error: No type for methods\n\t\t\tconst prefix = item.data.scope === 'static' || item.data.flags?.isStatic ? 's-' : '';\n\t\t\tif (this.methods.has(prefix + item.data.name)) {\n\t\t\t\tthrow new Error(`Doc ${this.data.name} already has method ${item.data.name}`);\n\t\t\t}\n\n\t\t\tthis.methods.set(prefix + item.data.name, item);\n\t\t} else if (item instanceof DocumentedMember) {\n\t\t\tif (this.props.has(item.data.name)) {\n\t\t\t\tthrow new Error(`Doc ${this.data.name} already has prop ${item.data.name}`);\n\t\t\t}\n\n\t\t\tthis.props.set(item.data.name, item);\n\t\t} else if (item instanceof DocumentedEvent) {\n\t\t\tif (this.events.has(item.data.name)) {\n\t\t\t\tthrow new Error(`Doc ${this.data.name} already has event ${item.data.name}`);\n\t\t\t}\n\n\t\t\tthis.events.set(item.data.name, item);\n\t\t}\n\t}\n\n\tpublic override serializer() {\n\t\tif (this.config.typescript) {\n\t\t\tconst data = this.data as DeclarationReflection;\n\t\t\tconst signature = (data.signatures ?? [])[0] ?? data;\n\t\t\tlet meta;\n\n\t\t\tconst sources = data.sources?.[0];\n\t\t\tif (sources) {\n\t\t\t\tmeta = new DocumentedItemMeta(sources, this.config).serialize();\n\t\t\t}\n\n\t\t\tconst see = signature.comment?.blockTags?.filter((block) => block.tag === '@see').length\n\t\t\t\t? signature.comment.blockTags\n\t\t\t\t\t\t.filter((block) => block.tag === '@see')\n\t\t\t\t\t\t.map((block) => block.content.find((contentText) => contentText.kind === 'text')?.text.trim())\n\t\t\t\t: undefined;\n\n\t\t\treturn {\n\t\t\t\t// @ts-expect-error: Type cannot be inferred\n\t\t\t\tname: signature.name === 'default' ? parse(meta?.file ?? 'default').name : signature.name,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing, no-param-reassign\n\t\t\t\tdescription: signature.comment?.summary.reduce((prev, curr) => (prev += curr.text), '').trim() || undefined,\n\t\t\t\tsee,\n\t\t\t\textends: this.extends?.serialize(),\n\t\t\t\timplements: this.implements?.serialize(),\n\t\t\t\taccess:\n\t\t\t\t\tdata.flags.isPrivate ||\n\t\t\t\t\tsignature.comment?.blockTags?.some((block) => block.tag === '@private' || block.tag === '@internal')\n\t\t\t\t\t\t? 'private'\n\t\t\t\t\t\t: undefined,\n\t\t\t\tabstract: signature.comment?.blockTags?.some((block) => block.tag === '@abstract') || undefined,\n\t\t\t\tdeprecated: signature.comment?.blockTags?.some((block) => block.tag === '@deprecated')\n\t\t\t\t\t? (signature.comment.blockTags\n\t\t\t\t\t\t\t.find((block) => block.tag === '@deprecated')\n\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t.trim() ?? true)\n\t\t\t\t\t: undefined,\n\t\t\t\tconstruct: this.construct?.serialize(),\n\t\t\t\tprops: this.props.size ? [...this.props.values()].map((param) => param.serialize()) : undefined,\n\t\t\t\tmethods: this.methods.size ? [...this.methods.values()].map((method) => method.serialize()) : undefined,\n\t\t\t\tevents: this.events.size ? [...this.events.values()].map((event) => event.serialize()) : undefined,\n\t\t\t\tmeta,\n\t\t\t};\n\t\t}\n\n\t\tconst data = this.data as Class;\n\t\treturn {\n\t\t\tname: data.name,\n\t\t\tdescription: data.description,\n\t\t\tsee: data.see,\n\t\t\textends: this.extends?.serialize(),\n\t\t\timplements: this.implements?.serialize(),\n\t\t\taccess: data.access,\n\t\t\tabstract: data.virtual,\n\t\t\tdeprecated: data.deprecated,\n\t\t\tconstruct: this.construct?.serialize(),\n\t\t\tprops: this.props.size ? [...this.props.values()].map((param) => param.serialize()) : undefined,\n\t\t\tmethods: this.methods.size ? [...this.methods.values()].map((method) => method.serialize()) : undefined,\n\t\t\tevents: this.events.size ? [...this.events.values()].map((event) => event.serialize()) : undefined,\n\t\t\tmeta: new DocumentedItemMeta(data.meta, this.config).serialize(),\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "packages/docgen/src/types/constructor.ts",
    "content": "import type { DeclarationReflection, SignatureReflection } from 'typedoc';\nimport type { Constructor } from '../interfaces/index.js';\nimport { DocumentedItem } from './item.js';\nimport { DocumentedParam } from './param.js';\n\nexport class DocumentedConstructor extends DocumentedItem<Constructor | DeclarationReflection> {\n\tpublic override serializer() {\n\t\tif (this.config.typescript) {\n\t\t\tconst data = this.data as DeclarationReflection;\n\t\t\tconst signature = (data.signatures ?? [])[0] ?? data;\n\n\t\t\tconst see = signature.comment?.blockTags?.filter((block) => block.tag === '@see').length\n\t\t\t\t? signature.comment.blockTags\n\t\t\t\t\t\t.filter((block) => block.tag === '@see')\n\t\t\t\t\t\t.map((block) => block.content.find((textContent) => textContent.kind === 'text')?.text.trim())\n\t\t\t\t: undefined;\n\n\t\t\treturn {\n\t\t\t\tname: signature.name,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing, no-param-reassign\n\t\t\t\tdescription: signature.comment?.summary?.reduce((prev, curr) => (prev += curr.text), '').trim() || undefined,\n\t\t\t\tsee,\n\t\t\t\taccess:\n\t\t\t\t\tdata.flags.isPrivate ||\n\t\t\t\t\tsignature.comment?.blockTags?.some((block) => block.tag === '@private' || block.tag === '@internal')\n\t\t\t\t\t\t? 'private'\n\t\t\t\t\t\t: undefined,\n\t\t\t\t// @ts-expect-error: No type for params\n\t\t\t\tparams: signature.parameters\n\t\t\t\t\t? (signature as SignatureReflection).parameters?.map((param) =>\n\t\t\t\t\t\t\tnew DocumentedParam(param, this.config).serialize(),\n\t\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t};\n\t\t}\n\n\t\tconst data = this.data as Constructor;\n\t\treturn {\n\t\t\tname: data.name,\n\t\t\tdescription: data.description,\n\t\t\tsee: data.see,\n\t\t\taccess: data.access,\n\t\t\tparams: data.params?.length\n\t\t\t\t? data.params.map((param) => new DocumentedParam(param, this.config).serialize())\n\t\t\t\t: undefined,\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "packages/docgen/src/types/event.ts",
    "content": "import type { DeclarationReflection, SignatureReflection } from 'typedoc';\nimport type { Event } from '../interfaces/index.js';\nimport { parseType } from '../util/parseType.js';\nimport { DocumentedItemMeta } from './item-meta.js';\nimport { DocumentedItem } from './item.js';\nimport { DocumentedParam } from './param.js';\nimport { DocumentedVarType } from './var-type.js';\n\nexport class DocumentedEvent extends DocumentedItem<DeclarationReflection | Event> {\n\tpublic override serializer() {\n\t\tif (this.config.typescript) {\n\t\t\tconst data = this.data as DeclarationReflection;\n\t\t\tconst signature = (data.signatures ?? [])[0] ?? data;\n\t\t\tlet meta;\n\n\t\t\tconst sources = data.sources?.[0];\n\t\t\tif (sources) {\n\t\t\t\tmeta = new DocumentedItemMeta(sources, this.config).serialize();\n\t\t\t}\n\n\t\t\tconst see = signature.comment?.blockTags?.filter((block) => block.tag === '@see').length\n\t\t\t\t? signature.comment.blockTags\n\t\t\t\t\t\t.filter((block) => block.tag === '@see')\n\t\t\t\t\t\t.map((block) => block.content.find((contentText) => contentText.kind === 'text')?.text.trim())\n\t\t\t\t: undefined;\n\n\t\t\tconst examples = signature.comment?.blockTags?.filter((block) => block.tag === '@example').length\n\t\t\t\t? signature.comment.blockTags\n\t\t\t\t\t\t.filter((block) => block.tag === '@example')\n\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t.map((block) => block.content.reduce((prev, curr) => (prev += curr.text), '').trim())\n\t\t\t\t: undefined;\n\n\t\t\treturn {\n\t\t\t\t// @ts-expect-error: No type for params\n\t\t\t\tname: signature.parameters?.[0]?.type?.value,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing, no-param-reassign\n\t\t\t\tdescription: signature.comment?.summary?.reduce((prev, curr) => (prev += curr.text), '').trim() || undefined,\n\t\t\t\tsee,\n\t\t\t\taccess:\n\t\t\t\t\tdata.flags.isPrivate ||\n\t\t\t\t\tsignature.comment?.blockTags?.some((block) => block.tag === '@private' || block.tag === '@internal')\n\t\t\t\t\t\t? 'private'\n\t\t\t\t\t\t: undefined,\n\t\t\t\texamples,\n\t\t\t\tdeprecated: signature.comment?.blockTags?.some((block) => block.tag === '@deprecated')\n\t\t\t\t\t? (signature.comment.blockTags\n\t\t\t\t\t\t\t.find((block) => block.tag === '@deprecated')\n\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t.trim() ?? true)\n\t\t\t\t\t: undefined,\n\t\t\t\t// @ts-expect-error: Parameters type is not available\n\t\t\t\tparams: signature.parameters\n\t\t\t\t\t? (signature as SignatureReflection).parameters\n\t\t\t\t\t\t\t?.slice(1)\n\t\t\t\t\t\t\t.map((param) => new DocumentedParam(param, this.config).serialize())\n\t\t\t\t\t: undefined,\n\t\t\t\treturns: signature.type\n\t\t\t\t\t? [\n\t\t\t\t\t\t\tnew DocumentedVarType(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnames: [parseType(signature.type)],\n\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\tsignature.comment?.blockTags\n\t\t\t\t\t\t\t\t\t\t\t?.find((block) => block.tag === '@returns')\n\t\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t\t\t\t\t\t.trim() || undefined,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tthis.config,\n\t\t\t\t\t\t\t).serialize(),\n\t\t\t\t\t\t]\n\t\t\t\t\t: undefined,\n\t\t\t\treturnsDescription:\n\t\t\t\t\tsignature.comment?.blockTags\n\t\t\t\t\t\t?.find((block) => block.tag === '@returns')\n\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t.trim() || undefined,\n\t\t\t\tmeta,\n\t\t\t};\n\t\t}\n\n\t\tconst data = this.data as Event;\n\t\treturn {\n\t\t\tname: data.name,\n\t\t\tdescription: data.description,\n\t\t\tsee: data.see,\n\t\t\tdeprecated: data.deprecated,\n\t\t\tparams: data.params?.length\n\t\t\t\t? data.params.map((param) => new DocumentedParam(param, this.config).serialize())\n\t\t\t\t: undefined,\n\t\t\tmeta: new DocumentedItemMeta(data.meta, this.config).serialize(),\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "packages/docgen/src/types/external.ts",
    "content": "import type { External } from '../interfaces/index.js';\nimport { DocumentedItemMeta } from './item-meta.js';\nimport { DocumentedItem } from './item.js';\n\nexport class DocumentedExternal extends DocumentedItem<External> {\n\tpublic override serializer() {\n\t\treturn {\n\t\t\tname: this.data.name,\n\t\t\tdescription: this.data.description,\n\t\t\tsee: this.data.see,\n\t\t\tmeta: new DocumentedItemMeta(this.data.meta, this.config).serialize(),\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "packages/docgen/src/types/interface.ts",
    "content": "import type { Interface } from '../interfaces/index.js';\nimport { DocumentedClass } from './class.js';\n\nexport class DocumentedInterface extends DocumentedClass {\n\tpublic override serializer() {\n\t\tconst data = this.data as unknown as Interface;\n\t\tconst serialized = super.serializer();\n\t\tserialized.description = data.classdesc;\n\t\treturn serialized;\n\t}\n}\n"
  },
  {
    "path": "packages/docgen/src/types/item-meta.ts",
    "content": "import { basename, relative } from 'node:path';\nimport type { SourceReference } from 'typedoc';\nimport type { Meta } from '../interfaces/index.js';\nimport { DocumentedItem } from './item.js';\n\nexport class DocumentedItemMeta extends DocumentedItem<Meta | SourceReference> {\n\tpublic override serializer() {\n\t\tif (this.config.typescript) {\n\t\t\tconst data = this.data as SourceReference;\n\n\t\t\treturn {\n\t\t\t\tline: data.line,\n\t\t\t\tfile: basename(data.fileName),\n\t\t\t\tpath: undefined,\n\t\t\t\turl: data.url,\n\t\t\t};\n\t\t}\n\n\t\tconst data = this.data as Meta;\n\t\treturn {\n\t\t\tline: data.lineno,\n\t\t\tfile: data.filename,\n\t\t\tpath: relative(this.config.root, data.path).replaceAll('\\\\', '/'),\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "packages/docgen/src/types/item.ts",
    "content": "import type { DeclarationReflection } from 'typedoc';\nimport type { Config, Item } from '../interfaces/index.js';\n\nexport class DocumentedItem<Data = DeclarationReflection | Item> {\n\tpublic constructor(\n\t\tpublic readonly data: Data,\n\t\tpublic readonly config: Config,\n\t) {}\n\n\tpublic serialize(): unknown {\n\t\ttry {\n\t\t\treturn this.serializer();\n\t\t} catch (error_) {\n\t\t\tconst error = error_ as Error;\n\t\t\terror.message = `Error while serializing ${this.detailedName()}: ${error.message}`;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprotected serializer(): unknown {\n\t\tthrow new Error(\"Method 'serializer()' must be implemented.\");\n\t}\n\n\tprivate detailedName() {\n\t\tconst data = this.data as unknown as Item | undefined;\n\t\tif (!data) return this.constructor.name;\n\t\tif (data.id) return `${data.id} (${this.constructor.name})`;\n\t\tif (data.name) return `${data.name} (${this.constructor.name})`;\n\t\treturn this.constructor.name;\n\t}\n}\n"
  },
  {
    "path": "packages/docgen/src/types/member.ts",
    "content": "import type { DeclarationReflection } from 'typedoc';\nimport type { Member } from '../interfaces/index.js';\nimport { parseType } from '../util/parseType.js';\nimport { DocumentedItemMeta } from './item-meta.js';\nimport { DocumentedItem } from './item.js';\nimport { DocumentedParam } from './param.js';\nimport { DocumentedVarType } from './var-type.js';\n\nexport class DocumentedMember extends DocumentedItem<DeclarationReflection | Member> {\n\tpublic override serializer() {\n\t\tif (this.config.typescript) {\n\t\t\tconst data = this.data as DeclarationReflection;\n\t\t\tconst signature = (data.signatures ?? [])[0] ?? data;\n\t\t\tlet meta;\n\n\t\t\tconst sources = data.sources?.[0];\n\t\t\tif (sources) {\n\t\t\t\tmeta = new DocumentedItemMeta(sources, this.config).serialize();\n\t\t\t}\n\n\t\t\tconst see = signature.comment?.blockTags?.filter((block) => block.tag === '@see').length\n\t\t\t\t? signature.comment.blockTags\n\t\t\t\t\t\t.filter((block) => block.tag === '@see')\n\t\t\t\t\t\t.map((block) => block.content.find((contentText) => contentText.kind === 'text')?.text.trim())\n\t\t\t\t: undefined;\n\n\t\t\tconst base = {\n\t\t\t\tname: signature.name,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing, no-param-reassign\n\t\t\t\tdescription: signature.comment?.summary?.reduce((prev, curr) => (prev += curr.text), '').trim() || undefined,\n\t\t\t\tsee,\n\t\t\t\tscope: data.flags.isStatic ? 'static' : undefined,\n\t\t\t\taccess:\n\t\t\t\t\tdata.flags.isPrivate ||\n\t\t\t\t\tsignature.comment?.blockTags?.some((block) => block.tag === '@private' || block.tag === '@internal')\n\t\t\t\t\t\t? 'private'\n\t\t\t\t\t\t: undefined,\n\t\t\t\treadonly: data.flags.isReadonly,\n\t\t\t\tabstract: signature.comment?.blockTags?.some((block) => block.tag === '@abstract') || undefined,\n\t\t\t\tdeprecated: signature.comment?.blockTags?.some((block) => block.tag === '@deprecated')\n\t\t\t\t\t? (signature.comment.blockTags\n\t\t\t\t\t\t\t.find((block) => block.tag === '@deprecated')\n\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t.trim() ?? true)\n\t\t\t\t\t: undefined,\n\t\t\t\tdefault:\n\t\t\t\t\t(data.defaultValue === '...' ? undefined : data.defaultValue) ??\n\t\t\t\t\t(signature.comment?.blockTags\n\t\t\t\t\t\t?.find((block) => block.tag === '@default')\n\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t.trim() ||\n\t\t\t\t\t\tundefined),\n\t\t\t\ttype: signature.type\n\t\t\t\t\t? new DocumentedVarType({ names: [parseType(signature.type)] }, this.config).serialize()\n\t\t\t\t\t: undefined,\n\t\t\t\tmeta,\n\t\t\t};\n\n\t\t\tif (data.kindString === 'Accessor') {\n\t\t\t\tconst getter = data.getSignature;\n\t\t\t\tconst hasSetter = data.setSignature;\n\n\t\t\t\tif (!getter) {\n\t\t\t\t\tthrow new Error(\"Can't parse accessor without getter.\");\n\t\t\t\t}\n\n\t\t\t\tif (!hasSetter) {\n\t\t\t\t\tbase.readonly = true;\n\t\t\t\t}\n\n\t\t\t\tconst see = getter.comment?.blockTags?.filter((block) => block.tag === '@see').length\n\t\t\t\t\t? getter.comment.blockTags\n\t\t\t\t\t\t\t.filter((block) => block.tag === '@see')\n\t\t\t\t\t\t\t.map((block) => block.content.find((contentText) => contentText.kind === 'text')?.text.trim())\n\t\t\t\t\t: undefined;\n\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing, no-param-reassign\n\t\t\t\t\tdescription: getter.comment?.summary?.reduce((prev, curr) => (prev += curr.text), '').trim() || undefined,\n\t\t\t\t\tsee,\n\t\t\t\t\taccess:\n\t\t\t\t\t\tdata.flags.isPrivate ||\n\t\t\t\t\t\tgetter.comment?.blockTags?.some((block) => block.tag === '@private' || block.tag === '@internal')\n\t\t\t\t\t\t\t? 'private'\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\treadonly: base.readonly || !hasSetter,\n\t\t\t\t\tabstract: getter.comment?.blockTags?.some((block) => block.tag === '@abstract') || undefined,\n\t\t\t\t\tdeprecated: getter.comment?.blockTags?.some((block) => block.tag === '@deprecated')\n\t\t\t\t\t\t? (getter.comment.blockTags\n\t\t\t\t\t\t\t\t.find((block) => block.tag === '@deprecated')\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t\t.trim() ?? true)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbase.default ??\n\t\t\t\t\t\t(getter.comment?.blockTags\n\t\t\t\t\t\t\t?.find((block) => block.tag === '@default')\n\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t\t.trim() ||\n\t\t\t\t\t\t\tundefined),\n\t\t\t\t\ttype: getter.type ? parseType(getter.type) : undefined,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn base;\n\t\t}\n\n\t\tconst data = this.data as Member;\n\t\treturn {\n\t\t\tname: data.name,\n\t\t\tdescription: data.description,\n\t\t\tsee: data.see,\n\t\t\tscope: data.scope,\n\t\t\taccess: data.access,\n\t\t\treadonly: data.readonly,\n\t\t\tnullable: data.nullable,\n\t\t\tabstract: data.virtual,\n\t\t\tdeprecated: data.deprecated,\n\t\t\tdefault: data.default,\n\t\t\ttype: new DocumentedVarType(data.type, this.config).serialize(),\n\t\t\tprops: data.properties?.length\n\t\t\t\t? data.properties.map((prop) => new DocumentedParam(prop, this.config).serialize())\n\t\t\t\t: undefined,\n\t\t\tmeta: new DocumentedItemMeta(data.meta, this.config).serialize(),\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "packages/docgen/src/types/method.ts",
    "content": "import type { DeclarationReflection, SignatureReflection } from 'typedoc';\nimport type { Method } from '../interfaces/index.js';\nimport { parseType } from '../util/parseType.js';\nimport { DocumentedItemMeta } from './item-meta.js';\nimport { DocumentedItem } from './item.js';\nimport { DocumentedParam } from './param.js';\nimport { DocumentedVarType } from './var-type.js';\n\nexport class DocumentedMethod extends DocumentedItem<DeclarationReflection | Method> {\n\tpublic override serializer() {\n\t\tif (this.config.typescript) {\n\t\t\tconst data = this.data as DeclarationReflection;\n\t\t\tconst signature = (data.signatures ?? [])[0] ?? data;\n\t\t\tlet meta;\n\n\t\t\tconst sources = data.sources?.[0];\n\t\t\tif (sources) {\n\t\t\t\tmeta = new DocumentedItemMeta(sources, this.config).serialize();\n\t\t\t}\n\n\t\t\tconst see = signature.comment?.blockTags?.filter((block) => block.tag === '@see').length\n\t\t\t\t? signature.comment.blockTags\n\t\t\t\t\t\t.filter((block) => block.tag === '@see')\n\t\t\t\t\t\t.map((block) => block.content.find((innerContent) => innerContent.kind === 'text')?.text.trim())\n\t\t\t\t: undefined;\n\n\t\t\tconst examples = signature.comment?.blockTags?.filter((block) => block.tag === '@example').length\n\t\t\t\t? signature.comment.blockTags\n\t\t\t\t\t\t.filter((block) => block.tag === '@example')\n\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t.map((block) => block.content.reduce((prev, curr) => (prev += curr.text), '').trim())\n\t\t\t\t: undefined;\n\n\t\t\treturn {\n\t\t\t\tname: signature.name,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing, no-param-reassign\n\t\t\t\tdescription: signature.comment?.summary?.reduce((prev, curr) => (prev += curr.text), '').trim() || undefined,\n\t\t\t\tsee,\n\t\t\t\tscope: data.flags.isStatic ? 'static' : undefined,\n\t\t\t\taccess:\n\t\t\t\t\tdata.flags.isPrivate ||\n\t\t\t\t\tsignature.comment?.blockTags?.some((block) => block.tag === '@private' || block.tag === '@internal')\n\t\t\t\t\t\t? 'private'\n\t\t\t\t\t\t: undefined,\n\t\t\t\texamples,\n\t\t\t\tabstract: signature.comment?.blockTags?.some((block) => block.tag === '@abstract') || undefined,\n\t\t\t\tdeprecated: signature.comment?.blockTags?.some((block) => block.tag === '@deprecated')\n\t\t\t\t\t? (signature.comment.blockTags\n\t\t\t\t\t\t\t.find((block) => block.tag === '@deprecated')\n\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t.trim() ?? true)\n\t\t\t\t\t: undefined,\n\t\t\t\t// emits: signature.comment?.blockTags?.filter((t) => t.tag === '@emits').map((t) => t.content),\n\t\t\t\t// @ts-expect-error: Typescript doesn't know that this is a SignatureReflection\n\t\t\t\tparams: signature.parameters\n\t\t\t\t\t? (signature as SignatureReflection).parameters?.map((param) =>\n\t\t\t\t\t\t\tnew DocumentedParam(param, this.config).serialize(),\n\t\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t\treturns: signature.type\n\t\t\t\t\t? [\n\t\t\t\t\t\t\tnew DocumentedVarType(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnames: [parseType(signature.type)],\n\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\tsignature.comment?.blockTags\n\t\t\t\t\t\t\t\t\t\t\t?.find((block) => block.tag === '@returns')\n\t\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t\t\t\t\t\t.trim() || undefined,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tthis.config,\n\t\t\t\t\t\t\t).serialize(),\n\t\t\t\t\t\t]\n\t\t\t\t\t: undefined,\n\t\t\t\treturnsDescription:\n\t\t\t\t\tsignature.comment?.blockTags\n\t\t\t\t\t\t?.find((block) => block.tag === '@returns')\n\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t.trim() || undefined,\n\t\t\t\tmeta,\n\t\t\t};\n\t\t}\n\n\t\tconst data = this.data as Method;\n\t\treturn {\n\t\t\tname: data.name,\n\t\t\tdescription: data.description,\n\t\t\tsee: data.see,\n\t\t\tscope: data.scope,\n\t\t\taccess: data.access,\n\t\t\tinherits: data.inherits,\n\t\t\tinherited: data.inherited,\n\t\t\timplements: data.implements,\n\t\t\texamples: data.examples,\n\t\t\tabstract: data.virtual && !data.inherited,\n\t\t\tdeprecated: data.deprecated,\n\t\t\temits: data.fires,\n\t\t\tthrows: data.exceptions,\n\t\t\tparams: data.params?.length\n\t\t\t\t? data.params.map((param) => new DocumentedParam(param, this.config).serialize())\n\t\t\t\t: undefined,\n\t\t\tasync: data.async,\n\t\t\tgenerator: data.generator,\n\t\t\treturns: data.returns?.length\n\t\t\t\t? data.returns.map((param) =>\n\t\t\t\t\t\tnew DocumentedVarType(\n\t\t\t\t\t\t\t{ names: param.type.names, description: param.description, nullable: param.nullable },\n\t\t\t\t\t\t\tthis.config,\n\t\t\t\t\t\t).serialize(),\n\t\t\t\t\t)\n\t\t\t\t: undefined,\n\t\t\tmeta: new DocumentedItemMeta(data.meta, this.config).serialize(),\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "packages/docgen/src/types/param.ts",
    "content": "import type { ParameterReflection } from 'typedoc';\nimport type { Param } from '../interfaces/index.js';\nimport { parseType } from '../util/parseType.js';\nimport { DocumentedItem } from './item.js';\nimport { DocumentedVarType } from './var-type.js';\n\nexport class DocumentedParam extends DocumentedItem<Param | ParameterReflection> {\n\tpublic override serializer() {\n\t\tif (this.config.typescript) {\n\t\t\tconst data = this.data as ParameterReflection;\n\n\t\t\treturn {\n\t\t\t\tname: data.name,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing, no-param-reassign\n\t\t\t\tdescription: data.comment?.summary?.reduce((prev, curr) => (prev += curr.text), '').trim() || undefined,\n\t\t\t\toptional: data.flags.isOptional || data.defaultValue !== undefined,\n\t\t\t\tdefault:\n\t\t\t\t\t(data.defaultValue === '...' ? undefined : data.defaultValue) ??\n\t\t\t\t\t(data.comment?.blockTags\n\t\t\t\t\t\t?.find((block) => block.tag === '@default')\n\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t.trim() ||\n\t\t\t\t\t\tundefined),\n\t\t\t\tvariable: data.flags.isRest,\n\t\t\t\ttype: data.type ? new DocumentedVarType({ names: [parseType(data.type)] }, this.config).serialize() : undefined,\n\t\t\t};\n\t\t}\n\n\t\tconst data = this.data as Param;\n\t\treturn {\n\t\t\tname: data.name,\n\t\t\tdescription: data.description,\n\t\t\toptional: data.optional,\n\t\t\tdefault: data.defaultvalue,\n\t\t\tvariable: data.variable,\n\t\t\tnullable: data.nullable,\n\t\t\ttype: new DocumentedVarType(data.type, this.config).serialize(),\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "packages/docgen/src/types/typedef.ts",
    "content": "import type { DeclarationReflection, LiteralType } from 'typedoc';\nimport type { Typedef } from '../interfaces/index.js';\nimport { parseType } from '../util/parseType.js';\nimport { isReflectionType } from '../util/types.js';\nimport { DocumentedItemMeta } from './item-meta.js';\nimport { DocumentedItem } from './item.js';\nimport { DocumentedParam } from './param.js';\nimport { DocumentedVarType } from './var-type.js';\n\nexport class DocumentedTypeDef extends DocumentedItem<DeclarationReflection | Typedef> {\n\tpublic override serializer() {\n\t\tif (this.config.typescript) {\n\t\t\tconst data = this.data as DeclarationReflection;\n\t\t\tconst signature = (data.signatures ?? [])[0] ?? data;\n\t\t\tlet meta;\n\n\t\t\tconst sources = data.sources?.[0];\n\t\t\tif (sources) {\n\t\t\t\tmeta = new DocumentedItemMeta(sources, this.config).serialize();\n\t\t\t}\n\n\t\t\tconst see = signature.comment?.blockTags?.filter((block) => block.tag === '@see').length\n\t\t\t\t? signature.comment.blockTags\n\t\t\t\t\t\t.filter((block) => block.tag === '@see')\n\t\t\t\t\t\t.map((block) => block.content.find((contentText) => contentText.kind === 'text')?.text.trim())\n\t\t\t\t: undefined;\n\n\t\t\tconst baseReturn = {\n\t\t\t\tname: signature.name,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing, no-param-reassign\n\t\t\t\tdescription: signature.comment?.summary?.reduce((prev, curr) => (prev += curr.text), '').trim() || undefined,\n\t\t\t\tsee,\n\t\t\t\taccess:\n\t\t\t\t\tdata.flags.isPrivate ||\n\t\t\t\t\tsignature.comment?.blockTags?.some((block) => block.tag === '@private' || block.tag === '@internal')\n\t\t\t\t\t\t? 'private'\n\t\t\t\t\t\t: undefined,\n\t\t\t\tdeprecated: signature.comment?.blockTags?.some((block) => block.tag === '@deprecated')\n\t\t\t\t\t? (signature.comment.blockTags\n\t\t\t\t\t\t\t.find((block) => block.tag === '@deprecated')\n\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t.trim() ?? true)\n\t\t\t\t\t: undefined,\n\t\t\t\ttype: signature.type\n\t\t\t\t\t? new DocumentedVarType({ names: [parseType(signature.type)] }, this.config).serialize()\n\t\t\t\t\t: undefined,\n\t\t\t\tmeta,\n\t\t\t};\n\n\t\t\tlet typeDef: DeclarationReflection | undefined;\n\t\t\tif (isReflectionType(data.type)) {\n\t\t\t\ttypeDef = data.type.declaration;\n\t\t\t} else if (data.kindString === 'Interface') {\n\t\t\t\ttypeDef = data;\n\t\t\t} else if (data.kindString === 'Enumeration') {\n\t\t\t\treturn {\n\t\t\t\t\t...baseReturn,\n\t\t\t\t\tprops: data.children?.length\n\t\t\t\t\t\t? data.children.map((child) => ({\n\t\t\t\t\t\t\t\tname: child.name,\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\tchild.comment?.summary\n\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t\t\t\t?.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t\t\t\t\t.trim() || undefined,\n\t\t\t\t\t\t\t\ttype: [[[(child.type as LiteralType | undefined)?.value]]],\n\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t: undefined,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (typeDef) {\n\t\t\t\tconst { children, signatures } = typeDef;\n\n\t\t\t\tif (children && children.length > 0) {\n\t\t\t\t\tconst props = children.map((child) => ({\n\t\t\t\t\t\tname: child.name,\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\tchild.comment?.summary\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t\t?.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t\t\t.trim() ||\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing, no-param-reassign\n\t\t\t\t\t\t\tchild.signatures?.[0]?.comment?.summary?.reduce((prev, curr) => (prev += curr.text), '').trim() ||\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\toptional: child.flags.isOptional || child.defaultValue !== undefined,\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t(child.defaultValue === '...' ? undefined : child.defaultValue) ??\n\t\t\t\t\t\t\t(child.comment?.blockTags\n\t\t\t\t\t\t\t\t?.find((block) => block.tag === '@default')\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t\t\t.trim() ||\n\t\t\t\t\t\t\t\tundefined),\n\t\t\t\t\t\ttype: child.type\n\t\t\t\t\t\t\t? new DocumentedVarType({ names: [parseType(child.type)] }, this.config).serialize()\n\t\t\t\t\t\t\t: child.kindString === 'Method'\n\t\t\t\t\t\t\t\t? new DocumentedVarType(\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnames: [\n\t\t\t\t\t\t\t\t\t\t\t\tparseType({\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: 'reflection',\n\t\t\t\t\t\t\t\t\t\t\t\t\tdeclaration: child,\n\t\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\tdescription: child.signatures?.[0]?.comment?.blockTags\n\t\t\t\t\t\t\t\t\t\t\t\t?.find((block) => block.tag === '@returns')\n\t\t\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t\t\t\t\t\t.trim(),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tthis.config,\n\t\t\t\t\t\t\t\t\t).serialize()\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t}));\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...baseReturn,\n\t\t\t\t\t\tprops,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif (signatures && signatures.length > 0) {\n\t\t\t\t\tconst sig = signatures[0];\n\n\t\t\t\t\tconst params = sig?.parameters?.map((param) => ({\n\t\t\t\t\t\tname: param.name,\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing, no-param-reassign\n\t\t\t\t\t\tdescription: param.comment?.summary?.reduce((prev, curr) => (prev += curr.text), '').trim() || undefined,\n\t\t\t\t\t\toptional: param.flags.isOptional || param.defaultValue !== undefined,\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t(param.defaultValue === '...' ? undefined : param.defaultValue) ??\n\t\t\t\t\t\t\t(param.comment?.blockTags\n\t\t\t\t\t\t\t\t?.find((block) => block.tag === '@default')\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t\t\t.trim() ||\n\t\t\t\t\t\t\t\tundefined),\n\t\t\t\t\t\ttype: param.type\n\t\t\t\t\t\t\t? new DocumentedVarType({ names: [parseType(param.type)] }, this.config).serialize()\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t}));\n\n\t\t\t\t\tconst see = sig?.comment?.blockTags?.filter((block) => block.tag === '@see').length\n\t\t\t\t\t\t? sig.comment.blockTags\n\t\t\t\t\t\t\t\t.filter((block) => block.tag === '@see')\n\t\t\t\t\t\t\t\t.map((block) => block.content.find((contentText) => contentText.kind === 'text')?.text.trim())\n\t\t\t\t\t\t: undefined;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...baseReturn,\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing, no-param-reassign\n\t\t\t\t\t\tdescription: sig?.comment?.summary?.reduce((prev, curr) => (prev += curr.text), '').trim() || undefined,\n\t\t\t\t\t\tsee,\n\t\t\t\t\t\taccess:\n\t\t\t\t\t\t\tsig?.flags.isPrivate ||\n\t\t\t\t\t\t\tsig?.comment?.blockTags?.some((block) => block.tag === '@private' || block.tag === '@internal')\n\t\t\t\t\t\t\t\t? 'private'\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\tdeprecated: sig?.comment?.blockTags?.some((block) => block.tag === '@deprecated')\n\t\t\t\t\t\t\t? (sig.comment.blockTags\n\t\t\t\t\t\t\t\t\t.find((block) => block.tag === '@deprecated')\n\t\t\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t\t\t.trim() ?? true)\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\tparams,\n\t\t\t\t\t\treturns: sig?.type\n\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\tnew DocumentedVarType(\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnames: [parseType(sig.type)],\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\tsig.comment?.blockTags\n\t\t\t\t\t\t\t\t\t\t\t\t\t?.find((block) => block.tag === '@returns')\n\t\t\t\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t\t\t\t\t\t\t\t.trim() || undefined,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tthis.config,\n\t\t\t\t\t\t\t\t\t).serialize(),\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\treturnsDescription:\n\t\t\t\t\t\t\tsig?.comment?.blockTags\n\t\t\t\t\t\t\t\t?.find((block) => block.tag === '@returns')\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\t\t\t\t\t?.content.reduce((prev, curr) => (prev += curr.text), '')\n\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\t\t\t\t\t.trim() || undefined,\n\t\t\t\t\t\tmeta,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn baseReturn;\n\t\t}\n\n\t\tconst data = this.data as Typedef;\n\t\treturn {\n\t\t\tname: data.name,\n\t\t\tdescription: data.description,\n\t\t\tsee: data.see,\n\t\t\taccess: data.access,\n\t\t\tdeprecated: data.deprecated,\n\t\t\ttype: new DocumentedVarType(data.type, this.config).serialize(),\n\t\t\tprops: data.properties?.length\n\t\t\t\t? data.properties.map((prop) => new DocumentedParam(prop, this.config).serialize())\n\t\t\t\t: undefined,\n\t\t\tparams: data.params?.length\n\t\t\t\t? data.params.map((param) => new DocumentedParam(param, this.config).serialize())\n\t\t\t\t: undefined,\n\t\t\treturns: data.returns?.length\n\t\t\t\t? data.returns.map((prop) => new DocumentedVarType(prop, this.config).serialize())\n\t\t\t\t: undefined,\n\t\t\tmeta: new DocumentedItemMeta(data.meta, this.config).serialize(),\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "packages/docgen/src/types/var-type.ts",
    "content": "import type { VarType } from '../interfaces/index.js';\nimport { parseType } from '../util/parseType.js';\nimport { splitVarName } from '../util/splitVarName.js';\nimport { DocumentedItem } from './item.js';\n\nexport class DocumentedVarType extends DocumentedItem<VarType> {\n\tpublic override serializer() {\n\t\tif (this.config.typescript) {\n\t\t\tconst data = this.data;\n\t\t\tconst names = data.names?.map((name) => splitVarName(parseType(name)));\n\n\t\t\tif (!data.description && !data.nullable) {\n\t\t\t\treturn names;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttypes: names,\n\t\t\t\tdescription: data.description,\n\t\t\t\tnullable: data.nullable,\n\t\t\t};\n\t\t}\n\n\t\tconst data = this.data;\n\t\tconst names = (data.names ?? data.type?.names)?.map((name) => splitVarName(name));\n\n\t\tif (!data.description && !data.nullable) {\n\t\t\treturn names;\n\t\t}\n\n\t\treturn {\n\t\t\ttypes: names,\n\t\t\tdescription: data.description,\n\t\t\tnullable: data.nullable,\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "packages/docgen/src/util/parseType.ts",
    "content": "import type { JSONOutput } from 'typedoc';\nimport {\n\tisArrayType,\n\tisConditionalType,\n\tisIndexedAccessType,\n\tisIntersectionType,\n\tisPredicateType,\n\tisReferenceType,\n\tisReflectionType,\n\tisLiteralType,\n\tisTupleType,\n\tisTypeOperatorType,\n\tisUnionType,\n\tisQueryType,\n\tisInferredType,\n\tisIntrinsicType,\n\tisUnknownType,\n} from './types.js';\n\nexport function parseType(someType: JSONOutput.SomeType | JSONOutput.Type | string): string {\n\tif (typeof someType === 'string') {\n\t\treturn someType;\n\t}\n\n\tif (isArrayType(someType)) {\n\t\treturn `Array<${parseType(someType.elementType)}>`;\n\t}\n\n\tif (isConditionalType(someType)) {\n\t\tconst { checkType, extendsType, trueType, falseType } = someType;\n\t\treturn `${parseType(checkType)} extends ${parseType(extendsType)} ? ${parseType(trueType)} : ${parseType(\n\t\t\tfalseType,\n\t\t)}`;\n\t}\n\n\tif (isIndexedAccessType(someType)) {\n\t\treturn `${parseType(someType.objectType)}[${parseType(someType.indexType)}]`;\n\t}\n\n\tif (isIntersectionType(someType)) {\n\t\treturn someType.types.map(parseType).join(' & ');\n\t}\n\n\tif (isPredicateType(someType)) {\n\t\treturn (\n\t\t\t(someType.asserts ? 'asserts ' : '') +\n\t\t\tsomeType.name +\n\t\t\t(someType.targetType ? ` is ${parseType(someType.targetType)}` : '')\n\t\t);\n\t}\n\n\tif (isReferenceType(someType)) {\n\t\treturn someType.name + (someType.typeArguments ? `<${someType.typeArguments.map(parseType).join(', ')}>` : '');\n\t}\n\n\tif (isReflectionType(someType)) {\n\t\tconst obj: Record<string, any> = {};\n\n\t\tconst { children, signatures } = someType.declaration!;\n\n\t\t// This is run when we're parsing interface-like declaration\n\t\tif (children && children.length > 0) {\n\t\t\tfor (const child of children) {\n\t\t\t\tconst { type } = child;\n\t\t\t\tif (type) {\n\t\t\t\t\tobj[child.name] = parseType(type);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn `{\\n${Object.entries(obj)\n\t\t\t\t.map(([key, value]) => `${key}: ${value as string}`)\n\t\t\t\t.join(',\\n')}\\n}`;\n\t\t}\n\n\t\t// This is run if we're parsing a function type\n\t\tif (signatures && signatures.length > 0) {\n\t\t\tconst signature = signatures[0];\n\t\t\tconst params = signature?.parameters?.map(\n\t\t\t\t(param) => `${param.name}: ${param.type ? parseType(param.type) : 'unknown'}`,\n\t\t\t);\n\t\t\treturn `(${params?.join(', ') ?? '...args: unknown[]'}) => ${\n\t\t\t\tsignature?.type ? parseType(signature.type) : 'unknown'\n\t\t\t}`;\n\t\t}\n\n\t\treturn '{}';\n\t}\n\n\tif (isLiteralType(someType)) {\n\t\tif (typeof someType.value === 'string') {\n\t\t\treturn `'${someType.value}'`;\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-base-to-string\n\t\treturn `${someType.value}`;\n\t}\n\n\tif (isTupleType(someType)) {\n\t\treturn `[${(someType.elements ?? []).map(parseType).join(', ')}]`;\n\t}\n\n\tif (isTypeOperatorType(someType)) {\n\t\treturn `${someType.operator} ${parseType(someType.target)}`;\n\t}\n\n\tif (isUnionType(someType)) {\n\t\treturn someType.types\n\t\t\t.map(parseType)\n\t\t\t.filter((currentType) => Boolean(currentType) && currentType.trim().length > 0)\n\t\t\t.join(' | ');\n\t}\n\n\tif (isQueryType(someType)) {\n\t\treturn `(typeof ${parseType(someType.queryType)})`;\n\t}\n\n\tif (isInferredType(someType) || isIntrinsicType(someType) || isUnknownType(someType)) {\n\t\treturn someType.name;\n\t}\n\n\treturn 'unknown';\n}\n"
  },
  {
    "path": "packages/docgen/src/util/splitVarName.ts",
    "content": "const isASymbol = (char: string) => '-!$%^&*()_+|~=`{}[]:;<>?,. '.includes(char);\n\nexport function splitVarName(str: string) {\n\tconst res: string[][] = [];\n\tlet currGroup: string[] = [];\n\tlet currStr = '';\n\n\tfor (const char of str) {\n\t\tconst currentlyInASymbolSection = isASymbol(currStr[0]!);\n\t\tconst charIsASymbol = isASymbol(char);\n\n\t\tif (currStr.length && currentlyInASymbolSection !== charIsASymbol) {\n\t\t\tif (char === '.') {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcurrGroup.push(currStr);\n\t\t\tcurrStr = char;\n\n\t\t\tif (!charIsASymbol) {\n\t\t\t\tres.push(currGroup);\n\t\t\t\tcurrGroup = [];\n\t\t\t}\n\t\t} else {\n\t\t\tcurrStr += char;\n\t\t}\n\t}\n\n\tcurrGroup.push(currStr);\n\tres.push(currGroup);\n\n\treturn res;\n}\n"
  },
  {
    "path": "packages/docgen/src/util/types.ts",
    "content": "import type { JSONOutput } from 'typedoc';\n\ninterface QueryType {\n\tqueryType: JSONOutput.SomeType;\n\ttype: 'query';\n}\n\nexport function isArrayType(value: any): value is JSONOutput.ArrayType {\n\treturn typeof value === 'object' && value.type === 'array';\n}\n\nexport function isConditionalType(value: any): value is JSONOutput.ConditionalType {\n\treturn typeof value === 'object' && value.type === 'conditional';\n}\n\nexport function isIndexedAccessType(value: any): value is JSONOutput.IndexedAccessType {\n\treturn typeof value === 'object' && value.type === 'indexedAccess';\n}\n\nexport function isInferredType(value: any): value is JSONOutput.InferredType {\n\treturn typeof value === 'object' && value.type === 'inferred';\n}\n\nexport function isIntersectionType(value: any): value is JSONOutput.IntersectionType {\n\treturn typeof value === 'object' && value.type === 'intersection';\n}\n\nexport function isIntrinsicType(value: any): value is JSONOutput.IntrinsicType {\n\treturn typeof value === 'object' && value.type === 'intrinsic';\n}\n\nexport function isPredicateType(value: any): value is JSONOutput.PredicateType {\n\treturn typeof value === 'object' && value.type === 'predicate';\n}\n\nexport function isReferenceType(value: any): value is JSONOutput.ReferenceType {\n\treturn typeof value === 'object' && value.type === 'reference';\n}\n\nexport function isReflectionType(value: any): value is JSONOutput.ReflectionType {\n\treturn typeof value === 'object' && value.type === 'reflection';\n}\n\nexport function isLiteralType(value: any): value is JSONOutput.LiteralType {\n\treturn typeof value === 'object' && value.type === 'literal';\n}\n\nexport function isTupleType(value: any): value is JSONOutput.TupleType {\n\treturn typeof value === 'object' && value.type === 'tuple';\n}\n\nexport function isTypeOperatorType(value: any): value is JSONOutput.TypeOperatorType {\n\treturn typeof value === 'object' && value.type === 'typeOperator';\n}\n\nexport function isUnionType(value: any): value is JSONOutput.UnionType {\n\treturn typeof value === 'object' && value.type === 'union';\n}\n\nexport function isUnknownType(value: any): value is JSONOutput.UnknownType {\n\treturn typeof value === 'object' && value.type === 'unknown';\n}\n\nexport function isQueryType(value: any): value is QueryType {\n\treturn typeof value === 'object' && value.type === 'query';\n}\n"
  },
  {
    "path": "packages/docgen/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/docgen/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/docgen/tsup.config.ts",
    "content": "import { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tentry: ['src/index.ts', 'bin/index.ts'],\n\tminify: 'terser',\n});\n"
  },
  {
    "path": "packages/formatters/.cliff-jumperrc.json",
    "content": "{\n\t\"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n\t\"name\": \"formatters\",\n\t\"org\": \"discordjs\",\n\t\"packagePath\": \"packages/formatters\",\n\t\"identifierBase\": false\n}\n"
  },
  {
    "path": "packages/formatters/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\ndist-docs\n\n# Docs\ndocs/**/*\n!docs/README.md\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/formatters/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/formatters/.prettierignore",
    "content": ".turbo\ncoverage\ndist\ndist-docs\ndocs/docs.api.json\nCHANGELOG.md\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/formatters/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/formatters/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n# [@discordjs/formatters@0.5.0](https://github.com/discordjs/discord.js/compare/@discordjs/formatters@0.4.0...@discordjs/formatters@0.5.0) - (2024-09-01)\n\n## Features\n\n- Add subtext formatter (#10400) ([fcd35ea](https://github.com/discordjs/discord.js/commit/fcd35ea2e72b3268729466e4cd85b2794bb3394b))\n- Premium buttons (#10353) ([4f59b74](https://github.com/discordjs/discord.js/commit/4f59b740d01b9ff2213949708a36e17da32b89c3))\n\n# [@discordjs/formatters@0.4.0](https://github.com/discordjs/discord.js/compare/@discordjs/formatters@0.3.3...@discordjs/formatters@0.4.0) - (2024-05-04)\n\n## Bug Fixes\n\n- **Faces:** Escape backslash in `Shrug` (#10156) ([0f9017e](https://github.com/discordjs/discord.js/commit/0f9017ef954c4c971a6fc1304741843c876e589a))\n- **escape*:** Dont escape urls (#9958) ([0f1e02b](https://github.com/discordjs/discord.js/commit/0f1e02b3ddb7db8f5efdcd35a48a6f926b6ff13c))\n- Deprecate `underscore` in favor of `underline` (#10054) ([461948c](https://github.com/discordjs/discord.js/commit/461948c07d8b2dcd63f5e13174ec799dfe745beb))\n- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))\n\n## Documentation\n\n- Split docs.api.json into multiple json files ([597340f](https://github.com/discordjs/discord.js/commit/597340f288437c35da8c703d9b621274de60d880))\n\n## Features\n\n- Local and preview detection ([79fbda3](https://github.com/discordjs/discord.js/commit/79fbda3aac6d4f0f8bfb193e797d09cbe331d315))\n\n## Refactor\n\n- Docs (#10126) ([18cce83](https://github.com/discordjs/discord.js/commit/18cce83d80598c430218775c53441b6b2ecdc776))\n- **formatters:** Add support for object and name param in `formatEmoji()` (#10076) ([7b8e0de](https://github.com/discordjs/discord.js/commit/7b8e0debebb944184b5817edd76cb0ac7e870993))\n\n# [@discordjs/formatters@0.3.3](https://github.com/discordjs/discord.js/compare/@discordjs/formatters@0.3.2...@discordjs/formatters@0.3.3) - (2023-11-12)\n\n## Documentation\n\n- Remove markdown (#9914) ([efbcda7](https://github.com/discordjs/discord.js/commit/efbcda70fcc11583d0979e7e2a1f951a885b9b77))\n- **create-discord-bot:** Support bun in create-discord-bot (#9798) ([7157748](https://github.com/discordjs/discord.js/commit/7157748fe3a69265896adf0450cd3f37acbcf97b))\n\n## Features\n\n- **formatters:** Add guild navigation mentions (#9436) ([566d5e2](https://github.com/discordjs/discord.js/commit/566d5e2c8145b2dfe94415f30cab6f6712f2cf95))\n- Add new markdown formatters (#9613) ([0d787e9](https://github.com/discordjs/discord.js/commit/0d787e9f797b53974a49f56727acb6318cd8d650))\n\n# [@discordjs/formatters@0.3.2](https://github.com/discordjs/discord.js/compare/@discordjs/formatters@0.3.1...@discordjs/formatters@0.3.2) - (2023-08-17)\n\n## Documentation\n\n- Update Node.js requirement to 16.11.0 (#9764) ([188877c](https://github.com/discordjs/discord.js/commit/188877c50af70f0d5cffb246620fa277435c6ce6))\n\n# [@discordjs/formatters@0.3.1](https://github.com/discordjs/discord.js/compare/@discordjs/formatters@0.3.0...@discordjs/formatters@0.3.1) - (2023-05-01)\n\n## Documentation\n\n- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9))\n- **formatters:** Enhance the documentation (#9364) ([23e0ac5](https://github.com/discordjs/discord.js/commit/23e0ac56f456c39d925e2644ec3ca209d4410a99))\n\n# [@discordjs/formatters@0.3.1](https://github.com/discordjs/discord.js/compare/@discordjs/formatters@0.3.0...@discordjs/formatters@0.3.1) - (2023-05-01)\n\n## Documentation\n\n- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9))\n- **formatters:** Enhance the documentation (#9364) ([23e0ac5](https://github.com/discordjs/discord.js/commit/23e0ac56f456c39d925e2644ec3ca209d4410a99))\n\n# [@discordjs/formatters@0.3.0](https://github.com/discordjs/discord.js/compare/@discordjs/formatters@0.2.0...@discordjs/formatters@0.3.0) - (2023-04-01)\n\n## Bug Fixes\n\n- **scripts:** Accessing tsComment ([d8d5f31](https://github.com/discordjs/discord.js/commit/d8d5f31d3927fd1de62f1fa3a1a6e454243ad87b))\n\n## Features\n\n- **website:** Render syntax and mdx on the server (#9086) ([ee5169e](https://github.com/discordjs/discord.js/commit/ee5169e0aadd7bbfcd752aae614ec0f69602b68b))\n\n# [@discordjs/formatters@0.2.0](https://github.com/discordjs/discord.js/compare/@discordjs/formatters@0.1.0...@discordjs/formatters@0.2.0) - (2023-03-12)\n\n## Features\n\n- **website:** Add support for source file links (#9048) ([f6506e9](https://github.com/discordjs/discord.js/commit/f6506e99c496683ee0ab67db0726b105b929af38))\n\n## Refactor\n\n- Compare with `undefined` directly (#9191) ([869153c](https://github.com/discordjs/discord.js/commit/869153c3fdf155783e7c0ecebd3627b087c3a026))\n- Moved the escapeX functions from discord.js to @discord.js/formatters (#8957) ([13ce78a](https://github.com/discordjs/discord.js/commit/13ce78af6e3aedc793f53a099a6a615df44311f7))\n\n## Styling\n\n- Run prettier (#9041) ([2798ba1](https://github.com/discordjs/discord.js/commit/2798ba1eb3d734f0cf2eeccd2e16cfba6804873b))\n\n# [@discordjs/formatters@0.1.0](https://github.com/discordjs/discord.js/tree/@discordjs/formatters@0.1.0) - (2022-12-16)\n\n## Features\n\n- Add `@discordjs/formatters` (#8889) ([3fca638](https://github.com/discordjs/discord.js/commit/3fca638a8470dcea2f79ddb9f18526dbc0017c88))\n\n"
  },
  {
    "path": "packages/formatters/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n   \n   Copyright 2021 Noel Buechler\n   Copyright 2021 Vlad Frangu\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/formatters/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/formatters\"><img src=\"https://img.shields.io/npm/v/@discordjs/formatters.svg?maxAge=3600\" alt=\"npm version\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/formatters\"><img src=\"https://img.shields.io/npm/dt/@discordjs/formatters.svg?maxAge=3600\" alt=\"npm downloads\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/commits/main/packages/formatters\"><img alt=\"Last commit.\" src=\"https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fformatters\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t\t<a href=\"https://codecov.io/gh/discordjs/discord.js\"><img src=\"https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=formatters\" alt=\"Code coverage\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## About\n\n`@discordjs/formatters` is a collection of functions for formatting strings to be used on Discord.\n\n## Installation\n\n**Node.js 22.12.0 or newer is required.**\n\n```sh\nnpm install @discordjs/formatters\nyarn add @discordjs/formatters\npnpm add @discordjs/formatters\nbun add @discordjs/formatters\n```\n\n## Example usage\n\nThe example uses [ES modules](https://nodejs.org/api/esm.html#enabling).\n\n````ts\nimport { codeBlock } from '@discordjs/formatters';\n\nconst formattedCode = codeBlock('hello world!');\nconsole.log(formattedCode);\n\n// Prints:\n// ```\n// hello world!\n// ```\n````\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Documentation][documentation]\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [npm][npm]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the\n[documentation][documentation].  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs/packages/formatters/stable\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/formatters\n[npm]: https://www.npmjs.com/package/@discordjs/formatters\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/formatters/__tests__/escapers.test.ts",
    "content": "import { describe, test, expect } from 'vitest';\nimport {\n\tescapeCodeBlock,\n\tescapeInlineCode,\n\tescapeItalic,\n\tescapeBold,\n\tescapeUnderline,\n\tescapeStrikethrough,\n\tescapeMaskedLink,\n\tescapeSpoiler,\n\tescapeHeading,\n\tescapeBulletedList,\n\tescapeNumberedList,\n\tescapeMarkdown,\n\tescapeQuote,\n\tescapeBlockQuote,\n} from '../src/index.js';\n\nconst testString = \"> `_Behold!_`\\n||___~~***```js\\n`use strict`;\\nrequire('discord.js');```***~~___||\";\nconst testStringForums =\n\t'# Title\\n## Subtitle\\n### Subsubtitle\\n- Bullet list\\n - # Title with bullet\\n * Subbullet\\n1. Number list\\n 1. Sub number list';\nconst testURLs = [\n\t'https://example.com/name_wow',\n\t'https://example.com/name__wow',\n\t'https://example.com/name_with_underscores',\n\t'https://example.com/name__with__underscores',\n\t'https://example.com/name_with_underscores_and__double__underscores',\n\t'https://*.example.com/globbed/*',\n\t'https://example.com/*before*/>/*after*',\n];\n\ndescribe('Markdown escapers', () => {\n\tdescribe('escapeCodeblock', () => {\n\t\ttest('shared', () => {\n\t\t\texpect(escapeCodeBlock(testString)).toEqual(\n\t\t\t\t\"> `_Behold!_`\\n||___~~***\\\\`\\\\`\\\\`js\\n`use strict`;\\nrequire('discord.js');\\\\`\\\\`\\\\`***~~___||\",\n\t\t\t);\n\t\t});\n\n\t\ttest('basic', () => {\n\t\t\texpect(escapeCodeBlock('```test```')).toEqual('\\\\`\\\\`\\\\`test\\\\`\\\\`\\\\`');\n\t\t});\n\t});\n\n\tdescribe('escapeInlineCode', () => {\n\t\ttest('shared', () => {\n\t\t\texpect(escapeInlineCode(testString)).toEqual(\n\t\t\t\t\"> \\\\`_Behold!_\\\\`\\n||___~~***```js\\n\\\\`use strict\\\\`;\\nrequire('discord.js');```***~~___||\",\n\t\t\t);\n\t\t});\n\n\t\ttest('basic', () => {\n\t\t\texpect(escapeInlineCode('`test`')).toEqual('\\\\`test\\\\`');\n\t\t});\n\t});\n\n\tdescribe('escapeBold', () => {\n\t\ttest('shared', () => {\n\t\t\texpect(escapeBold(testString)).toEqual(\n\t\t\t\t\"> `_Behold!_`\\n||___~~*\\\\*\\\\*```js\\n`use strict`;\\nrequire('discord.js');```\\\\*\\\\**~~___||\",\n\t\t\t);\n\t\t});\n\n\t\ttest('basic', () => {\n\t\t\texpect(escapeBold('**test**')).toEqual('\\\\*\\\\*test\\\\*\\\\*');\n\t\t});\n\t});\n\n\tdescribe('escapeItalic', () => {\n\t\ttest('shared', () => {\n\t\t\texpect(escapeItalic(testString)).toEqual(\n\t\t\t\t\"> `\\\\_Behold!\\\\_`\\n||\\\\___~~\\\\***```js\\n`use strict`;\\nrequire('discord.js');```**\\\\*~~__\\\\_||\",\n\t\t\t);\n\t\t});\n\n\t\ttest('basic (_)', () => {\n\t\t\texpect(escapeItalic('_test_')).toEqual('\\\\_test\\\\_');\n\t\t});\n\n\t\ttest('basic (*)', () => {\n\t\t\texpect(escapeItalic('*test*')).toEqual('\\\\*test\\\\*');\n\t\t});\n\n\t\ttest('emoji', () => {\n\t\t\tconst testOne = 'This is a test with _emojis_ <:Frost_ed_Wreath:1053399941210443826> and **bold text**.';\n\t\t\texpect(escapeItalic(testOne)).toEqual(\n\t\t\t\t'This is a test with \\\\_emojis\\\\_ <:Frost_ed_Wreath:1053399941210443826> and **bold text**.',\n\t\t\t);\n\t\t});\n\n\t\ttest('url', () => {\n\t\t\tfor (const url of testURLs) expect(escapeItalic(url)).toBe(url);\n\t\t});\n\n\t\ttest('after-url', () => {\n\t\t\tconst url = '<https://example.com>';\n\t\t\tfor (const [input, output] of [\n\t\t\t\t['*hi*', '\\\\*hi\\\\*'],\n\t\t\t\t['_hi_', '\\\\_hi\\\\_'],\n\t\t\t]) {\n\t\t\t\texpect(escapeItalic(url + input)).toBe(url + output);\n\t\t\t}\n\t\t});\n\t});\n\n\tdescribe('escapeUnderline', () => {\n\t\ttest('shared', () => {\n\t\t\texpect(escapeUnderline(testString)).toEqual(\n\t\t\t\t\"> `_Behold!_`\\n||_\\\\_\\\\_~~***```js\\n`use strict`;\\nrequire('discord.js');```***~~\\\\_\\\\__||\",\n\t\t\t);\n\t\t});\n\n\t\ttest('basic', () => {\n\t\t\texpect(escapeUnderline('__test__')).toEqual('\\\\_\\\\_test\\\\_\\\\_');\n\t\t});\n\n\t\ttest('emoji', () => {\n\t\t\tconst testTwo = 'This is a test with __emojis__ <:Frost__ed__Wreath:1053399939654352978> and **bold text**.';\n\t\t\texpect(escapeUnderline(testTwo)).toBe(\n\t\t\t\t'This is a test with \\\\_\\\\_emojis\\\\_\\\\_ <:Frost__ed__Wreath:1053399939654352978> and **bold text**.',\n\t\t\t);\n\t\t});\n\n\t\ttest('url', () => {\n\t\t\tfor (const url of testURLs) expect(escapeUnderline(url)).toBe(url);\n\t\t});\n\t});\n\n\tdescribe('escapeStrikethrough', () => {\n\t\ttest('shared', () => {\n\t\t\texpect(escapeStrikethrough(testString)).toEqual(\n\t\t\t\t\"> `_Behold!_`\\n||___\\\\~\\\\~***```js\\n`use strict`;\\nrequire('discord.js');```***\\\\~\\\\~___||\",\n\t\t\t);\n\t\t});\n\n\t\ttest('basic', () => {\n\t\t\texpect(escapeStrikethrough('~~test~~')).toEqual('\\\\~\\\\~test\\\\~\\\\~');\n\t\t});\n\t});\n\n\tdescribe('escapeSpoiler', () => {\n\t\ttest('shared', () => {\n\t\t\texpect(escapeSpoiler(testString)).toEqual(\n\t\t\t\t\"> `_Behold!_`\\n\\\\|\\\\|___~~***```js\\n`use strict`;\\nrequire('discord.js');```***~~___\\\\|\\\\|\",\n\t\t\t);\n\t\t});\n\n\t\ttest('basic', () => {\n\t\t\texpect(escapeSpoiler('||test||')).toEqual('\\\\|\\\\|test\\\\|\\\\|');\n\t\t});\n\t});\n\n\tdescribe('escapeHeading', () => {\n\t\ttest('shared', () => {\n\t\t\texpect(escapeHeading(testStringForums)).toEqual(\n\t\t\t\t'\\\\# Title\\n\\\\## Subtitle\\n\\\\### Subsubtitle\\n- Bullet list\\n - \\\\# Title with bullet\\n * Subbullet\\n1. Number list\\n 1. Sub number list',\n\t\t\t);\n\t\t});\n\n\t\ttest('basic', () => {\n\t\t\texpect(escapeHeading('# test')).toEqual('\\\\# test');\n\t\t});\n\t});\n\n\tdescribe('escapeBulletedList', () => {\n\t\ttest('shared', () => {\n\t\t\texpect(escapeBulletedList(testStringForums)).toEqual(\n\t\t\t\t'# Title\\n## Subtitle\\n### Subsubtitle\\n\\\\- Bullet list\\n \\\\- # Title with bullet\\n \\\\* Subbullet\\n1. Number list\\n 1. Sub number list',\n\t\t\t);\n\t\t});\n\n\t\ttest('basic', () => {\n\t\t\texpect(escapeBulletedList('- test')).toEqual('\\\\- test');\n\t\t});\n\t});\n\n\tdescribe('escapeNumberedList', () => {\n\t\ttest('shared', () => {\n\t\t\texpect(escapeNumberedList(testStringForums)).toEqual(\n\t\t\t\t'# Title\\n## Subtitle\\n### Subsubtitle\\n- Bullet list\\n - # Title with bullet\\n * Subbullet\\n1\\\\. Number list\\n 1\\\\. Sub number list',\n\t\t\t);\n\t\t});\n\n\t\ttest('basic', () => {\n\t\t\texpect(escapeNumberedList('1. test')).toEqual('1\\\\. test');\n\t\t});\n\t});\n\n\tdescribe('escapeMaskedLink', () => {\n\t\ttest('basic', () => {\n\t\t\texpect(escapeMaskedLink('[test](https://discord.js.org)')).toEqual('\\\\[test](https://discord.js.org)');\n\t\t});\n\t});\n\n\tdescribe('escapeQuote', () => {\n\t\ttest('basic', () => {\n\t\t\texpect(escapeQuote('> yeet')).toEqual('\\\\> yeet');\n\t\t\texpect(escapeQuote('>  test')).toEqual('\\\\>  test');\n\t\t\texpect(escapeQuote(' > leading spaces')).toEqual(' \\\\> leading spaces');\n\t\t});\n\n\t\ttest('not quotes', () => {\n\t\t\texpect(escapeQuote('>')).toEqual('>');\n\t\t\texpect(escapeQuote('>test')).toEqual('>test');\n\t\t\texpect(escapeQuote('>> test')).toEqual('>> test');\n\t\t\texpect(escapeQuote('not a > quote')).toEqual('not a > quote');\n\t\t\texpect(escapeQuote('>>> yeet')).toEqual('>>> yeet');\n\t\t});\n\n\t\ttest('multiple lines', () => {\n\t\t\tconst input = `> quote\nnot a quote\n > another quote\n>> not a quote`;\n\n\t\t\tconst expectedOutput = `\\\\> quote\nnot a quote\n \\\\> another quote\n>> not a quote`;\n\t\t\texpect(escapeQuote(input)).toEqual(expectedOutput);\n\t\t});\n\t});\n\n\tdescribe('escapeBlockQuote', () => {\n\t\ttest('basic', () => {\n\t\t\texpect(escapeBlockQuote('>>> block quote')).toEqual('\\\\>>> block quote');\n\t\t\texpect(escapeBlockQuote('   >>> leading spaces')).toEqual('   \\\\>>> leading spaces');\n\t\t});\n\n\t\ttest('not block quotes', () => {\n\t\t\texpect(escapeBlockQuote('>>>')).toEqual('>>>');\n\t\t\texpect(escapeBlockQuote('>>>not block quote')).toEqual('>>>not block quote');\n\t\t\texpect(escapeBlockQuote('>> not block quote')).toEqual('>> not block quote');\n\t\t\texpect(escapeBlockQuote('not a block >>> quote')).toEqual('not a block >>> quote');\n\t\t\texpect(escapeBlockQuote('> yeet')).toEqual('> yeet');\n\t\t});\n\n\t\ttest('multiple lines', () => {\n\t\t\tconst input = `>>> block quote\npart of it\n\n\t >>> another one\n\n  >>>this is not`;\n\n\t\t\tconst expectedOutput = `\\\\>>> block quote\npart of it\n\n\t \\\\>>> another one\n\n  >>>this is not`;\n\t\t\texpect(escapeBlockQuote(input)).toEqual(expectedOutput);\n\t\t});\n\t});\n\n\tdescribe('escapeMarkdown', () => {\n\t\ttest('shared', () => {\n\t\t\texpect(escapeMarkdown(testString)).toEqual(\n\t\t\t\t\"\\\\> \\\\`\\\\_Behold!\\\\_\\\\`\\n\\\\|\\\\|\\\\_\\\\_\\\\_\\\\~\\\\~\\\\*\\\\*\\\\*\\\\`\\\\`\\\\`js\\n\\\\`use strict\\\\`;\\nrequire('discord.js');\\\\`\\\\`\\\\`\\\\*\\\\*\\\\*\\\\~\\\\~\\\\_\\\\_\\\\_\\\\|\\\\|\",\n\t\t\t);\n\t\t});\n\n\t\ttest('no codeBlock', () => {\n\t\t\texpect(escapeMarkdown(testString, { codeBlock: false })).toEqual(\n\t\t\t\t\"\\\\> \\\\`\\\\_Behold!\\\\_\\\\`\\n\\\\|\\\\|\\\\_\\\\_\\\\_\\\\~\\\\~\\\\*\\\\*\\\\*```js\\n\\\\`use strict\\\\`;\\nrequire('discord.js');```\\\\*\\\\*\\\\*\\\\~\\\\~\\\\_\\\\_\\\\_\\\\|\\\\|\",\n\t\t\t);\n\t\t});\n\n\t\ttest('no inlineCode', () => {\n\t\t\texpect(escapeMarkdown(testString, { inlineCode: false })).toEqual(\n\t\t\t\t\"\\\\> `\\\\_Behold!\\\\_`\\n\\\\|\\\\|\\\\_\\\\_\\\\_\\\\~\\\\~\\\\*\\\\*\\\\*\\\\`\\\\`\\\\`js\\n`use strict`;\\nrequire('discord.js');\\\\`\\\\`\\\\`\\\\*\\\\*\\\\*\\\\~\\\\~\\\\_\\\\_\\\\_\\\\|\\\\|\",\n\t\t\t);\n\t\t});\n\n\t\ttest('no bold', () => {\n\t\t\texpect(escapeMarkdown(testString, { bold: false })).toEqual(\n\t\t\t\t\"\\\\> \\\\`\\\\_Behold!\\\\_\\\\`\\n\\\\|\\\\|\\\\_\\\\_\\\\_\\\\~\\\\~\\\\***\\\\`\\\\`\\\\`js\\n\\\\`use strict\\\\`;\\nrequire('discord.js');\\\\`\\\\`\\\\`**\\\\*\\\\~\\\\~\\\\_\\\\_\\\\_\\\\|\\\\|\",\n\t\t\t);\n\t\t});\n\n\t\ttest('no italic', () => {\n\t\t\texpect(escapeMarkdown(testString, { italic: false })).toEqual(\n\t\t\t\t\"\\\\> \\\\`_Behold!_\\\\`\\n\\\\|\\\\|_\\\\_\\\\_\\\\~\\\\~*\\\\*\\\\*\\\\`\\\\`\\\\`js\\n\\\\`use strict\\\\`;\\nrequire('discord.js');\\\\`\\\\`\\\\`\\\\*\\\\**\\\\~\\\\~\\\\_\\\\__\\\\|\\\\|\",\n\t\t\t);\n\t\t});\n\n\t\ttest('no underline', () => {\n\t\t\texpect(escapeMarkdown(testString, { underline: false })).toEqual(\n\t\t\t\t\"\\\\> \\\\`\\\\_Behold!\\\\_\\\\`\\n\\\\|\\\\|\\\\___\\\\~\\\\~\\\\*\\\\*\\\\*\\\\`\\\\`\\\\`js\\n\\\\`use strict\\\\`;\\nrequire('discord.js');\\\\`\\\\`\\\\`\\\\*\\\\*\\\\*\\\\~\\\\~__\\\\_\\\\|\\\\|\",\n\t\t\t);\n\t\t});\n\n\t\ttest('no strikethrough', () => {\n\t\t\texpect(escapeMarkdown(testString, { strikethrough: false })).toEqual(\n\t\t\t\t\"\\\\> \\\\`\\\\_Behold!\\\\_\\\\`\\n\\\\|\\\\|\\\\_\\\\_\\\\_~~\\\\*\\\\*\\\\*\\\\`\\\\`\\\\`js\\n\\\\`use strict\\\\`;\\nrequire('discord.js');\\\\`\\\\`\\\\`\\\\*\\\\*\\\\*~~\\\\_\\\\_\\\\_\\\\|\\\\|\",\n\t\t\t);\n\t\t});\n\n\t\ttest('no spoiler', () => {\n\t\t\texpect(escapeMarkdown(testString, { spoiler: false })).toEqual(\n\t\t\t\t\"\\\\> \\\\`\\\\_Behold!\\\\_\\\\`\\n||\\\\_\\\\_\\\\_\\\\~\\\\~\\\\*\\\\*\\\\*\\\\`\\\\`\\\\`js\\n\\\\`use strict\\\\`;\\nrequire('discord.js');\\\\`\\\\`\\\\`\\\\*\\\\*\\\\*\\\\~\\\\~\\\\_\\\\_\\\\_||\",\n\t\t\t);\n\t\t});\n\n\t\ttest('no quote', () => {\n\t\t\texpect(escapeMarkdown(testString, { quote: false })).toEqual(\n\t\t\t\t\"> \\\\`\\\\_Behold!\\\\_\\\\`\\n\\\\|\\\\|\\\\_\\\\_\\\\_\\\\~\\\\~\\\\*\\\\*\\\\*\\\\`\\\\`\\\\`js\\n\\\\`use strict\\\\`;\\nrequire('discord.js');\\\\`\\\\`\\\\`\\\\*\\\\*\\\\*\\\\~\\\\~\\\\_\\\\_\\\\_\\\\|\\\\|\",\n\t\t\t);\n\t\t});\n\n\t\tdescribe('block quotes', () => {\n\t\t\ttest('blockQuote', () => {\n\t\t\t\tconst testStringWithBlockQuote = `>>${testString}`;\n\t\t\t\texpect(escapeMarkdown(testStringWithBlockQuote)).toEqual(\n\t\t\t\t\t\"\\\\>>> \\\\`\\\\_Behold!\\\\_\\\\`\\n\\\\|\\\\|\\\\_\\\\_\\\\_\\\\~\\\\~\\\\*\\\\*\\\\*\\\\`\\\\`\\\\`js\\n\\\\`use strict\\\\`;\\nrequire('discord.js');\\\\`\\\\`\\\\`\\\\*\\\\*\\\\*\\\\~\\\\~\\\\_\\\\_\\\\_\\\\|\\\\|\",\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('no blockQuote', () => {\n\t\t\t\tconst testStringWithBlockQuote = `>>${testString}`;\n\t\t\t\texpect(escapeMarkdown(testStringWithBlockQuote, { blockQuote: false })).toEqual(\n\t\t\t\t\t\">>> \\\\`\\\\_Behold!\\\\_\\\\`\\n\\\\|\\\\|\\\\_\\\\_\\\\_\\\\~\\\\~\\\\*\\\\*\\\\*\\\\`\\\\`\\\\`js\\n\\\\`use strict\\\\`;\\nrequire('discord.js');\\\\`\\\\`\\\\`\\\\*\\\\*\\\\*\\\\~\\\\~\\\\_\\\\_\\\\_\\\\|\\\\|\",\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\n\t\tdescribe('code content', () => {\n\t\t\ttest('no code block content', () => {\n\t\t\t\texpect(escapeMarkdown(testString, { codeBlockContent: false })).toEqual(\n\t\t\t\t\t\"\\\\> \\\\`\\\\_Behold!\\\\_\\\\`\\n\\\\|\\\\|\\\\_\\\\_\\\\_\\\\~\\\\~\\\\*\\\\*\\\\*\\\\`\\\\`\\\\`js\\n`use strict`;\\nrequire('discord.js');\\\\`\\\\`\\\\`\\\\*\\\\*\\\\*\\\\~\\\\~\\\\_\\\\_\\\\_\\\\|\\\\|\",\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('no inline code content', () => {\n\t\t\t\texpect(escapeMarkdown(testString, { inlineCodeContent: false })).toEqual(\n\t\t\t\t\t\"\\\\> \\\\`_Behold!_\\\\`\\n\\\\|\\\\|\\\\_\\\\_\\\\_\\\\~\\\\~\\\\*\\\\*\\\\*\\\\`\\\\`\\\\`js\\n\\\\`use strict\\\\`;\\nrequire('discord.js');\\\\`\\\\`\\\\`\\\\*\\\\*\\\\*\\\\~\\\\~\\\\_\\\\_\\\\_\\\\|\\\\|\",\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('neither inline code or code block content', () => {\n\t\t\t\texpect(escapeMarkdown(testString, { inlineCodeContent: false, codeBlockContent: false })).toEqual(\n\t\t\t\t\t\"\\\\> \\\\`_Behold!_\\\\`\\n\\\\|\\\\|\\\\_\\\\_\\\\_\\\\~\\\\~\\\\*\\\\*\\\\*\\\\`\\\\`\\\\`js\\n`use strict`;\\nrequire('discord.js');\\\\`\\\\`\\\\`\\\\*\\\\*\\\\*\\\\~\\\\~\\\\_\\\\_\\\\_\\\\|\\\\|\",\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('neither code blocks or code block content', () => {\n\t\t\t\texpect(escapeMarkdown(testString, { codeBlock: false, codeBlockContent: false })).toEqual(\n\t\t\t\t\t\"\\\\> \\\\`\\\\_Behold!\\\\_\\\\`\\n\\\\|\\\\|\\\\_\\\\_\\\\_\\\\~\\\\~\\\\*\\\\*\\\\*```js\\n`use strict`;\\nrequire('discord.js');```\\\\*\\\\*\\\\*\\\\~\\\\~\\\\_\\\\_\\\\_\\\\|\\\\|\",\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('neither inline code or inline code content', () => {\n\t\t\t\texpect(escapeMarkdown(testString, { inlineCode: false, inlineCodeContent: false })).toEqual(\n\t\t\t\t\t\"\\\\> `_Behold!_`\\n\\\\|\\\\|\\\\_\\\\_\\\\_\\\\~\\\\~\\\\*\\\\*\\\\*\\\\`\\\\`\\\\`js\\n`use strict`;\\nrequire('discord.js');\\\\`\\\\`\\\\`\\\\*\\\\*\\\\*\\\\~\\\\~\\\\_\\\\_\\\\_\\\\|\\\\|\",\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('edge-case odd number of fences with no code block content', () => {\n\t\t\t\texpect(\n\t\t\t\t\tescapeMarkdown('**foo** ```**bar**``` **fizz** ``` **buzz**', {\n\t\t\t\t\t\tcodeBlock: false,\n\t\t\t\t\t\tcodeBlockContent: false,\n\t\t\t\t\t}),\n\t\t\t\t).toEqual('\\\\*\\\\*foo\\\\*\\\\* ```**bar**``` \\\\*\\\\*fizz\\\\*\\\\* ``` \\\\*\\\\*buzz\\\\*\\\\*');\n\t\t\t});\n\n\t\t\ttest('edge-case odd number of backticks with no inline code content', () => {\n\t\t\t\texpect(\n\t\t\t\t\tescapeMarkdown('**foo** `**bar**` **fizz** ` **buzz**', { inlineCode: false, inlineCodeContent: false }),\n\t\t\t\t).toEqual('\\\\*\\\\*foo\\\\*\\\\* `**bar**` \\\\*\\\\*fizz\\\\*\\\\* ` \\\\*\\\\*buzz\\\\*\\\\*');\n\t\t\t});\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/formatters/__tests__/formatters.test.ts",
    "content": "/* eslint-disable no-template-curly-in-string */\nimport { describe, test, expect, vitest } from 'vitest';\nimport {\n\tapplicationDirectory,\n\tchatInputApplicationCommandMention,\n\tblockQuote,\n\tbold,\n\tchannelLink,\n\tchannelMention,\n\tcodeBlock,\n\tFaces,\n\tformatEmoji,\n\theading,\n\tHeadingLevel,\n\thideLinkEmbed,\n\thyperlink,\n\tinlineCode,\n\titalic,\n\tlinkedRoleMention,\n\tmessageLink,\n\torderedList,\n\tquote,\n\troleMention,\n\tspoiler,\n\tstrikethrough,\n\tsubtext,\n\ttime,\n\tTimestampStyles,\n\tunderline,\n\tunorderedList,\n\tuserMention,\n\temail,\n\tphoneNumber,\n} from '../src/index.js';\n\ndescribe('Message formatters', () => {\n\tdescribe('codeBlock', () => {\n\t\ttest('GIVEN \"discord.js\" with no language THEN returns \"```\\\\ndiscord.js```\"', () => {\n\t\t\texpect<'```\\ndiscord.js\\n```'>(codeBlock('discord.js')).toEqual('```\\ndiscord.js\\n```');\n\t\t});\n\n\t\ttest('GIVEN \"discord.js\" with \"js\" as language THEN returns \"```js\\\\ndiscord.js```\"', () => {\n\t\t\texpect<'```js\\ndiscord.js\\n```'>(codeBlock('js', 'discord.js')).toEqual('```js\\ndiscord.js\\n```');\n\t\t});\n\t});\n\n\tdescribe('inlineCode', () => {\n\t\ttest('GIVEN \"discord.js\" THEN returns \"`discord.js`\"', () => {\n\t\t\texpect<'`discord.js`'>(inlineCode('discord.js')).toEqual('`discord.js`');\n\t\t});\n\t});\n\n\tdescribe('italic', () => {\n\t\ttest('GIVEN \"discord.js\" THEN returns \"_discord.js_\"', () => {\n\t\t\texpect<'_discord.js_'>(italic('discord.js')).toEqual('_discord.js_');\n\t\t});\n\t});\n\n\tdescribe('bold', () => {\n\t\ttest('GIVEN \"discord.js\" THEN returns \"**discord.js**\"', () => {\n\t\t\texpect<'**discord.js**'>(bold('discord.js')).toEqual('**discord.js**');\n\t\t});\n\t});\n\n\tdescribe('underline', () => {\n\t\ttest('GIVEN \"discord.js\" THEN returns \"__discord.js__\"', () => {\n\t\t\texpect<'__discord.js__'>(underline('discord.js')).toEqual('__discord.js__');\n\t\t});\n\t});\n\n\tdescribe('strikethrough', () => {\n\t\ttest('GIVEN \"discord.js\" THEN returns \"~~discord.js~~\"', () => {\n\t\t\texpect<'~~discord.js~~'>(strikethrough('discord.js')).toEqual('~~discord.js~~');\n\t\t});\n\t});\n\n\tdescribe('quote', () => {\n\t\ttest('GIVEN \"discord.js\" THEN returns \"> discord.js\"', () => {\n\t\t\texpect<'> discord.js'>(quote('discord.js')).toEqual('> discord.js');\n\t\t});\n\t});\n\n\tdescribe('blockQuote', () => {\n\t\ttest('GIVEN \"discord.js\" THEN returns \">>> discord.js\"', () => {\n\t\t\texpect<'>>> discord.js'>(blockQuote('discord.js')).toEqual('>>> discord.js');\n\t\t});\n\t});\n\n\tdescribe('hideLinkEmbed', () => {\n\t\ttest('GIVEN \"https://discord.js.org\" THEN returns \"<https://discord.js.org>\"', () => {\n\t\t\texpect<'<https://discord.js.org>'>(hideLinkEmbed('https://discord.js.org')).toEqual('<https://discord.js.org>');\n\t\t});\n\n\t\ttest('GIVEN new URL(\"https://discord.js.org\") THEN returns \"<https://discord.js.org>\"', () => {\n\t\t\texpect<`<${string}>`>(hideLinkEmbed(new URL('https://discord.js.org/'))).toEqual('<https://discord.js.org/>');\n\t\t});\n\t});\n\n\tdescribe('hyperlink', () => {\n\t\ttest('GIVEN content and string URL THEN returns \"[content](url)\"', () => {\n\t\t\texpect<'[discord.js](https://discord.js.org)'>(hyperlink('discord.js', 'https://discord.js.org')).toEqual(\n\t\t\t\t'[discord.js](https://discord.js.org)',\n\t\t\t);\n\t\t});\n\n\t\ttest('GIVEN content and URL THEN returns \"[content](url)\"', () => {\n\t\t\texpect<`[discord.js](${string})`>(hyperlink('discord.js', new URL('https://discord.js.org'))).toEqual(\n\t\t\t\t'[discord.js](https://discord.js.org/)',\n\t\t\t);\n\t\t});\n\n\t\ttest('GIVEN content, string URL, and title THEN returns \"[content](url \"title\")\"', () => {\n\t\t\texpect<'[discord.js](https://discord.js.org \"Official Documentation\")'>(\n\t\t\t\thyperlink('discord.js', 'https://discord.js.org', 'Official Documentation'),\n\t\t\t).toEqual('[discord.js](https://discord.js.org \"Official Documentation\")');\n\t\t});\n\n\t\ttest('GIVEN content, URL, and title THEN returns \"[content](url \"title\")\"', () => {\n\t\t\texpect<`[discord.js](${string} \"Official Documentation\")`>(\n\t\t\t\thyperlink('discord.js', new URL('https://discord.js.org'), 'Official Documentation'),\n\t\t\t).toEqual('[discord.js](https://discord.js.org/ \"Official Documentation\")');\n\t\t});\n\t});\n\n\tdescribe('spoiler', () => {\n\t\ttest('GIVEN \"discord.js\" THEN returns \"||discord.js||\"', () => {\n\t\t\texpect<'||discord.js||'>(spoiler('discord.js')).toEqual('||discord.js||');\n\t\t});\n\t});\n\n\tdescribe('Mentions', () => {\n\t\tdescribe('userMention', () => {\n\t\t\ttest('GIVEN userId THEN returns \"<@[userId]>\"', () => {\n\t\t\t\texpect(userMention('139836912335716352')).toEqual('<@139836912335716352>');\n\t\t\t});\n\t\t});\n\n\t\tdescribe('channelMention', () => {\n\t\t\ttest('GIVEN channelId THEN returns \"<#[channelId]>\"', () => {\n\t\t\t\texpect(channelMention('829924760309334087')).toEqual('<#829924760309334087>');\n\t\t\t});\n\t\t});\n\n\t\tdescribe('roleMention', () => {\n\t\t\ttest('GIVEN roleId THEN returns \"<&[roleId]>\"', () => {\n\t\t\t\texpect(roleMention('815434166602170409')).toEqual('<@&815434166602170409>');\n\t\t\t});\n\t\t});\n\n\t\tdescribe('linkedRoleMention', () => {\n\t\t\ttest('GIVEN roleId THEN returns \"<id:linked-roles:[roleId]>\"', () => {\n\t\t\t\texpect(linkedRoleMention('815434166602170409')).toEqual('<id:linked-roles:815434166602170409>');\n\t\t\t});\n\t\t});\n\n\t\tdescribe('chatInputApplicationCommandMention', () => {\n\t\t\ttest('GIVEN commandId and commandName THEN returns \"</[commandName]:[commandId]>\"', () => {\n\t\t\t\texpect(chatInputApplicationCommandMention('815434166602170409', 'airhorn')).toEqual(\n\t\t\t\t\t'</airhorn:815434166602170409>',\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('GIVEN commandId, commandName, subcommandName  THEN returns \"</[commandName] [subcommandName]:[commandId]>\"', () => {\n\t\t\t\texpect(chatInputApplicationCommandMention('815434166602170409', 'airhorn', 'sub')).toEqual(\n\t\t\t\t\t'</airhorn sub:815434166602170409>',\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('GIVEN commandId, commandName, subcommandName, and subcommandGroupName, THEN returns \"</[commandName] [subcommandGroupName] [subcommandName]:[commandId]>\"', () => {\n\t\t\t\texpect(chatInputApplicationCommandMention('815434166602170409', 'airhorn', 'sub', 'group')).toEqual(\n\t\t\t\t\t'</airhorn group sub:815434166602170409>',\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('formatEmoji', () => {\n\t\ttest('GIVEN static emojiId THEN returns \"<:emoji:${emojiId}>\"', () => {\n\t\t\texpect<`<:emoji:851461487498493952>`>(formatEmoji('851461487498493952')).toEqual('<:emoji:851461487498493952>');\n\t\t});\n\n\t\ttest('GIVEN static emojiId WITH animated explicitly false THEN returns \"<:emoji:[emojiId]>\"', () => {\n\t\t\texpect<`<:emoji:851461487498493952>`>(formatEmoji('851461487498493952', false)).toEqual(\n\t\t\t\t'<:emoji:851461487498493952>',\n\t\t\t);\n\t\t});\n\n\t\ttest('GIVEN animated emojiId THEN returns \"<a:emoji:${emojiId}>\"', () => {\n\t\t\texpect<`<a:emoji:827220205352255549>`>(formatEmoji('827220205352255549', true)).toEqual(\n\t\t\t\t'<a:emoji:827220205352255549>',\n\t\t\t);\n\t\t});\n\n\t\ttest('GIVEN static id in options object THEN returns \"<:emoji:${id}>\"', () => {\n\t\t\texpect<`<:emoji:851461487498493952>`>(formatEmoji({ id: '851461487498493952' })).toEqual(\n\t\t\t\t'<:emoji:851461487498493952>',\n\t\t\t);\n\t\t});\n\n\t\ttest('GIVEN static id in options object WITH animated explicitly false THEN returns \"<:emoji:${id}>\"', () => {\n\t\t\texpect<`<:emoji:851461487498493952>`>(formatEmoji({ animated: false, id: '851461487498493952' })).toEqual(\n\t\t\t\t'<:emoji:851461487498493952>',\n\t\t\t);\n\t\t});\n\n\t\ttest('GIVEN animated id in options object THEN returns \"<a:emoji:${id}>\"', () => {\n\t\t\texpect<`<a:emoji:827220205352255549>`>(formatEmoji({ animated: true, id: '827220205352255549' })).toEqual(\n\t\t\t\t'<a:emoji:827220205352255549>',\n\t\t\t);\n\t\t});\n\n\t\ttest('GIVEN static id and name in options object THEN returns \"<:${name}:${id}>\"', () => {\n\t\t\texpect<`<:test:851461487498493952>`>(formatEmoji({ id: '851461487498493952', name: 'test' })).toEqual(\n\t\t\t\t'<:test:851461487498493952>',\n\t\t\t);\n\t\t});\n\n\t\ttest('GIVEN static id and name WITH animated explicitly false THEN returns \"<:${name}:${id}>\"', () => {\n\t\t\texpect<`<:test:851461487498493952>`>(\n\t\t\t\tformatEmoji({ animated: false, id: '851461487498493952', name: 'test' }),\n\t\t\t).toEqual('<:test:851461487498493952>');\n\t\t});\n\n\t\ttest('GIVEN animated id and name THEN returns \"<a:${name}:${id}>\"', () => {\n\t\t\texpect<`<a:test:827220205352255549>`>(\n\t\t\t\tformatEmoji({ id: '827220205352255549', name: 'test', animated: true }),\n\t\t\t).toEqual('<a:test:827220205352255549>');\n\t\t});\n\t});\n\n\tdescribe('channelLink', () => {\n\t\ttest('GIVEN channelId THEN returns \"https://discord.com/channels/@me/${channelId}\"', () => {\n\t\t\texpect<'https://discord.com/channels/@me/123456789012345678'>(channelLink('123456789012345678')).toEqual(\n\t\t\t\t'https://discord.com/channels/@me/123456789012345678',\n\t\t\t);\n\t\t});\n\n\t\ttest('GIVEN channelId WITH guildId THEN returns \"https://discord.com/channels/${guildId}/${channelId}\"', () => {\n\t\t\texpect<'https://discord.com/channels/987654321987654/123456789012345678'>(\n\t\t\t\tchannelLink('123456789012345678', '987654321987654'),\n\t\t\t).toEqual('https://discord.com/channels/987654321987654/123456789012345678');\n\t\t});\n\t});\n\n\tdescribe('messageLink', () => {\n\t\ttest('GIVEN channelId AND messageId THEN returns \"https://discord.com/channels/@me/${channelId}/${messageId}\"', () => {\n\t\t\texpect<'https://discord.com/channels/@me/123456789012345678/102938475657483'>(\n\t\t\t\tmessageLink('123456789012345678', '102938475657483'),\n\t\t\t).toEqual('https://discord.com/channels/@me/123456789012345678/102938475657483');\n\t\t});\n\n\t\ttest('GIVEN channelId AND messageId WITH guildId THEN returns \"https://discord.com/channels/${guildId}/${channelId}/${messageId}\"', () => {\n\t\t\texpect<'https://discord.com/channels/987654321987654/123456789012345678/102938475657483'>(\n\t\t\t\tmessageLink('123456789012345678', '102938475657483', '987654321987654'),\n\t\t\t).toEqual('https://discord.com/channels/987654321987654/123456789012345678/102938475657483');\n\t\t});\n\t});\n\n\tdescribe('heading', () => {\n\t\ttest('GIVEN \"discord.js\" THEN returns \"# discord.js\"', () => {\n\t\t\texpect<'# discord.js'>(heading('discord.js')).toEqual('# discord.js');\n\t\t});\n\n\t\ttest('GIVEN \"discord.js\" AND a heading level 2 from number THEN returns \"## discord.js\"', () => {\n\t\t\texpect<'## discord.js'>(heading('discord.js', 2)).toEqual('## discord.js');\n\t\t});\n\n\t\ttest('GIVEN \"discord.js\" AND a heading level 3 from enum THEN returns \"### discord.js\"', () => {\n\t\t\texpect<'### discord.js'>(heading('discord.js', HeadingLevel.Three)).toEqual('### discord.js');\n\t\t});\n\t});\n\n\tdescribe('orderedList', () => {\n\t\ttest('GIVEN [\"discord.js\", \"discord.js 2\", [\"discord.js 3\"]] THEN returns \"1. discord.js\\n1. discord.js 2\\n  1. discord.js\"', () => {\n\t\t\texpect(orderedList(['discord.js', 'discord.js 2', ['discord.js 3']])).toEqual(\n\t\t\t\t'1. discord.js\\n1. discord.js 2\\n  1. discord.js 3',\n\t\t\t);\n\t\t});\n\n\t\ttest('GIVEN [\"discord.js\", \"discord.js 2\", [\"discord.js 3\"]] AND a startNumber THEN returns \"${startNumber}. discord.js\\n${startNumber}. discord.js 2\\n  ${startNumber}. discord.js\"', () => {\n\t\t\texpect(orderedList(['discord.js', 'discord.js 2', ['discord.js 3']], 50)).toEqual(\n\t\t\t\t'50. discord.js\\n50. discord.js 2\\n  50. discord.js 3',\n\t\t\t);\n\t\t});\n\t});\n\n\tdescribe('unorderedList', () => {\n\t\ttest('GIVEN [\"discord.js\", \"discord.js 2\", [\"discord.js 3\"]] THEN returns \"- discord.js\\n- discord.js 2\\n  - discord.js\"', () => {\n\t\t\texpect(unorderedList(['discord.js', 'discord.js 2', ['discord.js 3']])).toEqual(\n\t\t\t\t'- discord.js\\n- discord.js 2\\n  - discord.js 3',\n\t\t\t);\n\t\t});\n\t});\n\n\tdescribe('subtext', () => {\n\t\ttest('GIVEN \"discord.js\" THEN returns \"-# discord.js\"', () => {\n\t\t\texpect<'-# discord.js'>(subtext('discord.js')).toEqual('-# discord.js');\n\t\t});\n\t});\n\n\tdescribe('time', () => {\n\t\ttest('GIVEN no arguments THEN returns \"<t:${bigint}>\"', () => {\n\t\t\tvitest.useFakeTimers();\n\t\t\tvitest.setSystemTime(1_566_424_897_579);\n\n\t\t\texpect<`<t:${bigint}>`>(time()).toEqual('<t:1566424897>');\n\n\t\t\tvitest.useRealTimers();\n\t\t});\n\n\t\ttest('GIVEN a date THEN returns \"<t:${bigint}>\"', () => {\n\t\t\texpect<`<t:${bigint}>`>(time(new Date(1_867_424_897_579))).toEqual('<t:1867424897>');\n\t\t});\n\n\t\ttest('GIVEN a date and a style from string THEN returns \"<t:${bigint}:${style}>\"', () => {\n\t\t\texpect<`<t:${bigint}:d>`>(time(new Date(1_867_424_897_579), 'd')).toEqual('<t:1867424897:d>');\n\t\t});\n\n\t\ttest('GIVEN a date and a format from enum THEN returns \"<t:${bigint}:${style}>\"', () => {\n\t\t\texpect<`<t:${bigint}:R>`>(time(new Date(1_867_424_897_579), TimestampStyles.RelativeTime)).toEqual(\n\t\t\t\t'<t:1867424897:R>',\n\t\t\t);\n\t\t});\n\n\t\ttest('GIVEN a date THEN returns \"<t:${time}>\"', () => {\n\t\t\texpect<'<t:1867424897>'>(time(1_867_424_897)).toEqual('<t:1867424897>');\n\t\t});\n\n\t\ttest('GIVEN a date and a style from string THEN returns \"<t:${time}:${style}>\"', () => {\n\t\t\texpect<'<t:1867424897:d>'>(time(1_867_424_897, 'd')).toEqual('<t:1867424897:d>');\n\t\t});\n\n\t\ttest.each([\n\t\t\t[TimestampStyles.ShortTime, 't'],\n\t\t\t[TimestampStyles.MediumTime, 'T'],\n\t\t\t[TimestampStyles.ShortDate, 'd'],\n\t\t\t[TimestampStyles.LongDate, 'D'],\n\t\t\t[TimestampStyles.LongDateShortTime, 'f'],\n\t\t\t[TimestampStyles.FullDateShortTime, 'F'],\n\t\t\t[TimestampStyles.ShortDateShortTime, 's'],\n\t\t\t[TimestampStyles.ShortDateMediumTime, 'S'],\n\t\t\t[TimestampStyles.RelativeTime, 'R'],\n\t\t])('GIVEN a date and style from enum THEN returns \"<t:${time}:${style}>\"', (style, expectedStyle) => {\n\t\t\texpect<`<t:1867424897:${typeof style}>`>(time(1_867_424_897, style)).toEqual(`<t:1867424897:${expectedStyle}>`);\n\t\t});\n\t});\n\n\tdescribe('applicationDirectory', () => {\n\t\ttest('GIVEN application id THEN returns application directory store', () => {\n\t\t\texpect(applicationDirectory('123456789012345678')).toEqual(\n\t\t\t\t'https://discord.com/application-directory/123456789012345678/store',\n\t\t\t);\n\t\t});\n\n\t\ttest('GIVEN application id AND SKU id THEN returns SKU within the application directory store', () => {\n\t\t\texpect(applicationDirectory('123456789012345678', '123456789012345678')).toEqual(\n\t\t\t\t'https://discord.com/application-directory/123456789012345678/store/123456789012345678',\n\t\t\t);\n\t\t});\n\t});\n\n\tdescribe('email', () => {\n\t\ttest('GIVEN an email THEN returns \"<[email]>\"', () => {\n\t\t\texpect<'<test@example.com>'>(email('test@example.com')).toEqual('<test@example.com>');\n\t\t});\n\n\t\ttest('GIVEN an email AND headers THEN returns \"<[email]?[headers]>\"', () => {\n\t\t\texpect<`<test@example.com?${string}>`>(email('test@example.com', { subject: 'Hello', body: 'World' })).toEqual(\n\t\t\t\t'<test@example.com?subject=Hello&body=World>',\n\t\t\t);\n\t\t});\n\t});\n\n\tdescribe('phoneNumber', () => {\n\t\ttest('GIVEN a phone number with + THEN returns \"<[phoneNumber]>\"', () => {\n\t\t\texpect<'<+1234567890>'>(phoneNumber('+1234567890')).toEqual('<+1234567890>');\n\t\t});\n\n\t\ttest('GIVEN a phone number without + THEN throws', () => {\n\t\t\texpect(() =>\n\t\t\t\tphoneNumber(\n\t\t\t\t\t// @ts-expect-error - Invalid input\n\t\t\t\t\t'1234567890',\n\t\t\t\t),\n\t\t\t).toThrowError();\n\t\t});\n\t});\n\n\tdescribe('Faces', () => {\n\t\ttest('GIVEN Faces.Shrug THEN returns \"¯\\\\_(ツ)_/¯\"', () => {\n\t\t\texpect<'¯\\\\_(ツ)_/¯'>(Faces.Shrug).toEqual('¯\\\\_(ツ)_/¯');\n\t\t});\n\n\t\ttest('GIVEN Faces.Tableflip THEN returns \"(╯°□°)╯︵ ┻━┻\"', () => {\n\t\t\texpect<'(╯°□°)╯︵ ┻━┻'>(Faces.Tableflip).toEqual('(╯°□°)╯︵ ┻━┻');\n\t\t});\n\n\t\ttest('GIVEN Faces.Unflip THEN returns \"┬─┬ノ( º _ ºノ)\"', () => {\n\t\t\texpect<'┬─┬ノ( º _ ºノ)'>(Faces.Unflip).toEqual('┬─┬ノ( º _ ºノ)');\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/formatters/api-extractor.json",
    "content": "{\n\t\"extends\": \"../../api-extractor.json\",\n\t\"docModel\": {\n\t\t\"projectFolderUrl\": \"https://github.com/discordjs/discord.js/tree/main/packages/formatters\"\n\t}\n}\n"
  },
  {
    "path": "packages/formatters/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t\t{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length %}\\\n\t\\n### New Contributors\\n\n\t{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\\\n\t\t* @{{ contributor.username }} made their first contribution in #{{ contributor.pr_number }}\n\t{% endfor %}\\\n{% endif %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"@discordjs/formatters@[0-9]*\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/formatters/docs/README.md",
    "content": "## [View the documentation here.](https://discord.js.org/docs/packages/formatters/main)\n"
  },
  {
    "path": "packages/formatters/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/formatters\",\n\t\"version\": \"0.6.1\",\n\t\"description\": \"A set of functions to format strings for Discord.\",\n\t\"scripts\": {\n\t\t\"test\": \"vitest run --config ../../vitest.config.ts\",\n\t\t\"build\": \"tsc --noEmit && tsup\",\n\t\t\"build:docs\": \"tsc -p tsconfig.docs.json\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src __tests__\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src __tests__\",\n\t\t\"docs\": \"pnpm run build:docs && api-extractor run --local --minify && generate-split-documentation\",\n\t\t\"prepack\": \"pnpm run build && pnpm run lint\",\n\t\t\"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/formatters/*'\",\n\t\t\"release\": \"cliff-jumper\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"main\": \"./dist/index.js\",\n\t\"module\": \"./dist/index.mjs\",\n\t\"types\": \"./dist/index.d.ts\",\n\t\"directories\": {\n\t\t\"lib\": \"src\",\n\t\t\"test\": \"__tests__\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/formatters\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"discord-api-types\": \"^0.38.41\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@discordjs/api-extractor\": \"workspace:^\",\n\t\t\"@discordjs/scripts\": \"workspace:^\",\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@types/node\": \"^22.19.11\",\n\t\t\"@vitest/coverage-v8\": \"^4.0.18\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"esbuild-plugin-version-injector\": \"^1.2.1\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vitest\": \"^4.0.18\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/formatters/src/escapers.ts",
    "content": "/* eslint-disable prefer-named-capture-group */\n\n/**\n * The options that affect what will be escaped.\n */\nexport interface EscapeMarkdownOptions {\n\t/**\n\t * Whether to escape block quotes.\n\t *\n\t * @defaultValue `true`\n\t */\n\tblockQuote?: boolean;\n\n\t/**\n\t * Whether to escape bold text.\n\t *\n\t * @defaultValue `true`\n\t */\n\tbold?: boolean;\n\n\t/**\n\t * Whether to escape bulleted lists.\n\t *\n\t * @defaultValue `true`\n\t */\n\tbulletedList?: boolean;\n\n\t/**\n\t * Whether to escape code blocks.\n\t *\n\t * @defaultValue `true`\n\t */\n\tcodeBlock?: boolean;\n\n\t/**\n\t * Whether to escape text inside code blocks.\n\t *\n\t * @defaultValue `true`\n\t */\n\tcodeBlockContent?: boolean;\n\n\t/**\n\t * Whether to escape `\\`.\n\t *\n\t * @defaultValue `true`\n\t */\n\tescape?: boolean;\n\n\t/**\n\t * Whether to escape headings.\n\t *\n\t * @defaultValue `true`\n\t */\n\theading?: boolean;\n\n\t/**\n\t * Whether to escape inline code.\n\t *\n\t * @defaultValue `true`\n\t */\n\tinlineCode?: boolean;\n\n\t/**\n\t * Whether to escape text inside inline code.\n\t *\n\t * @defaultValue `true`\n\t */\n\tinlineCodeContent?: boolean;\n\t/**\n\t * Whether to escape italics.\n\t *\n\t * @defaultValue `true`\n\t */\n\titalic?: boolean;\n\n\t/**\n\t * Whether to escape masked links.\n\t *\n\t * @defaultValue `true`\n\t */\n\tmaskedLink?: boolean;\n\n\t/**\n\t * Whether to escape numbered lists.\n\t *\n\t * @defaultValue `true`\n\t */\n\tnumberedList?: boolean;\n\n\t/**\n\t * Whether to escape block quotes.\n\t *\n\t * @defaultValue `true`\n\t */\n\tquote?: boolean;\n\n\t/**\n\t * Whether to escape spoilers.\n\t *\n\t * @defaultValue `true`\n\t */\n\tspoiler?: boolean;\n\n\t/**\n\t * Whether to escape strikethroughs.\n\t *\n\t * @defaultValue `true`\n\t */\n\tstrikethrough?: boolean;\n\n\t/**\n\t * Whether to escape underlines.\n\t *\n\t * @defaultValue `true`\n\t */\n\tunderline?: boolean;\n}\n\n/**\n * Escapes any Discord-flavored markdown in a string.\n *\n * @param text - Content to escape\n * @param options - Options for escaping the markdown\n */\nexport function escapeMarkdown(text: string, options: EscapeMarkdownOptions = {}): string {\n\tconst {\n\t\tcodeBlock = true,\n\t\tinlineCode = true,\n\t\tbold = true,\n\t\titalic = true,\n\t\tunderline = true,\n\t\tstrikethrough = true,\n\t\tspoiler = true,\n\t\tcodeBlockContent = true,\n\t\tinlineCodeContent = true,\n\t\tescape = true,\n\t\theading = true,\n\t\tbulletedList = true,\n\t\tnumberedList = true,\n\t\tmaskedLink = true,\n\t\tblockQuote = true,\n\t\tquote = true,\n\t} = options;\n\n\tif (!codeBlockContent) {\n\t\treturn text\n\t\t\t.split('```')\n\t\t\t.map((subString, index, array) => {\n\t\t\t\tif (index % 2 && index !== array.length - 1) return subString;\n\t\t\t\treturn escapeMarkdown(subString, {\n\t\t\t\t\tinlineCode,\n\t\t\t\t\tbold,\n\t\t\t\t\titalic,\n\t\t\t\t\tunderline,\n\t\t\t\t\tstrikethrough,\n\t\t\t\t\tspoiler,\n\t\t\t\t\tinlineCodeContent,\n\t\t\t\t\tescape,\n\t\t\t\t\theading,\n\t\t\t\t\tbulletedList,\n\t\t\t\t\tnumberedList,\n\t\t\t\t\tmaskedLink,\n\t\t\t\t\tblockQuote,\n\t\t\t\t\tquote,\n\t\t\t\t});\n\t\t\t})\n\t\t\t.join(codeBlock ? '\\\\`\\\\`\\\\`' : '```');\n\t}\n\n\tif (!inlineCodeContent) {\n\t\treturn text\n\t\t\t.split(/(?<=^|[^`])`(?=[^`]|$)/g)\n\t\t\t.map((subString, index, array) => {\n\t\t\t\tif (index % 2 && index !== array.length - 1) return subString;\n\t\t\t\treturn escapeMarkdown(subString, {\n\t\t\t\t\tcodeBlock,\n\t\t\t\t\tbold,\n\t\t\t\t\titalic,\n\t\t\t\t\tunderline,\n\t\t\t\t\tstrikethrough,\n\t\t\t\t\tspoiler,\n\t\t\t\t\tescape,\n\t\t\t\t\theading,\n\t\t\t\t\tbulletedList,\n\t\t\t\t\tnumberedList,\n\t\t\t\t\tmaskedLink,\n\t\t\t\t\tblockQuote,\n\t\t\t\t\tquote,\n\t\t\t\t});\n\t\t\t})\n\t\t\t.join(inlineCode ? '\\\\`' : '`');\n\t}\n\n\tlet res = text;\n\tif (escape) res = escapeEscape(res);\n\tif (inlineCode) res = escapeInlineCode(res);\n\tif (codeBlock) res = escapeCodeBlock(res);\n\tif (italic) res = escapeItalic(res);\n\tif (bold) res = escapeBold(res);\n\tif (underline) res = escapeUnderline(res);\n\tif (strikethrough) res = escapeStrikethrough(res);\n\tif (spoiler) res = escapeSpoiler(res);\n\tif (heading) res = escapeHeading(res);\n\tif (bulletedList) res = escapeBulletedList(res);\n\tif (numberedList) res = escapeNumberedList(res);\n\tif (maskedLink) res = escapeMaskedLink(res);\n\tif (quote) res = escapeQuote(res);\n\tif (blockQuote) res = escapeBlockQuote(res);\n\treturn res;\n}\n\n/**\n * Escapes code block markdown in a string.\n *\n * @param text - Content to escape\n */\nexport function escapeCodeBlock(text: string): string {\n\treturn text.replaceAll('```', '\\\\`\\\\`\\\\`');\n}\n\n/**\n * Escapes inline code markdown in a string.\n *\n * @param text - Content to escape\n */\nexport function escapeInlineCode(text: string): string {\n\treturn text.replaceAll(/(?<=^|[^`])``?(?=[^`]|$)/g, (match) => (match.length === 2 ? '\\\\`\\\\`' : '\\\\`'));\n}\n\n/**\n * Escapes italic markdown in a string.\n *\n * @param text - Content to escape\n */\nexport function escapeItalic(text: string): string {\n\tlet idx = 0;\n\tconst newText = text.replaceAll(\n\t\t/(?<=^|[^*])(?<!(?<!<)https?:\\/\\/\\S*|<[^\\s:]+:\\/[^\\s>]*)\\*([^*]|\\*\\*|$)/g,\n\t\t(_, match) => {\n\t\t\tif (match === '**') return ++idx % 2 ? `\\\\*${match}` : `${match}\\\\*`;\n\t\t\treturn `\\\\*${match}`;\n\t\t},\n\t);\n\tidx = 0;\n\treturn newText.replaceAll(\n\t\t/(?<=^|[^_])(?<!<a?:.+|(?<!<)https?:\\/\\/\\S*|<[^\\s:]:\\/[^\\s>]*)_(?!:\\d+>)([^_]|__|$)/g,\n\t\t(_, match) => {\n\t\t\tif (match === '__') return ++idx % 2 ? `\\\\_${match}` : `${match}\\\\_`;\n\t\t\treturn `\\\\_${match}`;\n\t\t},\n\t);\n}\n\n/**\n * Escapes bold markdown in a string.\n *\n * @param text - Content to escape\n */\nexport function escapeBold(text: string): string {\n\tlet idx = 0;\n\treturn text.replaceAll(/\\*\\*(\\*)?/g, (_, match) => {\n\t\tif (match) return ++idx % 2 ? `${match}\\\\*\\\\*` : `\\\\*\\\\*${match}`;\n\t\treturn '\\\\*\\\\*';\n\t});\n}\n\n/**\n * Escapes underline markdown in a string.\n *\n * @param text - Content to escape\n */\nexport function escapeUnderline(text: string): string {\n\tlet idx = 0;\n\treturn text.replaceAll(/(?<!<a?:.+|https?:\\/\\/\\S+)__(_)?(?!:\\d+>)/g, (_, match) => {\n\t\tif (match) return ++idx % 2 ? `${match}\\\\_\\\\_` : `\\\\_\\\\_${match}`;\n\t\treturn '\\\\_\\\\_';\n\t});\n}\n\n/**\n * Escapes strikethrough markdown in a string.\n *\n * @param text - Content to escape\n */\nexport function escapeStrikethrough(text: string): string {\n\treturn text.replaceAll('~~', '\\\\~\\\\~');\n}\n\n/**\n * Escapes spoiler markdown in a string.\n *\n * @param text - Content to escape\n */\nexport function escapeSpoiler(text: string): string {\n\treturn text.replaceAll('||', '\\\\|\\\\|');\n}\n\n/**\n * Escapes escape characters in a string.\n *\n * @param text - Content to escape\n */\nexport function escapeEscape(text: string): string {\n\treturn text.replaceAll('\\\\', '\\\\\\\\');\n}\n\n/**\n * Escapes heading characters in a string.\n *\n * @param text - Content to escape\n */\nexport function escapeHeading(text: string): string {\n\treturn text.replaceAll(/^( {0,2})([*-] )?( *)(#{1,3} )/gm, '$1$2$3\\\\$4');\n}\n\n/**\n * Escapes bulleted list characters in a string.\n *\n * @param text - Content to escape\n */\nexport function escapeBulletedList(text: string): string {\n\treturn text.replaceAll(/^( *)([*-])( +)/gm, '$1\\\\$2$3');\n}\n\n/**\n * Escapes numbered list characters in a string.\n *\n * @param text - Content to escape\n */\nexport function escapeNumberedList(text: string): string {\n\treturn text.replaceAll(/^( *\\d+)\\./gm, '$1\\\\.');\n}\n\n/**\n * Escapes masked link characters in a string.\n *\n * @param text - Content to escape\n */\nexport function escapeMaskedLink(text: string): string {\n\treturn text.replaceAll(/\\[.+]\\(.+\\)/gm, '\\\\$&');\n}\n\n/**\n * Escapes quote characters in a string.\n *\n * @param text - Content to escape\n */\nexport function escapeQuote(text: string): string {\n\treturn text.replaceAll(/^(\\s*)>(\\s+)/gm, '$1\\\\>$2');\n}\n\n/**\n * Escapes block quote characters in a string.\n *\n * @param text - Content to escape\n */\nexport function escapeBlockQuote(text: string): string {\n\treturn text.replaceAll(/^(\\s*)>>>(\\s+)/gm, '$1\\\\>>>$2');\n}\n"
  },
  {
    "path": "packages/formatters/src/formatters.ts",
    "content": "import type { Snowflake } from 'discord-api-types/globals';\n\n/**\n * Wraps the content inside a code block with no language.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @param content - The content to wrap\n */\nexport function codeBlock<Content extends string>(content: Content): `\\`\\`\\`\\n${Content}\\n\\`\\`\\``;\n\n/**\n * Wraps the content inside a code block with the specified language.\n *\n * @typeParam Language - This is inferred by the supplied language\n * @typeParam Content - This is inferred by the supplied content\n * @param language - The language for the code block\n * @param content - The content to wrap\n */\nexport function codeBlock<Language extends string, Content extends string>(\n\tlanguage: Language,\n\tcontent: Content,\n): `\\`\\`\\`${Language}\\n${Content}\\n\\`\\`\\``;\n\nexport function codeBlock(language: string, content?: string): string {\n\treturn content === undefined ? `\\`\\`\\`\\n${language}\\n\\`\\`\\`` : `\\`\\`\\`${language}\\n${content}\\n\\`\\`\\``;\n}\n\n/**\n * Wraps the content inside \\`backticks\\` which formats it as inline code.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @param content - The content to wrap\n */\nexport function inlineCode<Content extends string>(content: Content): `\\`${Content}\\`` {\n\treturn `\\`${content}\\``;\n}\n\n/**\n * Formats the content into italic text.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @param content - The content to wrap\n */\nexport function italic<Content extends string>(content: Content): `_${Content}_` {\n\treturn `_${content}_`;\n}\n\n/**\n * Formats the content into bold text.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @param content - The content to wrap\n */\nexport function bold<Content extends string>(content: Content): `**${Content}**` {\n\treturn `**${content}**`;\n}\n\n/**\n * Formats the content into underlined text.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @param content - The content to wrap\n */\nexport function underline<Content extends string>(content: Content): `__${Content}__` {\n\treturn `__${content}__`;\n}\n\n/**\n * Formats the content into strike-through text.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @param content - The content to wrap\n */\nexport function strikethrough<Content extends string>(content: Content): `~~${Content}~~` {\n\treturn `~~${content}~~`;\n}\n\n/**\n * Formats the content into a quote.\n *\n * @remarks This needs to be at the start of the line for Discord to format it.\n * @typeParam Content - This is inferred by the supplied content\n * @param content - The content to wrap\n */\nexport function quote<Content extends string>(content: Content): `> ${Content}` {\n\treturn `> ${content}`;\n}\n\n/**\n * Formats the content into a block quote.\n *\n * @remarks This needs to be at the start of the line for Discord to format it.\n * @typeParam Content - This is inferred by the supplied content\n * @param content - The content to wrap\n */\nexport function blockQuote<Content extends string>(content: Content): `>>> ${Content}` {\n\treturn `>>> ${content}`;\n}\n\n/**\n * Wraps the URL into `<>` which stops it from embedding.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @param url - The URL to wrap\n */\nexport function hideLinkEmbed<Content extends string>(url: Content): `<${Content}>`;\n\n/**\n * Wraps the URL into `<>` which stops it from embedding.\n *\n * @param url - The URL to wrap\n */\nexport function hideLinkEmbed(url: URL): `<${string}>`;\n\nexport function hideLinkEmbed(url: URL | string) {\n\treturn `<${url}>`;\n}\n\n/**\n * Formats the content and the URL into a masked URL.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @param content - The content to display\n * @param url - The URL the content links to\n */\nexport function hyperlink<Content extends string>(content: Content, url: URL): `[${Content}](${string})`;\n\n/**\n * Formats the content and the URL into a masked URL.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @typeParam Url - This is inferred by the supplied URL\n * @param content - The content to display\n * @param url - The URL the content links to\n */\nexport function hyperlink<Content extends string, Url extends string>(\n\tcontent: Content,\n\turl: Url,\n): `[${Content}](${Url})`;\n\n/**\n * Formats the content and the URL into a masked URL with a custom tooltip.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @typeParam Title - This is inferred by the supplied title\n * @param content - The content to display\n * @param url - The URL the content links to\n * @param title - The title shown when hovering on the masked link\n */\nexport function hyperlink<Content extends string, Title extends string>(\n\tcontent: Content,\n\turl: URL,\n\ttitle: Title,\n): `[${Content}](${string} \"${Title}\")`;\n\n/**\n * Formats the content and the URL into a masked URL with a custom tooltip.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @typeParam Url - This is inferred by the supplied URL\n * @typeParam Title - This is inferred by the supplied title\n * @param content - The content to display\n * @param url - The URL the content links to\n * @param title - The title shown when hovering on the masked link\n */\nexport function hyperlink<Content extends string, Url extends string, Title extends string>(\n\tcontent: Content,\n\turl: Url,\n\ttitle: Title,\n): `[${Content}](${Url} \"${Title}\")`;\n\nexport function hyperlink(content: string, url: URL | string, title?: string) {\n\treturn title ? `[${content}](${url} \"${title}\")` : `[${content}](${url})`;\n}\n\n/**\n * Formats the content into a spoiler.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @param content - The content to wrap\n */\nexport function spoiler<Content extends string>(content: Content): `||${Content}||` {\n\treturn `||${content}||`;\n}\n\n/**\n * Formats a user id into a user mention.\n *\n * @typeParam UserId - This is inferred by the supplied user id\n * @param userId - The user id to format\n */\nexport function userMention<UserId extends Snowflake>(userId: UserId): `<@${UserId}>` {\n\treturn `<@${userId}>`;\n}\n\n/**\n * Formats a channel id into a channel mention.\n *\n * @typeParam ChannelId - This is inferred by the supplied channel id\n * @param channelId - The channel id to format\n */\nexport function channelMention<ChannelId extends Snowflake>(channelId: ChannelId): `<#${ChannelId}>` {\n\treturn `<#${channelId}>`;\n}\n\n/**\n * Formats a role id into a role mention.\n *\n * @typeParam RoleId - This is inferred by the supplied role id\n * @param roleId - The role id to format\n */\nexport function roleMention<RoleId extends Snowflake>(roleId: RoleId): `<@&${RoleId}>` {\n\treturn `<@&${roleId}>`;\n}\n\n/**\n * Formats a role id into a linked role mention.\n *\n * @typeParam RoleId - This is inferred by the supplied role id\n * @param roleId - The role id to format\n */\nexport function linkedRoleMention<RoleId extends Snowflake>(roleId: RoleId): `<id:linked-roles:${RoleId}>` {\n\treturn `<id:linked-roles:${roleId}>`;\n}\n\n/**\n * Formats an application command name and id into an application command mention.\n *\n * @typeParam CommandId - This is inferred by the supplied command id\n * @typeParam CommandName - This is inferred by the supplied command name\n * @param commandId - The application command id to format\n * @param commandName - The application command name to format\n */\nexport function chatInputApplicationCommandMention<CommandId extends Snowflake, CommandName extends string>(\n\tcommandId: CommandId,\n\tcommandName: CommandName,\n): `</${CommandName}:${CommandId}>`;\n\n/**\n * Formats an application command name, subcommand name, and id into an application command mention.\n *\n * @typeParam CommandId - This is inferred by the supplied command id\n * @typeParam CommandName - This is inferred by the supplied command name\n * @typeParam SubcommandName - This is inferred by the supplied subcommand name\n * @param commandId - The application command id to format\n * @param commandName - The application command name to format\n * @param subcommandName - The subcommand name to format\n */\nexport function chatInputApplicationCommandMention<\n\tCommandId extends Snowflake,\n\tCommandName extends string,\n\tSubcommandName extends string,\n>(\n\tcommandId: CommandId,\n\tcommandName: CommandName,\n\tsubcommandName: SubcommandName,\n): `</${CommandName} ${SubcommandName}:${CommandId}>`;\n\n/**\n * Formats an application command name, subcommand group name, subcommand name, and id into an application command mention.\n *\n * @typeParam CommandId - This is inferred by the supplied command id\n * @typeParam CommandName - This is inferred by the supplied command name\n * @typeParam SubcommandName - This is inferred by the supplied subcommand name\n * @typeParam SubcommandGroupName - This is inferred by the supplied subcommand group name\n * @param commandId - The application command id to format\n * @param commandName - The application command name to format\n * @param subcommandName - The subcommand name to format\n * @param subcommandGroupName - The subcommand group name to format\n */\nexport function chatInputApplicationCommandMention<\n\tCommandId extends Snowflake,\n\tCommandName extends string,\n\tSubcommandName extends string,\n\tSubcommandGroupName extends string,\n>(\n\tcommandId: CommandId,\n\tcommandName: CommandName,\n\tsubcommandName: SubcommandName,\n\tsubcommandGroupName: SubcommandGroupName,\n): `</${CommandName} ${SubcommandGroupName} ${SubcommandName}:${CommandId}>`;\n\nexport function chatInputApplicationCommandMention<\n\tCommandId extends Snowflake,\n\tCommandName extends string,\n\tSubcommandName extends string,\n\tSubcommandGroupName extends string,\n>(\n\tcommandId: CommandId,\n\tcommandName: CommandName,\n\tsubcommandName?: SubcommandName,\n\tsubcommandGroupName?: SubcommandGroupName,\n):\n\t| `</${CommandName} ${SubcommandGroupName} ${SubcommandName}:${CommandId}>`\n\t| `</${CommandName} ${SubcommandName}:${CommandId}>`\n\t| `</${CommandName}:${CommandId}>` {\n\tif (subcommandGroupName !== undefined && subcommandName !== undefined) {\n\t\treturn `</${commandName} ${subcommandGroupName} ${subcommandName}:${commandId}>`;\n\t}\n\n\tif (subcommandName !== undefined) {\n\t\treturn `</${commandName} ${subcommandName}:${commandId}>`;\n\t}\n\n\treturn `</${commandName}:${commandId}>`;\n}\n\n/**\n * Formats a non-animated emoji id into a fully qualified emoji identifier.\n *\n * @typeParam EmojiId - This is inferred by the supplied emoji id\n * @param emojiId - The emoji id to format\n */\nexport function formatEmoji<EmojiId extends Snowflake>(emojiId: EmojiId, animated?: false): `<:emoji:${EmojiId}>`;\n\n/**\n * Formats an animated emoji id into a fully qualified emoji identifier.\n *\n * @typeParam EmojiId - This is inferred by the supplied emoji id\n * @param emojiId - The emoji id to format\n * @param animated - Whether the emoji is animated\n */\nexport function formatEmoji<EmojiId extends Snowflake>(emojiId: EmojiId, animated?: true): `<a:emoji:${EmojiId}>`;\n\n/**\n * Formats an emoji id into a fully qualified emoji identifier.\n *\n * @typeParam EmojiId - This is inferred by the supplied emoji id\n * @param emojiId - The emoji id to format\n * @param animated - Whether the emoji is animated\n */\nexport function formatEmoji<EmojiId extends Snowflake>(\n\temojiId: EmojiId,\n\tanimated?: boolean,\n): `<:emoji:${EmojiId}>` | `<a:emoji:${EmojiId}>`;\n\n/**\n * Formats a non-animated emoji id and name into a fully qualified emoji identifier.\n *\n * @typeParam EmojiId - This is inferred by the supplied emoji id\n * @typeParam EmojiName - This is inferred by the supplied name\n * @param options - The options for formatting an emoji\n */\nexport function formatEmoji<EmojiId extends Snowflake, EmojiName extends string>(\n\toptions: FormatEmojiOptions<EmojiId, EmojiName> & { animated: true },\n): `<a:${EmojiName}:${EmojiId}>`;\n\n/**\n * Formats an animated emoji id and name into a fully qualified emoji identifier.\n *\n * @typeParam EmojiId - This is inferred by the supplied emoji id\n * @typeParam EmojiName - This is inferred by the supplied name\n * @param options - The options for formatting an emoji\n */\nexport function formatEmoji<EmojiId extends Snowflake, EmojiName extends string>(\n\toptions: FormatEmojiOptions<EmojiId, EmojiName> & { animated?: false },\n): `<:${EmojiName}:${EmojiId}>`;\n\n/**\n * Formats an emoji id and name into a fully qualified emoji identifier.\n *\n * @typeParam EmojiId - This is inferred by the supplied emoji id\n * @typeParam EmojiName - This is inferred by the supplied emoji name\n * @param options - The options for formatting an emoji\n */\nexport function formatEmoji<EmojiId extends Snowflake, EmojiName extends string>(\n\toptions: FormatEmojiOptions<EmojiId, EmojiName>,\n): `<:${EmojiName}:${EmojiId}>` | `<a:${EmojiName}:${EmojiId}>`;\n\nexport function formatEmoji<EmojiId extends Snowflake, EmojiName extends string>(\n\temojiIdOrOptions: EmojiId | FormatEmojiOptions<EmojiId, EmojiName>,\n\tanimated?: boolean,\n): `<:${string}:${EmojiId}>` | `<a:${string}:${EmojiId}>` {\n\tconst options =\n\t\ttypeof emojiIdOrOptions === 'string'\n\t\t\t? {\n\t\t\t\t\tid: emojiIdOrOptions,\n\t\t\t\t\tanimated: animated ?? false,\n\t\t\t\t}\n\t\t\t: emojiIdOrOptions;\n\n\tconst { id, animated: isAnimated, name: emojiName } = options;\n\n\treturn `<${isAnimated ? 'a' : ''}:${emojiName ?? 'emoji'}:${id}>`;\n}\n\n/**\n * The options for formatting an emoji.\n *\n * @typeParam EmojiId - This is inferred by the supplied emoji id\n * @typeParam EmojiName - This is inferred by the supplied emoji name\n */\nexport interface FormatEmojiOptions<EmojiId extends Snowflake, EmojiName extends string> {\n\t/**\n\t * Whether the emoji is animated\n\t */\n\tanimated?: boolean;\n\t/**\n\t * The emoji id to format\n\t */\n\tid: EmojiId;\n\t/**\n\t * The name of the emoji\n\t */\n\tname?: EmojiName;\n}\n\n/**\n * Formats a channel link for a direct message channel.\n *\n * @typeParam ChannelId - This is inferred by the supplied channel id\n * @param channelId - The channel's id\n */\nexport function channelLink<ChannelId extends Snowflake>(\n\tchannelId: ChannelId,\n): `https://discord.com/channels/@me/${ChannelId}`;\n\n/**\n * Formats a channel link for a guild channel.\n *\n * @typeParam ChannelId - This is inferred by the supplied channel id\n * @typeParam GuildId - This is inferred by the supplied guild id\n * @param channelId - The channel's id\n * @param guildId - The guild's id\n */\nexport function channelLink<ChannelId extends Snowflake, GuildId extends Snowflake>(\n\tchannelId: ChannelId,\n\tguildId: GuildId,\n): `https://discord.com/channels/${GuildId}/${ChannelId}`;\n\nexport function channelLink<ChannelId extends Snowflake, GuildId extends Snowflake>(\n\tchannelId: ChannelId,\n\tguildId?: GuildId,\n): `https://discord.com/channels/@me/${ChannelId}` | `https://discord.com/channels/${GuildId}/${ChannelId}` {\n\treturn `https://discord.com/channels/${guildId ?? '@me'}/${channelId}`;\n}\n\n/**\n * Formats a message link for a direct message channel.\n *\n * @typeParam ChannelId - This is inferred by the supplied channel id\n * @typeParam MessageId - This is inferred by the supplied message id\n * @param channelId - The channel's id\n * @param messageId - The message's id\n */\nexport function messageLink<ChannelId extends Snowflake, MessageId extends Snowflake>(\n\tchannelId: ChannelId,\n\tmessageId: MessageId,\n): `https://discord.com/channels/@me/${ChannelId}/${MessageId}`;\n\n/**\n * Formats a message link for a guild channel.\n *\n * @typeParam ChannelId - This is inferred by the supplied channel id\n * @typeParam MessageId - This is inferred by the supplied message id\n * @typeParam GuildId - This is inferred by the supplied guild id\n * @param channelId - The channel's id\n * @param messageId - The message's id\n * @param guildId - The guild's id\n */\nexport function messageLink<ChannelId extends Snowflake, MessageId extends Snowflake, GuildId extends Snowflake>(\n\tchannelId: ChannelId,\n\tmessageId: MessageId,\n\tguildId: GuildId,\n): `https://discord.com/channels/${GuildId}/${ChannelId}/${MessageId}`;\n\nexport function messageLink<ChannelId extends Snowflake, MessageId extends Snowflake, GuildId extends Snowflake>(\n\tchannelId: ChannelId,\n\tmessageId: MessageId,\n\tguildId?: GuildId,\n):\n\t| `https://discord.com/channels/@me/${ChannelId}/${MessageId}`\n\t| `https://discord.com/channels/${GuildId}/${ChannelId}/${MessageId}` {\n\treturn `${guildId === undefined ? channelLink(channelId) : channelLink(channelId, guildId)}/${messageId}`;\n}\n\n/**\n * The heading levels for expanded markdown.\n */\nexport enum HeadingLevel {\n\t/**\n\t * The first heading level.\n\t */\n\tOne = 1,\n\t/**\n\t * The second heading level.\n\t */\n\tTwo,\n\t/**\n\t * The third heading level.\n\t */\n\tThree,\n}\n\n/**\n * Formats the content into a heading level.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @param content - The content to wrap\n * @param level - The heading level\n */\nexport function heading<Content extends string>(content: Content, level?: HeadingLevel.One): `# ${Content}`;\n\n/**\n * Formats the content into a heading level.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @param content - The content to wrap\n * @param level - The heading level\n */\nexport function heading<Content extends string>(content: Content, level: HeadingLevel.Two): `## ${Content}`;\n\n/**\n * Formats the content into a heading level.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @param content - The content to wrap\n * @param level - The heading level\n */\nexport function heading<Content extends string>(content: Content, level: HeadingLevel.Three): `### ${Content}`;\n\nexport function heading(content: string, level?: HeadingLevel) {\n\t// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check\n\tswitch (level) {\n\t\tcase HeadingLevel.Three:\n\t\t\treturn `### ${content}`;\n\t\tcase HeadingLevel.Two:\n\t\t\treturn `## ${content}`;\n\t\tdefault:\n\t\t\treturn `# ${content}`;\n\t}\n}\n\n/**\n * A type that recursively traverses into arrays.\n */\nexport type RecursiveArray<ItemType> = readonly (ItemType | RecursiveArray<ItemType>)[];\n\n/**\n * Callback function for list formatters.\n *\n * @internal\n */\nfunction listCallback(element: RecursiveArray<string>, startNumber?: number, depth = 0): string {\n\tif (Array.isArray(element)) {\n\t\treturn element.map((element) => listCallback(element, startNumber, depth + 1)).join('\\n');\n\t}\n\n\treturn `${'  '.repeat(depth - 1)}${startNumber ? `${startNumber}.` : '-'} ${element}`;\n}\n\n/**\n * Formats the elements in the array to an ordered list.\n *\n * @param list - The array of elements to list\n * @param startNumber - The starting number for the list\n */\nexport function orderedList(list: RecursiveArray<string>, startNumber = 1): string {\n\treturn listCallback(list, Math.max(startNumber, 1));\n}\n\n/**\n * Formats the elements in the array to an unordered list.\n *\n * @param list - The array of elements to list\n */\nexport function unorderedList(list: RecursiveArray<string>): string {\n\treturn listCallback(list);\n}\n\n/**\n * Formats the content into a subtext.\n *\n * @typeParam Content - This is inferred by the supplied content\n * @param content - The content to wrap\n */\nexport function subtext<Content extends string>(content: Content): `-# ${Content}` {\n\treturn `-# ${content}`;\n}\n\n/**\n * Formats a date into a short date-time string.\n *\n * @param date - The date to format. Defaults to the current time\n */\nexport function time(date?: Date): `<t:${bigint}>`;\n\n/**\n * Formats a date given a format style.\n *\n * @typeParam Style - This is inferred by the supplied {@link TimestampStylesString}\n * @param date - The date to format\n * @param style - The style to use\n */\nexport function time<Style extends TimestampStylesString>(date: Date, style: Style): `<t:${bigint}:${Style}>`;\n\n/**\n * Formats the given timestamp into a short date-time string.\n *\n * @typeParam Seconds - This is inferred by the supplied timestamp\n * @param seconds - A Unix timestamp in seconds\n */\nexport function time<Seconds extends number>(seconds: Seconds): `<t:${Seconds}>`;\n\n/**\n * Formats the given timestamp into a short date-time string.\n *\n * @typeParam Seconds - This is inferred by the supplied timestamp\n * @typeParam Style - This is inferred by the supplied {@link TimestampStylesString}\n * @param seconds - A Unix timestamp in seconds\n * @param style - The style to use\n */\nexport function time<Seconds extends number, Style extends TimestampStylesString>(\n\tseconds: Seconds,\n\tstyle: Style,\n): `<t:${Seconds}:${Style}>`;\n\nexport function time(timeOrSeconds?: Date | number, style?: TimestampStylesString): string {\n\tif (typeof timeOrSeconds !== 'number') {\n\t\t// eslint-disable-next-line no-param-reassign\n\t\ttimeOrSeconds = Math.floor((timeOrSeconds?.getTime() ?? Date.now()) / 1_000);\n\t}\n\n\treturn typeof style === 'string' ? `<t:${timeOrSeconds}:${style}>` : `<t:${timeOrSeconds}>`;\n}\n\n/**\n * Formats an application directory link.\n *\n * @typeParam ApplicationId - This is inferred by the supplied application id\n * @param applicationId - The application id\n */\nexport function applicationDirectory<ApplicationId extends Snowflake>(\n\tapplicationId: ApplicationId,\n): `https://discord.com/application-directory/${ApplicationId}/store`;\n\n/**\n * Formats an application directory SKU link.\n *\n * @typeParam ApplicationId - This is inferred by the supplied application id\n * @typeParam SKUId - This is inferred by the supplied SKU id\n * @param applicationId - The application id\n * @param skuId - The SKU id\n */\nexport function applicationDirectory<ApplicationId extends Snowflake, SKUId extends Snowflake>(\n\tapplicationId: ApplicationId,\n\tskuId: SKUId,\n): `https://discord.com/application-directory/${ApplicationId}/store/${SKUId}`;\n\nexport function applicationDirectory<ApplicationId extends Snowflake, SKUId extends Snowflake>(\n\tapplicationId: ApplicationId,\n\tskuId?: SKUId,\n):\n\t| `https://discord.com/application-directory/${ApplicationId}/store/${SKUId}`\n\t| `https://discord.com/application-directory/${ApplicationId}/store` {\n\tconst url = `https://discord.com/application-directory/${applicationId}/store` as const;\n\treturn skuId ? `${url}/${skuId}` : url;\n}\n\n/**\n * Formats an email address into an email mention.\n *\n * @typeParam Email - This is inferred by the supplied email address\n * @param email - The email address to format\n */\nexport function email<Email extends string>(email: Email): `<${Email}>`;\n\n/**\n * Formats an email address and headers into an email mention.\n *\n * @typeParam Email - This is inferred by the supplied email address\n * @param email - The email address to format\n * @param headers - Optional headers to include in the email mention\n */\nexport function email<Email extends string>(\n\temail: Email,\n\theaders: Record<string, string | readonly string[]> | undefined,\n): `<${Email}?${string}>`;\n\n/**\n * Formats an email address into an email mention.\n *\n * @typeParam Email - This is inferred by the supplied email address\n * @param email - The email address to format\n * @param headers - Optional headers to include in the email mention\n */\nexport function email<Email extends string>(email: Email, headers?: Record<string, string | readonly string[]>) {\n\tif (headers) {\n\t\tconst searchParams = new URLSearchParams(\n\t\t\tObject.fromEntries(Object.entries(headers).map(([key, value]) => [key.toLowerCase(), value])),\n\t\t);\n\n\t\treturn `<${email}?${searchParams.toString()}>` as const;\n\t}\n\n\treturn `<${email}>` as const;\n}\n\n/**\n * Formats a phone number into a phone number mention.\n *\n * @typeParam PhoneNumber - This is inferred by the supplied phone number\n * @param phoneNumber - The phone number to format. Must start with a `+` sign.\n */\nexport function phoneNumber<PhoneNumber extends `+${string}`>(phoneNumber: PhoneNumber) {\n\tif (!phoneNumber.startsWith('+')) {\n\t\tthrow new Error('Phone number must start with a \"+\" sign.');\n\t}\n\n\treturn `<${phoneNumber}>` as const;\n}\n\n/**\n * The {@link https://discord.com/developers/docs/reference#message-formatting-timestamp-styles | message formatting timestamp styles}\n * supported by Discord.\n */\nexport const TimestampStyles = {\n\t/**\n\t * Short time format, consisting of hours and minutes.\n\t *\n\t * @example `16:20`\n\t */\n\tShortTime: 't',\n\n\t/**\n\t * Medium time format, consisting of hours, minutes, and seconds.\n\t *\n\t * @example `16:20:30`\n\t */\n\tMediumTime: 'T',\n\n\t/**\n\t * Short date format, consisting of day, month, and year.\n\t *\n\t * @example `20/04/2021`\n\t */\n\tShortDate: 'd',\n\n\t/**\n\t * Long date format, consisting of day, month, and year.\n\t *\n\t * @example `April 20, 2021`\n\t */\n\tLongDate: 'D',\n\n\t/**\n\t * Long date-short time format, consisting of long date and short time.\n\t *\n\t * @example `April 20, 2021 at 16:20`\n\t */\n\tLongDateShortTime: 'f',\n\n\t/**\n\t * Full date-short time format, consisting of full date and short time.\n\t *\n\t * @example `Tuesday, April 20, 2021 at 16:20`\n\t */\n\tFullDateShortTime: 'F',\n\n\t/**\n\t * Short date, short time format, consisting of short date and short time.\n\t *\n\t * @example `20/04/2021, 16:20`\n\t */\n\tShortDateShortTime: 's',\n\n\t/**\n\t * Short date, medium time format, consisting of short date and medium time.\n\t *\n\t * @example `20/04/2021, 16:20:30`\n\t */\n\tShortDateMediumTime: 'S',\n\n\t/**\n\t * Relative time format, consisting of a relative duration format.\n\t *\n\t * @example `2 months ago`\n\t */\n\tRelativeTime: 'R',\n} as const satisfies Record<string, string>;\n\n/**\n * The possible {@link TimestampStyles} values.\n */\nexport type TimestampStylesString = (typeof TimestampStyles)[keyof typeof TimestampStyles];\n\n/**\n * All the available faces from Discord's native slash commands.\n */\nexport enum Faces {\n\t/**\n\t * `¯\\_(ツ)_/¯`\n\t */\n\tShrug = '¯\\\\_(ツ)_/¯',\n\n\t/**\n\t * `(╯°□°)╯︵ ┻━┻`\n\t */\n\tTableflip = '(╯°□°)╯︵ ┻━┻',\n\n\t/**\n\t * `┬─┬ノ( º _ ºノ)`\n\t */\n\tUnflip = '┬─┬ノ( º _ ºノ)',\n}\n\n/**\n * All the available guild navigation mentions.\n */\nexport enum GuildNavigationMentions {\n\t/**\n\t * Browse Channels tab.\n\t */\n\tBrowse = '<id:browse>',\n\t/**\n\t * Customize tab with the server's {@link https://discord.com/developers/docs/resources/guild#guild-onboarding-object | onboarding prompts}.\n\t */\n\tCustomize = '<id:customize>',\n\t/**\n\t * {@link https://support.discord.com/hc/articles/13497665141655 | Server Guide} tab.\n\t */\n\tGuide = '<id:guide>',\n\t/**\n\t * {@link https://support.discord.com/hc/articles/10388356626711 | Linked Roles} tab.\n\t */\n\tLinkedRoles = '<id:linked-roles>',\n}\n"
  },
  {
    "path": "packages/formatters/src/index.ts",
    "content": "export * from './escapers.js';\nexport * from './formatters.js';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/formatters#readme | @discordjs/formatters} version\n * that you are currently using.\n *\n * @privateRemarks This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild.\n */\nexport const version = '[VI]{{inject}}[/VI]' as string;\n"
  },
  {
    "path": "packages/formatters/tsconfig.docs.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.docs.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist-docs\"\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/formatters/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/formatters/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/formatters/tsconfig.test.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"noEmit\": true,\n\t\t\"skipLibCheck\": true\n\t},\n\t\"include\": [\"__tests__/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/formatters/tsup.config.ts",
    "content": "import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector';\nimport { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tesbuildPlugins: [esbuildPluginVersionInjector()],\n});\n"
  },
  {
    "path": "packages/next/.cliff-jumperrc.json",
    "content": "{\n\t\"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n\t\"name\": \"next\",\n\t\"org\": \"discordjs\",\n\t\"packagePath\": \"packages/next\",\n\t\"identifierBase\": false\n}\n"
  },
  {
    "path": "packages/next/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\ndist-docs\n\n# Docs\ndocs/**/*\n!docs/README.md\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/next/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/next/.prettierignore",
    "content": ".turbo\ncoverage\ndist\ndist-docs\ndocs/docs.api.json\nCHANGELOG.md\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/next/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/next/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/next/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/commits/main/packages/next\"><img alt=\"Last commit.\" src=\"https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fnext\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## Installation\n\n**Node.js 22.12.0 or newer is required.**\n\n```sh\nnpm install @discordjs/next\nyarn add @discordjs/next\npnpm add @discordjs/next\nbun add @discordjs/next\n```\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [npm][npm]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the\n[documentation][documentation].  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs/packages/next/stable\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/next\n[npm]: https://www.npmjs.com/package/@discordjs/next\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/next/__tests__/fake.test.ts",
    "content": "import { describe, test } from 'vitest';\n\ndescribe('@discordjs/next', () => {\n\ttest.todo('Should totally write tests');\n});\n"
  },
  {
    "path": "packages/next/api-extractor.json",
    "content": "{\n\t\"extends\": \"../../api-extractor.json\",\n\t\"docModel\": {\n\t\t\"projectFolderUrl\": \"https://github.com/discordjs/discord.js/tree/main/packages/next\"\n\t}\n\t// We probably don't want to generate docs here for these and instead link to the other modules\n\t// \"additionalEntryPoints\": [\n\t// \t{ \"modulePath\": \"discord-api-types\", \"filePath\": \"<projectFolder>/dist-docs/exports/discord-api-types.d.ts\" },\n\t// \t{ \"modulePath\": \"builders\", \"filePath\": \"<projectFolder>/dist-docs/exports/builders.d.ts\" },\n\t// \t{ \"modulePath\": \"collection\", \"filePath\": \"<projectFolder>/dist-docs/exports/collection.d.ts\" },\n\t// \t{ \"modulePath\": \"core\", \"filePath\": \"<projectFolder>/dist-docs/exports/core.d.ts\" },\n\t// \t{ \"modulePath\": \"formatters\", \"filePath\": \"<projectFolder>/dist-docs/exports/formatters.d.ts\" },\n\t// \t{ \"modulePath\": \"rest\", \"filePath\": \"<projectFolder>/dist-docs/exports/rest.d.ts\" },\n\t// \t{ \"modulePath\": \"util\", \"filePath\": \"<projectFolder>/dist-docs/exports/util.d.ts\" },\n\t// \t{ \"modulePath\": \"ws\", \"filePath\": \"<projectFolder>/dist-docs/exports/ws.d.ts\" }\n\t// ],\n\t// \"bundledPackages\": [\n\t// \t\"discord-api-types\",\n\t// \t\"@discordjs/builders\",\n\t// \t\"@discordjs/collection\",\n\t// \t\"@discordjs/core\",\n\t// \t\"@discordjs/formatters\",\n\t// \t\"@discordjs/rest\",\n\t// \t\"@discordjs/util\",\n\t// \t\"@discordjs/ws\"\n\t// ]\n}\n"
  },
  {
    "path": "packages/next/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t\t{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length %}\\\n\t\\n### New Contributors\\n\n\t{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\\\n\t\t* @{{ contributor.username }} made their first contribution in #{{ contributor.pr_number }}\n\t{% endfor %}\\\n{% endif %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"@discordjs/next@[0-9]*\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/next/docs/README.md",
    "content": "## [View the documentation here.](https://discord.js.org/docs/packages/next/main)\n"
  },
  {
    "path": "packages/next/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/next\",\n\t\"version\": \"0.1.0\",\n\t\"description\": \"A powerful TypeScript library for interacting with the Discord API\",\n\t\"scripts\": {\n\t\t\"test\": \"vitest run --config ../../vitest.config.ts\",\n\t\t\"build\": \"tsc --noEmit && tsup\",\n\t\t\"build:docs\": \"tsc -p tsconfig.docs.json\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src __tests__\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src __tests__\",\n\t\t\"docs\": \"pnpm run build:docs && api-extractor run --local --minify && generate-split-documentation\",\n\t\t\"prepack\": \"pnpm run build && pnpm run lint\",\n\t\t\"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/next/*'\",\n\t\t\"release\": \"cliff-jumper\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t}\n\t\t},\n\t\t\"./*\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/exports/*.d.ts\",\n\t\t\t\t\"default\": \"./dist/exports/*.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/exports/*.d.mts\",\n\t\t\t\t\"default\": \"./dist/exports/*.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"main\": \"./dist/index.js\",\n\t\"module\": \"./dist/index.mjs\",\n\t\"types\": \"./dist/index.d.ts\",\n\t\"directories\": {\n\t\t\"lib\": \"src\",\n\t\t\"test\": \"__tests__\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/next\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"@discordjs/builders\": \"workspace:^\",\n\t\t\"@discordjs/collection\": \"workspace:^\",\n\t\t\"@discordjs/core\": \"workspace:^\",\n\t\t\"@discordjs/formatters\": \"workspace:^\",\n\t\t\"@discordjs/rest\": \"workspace:^\",\n\t\t\"@discordjs/util\": \"workspace:^\",\n\t\t\"@discordjs/ws\": \"workspace:^\",\n\t\t\"discord-api-types\": \"^0.38.41\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@discordjs/api-extractor\": \"workspace:^\",\n\t\t\"@discordjs/scripts\": \"workspace:^\",\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@types/node\": \"^22.19.11\",\n\t\t\"@vitest/coverage-v8\": \"^4.0.18\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"esbuild-plugin-version-injector\": \"^1.2.1\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vitest\": \"^4.0.18\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/next/src/exports/builders.ts",
    "content": "export * from '@discordjs/builders';\n"
  },
  {
    "path": "packages/next/src/exports/collection.ts",
    "content": "export * from '@discordjs/collection';\n"
  },
  {
    "path": "packages/next/src/exports/core.ts",
    "content": "export * from '@discordjs/core';\n"
  },
  {
    "path": "packages/next/src/exports/discord-api-types.ts",
    "content": "export * from 'discord-api-types/v10';\n"
  },
  {
    "path": "packages/next/src/exports/formatters.ts",
    "content": "export * from '@discordjs/formatters';\n"
  },
  {
    "path": "packages/next/src/exports/rest.ts",
    "content": "export * from '@discordjs/rest';\n"
  },
  {
    "path": "packages/next/src/exports/util.ts",
    "content": "export * from '@discordjs/util';\n"
  },
  {
    "path": "packages/next/src/exports/ws.ts",
    "content": "export * from '@discordjs/ws';\n"
  },
  {
    "path": "packages/next/src/index.ts",
    "content": "/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/next#readme | @discordjs/next} version\n * that you are currently using.\n */\n// This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild\nexport const version = '[VI]{{inject}}[/VI]' as string;\n"
  },
  {
    "path": "packages/next/tsconfig.docs.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.docs.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist-docs\"\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/next/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/next/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/next/tsconfig.test.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"noEmit\": true,\n\t\t\"skipLibCheck\": true\n\t},\n\t\"include\": [\"__tests__/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/next/tsup.config.ts",
    "content": "import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector';\nimport { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tentry: ['src/index.ts', 'src/exports/*.ts'],\n\tesbuildPlugins: [esbuildPluginVersionInjector()],\n});\n"
  },
  {
    "path": "packages/proxy/.cliff-jumperrc.json",
    "content": "{\n\t\"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n\t\"name\": \"proxy\",\n\t\"org\": \"discordjs\",\n\t\"packagePath\": \"packages/proxy\",\n\t\"identifierBase\": false\n}\n"
  },
  {
    "path": "packages/proxy/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\ndist-docs\n\n# Docs\ndocs/**/*\n!docs/README.md\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/proxy/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/proxy/.prettierignore",
    "content": ".turbo\ncoverage\ndist\ndist-docs\ndocs/docs.api.json\nCHANGELOG.md\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/proxy/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/proxy/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n# [@discordjs/proxy@2.1.1](https://github.com/discordjs/discord.js/compare/@discordjs/proxy@2.1.0...@discordjs/proxy@2.1.1) - (2024-09-01)\n\n# [@discordjs/proxy@2.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/proxy@2.0.2...@discordjs/proxy@2.1.0) - (2024-05-04)\n\n## Bug Fixes\n\n- Anchor link for events ([0efd1be](https://github.com/discordjs/discord.js/commit/0efd1bea46fa2fc8bcd3dcfd0ac5cd608a0a7df0))\n- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))\n\n## Documentation\n\n- Split docs.api.json into multiple json files ([597340f](https://github.com/discordjs/discord.js/commit/597340f288437c35da8c703d9b621274de60d880))\n- Remove hyphen after `@returns` (#9989) ([e9ff991](https://github.com/discordjs/discord.js/commit/e9ff99101b9800f36839e6158d544c8ef5938d22))\n\n## Features\n\n- Local and preview detection ([79fbda3](https://github.com/discordjs/discord.js/commit/79fbda3aac6d4f0f8bfb193e797d09cbe331d315))\n\n## Refactor\n\n- Docs (#10126) ([18cce83](https://github.com/discordjs/discord.js/commit/18cce83d80598c430218775c53441b6b2ecdc776))\n\n# [@discordjs/proxy@2.0.2](https://github.com/discordjs/discord.js/compare/@discordjs/proxy@2.0.1...@discordjs/proxy@2.0.2) - (2023-11-12)\n\n## Bug Fixes\n\n- Forward x-audit-log-reason header (#9889) ([6a63c44](https://github.com/discordjs/discord.js/commit/6a63c441fe378ca6dd630ad05e29647903f898bc))\n\n## Documentation\n\n- **create-discord-bot:** Support bun in create-discord-bot (#9798) ([7157748](https://github.com/discordjs/discord.js/commit/7157748fe3a69265896adf0450cd3f37acbcf97b))\n\n# [@discordjs/proxy@2.0.1](https://github.com/discordjs/discord.js/compare/@discordjs/proxy@2.0.0...@discordjs/proxy@2.0.1) - (2023-08-17)\n\n## Documentation\n\n- Update Node.js requirement to 16.11.0 (#9764) ([188877c](https://github.com/discordjs/discord.js/commit/188877c50af70f0d5cffb246620fa277435c6ce6))\n\n# [@discordjs/proxy@2.0.0](https://github.com/discordjs/discord.js/compare/@discordjs/proxy@1.4.1...@discordjs/proxy@2.0.0) - (2023-07-31)\n\n## Refactor\n\n- **REST:** Remove double classing (#9722) ([8f4256d](https://github.com/discordjs/discord.js/commit/8f4256db8a52ac08359d0b3436f41b641ac4e382))\n  - **BREAKING CHANGE:** `REST` and `RequestManager` have been combined, most of the properties, methods, and events from both classes can now be found on `REST`\n  - **BREAKING CHANGE:** `REST#raw` has been removed in favor of `REST#queueRequest`\n  - **BREAKING CHANGE:** `REST#getAgent` has been removed in favor of `REST#agent`\n\n* chore: update for /rest changes\n- **rest:** Switch api to fetch-like and provide strategies (#9416) ([cdaa0a3](https://github.com/discordjs/discord.js/commit/cdaa0a36f586459f1e5ede868c4250c7da90455c))\n  - **BREAKING CHANGE:** NodeJS v18+ is required when using node due to the use of global `fetch`\n  - **BREAKING CHANGE:** The raw method of REST now returns a web compatible `Respone` object.\n  - **BREAKING CHANGE:** The `parseResponse` utility method has been updated to operate on a web compatible `Response` object.\n  - **BREAKING CHANGE:** Many underlying internals have changed, some of which were exported.\n  - **BREAKING CHANGE:** `DefaultRestOptions` used to contain a default `agent`, which is now set to `null` instead.\n\n# [@discordjs/proxy@1.4.1](https://github.com/discordjs/discord.js/compare/@discordjs/proxy@1.4.0...@discordjs/proxy@1.4.1) - (2023-05-01)\n\n## Bug Fixes\n\n- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2))\n\n## Documentation\n\n- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9))\n\n## Refactor\n\n- **proxy:** Rely on auth header instead (#9422) ([a49ed0a](https://github.com/discordjs/discord.js/commit/a49ed0a2d5934ad7af2e9cfbf7c5ccf171599591))\n\n# [@discordjs/proxy@1.4.0](https://github.com/discordjs/discord.js/compare/@discordjs/proxy@1.3.0...@discordjs/proxy@1.4.0) - (2023-04-01)\n\n## Bug Fixes\n\n- **scripts:** Accessing tsComment ([d8d5f31](https://github.com/discordjs/discord.js/commit/d8d5f31d3927fd1de62f1fa3a1a6e454243ad87b))\n\n## Features\n\n- **website:** Render syntax and mdx on the server (#9086) ([ee5169e](https://github.com/discordjs/discord.js/commit/ee5169e0aadd7bbfcd752aae614ec0f69602b68b))\n\n# [@discordjs/proxy@1.3.0](https://github.com/discordjs/discord.js/compare/@discordjs/proxy@1.2.1...@discordjs/proxy@1.3.0) - (2023-03-12)\n\n## Documentation\n\n- Fix typos (#9127) ([1ba1f23](https://github.com/discordjs/discord.js/commit/1ba1f238f04221ec890fc921678909b5b7d92c26))\n\n## Features\n\n- **website:** Add support for source file links (#9048) ([f6506e9](https://github.com/discordjs/discord.js/commit/f6506e99c496683ee0ab67db0726b105b929af38))\n\n# [@discordjs/proxy@1.2.1](https://github.com/discordjs/discord.js/compare/@discordjs/proxy@1.2.0...@discordjs/proxy@1.2.1) - (2022-11-25)\n\n## Bug Fixes\n\n- Pin @types/node version ([9d8179c](https://github.com/discordjs/discord.js/commit/9d8179c6a78e1c7f9976f852804055964d5385d4))\n\n# [@discordjs/proxy@1.2.0](https://github.com/discordjs/discord.js/compare/@discordjs/proxy@1.1.0...@discordjs/proxy@1.2.0) - (2022-10-07)\n\n## Bug Fixes\n\n- **proxyRequests:** Forward query parameters (#8691) ([f063625](https://github.com/discordjs/discord.js/commit/f063625836915b0fa3b0f0b89d073e877465dfd4))\n- Footer / sidebar / deprecation alert ([ba3e0ed](https://github.com/discordjs/discord.js/commit/ba3e0ed348258fe8e51eefb4aa7379a1230616a9))\n\n## Documentation\n\n- Change name (#8604) ([dd5a089](https://github.com/discordjs/discord.js/commit/dd5a08944c258a847fc4377f1d5e953264ab47d0))\n\n## Features\n\n- Web-components (#8715) ([0ac3e76](https://github.com/discordjs/discord.js/commit/0ac3e766bd9dbdeb106483fa4bb085d74de346a2))\n- Add `@discordjs/util` (#8591) ([b2ec865](https://github.com/discordjs/discord.js/commit/b2ec865765bf94181473864a627fb63ea8173fd3))\n\n## Refactor\n\n- Website components (#8600) ([c334157](https://github.com/discordjs/discord.js/commit/c3341570d983aea9ecc419979d5a01de658c9d67))\n- Use `eslint-config-neon` for packages. (#8579) ([edadb9f](https://github.com/discordjs/discord.js/commit/edadb9fe5dfd9ff51a3cfc9b25cb242d3f9f5241))\n\n# [@discordjs/proxy@1.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/proxy@1.0.1...@discordjs/proxy@1.1.0) - (2022-08-22)\n\n## Bug Fixes\n\n- **proxyRequests:** Typo in error message (#8537) ([dd44e8b](https://github.com/discordjs/discord.js/commit/dd44e8b6ec141e630af4543bd3babcce39aa2887))\n\n## Features\n\n- **website:** Show `constructor` information (#8540) ([e42fd16](https://github.com/discordjs/discord.js/commit/e42fd1636973b10dd7ed6fb4280ee1a4a8f82007))\n\n## Refactor\n\n- Docs design (#8487) ([4ab1d09](https://github.com/discordjs/discord.js/commit/4ab1d09997a18879a9eb9bda39df6f15aa22557e))\n\n# [@discordjs/proxy@1.0.1](https://github.com/discordjs/discord.js/tree/@discordjs/proxy@1.0.1) - (2022-07-27)\n\n## Bug Fixes\n\n- **proxy-container:** Proper deps (#8120) ([17867f9](https://github.com/discordjs/discord.js/commit/17867f9154d0dd16357f4ff29da641e23a33a9fa))\n- **proxy:** Add docs script ([a45bef4](https://github.com/discordjs/discord.js/commit/a45bef4cad77dac1a4138fd0d52b769ce09b5678))\n\n## Documentation\n\n- Add codecov coverage badge to readmes (#8226) ([f6db285](https://github.com/discordjs/discord.js/commit/f6db285c073898a749fe4591cbd4463d1896daf5))\n\n## Features\n\n- Codecov (#8219) ([f10f4cd](https://github.com/discordjs/discord.js/commit/f10f4cdcd88ca6be7ec735ed3a415ba13da83db0))\n- Proxy container (#8000) ([2681929](https://github.com/discordjs/discord.js/commit/2681929e4263032ad34a99ecb42465c320b271ba))\n- **docgen:** Update typedoc ([b3346f4](https://github.com/discordjs/discord.js/commit/b3346f4b9b3d4f96443506643d4631dc1c6d7b21))\n- Website (#8043) ([127931d](https://github.com/discordjs/discord.js/commit/127931d1df7a2a5c27923c2f2151dbf3824e50cc))\n- **docgen:** Typescript support ([3279b40](https://github.com/discordjs/discord.js/commit/3279b40912e6aa61507bedb7db15a2b8668de44b))\n- Docgen package (#8029) ([8b979c0](https://github.com/discordjs/discord.js/commit/8b979c0245c42fd824d8e98745ee869f5360fc86))\n- Use vitest instead of jest for more speed ([8d8e6c0](https://github.com/discordjs/discord.js/commit/8d8e6c03decd7352a2aa180f6e5bc1a13602539b))\n- Add scripts package for locally used scripts ([f2ae1f9](https://github.com/discordjs/discord.js/commit/f2ae1f9348bfd893332a9060f71a8a5f272a1b8b))\n- @discordjs/proxy (#7925) ([1ba2d2a](https://github.com/discordjs/discord.js/commit/1ba2d2a898613e5fcc119a97dce935f4db91162c))\n\n## Refactor\n\n- Move all the config files to root (#8033) ([769ea0b](https://github.com/discordjs/discord.js/commit/769ea0bfe78c4f1d413c6b397c604ffe91e39c6a))\n\n## Styling\n\n- Cleanup tests and tsup configs ([6b8ef20](https://github.com/discordjs/discord.js/commit/6b8ef20cb3af5b5cfd176dd0aa0a1a1e98551629))\n"
  },
  {
    "path": "packages/proxy/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2022 Noel Buechler\n   Copyright 2022 Denis Cristea\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/proxy/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/proxy\"><img src=\"https://img.shields.io/npm/v/@discordjs/proxy.svg?maxAge=3600\" alt=\"npm version\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/proxy\"><img src=\"https://img.shields.io/npm/dt/@discordjs/proxy.svg?maxAge=3600\" alt=\"npm downloads\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/commits/main/packages/proxy\"><img alt=\"Last commit.\" src=\"https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fproxy\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t\t<a href=\"https://codecov.io/gh/discordjs/discord.js\"><img src=\"https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=proxy\" alt=\"Code coverage\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## About\n\n`@discordjs/proxy` is a powerful wrapper around `@discordjs/rest` for running an HTTP proxy in front of Discord's API.\n\n## Installation\n\n**Node.js 22.12.0 or newer is required.**\n\n```sh\nnpm install @discordjs/proxy\nyarn add @discordjs/proxy\npnpm add @discordjs/proxy\nbun add @discordjs/proxy\n```\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Documentation][documentation]\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [npm][npm]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the\n[documentation][documentation].  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs/packages/proxy/stable\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/proxy\n[npm]: https://www.npmjs.com/package/@discordjs/proxy\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/proxy/__tests__/proxyRequests.test.ts",
    "content": "import { createServer } from 'node:http';\nimport { REST } from '@discordjs/rest';\nimport supertest from 'supertest';\nimport { MockAgent, setGlobalDispatcher, type Interceptable } from 'undici';\nimport type { MockInterceptor } from 'undici/types/mock-interceptor.js';\nimport { beforeEach, afterAll, afterEach, test, expect } from 'vitest';\nimport { proxyRequests } from '../src/index.js';\n\nlet mockAgent: MockAgent;\nlet mockPool: Interceptable;\n\nconst responseOptions: MockInterceptor.MockResponseOptions = {\n\theaders: {\n\t\t'content-type': 'application/json',\n\t},\n};\n\nconst api = new REST().setToken('A-Very-Fake-Token');\nconst server = createServer(proxyRequests(api));\n\nbeforeEach(() => {\n\tmockAgent = new MockAgent();\n\tmockAgent.disableNetConnect(); // prevent actual requests to Discord\n\tsetGlobalDispatcher(mockAgent); // enabled the mock client to intercept requests\n\n\tmockPool = mockAgent.get('https://discord.com');\n\tapi.setAgent(mockAgent);\n});\n\nafterEach(async () => {\n\tawait mockAgent.close();\n});\n\nafterAll(() => {\n\tserver.close();\n});\n\ntest('simple GET', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: '/api/v10/simpleGet',\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tdata: { test: true },\n\t\t\tstatusCode: 200,\n\t\t\tresponseOptions: {\n\t\t\t\t...responseOptions,\n\t\t\t\theaders: {\n\t\t\t\t\t...responseOptions.headers,\n\t\t\t\t\t'x-ratelimit-limit': '10',\n\t\t\t\t},\n\t\t\t},\n\t\t}));\n\n\tconst res = await supertest(server).get('/api/v10/simpleGet');\n\tconst headers = res.headers as Record<string, string>;\n\n\texpect(headers['content-type']).toEqual(expect.stringMatching(/^application\\/json/));\n\t// Ratelimit headers should be dropped\n\texpect(headers).not.toHaveProperty('x-ratelimit-limit');\n\texpect(res.statusCode).toEqual(200);\n\texpect(res.body).toStrictEqual({ test: true });\n});\n\ntest('failed request', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: '/api/v10/simpleGet',\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tdata: { code: 404, message: 'Not Found' },\n\t\t\tstatusCode: 404,\n\t\t\tresponseOptions,\n\t\t}));\n\n\tconst res = await supertest(server).get('/api/v10/simpleGet');\n\tconst headers = res.headers as Record<string, string>;\n\n\texpect(headers['content-type']).toEqual(expect.stringMatching(/^application\\/json/));\n\texpect(res.statusCode).toEqual(404);\n\texpect(res.body).toStrictEqual({ code: 404, message: 'Not Found' });\n});\n"
  },
  {
    "path": "packages/proxy/api-extractor.json",
    "content": "{\n\t\"extends\": \"../../api-extractor.json\",\n\t\"docModel\": {\n\t\t\"projectFolderUrl\": \"https://github.com/discordjs/discord.js/tree/main/packages/proxy\"\n\t}\n}\n"
  },
  {
    "path": "packages/proxy/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t\t{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length %}\\\n\t\\n### New Contributors\\n\n\t{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\\\n\t\t* @{{ contributor.username }} made their first contribution in #{{ contributor.pr_number }}\n\t{% endfor %}\\\n{% endif %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"@discordjs/proxy@[0-9]*\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/proxy/docs/README.md",
    "content": "## [View the documentation here.](https://discord.js.org/docs/packages/proxy/main)\n"
  },
  {
    "path": "packages/proxy/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/proxy\",\n\t\"version\": \"2.1.1\",\n\t\"description\": \"Tools for running an HTTP proxy for Discord's API\",\n\t\"scripts\": {\n\t\t\"test\": \"vitest run --config ../../vitest.config.ts\",\n\t\t\"build\": \"tsc --noEmit && tsup\",\n\t\t\"build:docs\": \"tsc -p tsconfig.docs.json\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src __tests__\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src __tests__\",\n\t\t\"fmt\": \"pnpm run format\",\n\t\t\"docs\": \"pnpm run build:docs && api-extractor run --local --minify && generate-split-documentation\",\n\t\t\"prepack\": \"pnpm run lint && pnpm run test && pnpm run build\",\n\t\t\"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/proxy/*'\",\n\t\t\"release\": \"cliff-jumper\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"main\": \"./dist/index.js\",\n\t\"module\": \"./dist/index.mjs\",\n\t\"types\": \"./dist/index.d.ts\",\n\t\"directories\": {\n\t\t\"lib\": \"src\",\n\t\t\"test\": \"__tests__\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"Amish Shah <amishshah.2k@gmail.com>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\",\n\t\t\"DD <didinele.dev@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"discord\",\n\t\t\"api\",\n\t\t\"rest\",\n\t\t\"proxy\",\n\t\t\"discordapp\",\n\t\t\"discordjs\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/proxy\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"@discordjs/rest\": \"workspace:^\",\n\t\t\"@discordjs/util\": \"workspace:^\",\n\t\t\"tslib\": \"^2.8.1\",\n\t\t\"undici\": \"7.22.0\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@discordjs/api-extractor\": \"workspace:^\",\n\t\t\"@discordjs/scripts\": \"workspace:^\",\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@types/node\": \"^22.19.11\",\n\t\t\"@types/supertest\": \"^6.0.3\",\n\t\t\"@vitest/coverage-v8\": \"^4.0.18\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"esbuild-plugin-version-injector\": \"^1.2.1\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"supertest\": \"^7.2.2\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vitest\": \"^4.0.18\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/proxy/src/handlers/proxyRequests.ts",
    "content": "import type { RequestMethod, REST, RouteLike } from '@discordjs/rest';\nimport { populateSuccessfulResponse, populateErrorResponse } from '../util/responseHelpers.js';\nimport type { RequestHandler } from '../util/util.js';\n\n/**\n * Creates an HTTP handler used to forward requests to Discord\n *\n * @param rest - REST instance to use for the requests\n */\nexport function proxyRequests(rest: REST): RequestHandler {\n\treturn async (req, res) => {\n\t\tconst { method, url } = req;\n\n\t\tif (!method || !url) {\n\t\t\tthrow new TypeError(\n\t\t\t\t'Invalid request. Missing method and/or url, implying that this is not a Server IncomingMessage',\n\t\t\t);\n\t\t}\n\n\t\t// The 2nd parameter is here so the URL constructor doesn't complain about an \"invalid url\" when the origin is missing\n\t\t// we don't actually care about the origin and the value passed is irrelevant\n\t\tconst parsedUrl = new URL(url, 'http://noop');\n\t\t// eslint-disable-next-line prefer-named-capture-group\n\t\tconst fullRoute = parsedUrl.pathname.replace(/^\\/api(\\/v\\d+)?/, '') as RouteLike;\n\n\t\tconst headers: Record<string, string> = {\n\t\t\t'Content-Type': req.headers['content-type']!,\n\t\t};\n\n\t\tif (req.headers.authorization) {\n\t\t\theaders.authorization = req.headers.authorization;\n\t\t}\n\n\t\tif (req.headers['x-audit-log-reason']) {\n\t\t\theaders['x-audit-log-reason'] = req.headers['x-audit-log-reason'] as string;\n\t\t}\n\n\t\ttry {\n\t\t\tconst discordResponse = await rest.queueRequest({\n\t\t\t\tbody: req,\n\t\t\t\tfullRoute,\n\t\t\t\t// This type cast is technically incorrect, but we want Discord to throw Method Not Allowed for us\n\t\t\t\tmethod: method as RequestMethod,\n\t\t\t\t// We forward the auth header anyway\n\t\t\t\tauth: false,\n\t\t\t\tpassThroughBody: true,\n\t\t\t\tquery: parsedUrl.searchParams,\n\t\t\t\theaders,\n\t\t\t});\n\n\t\t\tawait populateSuccessfulResponse(res, discordResponse);\n\t\t} catch (error) {\n\t\t\tconst knownError = populateErrorResponse(res, error);\n\t\t\tif (!knownError) {\n\t\t\t\t// Unclear if there's better course of action here for unknown errors.\n\t\t\t\t// Any web framework allows to pass in an error handler for something like this\n\t\t\t\t// at which point the user could dictate what to do with the error - otherwise we could just 500\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t} finally {\n\t\t\tres.end();\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "packages/proxy/src/index.ts",
    "content": "export * from './handlers/proxyRequests.js';\nexport * from './util/responseHelpers.js';\nexport type { RequestHandler } from './util/util.js';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/proxy#readme | @discordjs/proxy} version\n * that you are currently using.\n *\n * @privateRemarks This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild.\n */\nexport const version = '[VI]{{inject}}[/VI]' as string;\n"
  },
  {
    "path": "packages/proxy/src/util/responseHelpers.ts",
    "content": "import type { ServerResponse } from 'node:http';\nimport { Readable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\nimport { DiscordAPIError, HTTPError, RateLimitError, type ResponseLike } from '@discordjs/rest';\n\n/**\n * Populates a server response with the data from a Discord 2xx REST response\n *\n * @param res - The server response to populate\n * @param data - The data to populate the response with\n */\nexport async function populateSuccessfulResponse(res: ServerResponse, data: ResponseLike): Promise<void> {\n\tres.statusCode = data.status;\n\n\tfor (const [header, value] of data.headers) {\n\t\t// Strip ratelimit headers\n\t\tif (/^x-ratelimit/i.test(header)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tres.setHeader(header, value);\n\t}\n\n\tif (data.body) {\n\t\tawait pipeline(data.body instanceof Readable ? data.body : Readable.fromWeb(data.body), res);\n\t}\n}\n\n/**\n * Populates a server response with the data from a Discord non-2xx REST response that is NOT a 429\n *\n * @param res - The server response to populate\n * @param error - The error to populate the response with\n */\nexport function populateGeneralErrorResponse(res: ServerResponse, error: DiscordAPIError | HTTPError): void {\n\tres.statusCode = error.status;\n\n\tif ('rawError' in error) {\n\t\tres.setHeader('Content-Type', 'application/json');\n\t\tres.write(JSON.stringify(error.rawError));\n\t}\n}\n\n/**\n * Populates a server response with the data from a Discord 429 REST response\n *\n * @param res - The server response to populate\n * @param error - The error to populate the response with\n */\nexport function populateRatelimitErrorResponse(res: ServerResponse, error: RateLimitError): void {\n\tres.statusCode = 429;\n\tres.setHeader('Retry-After', error.timeToReset / 1_000);\n}\n\n/**\n * Populates a server response with data relevant for a timeout\n *\n * @param res - The sever response to populate\n */\nexport function populateAbortErrorResponse(res: ServerResponse): void {\n\tres.statusCode = 504;\n\tres.statusMessage = 'Upstream timed out';\n}\n\n/**\n * Tries to populate a server response from an error object\n *\n * @param res - The server response to populate\n * @param error - The error to check and use\n * @returns `true` if the error is known and the response object was populated, otherwise `false`\n */\nexport function populateErrorResponse(res: ServerResponse, error: unknown): boolean {\n\tif (error instanceof DiscordAPIError || error instanceof HTTPError) {\n\t\tpopulateGeneralErrorResponse(res, error);\n\t} else if (error instanceof RateLimitError) {\n\t\tpopulateRatelimitErrorResponse(res, error);\n\t} else if (error instanceof Error && error.name === 'AbortError') {\n\t\tpopulateAbortErrorResponse(res);\n\t} else {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n"
  },
  {
    "path": "packages/proxy/src/util/util.ts",
    "content": "import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { Awaitable } from '@discordjs/util';\n\n/**\n * Represents a simple HTTP request handler\n */\nexport type RequestHandler = (req: IncomingMessage, res: ServerResponse) => Awaitable<void>;\n"
  },
  {
    "path": "packages/proxy/tsconfig.docs.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.docs.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist-docs\"\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/proxy/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/proxy/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/proxy/tsconfig.test.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"noEmit\": true,\n\t\t\"skipLibCheck\": true\n\t},\n\t\"include\": [\"__tests__/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/proxy/tsup.config.ts",
    "content": "import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector';\nimport { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tesbuildPlugins: [esbuildPluginVersionInjector()],\n});\n"
  },
  {
    "path": "packages/rest/.cliff-jumperrc.json",
    "content": "{\n\t\"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n\t\"name\": \"rest\",\n\t\"org\": \"discordjs\",\n\t\"packagePath\": \"packages/rest\",\n\t\"identifierBase\": false\n}\n"
  },
  {
    "path": "packages/rest/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\ndist-docs\n\n# Docs\ndocs/**/*\n!docs/README.md\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/rest/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = {\n\t...require('../../.lintstagedrc.json'),\n\t'src/**.ts': 'vitest related --run --config ./vitest.config.ts',\n};\n"
  },
  {
    "path": "packages/rest/.prettierignore",
    "content": ".turbo\ncoverage\ndist\ndist-docs\ndocs/docs.api.json\nCHANGELOG.md\ntsup.config.bundled*\nvitest.config.ts.timestamp*\n"
  },
  {
    "path": "packages/rest/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/rest/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n# [@discordjs/rest@2.5.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@2.4.3...@discordjs/rest@2.5.0) - (2025-04-25)\n\n## Features\n\n- Components v2 in v14 (#10781) ([edace17](https://github.com/discordjs/discord.js/commit/edace17a131f857547163a3acf4bb6fec0c1e415))\n- Add soundboard in v14 (#10843) ([d3154cf](https://github.com/discordjs/discord.js/commit/d3154cf8f1eb027b5b4921d4048a32f464a3cd85))\n\n# [@discordjs/rest@2.4.2](https://github.com/discordjs/discord.js/compare/@discordjs/rest@2.4.1...@discordjs/rest@2.4.2) - (2025-01-01)\n\n## Bug Fixes\n\n- Correct guild member banner URL ([8d69b24](https://github.com/discordjs/discord.js/commit/8d69b24b5c83249dffa5899a417a9dcbc6f3f30c))\n\n# [@discordjs/rest@2.4.2](https://github.com/discordjs/discord.js/compare/@discordjs/rest@2.4.1...@discordjs/rest@2.4.2) - (2025-01-01)\n\n## Bug Fixes\n\n- Correct guild member banner URL ([8d69b24](https://github.com/discordjs/discord.js/commit/8d69b24b5c83249dffa5899a417a9dcbc6f3f30c))\n\n# [@discordjs/rest@2.4.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@2.3.0...@discordjs/rest@2.4.0) - (2024-09-01)\n\n## Bug Fixes\n\n- Correct base path for GIF stickers (#10330) ([599ad3e](https://github.com/discordjs/discord.js/commit/599ad3eab556463bcde60f8941d0354475cde16b))\n\n## Features\n\n- **User:** Add `avatarDecorationData` (#9888) ([3b5c600](https://github.com/discordjs/discord.js/commit/3b5c600b9e3f8d40ed48f02e3c9acec7433f1cc3))\n\n# [@discordjs/rest@2.3.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@2.2.0...@discordjs/rest@2.3.0) - (2024-05-04)\n\n## Bug Fixes\n\n- Anchor link for events ([0efd1be](https://github.com/discordjs/discord.js/commit/0efd1bea46fa2fc8bcd3dcfd0ac5cd608a0a7df0))\n\n## Documentation\n\n- Split docs.api.json into multiple json files ([597340f](https://github.com/discordjs/discord.js/commit/597340f288437c35da8c703d9b621274de60d880))\n- Remove hyphen after `@returns` (#9989) ([e9ff991](https://github.com/discordjs/discord.js/commit/e9ff99101b9800f36839e6158d544c8ef5938d22))\n\n## Features\n\n- Local and preview detection ([79fbda3](https://github.com/discordjs/discord.js/commit/79fbda3aac6d4f0f8bfb193e797d09cbe331d315))\n- **REST:** Dynamic rate limit offsets (#10099) ([278396e](https://github.com/discordjs/discord.js/commit/278396e815add4e028e43034fab586f971a043d4))\n\n## Refactor\n\n- Docs (#10126) ([18cce83](https://github.com/discordjs/discord.js/commit/18cce83d80598c430218775c53441b6b2ecdc776))\n- Use interfaces for AsyncEventEmitter event maps (#10044) ([adfd9cd](https://github.com/discordjs/discord.js/commit/adfd9cd3b32cfabdcc45ec90f535b2852a3ca4a6))\n\n## Styling\n\n- Fix up lint ([d869d9b](https://github.com/discordjs/discord.js/commit/d869d9b3fecc3d89c051128380907e258a6a6c63))\n\n## Testing\n\n- Skip flaky rest test (#10234) ([dc8f149](https://github.com/discordjs/discord.js/commit/dc8f14967c2c10b26c1be986d42e5d135675ad43))\n\n# [@discordjs/rest@2.2.0](https://github.com/discordjs/discord.js/tree/@discordjs/rest@2.2.0) - (2023-11-18)\n\n## Bug Fixes\n\n- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))\n\n## Features\n\n- Present x-ratelimit-scope for 429s hit (#9973) ([6df233d](https://github.com/discordjs/discord.js/commit/6df233de14e343578fdee3c99a85494e898c7ecc))\n\n## Typings\n\n- Use wrapper utilities (#9945) ([4bc1dae](https://github.com/discordjs/discord.js/commit/4bc1dae36f01649127774c40b14e778d65cf25c5))\n\n# [@discordjs/rest@2.2.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@2.1.0...@discordjs/rest@2.2.0) - (2023-11-17)\n\n## Bug Fixes\n\n- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))\n\n## Features\n\n- Present x-ratelimit-scope for 429s hit (#9973) ([6df233d](https://github.com/discordjs/discord.js/commit/6df233de14e343578fdee3c99a85494e898c7ecc))\n\n## Typings\n\n- Use wrapper utilities (#9945) ([4bc1dae](https://github.com/discordjs/discord.js/commit/4bc1dae36f01649127774c40b14e778d65cf25c5))\n\n# [@discordjs/rest@2.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@2.0.1...@discordjs/rest@2.1.0) - (2023-11-12)\n\n## Bug Fixes\n\n- **REST:** Strip webhook tokens (#9723) ([cf49f40](https://github.com/discordjs/discord.js/commit/cf49f405b0a8e565d5766e774cd57c9ae2184591))\n\n## Documentation\n\n- Fix \"its\" typo (#9825) ([c50809e](https://github.com/discordjs/discord.js/commit/c50809e20648cacea99f5450e8073d960ff8aa39))\n- **create-discord-bot:** Support bun in create-discord-bot (#9798) ([7157748](https://github.com/discordjs/discord.js/commit/7157748fe3a69265896adf0450cd3f37acbcf97b))\n\n## Features\n\n- Expose Retry-After and sublimit timeouts in RatelimitData (#9864) ([81e7866](https://github.com/discordjs/discord.js/commit/81e7866903b22a9b547825698397a5fd7ff1a533))\n- **CDN:** Support emoji size (#9787) ([778df45](https://github.com/discordjs/discord.js/commit/778df451663d04cd1fb5818ef4dcdd01a7b90cc1))\n\n# [@discordjs/rest@2.0.1](https://github.com/discordjs/discord.js/compare/@discordjs/rest@2.0.0...@discordjs/rest@2.0.1) - (2023-08-17)\n\n## Documentation\n\n- Update Node.js requirement to 16.11.0 (#9764) ([188877c](https://github.com/discordjs/discord.js/commit/188877c50af70f0d5cffb246620fa277435c6ce6))\n\n# [@discordjs/rest@2.0.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@1.7.1...@discordjs/rest@2.0.0) - (2023-07-31)\n\n## Features\n\n- No-de-no-de, now with extra buns (#9683) ([386f206](https://github.com/discordjs/discord.js/commit/386f206caf74a04c426799af9796ca96dcb37056))\n  - **BREAKING CHANGE:** The REST and RequestManager classes now extend AsyncEventEmitter\nfrom `@vladfrangu/async_event_emitter`, which aids in cross-compatibility\nbetween Node, Deno, Bun, CF Workers, Vercel Functions, etc.\n  - **BREAKING CHANGE:** DefaultUserAgentAppendix has been adapted to support multiple\ndifferent platforms (previously mentioned Deno, Bun, CF Workers, etc)\n  - **BREAKING CHANGE:** the entry point for `@discordjs/rest` will now differ\nin non-node-like environments (CF Workers, etc.)\n  - **Co-authored-by:** Suneet Tipirneni <77477100+suneettipirneni@users.noreply.github.com>\n  - **Co-authored-by:** Jiralite <33201955+Jiralite@users.noreply.github.com>\n  - **Co-authored-by:** suneettipirneni <suneettipirneni@icloud.com>\n- User avatar decorations (#8914) ([8d97017](https://github.com/discordjs/discord.js/commit/8d9701745840e23854e8f0b057d21cb10e7d1d54))\n- Support new username system (#9512) ([1ab60f9](https://github.com/discordjs/discord.js/commit/1ab60f9da4d6b7ea144fa05b97b029a4bfaeede2))\n\n## Refactor\n\n- **REST:** Remove double classing (#9722) ([8f4256d](https://github.com/discordjs/discord.js/commit/8f4256db8a52ac08359d0b3436f41b641ac4e382))\n  - **BREAKING CHANGE:** `REST` and `RequestManager` have been combined, most of the properties, methods, and events from both classes can now be found on `REST`\n  - **BREAKING CHANGE:** `REST#raw` has been removed in favor of `REST#queueRequest`\n  - **BREAKING CHANGE:** `REST#getAgent` has been removed in favor of `REST#agent`\n\n* chore: update for /rest changes\n- **rest:** Switch api to fetch-like and provide strategies (#9416) ([cdaa0a3](https://github.com/discordjs/discord.js/commit/cdaa0a36f586459f1e5ede868c4250c7da90455c))\n  - **BREAKING CHANGE:** NodeJS v18+ is required when using node due to the use of global `fetch`\n  - **BREAKING CHANGE:** The raw method of REST now returns a web compatible `Respone` object.\n  - **BREAKING CHANGE:** The `parseResponse` utility method has been updated to operate on a web compatible `Response` object.\n  - **BREAKING CHANGE:** Many underlying internals have changed, some of which were exported.\n  - **BREAKING CHANGE:** `DefaultRestOptions` used to contain a default `agent`, which is now set to `null` instead.\n\n# [@discordjs/rest@1.7.1](https://github.com/discordjs/discord.js/compare/@discordjs/rest@1.7.0...@discordjs/rest@1.7.1) - (2023-05-01)\n\n## Bug Fixes\n\n- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2))\n\n## Documentation\n\n- Reference package names properly (#9426) ([d6bca9b](https://github.com/discordjs/discord.js/commit/d6bca9bb4d976dc069a5039250db7d5b3e9142ef))\n- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9))\n\n# [@discordjs/rest@1.7.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@1.6.0...@discordjs/rest@1.7.0) - (2023-04-01)\n\n## Bug Fixes\n\n- **handlers:** Create burst handler for interaction callbacks (#8996) ([db8df10](https://github.com/discordjs/discord.js/commit/db8df104c5e70a12f35b54e5f3f7c897068dde6f))\n- **scripts:** Accessing tsComment ([d8d5f31](https://github.com/discordjs/discord.js/commit/d8d5f31d3927fd1de62f1fa3a1a6e454243ad87b))\n- **rest:** Remove `const enum`s in favour of regular enums (#9243) ([229ad07](https://github.com/discordjs/discord.js/commit/229ad077ff52d8706d68ed4d31983619a32eba45))\n\n## Features\n\n- **website:** Render syntax and mdx on the server (#9086) ([ee5169e](https://github.com/discordjs/discord.js/commit/ee5169e0aadd7bbfcd752aae614ec0f69602b68b))\n\n# [@discordjs/rest@1.6.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@1.5.0...@discordjs/rest@1.6.0) - (2023-03-12)\n\n## Bug Fixes\n\n- **snowflake:** Snowflakes length (#9144) ([955e8fe](https://github.com/discordjs/discord.js/commit/955e8fe312c42ad4937cc1994d1d81e517c413c8))\n- **RequestManager:** Inference of image/apng (#9014) ([ecb4281](https://github.com/discordjs/discord.js/commit/ecb4281d1e2d9a0a427605f75352cbf74ffb2d7c))\n\n## Documentation\n\n- Fix typos (#9127) ([1ba1f23](https://github.com/discordjs/discord.js/commit/1ba1f238f04221ec890fc921678909b5b7d92c26))\n- Fix version export (#9049) ([8b70f49](https://github.com/discordjs/discord.js/commit/8b70f497a1207e30edebdecd12b926c981c13d28))\n\n## Features\n\n- **Sticker:** Add support for gif stickers (#9038) ([6a9875d](https://github.com/discordjs/discord.js/commit/6a9875da054a875a4711394547d47439bbe66fb6))\n- **website:** Add support for source file links (#9048) ([f6506e9](https://github.com/discordjs/discord.js/commit/f6506e99c496683ee0ab67db0726b105b929af38))\n\n## Styling\n\n- Run prettier (#9041) ([2798ba1](https://github.com/discordjs/discord.js/commit/2798ba1eb3d734f0cf2eeccd2e16cfba6804873b))\n\n# [@discordjs/rest@1.5.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@1.4.0...@discordjs/rest@1.5.0) - (2022-12-16)\n\n## Features\n\n- **core:** Add support for role connections (#8930) ([3d6fa24](https://github.com/discordjs/discord.js/commit/3d6fa248c07b2278504bbe8bafa17a3294971fd9))\n\n# [@discordjs/rest@1.4.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@1.3.0...@discordjs/rest@1.4.0) - (2022-11-28)\n\n## Bug Fixes\n\n- **SequentialHandler:** Downlevel ECONNRESET errors (#8785) ([5a70057](https://github.com/discordjs/discord.js/commit/5a70057826b47fb8251f3d836a536de689444ca1))\n- Make ratelimit timeout require event loop to be active (#8779) ([68d5712](https://github.com/discordjs/discord.js/commit/68d5712deae85532604d93b4505f0953d664cde7))\n- Pin @types/node version ([9d8179c](https://github.com/discordjs/discord.js/commit/9d8179c6a78e1c7f9976f852804055964d5385d4))\n\n## Features\n\n- Add `@discordjs/core` (#8736) ([2127b32](https://github.com/discordjs/discord.js/commit/2127b32d26dedeb44ec43d16ec2e2046919f9bb0))\n- New select menus (#8793) ([5152abf](https://github.com/discordjs/discord.js/commit/5152abf7285581abf7689e9050fdc56c4abb1e2b))\n\n## Refactor\n\n- Update `makeURLSearchParams` to accept readonly non-`Record`s (#8868) ([8376e2d](https://github.com/discordjs/discord.js/commit/8376e2dbcd38697ce62615d9a539fd198fbc4713))\n\n# [@discordjs/rest@1.3.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@1.2.0...@discordjs/rest@1.3.0) - (2022-10-08)\n\n## Bug Fixes\n\n- **SequentialHandler:** Throw http error with proper name and more useful message (#8694) ([3f86561](https://github.com/discordjs/discord.js/commit/3f8656115bf9df0dbf8391de68a3401535325895))\n\n## Features\n\n- Web-components (#8715) ([0ac3e76](https://github.com/discordjs/discord.js/commit/0ac3e766bd9dbdeb106483fa4bb085d74de346a2))\n- Add `@discordjs/util` (#8591) ([b2ec865](https://github.com/discordjs/discord.js/commit/b2ec865765bf94181473864a627fb63ea8173fd3))\n- Add `AbortSignal` support (#8672) ([3c231ae](https://github.com/discordjs/discord.js/commit/3c231ae81a52b66940ba495f35fd59a76c65e306))\n\n# [@discordjs/rest@1.2.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@1.1.0...@discordjs/rest@1.2.0) - (2022-09-25)\n\n## Bug Fixes\n\n- Footer / sidebar / deprecation alert ([ba3e0ed](https://github.com/discordjs/discord.js/commit/ba3e0ed348258fe8e51eefb4aa7379a1230616a9))\n\n## Documentation\n\n- Change name (#8604) ([dd5a089](https://github.com/discordjs/discord.js/commit/dd5a08944c258a847fc4377f1d5e953264ab47d0))\n\n## Features\n\n- **rest:** Use Agent with higher connect timeout (#8679) ([64cd53c](https://github.com/discordjs/discord.js/commit/64cd53c4c23dd9c9503fd0887ac5c542137c57e8))\n\n## Refactor\n\n- Website components (#8600) ([c334157](https://github.com/discordjs/discord.js/commit/c3341570d983aea9ecc419979d5a01de658c9d67))\n- Use `eslint-config-neon` for packages. (#8579) ([edadb9f](https://github.com/discordjs/discord.js/commit/edadb9fe5dfd9ff51a3cfc9b25cb242d3f9f5241))\n\n# [@discordjs/rest@1.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@1.0.1...@discordjs/rest@1.1.0) - (2022-08-22)\n\n## Features\n\n- **website:** Show `constructor` information (#8540) ([e42fd16](https://github.com/discordjs/discord.js/commit/e42fd1636973b10dd7ed6fb4280ee1a4a8f82007))\n- **website:** Render `@defaultValue` blocks (#8527) ([8028813](https://github.com/discordjs/discord.js/commit/8028813825e7708915ea892760c1003afd60df2f))\n- **WebSocketShard:** Support new resume url (#8480) ([bc06cc6](https://github.com/discordjs/discord.js/commit/bc06cc638d2f57ab5c600e8cdb6afc8eb2180166))\n\n## Refactor\n\n- Docs design (#8487) ([4ab1d09](https://github.com/discordjs/discord.js/commit/4ab1d09997a18879a9eb9bda39df6f15aa22557e))\n\n# [@discordjs/rest@0.6.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@0.5.0...@discordjs/rest@0.6.0) - (2022-07-17)\n\n## Documentation\n\n- Add codecov coverage badge to readmes (#8226) ([f6db285](https://github.com/discordjs/discord.js/commit/f6db285c073898a749fe4591cbd4463d1896daf5))\n\n## Features\n\n- **builder:** Add max min length in string option (#8214) ([96c8d21](https://github.com/discordjs/discord.js/commit/96c8d21f95eb366c46ae23505ba9054f44821b25))\n- Codecov (#8219) ([f10f4cd](https://github.com/discordjs/discord.js/commit/f10f4cdcd88ca6be7ec735ed3a415ba13da83db0))\n- **docgen:** Update typedoc ([b3346f4](https://github.com/discordjs/discord.js/commit/b3346f4b9b3d4f96443506643d4631dc1c6d7b21))\n- Website (#8043) ([127931d](https://github.com/discordjs/discord.js/commit/127931d1df7a2a5c27923c2f2151dbf3824e50cc))\n- **docgen:** Typescript support ([3279b40](https://github.com/discordjs/discord.js/commit/3279b40912e6aa61507bedb7db15a2b8668de44b))\n- Docgen package (#8029) ([8b979c0](https://github.com/discordjs/discord.js/commit/8b979c0245c42fd824d8e98745ee869f5360fc86))\n- Use vitest instead of jest for more speed ([8d8e6c0](https://github.com/discordjs/discord.js/commit/8d8e6c03decd7352a2aa180f6e5bc1a13602539b))\n- Add scripts package for locally used scripts ([f2ae1f9](https://github.com/discordjs/discord.js/commit/f2ae1f9348bfd893332a9060f71a8a5f272a1b8b))\n\n## Refactor\n\n- **rest:** Add content-type(s) to uploads (#8290) ([103a358](https://github.com/discordjs/discord.js/commit/103a3584c95a7b7f57fa62d47b86520d5ec32303))\n- **collection:** Remove default export (#8053) ([16810f3](https://github.com/discordjs/discord.js/commit/16810f3e410bf35ed7e6e7412d517ea74c792c5d))\n- Move all the config files to root (#8033) ([769ea0b](https://github.com/discordjs/discord.js/commit/769ea0bfe78c4f1d413c6b397c604ffe91e39c6a))\n\n# [@discordjs/rest@0.5.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@2.1.0...@discordjs/rest@0.5.0) - (2022-06-04)\n\n## Bug Fixes\n\n- **REST:** Remove dom types (#7922) ([e92b17d](https://github.com/discordjs/discord.js/commit/e92b17d8555164ff259e524efc6a26675660e5c2))\n- Ok statusCode can be 200..299 (#7919) ([d1504f2](https://github.com/discordjs/discord.js/commit/d1504f2ae19816b3fadcdb3ad17facc863ed7529))\n\n## Features\n\n- **rest:** Add guild member banner cdn url (#7973) ([97eaab3](https://github.com/discordjs/discord.js/commit/97eaab35d7383ecbbd93dc623ceda969286c1554))\n- REST#raw (#7929) ([dfe449c](https://github.com/discordjs/discord.js/commit/dfe449c253b617e8f92c720a2f71135aa1601a65))\n- **rest:** Use undici (#7747) ([d1ec8c3](https://github.com/discordjs/discord.js/commit/d1ec8c37ffb7fe3b63eaa8c382f22ca1fb348c9b))\n- **REST:** Enable setting default authPrefix (#7853) ([679dcda](https://github.com/discordjs/discord.js/commit/679dcda9709376f37cc58a60f74d12d324d93e4e))\n\n## Styling\n\n- Cleanup tests and tsup configs ([6b8ef20](https://github.com/discordjs/discord.js/commit/6b8ef20cb3af5b5cfd176dd0aa0a1a1e98551629))\n\n# [@discordjs/rest@0.4.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@0.3.0...@discordjs/rest@0.4.0) - (2022-04-17)\n\n## Bug Fixes\n\n- **gateway:** Use version 10 (#7689) ([8880de0](https://github.com/discordjs/discord.js/commit/8880de0cecdf273fd6df23988e4cb77774a75390))\n- **RequestHandler:** Only reset tokens for authenticated 401s (#7508) ([b9ff7b0](https://github.com/discordjs/discord.js/commit/b9ff7b057379a47ce13265f78e21bf0d55feaf0a))\n- **ci:** Ci error (#7454) ([0af9bc8](https://github.com/discordjs/discord.js/commit/0af9bc841ffe1a297d308500d696bad4b85abda9))\n- Use png as extension for defaultAvatarURL (#7414) ([538e9ce](https://github.com/discordjs/discord.js/commit/538e9cef459d00d74b9bd6852da3ce2acac9bae5))\n- **rest:** Sublimit all requests on unhandled routes (#7366) ([733ac82](https://github.com/discordjs/discord.js/commit/733ac82d5dffabc622fb59e06d06e83396734dc6))\n- Fix some typos (#7393) ([92a04f4](https://github.com/discordjs/discord.js/commit/92a04f4d98f6c6760214034cc8f5a1eaa78893c7))\n\n## Documentation\n\n- Enhance /rest README (#7757) ([a1329bd](https://github.com/discordjs/discord.js/commit/a1329bd3ebafc6d5b5e2788ff082674f01b726f3))\n\n## Features\n\n- Add `makeURLSearchParams` utility function (#7744) ([8eaec11](https://github.com/discordjs/discord.js/commit/8eaec114a98026024c21545988860c123948c55d))\n- Add API v10 support (#7477) ([72577c4](https://github.com/discordjs/discord.js/commit/72577c4bfd02524a27afb6ff4aebba9301a690d3))\n- Add support for module: NodeNext in TS and ESM (#7598) ([8f1986a](https://github.com/discordjs/discord.js/commit/8f1986a6aa98365e09b00e84ad5f9f354ab61f3d))\n- **builders:** Add attachment command option type (#7203) ([ae0f35f](https://github.com/discordjs/discord.js/commit/ae0f35f51d68dfa5a7dc43d161ef9365171debdb))\n- **cdn:** Add support for scheduled event image covers (#7335) ([ac26d9b](https://github.com/discordjs/discord.js/commit/ac26d9b1307d63e116b043505e5f925db7ed01aa))\n\n## Refactor\n\n- **requestmanager:** Use timestampfrom (#7459) ([3298510](https://github.com/discordjs/discord.js/commit/32985109c3b7614d364007608f8c5af4bed753ae))\n- **files:** Remove redundant file property names (#7340) ([6725038](https://github.com/discordjs/discord.js/commit/67250382f99872a9edff99ebaa482ffa895b0c37))\n\n# [@discordjs/rest@0.3.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@0.2.0...@discordjs/rest@0.3.0) - (2022-01-24)\n\n## Bug Fixes\n\n- **rest:** Don't add empty query (#7308) ([d0fa5aa](https://github.com/discordjs/discord.js/commit/d0fa5aaa26d316608120bca3050e14eefbe2f93b))\n- **rest:** Use http agent when protocol is not https (#7309) ([d8ea572](https://github.com/discordjs/discord.js/commit/d8ea572fb8a51f2f6a902c4926e814017d115708))\n- `ref` delay for rate limited requests (#7239) ([ed0cfd9](https://github.com/discordjs/discord.js/commit/ed0cfd91edc3a2b23a34a8ecd9db38baa12b52fa))\n\n## Documentation\n\n- Fix a typo and use milliseconds instead of ms (#7251) ([0dd56af](https://github.com/discordjs/discord.js/commit/0dd56afe1cdf16f1e7d9afe1f8c29c31d1833a25))\n\n## Features\n\n- Rest hash and handler sweeping (#7255) ([3bb4829](https://github.com/discordjs/discord.js/commit/3bb48298004d292214c6cb8f927c2fea78a42952))\n- Rest docs (#7281) ([9054f2f](https://github.com/discordjs/discord.js/commit/9054f2f7ad7f246431e5f53403535bf301c27a80))\n\n## Refactor\n\n- **files:** File data can be much more than buffer (#7238) ([86ab526](https://github.com/discordjs/discord.js/commit/86ab526d493415b14b79b51d08c3677897d219ee))\n- **rest:** Rename attachment to file (#7199) ([c969cbf](https://github.com/discordjs/discord.js/commit/c969cbf6524093757d47108b6a55e62dcb210e8b))\n\n## Testing\n\n- **voice:** Fix tests ([62c74b8](https://github.com/discordjs/discord.js/commit/62c74b8333066465e5bd295b8b102b35a506751d))\n"
  },
  {
    "path": "packages/rest/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1.  Definitions.\n\n    \"License\" shall mean the terms and conditions for use, reproduction,\n    and distribution as defined by Sections 1 through 9 of this document.\n\n    \"Licensor\" shall mean the copyright owner or entity authorized by\n    the copyright owner that is granting the License.\n\n    \"Legal Entity\" shall mean the union of the acting entity and all\n    other entities that control, are controlled by, or are under common\n    control with that entity. For the purposes of this definition,\n    \"control\" means (i) the power, direct or indirect, to cause the\n    direction or management of such entity, whether by contract or\n    otherwise, or (ii) ownership of fifty percent (50%) or more of the\n    outstanding shares, or (iii) beneficial ownership of such entity.\n\n    \"You\" (or \"Your\") shall mean an individual or Legal Entity\n    exercising permissions granted by this License.\n\n    \"Source\" form shall mean the preferred form for making modifications,\n    including but not limited to software source code, documentation\n    source, and configuration files.\n\n    \"Object\" form shall mean any form resulting from mechanical\n    transformation or translation of a Source form, including but\n    not limited to compiled object code, generated documentation,\n    and conversions to other media types.\n\n    \"Work\" shall mean the work of authorship, whether in Source or\n    Object form, made available under the License, as indicated by a\n    copyright notice that is included in or attached to the work\n    (an example is provided in the Appendix below).\n\n    \"Derivative Works\" shall mean any work, whether in Source or Object\n    form, that is based on (or derived from) the Work and for which the\n    editorial revisions, annotations, elaborations, or other modifications\n    represent, as a whole, an original work of authorship. For the purposes\n    of this License, Derivative Works shall not include works that remain\n    separable from, or merely link (or bind by name) to the interfaces of,\n    the Work and Derivative Works thereof.\n\n    \"Contribution\" shall mean any work of authorship, including\n    the original version of the Work and any modifications or additions\n    to that Work or Derivative Works thereof, that is intentionally\n    submitted to Licensor for inclusion in the Work by the copyright owner\n    or by an individual or Legal Entity authorized to submit on behalf of\n    the copyright owner. For the purposes of this definition, \"submitted\"\n    means any form of electronic, verbal, or written communication sent\n    to the Licensor or its representatives, including but not limited to\n    communication on electronic mailing lists, source code control systems,\n    and issue tracking systems that are managed by, or on behalf of, the\n    Licensor for the purpose of discussing and improving the Work, but\n    excluding communication that is conspicuously marked or otherwise\n    designated in writing by the copyright owner as \"Not a Contribution.\"\n\n    \"Contributor\" shall mean Licensor and any individual or Legal Entity\n    on behalf of whom a Contribution has been received by Licensor and\n    subsequently incorporated within the Work.\n\n2.  Grant of Copyright License. Subject to the terms and conditions of\n    this License, each Contributor hereby grants to You a perpetual,\n    worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n    copyright license to reproduce, prepare Derivative Works of,\n    publicly display, publicly perform, sublicense, and distribute the\n    Work and such Derivative Works in Source or Object form.\n\n3.  Grant of Patent License. Subject to the terms and conditions of\n    this License, each Contributor hereby grants to You a perpetual,\n    worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n    (except as stated in this section) patent license to make, have made,\n    use, offer to sell, sell, import, and otherwise transfer the Work,\n    where such license applies only to those patent claims licensable\n    by such Contributor that are necessarily infringed by their\n    Contribution(s) alone or by combination of their Contribution(s)\n    with the Work to which such Contribution(s) was submitted. If You\n    institute patent litigation against any entity (including a\n    cross-claim or counterclaim in a lawsuit) alleging that the Work\n    or a Contribution incorporated within the Work constitutes direct\n    or contributory patent infringement, then any patent licenses\n    granted to You under this License for that Work shall terminate\n    as of the date such litigation is filed.\n\n4.  Redistribution. You may reproduce and distribute copies of the\n    Work or Derivative Works thereof in any medium, with or without\n    modifications, and in Source or Object form, provided that You\n    meet the following conditions:\n\n    (a) You must give any other recipients of the Work or\n    Derivative Works a copy of this License; and\n\n    (b) You must cause any modified files to carry prominent notices\n    stating that You changed the files; and\n\n    (c) You must retain, in the Source form of any Derivative Works\n    that You distribute, all copyright, patent, trademark, and\n    attribution notices from the Source form of the Work,\n    excluding those notices that do not pertain to any part of\n    the Derivative Works; and\n\n    (d) If the Work includes a \"NOTICE\" text file as part of its\n    distribution, then any Derivative Works that You distribute must\n    include a readable copy of the attribution notices contained\n    within such NOTICE file, excluding those notices that do not\n    pertain to any part of the Derivative Works, in at least one\n    of the following places: within a NOTICE text file distributed\n    as part of the Derivative Works; within the Source form or\n    documentation, if provided along with the Derivative Works; or,\n    within a display generated by the Derivative Works, if and\n    wherever such third-party notices normally appear. The contents\n    of the NOTICE file are for informational purposes only and\n    do not modify the License. You may add Your own attribution\n    notices within Derivative Works that You distribute, alongside\n    or as an addendum to the NOTICE text from the Work, provided\n    that such additional attribution notices cannot be construed\n    as modifying the License.\n\n    You may add Your own copyright statement to Your modifications and\n    may provide additional or different license terms and conditions\n    for use, reproduction, or distribution of Your modifications, or\n    for any such Derivative Works as a whole, provided Your use,\n    reproduction, and distribution of the Work otherwise complies with\n    the conditions stated in this License.\n\n5.  Submission of Contributions. Unless You explicitly state otherwise,\n    any Contribution intentionally submitted for inclusion in the Work\n    by You to the Licensor shall be under the terms and conditions of\n    this License, without any additional terms or conditions.\n    Notwithstanding the above, nothing herein shall supersede or modify\n    the terms of any separate license agreement you may have executed\n    with Licensor regarding such Contributions.\n\n6.  Trademarks. This License does not grant permission to use the trade\n    names, trademarks, service marks, or product names of the Licensor,\n    except as required for reasonable and customary use in describing the\n    origin of the Work and reproducing the content of the NOTICE file.\n\n7.  Disclaimer of Warranty. Unless required by applicable law or\n    agreed to in writing, Licensor provides the Work (and each\n    Contributor provides its Contributions) on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n    implied, including, without limitation, any warranties or conditions\n    of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n    PARTICULAR PURPOSE. You are solely responsible for determining the\n    appropriateness of using or redistributing the Work and assume any\n    risks associated with Your exercise of permissions under this License.\n\n8.  Limitation of Liability. In no event and under no legal theory,\n    whether in tort (including negligence), contract, or otherwise,\n    unless required by applicable law (such as deliberate and grossly\n    negligent acts) or agreed to in writing, shall any Contributor be\n    liable to You for damages, including any direct, indirect, special,\n    incidental, or consequential damages of any character arising as a\n    result of this License or out of the use or inability to use the\n    Work (including but not limited to damages for loss of goodwill,\n    work stoppage, computer failure or malfunction, or any and all\n    other commercial damages or losses), even if such Contributor\n    has been advised of the possibility of such damages.\n\n9.  Accepting Warranty or Additional Liability. While redistributing\n    the Work or Derivative Works thereof, You may choose to offer,\n    and charge a fee for, acceptance of support, warranty, indemnity,\n    or other liability obligations and/or rights consistent with this\n    License. However, in accepting such obligations, You may act only\n    on Your own behalf and on Your sole responsibility, not on behalf\n    of any other Contributor, and only if You agree to indemnify,\n    defend, and hold each Contributor harmless for any liability\n    incurred by, or claims asserted against, such Contributor by reason\n    of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nCopyright 2021 Noel Buechler\nCopyright 2021 Vlad Frangu\nCopyright 2021 Aura Román\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n"
  },
  {
    "path": "packages/rest/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/rest\"><img src=\"https://img.shields.io/npm/v/@discordjs/rest.svg?maxAge=3600\" alt=\"npm version\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/rest\"><img src=\"https://img.shields.io/npm/dt/@discordjs/rest.svg?maxAge=3600\" alt=\"npm downloads\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Tests status\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/commits/main/packages/rest\"><img alt=\"Last commit.\" src=\"https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Frest\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t\t<a href=\"https://codecov.io/gh/discordjs/discord.js\"><img src=\"https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=rest\" alt=\"Code coverage\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## About\n\n`@discordjs/rest` is a module that allows you to easily make REST requests to the Discord API.\n\n## Installation\n\n**Node.js 22.12.0 or newer is required.**\n\n```sh\nnpm install @discordjs/rest\nyarn add @discordjs/rest\npnpm add @discordjs/rest\nbun add @discordjs/rest\n```\n\n## Examples\n\nInstall all required dependencies:\n\n```sh\nnpm install @discordjs/rest discord-api-types\nyarn add @discordjs/rest discord-api-types\npnpm add @discordjs/rest discord-api-types\nbun add @discordjs/rest discord-api-types\n```\n\nSend a basic message:\n\n```js\nimport { REST } from '@discordjs/rest';\nimport { Routes } from 'discord-api-types/v10';\n\nconst rest = new REST({ version: '10' }).setToken(TOKEN);\n\ntry {\n\tawait rest.post(Routes.channelMessages(CHANNEL_ID), {\n\t\tbody: {\n\t\t\tcontent: 'A message via REST!',\n\t\t},\n\t});\n} catch (error) {\n\tconsole.error(error);\n}\n```\n\nCreate a thread from an existing message to be archived after 60 minutes of inactivity:\n\n```js\nimport { REST } from '@discordjs/rest';\nimport { Routes } from 'discord-api-types/v10';\n\nconst rest = new REST({ version: '10' }).setToken(TOKEN);\n\ntry {\n\tawait rest.post(Routes.threads(CHANNEL_ID, MESSAGE_ID), {\n\t\tbody: {\n\t\t\tname: 'Thread',\n\t\t\tauto_archive_duration: 60,\n\t\t},\n\t});\n} catch (error) {\n\tconsole.error(error);\n}\n```\n\nSend a basic message in an edge environment:\n\n```js\nimport { REST } from '@discordjs/rest';\nimport { Routes } from 'discord-api-types/v10';\n\nconst rest = new REST({ version: '10', makeRequest: fetch }).setToken(TOKEN);\n\ntry {\n\tawait rest.post(Routes.channelMessages(CHANNEL_ID), {\n\t\tbody: {\n\t\t\tcontent: 'A message via REST from the edge!',\n\t\t},\n\t});\n} catch (error) {\n\tconsole.error(error);\n}\n```\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Documentation][documentation]\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [npm][npm]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the\n[documentation][documentation].  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs/packages/rest/stable\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/rest\n[npm]: https://www.npmjs.com/package/@discordjs/rest\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/rest/__tests__/BurstHandler.test.ts",
    "content": "/* eslint-disable id-length */\n/* eslint-disable promise/prefer-await-to-then */\nimport { MockAgent, setGlobalDispatcher } from 'undici';\nimport type { Interceptable, MockInterceptor } from 'undici/types/mock-interceptor';\nimport { beforeEach, afterEach, test, expect } from 'vitest';\nimport { DiscordAPIError, REST, BurstHandlerMajorIdKey } from '../src/index.js';\nimport { BurstHandler } from '../src/lib/handlers/BurstHandler.js';\nimport { genPath } from './util.js';\n\nconst callbackKey = `Global(POST:/interactions/:id/:token/callback):${BurstHandlerMajorIdKey}`;\nconst callbackPath = new RegExp(genPath('/interactions/[0-9]{17,19}/.+/callback'));\n\nconst api = new REST();\n\nlet mockAgent: MockAgent;\nlet mockPool: Interceptable;\nlet serverOutage = true;\n\nbeforeEach(() => {\n\tmockAgent = new MockAgent();\n\tmockAgent.disableNetConnect();\n\tsetGlobalDispatcher(mockAgent);\n\n\tmockPool = mockAgent.get('https://discord.com');\n\tapi.setAgent(mockAgent);\n});\n\nafterEach(async () => {\n\tawait mockAgent.close();\n});\n\n// @discordjs/rest uses the `content-type` header to detect whether to parse\n// the response as JSON or as an ArrayBuffer.\nconst responseOptions: MockInterceptor.MockResponseOptions = {\n\theaders: {\n\t\t'content-type': 'application/json',\n\t},\n};\n\ntest('Interaction callback creates burst handler', async () => {\n\tmockPool.intercept({ path: callbackPath, method: 'POST' }).reply(200);\n\n\texpect(api.handlers.get(callbackKey)).toBe(undefined);\n\texpect(\n\t\tawait api.post('/interactions/1234567890123456789/totallyarealtoken/callback', {\n\t\t\tauth: false,\n\t\t\tbody: { type: 4, data: { content: 'Reply' } },\n\t\t}),\n\t).toBeInstanceOf(ArrayBuffer);\n\texpect(api.handlers.get(callbackKey)).toBeInstanceOf(BurstHandler);\n});\n\ntest('Requests are handled in bursts', async () => {\n\tmockPool.intercept({ path: callbackPath, method: 'POST' }).reply(200).delay(100).times(3);\n\n\t// Return the current time on these results as their response does not indicate anything\n\tconst [a, b, c] = await Promise.all([\n\t\tapi\n\t\t\t.post('/interactions/1234567890123456789/totallyarealtoken/callback', {\n\t\t\t\tauth: false,\n\t\t\t\tbody: { type: 4, data: { content: 'Reply1' } },\n\t\t\t})\n\t\t\t.then(() => performance.now()),\n\t\tapi\n\t\t\t.post('/interactions/2345678901234567890/anotherveryrealtoken/callback', {\n\t\t\t\tauth: false,\n\t\t\t\tbody: { type: 4, data: { content: 'Reply2' } },\n\t\t\t})\n\t\t\t.then(() => performance.now()),\n\t\tapi\n\t\t\t.post('/interactions/3456789012345678901/nowaytheresanotherone/callback', {\n\t\t\t\tauth: false,\n\t\t\t\tbody: { type: 4, data: { content: 'Reply3' } },\n\t\t\t})\n\t\t\t.then(() => performance.now()),\n\t]);\n\n\texpect(b - a).toBeLessThan(10);\n\texpect(c - a).toBeLessThan(10);\n});\n\ntest('Handle 404', async () => {\n\tmockPool\n\t\t.intercept({ path: callbackPath, method: 'POST' })\n\t\t.reply(404, { message: 'Unknown interaction', code: 10_062 }, responseOptions);\n\n\tconst promise = api.post('/interactions/1234567890123456788/definitelynotarealinteraction/callback', {\n\t\tauth: false,\n\t\tbody: { type: 4, data: { content: 'Malicious' } },\n\t});\n\tawait expect(promise).rejects.toThrowError('Unknown interaction');\n\tawait expect(promise).rejects.toBeInstanceOf(DiscordAPIError);\n});\n\nlet unexpected429 = true;\ntest('Handle unexpected 429', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: callbackPath,\n\t\t\tmethod: 'POST',\n\t\t})\n\t\t.reply(() => {\n\t\t\tif (unexpected429) {\n\t\t\t\tunexpected429 = false;\n\t\t\t\treturn {\n\t\t\t\t\tstatusCode: 429,\n\t\t\t\t\tdata: '',\n\t\t\t\t\tresponseOptions: {\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t'retry-after': '1',\n\t\t\t\t\t\t\tvia: '1.1 google',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tstatusCode: 200,\n\t\t\t\tdata: { test: true },\n\t\t\t\tresponseOptions,\n\t\t\t};\n\t\t})\n\t\t.times(2);\n\n\tconst previous = performance.now();\n\tlet firstResolvedTime: number;\n\tconst unexpectedLimit = api\n\t\t.post('/interactions/1234567890123456789/totallyarealtoken/callback', {\n\t\t\tauth: false,\n\t\t\tbody: { type: 4, data: { content: 'Reply' } },\n\t\t})\n\t\t.then((res) => {\n\t\t\tfirstResolvedTime = performance.now();\n\t\t\treturn res;\n\t\t});\n\n\texpect(await unexpectedLimit).toStrictEqual({ test: true });\n\texpect(firstResolvedTime!).toBeGreaterThanOrEqual(previous + 1_000);\n});\n\ntest('server responding too slow', async () => {\n\tconst api2 = new REST({ timeout: 1 }).setToken('A-Very-Really-Real-Token');\n\n\tapi2.setAgent(mockAgent);\n\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: callbackPath,\n\t\t\tmethod: 'POST',\n\t\t})\n\t\t.reply(200, '')\n\t\t.delay(100)\n\t\t.times(10);\n\n\tconst promise = api2.post('/interactions/1234567890123456789/totallyarealtoken/callback', {\n\t\tauth: false,\n\t\tbody: { type: 4, data: { content: 'Reply' } },\n\t});\n\n\tawait expect(promise).rejects.toThrowError('aborted');\n}, 1_000);\n\ntest('Handle temp server outage', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: callbackPath,\n\t\t\tmethod: 'POST',\n\t\t})\n\t\t.reply(() => {\n\t\t\tif (serverOutage) {\n\t\t\t\tserverOutage = false;\n\n\t\t\t\treturn {\n\t\t\t\t\tstatusCode: 500,\n\t\t\t\t\tdata: '',\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tstatusCode: 200,\n\t\t\t\tdata: { test: true },\n\t\t\t\tresponseOptions,\n\t\t\t};\n\t\t})\n\t\t.times(2);\n\n\texpect(\n\t\tawait api.post('/interactions/1234567890123456789/totallyarealtoken/callback', {\n\t\t\tauth: false,\n\t\t\tbody: { type: 4, data: { content: 'Reply' } },\n\t\t}),\n\t).toStrictEqual({ test: true });\n});\n"
  },
  {
    "path": "packages/rest/__tests__/CDN.test.ts",
    "content": "import { test, expect } from 'vitest';\nimport { CDN } from '../src/index.js';\n\nconst baseCDN = 'https://cdn-discord.com';\nconst baseMedia = 'https://media-discord.com';\nconst id = '123456';\nconst hash = 'abcdef';\nconst animatedHash = 'a_bcdef';\nconst defaultAvatar = 1_234 % 5;\n\nconst cdn = new CDN({ cdn: baseCDN, mediaProxy: baseMedia });\n\ntest('appAsset default', () => {\n\texpect(cdn.appAsset(id, hash)).toEqual(`${baseCDN}/app-assets/${id}/${hash}.webp`);\n});\n\ntest('appIcon default', () => {\n\texpect(cdn.appIcon(id, hash)).toEqual(`${baseCDN}/app-icons/${id}/${hash}.webp`);\n});\n\ntest('avatar default', () => {\n\texpect(cdn.avatar(id, hash)).toEqual(`${baseCDN}/avatars/${id}/${hash}.webp`);\n});\n\ntest('avatar dynamic-animated', () => {\n\texpect(cdn.avatar(id, animatedHash)).toEqual(`${baseCDN}/avatars/${id}/${animatedHash}.webp?animated=true`);\n});\n\ntest('avatar dynamic-not-animated', () => {\n\texpect(cdn.avatar(id, hash)).toEqual(`${baseCDN}/avatars/${id}/${hash}.webp`);\n});\n\ntest('avatar decoration preset', () => {\n\texpect(cdn.avatarDecoration(hash)).toEqual(`${baseCDN}/avatar-decoration-presets/${hash}.png`);\n});\n\ntest('banner default', () => {\n\texpect(cdn.banner(id, hash)).toEqual(`${baseCDN}/banners/${id}/${hash}.webp`);\n});\n\ntest('channelIcon default', () => {\n\texpect(cdn.channelIcon(id, hash)).toEqual(`${baseCDN}/channel-icons/${id}/${hash}.webp`);\n});\n\ntest('defaultAvatar default', () => {\n\texpect(cdn.defaultAvatar(defaultAvatar)).toEqual(`${baseCDN}/embed/avatars/${defaultAvatar}.png`);\n});\n\ntest('discoverySplash default', () => {\n\texpect(cdn.discoverySplash(id, hash)).toEqual(`${baseCDN}/discovery-splashes/${id}/${hash}.webp`);\n});\n\ntest('emoji', () => {\n\texpect(cdn.emoji(id)).toEqual(`${baseCDN}/emojis/${id}.webp`);\n});\n\ntest('emoji animated', () => {\n\texpect(cdn.emoji(id, { animated: true })).toEqual(`${baseCDN}/emojis/${id}.webp?animated=true`);\n});\n\ntest('emoji with GIF format', () => {\n\texpect(cdn.emoji(id, { extension: 'gif' })).toEqual(`${baseCDN}/emojis/${id}.gif`);\n});\n\ntest('guildMemberAvatar default', () => {\n\texpect(cdn.guildMemberAvatar(id, id, hash)).toEqual(`${baseCDN}/guilds/${id}/users/${id}/avatars/${hash}.webp`);\n});\n\ntest('guildMemberAvatar dynamic-animated', () => {\n\texpect(cdn.guildMemberAvatar(id, id, animatedHash)).toEqual(\n\t\t`${baseCDN}/guilds/${id}/users/${id}/avatars/${animatedHash}.webp?animated=true`,\n\t);\n});\n\ntest('guildMemberAvatar dynamic-not-animated', () => {\n\texpect(cdn.guildMemberAvatar(id, id, hash)).toEqual(`${baseCDN}/guilds/${id}/users/${id}/avatars/${hash}.webp`);\n});\n\ntest('guildMemberBanner default', () => {\n\texpect(cdn.guildMemberBanner(id, id, hash)).toEqual(`${baseCDN}/guilds/${id}/users/${id}/banners/${hash}.webp`);\n});\n\ntest('guildMemberBanner dynamic-animated', () => {\n\texpect(cdn.guildMemberBanner(id, id, animatedHash)).toEqual(\n\t\t`${baseCDN}/guilds/${id}/users/${id}/banners/${animatedHash}.webp?animated=true`,\n\t);\n});\n\ntest('guildMemberBanner dynamic-not-animated', () => {\n\texpect(cdn.guildMemberBanner(id, id, hash)).toEqual(`${baseCDN}/guilds/${id}/users/${id}/banners/${hash}.webp`);\n});\n\ntest('guildScheduledEventCover default', () => {\n\texpect(cdn.guildScheduledEventCover(id, hash)).toEqual(`${baseCDN}/guild-events/${id}/${hash}.webp`);\n});\n\ntest('icon default', () => {\n\texpect(cdn.icon(id, hash)).toEqual(`${baseCDN}/icons/${id}/${hash}.webp`);\n});\n\ntest('icon dynamic-animated', () => {\n\texpect(cdn.icon(id, animatedHash)).toEqual(`${baseCDN}/icons/${id}/${animatedHash}.webp?animated=true`);\n});\n\ntest('icon dynamic-not-animated', () => {\n\texpect(cdn.icon(id, hash)).toEqual(`${baseCDN}/icons/${id}/${hash}.webp`);\n});\n\ntest('role icon default', () => {\n\texpect(cdn.roleIcon(id, hash)).toEqual(`${baseCDN}/role-icons/${id}/${hash}.webp`);\n});\n\ntest('splash default', () => {\n\texpect(cdn.splash(id, hash)).toEqual(`${baseCDN}/splashes/${id}/${hash}.webp`);\n});\n\ntest('sticker default', () => {\n\texpect(cdn.sticker(id)).toEqual(`${baseCDN}/stickers/${id}.png`);\n});\n\ntest('sticker GIF', () => {\n\texpect(cdn.sticker(id, 'gif')).toEqual(`${baseMedia}/stickers/${id}.gif`);\n});\n\ntest('stickerPackBanner default', () => {\n\texpect(cdn.stickerPackBanner(id)).toEqual(`${baseCDN}/app-assets/710982414301790216/store/${id}.webp`);\n});\n\ntest('teamIcon default', () => {\n\texpect(cdn.teamIcon(id, hash)).toEqual(`${baseCDN}/team-icons/${id}/${hash}.webp`);\n});\n\ntest('soundboardSound', () => {\n\texpect(cdn.soundboardSound(id)).toEqual(`${baseCDN}/soundboard-sounds/${id}`);\n});\n\ntest('guildTagBadge', () => {\n\texpect(cdn.guildTagBadge(id, hash)).toEqual(`${baseCDN}/guild-tag-badges/${id}/${hash}.webp`);\n});\n\ntest('makeURL throws on invalid size', () => {\n\texpect(() => cdn.avatar(id, animatedHash, { size: 5 })).toThrow(RangeError);\n});\n\ntest('makeURL throws on invalid extension', () => {\n\t// @ts-expect-error: Invalid extension\n\texpect(() => cdn.avatar(id, animatedHash, { extension: 'tif', forceStatic: true })).toThrow(RangeError);\n});\n\ntest('makeURL valid size', () => {\n\texpect(cdn.avatar(id, animatedHash, { size: 512 })).toEqual(\n\t\t`${baseCDN}/avatars/${id}/${animatedHash}.webp?animated=true&size=512`,\n\t);\n});\n"
  },
  {
    "path": "packages/rest/__tests__/DiscordAPIError.test.ts",
    "content": "import { test, expect } from 'vitest';\nimport { DiscordAPIError } from '../src/index.js';\n\ntest('Unauthorized', () => {\n\tconst error = new DiscordAPIError(\n\t\t{ message: '401: Unauthorized', code: 0 },\n\t\t0,\n\t\t401,\n\t\t'PATCH',\n\t\t'https://discord.com/api/v10/guilds/:id',\n\t\t{\n\t\t\tfiles: undefined,\n\t\t\tbody: undefined,\n\t\t},\n\t);\n\n\texpect(error.code).toEqual(0);\n\texpect(error.message).toEqual('401: Unauthorized');\n\texpect(error.method).toEqual('PATCH');\n\texpect(error.name).toEqual('DiscordAPIError[0]');\n\texpect(error.status).toEqual(401);\n\texpect(error.url).toEqual('https://discord.com/api/v10/guilds/:id');\n\texpect(error.requestBody.files).toBeUndefined();\n\texpect(error.requestBody.json).toBeUndefined();\n});\n\ntest('Invalid Form Body Error (error.{property}._errors.{index})', () => {\n\tconst error = new DiscordAPIError(\n\t\t{\n\t\t\tcode: 50_035,\n\t\t\terrors: {\n\t\t\t\tusername: { _errors: [{ code: 'BASE_TYPE_BAD_LENGTH', message: 'Must be between 2 and 32 in length.' }] },\n\t\t\t},\n\t\t\tmessage: 'Invalid Form Body',\n\t\t},\n\t\t50_035,\n\t\t400,\n\t\t'PATCH',\n\t\t'https://discord.com/api/v10/users/@me',\n\t\t{\n\t\t\tfiles: undefined,\n\t\t\tbody: {\n\t\t\t\tusername: 'a',\n\t\t\t},\n\t\t},\n\t);\n\n\texpect(error.code).toEqual(50_035);\n\texpect(error.message).toEqual(\n\t\t['Invalid Form Body', 'username[BASE_TYPE_BAD_LENGTH]: Must be between 2 and 32 in length.'].join('\\n'),\n\t);\n\texpect(error.method).toEqual('PATCH');\n\texpect(error.name).toEqual('DiscordAPIError[50035]');\n\texpect(error.status).toEqual(400);\n\texpect(error.url).toEqual('https://discord.com/api/v10/users/@me');\n\texpect(error.requestBody.files).toBeUndefined();\n\texpect(error.requestBody.json).toStrictEqual({ username: 'a' });\n});\n\ntest('Invalid FormFields Error (error.errors.{property}.{property}.{index}.{property}._errors.{index})', () => {\n\tconst error = new DiscordAPIError(\n\t\t{\n\t\t\tcode: 50_035,\n\t\t\terrors: {\n\t\t\t\tembed: {\n\t\t\t\t\tfields: { '0': { value: { _errors: [{ code: 'BASE_TYPE_REQUIRED', message: 'This field is required' }] } } },\n\t\t\t\t},\n\t\t\t},\n\t\t\tmessage: 'Invalid Form Body',\n\t\t},\n\t\t50_035,\n\t\t400,\n\t\t'POST',\n\t\t'https://discord.com/api/v10/channels/:id',\n\t\t{},\n\t);\n\n\texpect(error.code).toEqual(50_035);\n\texpect(error.message).toEqual(\n\t\t['Invalid Form Body', 'embed.fields[0].value[BASE_TYPE_REQUIRED]: This field is required'].join('\\n'),\n\t);\n\texpect(error.method).toEqual('POST');\n\texpect(error.name).toEqual('DiscordAPIError[50035]');\n\texpect(error.status).toEqual(400);\n\texpect(error.url).toEqual('https://discord.com/api/v10/channels/:id');\n});\n\ntest('Invalid FormFields Error (error.errors.{property}.{property}._errors.{index}._errors)', () => {\n\tconst error = new DiscordAPIError(\n\t\t{\n\t\t\tcode: 50_035,\n\t\t\terrors: {\n\t\t\t\tform_fields: {\n\t\t\t\t\tlabel: { _errors: [{ _errors: [{ code: 'BASE_TYPE_REQUIRED', message: 'This field is required' }] }] },\n\t\t\t\t},\n\t\t\t},\n\t\t\tmessage: 'Invalid Form Body',\n\t\t},\n\t\t50_035,\n\t\t400,\n\t\t'PATCH',\n\t\t'https://discord.com/api/v10/guilds/:id',\n\t\t{},\n\t);\n\n\texpect(error.code).toEqual(50_035);\n\texpect(error.message).toEqual(\n\t\t['Invalid Form Body', 'form_fields.label[0][BASE_TYPE_REQUIRED]: This field is required'].join('\\n'),\n\t);\n\texpect(error.method).toEqual('PATCH');\n\texpect(error.name).toEqual('DiscordAPIError[50035]');\n\texpect(error.status).toEqual(400);\n\texpect(error.url).toEqual('https://discord.com/api/v10/guilds/:id');\n});\n\ntest('Invalid Oauth Code Error (error.error)', () => {\n\tconst error = new DiscordAPIError(\n\t\t{\n\t\t\terror: 'invalid_request',\n\t\t\terror_description: 'Invalid \"code\" in request.',\n\t\t},\n\t\t'invalid_request',\n\t\t400,\n\t\t'POST',\n\t\t'https://discord.com/api/v10/oauth2/token',\n\t\t{\n\t\t\tbody: new URLSearchParams([\n\t\t\t\t['client_id', '1234567890123545678'],\n\t\t\t\t['client_secret', 'totally-valid-secret'],\n\t\t\t\t['redirect_uri', 'http://localhost'],\n\t\t\t\t['grant_type', 'authorization_code'],\n\t\t\t\t['code', 'very-invalid-code'],\n\t\t\t]),\n\t\t},\n\t);\n\n\texpect(error.code).toEqual('invalid_request');\n\texpect(error.message).toEqual('Invalid \"code\" in request.');\n\texpect(error.method).toEqual('POST');\n\texpect(error.name).toEqual('DiscordAPIError[invalid_request]');\n\texpect(error.status).toEqual(400);\n\texpect(error.url).toEqual('https://discord.com/api/v10/oauth2/token');\n});\n"
  },
  {
    "path": "packages/rest/__tests__/REST.test.ts",
    "content": "import { Buffer } from 'node:buffer';\nimport { DiscordSnowflake } from '@sapphire/snowflake';\nimport type { Snowflake } from 'discord-api-types/v10';\nimport { Routes } from 'discord-api-types/v10';\nimport { type FormData, fetch } from 'undici';\nimport { MockAgent, setGlobalDispatcher } from 'undici';\nimport type { Interceptable, MockInterceptor } from 'undici/types/mock-interceptor.js';\nimport { beforeEach, afterEach, test, expect, vitest } from 'vitest';\nimport { REST } from '../src/index.js';\nimport { genPath } from './util.js';\n\nconst newSnowflake: Snowflake = DiscordSnowflake.generate().toString();\n\nconst api = new REST().setToken('A-Very-Fake-Token');\n\nconst makeRequestMock = vitest.fn(fetch);\n\nconst fetchApi = new REST({ makeRequest: makeRequestMock }).setToken('A-Very-Fake-Token');\n\n// @discordjs/rest uses the `content-type` header to detect whether to parse\n// the response as JSON or as an ArrayBuffer.\nconst responseOptions: MockInterceptor.MockResponseOptions = {\n\theaders: {\n\t\t'content-type': 'application/json',\n\t},\n};\n\nlet mockAgent: MockAgent;\nlet mockPool: Interceptable;\n\nbeforeEach(() => {\n\tmockAgent = new MockAgent();\n\tmockAgent.disableNetConnect(); // prevent actual requests to Discord\n\tsetGlobalDispatcher(mockAgent); // enabled the mock client to intercept requests\n\n\tmockPool = mockAgent.get('https://discord.com');\n\tapi.setAgent(mockAgent);\n\tfetchApi.setAgent(mockAgent);\n});\n\nafterEach(async () => {\n\tawait mockAgent.close();\n});\n\ntest('simple GET', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/simpleGet'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tdata: { test: true },\n\t\t\tstatusCode: 200,\n\t\t\tresponseOptions,\n\t\t}));\n\n\texpect(await api.get('/simpleGet')).toStrictEqual({ test: true });\n});\n\ntest('simple DELETE', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/simpleDelete'),\n\t\t\tmethod: 'DELETE',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tdata: { test: true },\n\t\t\tstatusCode: 200,\n\t\t\tresponseOptions,\n\t\t}));\n\n\texpect(await api.delete('/simpleDelete')).toStrictEqual({ test: true });\n});\n\ntest('simple PATCH', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/simplePatch'),\n\t\t\tmethod: 'PATCH',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tdata: { test: true },\n\t\t\tstatusCode: 200,\n\t\t\tresponseOptions,\n\t\t}));\n\n\texpect(await api.patch('/simplePatch')).toStrictEqual({ test: true });\n});\n\ntest('simple PUT', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/simplePut'),\n\t\t\tmethod: 'PUT',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tdata: { test: true },\n\t\t\tstatusCode: 200,\n\t\t\tresponseOptions,\n\t\t}));\n\n\texpect(await api.put('/simplePut')).toStrictEqual({ test: true });\n});\n\ntest('simple POST', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/simplePost'),\n\t\t\tmethod: 'POST',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tdata: { test: true },\n\t\t\tstatusCode: 200,\n\t\t\tresponseOptions,\n\t\t}));\n\n\texpect(await api.post('/simplePost')).toStrictEqual({ test: true });\n});\n\ntest('simple POST with fetch', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/fetchSimplePost'),\n\t\t\tmethod: 'POST',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tdata: { test: true },\n\t\t\tstatusCode: 200,\n\t\t\tresponseOptions,\n\t\t}));\n\n\texpect(await fetchApi.post('/fetchSimplePost')).toStrictEqual({ test: true });\n\texpect(makeRequestMock).toHaveBeenCalledTimes(1);\n});\n\ntest('simple PUT 2', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/simplePut'),\n\t\t\tmethod: 'PUT',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tdata: { test: true },\n\t\t\tstatusCode: 200,\n\t\t\tresponseOptions,\n\t\t}));\n\n\texpect(await api.put('/simplePut')).toStrictEqual({ test: true });\n});\n\ntest('getQuery', async () => {\n\tconst query = new URLSearchParams([\n\t\t['foo', 'bar'],\n\t\t['hello', 'world'],\n\t]);\n\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: `${genPath('/getQuery')}?${query.toString()}`,\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tdata: { test: true },\n\t\t\tstatusCode: 200,\n\t\t\tresponseOptions,\n\t\t}));\n\n\texpect(\n\t\tawait api.get('/getQuery', {\n\t\t\tquery,\n\t\t}),\n\t).toStrictEqual({ test: true });\n});\n\ntest('getAuth', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/getAuth'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(\n\t\t\t200,\n\t\t\t(from) => ({ auth: (from.headers as unknown as Record<string, string | undefined>).Authorization ?? null }),\n\t\t\tresponseOptions,\n\t\t)\n\t\t.times(5);\n\n\t// default\n\texpect(await api.get('/getAuth')).toStrictEqual({ auth: 'Bot A-Very-Fake-Token' });\n\n\t// unauthorized\n\texpect(\n\t\tawait api.get('/getAuth', {\n\t\t\tauth: false,\n\t\t}),\n\t).toStrictEqual({ auth: null });\n\n\t// authorized\n\texpect(\n\t\tawait api.get('/getAuth', {\n\t\t\tauth: true,\n\t\t}),\n\t).toStrictEqual({ auth: 'Bot A-Very-Fake-Token' });\n\n\t// Custom Bot Auth\n\texpect(\n\t\tawait api.get('/getAuth', {\n\t\t\tauth: { token: 'A-Very-Different-Fake-Token' },\n\t\t}),\n\t).toStrictEqual({ auth: 'Bot A-Very-Different-Fake-Token' });\n\n\t// Custom Bearer Auth\n\texpect(\n\t\tawait api.get('/getAuth', {\n\t\t\tauth: { token: 'A-Bearer-Fake-Token', prefix: 'Bearer' },\n\t\t}),\n\t).toStrictEqual({ auth: 'Bearer A-Bearer-Fake-Token' });\n});\n\ntest('getReason', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/getReason'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(\n\t\t\t200,\n\t\t\t(from) => ({\n\t\t\t\treason: (from.headers as unknown as Record<string, string | undefined>)['X-Audit-Log-Reason'] ?? null,\n\t\t\t}),\n\t\t\tresponseOptions,\n\t\t)\n\t\t.times(3);\n\n\t// default\n\texpect(await api.get('/getReason')).toStrictEqual({ reason: null });\n\n\t// plain text\n\texpect(\n\t\tawait api.get('/getReason', {\n\t\t\treason: 'Hello',\n\t\t}),\n\t).toStrictEqual({ reason: 'Hello' });\n\n\t// encoded\n\texpect(\n\t\tawait api.get('/getReason', {\n\t\t\treason: '😄',\n\t\t}),\n\t).toStrictEqual({ reason: '%F0%9F%98%84' });\n});\n\ntest('urlEncoded', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/urlEncoded'),\n\t\t\tmethod: 'POST',\n\t\t})\n\t\t.reply((from) => ({\n\t\t\tdata: from.body!,\n\t\t\tstatusCode: 200,\n\t\t}));\n\n\tconst body = new URLSearchParams([\n\t\t['client_id', '1234567890123545678'],\n\t\t['client_secret', 'totally-valid-secret'],\n\t\t['redirect_uri', 'http://localhost'],\n\t\t['grant_type', 'authorization_code'],\n\t\t['code', 'very-invalid-code'],\n\t]);\n\n\texpect(\n\t\tnew Uint8Array(\n\t\t\t(await api.post('/urlEncoded', {\n\t\t\t\tbody,\n\t\t\t\tpassThroughBody: true,\n\t\t\t\tauth: false,\n\t\t\t})) as ArrayBuffer,\n\t\t),\n\t).toStrictEqual(new Uint8Array(Buffer.from(body.toString())));\n});\n\ntest('postEcho', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/postEcho'),\n\t\t\tmethod: 'POST',\n\t\t})\n\t\t.reply((from) => ({\n\t\t\tdata: from.body!,\n\t\t\tstatusCode: 200,\n\t\t\tresponseOptions,\n\t\t}));\n\n\texpect(await api.post('/postEcho', { body: { foo: 'bar' } })).toStrictEqual({ foo: 'bar' });\n});\n\ntest('201 status code', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/postNon200StatusCode'),\n\t\t\tmethod: 'POST',\n\t\t})\n\t\t.reply((from) => ({\n\t\t\tdata: from.body!,\n\t\t\tstatusCode: 201,\n\t\t\tresponseOptions,\n\t\t}));\n\n\texpect(await api.post('/postNon200StatusCode', { body: { foo: 'bar' } })).toStrictEqual({ foo: 'bar' });\n});\n\ntest('Old Message Delete Edge-Case: Old message', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/channels/339942739275677727/messages/392063687801700356'),\n\t\t\tmethod: 'DELETE',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tdata: { test: true },\n\t\t\tstatusCode: 200,\n\t\t\tresponseOptions,\n\t\t}));\n\n\texpect(await api.delete(Routes.channelMessage('339942739275677727', '392063687801700356'))).toStrictEqual({\n\t\ttest: true,\n\t});\n});\n\ntest('Old Message Delete Edge-Case: Old message 2', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath(`/channels/339942739275677727/messages/${newSnowflake}`),\n\t\t\tmethod: 'DELETE',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tdata: { test: true },\n\t\t\tstatusCode: 200,\n\t\t\tresponseOptions,\n\t\t}));\n\n\texpect(await api.delete(Routes.channelMessage('339942739275677727', newSnowflake))).toStrictEqual({ test: true });\n});\n\ntest('postFile', async () => {\n\tconst mockData = {\n\t\tstatusCode: 200,\n\t\tdata: 'Hello',\n\t};\n\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/postFileEmptyArray'),\n\t\t\tmethod: 'POST',\n\t\t})\n\t\t.reply(({ body }) => {\n\t\t\texpect(body).toBeNull();\n\t\t\treturn mockData;\n\t\t});\n\n\t// postFile empty\n\tawait api.post('/postFileEmptyArray', { files: [] });\n\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/postFileStringData'),\n\t\t\tmethod: 'POST',\n\t\t})\n\t\t.reply(({ body }) => {\n\t\t\tconst fd = body as FormData;\n\n\t\t\texpect(fd.get('files[0]')).toBeInstanceOf(File);\n\t\t\texpect(fd.get('files[0]')).toHaveProperty('size', 5); // 'Hello'\n\n\t\t\treturn mockData;\n\t\t});\n\n\t// postFile file (string)\n\tawait api.post('/postFileStringData', {\n\t\tfiles: [{ name: 'out.txt', data: 'Hello' }],\n\t});\n\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/postFileBufferWithJson'),\n\t\t\tmethod: 'POST',\n\t\t})\n\t\t.reply(({ body }) => {\n\t\t\tconst fd = body as FormData;\n\n\t\t\texpect(fd.get('files[0]')).toBeInstanceOf(File);\n\t\t\texpect(fd.get('files[0]')).toHaveProperty('size', 5); // Buffer.from('Hello')\n\t\t\texpect(fd.get('payload_json')).toStrictEqual(JSON.stringify({ foo: 'bar' }));\n\n\t\t\treturn mockData;\n\t\t});\n\n\t// postFile file and JSON\n\tawait api.post('/postFileBufferWithJson', {\n\t\tfiles: [{ name: 'out.txt', data: Buffer.from('Hello') }],\n\t\tbody: { foo: 'bar' },\n\t});\n\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/postFilesAndJson'),\n\t\t\tmethod: 'POST',\n\t\t})\n\t\t.reply(({ body }) => {\n\t\t\tconst fd = body as FormData;\n\n\t\t\texpect(fd.get('files[0]')).toBeInstanceOf(File);\n\t\t\texpect(fd.get('files[1]')).toBeInstanceOf(File);\n\t\t\texpect(fd.get('files[0]')).toHaveProperty('size', 5); // Buffer.from('Hello')\n\t\t\texpect(fd.get('files[1]')).toHaveProperty('size', 2); // Buffer.from('Hi')\n\t\t\texpect(fd.get('payload_json')).toStrictEqual(JSON.stringify({ files: [{ id: 0, description: 'test' }] }));\n\n\t\t\treturn mockData;\n\t\t});\n\n\t// postFile files and JSON\n\tawait api.post('/postFilesAndJson', {\n\t\tfiles: [\n\t\t\t{ name: 'out.txt', data: Buffer.from('Hello') },\n\t\t\t{ name: 'out.txt', data: Buffer.from('Hi') },\n\t\t],\n\t\tbody: { files: [{ id: 0, description: 'test' }] },\n\t});\n\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/postFileStickerAndJson'),\n\t\t\tmethod: 'POST',\n\t\t})\n\t\t.reply(({ body }) => {\n\t\t\tconst fd = body as FormData;\n\n\t\t\texpect(fd.get('file')).toBeInstanceOf(File);\n\t\t\texpect(fd.get('file')).toHaveProperty('size', 7); // Buffer.from('Sticker')\n\t\t\texpect(fd.get('foo')).toStrictEqual('bar');\n\n\t\t\treturn mockData;\n\t\t});\n\n\t// postFile sticker and JSON\n\tawait api.post('/postFileStickerAndJson', {\n\t\tfiles: [{ key: 'file', name: 'sticker.png', data: Buffer.from('Sticker') }],\n\t\tbody: { foo: 'bar' },\n\t\tappendToFormData: true,\n\t});\n});\n"
  },
  {
    "path": "packages/rest/__tests__/RequestHandler.test.ts",
    "content": "/* eslint-disable id-length */\n/* eslint-disable promise/prefer-await-to-then */\nimport { MockAgent, setGlobalDispatcher } from 'undici';\nimport type { Interceptable, MockInterceptor } from 'undici/types/mock-interceptor.js';\nimport { beforeEach, afterEach, test, expect, vitest } from 'vitest';\nimport { DiscordAPIError, HTTPError, RateLimitError, REST, RESTEvents } from '../src/index.js';\nimport { genPath } from './util.js';\n\nlet mockAgent: MockAgent;\nlet mockPool: Interceptable;\n\nconst api = new REST({ timeout: 2_000, offset: 5 }).setToken('A-Very-Fake-Token');\nconst invalidAuthApi = new REST({ timeout: 2_000 }).setToken('Definitely-Not-A-Fake-Token');\nconst rateLimitErrorApi = new REST({ rejectOnRateLimit: ['/channels'] }).setToken('Obviously-Not-A-Fake-Token');\n\nbeforeEach(() => {\n\tmockAgent = new MockAgent();\n\tmockAgent.disableNetConnect();\n\tsetGlobalDispatcher(mockAgent);\n\n\tmockPool = mockAgent.get('https://discord.com');\n\tapi.setAgent(mockAgent);\n\tinvalidAuthApi.setAgent(mockAgent);\n\trateLimitErrorApi.setAgent(mockAgent);\n});\n\nafterEach(async () => {\n\tawait mockAgent.close();\n});\n\n// @discordjs/rest uses the `content-type` header to detect whether to parse\n// the response as JSON or as an ArrayBuffer.\nconst responseOptions: MockInterceptor.MockResponseOptions = {\n\theaders: {\n\t\t'content-type': 'application/json',\n\t},\n};\n\nlet resetAfter = 0;\nlet sublimitResetAfter = 0;\nlet retryAfter = 0;\nlet sublimitRequests = 0;\nlet sublimitHits = 0;\nlet serverOutage = true;\nlet unexpected429 = true;\nlet unexpected429cf = true;\nconst sublimitIntervals: {\n\treset: NodeJS.Timeout | null;\n\tretry: NodeJS.Timeout | null;\n} = {\n\treset: null,\n\tretry: null,\n};\n\nconst sublimit = { body: { name: 'newname' } };\nconst noSublimit = { body: { bitrate: 40_000 } };\n\nfunction startSublimitIntervals() {\n\tif (!sublimitIntervals.reset) {\n\t\tsublimitResetAfter = Date.now() + 250;\n\t\tsublimitIntervals.reset = setInterval(() => {\n\t\t\tsublimitRequests = 0;\n\t\t\tsublimitResetAfter = Date.now() + 250;\n\t\t}, 250);\n\t}\n\n\tif (!sublimitIntervals.retry) {\n\t\tretryAfter = Date.now() + 1_000;\n\t\tsublimitIntervals.retry = setInterval(() => {\n\t\t\tsublimitHits = 0;\n\t\t\tretryAfter = Date.now() + 1_000;\n\t\t}, 1_000);\n\t}\n}\n\n// This is tested first to ensure the count remains accurate\ntest('Significant Invalid Requests', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/badRequest'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(403, { message: 'Missing Permissions', code: 50_013 }, responseOptions)\n\t\t.times(10);\n\n\tconst invalidListener = vitest.fn();\n\tconst invalidListener2 = vitest.fn();\n\tapi.on(RESTEvents.InvalidRequestWarning, invalidListener);\n\t// Ensure listeners on REST do not get double added\n\tapi.on(RESTEvents.InvalidRequestWarning, invalidListener2);\n\tapi.off(RESTEvents.InvalidRequestWarning, invalidListener2);\n\n\tconst [a, b, c, d, e] = [\n\t\tapi.get('/badRequest'),\n\t\tapi.get('/badRequest'),\n\t\tapi.get('/badRequest'),\n\t\tapi.get('/badRequest'),\n\t\tapi.get('/badRequest'),\n\t];\n\tawait expect(a).rejects.toThrowError('Missing Permissions');\n\tawait expect(b).rejects.toThrowError('Missing Permissions');\n\tawait expect(c).rejects.toThrowError('Missing Permissions');\n\tawait expect(d).rejects.toThrowError('Missing Permissions');\n\tawait expect(e).rejects.toThrowError('Missing Permissions');\n\texpect(invalidListener).toHaveBeenCalledTimes(0);\n\t// eslint-disable-next-line require-atomic-updates\n\tapi.options.invalidRequestWarningInterval = 2;\n\n\tconst [f, g, h, i, j] = [\n\t\tapi.get('/badRequest'),\n\t\tapi.get('/badRequest'),\n\t\tapi.get('/badRequest'),\n\t\tapi.get('/badRequest'),\n\t\tapi.get('/badRequest'),\n\t];\n\tawait expect(f).rejects.toThrowError('Missing Permissions');\n\tawait expect(g).rejects.toThrowError('Missing Permissions');\n\tawait expect(h).rejects.toThrowError('Missing Permissions');\n\tawait expect(i).rejects.toThrowError('Missing Permissions');\n\tawait expect(j).rejects.toThrowError('Missing Permissions');\n\texpect(invalidListener).toHaveBeenCalledTimes(3);\n\tapi.off(RESTEvents.InvalidRequestWarning, invalidListener);\n});\n\ntest('Handle standard rate limits', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/standard'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(() => {\n\t\t\tconst response = Date.now() >= resetAfter ? 204 : 429;\n\t\t\tresetAfter = Date.now() + 250;\n\n\t\t\tif (response === 204) {\n\t\t\t\treturn {\n\t\t\t\t\tstatusCode: 204,\n\t\t\t\t\tdata: '',\n\t\t\t\t\tresponseOptions: {\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t'x-ratelimit-limit': '1',\n\t\t\t\t\t\t\t'x-ratelimit-remaining': '0',\n\t\t\t\t\t\t\t'x-ratelimit-reset-after': ((resetAfter - Date.now()) / 1_000).toString(),\n\t\t\t\t\t\t\t'x-ratelimit-bucket': '80c17d2f203122d936070c88c8d10f33',\n\t\t\t\t\t\t\tvia: '1.1 google',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tstatusCode: 429,\n\t\t\t\tdata: {\n\t\t\t\t\tlimit: '1',\n\t\t\t\t\tremaining: '0',\n\t\t\t\t\tresetAfter: (resetAfter / 1_000).toString(),\n\t\t\t\t\tbucket: '80c17d2f203122d936070c88c8d10f33',\n\t\t\t\t\tretryAfter: (resetAfter - Date.now()).toString(),\n\t\t\t\t},\n\t\t\t\tresponseOptions: {\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t'x-ratelimit-limit': '1',\n\t\t\t\t\t\t'x-ratelimit-remaining': '0',\n\t\t\t\t\t\t'x-ratelimit-reset-after': ((resetAfter - Date.now()) / 1_000).toString(),\n\t\t\t\t\t\t'x-ratelimit-bucket': '80c17d2f203122d936070c88c8d10f33',\n\t\t\t\t\t\t'retry-after': (resetAfter - Date.now()).toString(),\n\t\t\t\t\t\tvia: '1.1 google',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t})\n\t\t.times(3);\n\n\tconst [a, b, c] = [api.get('/standard'), api.get('/standard'), api.get('/standard')];\n\tconst uint8 = new Uint8Array();\n\n\texpect(new Uint8Array((await a) as ArrayBuffer)).toStrictEqual(uint8);\n\tconst previous1 = performance.now();\n\texpect(new Uint8Array((await b) as ArrayBuffer)).toStrictEqual(uint8);\n\tconst previous2 = performance.now();\n\texpect(new Uint8Array((await c) as ArrayBuffer)).toStrictEqual(uint8);\n\tconst now = performance.now();\n\texpect(previous2).toBeGreaterThanOrEqual(previous1 + 200);\n\texpect(now).toBeGreaterThanOrEqual(previous2 + 200);\n});\n\ntest('Handle sublimits', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/channels/:id'),\n\t\t\tmethod: 'PATCH',\n\t\t})\n\t\t.reply((from) => {\n\t\t\tconst body = JSON.parse(from.body as string) as Record<string, unknown>;\n\n\t\t\tif ('name' in body || 'topic' in body) {\n\t\t\t\tsublimitHits += 1;\n\t\t\t\tsublimitRequests += 1;\n\t\t\t\tconst response = 2 - sublimitHits >= 0 && 10 - sublimitRequests >= 0 ? 200 : 429;\n\t\t\t\tstartSublimitIntervals();\n\n\t\t\t\tif (response === 200) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatusCode: 200,\n\t\t\t\t\t\tdata: '',\n\t\t\t\t\t\tresponseOptions: {\n\t\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t\t'x-ratelimit-limit': '10',\n\t\t\t\t\t\t\t\t'x-ratelimit-remaining': `${10 - sublimitRequests}`,\n\t\t\t\t\t\t\t\t'x-ratelimit-reset-after': ((sublimitResetAfter - Date.now()) / 1_000).toString(),\n\t\t\t\t\t\t\t\tvia: '1.1 google',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tstatusCode: 429,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tlimit: '10',\n\t\t\t\t\t\tremaining: `${10 - sublimitRequests}`,\n\t\t\t\t\t\tresetAfter: (sublimitResetAfter / 1_000).toString(),\n\t\t\t\t\t\tretryAfter: ((retryAfter - Date.now()) / 1_000).toString(),\n\t\t\t\t\t},\n\t\t\t\t\tresponseOptions: {\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t'x-ratelimit-limit': '10',\n\t\t\t\t\t\t\t'x-ratelimit-remaining': `${10 - sublimitRequests}`,\n\t\t\t\t\t\t\t'x-ratelimit-reset-after': ((sublimitResetAfter - Date.now()) / 1_000).toString(),\n\t\t\t\t\t\t\t'retry-after': ((retryAfter - Date.now()) / 1_000).toString(),\n\t\t\t\t\t\t\tvia: '1.1 google',\n\t\t\t\t\t\t\t...responseOptions.headers,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t} else if (!('name' in body) && !('topic' in body)) {\n\t\t\t\tsublimitRequests += 1;\n\t\t\t\tconst response = 10 - sublimitRequests >= 0 ? 200 : 429;\n\t\t\t\tstartSublimitIntervals();\n\n\t\t\t\tif (response === 200) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatusCode: 200,\n\t\t\t\t\t\tdata: '',\n\t\t\t\t\t\tresponseOptions: {\n\t\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t\t'x-ratelimit-limit': '10',\n\t\t\t\t\t\t\t\t'x-ratelimit-remaining': `${10 - sublimitRequests}`,\n\t\t\t\t\t\t\t\t'x-ratelimit-reset-after': ((sublimitResetAfter - Date.now()) / 1_000).toString(),\n\t\t\t\t\t\t\t\tvia: '1.1 google',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tstatusCode: 429,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tlimit: '10',\n\t\t\t\t\t\tremaining: `${10 - sublimitRequests}`,\n\t\t\t\t\t\tresetAfter: (sublimitResetAfter / 1_000).toString(),\n\t\t\t\t\t\tretryAfter: ((sublimitResetAfter - Date.now()) / 1_000).toString(),\n\t\t\t\t\t},\n\t\t\t\t\tresponseOptions: {\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t'x-ratelimit-limit': '10',\n\t\t\t\t\t\t\t'x-ratelimit-remaining': `${10 - sublimitRequests}`,\n\t\t\t\t\t\t\t'x-ratelimit-reset-after': ((sublimitResetAfter - Date.now()) / 1_000).toString(),\n\t\t\t\t\t\t\t'retry-after': ((sublimitResetAfter - Date.now()) / 1_000).toString(),\n\t\t\t\t\t\t\tvia: '1.1 google',\n\t\t\t\t\t\t\t...responseOptions.headers,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tstatusCode: 420,\n\t\t\t\tdata: 'Oh no',\n\t\t\t};\n\t\t})\n\t\t.persist();\n\n\t// Return the current time on these results as their response does not indicate anything\n\t// Queue all requests, don't wait, to allow retroactive check\n\tconst [aP, bP, cP, dP, eP] = [\n\t\tapi.patch('/channels/:id', sublimit).then(() => Date.now()),\n\t\tapi.patch('/channels/:id', sublimit).then(() => Date.now()),\n\t\tapi.patch('/channels/:id', sublimit).then(() => Date.now()), // Limit hits\n\t\tapi.patch('/channels/:id', noSublimit).then(() => Date.now()), // Ensure normal request passes\n\t\tapi.patch('/channels/:id', sublimit).then(() => Date.now()), // For retroactive check\n\t];\n\n\tconst [a, b, c, d] = await Promise.all([aP, bP, cP, dP]);\n\n\tconst [f, g] = await Promise.all([\n\t\tapi.patch('/channels/:id', sublimit).then(() => Date.now()),\n\t\tapi.patch('/channels/:id', noSublimit).then(() => Date.now()),\n\t]); // For additional sublimited checks\n\n\tconst e = await eP;\n\n\texpect(a).toBeLessThanOrEqual(b);\n\texpect(b).toBeLessThanOrEqual(c);\n\texpect(d).toBeLessThanOrEqual(c);\n\texpect(c).toBeLessThanOrEqual(e);\n\texpect(d).toBeLessThanOrEqual(e);\n\texpect(e).toBeLessThanOrEqual(f);\n\texpect(e).toBeLessThanOrEqual(g);\n\texpect(g).toBeLessThanOrEqual(f);\n\n\tclearInterval(sublimitIntervals.reset!);\n\tclearInterval(sublimitIntervals.retry!);\n\n\t// Reject on RateLimit\n\tconst [aP2, bP2, cP2] = [\n\t\trateLimitErrorApi.patch('/channels/:id', sublimit),\n\t\trateLimitErrorApi.patch('/channels/:id', sublimit),\n\t\trateLimitErrorApi.patch('/channels/:id', sublimit),\n\t];\n\t// eslint-disable-next-line @typescript-eslint/await-thenable\n\tawait expect(aP2).resolves;\n\tawait expect(bP2).rejects.toThrowError();\n\tawait expect(bP2).rejects.toBeInstanceOf(RateLimitError);\n\tawait expect(cP2).rejects.toThrowError();\n\tawait expect(cP2).rejects.toBeInstanceOf(RateLimitError);\n});\n\ntest('Handle unexpected 429', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/unexpected'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(() => {\n\t\t\tif (unexpected429) {\n\t\t\t\tunexpected429 = false;\n\t\t\t\treturn {\n\t\t\t\t\tstatusCode: 429,\n\t\t\t\t\tdata: '',\n\t\t\t\t\tresponseOptions: {\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t'retry-after': '1',\n\t\t\t\t\t\t\tvia: '1.1 google',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tstatusCode: 200,\n\t\t\t\tdata: { test: true },\n\t\t\t\tresponseOptions,\n\t\t\t};\n\t\t})\n\t\t.times(3);\n\n\tconst previous = performance.now();\n\tlet firstResolvedTime: number;\n\tlet secondResolvedTime: number;\n\tconst unexpectedSublimit = api.get('/unexpected').then((res) => {\n\t\tfirstResolvedTime = performance.now();\n\t\treturn res;\n\t});\n\tconst queuedSublimit = api.get('/unexpected').then((res) => {\n\t\tsecondResolvedTime = performance.now();\n\t\treturn res;\n\t});\n\n\texpect(await unexpectedSublimit).toStrictEqual({ test: true });\n\texpect(await queuedSublimit).toStrictEqual({ test: true });\n\texpect(performance.now()).toBeGreaterThanOrEqual(previous + 1_000);\n\t// @ts-expect-error: This is intentional\n\texpect(secondResolvedTime).toBeGreaterThan(firstResolvedTime);\n});\n\ntest('Handle unexpected 429 cloudflare', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/unexpected-cf'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(() => {\n\t\t\tif (unexpected429cf) {\n\t\t\t\tunexpected429cf = false;\n\n\t\t\t\treturn {\n\t\t\t\t\tstatusCode: 429,\n\t\t\t\t\tdata: '',\n\t\t\t\t\tresponseOptions: {\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t'retry-after': '1',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tstatusCode: 200,\n\t\t\t\tdata: { test: true },\n\t\t\t\tresponseOptions,\n\t\t\t};\n\t\t})\n\t\t.times(2); // twice because it re-runs the request after first 429\n\n\tconst previous = Date.now();\n\texpect(await api.get('/unexpected-cf')).toStrictEqual({ test: true });\n\texpect(Date.now()).toBeGreaterThanOrEqual(previous + 1_000);\n});\n\ntest('Handle global rate limits', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/triggerGlobal'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tdata: { global: true },\n\t\t\tstatusCode: 200,\n\t\t\tresponseOptions,\n\t\t}));\n\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/regularRequest'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tdata: { test: true },\n\t\t\tstatusCode: 200,\n\t\t\tresponseOptions,\n\t\t}));\n\n\texpect(await api.get('/triggerGlobal')).toStrictEqual({ global: true });\n\texpect(await api.get('/regularRequest')).toStrictEqual({ test: true });\n});\n\ntest('Handle temp server outage', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/temp'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(() => {\n\t\t\tif (serverOutage) {\n\t\t\t\tserverOutage = false;\n\n\t\t\t\treturn {\n\t\t\t\t\tstatusCode: 500,\n\t\t\t\t\tdata: '',\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tstatusCode: 200,\n\t\t\t\tdata: { test: true },\n\t\t\t\tresponseOptions,\n\t\t\t};\n\t\t})\n\t\t.times(2);\n\n\texpect(await api.get('/temp')).toStrictEqual({ test: true });\n});\n\ntest('perm server outage', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/outage'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(500, '', responseOptions)\n\t\t.times(4);\n\n\tconst promise = api.get('/outage');\n\tawait expect(promise).rejects.toThrowError();\n\tawait expect(promise).rejects.toBeInstanceOf(HTTPError);\n});\n\ntest('server responding too slow', async () => {\n\tconst api2 = new REST({ timeout: 1 }).setToken('A-Very-Really-Real-Token');\n\n\tapi2.setAgent(mockAgent);\n\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/slow'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(200, '')\n\t\t.delay(100)\n\t\t.times(10);\n\n\tconst promise = api2.get('/slow');\n\n\tawait expect(promise).rejects.toThrowError('aborted');\n}, 1_000);\n\ntest('Unauthorized', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/unauthorized'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(401, { message: '401: Unauthorized', code: 0 }, responseOptions)\n\t\t.times(2);\n\n\tconst setTokenSpy = vitest.spyOn(invalidAuthApi, 'setToken');\n\n\t// Ensure authless requests don't reset the token\n\tconst promiseWithoutTokenClear = invalidAuthApi.get('/unauthorized', { auth: false });\n\tawait expect(promiseWithoutTokenClear).rejects.toThrowError('401: Unauthorized');\n\tawait expect(promiseWithoutTokenClear).rejects.toBeInstanceOf(DiscordAPIError);\n\texpect(setTokenSpy).not.toHaveBeenCalled();\n\n\t// Ensure authed requests do reset the token\n\tconst promise = invalidAuthApi.get('/unauthorized');\n\tawait expect(promise).rejects.toThrowError('401: Unauthorized');\n\tawait expect(promise).rejects.toBeInstanceOf(DiscordAPIError);\n\texpect(setTokenSpy).toHaveBeenCalledTimes(1);\n});\n\ntest('Bad Request', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/badRequest'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(403, { message: 'Missing Permissions', code: 50_013 }, responseOptions);\n\n\tconst promise = api.get('/badRequest');\n\tawait expect(promise).rejects.toThrowError('Missing Permissions');\n\tawait expect(promise).rejects.toBeInstanceOf(DiscordAPIError);\n});\n\ntest('malformedRequest', async () => {\n\t// This test doesn't really make sense because\n\t// there is no such thing as a 601 status code.\n\t// So, what exactly is a malformed request?\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/malformedRequest'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tstatusCode: 405,\n\t\t\tdata: '',\n\t\t}));\n\n\tawait expect(api.get('/malformedRequest')).rejects.toBeInstanceOf(DiscordAPIError);\n});\n\n// TODO: flaky due to changes in undici\ntest.skip('abort', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/abort'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(200, { message: 'Hello World' }, responseOptions)\n\t\t.delay(100)\n\t\t.times(3);\n\n\tconst controller = new AbortController();\n\tconst [aP2, bP2, cP2] = [\n\t\tapi.get('/abort', { signal: controller.signal }),\n\t\tapi.get('/abort', { signal: controller.signal }),\n\t\tapi.get('/abort', { signal: controller.signal }),\n\t];\n\n\tawait expect(aP2).resolves.toStrictEqual({ message: 'Hello World' });\n\tcontroller.abort();\n\n\t// Abort mid-execution:\n\tawait expect(bP2).rejects.toThrowError('aborted');\n\n\t// Abort scheduled:\n\tawait expect(cP2).rejects.toThrowError('Request aborted manually');\n});\n"
  },
  {
    "path": "packages/rest/__tests__/RequestManager.test.ts",
    "content": "import { MockAgent, setGlobalDispatcher, type Interceptable } from 'undici';\nimport { beforeEach, afterEach, test, expect } from 'vitest';\nimport { REST } from '../src/index.js';\nimport { normalizeRateLimitOffset } from '../src/lib/utils/utils.js';\nimport { genPath } from './util.js';\n\nconst api = new REST();\n\nlet mockAgent: MockAgent;\nlet mockPool: Interceptable;\n\nbeforeEach(() => {\n\tmockAgent = new MockAgent();\n\tmockAgent.disableNetConnect();\n\tsetGlobalDispatcher(mockAgent);\n\n\tmockPool = mockAgent.get('https://discord.com');\n\tapi.setAgent(mockAgent);\n});\n\nafterEach(async () => {\n\tawait mockAgent.close();\n});\n\ntest('no token', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/simpleGet'),\n\t\t\tmethod: 'GET',\n\t\t})\n\t\t.reply(200, 'Well this is awkward...');\n\n\tconst promise = api.get('/simpleGet');\n\tawait expect(promise).rejects.toThrowError('Expected token to be set for this request, but none was present');\n\tawait expect(promise).rejects.toBeInstanceOf(Error);\n});\n\ntest('negative offset', () => {\n\tconst badREST = new REST({ offset: -5_000 });\n\n\texpect(normalizeRateLimitOffset(badREST.options.offset, 'hehe :3')).toEqual(0);\n});\n"
  },
  {
    "path": "packages/rest/__tests__/UndiciRequest.test.ts",
    "content": "import { Blob, Buffer } from 'node:buffer';\nimport { MockAgent, setGlobalDispatcher, FormData as UndiciFormData } from 'undici';\nimport type { Interceptable, MockInterceptor } from 'undici/types/mock-interceptor.js';\nimport { beforeEach, afterEach, test, expect, vitest } from 'vitest';\nimport { REST } from '../src/index.js';\nimport { makeRequest, resolveBody } from '../src/strategies/undiciRequest.js';\nimport { genPath } from './util.js';\n\nconst makeRequestMock = vitest.fn(makeRequest);\n\nconst api = new REST({ makeRequest: makeRequestMock }).setToken('A-Very-Fake-Token');\n\n// @discordjs/rest uses the `content-type` header to detect whether to parse\n// the response as JSON or as an ArrayBuffer.\nconst responseOptions: MockInterceptor.MockResponseOptions = {\n\theaders: {\n\t\t'content-type': 'application/json',\n\t},\n};\n\nlet mockAgent: MockAgent;\nlet mockPool: Interceptable;\n\nbeforeEach(() => {\n\tmockAgent = new MockAgent();\n\tmockAgent.disableNetConnect(); // prevent actual requests to Discord\n\tsetGlobalDispatcher(mockAgent); // enabled the mock client to intercept requests\n\n\tmockPool = mockAgent.get('https://discord.com');\n\tapi.setAgent(mockAgent);\n});\n\nafterEach(async () => {\n\tawait mockAgent.close();\n});\n\ntest('resolveBody', async () => {\n\tawait expect(resolveBody(null)).resolves.toEqual(null);\n\tawait expect(resolveBody(undefined)).resolves.toEqual(null);\n\tawait expect(resolveBody('Hello')).resolves.toEqual('Hello');\n\tawait expect(resolveBody(new Uint8Array([1, 2, 3]))).resolves.toStrictEqual(new Uint8Array([1, 2, 3]));\n\t// ArrayBuffers gets resolved to Uint8Array\n\tawait expect(resolveBody(new ArrayBuffer(8))).resolves.toStrictEqual(new Uint8Array(new ArrayBuffer(8)));\n\n\tconst urlSearchParams = new URLSearchParams([['a', 'b']]);\n\tawait expect(resolveBody(urlSearchParams)).resolves.toEqual(urlSearchParams.toString());\n\n\tconst dataView = new DataView(new ArrayBuffer(8));\n\tawait expect(resolveBody(dataView)).resolves.toStrictEqual(new Uint8Array(new ArrayBuffer(8)));\n\n\tconst blob = new Blob(['hello']);\n\tawait expect(resolveBody(blob)).resolves.toStrictEqual(new Uint8Array(await blob.arrayBuffer()));\n\n\tconst iterable: Iterable<Uint8Array> = {\n\t\t*[Symbol.iterator]() {\n\t\t\tfor (let index = 0; index < 3; index++) {\n\t\t\t\tyield new Uint8Array([1, 2, 3]);\n\t\t\t}\n\t\t},\n\t};\n\tawait expect(resolveBody(iterable)).resolves.toStrictEqual(Buffer.from([1, 2, 3, 1, 2, 3, 1, 2, 3]));\n\n\tconst asyncIterable: AsyncIterable<Uint8Array> = {\n\t\t[Symbol.asyncIterator]() {\n\t\t\tlet index = 0;\n\t\t\treturn {\n\t\t\t\tasync next() {\n\t\t\t\t\tif (index < 3) {\n\t\t\t\t\t\tindex++;\n\t\t\t\t\t\treturn { value: new Uint8Array([1, 2, 3]), done: false };\n\t\t\t\t\t}\n\n\t\t\t\t\treturn { value: undefined, done: true };\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t};\n\tawait expect(resolveBody(asyncIterable)).resolves.toStrictEqual(Buffer.from([1, 2, 3, 1, 2, 3, 1, 2, 3]));\n\n\t{\n\t\tconst fd = new globalThis.FormData();\n\t\tfd.append('key', 'value');\n\n\t\tconst resolved = await resolveBody(fd as UndiciFormData);\n\n\t\texpect(resolved).toBeInstanceOf(UndiciFormData);\n\t\texpect([...(resolved as UndiciFormData).entries()]).toStrictEqual([['key', 'value']]);\n\t}\n\n\t{\n\t\tconst ufd = new UndiciFormData();\n\t\tufd.append('key', 'value');\n\n\t\tconst resolved = await resolveBody(ufd);\n\n\t\texpect(resolved).toBeInstanceOf(UndiciFormData);\n\t\texpect([...(resolved as UndiciFormData).entries()]).toStrictEqual([['key', 'value']]);\n\t}\n\n\t// Unknown type\n\t// @ts-expect-error: This test is ensuring that this throws\n\tawait expect(resolveBody(true)).rejects.toThrow(TypeError);\n});\n\ntest('use passed undici request', async () => {\n\tmockPool\n\t\t.intercept({\n\t\t\tpath: genPath('/simplePost'),\n\t\t\tmethod: 'POST',\n\t\t})\n\t\t.reply(() => ({\n\t\t\tdata: { test: true },\n\t\t\tstatusCode: 200,\n\t\t\tresponseOptions,\n\t\t}));\n\n\texpect(await api.post('/simplePost')).toStrictEqual({ test: true });\n\texpect(makeRequestMock).toHaveBeenCalledTimes(1);\n});\n"
  },
  {
    "path": "packages/rest/__tests__/setup.ts",
    "content": "import { setDefaultStrategy } from '../src/environment.js';\nimport { makeRequest } from '../src/strategies/undiciRequest.js';\n\nsetDefaultStrategy(makeRequest);\n"
  },
  {
    "path": "packages/rest/__tests__/util.ts",
    "content": "import { DefaultRestOptions } from '../src/index.js';\n\nexport function genPath(path: `/${string}`) {\n\treturn `/api/v${DefaultRestOptions.version}${path}` as const;\n}\n\nexport function jsonHeaders(headers: Record<string, string> = {}) {\n\treturn {\n\t\theaders: {\n\t\t\t'content-type': 'application/json',\n\t\t\t...headers,\n\t\t},\n\t};\n}\n"
  },
  {
    "path": "packages/rest/__tests__/utils.test.ts",
    "content": "/* eslint-disable unicorn/consistent-function-scoping */\nimport { describe, test, expect } from 'vitest';\nimport type { GetRateLimitOffsetFunction, GetRetryBackoffFunction, GetTimeoutFunction } from '../src/index.js';\nimport { makeURLSearchParams } from '../src/index.js';\nimport { normalizeRateLimitOffset, normalizeRetryBackoff, normalizeTimeout } from '../src/lib/utils/utils.js';\n\ndescribe('makeURLSearchParams', () => {\n\ttest('GIVEN undefined THEN returns empty URLSearchParams', () => {\n\t\tconst params = makeURLSearchParams();\n\n\t\texpect([...params.entries()]).toEqual([]);\n\t});\n\n\ttest('GIVEN empty object THEN returns empty URLSearchParams', () => {\n\t\tconst params = makeURLSearchParams({});\n\n\t\texpect([...params.entries()]).toEqual([]);\n\t});\n\n\ttest('GIVEN a record of strings THEN returns URLSearchParams with strings', () => {\n\t\tconst params = makeURLSearchParams({ foo: 'bar', hello: 'world' });\n\n\t\texpect([...params.entries()]).toEqual([\n\t\t\t['foo', 'bar'],\n\t\t\t['hello', 'world'],\n\t\t]);\n\t});\n\n\ttest('GIVEN a record of strings with nullish values THEN returns URLSearchParams without nullish values', () => {\n\t\tconst params = makeURLSearchParams({ foo: 'bar', hello: null, one: undefined });\n\n\t\texpect([...params.entries()]).toEqual([['foo', 'bar']]);\n\t});\n\n\ttest('GIVEN a record of non-string values THEN returns URLSearchParams with string values', () => {\n\t\tconst params = makeURLSearchParams({ life: 42, big: 100n, bool: true });\n\n\t\texpect([...params.entries()]).toEqual([\n\t\t\t['life', '42'],\n\t\t\t['big', '100'],\n\t\t\t['bool', 'true'],\n\t\t]);\n\t});\n\n\tdescribe('objects', () => {\n\t\ttest('GIVEN a record of date values THEN URLSearchParams with ISO string values', () => {\n\t\t\tconst params = makeURLSearchParams({ before: new Date('2022-04-04T15:43:05.108Z'), after: new Date(Number.NaN) });\n\n\t\t\texpect([...params.entries()]).toEqual([['before', '2022-04-04T15:43:05.108Z']]);\n\t\t});\n\n\t\ttest('GIVEN a record of plain object values THEN returns empty URLSearchParams', () => {\n\t\t\tconst params = makeURLSearchParams({ foo: {}, hello: { happy: true } });\n\n\t\t\texpect([...params.entries()]).toEqual([]);\n\t\t});\n\n\t\ttest('GIVEN a record of objects with overridden toString THEN returns non-empty URLSearchParams', () => {\n\t\t\tconst params = makeURLSearchParams({ foo: { toString: () => 'bar' } });\n\n\t\t\texpect([...params.entries()]).toEqual([['foo', 'bar']]);\n\t\t});\n\t});\n\n\tdescribe('types', () => {\n\t\tinterface TestInput {\n\t\t\tfoo: string;\n\t\t}\n\n\t\ttest(\"GIVEN object without index signature THEN TypeScript doesn't raise a type error\", () => {\n\t\t\t// Previously, `makeURLSearchParams` used `Record<string, unknown>` as an input, but that meant that it\n\t\t\t// couldn't accept most interfaces, since they don't have an index signature. This test is to make sure\n\t\t\t// non-Records can be used without casting.\n\n\t\t\tconst input = { foo: 'bar' } as TestInput;\n\t\t\tconst params = makeURLSearchParams(input);\n\n\t\t\texpect([...params.entries()]).toEqual([['foo', 'bar']]);\n\t\t});\n\n\t\ttest(\"GIVEN readonly object on a non-readonly generic type THEN TypeScript doesn't raise a type error\", () => {\n\t\t\t// While `Readonly<T>` type was always accepted in `makeURLSearchParams`, this test is to ensure that we can\n\t\t\t// use the generic type and accept `Readonly<T>` rather than only [possibly] mutable `T`.\n\n\t\t\tconst input = Object.freeze({ foo: 'bar' } as TestInput);\n\t\t\tconst params = makeURLSearchParams<TestInput>(input);\n\n\t\t\texpect([...params.entries()]).toEqual([['foo', 'bar']]);\n\t\t});\n\t});\n});\n\ndescribe('option normalization functions', () => {\n\tdescribe('rate limit offset', () => {\n\t\tconst func: GetRateLimitOffsetFunction = (route) => {\n\t\t\tif (route === '/negative') return -150;\n\t\t\tif (route === '/high') return 150;\n\t\t\treturn 50;\n\t\t};\n\n\t\ttest('offset as number', () => {\n\t\t\texpect(normalizeRateLimitOffset(-150, '/negative')).toEqual(0);\n\t\t\texpect(normalizeRateLimitOffset(150, '/high')).toEqual(150);\n\t\t\texpect(normalizeRateLimitOffset(50, '/normal')).toEqual(50);\n\t\t});\n\n\t\ttest('offset as function', () => {\n\t\t\texpect(normalizeRateLimitOffset(func, '/negative')).toEqual(0);\n\t\t\texpect(normalizeRateLimitOffset(func, '/high')).toEqual(150);\n\t\t\texpect(normalizeRateLimitOffset(func, '/normal')).toEqual(50);\n\t\t});\n\t});\n\n\tdescribe('retry backoff', () => {\n\t\tconst body = {\n\t\t\tcontent: 'yo',\n\t\t};\n\t\tconst func: GetRetryBackoffFunction = (_route, statusCode, retryCount) => {\n\t\t\tif (statusCode === null) return 0;\n\t\t\tif (statusCode === 502) return 50;\n\t\t\tif (retryCount === 0) return 0;\n\t\t\tif (retryCount === 1) return 150;\n\t\t\tif (retryCount === 2) return 500;\n\t\t\treturn null;\n\t\t};\n\n\t\ttest('retry backoff as number', () => {\n\t\t\texpect(normalizeRetryBackoff(0, '/test', null, 0, body)).toEqual(0);\n\t\t\texpect(normalizeRetryBackoff(0, '/test', null, 1, body)).toEqual(0);\n\t\t\texpect(normalizeRetryBackoff(0, '/test', null, 2, body)).toEqual(0);\n\t\t\texpect(normalizeRetryBackoff(50, '/test', null, 0, body)).toEqual(50);\n\t\t\texpect(normalizeRetryBackoff(50, '/test', null, 1, body)).toEqual(100);\n\t\t\texpect(normalizeRetryBackoff(50, '/test', null, 2, body)).toEqual(200);\n\t\t});\n\n\t\ttest('retry backoff as function', () => {\n\t\t\texpect(normalizeRetryBackoff(func, '/test', null, 0, body)).toEqual(0);\n\t\t\texpect(normalizeRetryBackoff(func, '/test', 502, 0, body)).toEqual(50);\n\t\t\texpect(normalizeRetryBackoff(func, '/test', 500, 0, body)).toEqual(0);\n\t\t\texpect(normalizeRetryBackoff(func, '/test', 500, 1, body)).toEqual(150);\n\t\t\texpect(normalizeRetryBackoff(func, '/test', 500, 2, body)).toEqual(500);\n\t\t\texpect(normalizeRetryBackoff(func, '/test', 500, 3, body)).toEqual(null);\n\t\t});\n\t});\n\n\tdescribe('timeout', () => {\n\t\tconst body1 = {\n\t\t\tattachments: [{ id: 1 }],\n\t\t};\n\t\tconst body2 = {\n\t\t\tcontent: 'yo',\n\t\t};\n\t\tconst func: GetTimeoutFunction = (route, body) => {\n\t\t\tif (\n\t\t\t\ttypeof body === 'object' &&\n\t\t\t\tbody &&\n\t\t\t\t'attachments' in body &&\n\t\t\t\tArray.isArray(body.attachments) &&\n\t\t\t\tbody.attachments.length\n\t\t\t) {\n\t\t\t\treturn 1_000;\n\t\t\t}\n\n\t\t\tif (route === '/negative') return -150;\n\t\t\tif (route === '/high') return 150;\n\t\t\treturn 50;\n\t\t};\n\n\t\ttest('timeout as number', () => {\n\t\t\texpect(normalizeTimeout(-150, '/negative', body1)).toEqual(0);\n\t\t\texpect(normalizeTimeout(150, '/high', body1)).toEqual(150);\n\t\t\texpect(normalizeTimeout(50, '/normal', body1)).toEqual(50);\n\t\t});\n\n\t\ttest('timeout as function', () => {\n\t\t\texpect(normalizeTimeout(func, '/negative', body1)).toEqual(1_000);\n\t\t\texpect(normalizeTimeout(func, '/negative', body2)).toEqual(0);\n\t\t\texpect(normalizeTimeout(func, '/high', body2)).toEqual(150);\n\t\t\texpect(normalizeTimeout(func, '/normal', body2)).toEqual(50);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/rest/api-extractor.json",
    "content": "{\n\t\"extends\": \"../../api-extractor.json\",\n\t\"docModel\": {\n\t\t\"projectFolderUrl\": \"https://github.com/discordjs/discord.js/tree/main/packages/rest\"\n\t}\n}\n"
  },
  {
    "path": "packages/rest/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t\t{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length %}\\\n\t\\n### New Contributors\\n\n\t{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\\\n\t\t* @{{ contributor.username }} made their first contribution in #{{ contributor.pr_number }}\n\t{% endfor %}\\\n{% endif %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"@discordjs/rest@[0-9]*\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/rest/docs/README.md",
    "content": "## [View the documentation here.](https://discord.js.org/docs/packages/rest/main)\n"
  },
  {
    "path": "packages/rest/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/rest\",\n\t\"version\": \"2.5.0\",\n\t\"description\": \"The REST API for discord.js\",\n\t\"scripts\": {\n\t\t\"test\": \"vitest run\",\n\t\t\"build\": \"tsc --noEmit && tsup\",\n\t\t\"build:docs\": \"tsc -p tsconfig.docs.json\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src __tests__\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src __tests__\",\n\t\t\"fmt\": \"pnpm run format\",\n\t\t\"docs\": \"pnpm run build:docs && api-extractor run --local --minify && generate-split-documentation\",\n\t\t\"prepack\": \"pnpm run lint && pnpm run test && pnpm run build\",\n\t\t\"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/rest/*'\",\n\t\t\"release\": \"cliff-jumper\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"node\": {\n\t\t\t\t\"require\": {\n\t\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t\t},\n\t\t\t\t\"import\": {\n\t\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"default\": {\n\t\t\t\t\"require\": {\n\t\t\t\t\t\"types\": \"./dist/web.d.ts\",\n\t\t\t\t\t\"default\": \"./dist/web.js\"\n\t\t\t\t},\n\t\t\t\t\"import\": {\n\t\t\t\t\t\"types\": \"./dist/web.d.mts\",\n\t\t\t\t\t\"default\": \"./dist/web.mjs\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"./*\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/strategies/*.d.ts\",\n\t\t\t\t\"default\": \"./dist/strategies/*.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/strategies/*.d.mts\",\n\t\t\t\t\"default\": \"./dist/strategies/*.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"types\": \"./dist/index.d.ts\",\n\t\"directories\": {\n\t\t\"lib\": \"src\",\n\t\t\"test\": \"__tests__\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"Amish Shah <amishshah.2k@gmail.com>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"discord\",\n\t\t\"api\",\n\t\t\"rest\",\n\t\t\"discordapp\",\n\t\t\"discordjs\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/rest\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"@discordjs/collection\": \"workspace:^\",\n\t\t\"@discordjs/util\": \"workspace:^\",\n\t\t\"@sapphire/async-queue\": \"^1.5.5\",\n\t\t\"@sapphire/snowflake\": \"^3.5.5\",\n\t\t\"@vladfrangu/async_event_emitter\": \"^2.4.7\",\n\t\t\"discord-api-types\": \"^0.38.41\",\n\t\t\"magic-bytes.js\": \"^1.13.0\",\n\t\t\"tslib\": \"^2.8.1\",\n\t\t\"undici\": \"7.22.0\",\n\t\t\"uuid\": \"^13.0.0\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@discordjs/api-extractor\": \"workspace:^\",\n\t\t\"@discordjs/scripts\": \"workspace:^\",\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@types/node\": \"^22.19.11\",\n\t\t\"@vitest/coverage-v8\": \"^4.0.18\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"esbuild-plugin-version-injector\": \"^1.2.1\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vitest\": \"^4.0.18\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/rest/src/environment.ts",
    "content": "import type { RESTOptions } from './shared.js';\n\nlet defaultStrategy: RESTOptions['makeRequest'];\n\nexport function setDefaultStrategy(newStrategy: RESTOptions['makeRequest']) {\n\tdefaultStrategy = newStrategy;\n}\n\nexport function getDefaultStrategy() {\n\treturn defaultStrategy;\n}\n"
  },
  {
    "path": "packages/rest/src/index.ts",
    "content": "import { shouldUseGlobalFetchAndWebSocket } from '@discordjs/util';\nimport { setDefaultStrategy } from './environment.js';\nimport { makeRequest } from './strategies/undiciRequest.js';\n\n// This cast is needed because of a mismatch between the version of undici-types provided by @types/node and undici\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\nsetDefaultStrategy(shouldUseGlobalFetchAndWebSocket() ? (fetch as typeof import('undici').fetch) : makeRequest);\n\nexport * from './shared.js';\n"
  },
  {
    "path": "packages/rest/src/lib/CDN.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\nimport { CDNRoutes } from 'discord-api-types/v10';\nimport {\n\tALLOWED_EXTENSIONS,\n\tALLOWED_SIZES,\n\tALLOWED_STICKER_EXTENSIONS,\n\tDefaultRestOptions,\n\ttype ImageExtension,\n\ttype ImageSize,\n\ttype StickerExtension,\n} from './utils/constants.js';\n\n/**\n * The options used for image URLs.\n */\nexport interface BaseImageURLOptions {\n\t/**\n\t * The extension to use for the image URL.\n\t *\n\t * @defaultValue `'webp'`\n\t */\n\textension?: ImageExtension;\n\t/**\n\t * The size specified in the image URL.\n\t */\n\tsize?: ImageSize;\n}\n\nexport interface EmojiURLOptionsWebp extends BaseImageURLOptions {\n\t/**\n\t * Whether to use the `animated` query parameter.\n\t */\n\tanimated?: boolean;\n\textension?: 'webp';\n}\n\nexport interface EmojiURLOptionsNotWebp extends BaseImageURLOptions {\n\textension: Exclude<ImageExtension, 'webp'>;\n}\n\n/**\n * The options used for emoji URLs.\n */\nexport type EmojiURLOptions = EmojiURLOptionsNotWebp | EmojiURLOptionsWebp;\n\n/**\n * The options used for image URLs that may be animated.\n */\nexport interface ImageURLOptions extends BaseImageURLOptions {\n\t/**\n\t * Whether to prefer the static asset.\n\t */\n\tforceStatic?: boolean;\n}\n\n/**\n * The options to use when making a CDN URL\n */\ninterface MakeURLOptions {\n\t/**\n\t * The allowed extensions that can be used\n\t */\n\tallowedExtensions?: readonly string[];\n\t/**\n\t * Whether to use the `animated` query parameter\n\t */\n\tanimated?: boolean;\n\t/**\n\t * The base URL.\n\t *\n\t * @defaultValue `DefaultRestOptions.cdn`\n\t */\n\tbase?: string;\n\t/**\n\t * The extension to use for the image URL\n\t *\n\t * @defaultValue `'webp'`\n\t */\n\textension?: string | undefined;\n\t/**\n\t * The size specified in the image URL\n\t */\n\tsize?: ImageSize;\n}\n\n/**\n * Options for initializing the {@link CDN} class.\n */\nexport interface CDNOptions {\n\t/**\n\t * The base URL for the CDN.\n\t *\n\t * @defaultValue `DefaultRestOptions.cdn`\n\t */\n\tcdn?: string | undefined;\n\t/**\n\t * The base URL for the media proxy.\n\t *\n\t * @defaultValue `DefaultRestOptions.mediaProxy`\n\t */\n\tmediaProxy?: string | undefined;\n}\n\n/**\n * The CDN link builder\n */\nexport class CDN {\n\tprivate readonly cdn: string;\n\n\tprivate readonly mediaProxy: string;\n\n\tpublic constructor({ cdn, mediaProxy }: CDNOptions = {}) {\n\t\tthis.cdn = cdn ?? DefaultRestOptions.cdn;\n\t\tthis.mediaProxy = mediaProxy ?? DefaultRestOptions.mediaProxy;\n\t}\n\n\t/**\n\t * Generates an app asset URL for a client's asset.\n\t *\n\t * @param clientId - The client id that has the asset\n\t * @param assetHash - The hash provided by Discord for this asset\n\t * @param options - Optional options for the asset\n\t */\n\tpublic appAsset(clientId: string, assetHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/app-assets/${clientId}/${assetHash}`, options);\n\t}\n\n\t/**\n\t * Generates an app icon URL for a client's icon.\n\t *\n\t * @param clientId - The client id that has the icon\n\t * @param iconHash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the icon\n\t */\n\tpublic appIcon(clientId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/app-icons/${clientId}/${iconHash}`, options);\n\t}\n\n\t/**\n\t * Generates an avatar URL, e.g. for a user or a webhook.\n\t *\n\t * @param id - The id that has the icon\n\t * @param avatarHash - The hash provided by Discord for this avatar\n\t * @param options - Optional options for the avatar\n\t */\n\tpublic avatar(id: string, avatarHash: string, options?: Readonly<ImageURLOptions>): string {\n\t\treturn this.dynamicMakeURL(`/avatars/${id}/${avatarHash}`, avatarHash, options);\n\t}\n\n\t/**\n\t * Generates a user avatar decoration preset URL.\n\t *\n\t * @param asset - The avatar decoration hash\n\t */\n\tpublic avatarDecoration(asset: string): string {\n\t\treturn this.makeURL(`/avatar-decoration-presets/${asset}`, { extension: 'png' });\n\t}\n\n\t/**\n\t * Generates a banner URL, e.g. for a user or a guild.\n\t *\n\t * @param id - The id that has the banner splash\n\t * @param bannerHash - The hash provided by Discord for this banner\n\t * @param options - Optional options for the banner\n\t */\n\tpublic banner(id: string, bannerHash: string, options?: Readonly<ImageURLOptions>): string {\n\t\treturn this.dynamicMakeURL(`/banners/${id}/${bannerHash}`, bannerHash, options);\n\t}\n\n\t/**\n\t * Generates an icon URL for a channel, e.g. a group DM.\n\t *\n\t * @param channelId - The channel id that has the icon\n\t * @param iconHash - The hash provided by Discord for this channel\n\t * @param options - Optional options for the icon\n\t */\n\tpublic channelIcon(channelId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/channel-icons/${channelId}/${iconHash}`, options);\n\t}\n\n\t/**\n\t * Generates a default avatar URL\n\t *\n\t * @param index - The default avatar index\n\t * @remarks\n\t * To calculate the index for a user do `(userId >> 22) % 6`,\n\t * or `discriminator % 5` if they're using the legacy username system.\n\t */\n\tpublic defaultAvatar(index: number): string {\n\t\treturn this.makeURL(`/embed/avatars/${index}`, { extension: 'png' });\n\t}\n\n\t/**\n\t * Generates a discovery splash URL for a guild's discovery splash.\n\t *\n\t * @param guildId - The guild id that has the discovery splash\n\t * @param splashHash - The hash provided by Discord for this splash\n\t * @param options - Optional options for the splash\n\t */\n\tpublic discoverySplash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/discovery-splashes/${guildId}/${splashHash}`, options);\n\t}\n\n\t/**\n\t * Generates an emoji's URL.\n\t *\n\t * @param emojiId - The emoji id\n\t * @param options - Optional options for the emoji\n\t */\n\tpublic emoji(emojiId: string, options?: Readonly<EmojiURLOptions>): string {\n\t\treturn this.makeURL(`/emojis/${emojiId}`, options);\n\t}\n\n\t/**\n\t * Generates a guild member avatar URL.\n\t *\n\t * @param guildId - The id of the guild\n\t * @param userId - The id of the user\n\t * @param avatarHash - The hash provided by Discord for this avatar\n\t * @param options - Optional options for the avatar\n\t */\n\tpublic guildMemberAvatar(\n\t\tguildId: string,\n\t\tuserId: string,\n\t\tavatarHash: string,\n\t\toptions?: Readonly<ImageURLOptions>,\n\t): string {\n\t\treturn this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/avatars/${avatarHash}`, avatarHash, options);\n\t}\n\n\t/**\n\t * Generates a guild member banner URL.\n\t *\n\t * @param guildId - The id of the guild\n\t * @param userId - The id of the user\n\t * @param bannerHash - The hash provided by Discord for this banner\n\t * @param options - Optional options for the banner\n\t */\n\tpublic guildMemberBanner(\n\t\tguildId: string,\n\t\tuserId: string,\n\t\tbannerHash: string,\n\t\toptions?: Readonly<ImageURLOptions>,\n\t): string {\n\t\treturn this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/banners/${bannerHash}`, bannerHash, options);\n\t}\n\n\t/**\n\t * Generates an icon URL, e.g. for a guild.\n\t *\n\t * @param id - The id that has the icon splash\n\t * @param iconHash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the icon\n\t */\n\tpublic icon(id: string, iconHash: string, options?: Readonly<ImageURLOptions>): string {\n\t\treturn this.dynamicMakeURL(`/icons/${id}/${iconHash}`, iconHash, options);\n\t}\n\n\t/**\n\t * Generates a URL for the icon of a role\n\t *\n\t * @param roleId - The id of the role that has the icon\n\t * @param roleIconHash - The hash provided by Discord for this role icon\n\t * @param options - Optional options for the role icon\n\t */\n\tpublic roleIcon(roleId: string, roleIconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/role-icons/${roleId}/${roleIconHash}`, options);\n\t}\n\n\t/**\n\t * Generates a guild invite splash URL for a guild's invite splash.\n\t *\n\t * @param guildId - The guild id that has the invite splash\n\t * @param splashHash - The hash provided by Discord for this splash\n\t * @param options - Optional options for the splash\n\t */\n\tpublic splash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/splashes/${guildId}/${splashHash}`, options);\n\t}\n\n\t/**\n\t * Generates a sticker URL.\n\t *\n\t * @param stickerId - The sticker id\n\t * @param extension - The extension of the sticker\n\t * @privateRemarks\n\t * Stickers cannot have a `.webp` extension, so we default to a `.png`.\n\t * Sticker GIFs do not use the CDN base URL.\n\t */\n\tpublic sticker(stickerId: string, extension: StickerExtension = 'png'): string {\n\t\treturn this.makeURL(`/stickers/${stickerId}`, {\n\t\t\tallowedExtensions: ALLOWED_STICKER_EXTENSIONS,\n\t\t\tbase: extension === 'gif' ? this.mediaProxy : this.cdn,\n\t\t\textension,\n\t\t});\n\t}\n\n\t/**\n\t * Generates a sticker pack banner URL.\n\t *\n\t * @param bannerId - The banner id\n\t * @param options - Optional options for the banner\n\t */\n\tpublic stickerPackBanner(bannerId: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/app-assets/710982414301790216/store/${bannerId}`, options);\n\t}\n\n\t/**\n\t * Generates a team icon URL for a team's icon.\n\t *\n\t * @param teamId - The team id that has the icon\n\t * @param iconHash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the icon\n\t */\n\tpublic teamIcon(teamId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/team-icons/${teamId}/${iconHash}`, options);\n\t}\n\n\t/**\n\t * Generates a cover image for a guild scheduled event.\n\t *\n\t * @param scheduledEventId - The scheduled event id\n\t * @param coverHash - The hash provided by discord for this cover image\n\t * @param options - Optional options for the cover image\n\t */\n\tpublic guildScheduledEventCover(\n\t\tscheduledEventId: string,\n\t\tcoverHash: string,\n\t\toptions?: Readonly<BaseImageURLOptions>,\n\t): string {\n\t\treturn this.makeURL(`/guild-events/${scheduledEventId}/${coverHash}`, options);\n\t}\n\n\t/**\n\t * Generates a URL for a soundboard sound.\n\t *\n\t * @param soundId - The soundboard sound id\n\t */\n\tpublic soundboardSound(soundId: string): string {\n\t\treturn `${this.cdn}${CDNRoutes.soundboardSound(soundId)}`;\n\t}\n\n\t/**\n\t * Generates a URL for a guild tag badge.\n\t *\n\t * @param guildId - The guild id\n\t * @param badgeHash - The hash of the badge\n\t * @param options - Optional options for the badge\n\t */\n\tpublic guildTagBadge(guildId: string, badgeHash: string, options?: Readonly<BaseImageURLOptions>): string {\n\t\treturn this.makeURL(`/guild-tag-badges/${guildId}/${badgeHash}`, options);\n\t}\n\n\t/**\n\t * Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`.\n\t *\n\t * @param route - The base cdn route\n\t * @param hash - The hash provided by Discord for this icon\n\t * @param options - Optional options for the link\n\t */\n\tprivate dynamicMakeURL(\n\t\troute: string,\n\t\thash: string,\n\t\t{ forceStatic = false, ...options }: Readonly<ImageURLOptions> = {},\n\t): string {\n\t\treturn this.makeURL(route, !forceStatic && hash.startsWith('a_') ? { ...options, animated: true } : options);\n\t}\n\n\t/**\n\t * Constructs the URL for the resource\n\t *\n\t * @param route - The base cdn route\n\t * @param options - The extension/size options for the link\n\t */\n\tprivate makeURL(\n\t\troute: string,\n\t\t{\n\t\t\tallowedExtensions = ALLOWED_EXTENSIONS,\n\t\t\tbase = this.cdn,\n\t\t\textension = 'webp',\n\t\t\tsize,\n\t\t\tanimated,\n\t\t}: Readonly<MakeURLOptions> = {},\n\t): string {\n\t\t// eslint-disable-next-line no-param-reassign\n\t\textension = String(extension).toLowerCase();\n\n\t\tif (!allowedExtensions.includes(extension)) {\n\t\t\tthrow new RangeError(`Invalid extension provided: ${extension}\\nMust be one of: ${allowedExtensions.join(', ')}`);\n\t\t}\n\n\t\tif (size && !ALLOWED_SIZES.includes(size)) {\n\t\t\tthrow new RangeError(`Invalid size provided: ${size}\\nMust be one of: ${ALLOWED_SIZES.join(', ')}`);\n\t\t}\n\n\t\tconst url = new URL(`${base}${route}.${extension}`);\n\n\t\tif (animated !== undefined) {\n\t\t\turl.searchParams.set('animated', String(animated));\n\t\t}\n\n\t\tif (size) {\n\t\t\turl.searchParams.set('size', String(size));\n\t\t}\n\n\t\treturn url.toString();\n\t}\n}\n"
  },
  {
    "path": "packages/rest/src/lib/REST.ts",
    "content": "import { Collection } from '@discordjs/collection';\nimport { DiscordSnowflake } from '@sapphire/snowflake';\nimport { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';\nimport { filetypeinfo } from 'magic-bytes.js';\nimport type { RequestInit, BodyInit, Dispatcher } from 'undici';\nimport { v5 as uuidV5 } from 'uuid';\nimport { CDN } from './CDN.js';\nimport { BurstHandler } from './handlers/BurstHandler.js';\nimport { SequentialHandler } from './handlers/SequentialHandler.js';\nimport type { IHandler } from './interfaces/Handler.js';\nimport {\n\tAUTH_UUID_NAMESPACE,\n\tBurstHandlerMajorIdKey,\n\tDefaultRestOptions,\n\tDefaultUserAgent,\n\tOverwrittenMimeTypes,\n\tRESTEvents,\n} from './utils/constants.js';\nimport { RequestMethod } from './utils/types.js';\nimport type {\n\tRESTOptions,\n\tResponseLike,\n\tRestEvents,\n\tHashData,\n\tInternalRequest,\n\tRouteLike,\n\tRequestHeaders,\n\tRouteData,\n\tRequestData,\n\tAuthData,\n} from './utils/types.js';\nimport { isBufferLike, parseResponse } from './utils/utils.js';\n\n/**\n * Represents the class that manages handlers for endpoints\n */\nexport class REST extends AsyncEventEmitter<RestEvents> {\n\t/**\n\t * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} for all requests\n\t * performed by this manager.\n\t */\n\tpublic agent: Dispatcher | null = null;\n\n\tpublic readonly cdn: CDN;\n\n\t/**\n\t * The number of requests remaining in the global bucket\n\t */\n\tpublic globalRemaining: number;\n\n\t/**\n\t * The promise used to wait out the global rate limit\n\t */\n\tpublic globalDelay: Promise<void> | null = null;\n\n\t/**\n\t * The timestamp at which the global bucket resets\n\t */\n\tpublic globalReset = -1;\n\n\t/**\n\t * API bucket hashes that are cached from provided routes\n\t */\n\tpublic readonly hashes = new Collection<string, HashData>();\n\n\t/**\n\t * Request handlers created from the bucket hash and the major parameters\n\t */\n\tpublic readonly handlers = new Collection<string, IHandler>();\n\n\t#token: string | null = null;\n\n\tprivate hashTimer!: NodeJS.Timeout | number;\n\n\tprivate handlerTimer!: NodeJS.Timeout | number;\n\n\tpublic readonly options: RESTOptions;\n\n\tpublic constructor(options: Partial<RESTOptions> = {}) {\n\t\tsuper();\n\t\tthis.cdn = new CDN(options);\n\t\tthis.options = { ...DefaultRestOptions, ...options };\n\t\tthis.globalRemaining = Math.max(1, this.options.globalRequestsPerSecond);\n\t\tthis.agent = options.agent ?? null;\n\n\t\t// Start sweepers\n\t\tthis.setupSweepers();\n\t}\n\n\tprivate setupSweepers() {\n\t\t// eslint-disable-next-line unicorn/consistent-function-scoping\n\t\tconst validateMaxInterval = (interval: number) => {\n\t\t\tif (interval > 14_400_000) {\n\t\t\t\tthrow new Error('Cannot set an interval greater than 4 hours');\n\t\t\t}\n\t\t};\n\n\t\tif (this.options.hashSweepInterval !== 0 && this.options.hashSweepInterval !== Number.POSITIVE_INFINITY) {\n\t\t\tvalidateMaxInterval(this.options.hashSweepInterval);\n\t\t\tthis.hashTimer = setInterval(() => {\n\t\t\t\tconst sweptHashes = new Collection<string, HashData>();\n\t\t\t\tconst currentDate = Date.now();\n\n\t\t\t\t// Begin sweeping hash based on lifetimes\n\t\t\t\tthis.hashes.sweep((val, key) => {\n\t\t\t\t\t// `-1` indicates a global hash\n\t\t\t\t\tif (val.lastAccess === -1) return false;\n\n\t\t\t\t\t// Check if lifetime has been exceeded\n\t\t\t\t\tconst shouldSweep = Math.floor(currentDate - val.lastAccess) > this.options.hashLifetime;\n\n\t\t\t\t\t// Add hash to collection of swept hashes\n\t\t\t\t\tif (shouldSweep) {\n\t\t\t\t\t\t// Add to swept hashes\n\t\t\t\t\t\tsweptHashes.set(key, val);\n\n\t\t\t\t\t\t// Emit debug information\n\t\t\t\t\t\tthis.emit(RESTEvents.Debug, `[REST] Hash ${val.value} for ${key} swept due to lifetime being exceeded`);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn shouldSweep;\n\t\t\t\t});\n\n\t\t\t\t// Fire event\n\t\t\t\tthis.emit(RESTEvents.HashSweep, sweptHashes);\n\t\t\t}, this.options.hashSweepInterval);\n\n\t\t\tthis.hashTimer.unref?.();\n\t\t}\n\n\t\tif (this.options.handlerSweepInterval !== 0 && this.options.handlerSweepInterval !== Number.POSITIVE_INFINITY) {\n\t\t\tvalidateMaxInterval(this.options.handlerSweepInterval);\n\t\t\tthis.handlerTimer = setInterval(() => {\n\t\t\t\tconst sweptHandlers = new Collection<string, IHandler>();\n\n\t\t\t\t// Begin sweeping handlers based on activity\n\t\t\t\tthis.handlers.sweep((val, key) => {\n\t\t\t\t\tconst { inactive } = val;\n\n\t\t\t\t\t// Collect inactive handlers\n\t\t\t\t\tif (inactive) {\n\t\t\t\t\t\tsweptHandlers.set(key, val);\n\t\t\t\t\t\tthis.emit(RESTEvents.Debug, `[REST] Handler ${val.id} for ${key} swept due to being inactive`);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn inactive;\n\t\t\t\t});\n\n\t\t\t\t// Fire event\n\t\t\t\tthis.emit(RESTEvents.HandlerSweep, sweptHandlers);\n\t\t\t}, this.options.handlerSweepInterval);\n\n\t\t\tthis.handlerTimer.unref?.();\n\t\t}\n\t}\n\n\t/**\n\t * Runs a get request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async get(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Get });\n\t}\n\n\t/**\n\t * Runs a delete request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async delete(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Delete });\n\t}\n\n\t/**\n\t * Runs a post request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async post(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Post });\n\t}\n\n\t/**\n\t * Runs a put request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async put(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Put });\n\t}\n\n\t/**\n\t * Runs a patch request from the api\n\t *\n\t * @param fullRoute - The full route to query\n\t * @param options - Optional request options\n\t */\n\tpublic async patch(fullRoute: RouteLike, options: RequestData = {}) {\n\t\treturn this.request({ ...options, fullRoute, method: RequestMethod.Patch });\n\t}\n\n\t/**\n\t * Runs a request from the api\n\t *\n\t * @param options - Request options\n\t */\n\tpublic async request(options: InternalRequest) {\n\t\tconst response = await this.queueRequest(options);\n\t\treturn parseResponse(response);\n\t}\n\n\t/**\n\t * Sets the default agent to use for requests performed by this manager\n\t *\n\t * @param agent - The agent to use\n\t */\n\tpublic setAgent(agent: Dispatcher) {\n\t\tthis.agent = agent;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the authorization token that should be used for requests\n\t *\n\t * @param token - The authorization token to use\n\t */\n\tpublic setToken(token: string) {\n\t\tthis.#token = token;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Queues a request to be sent\n\t *\n\t * @param request - All the information needed to make a request\n\t * @returns The response from the api request\n\t */\n\tpublic async queueRequest(request: InternalRequest): Promise<ResponseLike> {\n\t\t// Generalize the endpoint to its route data\n\t\tconst routeId = REST.generateRouteData(request.fullRoute, request.method);\n\t\tconst customAuth = typeof request.auth === 'object' && request.auth.token !== this.#token;\n\t\tconst auth = customAuth ? uuidV5((request.auth as AuthData).token, AUTH_UUID_NAMESPACE) : request.auth !== false;\n\t\t// Get the bucket hash for the generic route, or point to a global route otherwise\n\t\tconst hash = this.hashes.get(`${request.method}:${routeId.bucketRoute}${customAuth ? `:${auth}` : ''}`) ?? {\n\t\t\tvalue: `Global(${request.method}:${routeId.bucketRoute}${customAuth ? `:${auth}` : ''})`,\n\t\t\tlastAccess: -1,\n\t\t};\n\n\t\t// Get the request handler for the obtained hash, with its major parameter\n\t\tconst handler =\n\t\t\tthis.handlers.get(`${hash.value}:${routeId.majorParameter}`) ??\n\t\t\tthis.createHandler(hash.value, routeId.majorParameter);\n\n\t\t// Resolve the request into usable fetch options\n\t\tconst { url, fetchOptions } = await this.resolveRequest(request);\n\n\t\t// Queue the request\n\t\treturn handler.queueRequest(routeId, url, fetchOptions, {\n\t\t\tbody: request.body,\n\t\t\tfiles: request.files,\n\t\t\tauth,\n\t\t\tsignal: request.signal,\n\t\t});\n\t}\n\n\t/**\n\t * Creates a new rate limit handler from a hash, based on the hash and the major parameter\n\t *\n\t * @param hash - The hash for the route\n\t * @param majorParameter - The major parameter for this handler\n\t * @internal\n\t */\n\tprivate createHandler(hash: string, majorParameter: string) {\n\t\t// Create the async request queue to handle requests\n\t\tconst queue =\n\t\t\tmajorParameter === BurstHandlerMajorIdKey\n\t\t\t\t? new BurstHandler(this, hash, majorParameter)\n\t\t\t\t: new SequentialHandler(this, hash, majorParameter);\n\t\t// Save the queue based on its id\n\t\tthis.handlers.set(queue.id, queue);\n\n\t\treturn queue;\n\t}\n\n\t/**\n\t * Formats the request data to a usable format for fetch\n\t *\n\t * @param request - The request data\n\t */\n\tprivate async resolveRequest(request: InternalRequest): Promise<{ fetchOptions: RequestInit; url: string }> {\n\t\tconst { options } = this;\n\n\t\tlet query = '';\n\n\t\t// If a query option is passed, use it\n\t\tif (request.query) {\n\t\t\tconst resolvedQuery = request.query.toString();\n\t\t\tif (resolvedQuery !== '') {\n\t\t\t\tquery = `?${resolvedQuery}`;\n\t\t\t}\n\t\t}\n\n\t\t// Create the required headers\n\t\tconst headers: RequestHeaders = {\n\t\t\t...this.options.headers,\n\t\t\t'User-Agent': `${DefaultUserAgent} ${options.userAgentAppendix}`.trim(),\n\t\t};\n\n\t\t// If this request requires authorization (allowing non-\"authorized\" requests for webhooks)\n\t\tif (request.auth !== false) {\n\t\t\tif (typeof request.auth === 'object') {\n\t\t\t\theaders.Authorization = `${request.auth.prefix ?? this.options.authPrefix} ${request.auth.token}`;\n\t\t\t} else {\n\t\t\t\t// If we haven't received a token, throw an error\n\t\t\t\tif (!this.#token) {\n\t\t\t\t\tthrow new Error('Expected token to be set for this request, but none was present');\n\t\t\t\t}\n\n\t\t\t\theaders.Authorization = `${this.options.authPrefix} ${this.#token}`;\n\t\t\t}\n\t\t}\n\n\t\t// If a reason was set, set its appropriate header\n\t\tif (request.reason?.length) {\n\t\t\theaders['X-Audit-Log-Reason'] = encodeURIComponent(request.reason);\n\t\t}\n\n\t\t// Format the full request URL (api base, optional version, endpoint, optional querystring)\n\t\tconst url = `${options.api}${request.versioned === false ? '' : `/v${options.version}`}${\n\t\t\trequest.fullRoute\n\t\t}${query}`;\n\n\t\tlet finalBody: RequestInit['body'];\n\t\tlet additionalHeaders: Record<string, string> = {};\n\n\t\tif (request.files?.length) {\n\t\t\tconst formData = new FormData();\n\n\t\t\t// Attach all files to the request\n\t\t\tfor (const [index, file] of request.files.entries()) {\n\t\t\t\tconst fileKey = file.key ?? `files[${index}]`;\n\n\t\t\t\t// https://developer.mozilla.org/docs/Web/API/FormData/append#parameters\n\t\t\t\t// FormData.append only accepts a string or Blob.\n\t\t\t\t// https://developer.mozilla.org/docs/Web/API/Blob/Blob#parameters\n\t\t\t\t// The Blob constructor accepts TypedArray/ArrayBuffer, strings, and Blobs.\n\t\t\t\tif (isBufferLike(file.data)) {\n\t\t\t\t\t// Try to infer the content type from the buffer if one isn't passed\n\t\t\t\t\tlet contentType = file.contentType;\n\n\t\t\t\t\tif (!contentType) {\n\t\t\t\t\t\tconst [parsedType] = filetypeinfo(file.data);\n\n\t\t\t\t\t\tif (parsedType) {\n\t\t\t\t\t\t\tcontentType =\n\t\t\t\t\t\t\t\tOverwrittenMimeTypes[parsedType.mime as keyof typeof OverwrittenMimeTypes] ??\n\t\t\t\t\t\t\t\tparsedType.mime ??\n\t\t\t\t\t\t\t\t'application/octet-stream';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tformData.append(fileKey, new Blob([file.data], { type: contentType }), file.name);\n\t\t\t\t} else {\n\t\t\t\t\tformData.append(fileKey, new Blob([`${file.data}`], { type: file.contentType }), file.name);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If a JSON body was added as well, attach it to the form data, using payload_json unless otherwise specified\n\t\t\t// eslint-disable-next-line no-eq-null, eqeqeq\n\t\t\tif (request.body != null) {\n\t\t\t\tif (request.appendToFormData) {\n\t\t\t\t\tfor (const [key, value] of Object.entries(request.body as Record<string, unknown>)) {\n\t\t\t\t\t\tformData.append(key, value);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tformData.append('payload_json', JSON.stringify(request.body));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set the final body to the form data\n\t\t\tfinalBody = formData;\n\n\t\t\t// eslint-disable-next-line no-eq-null, eqeqeq\n\t\t} else if (request.body != null) {\n\t\t\tif (request.passThroughBody) {\n\t\t\t\tfinalBody = request.body as BodyInit;\n\t\t\t} else {\n\t\t\t\t// Stringify the JSON data\n\t\t\t\tfinalBody = JSON.stringify(request.body);\n\t\t\t\t// Set the additional headers to specify the content-type\n\t\t\t\tadditionalHeaders = { 'Content-Type': 'application/json' };\n\t\t\t}\n\t\t}\n\n\t\tconst method = request.method.toUpperCase();\n\n\t\t// The non null assertions in the following block are due to exactOptionalPropertyTypes, they have been tested to work with undefined\n\t\tconst fetchOptions: RequestInit = {\n\t\t\t// Set body to null on get / head requests. This does not follow fetch spec (likely because it causes subtle bugs) but is aligned with what request was doing\n\t\t\tbody: ['GET', 'HEAD'].includes(method) ? null : finalBody!,\n\t\t\theaders: { ...request.headers, ...additionalHeaders, ...headers } as Record<string, string>,\n\t\t\tmethod,\n\t\t\t// Prioritize setting an agent per request, use the agent for this instance otherwise.\n\t\t\tdispatcher: request.dispatcher ?? this.agent ?? undefined!,\n\t\t};\n\n\t\treturn { url, fetchOptions };\n\t}\n\n\t/**\n\t * Stops the hash sweeping interval\n\t */\n\tpublic clearHashSweeper() {\n\t\tclearInterval(this.hashTimer);\n\t}\n\n\t/**\n\t * Stops the request handler sweeping interval\n\t */\n\tpublic clearHandlerSweeper() {\n\t\tclearInterval(this.handlerTimer);\n\t}\n\n\t/**\n\t * Generates route data for an endpoint:method\n\t *\n\t * @param endpoint - The raw endpoint to generalize\n\t * @param method - The HTTP method this endpoint is called without\n\t * @internal\n\t */\n\tprivate static generateRouteData(endpoint: RouteLike, method: RequestMethod): RouteData {\n\t\tif (endpoint.startsWith('/interactions/') && endpoint.endsWith('/callback')) {\n\t\t\treturn {\n\t\t\t\tmajorParameter: BurstHandlerMajorIdKey,\n\t\t\t\tbucketRoute: '/interactions/:id/:token/callback',\n\t\t\t\toriginal: endpoint,\n\t\t\t};\n\t\t}\n\n\t\tconst majorIdMatch = /(?:^\\/webhooks\\/(\\d{17,19}\\/[^/?]+))|(?:^\\/(?:channels|guilds|webhooks)\\/(\\d{17,19}))/.exec(\n\t\t\tendpoint,\n\t\t);\n\n\t\t// Get the major id or id + token for this route - global otherwise\n\t\tconst majorId = majorIdMatch?.[2] ?? majorIdMatch?.[1] ?? 'global';\n\n\t\tconst baseRoute = endpoint\n\t\t\t// Strip out all ids\n\t\t\t.replaceAll(/\\d{17,19}/g, ':id')\n\t\t\t// Strip out reaction as they fall under the same bucket\n\t\t\t.replace(/\\/reactions\\/(.*)/, '/reactions/:reaction')\n\t\t\t// Strip out webhook tokens\n\t\t\t.replace(/\\/webhooks\\/:id\\/[^/?]+/, '/webhooks/:id/:token');\n\n\t\tlet exceptions = '';\n\n\t\t// Hard-Code Old Message Deletion Exception (2 week+ old messages are a different bucket)\n\t\t// https://github.com/discord/discord-api-docs/issues/1295\n\t\tif (method === RequestMethod.Delete && baseRoute === '/channels/:id/messages/:id') {\n\t\t\tconst id = /\\d{17,19}$/.exec(endpoint)![0]!;\n\t\t\tconst timestamp = DiscordSnowflake.timestampFrom(id);\n\t\t\tif (Date.now() - timestamp > 1_000 * 60 * 60 * 24 * 14) {\n\t\t\t\texceptions += '/Delete Old Message';\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tmajorParameter: majorId,\n\t\t\tbucketRoute: baseRoute + exceptions,\n\t\t\toriginal: endpoint,\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "packages/rest/src/lib/errors/DiscordAPIError.ts",
    "content": "import type { InternalRequest, RawFile } from '../utils/types.js';\n\nexport interface DiscordErrorFieldInformation {\n\tcode: string;\n\tmessage: string;\n}\n\nexport interface DiscordErrorGroupWrapper {\n\t_errors: DiscordError[];\n}\n\nexport type DiscordError =\n\t| DiscordErrorFieldInformation\n\t| DiscordErrorGroupWrapper\n\t| string\n\t| { [k: string]: DiscordError };\n\nexport interface DiscordErrorData {\n\tcode: number;\n\terrors?: DiscordError;\n\tmessage: string;\n}\n\nexport interface OAuthErrorData {\n\terror: string;\n\terror_description?: string;\n}\n\nexport interface RequestBody {\n\tfiles: RawFile[] | undefined;\n\tjson: unknown | undefined;\n}\n\nfunction isErrorGroupWrapper(error: DiscordError): error is DiscordErrorGroupWrapper {\n\treturn Reflect.has(error as Record<string, unknown>, '_errors');\n}\n\nfunction isErrorResponse(error: DiscordError): error is DiscordErrorFieldInformation {\n\treturn typeof Reflect.get(error as Record<string, unknown>, 'message') === 'string';\n}\n\n/**\n * Represents an API error returned by Discord\n */\nexport class DiscordAPIError extends Error {\n\tpublic requestBody: RequestBody;\n\n\t/**\n\t * @param rawError - The error reported by Discord\n\t * @param code - The error code reported by Discord\n\t * @param status - The status code of the response\n\t * @param method - The method of the request that errored\n\t * @param url - The url of the request that errored\n\t * @param bodyData - The unparsed data for the request that errored\n\t */\n\tpublic constructor(\n\t\tpublic rawError: DiscordErrorData | OAuthErrorData,\n\t\tpublic code: number | string,\n\t\tpublic status: number,\n\t\tpublic method: string,\n\t\tpublic url: string,\n\t\tbodyData: Pick<InternalRequest, 'body' | 'files'>,\n\t) {\n\t\tsuper(DiscordAPIError.getMessage(rawError));\n\n\t\tthis.requestBody = { files: bodyData.files, json: bodyData.body };\n\t}\n\n\t/**\n\t * The name of the error\n\t */\n\tpublic override get name(): string {\n\t\treturn `${DiscordAPIError.name}[${this.code}]`;\n\t}\n\n\tprivate static getMessage(error: DiscordErrorData | OAuthErrorData) {\n\t\tlet flattened = '';\n\t\tif ('code' in error) {\n\t\t\tif (error.errors) {\n\t\t\t\tflattened = [...this.flattenDiscordError(error.errors)].join('\\n');\n\t\t\t}\n\n\t\t\treturn error.message && flattened\n\t\t\t\t? `${error.message}\\n${flattened}`\n\t\t\t\t: error.message || flattened || 'Unknown Error';\n\t\t}\n\n\t\treturn error.error_description ?? 'No Description';\n\t}\n\n\tprivate static *flattenDiscordError(obj: DiscordError, key = ''): IterableIterator<string> {\n\t\tif (isErrorResponse(obj)) {\n\t\t\treturn yield `${key.length ? `${key}[${obj.code}]` : `${obj.code}`}: ${obj.message}`.trim();\n\t\t}\n\n\t\tfor (const [otherKey, val] of Object.entries(obj)) {\n\t\t\tconst nextKey = otherKey.startsWith('_')\n\t\t\t\t? key\n\t\t\t\t: key\n\t\t\t\t\t? Number.isNaN(Number(otherKey))\n\t\t\t\t\t\t? `${key}.${otherKey}`\n\t\t\t\t\t\t: `${key}[${otherKey}]`\n\t\t\t\t\t: otherKey;\n\n\t\t\tif (typeof val === 'string') {\n\t\t\t\tyield val;\n\t\t\t} else if (isErrorGroupWrapper(val)) {\n\t\t\t\tfor (const error of val._errors) {\n\t\t\t\t\tyield* this.flattenDiscordError(error, nextKey);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tyield* this.flattenDiscordError(val, nextKey);\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/rest/src/lib/errors/HTTPError.ts",
    "content": "import type { InternalRequest } from '../utils/types.js';\nimport type { RequestBody } from './DiscordAPIError.js';\n\n/**\n * Represents a HTTP error\n */\nexport class HTTPError extends Error {\n\tpublic requestBody: RequestBody;\n\n\tpublic override name = HTTPError.name;\n\n\t/**\n\t * @param status - The status code of the response\n\t * @param statusText - The status text of the response\n\t * @param method - The method of the request that errored\n\t * @param url - The url of the request that errored\n\t * @param bodyData - The unparsed data for the request that errored\n\t */\n\tpublic constructor(\n\t\tpublic status: number,\n\t\tstatusText: string,\n\t\tpublic method: string,\n\t\tpublic url: string,\n\t\tbodyData: Pick<InternalRequest, 'body' | 'files'>,\n\t) {\n\t\tsuper(statusText);\n\t\tthis.requestBody = { files: bodyData.files, json: bodyData.body };\n\t}\n}\n"
  },
  {
    "path": "packages/rest/src/lib/errors/RateLimitError.ts",
    "content": "import type { RateLimitData } from '../utils/types.js';\n\nexport class RateLimitError extends Error implements RateLimitData {\n\tpublic timeToReset: number;\n\n\tpublic limit: number;\n\n\tpublic method: string;\n\n\tpublic hash: string;\n\n\tpublic url: string;\n\n\tpublic route: string;\n\n\tpublic majorParameter: string;\n\n\tpublic global: boolean;\n\n\tpublic retryAfter: number;\n\n\tpublic sublimitTimeout: number;\n\n\tpublic scope: RateLimitData['scope'];\n\n\tpublic constructor(data: RateLimitData) {\n\t\tsuper();\n\t\tthis.timeToReset = data.timeToReset;\n\t\tthis.limit = data.limit;\n\t\tthis.method = data.method;\n\t\tthis.hash = data.hash;\n\t\tthis.url = data.url;\n\t\tthis.route = data.route;\n\t\tthis.majorParameter = data.majorParameter;\n\t\tthis.global = data.global;\n\t\tthis.retryAfter = data.retryAfter;\n\t\tthis.sublimitTimeout = data.sublimitTimeout;\n\t\tthis.scope = data.scope;\n\t}\n\n\t/**\n\t * The name of the error\n\t */\n\tpublic override get name(): string {\n\t\treturn `${RateLimitError.name}[${this.route}]`;\n\t}\n}\n"
  },
  {
    "path": "packages/rest/src/lib/handlers/BurstHandler.ts",
    "content": "import type { RequestInit } from 'undici';\nimport type { REST } from '../REST.js';\nimport type { IHandler } from '../interfaces/Handler.js';\nimport { RESTEvents } from '../utils/constants.js';\nimport type { ResponseLike, HandlerRequestData, RouteData, RateLimitData } from '../utils/types.js';\nimport { normalizeRateLimitOffset, onRateLimit, sleep } from '../utils/utils.js';\nimport { handleErrors, incrementInvalidCount, makeNetworkRequest } from './Shared.js';\n\n/**\n * The structure used to handle burst requests for a given bucket.\n * Burst requests have no ratelimit handling but allow for pre- and post-processing\n * of data in the same manner as sequentially queued requests.\n *\n * @remarks\n * This queue may still emit a rate limit error if an unexpected 429 is hit\n */\nexport class BurstHandler implements IHandler {\n\t/**\n\t * {@inheritdoc IHandler.id}\n\t */\n\tpublic readonly id: string;\n\n\t/**\n\t * {@inheritDoc IHandler.inactive}\n\t */\n\tpublic inactive = false;\n\n\t/**\n\t * @param manager - The request manager\n\t * @param hash - The hash that this RequestHandler handles\n\t * @param majorParameter - The major parameter for this handler\n\t */\n\tpublic constructor(\n\t\tprivate readonly manager: REST,\n\t\tprivate readonly hash: string,\n\t\tprivate readonly majorParameter: string,\n\t) {\n\t\tthis.id = `${hash}:${majorParameter}`;\n\t}\n\n\t/**\n\t * Emits a debug message\n\t *\n\t * @param message - The message to debug\n\t */\n\tprivate debug(message: string) {\n\t\tthis.manager.emit(RESTEvents.Debug, `[REST ${this.id}] ${message}`);\n\t}\n\n\t/**\n\t * {@inheritDoc IHandler.queueRequest}\n\t */\n\tpublic async queueRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t): Promise<ResponseLike> {\n\t\treturn this.runRequest(routeId, url, options, requestData);\n\t}\n\n\t/**\n\t * The method that actually makes the request to the API, and updates info about the bucket accordingly\n\t *\n\t * @param routeId - The generalized API route with literal ids for major parameters\n\t * @param url - The fully resolved URL to make the request to\n\t * @param options - The fetch options needed to make the request\n\t * @param requestData - Extra data from the user's request needed for errors and additional processing\n\t * @param retries - The number of retries this request has already attempted (recursion)\n\t */\n\tprivate async runRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t\tretries = 0,\n\t): Promise<ResponseLike> {\n\t\tconst method = options.method ?? 'get';\n\n\t\tconst res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries);\n\n\t\t// Retry requested\n\t\tif (res === null) {\n\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t}\n\n\t\tconst status = res.status;\n\t\tlet retryAfter = 0;\n\t\tconst retry = res.headers.get('Retry-After');\n\n\t\t// Amount of time in milliseconds until we should retry if rate limited (globally or otherwise)\n\t\tconst offset = normalizeRateLimitOffset(this.manager.options.offset, routeId.bucketRoute);\n\t\tif (retry) retryAfter = Number(retry) * 1_000 + offset;\n\n\t\t// Count the invalid requests\n\t\tif (status === 401 || status === 403 || status === 429) {\n\t\t\tincrementInvalidCount(this.manager);\n\t\t}\n\n\t\tif (status >= 200 && status < 300) {\n\t\t\treturn res;\n\t\t} else if (status === 429) {\n\t\t\t// Unexpected ratelimit\n\t\t\tconst isGlobal = res.headers.has('X-RateLimit-Global');\n\t\t\tconst scope = (res.headers.get('X-RateLimit-Scope') ?? 'user') as RateLimitData['scope'];\n\n\t\t\tawait onRateLimit(this.manager, {\n\t\t\t\tglobal: isGlobal,\n\t\t\t\tmethod,\n\t\t\t\turl,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\tmajorParameter: this.majorParameter,\n\t\t\t\thash: this.hash,\n\t\t\t\tlimit: Number.POSITIVE_INFINITY,\n\t\t\t\ttimeToReset: retryAfter,\n\t\t\t\tretryAfter,\n\t\t\t\tsublimitTimeout: 0,\n\t\t\t\tscope,\n\t\t\t});\n\n\t\t\tthis.debug(\n\t\t\t\t[\n\t\t\t\t\t'Encountered unexpected 429 rate limit',\n\t\t\t\t\t`  Global         : ${isGlobal}`,\n\t\t\t\t\t`  Method         : ${method}`,\n\t\t\t\t\t`  URL            : ${url}`,\n\t\t\t\t\t`  Bucket         : ${routeId.bucketRoute}`,\n\t\t\t\t\t`  Major parameter: ${routeId.majorParameter}`,\n\t\t\t\t\t`  Hash           : ${this.hash}`,\n\t\t\t\t\t`  Limit          : ${Number.POSITIVE_INFINITY}`,\n\t\t\t\t\t`  Retry After    : ${retryAfter}ms`,\n\t\t\t\t\t`  Sublimit       : None`,\n\t\t\t\t\t`  Scope          : ${scope}`,\n\t\t\t\t].join('\\n'),\n\t\t\t);\n\n\t\t\t// We are bypassing all other limits, but an encountered limit should be respected (it's probably a non-punished rate limit anyways)\n\t\t\tawait sleep(retryAfter);\n\n\t\t\t// Since this is not a server side issue, the next request should pass, so we don't bump the retries counter\n\t\t\treturn this.runRequest(routeId, url, options, requestData, retries);\n\t\t} else {\n\t\t\tconst handled = await handleErrors(this.manager, res, method, url, requestData, retries, routeId);\n\t\t\tif (handled === null) {\n\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t\t}\n\n\t\t\treturn handled;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/rest/src/lib/handlers/SequentialHandler.ts",
    "content": "import { AsyncQueue } from '@sapphire/async-queue';\nimport type { RequestInit } from 'undici';\nimport type { REST } from '../REST.js';\nimport type { IHandler } from '../interfaces/Handler.js';\nimport { RESTEvents } from '../utils/constants.js';\nimport type { RateLimitData, ResponseLike, HandlerRequestData, RouteData } from '../utils/types.js';\nimport { hasSublimit, normalizeRateLimitOffset, onRateLimit, sleep } from '../utils/utils.js';\nimport { handleErrors, incrementInvalidCount, makeNetworkRequest } from './Shared.js';\n\nconst enum QueueType {\n\tStandard,\n\tSublimit,\n}\n\n/**\n * The structure used to handle sequential requests for a given bucket\n */\nexport class SequentialHandler implements IHandler {\n\t/**\n\t * {@inheritDoc IHandler.id}\n\t */\n\tpublic readonly id: string;\n\n\t/**\n\t * The time this rate limit bucket will reset\n\t */\n\tprivate reset = -1;\n\n\t/**\n\t * The remaining requests that can be made before we are rate limited\n\t */\n\tprivate remaining = 1;\n\n\t/**\n\t * The total number of requests that can be made before we are rate limited\n\t */\n\tprivate limit = Number.POSITIVE_INFINITY;\n\n\t/**\n\t * The interface used to sequence async requests sequentially\n\t */\n\t#asyncQueue = new AsyncQueue();\n\n\t/**\n\t * The interface used to sequence sublimited async requests sequentially\n\t */\n\t#sublimitedQueue: AsyncQueue | null = null;\n\n\t/**\n\t * A promise wrapper for when the sublimited queue is finished being processed or null when not being processed\n\t */\n\t#sublimitPromise: { promise: Promise<void>; resolve(): void } | null = null;\n\n\t/**\n\t * Whether the sublimit queue needs to be shifted in the finally block\n\t */\n\t#shiftSublimit = false;\n\n\t/**\n\t * @param manager - The request manager\n\t * @param hash - The hash that this RequestHandler handles\n\t * @param majorParameter - The major parameter for this handler\n\t */\n\tpublic constructor(\n\t\tprivate readonly manager: REST,\n\t\tprivate readonly hash: string,\n\t\tprivate readonly majorParameter: string,\n\t) {\n\t\tthis.id = `${hash}:${majorParameter}`;\n\t}\n\n\t/**\n\t * {@inheritDoc IHandler.inactive}\n\t */\n\tpublic get inactive(): boolean {\n\t\treturn (\n\t\t\tthis.#asyncQueue.remaining === 0 &&\n\t\t\t(this.#sublimitedQueue === null || this.#sublimitedQueue.remaining === 0) &&\n\t\t\t!this.limited\n\t\t);\n\t}\n\n\t/**\n\t * If the rate limit bucket is currently limited by the global limit\n\t */\n\tprivate get globalLimited(): boolean {\n\t\treturn this.manager.globalRemaining <= 0 && Date.now() < this.manager.globalReset;\n\t}\n\n\t/**\n\t * If the rate limit bucket is currently limited by its limit\n\t */\n\tprivate get localLimited(): boolean {\n\t\treturn this.remaining <= 0 && Date.now() < this.reset;\n\t}\n\n\t/**\n\t * If the rate limit bucket is currently limited\n\t */\n\tprivate get limited(): boolean {\n\t\treturn this.globalLimited || this.localLimited;\n\t}\n\n\t/**\n\t * The time until queued requests can continue\n\t */\n\tprivate getTimeToReset(routeId: RouteData): number {\n\t\tconst offset = normalizeRateLimitOffset(this.manager.options.offset, routeId.bucketRoute);\n\t\treturn this.reset + offset - Date.now();\n\t}\n\n\t/**\n\t * Emits a debug message\n\t *\n\t * @param message - The message to debug\n\t */\n\tprivate debug(message: string) {\n\t\tthis.manager.emit(RESTEvents.Debug, `[REST ${this.id}] ${message}`);\n\t}\n\n\t/**\n\t * Delay all requests for the specified amount of time, handling global rate limits\n\t *\n\t * @param time - The amount of time to delay all requests for\n\t */\n\tprivate async globalDelayFor(time: number): Promise<void> {\n\t\tawait sleep(time);\n\t\tthis.manager.globalDelay = null;\n\t}\n\n\t/**\n\t * {@inheritDoc IHandler.queueRequest}\n\t */\n\tpublic async queueRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t): Promise<ResponseLike> {\n\t\tlet queue = this.#asyncQueue;\n\t\tlet queueType = QueueType.Standard;\n\t\t// Separate sublimited requests when already sublimited\n\t\tif (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) {\n\t\t\tqueue = this.#sublimitedQueue!;\n\t\t\tqueueType = QueueType.Sublimit;\n\t\t}\n\n\t\t// Wait for any previous requests to be completed before this one is run\n\t\tawait queue.wait({ signal: requestData.signal });\n\t\t// This set handles retroactively sublimiting requests\n\t\tif (queueType === QueueType.Standard) {\n\t\t\tif (this.#sublimitedQueue && hasSublimit(routeId.bucketRoute, requestData.body, options.method)) {\n\t\t\t\t/**\n\t\t\t\t * Remove the request from the standard queue, it should never be possible to get here while processing the\n\t\t\t\t * sublimit queue so there is no need to worry about shifting the wrong request\n\t\t\t\t */\n\t\t\t\tqueue = this.#sublimitedQueue!;\n\t\t\t\tconst wait = queue.wait();\n\t\t\t\tthis.#asyncQueue.shift();\n\t\t\t\tawait wait;\n\t\t\t} else if (this.#sublimitPromise) {\n\t\t\t\t// Stall requests while the sublimit queue gets processed\n\t\t\t\tawait this.#sublimitPromise.promise;\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\t// Make the request, and return the results\n\t\t\treturn await this.runRequest(routeId, url, options, requestData);\n\t\t} finally {\n\t\t\t// Allow the next request to fire\n\t\t\tqueue.shift();\n\t\t\tif (this.#shiftSublimit) {\n\t\t\t\tthis.#shiftSublimit = false;\n\t\t\t\tthis.#sublimitedQueue?.shift();\n\t\t\t}\n\n\t\t\t// If this request is the last request in a sublimit\n\t\t\tif (this.#sublimitedQueue?.remaining === 0) {\n\t\t\t\tthis.#sublimitPromise?.resolve();\n\t\t\t\tthis.#sublimitedQueue = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * The method that actually makes the request to the api, and updates info about the bucket accordingly\n\t *\n\t * @param routeId - The generalized api route with literal ids for major parameters\n\t * @param url - The fully resolved url to make the request to\n\t * @param options - The fetch options needed to make the request\n\t * @param requestData - Extra data from the user's request needed for errors and additional processing\n\t * @param retries - The number of retries this request has already attempted (recursion)\n\t */\n\tprivate async runRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t\tretries = 0,\n\t): Promise<ResponseLike> {\n\t\t/*\n\t\t * After calculations have been done, pre-emptively stop further requests\n\t\t * Potentially loop until this task can run if e.g. the global rate limit is hit twice\n\t\t */\n\t\twhile (this.limited) {\n\t\t\tconst isGlobal = this.globalLimited;\n\t\t\tlet limit: number;\n\t\t\tlet timeout: number;\n\t\t\tlet delay: Promise<void>;\n\n\t\t\tif (isGlobal) {\n\t\t\t\tconst offset = normalizeRateLimitOffset(this.manager.options.offset, routeId.bucketRoute);\n\n\t\t\t\t// Set RateLimitData based on the global limit\n\t\t\t\tlimit = this.manager.options.globalRequestsPerSecond;\n\t\t\t\ttimeout = this.manager.globalReset + offset - Date.now();\n\t\t\t\t// If this is the first task to reach the global timeout, set the global delay\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\t\t\tif (!this.manager.globalDelay) {\n\t\t\t\t\t// The global delay function clears the global delay state when it is resolved\n\t\t\t\t\tthis.manager.globalDelay = this.globalDelayFor(timeout);\n\t\t\t\t}\n\n\t\t\t\tdelay = this.manager.globalDelay;\n\t\t\t} else {\n\t\t\t\t// Set RateLimitData based on the route-specific limit\n\t\t\t\tlimit = this.limit;\n\t\t\t\ttimeout = this.getTimeToReset(routeId);\n\t\t\t\tdelay = sleep(timeout);\n\t\t\t}\n\n\t\t\tconst rateLimitData: RateLimitData = {\n\t\t\t\tglobal: isGlobal,\n\t\t\t\tmethod: options.method ?? 'get',\n\t\t\t\turl,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\tmajorParameter: this.majorParameter,\n\t\t\t\thash: this.hash,\n\t\t\t\tlimit,\n\t\t\t\ttimeToReset: timeout,\n\t\t\t\tretryAfter: timeout,\n\t\t\t\tsublimitTimeout: 0,\n\t\t\t\tscope: 'user',\n\t\t\t};\n\n\t\t\t// Let library users know they have hit a rate limit\n\t\t\tthis.manager.emit(RESTEvents.RateLimited, rateLimitData);\n\t\t\t// Determine whether a RateLimitError should be thrown\n\t\t\tawait onRateLimit(this.manager, rateLimitData);\n\n\t\t\t// When not erroring, emit debug for what is happening\n\t\t\tif (isGlobal) {\n\t\t\t\tthis.debug(`Global rate limit hit, blocking all requests for ${timeout}ms`);\n\t\t\t} else {\n\t\t\t\tthis.debug(`Waiting ${timeout}ms for rate limit to pass`);\n\t\t\t}\n\n\t\t\t// Wait the remaining time left before the rate limit resets\n\t\t\tawait delay;\n\t\t}\n\n\t\t// As the request goes out, update the global usage information\n\t\tif (!this.manager.globalReset || this.manager.globalReset < Date.now()) {\n\t\t\tthis.manager.globalReset = Date.now() + 1_000;\n\t\t\tthis.manager.globalRemaining = this.manager.options.globalRequestsPerSecond;\n\t\t}\n\n\t\tthis.manager.globalRemaining--;\n\n\t\tconst method = options.method ?? 'get';\n\n\t\tconst res = await makeNetworkRequest(this.manager, routeId, url, options, requestData, retries);\n\n\t\t// Retry requested\n\t\tif (res === null) {\n\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t}\n\n\t\tconst status = res.status;\n\t\tlet retryAfter = 0;\n\n\t\tconst limit = res.headers.get('X-RateLimit-Limit');\n\t\tconst remaining = res.headers.get('X-RateLimit-Remaining');\n\t\tconst reset = res.headers.get('X-RateLimit-Reset-After');\n\t\tconst hash = res.headers.get('X-RateLimit-Bucket');\n\t\tconst retry = res.headers.get('Retry-After');\n\t\tconst scope = (res.headers.get('X-RateLimit-Scope') ?? 'user') as RateLimitData['scope'];\n\n\t\tconst offset = normalizeRateLimitOffset(this.manager.options.offset, routeId.bucketRoute);\n\n\t\t// Update the total number of requests that can be made before the rate limit resets\n\t\tthis.limit = limit ? Number(limit) : Number.POSITIVE_INFINITY;\n\t\t// Update the number of remaining requests that can be made before the rate limit resets\n\t\tthis.remaining = remaining ? Number(remaining) : 1;\n\t\t// Update the time when this rate limit resets (reset-after is in seconds)\n\t\tthis.reset = reset ? Number(reset) * 1_000 + Date.now() + offset : Date.now();\n\n\t\t// Amount of time in milliseconds until we should retry if rate limited (globally or otherwise)\n\t\tif (retry) retryAfter = Number(retry) * 1_000 + offset;\n\n\t\t// Handle buckets via the hash header retroactively\n\t\tif (hash && hash !== this.hash) {\n\t\t\t// Let library users know when rate limit buckets have been updated\n\t\t\tthis.debug(['Received bucket hash update', `  Old Hash  : ${this.hash}`, `  New Hash  : ${hash}`].join('\\n'));\n\t\t\t// This queue will eventually be eliminated via attrition\n\t\t\tthis.manager.hashes.set(\n\t\t\t\t`${method}:${routeId.bucketRoute}${typeof requestData.auth === 'string' ? `:${requestData.auth}` : ''}`,\n\t\t\t\t{ value: hash, lastAccess: Date.now() },\n\t\t\t);\n\t\t} else if (hash) {\n\t\t\t// Handle the case where hash value doesn't change\n\t\t\t// Fetch the hash data from the manager\n\t\t\tconst hashData = this.manager.hashes.get(\n\t\t\t\t`${method}:${routeId.bucketRoute}${typeof requestData.auth === 'string' ? `:${requestData.auth}` : ''}`,\n\t\t\t);\n\n\t\t\t// When fetched, update the last access of the hash\n\t\t\tif (hashData) {\n\t\t\t\thashData.lastAccess = Date.now();\n\t\t\t}\n\t\t}\n\n\t\t// Handle retryAfter, which means we have actually hit a rate limit\n\t\tlet sublimitTimeout: number | null = null;\n\t\tif (retryAfter > 0) {\n\t\t\tif (res.headers.has('X-RateLimit-Global')) {\n\t\t\t\tthis.manager.globalRemaining = 0;\n\t\t\t\tthis.manager.globalReset = Date.now() + retryAfter;\n\t\t\t} else if (!this.localLimited) {\n\t\t\t\t/*\n\t\t\t\t * This is a sublimit (e.g. 2 channel name changes/10 minutes) since the headers don't indicate a\n\t\t\t\t * route-wide rate limit. Don't update remaining or reset to avoid rate limiting the whole\n\t\t\t\t * endpoint, just set a reset time on the request itself to avoid retrying too soon.\n\t\t\t\t */\n\t\t\t\tsublimitTimeout = retryAfter;\n\t\t\t}\n\t\t}\n\n\t\t// Count the invalid requests\n\t\tif (status === 401 || status === 403 || status === 429) {\n\t\t\tincrementInvalidCount(this.manager);\n\t\t}\n\n\t\tif (res.ok) {\n\t\t\treturn res;\n\t\t} else if (status === 429) {\n\t\t\t// A rate limit was hit - this may happen if the route isn't associated with an official bucket hash yet, or when first globally rate limited\n\t\t\tconst isGlobal = this.globalLimited;\n\t\t\tlet limit: number;\n\t\t\tlet timeout: number;\n\n\t\t\tif (isGlobal) {\n\t\t\t\tconst offset = normalizeRateLimitOffset(this.manager.options.offset, routeId.bucketRoute);\n\n\t\t\t\t// Set RateLimitData based on the global limit\n\t\t\t\tlimit = this.manager.options.globalRequestsPerSecond;\n\t\t\t\ttimeout = this.manager.globalReset + offset - Date.now();\n\t\t\t} else {\n\t\t\t\t// Set RateLimitData based on the route-specific limit\n\t\t\t\tlimit = this.limit;\n\t\t\t\ttimeout = this.getTimeToReset(routeId);\n\t\t\t}\n\n\t\t\tawait onRateLimit(this.manager, {\n\t\t\t\tglobal: isGlobal,\n\t\t\t\tmethod,\n\t\t\t\turl,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\tmajorParameter: this.majorParameter,\n\t\t\t\thash: this.hash,\n\t\t\t\tlimit,\n\t\t\t\ttimeToReset: timeout,\n\t\t\t\tretryAfter,\n\t\t\t\tsublimitTimeout: sublimitTimeout ?? 0,\n\t\t\t\tscope,\n\t\t\t});\n\n\t\t\tthis.debug(\n\t\t\t\t[\n\t\t\t\t\t'Encountered unexpected 429 rate limit',\n\t\t\t\t\t`  Global         : ${isGlobal.toString()}`,\n\t\t\t\t\t`  Method         : ${method}`,\n\t\t\t\t\t`  URL            : ${url}`,\n\t\t\t\t\t`  Bucket         : ${routeId.bucketRoute}`,\n\t\t\t\t\t`  Major parameter: ${routeId.majorParameter}`,\n\t\t\t\t\t`  Hash           : ${this.hash}`,\n\t\t\t\t\t`  Limit          : ${limit}`,\n\t\t\t\t\t`  Retry After    : ${retryAfter}ms`,\n\t\t\t\t\t`  Sublimit       : ${sublimitTimeout ? `${sublimitTimeout}ms` : 'None'}`,\n\t\t\t\t\t`  Scope          : ${scope}`,\n\t\t\t\t].join('\\n'),\n\t\t\t);\n\n\t\t\t// If caused by a sublimit, wait it out here so other requests on the route can be handled\n\t\t\tif (sublimitTimeout) {\n\t\t\t\t// Normally the sublimit queue will not exist, however, if a sublimit is hit while in the sublimit queue, it will\n\t\t\t\tconst firstSublimit = !this.#sublimitedQueue;\n\t\t\t\tif (firstSublimit) {\n\t\t\t\t\tthis.#sublimitedQueue = new AsyncQueue();\n\t\t\t\t\tvoid this.#sublimitedQueue.wait();\n\t\t\t\t\tthis.#asyncQueue.shift();\n\t\t\t\t}\n\n\t\t\t\tthis.#sublimitPromise?.resolve();\n\t\t\t\tthis.#sublimitPromise = null;\n\t\t\t\tawait sleep(sublimitTimeout);\n\t\t\t\tlet resolve: () => void;\n\t\t\t\t// eslint-disable-next-line promise/param-names, no-promise-executor-return\n\t\t\t\tconst promise = new Promise<void>((res) => (resolve = res));\n\t\t\t\tthis.#sublimitPromise = { promise, resolve: resolve! };\n\t\t\t\tif (firstSublimit) {\n\t\t\t\t\t// Re-queue this request so it can be shifted by the finally\n\t\t\t\t\tawait this.#asyncQueue.wait();\n\t\t\t\t\tthis.#shiftSublimit = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Since this is not a server side issue, the next request should pass, so we don't bump the retries counter\n\t\t\treturn this.runRequest(routeId, url, options, requestData, retries);\n\t\t} else {\n\t\t\tconst handled = await handleErrors(this.manager, res, method, url, requestData, retries, routeId);\n\t\t\tif (handled === null) {\n\t\t\t\t// eslint-disable-next-line no-param-reassign\n\t\t\t\treturn this.runRequest(routeId, url, options, requestData, ++retries);\n\t\t\t}\n\n\t\t\treturn handled;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/rest/src/lib/handlers/Shared.ts",
    "content": "/* eslint-disable n/prefer-global/process */\n\nimport type { RequestInit } from 'undici';\nimport type { REST } from '../REST.js';\nimport type { DiscordErrorData, OAuthErrorData } from '../errors/DiscordAPIError.js';\nimport { DiscordAPIError } from '../errors/DiscordAPIError.js';\nimport { HTTPError } from '../errors/HTTPError.js';\nimport { RESTEvents } from '../utils/constants.js';\nimport type { ResponseLike, HandlerRequestData, RouteData } from '../utils/types.js';\nimport { normalizeRetryBackoff, normalizeTimeout, parseResponse, shouldRetry, sleep } from '../utils/utils.js';\n\nlet authFalseWarningEmitted = false;\n\n/**\n * Invalid request limiting is done on a per-IP basis, not a per-token basis.\n * The best we can do is track invalid counts process-wide (on the theory that\n * users could have multiple bots run from one process) rather than per-bot.\n * Therefore, store these at file scope here rather than in the client's\n * RESTManager object.\n */\nlet invalidCount = 0;\nlet invalidCountResetTime: number | null = null;\n\n/**\n * Increment the invalid request count and emit warning if necessary\n *\n * @internal\n */\nexport function incrementInvalidCount(manager: REST) {\n\tif (!invalidCountResetTime || invalidCountResetTime < Date.now()) {\n\t\tinvalidCountResetTime = Date.now() + 1_000 * 60 * 10;\n\t\tinvalidCount = 0;\n\t}\n\n\tinvalidCount++;\n\n\tconst emitInvalid =\n\t\tmanager.options.invalidRequestWarningInterval > 0 &&\n\t\tinvalidCount % manager.options.invalidRequestWarningInterval === 0;\n\tif (emitInvalid) {\n\t\t// Let library users know periodically about invalid requests\n\t\tmanager.emit(RESTEvents.InvalidRequestWarning, {\n\t\t\tcount: invalidCount,\n\t\t\tremainingTime: invalidCountResetTime - Date.now(),\n\t\t});\n\t}\n}\n\n/**\n * Performs the actual network request for a request handler\n *\n * @param manager - The manager that holds options and emits informational events\n * @param routeId - The generalized api route with literal ids for major parameters\n * @param url - The fully resolved url to make the request to\n * @param options - The fetch options needed to make the request\n * @param requestData - Extra data from the user's request needed for errors and additional processing\n * @param retries - The number of retries this request has already attempted (recursion occurs on the handler)\n * @returns The respond from the network or `null` when the request should be retried\n * @internal\n */\nexport async function makeNetworkRequest(\n\tmanager: REST,\n\trouteId: RouteData,\n\turl: string,\n\toptions: RequestInit,\n\trequestData: HandlerRequestData,\n\tretries: number,\n) {\n\tconst controller = new AbortController();\n\tconst timeout = setTimeout(\n\t\t() => controller.abort(),\n\t\tnormalizeTimeout(manager.options.timeout, routeId.bucketRoute, requestData.body),\n\t);\n\tif (requestData.signal) {\n\t\t// If the user signal was aborted, abort the controller, else abort the local signal.\n\t\t// The reason why we don't re-use the user's signal, is because users may use the same signal for multiple\n\t\t// requests, and we do not want to cause unexpected side-effects.\n\t\tif (requestData.signal.aborted) controller.abort();\n\t\telse requestData.signal.addEventListener('abort', () => controller.abort());\n\t}\n\n\tlet res: ResponseLike;\n\ttry {\n\t\tres = await manager.options.makeRequest(url, { ...options, signal: controller.signal });\n\t} catch (error: unknown) {\n\t\tif (!(error instanceof Error)) throw error;\n\t\t// Retry the specified number of times if needed\n\t\tif (shouldRetry(error) && retries !== manager.options.retries) {\n\t\t\tconst backoff = normalizeRetryBackoff(\n\t\t\t\tmanager.options.retryBackoff,\n\t\t\t\trouteId.bucketRoute,\n\t\t\t\tnull,\n\t\t\t\tretries,\n\t\t\t\trequestData.body,\n\t\t\t);\n\t\t\tif (backoff === null) {\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tif (backoff > 0) {\n\t\t\t\tawait sleep(backoff);\n\t\t\t}\n\n\t\t\t// Retry is handled by the handler upon receiving null\n\t\t\treturn null;\n\t\t}\n\n\t\tthrow error;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t}\n\n\tif (manager.listenerCount(RESTEvents.Response)) {\n\t\tmanager.emit(\n\t\t\tRESTEvents.Response,\n\t\t\t{\n\t\t\t\tmethod: options.method ?? 'get',\n\t\t\t\tpath: routeId.original,\n\t\t\t\troute: routeId.bucketRoute,\n\t\t\t\toptions,\n\t\t\t\tdata: requestData,\n\t\t\t\tretries,\n\t\t\t},\n\t\t\tres instanceof Response ? res.clone() : { ...res },\n\t\t);\n\t}\n\n\treturn res;\n}\n\n/**\n * Handles 5xx and 4xx errors (not 429's) conventionally. 429's should be handled before calling this function\n *\n * @param manager - The manager that holds options and emits informational events\n * @param res - The response received from {@link makeNetworkRequest}\n * @param method - The method used to make the request\n * @param url - The fully resolved url to make the request to\n * @param requestData - Extra data from the user's request needed for errors and additional processing\n * @param retries - The number of retries this request has already attempted (recursion occurs on the handler)\n * @param routeId - The generalized API route with literal ids for major parameters\n * @returns The response if the status code is not handled or null to request a retry\n */\nexport async function handleErrors(\n\tmanager: REST,\n\tres: ResponseLike,\n\tmethod: string,\n\turl: string,\n\trequestData: HandlerRequestData,\n\tretries: number,\n\trouteId: RouteData,\n) {\n\tconst status = res.status;\n\tif (status >= 500 && status < 600) {\n\t\t// Retry the specified number of times for possible server side issues\n\t\tif (retries !== manager.options.retries) {\n\t\t\tconst backoff = normalizeRetryBackoff(\n\t\t\t\tmanager.options.retryBackoff,\n\t\t\t\trouteId.bucketRoute,\n\t\t\t\tstatus,\n\t\t\t\tretries,\n\t\t\t\trequestData.body,\n\t\t\t);\n\t\t\tif (backoff === null) {\n\t\t\t\tthrow new HTTPError(status, res.statusText, method, url, requestData);\n\t\t\t}\n\n\t\t\tif (backoff > 0) {\n\t\t\t\tawait sleep(backoff);\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\n\t\t// We are out of retries, throw an error\n\t\tthrow new HTTPError(status, res.statusText, method, url, requestData);\n\t} else {\n\t\t// Handle possible malformed requests\n\t\tif (status >= 400 && status < 500) {\n\t\t\t// The request will not succeed for some reason, parse the error returned from the api\n\t\t\tconst data = (await parseResponse(res)) as DiscordErrorData | OAuthErrorData;\n\t\t\tconst isDiscordError = 'code' in data;\n\n\t\t\t// If we receive this status code, it means the token we had is no longer valid.\n\t\t\tif (status === 401 && requestData.auth === true) {\n\t\t\t\tif (isDiscordError && data.code !== 0 && !authFalseWarningEmitted) {\n\t\t\t\t\tconst errorText = `Encountered HTTP 401 with error ${data.code}: ${data.message}. Your token will be removed from this REST instance. If you are using @discordjs/rest directly, consider adding 'auth: false' to the request. Open an issue with your library if not.`;\n\t\t\t\t\t// Use emitWarning if possible, probably not available in edge / web\n\t\t\t\t\tif (typeof globalThis.process !== 'undefined' && typeof globalThis.process.emitWarning === 'function') {\n\t\t\t\t\t\tglobalThis.process.emitWarning(errorText);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconsole.warn(errorText);\n\t\t\t\t\t}\n\n\t\t\t\t\tauthFalseWarningEmitted = true;\n\t\t\t\t}\n\n\t\t\t\tmanager.setToken(null!);\n\t\t\t}\n\n\t\t\t// throw the API error\n\t\t\tthrow new DiscordAPIError(data, isDiscordError ? data.code : data.error, status, method, url, requestData);\n\t\t}\n\n\t\treturn res;\n\t}\n}\n"
  },
  {
    "path": "packages/rest/src/lib/interfaces/Handler.ts",
    "content": "import type { RequestInit } from 'undici';\nimport type { HandlerRequestData, RouteData, ResponseLike } from '../utils/types.js';\n\nexport interface IHandler {\n\t/**\n\t * The unique id of the handler\n\t */\n\treadonly id: string;\n\t/**\n\t * If the bucket is currently inactive (no pending requests)\n\t */\n\tget inactive(): boolean;\n\t/**\n\t * Queues a request to be sent\n\t *\n\t * @param routeId - The generalized api route with literal ids for major parameters\n\t * @param url - The url to do the request on\n\t * @param options - All the information needed to make a request\n\t * @param requestData - Extra data from the user's request needed for errors and additional processing\n\t */\n\tqueueRequest(\n\t\trouteId: RouteData,\n\t\turl: string,\n\t\toptions: RequestInit,\n\t\trequestData: HandlerRequestData,\n\t): Promise<ResponseLike>;\n}\n"
  },
  {
    "path": "packages/rest/src/lib/utils/constants.ts",
    "content": "import { getUserAgentAppendix } from '@discordjs/util';\nimport type { ImageSize } from 'discord-api-types/v10';\nimport { APIVersion } from 'discord-api-types/v10';\nimport { getDefaultStrategy } from '../../environment.js';\nimport type { RESTOptions, ResponseLike } from './types.js';\n\nexport type { ImageSize } from 'discord-api-types/v10';\n\nexport const DefaultUserAgent =\n\t`DiscordBot (https://discord.js.org, [VI]{{inject}}[/VI])` as `DiscordBot (https://discord.js.org, ${string})`;\n\n/**\n * The default string to append onto the user agent.\n */\nexport const DefaultUserAgentAppendix = getUserAgentAppendix();\n\nexport const DefaultRestOptions = {\n\tagent: null,\n\tapi: 'https://discord.com/api',\n\tauthPrefix: 'Bot',\n\tcdn: 'https://cdn.discordapp.com',\n\theaders: {},\n\tinvalidRequestWarningInterval: 0,\n\tglobalRequestsPerSecond: 50,\n\toffset: 50,\n\trejectOnRateLimit: null,\n\tretries: 3,\n\tretryBackoff: 0,\n\ttimeout: 15_000,\n\tuserAgentAppendix: DefaultUserAgentAppendix,\n\tversion: APIVersion,\n\thashSweepInterval: 14_400_000, // 4 Hours\n\thashLifetime: 86_400_000, // 24 Hours\n\thandlerSweepInterval: 3_600_000, // 1 Hour\n\tasync makeRequest(...args): Promise<ResponseLike> {\n\t\treturn getDefaultStrategy()(...args);\n\t},\n\tmediaProxy: 'https://media.discordapp.net',\n} as const satisfies Required<RESTOptions>;\n\n/**\n * The events that the REST manager emits\n */\nexport enum RESTEvents {\n\tDebug = 'restDebug',\n\tHandlerSweep = 'handlerSweep',\n\tHashSweep = 'hashSweep',\n\tInvalidRequestWarning = 'invalidRequestWarning',\n\tRateLimited = 'rateLimited',\n\tResponse = 'response',\n}\n\nexport const ALLOWED_EXTENSIONS = ['webp', 'png', 'jpg', 'jpeg', 'gif'] as const satisfies readonly string[];\nexport const ALLOWED_STICKER_EXTENSIONS = ['png', 'json', 'gif'] as const satisfies readonly string[];\nexport const ALLOWED_SIZES: readonly number[] = [\n\t16, 32, 64, 128, 256, 512, 1_024, 2_048, 4_096,\n] satisfies readonly ImageSize[];\n\nexport type ImageExtension = (typeof ALLOWED_EXTENSIONS)[number];\nexport type StickerExtension = (typeof ALLOWED_STICKER_EXTENSIONS)[number];\n\nexport const OverwrittenMimeTypes = {\n\t// https://github.com/discordjs/discord.js/issues/8557\n\t'image/apng': 'image/png',\n} as const satisfies Readonly<Record<string, string>>;\n\nexport const BurstHandlerMajorIdKey = 'burst';\n\nexport const AUTH_UUID_NAMESPACE = 'acc82a4c-f887-417b-a69c-f74096ff7e59';\n"
  },
  {
    "path": "packages/rest/src/lib/utils/types.ts",
    "content": "import type { Readable } from 'node:stream';\nimport type { ReadableStream } from 'node:stream/web';\nimport type { Collection } from '@discordjs/collection';\nimport type { Awaitable, RawFile } from '@discordjs/util';\nimport type { Agent, Dispatcher, RequestInit, BodyInit, Response } from 'undici';\nimport type { IHandler } from '../interfaces/Handler.js';\n\nexport interface RestEvents {\n\thandlerSweep: [sweptHandlers: Collection<string, IHandler>];\n\thashSweep: [sweptHashes: Collection<string, HashData>];\n\tinvalidRequestWarning: [invalidRequestInfo: InvalidRequestWarningData];\n\trateLimited: [rateLimitInfo: RateLimitData];\n\tresponse: [request: APIRequest, response: ResponseLike];\n\trestDebug: [info: string];\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface RestEventsMap extends RestEvents {}\n\n/**\n * Options to be passed when creating the REST instance\n */\nexport interface RESTOptions {\n\t/**\n\t * The agent to set globally\n\t */\n\tagent: Dispatcher | null;\n\t/**\n\t * The base api path, without version\n\t *\n\t * @defaultValue `'https://discord.com/api'`\n\t */\n\tapi: string;\n\t/**\n\t * The authorization prefix to use for requests, useful if you want to use\n\t * bearer tokens\n\t *\n\t * @defaultValue `'Bot'`\n\t */\n\tauthPrefix: 'Bearer' | 'Bot';\n\t/**\n\t * The cdn path\n\t *\n\t * @defaultValue `'https://cdn.discordapp.com'`\n\t */\n\tcdn: string;\n\t/**\n\t * How many requests to allow sending per second (Infinity for unlimited, 50 for the standard global limit used by Discord)\n\t *\n\t * @defaultValue `50`\n\t */\n\tglobalRequestsPerSecond: number;\n\t/**\n\t * The amount of time in milliseconds that passes between each hash sweep. (defaults to 1h)\n\t *\n\t * @defaultValue `3_600_000`\n\t */\n\thandlerSweepInterval: number;\n\t/**\n\t * The maximum amount of time a hash can exist in milliseconds without being hit with a request (defaults to 24h)\n\t *\n\t * @defaultValue `86_400_000`\n\t */\n\thashLifetime: number;\n\t/**\n\t * The amount of time in milliseconds that passes between each hash sweep. (defaults to 4h)\n\t *\n\t * @defaultValue `14_400_000`\n\t */\n\thashSweepInterval: number;\n\t/**\n\t * Additional headers to send for all API requests\n\t *\n\t * @defaultValue `{}`\n\t */\n\theaders: Record<string, string>;\n\t/**\n\t * The number of invalid REST requests (those that return 401, 403, or 429) in a 10 minute window between emitted warnings (0 for no warnings).\n\t * That is, if set to 500, warnings will be emitted at invalid request number 500, 1000, 1500, and so on.\n\t *\n\t * @defaultValue `0`\n\t */\n\tinvalidRequestWarningInterval: number;\n\t/**\n\t * The method called to perform the actual HTTP request given a url and web `fetch` options\n\t * For example, to use global fetch, simply provide `makeRequest: fetch`\n\t */\n\tmakeRequest(url: string, init: RequestInit): Promise<ResponseLike>;\n\t/**\n\t * The media proxy path\n\t *\n\t * @defaultValue `'https://media.discordapp.net'`\n\t */\n\tmediaProxy: string;\n\t/**\n\t * The extra offset to add to rate limits in milliseconds\n\t *\n\t * @defaultValue `50`\n\t */\n\toffset: GetRateLimitOffsetFunction | number;\n\t/**\n\t * Determines how rate limiting and pre-emptive throttling should be handled.\n\t * When an array of strings, each element is treated as a prefix for the request route\n\t * (e.g. `/channels` to match any route starting with `/channels` such as `/channels/:id/messages`)\n\t * for which to throw {@link RateLimitError}s. All other request routes will be queued normally\n\t *\n\t * @defaultValue `null`\n\t */\n\trejectOnRateLimit: RateLimitQueueFilter | string[] | null;\n\t/**\n\t * The number of retries for errors with the 500 code, or errors\n\t * that timeout\n\t *\n\t * @defaultValue `3`\n\t */\n\tretries: number;\n\t/**\n\t * The time to exponentially add before retrying a 5xx or aborted request\n\t *\n\t * @defaultValue `0`\n\t */\n\tretryBackoff: GetRetryBackoffFunction | number;\n\t/**\n\t * The time to wait in milliseconds before a request is aborted\n\t *\n\t * @defaultValue `15_000`\n\t */\n\ttimeout: GetTimeoutFunction | number;\n\t/**\n\t * Extra information to add to the user agent\n\t *\n\t * @defaultValue DefaultUserAgentAppendix\n\t */\n\tuserAgentAppendix: string;\n\t/**\n\t * The version of the API to use\n\t *\n\t * @defaultValue `'10'`\n\t */\n\tversion: string;\n}\n\n/**\n * Data emitted on `RESTEvents.RateLimited`\n */\nexport interface RateLimitData {\n\t/**\n\t * Whether the rate limit that was reached was the global limit\n\t */\n\tglobal: boolean;\n\t/**\n\t * The bucket hash for this request\n\t */\n\thash: string;\n\t/**\n\t * The amount of requests we can perform before locking requests\n\t */\n\tlimit: number;\n\t/**\n\t * The major parameter of the route\n\t *\n\t * For example, in `/channels/x`, this will be `x`.\n\t * If there is no major parameter (e.g: `/bot/gateway`) this will be `global`.\n\t */\n\tmajorParameter: string;\n\t/**\n\t * The HTTP method being performed\n\t */\n\tmethod: string;\n\t/**\n\t * The time, in milliseconds, that will need to pass before this specific request can be retried\n\t */\n\tretryAfter: number;\n\t/**\n\t * The route being hit in this request\n\t */\n\troute: string;\n\t/**\n\t * The scope of the rate limit that was hit.\n\t *\n\t * This can be `user` for rate limits that are per client, `global` for rate limits that affect all clients or `shared` for rate limits that\n\t * are shared per resource.\n\t */\n\tscope: 'global' | 'shared' | 'user';\n\t/**\n\t * The time, in milliseconds, that will need to pass before the sublimit lock for the route resets, and requests that fall under a sublimit\n\t * can be retried\n\t *\n\t * This is only present on certain sublimits, and `0` otherwise\n\t */\n\tsublimitTimeout: number;\n\t/**\n\t * The time, in milliseconds, until the route's request-lock is reset\n\t */\n\ttimeToReset: number;\n\t/**\n\t * The full URL for this request\n\t */\n\turl: string;\n}\n\n/**\n * A function that determines whether the rate limit hit should throw an Error\n */\nexport type RateLimitQueueFilter = (rateLimitData: RateLimitData) => Awaitable<boolean>;\n\n/**\n * A function that determines the rate limit offset for a given request.\n */\nexport type GetRateLimitOffsetFunction = (route: string) => number;\n\n/**\n * A function that determines the backoff for a retry for a given request.\n *\n * @param route - The route that has encountered a server-side error\n * @param statusCode - The status code received or `null` if aborted\n * @param retryCount - The number of retries that have been attempted so far. The first call will be `0`\n * @param requestBody - The body that was sent with the request\n * @returns The delay for the current request or `null` to throw an error instead of retrying\n */\nexport type GetRetryBackoffFunction = (\n\troute: string,\n\tstatusCode: number | null,\n\tretryCount: number,\n\trequestBody: unknown,\n) => number | null;\n\n/**\n * A function that determines the timeout for a given request.\n *\n * @param route - The route that is being processed\n * @param body - The body that will be sent with the request\n */\nexport type GetTimeoutFunction = (route: string, body: unknown) => number;\n\nexport interface APIRequest {\n\t/**\n\t * The data that was used to form the body of this request\n\t */\n\tdata: HandlerRequestData;\n\t/**\n\t * The HTTP method used in this request\n\t */\n\tmethod: string;\n\t/**\n\t * Additional HTTP options for this request\n\t */\n\toptions: RequestInit;\n\t/**\n\t * The full path used to make the request\n\t */\n\tpath: RouteLike;\n\t/**\n\t * The number of times this request has been attempted\n\t */\n\tretries: number;\n\t/**\n\t * The API route identifying the ratelimit for this request\n\t */\n\troute: string;\n}\n\nexport interface ResponseLike extends Pick<\n\tResponse,\n\t'arrayBuffer' | 'bodyUsed' | 'headers' | 'json' | 'ok' | 'status' | 'statusText' | 'text'\n> {\n\tbody: Readable | ReadableStream | null;\n}\n\nexport interface InvalidRequestWarningData {\n\t/**\n\t * Number of invalid requests that have been made in the window\n\t */\n\tcount: number;\n\t/**\n\t * Time in milliseconds remaining before the count resets\n\t */\n\tremainingTime: number;\n}\n\nexport type { RawFile } from '@discordjs/util';\n\nexport interface AuthData {\n\t/**\n\t * The authorization prefix to use for this request, useful if you use this with bearer tokens\n\t *\n\t * @defaultValue `REST.options.authPrefix`\n\t */\n\tprefix?: 'Bearer' | 'Bot';\n\t/**\n\t * The authorization token to use for this request\n\t */\n\ttoken: string;\n}\n\n/**\n * Represents possible data to be given to an endpoint\n */\nexport interface RequestData {\n\t/**\n\t * Whether to append JSON data to form data instead of `payload_json` when sending files\n\t */\n\tappendToFormData?: boolean;\n\t/**\n\t * Alternate authorization data to use for this request only, or `false` to disable the Authorization header.\n\t * When making a request to a route that includes a token (such as interactions or webhooks), set to `false`\n\t * to avoid accidentally unsetting the instance token if a 401 is encountered.\n\t *\n\t * @defaultValue `true`\n\t */\n\tauth?: AuthData | boolean | undefined;\n\t/**\n\t * The body to send to this request.\n\t * If providing as BodyInit, set `passThroughBody: true`\n\t */\n\tbody?: BodyInit | unknown;\n\t/**\n\t * The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} to use for the request.\n\t */\n\tdispatcher?: Agent;\n\t/**\n\t * Files to be attached to this request\n\t */\n\tfiles?: RawFile[] | undefined;\n\t/**\n\t * Additional headers to add to this request\n\t */\n\theaders?: Record<string, string>;\n\t/**\n\t * Whether to pass-through the body property directly to `fetch()`.\n\t * <warn>This only applies when files is NOT present</warn>\n\t */\n\tpassThroughBody?: boolean;\n\t/**\n\t * Query string parameters to append to the called endpoint\n\t */\n\tquery?: URLSearchParams;\n\t/**\n\t * Reason to show in the audit logs\n\t */\n\treason?: string | undefined;\n\t/**\n\t * The signal to abort the queue entry or the REST call, where applicable\n\t */\n\tsignal?: AbortSignal | undefined;\n\t/**\n\t * If this request should be versioned\n\t *\n\t * @defaultValue `true`\n\t */\n\tversioned?: boolean;\n}\n\n/**\n * Possible headers for an API call\n */\nexport interface RequestHeaders {\n\tAuthorization?: string;\n\t'User-Agent': string;\n\t'X-Audit-Log-Reason'?: string;\n}\n\n/**\n * Possible API methods to be used when doing requests\n */\nexport enum RequestMethod {\n\tDelete = 'DELETE',\n\tGet = 'GET',\n\tPatch = 'PATCH',\n\tPost = 'POST',\n\tPut = 'PUT',\n}\n\nexport type RouteLike = `/${string}`;\n\n/**\n * Internal request options\n */\nexport interface InternalRequest extends RequestData {\n\tfullRoute: RouteLike;\n\tmethod: RequestMethod;\n}\n\nexport interface HandlerRequestData extends Pick<InternalRequest, 'body' | 'files' | 'signal'> {\n\tauth: boolean | string;\n}\n\n/**\n * Parsed route data for an endpoint\n */\nexport interface RouteData {\n\tbucketRoute: string;\n\tmajorParameter: string;\n\toriginal: RouteLike;\n}\n\n/**\n * Represents a hash and its associated fields\n */\nexport interface HashData {\n\tlastAccess: number;\n\tvalue: string;\n}\n"
  },
  {
    "path": "packages/rest/src/lib/utils/utils.ts",
    "content": "import type { Buffer } from 'node:buffer';\nimport type { RESTPatchAPIChannelJSONBody, Snowflake } from 'discord-api-types/v10';\nimport type { REST } from '../REST.js';\nimport { RateLimitError } from '../errors/RateLimitError.js';\nimport { RequestMethod } from './types.js';\nimport type {\n\tGetRateLimitOffsetFunction,\n\tGetRetryBackoffFunction,\n\tGetTimeoutFunction,\n\tRateLimitData,\n\tResponseLike,\n} from './types.js';\n\nfunction serializeSearchParam(value: unknown): string | null {\n\t// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check\n\tswitch (typeof value) {\n\t\tcase 'string':\n\t\t\treturn value;\n\t\tcase 'number':\n\t\tcase 'bigint':\n\t\tcase 'boolean':\n\t\t\treturn value.toString();\n\t\tcase 'object':\n\t\t\tif (value === null) return null;\n\t\t\tif (value instanceof Date) {\n\t\t\t\treturn Number.isNaN(value.getTime()) ? null : value.toISOString();\n\t\t\t}\n\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-base-to-string\n\t\t\tif (typeof value.toString === 'function' && value.toString !== Object.prototype.toString) return value.toString();\n\t\t\treturn null;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\n/**\n * Creates and populates an URLSearchParams instance from an object, stripping\n * out null and undefined values, while also coercing non-strings to strings.\n *\n * @param options - The options to use\n * @returns A populated URLSearchParams instance\n */\nexport function makeURLSearchParams<OptionsType extends object>(options?: Readonly<OptionsType>) {\n\tconst params = new URLSearchParams();\n\tif (!options) return params;\n\n\tfor (const [key, value] of Object.entries(options)) {\n\t\tconst serialized = serializeSearchParam(value);\n\t\tif (serialized !== null) params.append(key, serialized);\n\t}\n\n\treturn params;\n}\n\n/**\n * Converts the response to usable data\n *\n * @param res - The fetch response\n */\nexport async function parseResponse(res: ResponseLike): Promise<unknown> {\n\tif (res.headers.get('Content-Type')?.startsWith('application/json')) {\n\t\treturn res.json();\n\t}\n\n\treturn res.arrayBuffer();\n}\n\n/**\n * Check whether a request falls under a sublimit\n *\n * @param bucketRoute - The buckets route identifier\n * @param body - The options provided as JSON data\n * @param method - The HTTP method that will be used to make the request\n * @returns Whether the request falls under a sublimit\n */\nexport function hasSublimit(bucketRoute: string, body?: unknown, method?: string): boolean {\n\t// TODO: Update for new sublimits\n\t// Currently known sublimits:\n\t// Editing channel `name` or `topic`\n\tif (bucketRoute === '/channels/:id') {\n\t\tif (typeof body !== 'object' || body === null) return false;\n\t\t// This should never be a POST body, but just in case\n\t\tif (method !== RequestMethod.Patch) return false;\n\t\tconst castedBody = body as RESTPatchAPIChannelJSONBody;\n\t\treturn ['name', 'topic'].some((key) => Reflect.has(castedBody, key));\n\t}\n\n\t// If we are checking if a request has a sublimit on a route not checked above, sublimit all requests to avoid a flood of 429s\n\treturn true;\n}\n\n/**\n * Check whether an error indicates that a retry can be attempted\n *\n * @param error - The error thrown by the network request\n * @returns Whether the error indicates a retry should be attempted\n */\nexport function shouldRetry(error: Error | NodeJS.ErrnoException) {\n\t// Retry for possible timed out requests\n\tif (error.name === 'AbortError') return true;\n\t// Downlevel ECONNRESET to retry as it may be recoverable\n\treturn ('code' in error && error.code === 'ECONNRESET') || error.message.includes('ECONNRESET');\n}\n\n/**\n * Determines whether the request should be queued or whether a RateLimitError should be thrown\n *\n * @internal\n */\nexport async function onRateLimit(manager: REST, rateLimitData: RateLimitData) {\n\tconst { options } = manager;\n\tif (!options.rejectOnRateLimit) return;\n\n\tconst shouldThrow =\n\t\ttypeof options.rejectOnRateLimit === 'function'\n\t\t\t? await options.rejectOnRateLimit(rateLimitData)\n\t\t\t: options.rejectOnRateLimit.some((route) => rateLimitData.route.startsWith(route.toLowerCase()));\n\tif (shouldThrow) {\n\t\tthrow new RateLimitError(rateLimitData);\n\t}\n}\n\n/**\n * Calculates the default avatar index for a given user id.\n *\n * @param userId - The user id to calculate the default avatar index for\n */\nexport function calculateUserDefaultAvatarIndex(userId: Snowflake) {\n\treturn Number(BigInt(userId) >> 22n) % 6;\n}\n\n/**\n * Sleeps for a given amount of time.\n *\n * @param ms - The amount of time (in milliseconds) to sleep for\n */\nexport async function sleep(ms: number): Promise<void> {\n\treturn new Promise<void>((resolve) => {\n\t\tsetTimeout(() => resolve(), ms);\n\t});\n}\n\n/**\n * Verifies that a value is a buffer-like object.\n *\n * @param value - The value to check\n */\nexport function isBufferLike(value: unknown): value is ArrayBuffer | Buffer | Uint8Array | Uint8ClampedArray {\n\treturn value instanceof ArrayBuffer || value instanceof Uint8Array || value instanceof Uint8ClampedArray;\n}\n\n/**\n * Normalizes the offset for rate limits. Applies a Math.max(0, N) to prevent negative offsets,\n * also deals with callbacks.\n *\n * @internal\n */\nexport function normalizeRateLimitOffset(offset: GetRateLimitOffsetFunction | number, route: string): number {\n\tif (typeof offset === 'number') {\n\t\treturn Math.max(0, offset);\n\t}\n\n\tconst result = offset(route);\n\treturn Math.max(0, result);\n}\n\n/**\n * Normalizes the retry backoff used to add delay to retrying 5xx and aborted requests.\n * Applies a Math.max(0, N) to prevent negative backoffs, also deals with callbacks.\n *\n * @internal\n */\nexport function normalizeRetryBackoff(\n\tretryBackoff: GetRetryBackoffFunction | number,\n\troute: string,\n\tstatusCode: number | null,\n\tretryCount: number,\n\trequestBody: unknown,\n): number | null {\n\tif (typeof retryBackoff === 'number') {\n\t\treturn Math.max(0, retryBackoff) * (1 << retryCount);\n\t}\n\n\t// No need to Math.max as we'll only set the sleep timer if the value is > 0 (and not equal)\n\treturn retryBackoff(route, statusCode, retryCount, requestBody);\n}\n\n/**\n * Normalizes the timeout for aborting requests. Applies a Math.max(0, N) to prevent negative timeouts,\n * also deals with callbacks.\n *\n * @internal\n */\nexport function normalizeTimeout(timeout: GetTimeoutFunction | number, route: string, requestBody: unknown): number {\n\tif (typeof timeout === 'number') {\n\t\treturn Math.max(0, timeout);\n\t}\n\n\tconst result = timeout(route, requestBody);\n\treturn Math.max(0, result);\n}\n"
  },
  {
    "path": "packages/rest/src/shared.ts",
    "content": "export * from './lib/CDN.js';\nexport * from './lib/errors/DiscordAPIError.js';\nexport * from './lib/errors/HTTPError.js';\nexport * from './lib/errors/RateLimitError.js';\nexport type * from './lib/interfaces/Handler.js';\nexport * from './lib/REST.js';\nexport * from './lib/utils/constants.js';\nexport * from './lib/utils/types.js';\nexport { calculateUserDefaultAvatarIndex, makeURLSearchParams, parseResponse } from './lib/utils/utils.js';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/rest#readme | @discordjs/rest} version\n * that you are currently using.\n */\n// This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild\nexport const version = '[VI]{{inject}}[/VI]' as string;\n"
  },
  {
    "path": "packages/rest/src/strategies/undiciRequest.ts",
    "content": "import { Buffer } from 'node:buffer';\nimport { STATUS_CODES } from 'node:http';\nimport { types } from 'node:util';\nimport { type RequestInit, request, Headers, FormData as UndiciFormData, Agent } from 'undici';\nimport type { HeaderRecord } from 'undici/types/header.js';\nimport type { ResponseLike } from '../shared.js';\n\nexport type RequestOptions = Exclude<Parameters<typeof request>[1], undefined>;\n\nlet localAgent: Agent | null = null;\n\nexport async function makeRequest(url: string, init: RequestInit): Promise<ResponseLike> {\n\t// The cast is necessary because `headers` and `method` are narrower types in `undici.request`\n\t// our request path guarantees they are of acceptable type for `undici.request`\n\tconst options = {\n\t\t...init,\n\t\tbody: await resolveBody(init.body),\n\t} as RequestOptions;\n\n\t// Mismatched dispatchers from the Node.js-bundled undici and package-installed undici breaks file uploads.\n\t// So we ensure that we always pass an Agent to request()\n\t// https://github.com/nodejs/node/issues/59012\n\tif (!options.dispatcher) {\n\t\tlocalAgent ??= new Agent();\n\t\toptions.dispatcher = localAgent;\n\t}\n\n\tconst res = await request(url, options);\n\treturn {\n\t\tbody: res.body,\n\t\tasync arrayBuffer() {\n\t\t\treturn res.body.arrayBuffer();\n\t\t},\n\t\tasync json() {\n\t\t\treturn res.body.json();\n\t\t},\n\t\tasync text() {\n\t\t\treturn res.body.text();\n\t\t},\n\t\tget bodyUsed() {\n\t\t\treturn res.body.bodyUsed;\n\t\t},\n\t\theaders: new Headers(res.headers as HeaderRecord),\n\t\tstatus: res.statusCode,\n\t\tstatusText: STATUS_CODES[res.statusCode]!,\n\t\tok: res.statusCode >= 200 && res.statusCode < 300,\n\t};\n}\n\nexport async function resolveBody(body: RequestInit['body']): Promise<Exclude<RequestOptions['body'], undefined>> {\n\t// eslint-disable-next-line no-eq-null, eqeqeq\n\tif (body == null) {\n\t\treturn null;\n\t} else if (typeof body === 'string') {\n\t\treturn body;\n\t} else if (types.isUint8Array(body)) {\n\t\treturn body;\n\t} else if (types.isArrayBuffer(body)) {\n\t\treturn new Uint8Array(body);\n\t} else if (body instanceof URLSearchParams) {\n\t\treturn body.toString();\n\t} else if (body instanceof DataView) {\n\t\treturn new Uint8Array(body.buffer);\n\t} else if (body instanceof Blob) {\n\t\treturn new Uint8Array(await body.arrayBuffer());\n\t} else if (body instanceof UndiciFormData) {\n\t\treturn body;\n\t} else if (body instanceof FormData) {\n\t\treturn globalToUndiciFormData(body);\n\t} else if ((body as Iterable<Uint8Array>)[Symbol.iterator]) {\n\t\tconst chunks = [...(body as Iterable<Uint8Array>)];\n\n\t\treturn Buffer.concat(chunks);\n\t} else if ((body as AsyncIterable<Uint8Array>)[Symbol.asyncIterator]) {\n\t\tconst chunks: Uint8Array[] = [];\n\n\t\tfor await (const chunk of body as AsyncIterable<Uint8Array>) {\n\t\t\tchunks.push(chunk);\n\t\t}\n\n\t\treturn Buffer.concat(chunks);\n\t}\n\n\tthrow new TypeError(`Unable to resolve body.`);\n}\n\nfunction globalToUndiciFormData(fd: globalThis.FormData): UndiciFormData {\n\tconst clone = new UndiciFormData();\n\n\tfor (const [name, value] of fd.entries()) {\n\t\tif (typeof value === 'string') {\n\t\t\tclone.append(name, value);\n\t\t} else {\n\t\t\tclone.append(name, value, value.name);\n\t\t}\n\t}\n\n\treturn clone;\n}\n"
  },
  {
    "path": "packages/rest/src/web.ts",
    "content": "import { setDefaultStrategy } from './environment.js';\n\n// This cast is needed because of a mismatch between the version of undici-types provided by @types/node and undici\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\nsetDefaultStrategy(fetch as typeof import('undici').fetch);\n\nexport * from './shared.js';\n"
  },
  {
    "path": "packages/rest/tsconfig.docs.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.docs.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist-docs\"\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/rest/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/rest/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/rest/tsconfig.test.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"noEmit\": true,\n\t\t\"skipLibCheck\": true\n\t},\n\t\"include\": [\"__tests__/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/rest/tsup.config.ts",
    "content": "import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector';\nimport { createTsupConfig } from '../../tsup.config.js';\n\nexport default [\n\tcreateTsupConfig({\n\t\tentry: ['src/index.ts'],\n\t\tesbuildPlugins: [esbuildPluginVersionInjector()],\n\t}),\n\tcreateTsupConfig({\n\t\tentry: ['src/web.ts'],\n\t\tesbuildPlugins: [esbuildPluginVersionInjector()],\n\t}),\n\tcreateTsupConfig({\n\t\tentry: ['src/strategies/*.ts'],\n\t\toutDir: 'dist/strategies',\n\t\tesbuildPlugins: [esbuildPluginVersionInjector()],\n\t}),\n];\n"
  },
  {
    "path": "packages/rest/vitest.config.ts",
    "content": "import { defineProject, mergeConfig } from 'vitest/config';\nimport configShared from '../../vitest.config.js';\n\nexport default mergeConfig(configShared, {\n\tdefineProject: defineProject({\n\t\ttest: {\n\t\t\tsetupFiles: ['./__tests__/setup.ts'],\n\t\t},\n\t}),\n});\n"
  },
  {
    "path": "packages/scripts/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\n\n# Docs\ndocs/**/*\n!docs/README.md\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/scripts/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/scripts/.prettierignore",
    "content": ".turbo\ncoverage\ndist\nturbo\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/scripts/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = {\n\t...require('../../.prettierrc.json'),\n\toverrides: [\n\t\t{\n\t\t\tfiles: 'turbo/generators/templates/{.cliff-jumperrc.json.hbs,api-extractor.json.hbs,package.json.hbs}',\n\t\t\toptions: {\n\t\t\t\tparser: 'json',\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tfiles: 'turbo/generators/templates/{.lintstagedrc.js.hbs,.prettierrc.js.hbs}',\n\t\t\toptions: {\n\t\t\t\tparser: 'babel',\n\t\t\t},\n\t\t},\n\t],\n};\n"
  },
  {
    "path": "packages/scripts/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2022 Noel Buechler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/scripts/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested.  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/scripts\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/scripts/bin/generateSplitDocumentation.js",
    "content": "#!/usr/bin/env node\nrequire('../dist/bin/generateSplitDocumentation.js');\n"
  },
  {
    "path": "packages/scripts/bin/generateSplitDocumentation.ts",
    "content": "#!/usr/bin/env node\n\nimport { readFile } from 'node:fs/promises';\nimport process from 'node:process';\nimport { createCommand } from 'commander';\nimport packageFile from '../package.json';\nimport { generateSplitDocumentation } from '../src/index.js';\n\nexport interface CLIOptions {\n\tall: boolean;\n}\n\nconst command = createCommand().version(packageFile.version).option('-A, --all', 'Build all available versions', false);\n\nconst program = command.parse(process.argv);\nconst opts = program.opts<CLIOptions>();\n\nconsole.log('Generating split documentation...');\nvoid generateSplitDocumentation(\n\topts.all\n\t\t? {}\n\t\t: {\n\t\t\t\tfetchPackageVersions: async (_) => ['main'],\n\t\t\t\tfetchPackageVersionDocs: async (_, __) =>\n\t\t\t\t\tJSON.parse(await readFile(`${process.cwd()}/docs/docs.api.json`, 'utf8')),\n\t\t\t},\n).then(() => console.log('Generated split documentation.'));\n"
  },
  {
    "path": "packages/scripts/bin/sortLabels.js",
    "content": "#!/usr/bin/env node\nimport('../dist/bin/sortLabels.mjs');\n"
  },
  {
    "path": "packages/scripts/bin/sortLabels.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\nimport { parse as parseYAML, stringify as stringifyYAML } from 'yaml';\n\ninterface LabelerData {\n\tcolor: string;\n\tname: string;\n}\n\nconst labelsYamlFile = new URL('../../../../.github/labels.yml', import.meta.url);\n\nconst content = await readFile(labelsYamlFile, 'utf8');\n\nconst labelsYAML = parseYAML(content) as LabelerData[];\nlabelsYAML.sort((a, b) => a.name.localeCompare(b.name));\n\nawait writeFile(labelsYamlFile, stringifyYAML(labelsYAML));\n"
  },
  {
    "path": "packages/scripts/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/scripts\",\n\t\"version\": \"0.1.0\",\n\t\"description\": \"A set of scripts that we use for our workflows\",\n\t\"private\": true,\n\t\"scripts\": {\n\t\t\"build\": \"tsc --noEmit --lib ESNext,DOM && tsup\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src turbo/generators/config.ts\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src turbo/generators/config.ts\",\n\t\t\"fmt\": \"pnpm run format\"\n\t},\n\t\"bin\": {\n\t\t\"generate-split-documentation\": \"./bin/generateSplitDocumentation.js\",\n\t\t\"sort-labels\": \"./bin/sortLabels.js\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/src/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/src/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/src/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/src/index.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"main\": \"./dist/src/index.js\",\n\t\"module\": \"./dist/src/index.mjs\",\n\t\"types\": \"./dist/src/index.d.ts\",\n\t\"directories\": {\n\t\t\"bin\": \"bin\",\n\t\t\"lib\": \"src\",\n\t\t\"example\": \"turbo\"\n\t},\n\t\"files\": [\n\t\t\"bin/generateSplitDocumentation.js\",\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"api\",\n\t\t\"bot\",\n\t\t\"client\",\n\t\t\"node\",\n\t\t\"discordjs\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/scripts\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"@actions/glob\": \"^0.5.1\",\n\t\t\"@discordjs/api-extractor-model\": \"workspace:^\",\n\t\t\"@discordjs/api-extractor-utils\": \"workspace:^\",\n\t\t\"@microsoft/tsdoc\": \"~0.15.1\",\n\t\t\"@microsoft/tsdoc-config\": \"~0.17.1\",\n\t\t\"@vercel/blob\": \"^2.3.0\",\n\t\t\"@vercel/postgres\": \"^0.10.0\",\n\t\t\"commander\": \"^14.0.3\",\n\t\t\"tslib\": \"^2.8.1\",\n\t\t\"undici\": \"7.22.0\",\n\t\t\"yaml\": \"^2.8.2\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@turbo/gen\": \"^2.8.10\",\n\t\t\"@types/node\": \"^24.10.13\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"terser\": \"^5.46.0\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t}\n}\n"
  },
  {
    "path": "packages/scripts/src/builtinDocumentationLinks.ts",
    "content": "export const BuiltinDocumentationLinks = {\n\t// Built-in types\n\tbigint: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/BigInt',\n\tboolean: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean',\n\tnull: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/null',\n\tnumber: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number',\n\tstring: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String',\n\tsymbol: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Symbol',\n\tundefined: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined',\n\n\t// Built-in classes\n\tAbortSignal: 'https://developer.mozilla.org/docs/Web/API/AbortSignal',\n\tAgent: 'https://undici.nodejs.org/#/docs/api/Agent',\n\tArray: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array',\n\tArrayBuffer: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer',\n\tAsyncGenerator: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator',\n\tAsyncIterable: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Iteration_protocols',\n\tAsyncIterableIterator: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Iteration_protocols',\n\tBuffer: 'https://nodejs.org/api/buffer.html#class-buffer',\n\tChildProcess: 'https://nodejs.org/api/child_process.html#class-childprocess',\n\tDate: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date',\n\tDispatcher: 'https://undici.nodejs.org/#/docs/api/Dispatcher',\n\tError: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error',\n\tFunction: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function',\n\tGenerator: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Generator',\n\tIncomingMessage: 'https://nodejs.org/api/http.html#class-httpincomingmessage',\n\tIterable: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Iteration_protocols',\n\tIterableIterator: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Iteration_protocols',\n\tIterator: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Iterator',\n\tMap: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Map',\n\tMessagePort: 'https://nodejs.org/api/worker_threads.html#class-messageport',\n\tPromise: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise',\n\tRangeError: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RangeError',\n\tReadable: 'https://nodejs.org/api/stream.html#class-streamreadable',\n\tReadableStream: 'https://developer.mozilla.org/docs/Web/API/ReadableStream',\n\tRegExp: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RegExp',\n\tResponse: 'https://developer.mozilla.org/docs/Web/API/Response',\n\tServerResponse: 'https://nodejs.org/api/http.html#class-httpserverresponse',\n\tSet: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Set',\n\tStream: 'https://nodejs.org/api/stream.html#stream',\n\tSymbolConstructor: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Symbol',\n\tTypeError: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/TypeError',\n\tURL: 'https://developer.mozilla.org/docs/Web/API/URL',\n\tURLSearchParams: 'https://developer.mozilla.org/docs/Web/API/URLSearchParams',\n\tWeakMap: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WeakMap',\n\tWeakRef: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WeakRef',\n\tWeakSet: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WeakSet',\n\tWebSocket: 'https://developer.mozilla.org/docs/Web/API/WebSocket',\n\tWorker: 'https://nodejs.org/api/worker_threads.html#class-worker',\n\t'NodeJS.Timeout': 'https://nodejs.org/api/timers.html#class-timeout',\n\n\t// Typed arrays\n\tBigInt64Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array',\n\tBigUint64Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/BigUint64Array',\n\tFloat32Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Float32Array',\n\tFloat64Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Float64Array',\n\tInt16Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Int16Array',\n\tInt32Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Int32Array',\n\tInt8Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Int8Array',\n\tUint16Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint16Array',\n\tUint32Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array',\n\tUint8Array: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array',\n\tUint8ClampedArray: 'https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray',\n\n\t// TypeScript types\n\tany: 'https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any',\n\tkeyof: 'https://www.typescriptlang.org/docs/handbook/2/keyof-types.html',\n\tnever: 'https://www.typescriptlang.org/docs/handbook/2/functions.html#never',\n\tobject: 'https://www.typescriptlang.org/docs/handbook/2/functions.html#object',\n\tReadonlyArray: 'https://www.typescriptlang.org/docs/handbook/2/objects.html#the-readonlyarray-type',\n\tReadonlyMap:\n\t\t'https://github.com/microsoft/TypeScript/blob/1416053b9e85ca2344a7a6aa10456d633ea1cd65/src/lib/es2015.collection.d.ts#L38-L43',\n\tReadonlySet:\n\t\t'https://github.com/microsoft/TypeScript/blob/1416053b9e85ca2344a7a6aa10456d633ea1cd65/src/lib/es2015.collection.d.ts#L104-L108',\n\tunknown: 'https://www.typescriptlang.org/docs/handbook/2/functions.html#unknown',\n\tthis: 'https://www.typescriptlang.org/docs/handbook/2/classes.html#this-types',\n\ttypeof: 'https://www.typescriptlang.org/docs/handbook/2/typeof-types.html',\n\tvoid: 'https://www.typescriptlang.org/docs/handbook/2/functions.html#void',\n\n\t// TypeScript utility types\n\tAwaited: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#awaitedtype',\n\tPartial: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype',\n\tRequired: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredtype',\n\tReadonly: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype',\n\tRecord: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type',\n\tPick: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys',\n\tOmit: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys',\n\tExclude: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#excludeuniontype-excludedmembers',\n\tExtract: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#extracttype-union',\n\tNonNullable: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#nonnullabletype',\n\tParameters: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#parameterstype',\n\tConstructorParameters: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#constructorparameterstype',\n\tReturnType: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype',\n\tInstanceType: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#instancetypetype',\n\tThisParameterType: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#thisparametertypetype',\n\tOmitThisParameter: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#omitthisparametertype',\n\tThisType: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#thistypetype',\n\tUppercase: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#uppercasestringtype',\n\tLowercase: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#lowercasestringtype',\n\tCapitalize: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#capitalizestringtype',\n\tUncapitalize: 'https://www.typescriptlang.org/docs/handbook/utility-types.html#uncapitalizestringtype',\n\n\t// External Libraries\n\tAsyncEventEmitter: 'https://github.com/vladfrangu/async_event_emitter',\n\tAsyncQueue: 'https://www.sapphirejs.dev/docs/Documentation/api-utilities/classes/sapphire_async_queue.AsyncQueue',\n\tRedis: 'https://redis.github.io/ioredis/classes/Redis.html',\n\t'prism.opus.Encoder': 'https://amishshah.github.io/prism-media/opus.Encoder.html',\n\t'prism.VolumeTransformer': 'https://amishshah.github.io/prism-media/core.VolumeTransformer.html',\n} as const;\n"
  },
  {
    "path": "packages/scripts/src/generateIndex.ts",
    "content": "import { stat, mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport process from 'node:process';\nimport {\n\ttype ApiItem,\n\tApiPackage,\n\tApiModel,\n\tApiDeclaredItem,\n\tApiItemContainerMixin,\n\tApiItemKind,\n} from '@discordjs/api-extractor-model';\nimport { generatePath } from '@discordjs/api-extractor-utils';\nimport { DocNodeKind } from '@microsoft/tsdoc';\nimport type { DocLinkTag, DocCodeSpan, DocNode, DocParagraph, DocPlainText } from '@microsoft/tsdoc';\nimport { resolveMembers } from './generateSplitDocumentation.js';\nimport { PACKAGES, fetchVersionDocs, fetchVersions } from './shared.js';\n\nexport interface MemberJSON {\n\tkind: string;\n\tname: string;\n\tpath: string;\n\tsummary: string | null;\n\ttype: number;\n}\n\nlet idx = 0;\n\n/**\n * Attempts to resolve the summary text for the given item.\n *\n * @param item - The API item to resolve the summary text for.\n */\nexport function tryResolveSummaryText(item: ApiDeclaredItem): string | null {\n\tif (!item?.tsdocComment) {\n\t\treturn null;\n\t}\n\n\tconst { summarySection } = item.tsdocComment;\n\n\tlet retVal = '';\n\n\t// Recursively visit the nodes in the summary section.\n\tconst visitTSDocNode = (node: DocNode) => {\n\t\tswitch (node.kind) {\n\t\t\tcase DocNodeKind.CodeSpan:\n\t\t\t\tretVal += (node as DocCodeSpan).code;\n\t\t\t\tbreak;\n\t\t\tcase DocNodeKind.PlainText:\n\t\t\t\tretVal += (node as DocPlainText).text;\n\t\t\t\tbreak;\n\t\t\tcase DocNodeKind.LinkTag: {\n\t\t\t\tconst { codeDestination, urlDestination, linkText } = node as DocLinkTag;\n\t\t\t\tif (codeDestination) {\n\t\t\t\t\tconst declarationReference = item.getAssociatedModel()?.resolveDeclarationReference(codeDestination, item);\n\t\t\t\t\tif (declarationReference?.resolvedApiItem) {\n\t\t\t\t\t\tconst foundItem = declarationReference.resolvedApiItem;\n\t\t\t\t\t\tretVal += linkText ?? foundItem.displayName;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst typeName = codeDestination.memberReferences.map((ref) => ref.memberIdentifier?.identifier).join('.');\n\t\t\t\t\t\tretVal += typeName;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tretVal += linkText ?? urlDestination;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase DocNodeKind.Section:\n\t\t\tcase DocNodeKind.Paragraph: {\n\t\t\t\tfor (const child of (node as DocParagraph).nodes) {\n\t\t\t\t\tvisitTSDocNode(child);\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault: // We'll ignore all other nodes.\n\t\t\t\tbreak;\n\t\t}\n\t};\n\n\tfor (const node of summarySection.nodes) {\n\t\tvisitTSDocNode(node);\n\t}\n\n\tif (retVal === '') {\n\t\treturn null;\n\t}\n\n\treturn retVal;\n}\n\nexport enum SearchOrderType {\n\tClass,\n\tInterface,\n\tTypeAlias,\n\tFunction,\n\tEnum,\n\tVariable,\n\tEvent,\n\tMethod,\n\tProperty,\n\tMethodSignature,\n\tPropertySignature,\n\tEnumMember,\n\tPackage,\n\tNamespace,\n\tIndexSignature,\n\tCallSignature,\n\tConstructor,\n\tConstructSignature,\n\tEntryPoint,\n\tModel,\n\tNone,\n}\n\nexport function visitNodes(item: ApiItem, tag: string) {\n\tconst members: (MemberJSON & { id: number })[] = [];\n\n\tfor (const { item: member, inherited } of ApiItemContainerMixin.isBaseClassOf(item)\n\t\t? resolveMembers(item, (child): child is ApiDeclaredItem => child instanceof ApiDeclaredItem)\n\t\t: []) {\n\t\tif (member.kind === ApiItemKind.Constructor || member.kind === ApiItemKind.Namespace) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tmembers.push(...visitNodes(member, tag));\n\n\t\tmembers.push({\n\t\t\tid: idx++,\n\t\t\tname: (inherited && member.parent\n\t\t\t\t? member.getScopedNameWithinPackage().replace(new RegExp(`^${member.parent?.displayName}`), item.displayName)\n\t\t\t\t: member.getScopedNameWithinPackage()\n\t\t\t).replaceAll('.', '#'),\n\t\t\tkind: member.kind,\n\t\t\tsummary: tryResolveSummaryText(member) ?? '',\n\t\t\tpath: generatePath(inherited ? [...item.getHierarchy(), member] : member.getHierarchy(), tag),\n\t\t\ttype: SearchOrderType[member.kind as keyof typeof SearchOrderType],\n\t\t});\n\t}\n\n\treturn members;\n}\n\nexport async function writeIndexToFileSystem(\n\tmembers: ReturnType<typeof visitNodes>,\n\tpackageName: string,\n\ttag = 'main',\n) {\n\tconst dir = 'searchIndex';\n\n\ttry {\n\t\t(await stat(join(process.cwd(), 'public', dir))).isDirectory();\n\t} catch {\n\t\tawait mkdir(join(process.cwd(), 'public', dir));\n\t}\n\n\tawait writeFile(\n\t\tjoin(process.cwd(), 'public', dir, `${packageName}-${tag}-index.json`),\n\t\tJSON.stringify(members, undefined, 2),\n\t);\n}\n\nexport async function generateAllIndices({\n\tfetchPackageVersions = fetchVersions,\n\tfetchPackageVersionDocs = fetchVersionDocs,\n\twriteToFile = true,\n} = {}) {\n\tconst indices: {\n\t\tdata: ReturnType<typeof visitNodes>;\n\t\tindex: string;\n\t}[] = [];\n\n\tfor (const pkg of PACKAGES) {\n\t\tconst versions = await fetchPackageVersions(pkg);\n\n\t\tfor (const version of versions) {\n\t\t\tidx = 0;\n\n\t\t\tconst data = await fetchPackageVersionDocs(pkg, version);\n\t\t\tconst model = new ApiModel();\n\t\t\tmodel.addMember(ApiPackage.loadFromJson(data));\n\t\t\tconst members = visitNodes(model.tryGetPackageByName(pkg)!.entryPoints[0]!, version);\n\n\t\t\tconst sanitizePackageName = pkg.replaceAll('.', '-');\n\t\t\tconst sanitizeVersion = version.replaceAll('.', '-');\n\n\t\t\tif (writeToFile) {\n\t\t\t\tawait writeIndexToFileSystem(members, sanitizePackageName, sanitizeVersion);\n\t\t\t} else {\n\t\t\t\tindices.push({ index: `${sanitizePackageName}-${sanitizeVersion}`, data: members });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn indices;\n}\n"
  },
  {
    "path": "packages/scripts/src/generateSplitDocumentation.ts",
    "content": "import { mkdir, stat, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport process from 'node:process';\nimport {\n\ttype ApiClass,\n\ttype ApiConstructor,\n\ttype ApiDeclaredItem,\n\ttype ApiDocumentedItem,\n\ttype ApiEntryPoint,\n\ttype ApiEnum,\n\ttype ApiEnumMember,\n\ttype ApiEvent,\n\ttype ApiInterface,\n\ttype ApiItem,\n\ttype ApiItemContainerMixin,\n\ttype ApiMethod,\n\ttype ApiMethodSignature,\n\ttype ApiProperty,\n\ttype ApiPropertySignature,\n\ttype ApiTypeAlias,\n\ttype ApiVariable,\n\tApiTypeParameterListMixin,\n\tExcerpt,\n\tMeaning,\n\tApiAbstractMixin,\n\tApiFunction,\n\tApiItemKind,\n\tApiModel,\n\tApiPackage,\n\tApiParameterListMixin,\n\tApiProtectedMixin,\n\tApiReadonlyMixin,\n\tApiStaticMixin,\n\tExcerptTokenKind,\n\tExcerptToken,\n\tApiOptionalMixin,\n} from '@discordjs/api-extractor-model';\nimport { DocNodeKind, SelectorKind, StandardTags } from '@microsoft/tsdoc';\nimport type {\n\tDocEscapedText,\n\tDocNode,\n\tDocNodeContainer,\n\tDocDeclarationReference,\n\tDocPlainText,\n\tDocLinkTag,\n\tDocFencedCode,\n\tDocComment,\n} from '@microsoft/tsdoc';\nimport type { DeclarationReference, ModuleSource } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference.js';\nimport { BuiltinDocumentationLinks } from './builtinDocumentationLinks.js';\nimport { PACKAGES, fetchVersionDocs, fetchVersions } from './shared.js';\n\nfunction findMemberByKey(entry: ApiEntryPoint, containerKey: string) {\n\treturn entry.tryGetMemberByKey(containerKey);\n}\n\nfunction findMember(entry: ApiEntryPoint, memberName: string | undefined) {\n\tif (!memberName) {\n\t\treturn undefined;\n\t}\n\n\treturn entry.findMembersByName(memberName)[0];\n}\n\n/**\n * Resolves all inherited members (including merged members) of a given parent.\n *\n * @param parent - The parent to resolve the inherited members of.\n * @param predicate - A predicate to filter the members by.\n */\nexport function resolveMembers<WantedItem extends ApiItem>(\n\tparent: ApiItemContainerMixin,\n\tpredicate: (item: ApiItem) => item is WantedItem,\n) {\n\tconst seenItems = new Set<string>();\n\tconst inheritedMembers = parent.findMembersWithInheritance().items.reduce((acc, item) => {\n\t\tif (predicate(item) && !seenItems.has(item.displayName)) {\n\t\t\tacc.push({\n\t\t\t\titem,\n\t\t\t\tinherited:\n\t\t\t\t\titem.parent?.containerKey === parent.containerKey\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: (item.parent as ApiItemContainerMixin | undefined),\n\t\t\t});\n\n\t\t\tseenItems.add(item.displayName);\n\t\t}\n\n\t\treturn acc;\n\t}, new Array<{ inherited?: ApiItemContainerMixin | undefined; item: WantedItem }>());\n\n\tconst mergedMembers = parent\n\t\t.getMergedSiblings()\n\t\t.filter((sibling) => sibling.containerKey !== parent.containerKey)\n\t\t.flatMap((sibling) => (sibling as ApiItemContainerMixin).findMembersWithInheritance().items)\n\t\t.filter((item) => predicate(item) && !seenItems.has(item.displayName))\n\t\t.map((item) => ({\n\t\t\titem: item as WantedItem,\n\t\t\tinherited: item.parent ? (item.parent as ApiItemContainerMixin) : undefined,\n\t\t}));\n\n\treturn [...inheritedMembers, ...mergedMembers];\n}\n\nconst kindToMeaning = new Map([\n\t[ApiItemKind.CallSignature, Meaning.CallSignature],\n\t[ApiItemKind.Class, Meaning.Class],\n\t[ApiItemKind.ConstructSignature, Meaning.ConstructSignature],\n\t[ApiItemKind.Constructor, Meaning.Constructor],\n\t[ApiItemKind.Enum, Meaning.Enum],\n\t[ApiItemKind.Event, Meaning.Event],\n\t[ApiItemKind.Function, Meaning.Function],\n\t[ApiItemKind.IndexSignature, Meaning.IndexSignature],\n\t[ApiItemKind.Interface, Meaning.Interface],\n\t[ApiItemKind.Property, Meaning.Member],\n\t[ApiItemKind.Namespace, Meaning.Namespace],\n\t[ApiItemKind.None, Meaning.ComplexType],\n\t[ApiItemKind.TypeAlias, Meaning.TypeAlias],\n\t[ApiItemKind.Variable, Meaning.Variable],\n]);\n\nfunction mapMeaningToKind(meaning: Meaning): ApiItemKind {\n\treturn [...kindToMeaning.entries()].find((mapping) => mapping[1] === meaning)?.[0] ?? ApiItemKind.None;\n}\n\n// function mapKindToMeaning(kind: ApiItemKind): Meaning {\n// \treturn kindToMeaning.get(kind) ?? Meaning.Variable;\n// }\n\nfunction resolveCanonicalReference(\n\tcanonicalReference: DeclarationReference | DocDeclarationReference,\n\tapiPackage: ApiPackage | undefined,\n) {\n\tif (\n\t\t'source' in canonicalReference &&\n\t\tcanonicalReference.source &&\n\t\t'packageName' in canonicalReference.source &&\n\t\tcanonicalReference.symbol?.componentPath &&\n\t\tcanonicalReference.symbol.meaning\n\t)\n\t\treturn {\n\t\t\tpackage: canonicalReference.source.packageName,\n\t\t\tunscopedPackage: canonicalReference.source.unscopedPackageName,\n\t\t\titem: {\n\t\t\t\tkind: mapMeaningToKind(canonicalReference.symbol.meaning as unknown as Meaning),\n\t\t\t\tdisplayName: canonicalReference.symbol.componentPath.component.toString(),\n\t\t\t\tcontainerKey: `|${\n\t\t\t\t\tcanonicalReference.symbol.meaning\n\t\t\t\t}|${canonicalReference.symbol.componentPath.component.toString()}`,\n\t\t\t\tgetAssociatedEntryPoint() {\n\t\t\t\t\treturn canonicalReference.source as ModuleSource;\n\t\t\t\t},\n\t\t\t},\n\t\t\t// eslint-disable-next-line unicorn/better-regex\n\t\t\tversion: apiPackage?.dependencies?.[canonicalReference.source.packageName]?.replace(/[~^]/, ''),\n\t\t};\n\telse if (\n\t\t'memberReferences' in canonicalReference &&\n\t\tcanonicalReference.memberReferences.length &&\n\t\tcanonicalReference.memberReferences[0]?.memberIdentifier &&\n\t\tcanonicalReference.memberReferences[0]?.selector?.selectorKind === SelectorKind.System\n\t) {\n\t\tconst member = canonicalReference.memberReferences[0]!;\n\t\treturn {\n\t\t\tpackage: canonicalReference.packageName?.replace('@discordjs/', ''),\n\t\t\titem: {\n\t\t\t\tkind: member.selector!.selector,\n\t\t\t\tdisplayName: member.memberIdentifier!.identifier,\n\t\t\t\tcontainerKey: `|${member.selector!.selector}|${member.memberIdentifier!.identifier}`,\n\t\t\t\tmembers: canonicalReference.memberReferences\n\t\t\t\t\t.slice(1)\n\t\t\t\t\t.map((member) => ({ kind: member.kind, displayName: member.memberIdentifier!.identifier! })),\n\t\t\t\tgetAssociatedEntryPoint() {\n\t\t\t\t\treturn canonicalReference;\n\t\t\t\t},\n\t\t\t},\n\t\t\t// eslint-disable-next-line unicorn/better-regex\n\t\t\tversion: apiPackage?.dependencies?.[canonicalReference.packageName ?? '']?.replace(/[~^]/, ''),\n\t\t};\n\t}\n\n\treturn null;\n}\n\nexport function memberPredicate(\n\titem: ApiItem,\n): item is ApiEvent | ApiMethod | ApiMethodSignature | ApiProperty | ApiPropertySignature {\n\treturn (\n\t\titem.kind === ApiItemKind.Property ||\n\t\titem.kind === ApiItemKind.PropertySignature ||\n\t\titem.kind === ApiItemKind.Method ||\n\t\titem.kind === ApiItemKind.MethodSignature ||\n\t\titem.kind === ApiItemKind.Event\n\t);\n}\n\nexport function hasProperties(item: ApiItemContainerMixin) {\n\treturn resolveMembers(item, memberPredicate).some(\n\t\t({ item: member }) => member.kind === ApiItemKind.Property || member.kind === ApiItemKind.PropertySignature,\n\t);\n}\n\nexport function hasMethods(item: ApiItemContainerMixin) {\n\treturn resolveMembers(item, memberPredicate).some(\n\t\t({ item: member }) => member.kind === ApiItemKind.Method || member.kind === ApiItemKind.MethodSignature,\n\t);\n}\n\nexport function hasEvents(item: ApiItemContainerMixin) {\n\treturn resolveMembers(item, memberPredicate).some(({ item: member }) => member.kind === ApiItemKind.Event);\n}\n\ninterface ApiEntryPointLike {\n\timportPath: string | undefined;\n}\n\ninterface ApiItemLike {\n\tcontainerKey?: string;\n\tdisplayName: string;\n\tgetAssociatedEntryPoint?(): ApiEntryPointLike | undefined;\n\tkind: string;\n\tmembers?: readonly ApiItemLike[];\n\tparent?: ApiItemLike | undefined;\n}\n\nfunction resolveItemURI(item: ApiItemLike, entryPoint?: ApiEntryPoint): string {\n\tconst actualEntryPoint = entryPoint ?? item.getAssociatedEntryPoint?.();\n\treturn `${actualEntryPoint?.importPath ? `${actualEntryPoint.importPath}/` : ''}${\n\t\t!item.parent || item.parent.kind === ApiItemKind.EntryPoint\n\t\t\t? `${item.displayName}:${item.kind}`\n\t\t\t: `${item.parent.displayName}:${item.parent.kind}#${item.displayName}`\n\t}`;\n}\n\nfunction itemExcerptText(excerpt: Excerpt, apiPackage: ApiPackage, parent?: ApiTypeParameterListMixin) {\n\treturn excerpt.spannedTokens.map((token) => {\n\t\tif (token.kind === ExcerptTokenKind.Reference) {\n\t\t\tif (token.canonicalReference) {\n\t\t\t\tconst resolved = resolveCanonicalReference(token.canonicalReference, apiPackage);\n\n\t\t\t\tif (!resolved) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttext: token.text,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst declarationReference = apiPackage\n\t\t\t\t\t.getAssociatedModel()\n\t\t\t\t\t?.resolveDeclarationReference(token.canonicalReference, apiPackage);\n\t\t\t\tconst foundItem = declarationReference?.resolvedApiItem ?? resolved.item;\n\n\t\t\t\treturn {\n\t\t\t\t\ttext: token.text,\n\t\t\t\t\tresolvedItem: {\n\t\t\t\t\t\tkind: foundItem.kind,\n\t\t\t\t\t\tdisplayName: foundItem.displayName,\n\t\t\t\t\t\tcontainerKey: foundItem.containerKey,\n\t\t\t\t\t\turi: resolveItemURI(foundItem),\n\t\t\t\t\t\tpackageName: resolved.package?.replace('@discordjs/', ''),\n\t\t\t\t\t\tversion: resolved.version,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (token.text in BuiltinDocumentationLinks) {\n\t\t\t\treturn {\n\t\t\t\t\ttext: token.text,\n\t\t\t\t\thref: BuiltinDocumentationLinks[token.text as keyof typeof BuiltinDocumentationLinks],\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (parent?.typeParameters.some((type) => type.name === token.text)) {\n\t\t\t\tconst resolvedParent = resolveCanonicalReference(parent.canonicalReference, apiPackage);\n\t\t\t\treturn {\n\t\t\t\t\ttext: token.text,\n\t\t\t\t\tresolvedItem: {\n\t\t\t\t\t\tkind: 'TypeParameter',\n\t\t\t\t\t\tdisplayName: token.text,\n\t\t\t\t\t\tcontainerKey: `${parent.containerKey}|${token.text}`,\n\t\t\t\t\t\turi: `${resolveItemURI(parent)}#${token.text}`,\n\t\t\t\t\t\tpackageName: resolvedParent?.package?.replace('@discordjs/', ''),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttext: token.text,\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\ttext: token.text.replace(/import\\(\"discord-api-types(?:\\/v\\d+)?\"\\)\\./, ''),\n\t\t};\n\t});\n}\n\nfunction itemTsDoc(item: DocNode, apiItem: ApiItem) {\n\tconst createNode = (node: DocNode): any => {\n\t\tswitch (node.kind) {\n\t\t\tcase DocNodeKind.PlainText:\n\t\t\t\treturn {\n\t\t\t\t\tkind: DocNodeKind.PlainText,\n\t\t\t\t\ttext: (node as DocPlainText).text,\n\t\t\t\t};\n\t\t\tcase DocNodeKind.EscapedText:\n\t\t\t\treturn {\n\t\t\t\t\tkind: DocNodeKind.PlainText,\n\t\t\t\t\ttext: (node as DocEscapedText).decodedText,\n\t\t\t\t};\n\t\t\tcase DocNodeKind.Section:\n\t\t\tcase DocNodeKind.Paragraph:\n\t\t\t\treturn (node as DocNodeContainer).nodes.map((node) => createNode(node));\n\t\t\tcase DocNodeKind.SoftBreak:\n\t\t\t\treturn {\n\t\t\t\t\tkind: DocNodeKind.SoftBreak,\n\t\t\t\t\ttext: null,\n\t\t\t\t};\n\t\t\tcase DocNodeKind.LinkTag: {\n\t\t\t\tconst { codeDestination, urlDestination, linkText } = node as DocLinkTag;\n\n\t\t\t\tif (codeDestination) {\n\t\t\t\t\t// if (\n\t\t\t\t\t// \t!codeDestination.importPath &&\n\t\t\t\t\t// \t!codeDestination.packageName &&\n\t\t\t\t\t// \tcodeDestination.memberReferences.length === 1 &&\n\t\t\t\t\t// \tcodeDestination.memberReferences[0]!.memberIdentifier\n\t\t\t\t\t// ) {\n\t\t\t\t\t// \tconst typeName = codeDestination.memberReferences[0]!.memberIdentifier.identifier;\n\n\t\t\t\t\t// \treturn {\n\t\t\t\t\t// \t\tkind: DocNodeKind.LinkTag,\n\t\t\t\t\t// \t\ttext: typeName,\n\t\t\t\t\t// \t};\n\t\t\t\t\t// }\n\n\t\t\t\t\tconst declarationReference = apiItem\n\t\t\t\t\t\t.getAssociatedModel()\n\t\t\t\t\t\t?.resolveDeclarationReference(codeDestination, apiItem);\n\t\t\t\t\tconst foundItem = declarationReference?.resolvedApiItem;\n\t\t\t\t\tconst resolved = resolveCanonicalReference(codeDestination, apiItem.getAssociatedPackage());\n\n\t\t\t\t\tif (!foundItem && !resolved) {\n\t\t\t\t\t\tconst itemName = codeDestination.memberReferences[0]?.memberIdentifier?.identifier;\n\n\t\t\t\t\t\tif (itemName && itemName in BuiltinDocumentationLinks) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tkind: DocNodeKind.LinkTag,\n\t\t\t\t\t\t\t\ttext: itemName,\n\t\t\t\t\t\t\t\turi: BuiltinDocumentationLinks[itemName as keyof typeof BuiltinDocumentationLinks],\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tkind: DocNodeKind.LinkTag,\n\t\t\t\t\t\t\ttext: itemName ?? null,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: DocNodeKind.LinkTag,\n\t\t\t\t\t\ttext: linkText ?? foundItem?.displayName ?? resolved!.item.displayName,\n\t\t\t\t\t\turi: resolveItemURI(foundItem ?? resolved!.item),\n\t\t\t\t\t\tresolvedPackage: {\n\t\t\t\t\t\t\tpackageName: resolved?.package ?? apiItem.getAssociatedPackage()?.displayName.replace('@discordjs/', ''),\n\t\t\t\t\t\t\tversion: resolved?.package\n\t\t\t\t\t\t\t\t? (apiItem.getAssociatedPackage()?.dependencies?.[resolved.package] ?? null)\n\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif (urlDestination) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: DocNodeKind.LinkTag,\n\t\t\t\t\t\ttext: linkText ?? urlDestination,\n\t\t\t\t\t\turi: urlDestination,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tkind: DocNodeKind.LinkTag,\n\t\t\t\t\ttext: null,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tcase DocNodeKind.CodeSpan: {\n\t\t\t\tconst { code } = node as DocFencedCode;\n\n\t\t\t\treturn {\n\t\t\t\t\tkind: DocNodeKind.CodeSpan,\n\t\t\t\t\ttext: code,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tcase DocNodeKind.FencedCode: {\n\t\t\t\tconst { language, code } = node as DocFencedCode;\n\n\t\t\t\treturn {\n\t\t\t\t\tkind: DocNodeKind.FencedCode,\n\t\t\t\t\ttext: code,\n\t\t\t\t\tlanguage,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tcase DocNodeKind.Comment: {\n\t\t\t\tconst comment = node as DocComment;\n\n\t\t\t\tconst exampleBlocks = comment.customBlocks.filter(\n\t\t\t\t\t(block) => block.blockTag.tagNameWithUpperCase === StandardTags.example.tagNameWithUpperCase,\n\t\t\t\t);\n\n\t\t\t\tconst defaultValueBlock = comment.customBlocks.find(\n\t\t\t\t\t(block) => block.blockTag.tagNameWithUpperCase === StandardTags.defaultValue.tagNameWithUpperCase,\n\t\t\t\t);\n\n\t\t\t\tconst unstableBlock = comment.customBlocks.find((block) => block.blockTag.tagNameWithUpperCase === '@UNSTABLE');\n\n\t\t\t\tconst mixesBlocks = comment.customBlocks.filter((block) => block.blockTag.tagNameWithUpperCase === '@MIXES');\n\n\t\t\t\treturn {\n\t\t\t\t\tkind: DocNodeKind.Comment,\n\t\t\t\t\tdeprecatedBlock: comment.deprecatedBlock\n\t\t\t\t\t\t? createNode(comment.deprecatedBlock.content)\n\t\t\t\t\t\t\t\t.flat(1)\n\t\t\t\t\t\t\t\t.filter((val: any) => val.kind !== DocNodeKind.SoftBreak)\n\t\t\t\t\t\t: [],\n\t\t\t\t\tsummarySection: comment.summarySection\n\t\t\t\t\t\t? createNode(comment.summarySection)\n\t\t\t\t\t\t\t\t.flat(1)\n\t\t\t\t\t\t\t\t.filter((val: any) => val.kind !== DocNodeKind.SoftBreak)\n\t\t\t\t\t\t: [],\n\t\t\t\t\tremarksBlock: comment.remarksBlock\n\t\t\t\t\t\t? createNode(comment.remarksBlock.content)\n\t\t\t\t\t\t\t\t.flat(1)\n\t\t\t\t\t\t\t\t.filter((val: any) => val.kind !== DocNodeKind.SoftBreak)\n\t\t\t\t\t\t: [],\n\t\t\t\t\tdefaultValueBlock: defaultValueBlock\n\t\t\t\t\t\t? createNode(defaultValueBlock.content)\n\t\t\t\t\t\t\t\t.flat(1)\n\t\t\t\t\t\t\t\t.filter((val: any) => val.kind !== DocNodeKind.SoftBreak)\n\t\t\t\t\t\t: [],\n\t\t\t\t\treturnsBlock: comment.returnsBlock\n\t\t\t\t\t\t? createNode(comment.returnsBlock.content)\n\t\t\t\t\t\t\t\t.flat(1)\n\t\t\t\t\t\t\t\t.filter((val: any) => val.kind !== DocNodeKind.SoftBreak)\n\t\t\t\t\t\t: [],\n\t\t\t\t\tunstableBlock: unstableBlock\n\t\t\t\t\t\t? createNode(unstableBlock.content)\n\t\t\t\t\t\t\t\t.flat(1)\n\t\t\t\t\t\t\t\t.filter((val: any) => val.kind !== DocNodeKind.SoftBreak)\n\t\t\t\t\t\t: [],\n\t\t\t\t\texampleBlocks: exampleBlocks\n\t\t\t\t\t\t.flatMap((block) => createNode(block.content).flat(1))\n\t\t\t\t\t\t.filter((val: any) => val.kind !== DocNodeKind.SoftBreak),\n\t\t\t\t\tseeBlocks: comment.seeBlocks\n\t\t\t\t\t\t.flatMap((block) => createNode(block.content).flat(1))\n\t\t\t\t\t\t.filter((val: any) => val.kind !== DocNodeKind.SoftBreak),\n\t\t\t\t\tmixesBlocks: mixesBlocks\n\t\t\t\t\t\t.flatMap((block) => createNode(block.content).flat(1))\n\t\t\t\t\t\t.filter((val: any) => val.kind !== DocNodeKind.SoftBreak),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\treturn {};\n\t\t}\n\t};\n\n\treturn item.kind === DocNodeKind.Paragraph || item.kind === DocNodeKind.Section\n\t\t? (item as DocNodeContainer).nodes\n\t\t\t\t.flatMap((node) => createNode(node))\n\t\t\t\t.filter((val: any) => val.kind !== DocNodeKind.SoftBreak)\n\t\t: createNode(item);\n}\n\nfunction itemInfo(item: ApiDeclaredItem) {\n\tconst sourceExcerpt = item.excerpt.text.trim();\n\tconst { sourceURL, sourceLine } = resolveFileUrl(item);\n\n\tconst isStatic = ApiStaticMixin.isBaseClassOf(item) && item.isStatic;\n\tconst isProtected = ApiProtectedMixin.isBaseClassOf(item) && item.isProtected;\n\tconst isReadonly = ApiReadonlyMixin.isBaseClassOf(item) && item.isReadonly;\n\tconst isAbstract = ApiAbstractMixin.isBaseClassOf(item) && item.isAbstract;\n\tconst isOptional = ApiOptionalMixin.isBaseClassOf(item) && item.isOptional;\n\tconst isDeprecated = Boolean(item.tsdocComment?.deprecatedBlock);\n\tconst isExternal = Boolean(sourceLine === undefined);\n\tconst hasSummary = Boolean(item.tsdocComment?.summarySection);\n\n\treturn {\n\t\tkind: item.kind,\n\t\tdisplayName: item.displayName,\n\t\tsourceURL,\n\t\tsourceLine,\n\t\tsourceExcerpt,\n\t\tsummary: hasSummary ? itemTsDoc(item.tsdocComment!, item) : null,\n\t\tisStatic,\n\t\tisProtected,\n\t\tisReadonly,\n\t\tisAbstract,\n\t\tisDeprecated,\n\t\tisOptional,\n\t\tisExternal,\n\t};\n}\n\nfunction resolveFileUrl(item: ApiDeclaredItem) {\n\tconst {\n\t\tsourceLocation: { fileUrl, fileLine },\n\t} = item;\n\tif (fileUrl?.includes('/node_modules/')) {\n\t\tconst [, pkg] = fileUrl.split('/node_modules/');\n\t\tconst parts = pkg?.split('/')[1]?.split('@');\n\t\tconst unscoped = parts?.[0]?.length;\n\t\tif (!unscoped) parts?.shift();\n\t\tconst pkgName = parts?.shift();\n\t\tconst version = parts?.shift()?.split('_')?.[0];\n\n\t\t// https://github.com/discordjs/discord.js/tree/main/node_modules/.pnpm/@discordjs+builders@1.9.0/node_modules/@discordjs/builders/dist/index.d.ts#L1764\n\t\t// https://github.com/discordjs/discord.js/tree/main/node_modules/.pnpm/@discordjs+ws@1.1.1_bufferutil@4.0.8_utf-8-validate@6.0.4/node_modules/@discordjs/ws/dist/index.d.ts#L...\n\t\tif (!unscoped && pkgName?.startsWith('discordjs+')) {\n\t\t\tlet currentItem = item;\n\t\t\twhile (currentItem.parent && currentItem.parent.kind !== ApiItemKind.EntryPoint)\n\t\t\t\tcurrentItem = currentItem.parent as ApiDeclaredItem;\n\n\t\t\treturn {\n\t\t\t\tsourceURL: `/docs/packages/${pkgName.replace('discordjs+', '')}/${version}/${currentItem.displayName}:${currentItem.kind}`,\n\t\t\t};\n\t\t}\n\n\t\t// https://github.com/discordjs/discord.js/tree/main/node_modules/.pnpm/discord-api-types@0.37.97/node_modules/discord-api-types/payloads/v10/gateway.d.ts#L240\n\t\tif (pkgName === 'discord-api-types') {\n\t\t\tlet currentItem = item;\n\t\t\twhile (currentItem.parent && currentItem.parent.kind !== ApiItemKind.EntryPoint)\n\t\t\t\tcurrentItem = currentItem.parent as ApiDeclaredItem;\n\n\t\t\treturn {\n\t\t\t\tsourceURL: `/docs/packages/${pkgName}/${version}/${(currentItem.parent as ApiEntryPoint).importPath}/${currentItem.displayName}:${currentItem.kind}`,\n\t\t\t};\n\t\t}\n\t} else if (fileUrl?.includes('/dist/') && fileUrl.includes('/main/packages/')) {\n\t\tconst [, pkg] = fileUrl.split('/main/packages/');\n\t\tconst pkgName = pkg!.split('/')[0];\n\t\tconst version = 'main';\n\n\t\t// https://github.com/discordjs/discord.js/tree/main/packages/builders/dist/index.d.ts\n\t\tlet currentItem = item;\n\t\twhile (currentItem.parent && currentItem.parent.kind !== ApiItemKind.EntryPoint)\n\t\t\tcurrentItem = currentItem.parent as ApiDeclaredItem;\n\n\t\treturn {\n\t\t\tsourceURL: `/docs/packages/${pkgName}/${version}/${currentItem.displayName}:${currentItem.kind}`,\n\t\t};\n\t}\n\n\treturn {\n\t\tsourceURL: fileUrl,\n\t\tsourceLine: fileLine,\n\t};\n}\n\n/**\n * This takes an api item with a parameter list and resolves the names and descriptions of all the parameters.\n *\n * @remarks\n * This is different from accessing `Parameter#name` or `Parameter.tsdocBlockComment` as this method cross-references the associated tsdoc\n * parameter names and descriptions and uses them as a higher precedence to the source code.\n * @param item - The api item to resolve parameter data for\n * @returns An array of parameters\n */\nfunction resolveParameters(item: ApiDocumentedItem & ApiParameterListMixin) {\n\treturn item.parameters.map((param, idx) => {\n\t\tconst tsdocAnalog =\n\t\t\titem.tsdocComment?.params.blocks[idx] ??\n\t\t\titem\n\t\t\t\t.getMergedSiblings()\n\t\t\t\t.find(\n\t\t\t\t\t(paramList): paramList is ApiDocumentedItem & ApiParameterListMixin =>\n\t\t\t\t\t\tApiParameterListMixin.isBaseClassOf(paramList) && paramList.overloadIndex === 1,\n\t\t\t\t)?.tsdocComment?.params.blocks[idx];\n\n\t\treturn {\n\t\t\tname: param.tsdocParamBlock?.parameterName ?? tsdocAnalog?.parameterName ?? param.name,\n\t\t\tdescription: param.tsdocParamBlock?.content ?? tsdocAnalog?.content,\n\t\t\tisOptional: param.isOptional,\n\t\t\tisRest: param.isRest,\n\t\t\tparameterTypeExcerpt: param.parameterTypeExcerpt,\n\t\t\tdefaultValue: param.defaultValue,\n\t\t};\n\t});\n}\n\nfunction itemTypeParameters(item: ApiTypeParameterListMixin) {\n\t// {\n\t//     Name: typeParam.name,\n\t//     Constraints: <ExcerptText excerpt={typeParam.constraintExcerpt} apiPackage={item.getAssociatedPackage()!} />,\n\t//     Optional: typeParam.isOptional ? 'Yes' : 'No',\n\t//     Default: <ExcerptText excerpt={typeParam.defaultTypeExcerpt} apiPackage={item.getAssociatedPackage()!} />,\n\t//     Description: typeParam.tsdocTypeParamBlock ? (\n\t//         <TSDoc item={item} tsdoc={typeParam.tsdocTypeParamBlock.content} />\n\t//     ) : (\n\t//         'None'\n\t//     ),\n\t// }\n\n\treturn item.typeParameters.map((typeParam) => ({\n\t\tname: typeParam.name,\n\t\tconstraintsExcerpt: itemExcerptText(typeParam.constraintExcerpt, item.getAssociatedPackage()!, item),\n\t\tisOptional: typeParam.isOptional,\n\t\tdefaultExcerpt: itemExcerptText(typeParam.defaultTypeExcerpt, item.getAssociatedPackage()!, item),\n\t\tdescription: typeParam.tsdocTypeParamBlock ? itemTsDoc(typeParam.tsdocTypeParamBlock.content, item) : null,\n\t}));\n}\n\nfunction itemParameters(item: ApiDocumentedItem & ApiParameterListMixin) {\n\tconst params = resolveParameters(item);\n\n\t// {\n\t//     Name: param.isRest ? `...${param.name}` : param.name,\n\t//     Type: <ExcerptText excerpt={param.parameterTypeExcerpt} apiPackage={item.getAssociatedPackage()!} />,\n\t//     Optional: param.isOptional ? 'Yes' : 'No',\n\t//     Description: param.description ? <TSDoc item={item} tsdoc={param.description} /> : 'None',\n\t// }\n\n\treturn params.map((param) => ({\n\t\tname: param.isRest ? `...${param.name}` : param.name,\n\t\ttypeExcerpt: itemExcerptText(\n\t\t\tparam.parameterTypeExcerpt,\n\t\t\titem.getAssociatedPackage()!,\n\t\t\titem.getHierarchy().find(ApiTypeParameterListMixin.isBaseClassOf),\n\t\t),\n\t\tisOptional: param.isOptional,\n\t\tdescription: param.description ? itemTsDoc(param.description, item) : null,\n\t\tdefaultValue: param.defaultValue,\n\t}));\n}\n\nfunction itemConstructor(item: ApiConstructor) {\n\treturn {\n\t\t...itemInfo(item),\n\t\tparametersString: parametersString(item),\n\t\tparameters: itemParameters(item),\n\t};\n}\n\nfunction isEventLike(item: ApiItem): item is ApiEvent {\n\treturn item.kind === ApiItemKind.Event;\n}\n\nfunction itemEvent(item: ApiItemContainerMixin) {\n\tconst members = resolveMembers(item, isEventLike);\n\n\treturn members.map((event) => {\n\t\tconst hasSummary = Boolean(event.item.tsdocComment?.summarySection);\n\n\t\treturn {\n\t\t\t...itemInfo(event.item),\n\t\t\tinheritedFrom: event.inherited ? resolveItemURI(event.inherited) : null,\n\t\t\tsummary: hasSummary ? itemTsDoc(event.item.tsdocComment!, event.item) : null,\n\t\t\tparameters: itemParameters(event.item),\n\t\t};\n\t});\n}\n\nfunction isPropertyLike(item: ApiItem): item is ApiProperty | ApiPropertySignature {\n\treturn item.kind === ApiItemKind.Property || item.kind === ApiItemKind.PropertySignature;\n}\n\nfunction itemProperty(item: ApiItemContainerMixin) {\n\tconst members = resolveMembers(item, isPropertyLike);\n\n\treturn members.map((property) => {\n\t\tconst hasSummary = Boolean(property.item.tsdocComment?.summarySection);\n\n\t\treturn {\n\t\t\t...itemInfo(property.item),\n\t\t\tinheritedFrom: property.inherited ? resolveItemURI(property.inherited) : null,\n\t\t\ttypeExcerpt: itemExcerptText(\n\t\t\t\tproperty.item.propertyTypeExcerpt,\n\t\t\t\tproperty.item.getAssociatedPackage()!,\n\t\t\t\tproperty.item.getHierarchy().find(ApiTypeParameterListMixin.isBaseClassOf),\n\t\t\t),\n\t\t\tsummary: hasSummary ? itemTsDoc(property.item.tsdocComment!, property.item) : null,\n\t\t};\n\t});\n}\n\nfunction parametersString(item: ApiDocumentedItem & ApiParameterListMixin) {\n\treturn resolveParameters(item).reduce((prev, cur, index) => {\n\t\tif (index === 0) {\n\t\t\treturn `${prev}${cur.isRest ? '...' : ''}${cur.isOptional ? `${cur.name}?` : cur.name}`;\n\t\t}\n\n\t\treturn `${prev}, ${cur.isRest ? '...' : ''}${cur.isOptional ? `${cur.name}?` : cur.name}`;\n\t}, '');\n}\n\nfunction isMethodLike(item: ApiItem): item is ApiMethod | ApiMethodSignature {\n\treturn (\n\t\titem.kind === ApiItemKind.Method ||\n\t\t(item.kind === ApiItemKind.MethodSignature && (item as ApiMethod).overloadIndex <= 1)\n\t);\n}\n\nfunction itemMethod(item: ApiItemContainerMixin) {\n\tconst members = resolveMembers(item, isMethodLike);\n\n\tconst methodItem = (method: {\n\t\tinherited?: ApiItemContainerMixin | undefined;\n\t\titem: ApiMethod | ApiMethodSignature;\n\t}) => {\n\t\tconst hasSummary = Boolean(method.item.tsdocComment?.summarySection);\n\n\t\treturn {\n\t\t\t...itemInfo(method.item),\n\t\t\toverloadIndex: method.item.overloadIndex,\n\t\t\tparametersString: parametersString(method.item),\n\t\t\treturnTypeExcerpt: itemExcerptText(\n\t\t\t\tmethod.item.returnTypeExcerpt,\n\t\t\t\tmethod.item.getAssociatedPackage()!,\n\t\t\t\tmethod.item.getHierarchy().find(ApiTypeParameterListMixin.isBaseClassOf),\n\t\t\t),\n\t\t\tinheritedFrom: method.inherited ? resolveItemURI(method.inherited) : null,\n\t\t\ttypeParameters: itemTypeParameters(method.item),\n\t\t\tparameters: itemParameters(method.item),\n\t\t\tsummary: hasSummary ? itemTsDoc(method.item.tsdocComment!, method.item) : null,\n\t\t};\n\t};\n\n\treturn members.map((method) => {\n\t\t// const parent = method.item.parent as ApiDeclaredItem;\n\t\tconst hasOverload =\n\t\t\tmethod.item\n\t\t\t\t.getMergedSiblings()\n\t\t\t\t.filter((sibling) => sibling.kind === ApiItemKind.Method || sibling.kind === ApiItemKind.MethodSignature)\n\t\t\t\t.length > 1;\n\n\t\tconst overloads = method.item\n\t\t\t.getMergedSiblings()\n\t\t\t.filter((sibling) => sibling.kind === ApiItemKind.Method || sibling.kind === ApiItemKind.MethodSignature)\n\t\t\t.map((sibling) => methodItem({ item: sibling as ApiMethod | ApiMethodSignature }));\n\n\t\treturn {\n\t\t\t...methodItem(method),\n\t\t\toverloads: hasOverload ? overloads : [],\n\t\t};\n\t});\n}\n\nfunction itemMembers(item: ApiDeclaredItem & ApiItemContainerMixin) {\n\tconst events = hasEvents(item) ? itemEvent(item) : [];\n\tconst properties = hasProperties(item) ? itemProperty(item) : [];\n\tconst methods = hasMethods(item) ? itemMethod(item) : [];\n\n\treturn {\n\t\tevents,\n\t\tproperties,\n\t\tmethods,\n\t};\n}\n\nexport function itemHierarchyText({\n\titem,\n\ttype,\n}: {\n\treadonly item: ApiClass | ApiInterface;\n\treadonly type: 'Extends' | 'Implements';\n}) {\n\tif (\n\t\t(item.kind === ApiItemKind.Class &&\n\t\t\t(item as ApiClass).extendsType === undefined &&\n\t\t\t(item as ApiClass).implementsTypes.length === 0) ||\n\t\t(item.kind === ApiItemKind.Interface && !(item as ApiInterface).extendsTypes)\n\t) {\n\t\treturn null;\n\t}\n\n\tlet excerpts: Excerpt[];\n\n\tif (item.kind === ApiItemKind.Class) {\n\t\tif (type === 'Implements') {\n\t\t\tif ((item as ApiClass).implementsTypes.length === 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\texcerpts = (item as ApiClass).implementsTypes.map((typeExcerpt) => typeExcerpt.excerpt);\n\t\t} else {\n\t\t\tif (!(item as ApiClass).extendsType) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\texcerpts = [(item as ApiClass).extendsType!.excerpt];\n\t\t}\n\t} else {\n\t\tif ((item as ApiInterface).extendsTypes.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\texcerpts = (item as ApiInterface).extendsTypes.map((typeExcerpt) => typeExcerpt.excerpt);\n\t}\n\n\t// return (\n\t// \t<div className=\"flex flex-col gap-4\">\n\t// \t\t{excerpts.map((excerpt, idx) => (\n\t// \t\t\t<div className=\"flex flex-row place-items-center gap-4\" key={`${type}-${idx}`}>\n\t// \t\t\t\t<h3 className=\"text-xl font-bold\">{type}</h3>\n\t// \t\t\t\t<span className=\"break-all font-mono space-y-2\">\n\t// \t\t\t\t\t<ExcerptText excerpt={excerpt} apiPackage={item.getAssociatedPackage()!} />\n\t// \t\t\t\t</span>\n\t// \t\t\t</div>\n\t// \t\t))}\n\t// \t</div>\n\t// );\n\n\treturn excerpts.map((excerpt) => ({\n\t\ttype,\n\t\texcerpts: itemExcerptText(\n\t\t\texcerpt,\n\t\t\titem.getAssociatedPackage()!,\n\t\t\titem.getHierarchy().find(ApiTypeParameterListMixin.isBaseClassOf),\n\t\t),\n\t}));\n}\n\nfunction itemClass(item: ApiClass) {\n\tconst constructor = item.members.find((member) => member.kind === ApiItemKind.Constructor) as\n\t\t| ApiConstructor\n\t\t| undefined;\n\n\treturn {\n\t\t...itemInfo(item),\n\t\textends: itemHierarchyText({ item, type: 'Extends' }),\n\t\timplements: itemHierarchyText({ item, type: 'Implements' }),\n\t\ttypeParameters: itemTypeParameters(item),\n\t\tconstruct: constructor ? itemConstructor(constructor) : null,\n\t\tmembers: itemMembers(item),\n\t};\n}\n\nfunction itemFunction(item: ApiFunction) {\n\tconst functionItem = (item: ApiFunction) => ({\n\t\t...itemInfo(item),\n\t\toverloadIndex: item.overloadIndex,\n\t\ttypeParameters: itemTypeParameters(item),\n\t\tparameters: itemParameters(item),\n\t});\n\n\tconst hasOverloads = item.getMergedSiblings().length > 1;\n\tconst overloads = item.getMergedSiblings().map((sibling) => functionItem(sibling as ApiFunction));\n\n\treturn {\n\t\t...functionItem(item),\n\t\toverloads: hasOverloads ? overloads : [],\n\t};\n}\n\nfunction itemInterface(item: ApiInterface) {\n\treturn {\n\t\t...itemInfo(item),\n\t\textends: itemHierarchyText({ item, type: 'Extends' }),\n\t\ttypeParameters: itemTypeParameters(item),\n\t\tmembers: itemMembers(item),\n\t};\n}\n\nfunction itemUnion(item: Excerpt) {\n\tconst union: ExcerptToken[][] = [];\n\tlet currentUnionMember: ExcerptToken[] = [];\n\tlet depth = 0;\n\tfor (const token of item.spannedTokens) {\n\t\tif (token.text.includes('?')) {\n\t\t\treturn [item.spannedTokens];\n\t\t}\n\n\t\tdepth += token.text.split('<').length - token.text.split('>').length;\n\n\t\tif (token.text.trim() === '|' && depth === 0) {\n\t\t\tif (currentUnionMember.length) {\n\t\t\t\tunion.push(currentUnionMember);\n\t\t\t\tcurrentUnionMember = [];\n\t\t\t}\n\t\t} else if (depth === 0 && token.kind === ExcerptTokenKind.Content && token.text.includes('|')) {\n\t\t\tfor (const [idx, tokenpart] of token.text.split('|').entries()) {\n\t\t\t\tif (currentUnionMember.length && depth === 0 && idx === 0) {\n\t\t\t\t\tcurrentUnionMember.push(new ExcerptToken(ExcerptTokenKind.Content, tokenpart));\n\t\t\t\t\tunion.push(currentUnionMember);\n\t\t\t\t\tcurrentUnionMember = [];\n\t\t\t\t} else if (currentUnionMember.length && depth === 0) {\n\t\t\t\t\tunion.push(currentUnionMember);\n\t\t\t\t\tcurrentUnionMember = [new ExcerptToken(ExcerptTokenKind.Content, tokenpart)];\n\t\t\t\t} else if (tokenpart.length) {\n\t\t\t\t\tcurrentUnionMember.push(new ExcerptToken(ExcerptTokenKind.Content, tokenpart));\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tcurrentUnionMember.push(token);\n\t\t}\n\t}\n\n\tif (currentUnionMember.length) {\n\t\tunion.push(currentUnionMember);\n\t}\n\n\treturn union;\n}\n\nfunction itemTypeAlias(item: ApiTypeAlias) {\n\treturn {\n\t\t...itemInfo(item),\n\t\ttypeParameters: itemTypeParameters(item),\n\t\tunionMembers: itemUnion(item.typeExcerpt).map((member) =>\n\t\t\titemExcerptText(\n\t\t\t\tnew Excerpt(member, { startIndex: 0, endIndex: member.length }),\n\t\t\t\titem.getAssociatedPackage()!,\n\t\t\t\titem.getHierarchy().find(ApiTypeParameterListMixin.isBaseClassOf),\n\t\t\t),\n\t\t),\n\t};\n}\n\nfunction itemVariable(item: ApiVariable) {\n\treturn {\n\t\t...itemInfo(item),\n\t\tunionMembers: itemUnion(item.variableTypeExcerpt).map((member) =>\n\t\t\titemExcerptText(\n\t\t\t\tnew Excerpt(member, { startIndex: 0, endIndex: member.length }),\n\t\t\t\titem.getAssociatedPackage()!,\n\t\t\t\titem.getHierarchy().find(ApiTypeParameterListMixin.isBaseClassOf),\n\t\t\t),\n\t\t),\n\t};\n}\n\nfunction itemEnumMember(item: ApiEnumMember) {\n\treturn {\n\t\t...itemInfo(item),\n\t\tname: item.name,\n\t\tinitializerExcerpt: item.initializerExcerpt\n\t\t\t? itemExcerptText(item.initializerExcerpt, item.getAssociatedPackage()!)\n\t\t\t: null,\n\t};\n}\n\nfunction itemEnum(item: ApiEnum) {\n\treturn {\n\t\t...itemInfo(item),\n\t\tmembers: item.members.map((member) => itemEnumMember(member)),\n\t};\n}\n\nfunction memberKind(member: ApiItem | null) {\n\t// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check\n\tswitch (member?.kind) {\n\t\tcase 'Class': {\n\t\t\tconst classMember = member as ApiClass;\n\t\t\treturn itemClass(classMember);\n\t\t}\n\n\t\tcase 'Function': {\n\t\t\tconst functionMember = member as ApiFunction;\n\t\t\treturn itemFunction(functionMember);\n\t\t}\n\n\t\tcase 'Interface': {\n\t\t\tconst interfaceMember = member as ApiInterface;\n\t\t\treturn itemInterface(interfaceMember);\n\t\t}\n\n\t\tcase 'TypeAlias': {\n\t\t\tconst typeAliasMember = member as ApiTypeAlias;\n\t\t\treturn itemTypeAlias(typeAliasMember);\n\t\t}\n\n\t\tcase 'Variable': {\n\t\t\tconst variableMember = member as ApiVariable;\n\t\t\treturn itemVariable(variableMember);\n\t\t}\n\n\t\tcase 'Enum': {\n\t\t\tconst enumMember = member as ApiEnum;\n\t\t\treturn itemEnum(enumMember);\n\t\t}\n\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nasync function writeSplitDocsToFileSystem({\n\tentry,\n\tmember,\n\tpackageName,\n\ttag = 'main',\n\toverrideName,\n}: {\n\tentry?: string;\n\tmember: Record<string, any>;\n\toverrideName?: string;\n\tpackageName: string;\n\ttag: string;\n}) {\n\tconst dir = 'split';\n\n\ttry {\n\t\t(await stat(join(process.cwd(), 'docs', packageName, dir))).isDirectory();\n\t} catch {\n\t\tawait mkdir(join(process.cwd(), 'docs', packageName, dir), { recursive: true });\n\t}\n\n\tawait writeFile(\n\t\tjoin(\n\t\t\tprocess.cwd(),\n\t\t\t'docs',\n\t\t\tpackageName,\n\t\t\tdir,\n\t\t\t`${tag}.${entry ? `${entry.replaceAll('/', '.')}.` : ''}${overrideName ?? `${member.displayName.toLowerCase()}.${member.kind.toLowerCase()}`}.api.json`,\n\t\t),\n\t\tJSON.stringify(member),\n\t);\n}\n\nexport async function generateSplitDocumentation({\n\tfetchPackageVersions = fetchVersions,\n\tfetchPackageVersionDocs = fetchVersionDocs,\n} = {}) {\n\tfor (const pkgName of PACKAGES) {\n\t\tconst versions = await fetchPackageVersions(pkgName);\n\n\t\tfor (const version of versions) {\n\t\t\tconst data = await fetchPackageVersionDocs(pkgName, version);\n\t\t\tconst model = new ApiModel();\n\t\t\tmodel.addMember(ApiPackage.loadFromJson(data));\n\t\t\tconst pkg = model.tryGetPackageByName(pkgName);\n\t\t\tconst entries = pkg?.entryPoints;\n\n\t\t\tif (!entries) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tawait writeSplitDocsToFileSystem({\n\t\t\t\tmember: pkg.dependencies ?? [],\n\t\t\t\tpackageName: pkgName,\n\t\t\t\ttag: version,\n\t\t\t\toverrideName: 'dependencies',\n\t\t\t});\n\n\t\t\tawait writeSplitDocsToFileSystem({\n\t\t\t\tmember: entries.map((entry) => ({\n\t\t\t\t\tentryPoint: entry.importPath,\n\t\t\t\t})),\n\t\t\t\tpackageName: pkgName,\n\t\t\t\ttag: version,\n\t\t\t\toverrideName: 'entrypoints',\n\t\t\t});\n\n\t\t\tfor (const entry of entries) {\n\t\t\t\tconst members = entry.members\n\t\t\t\t\t.filter((item) => {\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check\n\t\t\t\t\t\tswitch (item.kind) {\n\t\t\t\t\t\t\tcase ApiItemKind.Function:\n\t\t\t\t\t\t\t\treturn (item as ApiFunction).overloadIndex === 1;\n\t\t\t\t\t\t\tcase ApiItemKind.Interface:\n\t\t\t\t\t\t\t\treturn !entry.members.some(\n\t\t\t\t\t\t\t\t\t(innerItem) => innerItem.kind === ApiItemKind.Class && innerItem.displayName === item.displayName,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.map((item) => ({\n\t\t\t\t\t\tkind: item.kind,\n\t\t\t\t\t\tname: item.displayName,\n\t\t\t\t\t\thref: resolveItemURI(item),\n\t\t\t\t\t\tentry: entry.importPath,\n\t\t\t\t\t}));\n\n\t\t\t\tawait writeSplitDocsToFileSystem({\n\t\t\t\t\tmember: members,\n\t\t\t\t\tpackageName: pkgName,\n\t\t\t\t\ttag: version,\n\t\t\t\t\toverrideName: 'sitemap',\n\t\t\t\t\tentry: entry.importPath,\n\t\t\t\t});\n\n\t\t\t\tfor (const member of members) {\n\t\t\t\t\tconst item = `${member.name}:${member.kind}`;\n\t\t\t\t\tconst [memberName, overloadIndex] = decodeURIComponent(item).split(':');\n\n\t\t\t\t\t// eslint-disable-next-line prefer-const\n\t\t\t\t\tlet { containerKey, displayName: name } = findMember(entry, memberName) ?? {};\n\t\t\t\t\tif (name && overloadIndex && !Number.isNaN(Number.parseInt(overloadIndex, 10))) {\n\t\t\t\t\t\tcontainerKey = ApiFunction.getContainerKey(name, Number.parseInt(overloadIndex, 10));\n\t\t\t\t\t}\n\n\t\t\t\t\tconst foundMember = memberName && containerKey ? (findMemberByKey(entry, containerKey) ?? null) : null;\n\n\t\t\t\t\tconst returnValue = memberKind(foundMember);\n\n\t\t\t\t\tif (!returnValue) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tawait writeSplitDocsToFileSystem({\n\t\t\t\t\t\tmember: returnValue,\n\t\t\t\t\t\tpackageName: pkgName,\n\t\t\t\t\t\ttag: version,\n\t\t\t\t\t\tentry: entry.importPath,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/scripts/src/index.ts",
    "content": "export * from './generateIndex.js';\nexport * from './generateSplitDocumentation.js';\n"
  },
  {
    "path": "packages/scripts/src/populateDevDatabaseBranch.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport process from 'node:process';\nimport { create } from '@actions/glob';\nimport { put } from '@vercel/blob';\nimport { createPool } from '@vercel/postgres';\n\nconst pool = createPool({\n\tconnectionString: process.env.DATABASE_URL,\n});\n\nprocess.chdir(`${process.cwd()}/../../`);\nconst globber = await create(`packages/*/docs/*.api.json`);\nfor await (const file of globber.globGenerator()) {\n\tconst parsed = /(?<semver>\\d+.\\d+.\\d+)-?.*/.exec(file);\n\tconst data = await readFile(file, 'utf8');\n\n\tif (parsed?.groups) {\n\t\tconsole.log(parsed.groups.semver, file);\n\t\ttry {\n\t\t\tconst { name } = JSON.parse(data);\n\t\t\tconst { url } = await put(`${name.replace('@discordjs/', '')}/${parsed.groups.semver}.json`, data, {\n\t\t\t\taccess: 'public',\n\t\t\t\tallowOverwrite: true,\n\t\t\t});\n\t\t\tawait pool.sql`insert into documentation (name, version, url) values (${name.replace('@discordjs/', '')}, ${\n\t\t\t\tparsed.groups.semver\n\t\t\t}, ${url}) on conflict (name, version) do update set url = EXCLUDED.url`;\n\t\t} catch (error) {\n\t\t\tconsole.error(error);\n\t\t}\n\t} else {\n\t\tconsole.log('main', file);\n\t\ttry {\n\t\t\tconst { name } = JSON.parse(data);\n\t\t\tconst { url } = await put(`${name.replace('@discordjs/', '')}/main.json`, data, {\n\t\t\t\taccess: 'public',\n\t\t\t\tallowOverwrite: true,\n\t\t\t});\n\t\t\tawait pool.sql`insert into documentation (name, version, url) values (${name.replace(\n\t\t\t\t'@discordjs/',\n\t\t\t\t'',\n\t\t\t)}, ${'main'}, ${url}) on conflict (name, version) do update set url = EXCLUDED.url`;\n\t\t} catch (error) {\n\t\t\tconsole.error(error);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/scripts/src/shared.ts",
    "content": "import { request } from 'undici';\n\nexport const PACKAGES = [\n\t'discord.js',\n\t'brokers',\n\t'builders',\n\t'collection',\n\t'core',\n\t'formatters',\n\t'next',\n\t'proxy',\n\t'rest',\n\t'structures',\n\t'util',\n\t'voice',\n\t'ws',\n\t'discord-api-types',\n];\n\nexport async function fetchVersions(pkg: string) {\n\tconst response = await request(`https://discord.js.org/api/docs/versions?packageName=${pkg}`);\n\treturn response.body.json() as Promise<string[]>;\n}\n\nexport async function fetchVersionDocs(pkg: string, version: string) {\n\tconst response = await request(`https://r2-docs.discordjs.dev/${pkg}/${version}.json`);\n\treturn response.body.json();\n}\n"
  },
  {
    "path": "packages/scripts/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\",\n\t\t\"turbo\"\n\t],\n\t\"exclude\": [\"node_modules\", \"turbo/generators/templates\"]\n}\n"
  },
  {
    "path": "packages/scripts/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\", \"turbo/generators/templates\"]\n}\n"
  },
  {
    "path": "packages/scripts/tsup.config.ts",
    "content": "import { createTsupConfig } from '../../tsup.config.js';\n\nexport default [\n\tcreateTsupConfig({\n\t\tentry: ['src/index.ts', 'bin/generateSplitDocumentation.ts'],\n\t\tminify: 'terser',\n\t}),\n\tcreateTsupConfig({\n\t\tentry: ['src/populateDevDatabaseBranch.ts', 'bin/sortLabels.ts'],\n\t\tformat: 'esm',\n\t\tminify: 'terser',\n\t}),\n];\n"
  },
  {
    "path": "packages/scripts/turbo/generators/config.ts",
    "content": "import { writeFile } from 'node:fs/promises';\nimport type { PlopTypes } from '@turbo/gen';\nimport { parse as parseYAML, stringify as stringifyYAML } from 'yaml';\n\ninterface LabelerData {\n\tcolor: string;\n\tname: string;\n}\n\nfunction sortYAMLObject(yaml: Record<string, string[]>) {\n\tconst sortedYAML: typeof yaml = {};\n\tfor (const key of Object.keys(yaml).sort((a, b) => a.localeCompare(b))) sortedYAML[key] = yaml[key]!;\n\treturn sortedYAML;\n}\n\nexport default function generator(plop: PlopTypes.NodePlopAPI): void {\n\tplop.setGenerator('create-package', {\n\t\tdescription: '',\n\t\tprompts: [\n\t\t\t{\n\t\t\t\ttype: 'input',\n\t\t\t\tname: 'name',\n\t\t\t\tmessage: 'The name of the new package',\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'input',\n\t\t\t\tname: 'description',\n\t\t\t\tmessage: 'The description of the new package.',\n\t\t\t},\n\t\t],\n\t\tactions: [\n\t\t\t{\n\t\t\t\ttype: 'add',\n\t\t\t\tpath: `${plop.getDestBasePath()}/../{{name}}/src/index.ts`,\n\t\t\t\ttemplate: \"console.log('Hello, from @discordjs/{{name}}');\",\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'add',\n\t\t\t\tpath: `${plop.getDestBasePath()}/../{{name}}/__tests__/.gitkeep`,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'addMany',\n\t\t\t\tdestination: `${plop.getDestBasePath()}/../{{name}}`,\n\t\t\t\t// plop doesn't like our cliff.toml file since it tries to parse it. we add it manually later\n\t\t\t\ttemplateFiles: ['templates/**', '!templates/default/cliff.toml'],\n\t\t\t\tglobOptions: { dot: true },\n\t\t\t\tbase: 'templates/default/',\n\t\t\t\tstripExtensions: ['hbs'],\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'modify',\n\t\t\t\tpath: `${plop.getDestBasePath()}/turbo/generators/templates/default/cliff.toml`,\n\t\t\t\tasync transform(content, answers) {\n\t\t\t\t\tconst cliffTOML = content.replace('{{name}}', answers.name);\n\t\t\t\t\tawait writeFile(`${plop.getDestBasePath()}/../${answers.name}/cliff.toml`, cliffTOML);\n\t\t\t\t\treturn content;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'modify',\n\t\t\t\tpath: `${plop.getDestBasePath()}/../../.github/labels.yml`,\n\t\t\t\ttransform(content, answers) {\n\t\t\t\t\tconst labelsYAML = parseYAML(content) as LabelerData[];\n\t\t\t\t\tlabelsYAML.push({ name: `packages:${answers.name}`, color: 'fbca04' });\n\t\t\t\t\tlabelsYAML.sort((a, b) => a.name.localeCompare(b.name));\n\n\t\t\t\t\treturn stringifyYAML(labelsYAML);\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'modify',\n\t\t\t\tpath: `${plop.getDestBasePath()}/../../.github/labeler.yml`,\n\t\t\t\ttransform(content, answers) {\n\t\t\t\t\tconst labelerYAML = parseYAML(content) as Record<string, Record<string, Record<string, string[]>[]>[]>;\n\n\t\t\t\t\tlabelerYAML[`packages:${answers.name}`] = [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t'changed-files': [\n\t\t\t\t\t\t\t\t{ 'any-glob-to-any-file': [`packages/${answers.name}/*`, `packages/${answers.name}/**/*`] },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\t\t\t\t\t];\n\n\t\t\t\t\treturn stringifyYAML(labelerYAML, { sortMapEntries: true });\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'modify',\n\t\t\t\tpath: `${plop.getDestBasePath()}/../../.github/issue-labeler.yml`,\n\t\t\t\ttransform(content, answers) {\n\t\t\t\t\tconst issueLabelerYAML = parseYAML(content) as Record<string, string[]>;\n\t\t\t\t\tissueLabelerYAML[`packages:${answers.name}`] = [\n\t\t\t\t\t\t`### Which (application|package|application or package) is this (bug report|feature request) for\\\\?\\\\n\\\\n${answers.name}\\\\n`,\n\t\t\t\t\t];\n\n\t\t\t\t\treturn stringifyYAML(sortYAMLObject(issueLabelerYAML));\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t});\n}\n"
  },
  {
    "path": "packages/scripts/turbo/generators/templates/default/.cliff-jumperrc.json.hbs",
    "content": "{\n\t\"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n\t\"name\": \"{{name}}\",\n\t\"org\": \"discordjs\",\n\t\"packagePath\": \"packages/{{name}}\",\n\t\"identifierBase\": false\n}\n"
  },
  {
    "path": "packages/scripts/turbo/generators/templates/default/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\ndist-docs\n\n# Docs\ndocs/**/*\n!docs/README.md\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/scripts/turbo/generators/templates/default/.lintstagedrc.js.hbs",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/scripts/turbo/generators/templates/default/.prettierignore",
    "content": ".turbo\ncoverage\ndist\ndist-docs\ndocs/docs.api.json\nCHANGELOG.md\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/scripts/turbo/generators/templates/default/.prettierrc.js.hbs",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/scripts/turbo/generators/templates/default/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n    Copyright 2023 Noel Buechler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/scripts/turbo/generators/templates/default/api-extractor.json.hbs",
    "content": "{\n\t\"extends\": \"../../api-extractor.json\",\n\t\"docModel\": {\n\t\t\"projectFolderUrl\": \"https://github.com/discordjs/discord.js/tree/main/packages/{{name}}\"\n\t}\n}\n"
  },
  {
    "path": "packages/scripts/turbo/generators/templates/default/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t\t{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length %}\\\n\t\\n### New Contributors\\n\n\t{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\\\n\t\t* @{{ contributor.username }} made their first contribution in #{{ contributor.pr_number }}\n\t{% endfor %}\\\n{% endif %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"@discordjs/{{name}}@[0-9]*\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/scripts/turbo/generators/templates/default/package.json.hbs",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/{{name}}\",\n\t\"version\": \"0.1.0\",\n\t\"description\": \"{{description}}\",\n\t\"scripts\": {\n\t\t\"build\": \"tsc --noEmit && tsup\",\n\t\t\"build:docs\": \"tsc -p tsconfig.docs.json\",\n\t\t\"test\": \"vitest run --config ../../vitest.config.ts\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src\",\n\t\t\"fmt\": \"pnpm run format\",\n\t\t\"docs\": \"pnpm run build:docs && api-extractor run --local\",\n\t\t\"prepack\": \"pnpm run build && pnpm run lint\",\n\t\t\"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/{{name}}/*'\",\n\t\t\"release\": \"cliff-jumper\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"main\": \"./dist/index.js\",\n\t\"module\": \"./dist/index.mjs\",\n\t\"types\": \"./dist/index.d.ts\",\n\t\"directories\": {\n\t\t\"lib\": \"src\",\n\t\t\"test\": \"__tests__\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/{{name}}\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {},\n\t\"devDependencies\": {\n\t\t\"@discordjs/api-extractor\": \"workspace:^\",\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@types/node\": \"^24.10.13\",\n\t\t\"@vitest/coverage-v8\": \"^4.0.18\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"esbuild-plugin-version-injector\": \"^1.2.1\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vitest\": \"^4.0.18\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/scripts/turbo/generators/templates/default/tsconfig.docs.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.docs.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist-docs\"\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/scripts/turbo/generators/templates/default/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/scripts/turbo/generators/templates/default/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/scripts/turbo/generators/templates/default/tsconfig.test.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"noEmit\": true\n\t},\n\t\"include\": [\"__tests__/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/scripts/turbo/generators/templates/default/tsup.config.ts",
    "content": "import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector';\nimport { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tesbuildPlugins: [esbuildPluginVersionInjector()],\n});\n"
  },
  {
    "path": "packages/structures/.cliff-jumperrc.json",
    "content": "{\n\t\"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n\t\"name\": \"structures\",\n\t\"org\": \"discordjs\",\n\t\"packagePath\": \"packages/structures\",\n\t\"identifierBase\": false\n}\n"
  },
  {
    "path": "packages/structures/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\ndist-docs\n\n# Docs\ndocs/**/*\n!docs/README.md\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/structures/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/structures/.prettierignore",
    "content": ".turbo\ncoverage\ndist\ndist-docs\ndocs/docs.api.json\nCHANGELOG.md\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/structures/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/structures/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n    Copyright 2023 Noel Buechler\n    Copyright 2023 Chai Kohen\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/structures/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/structures\"><img src=\"https://img.shields.io/npm/v/@discordjs/structures.svg?maxAge=3600\" alt=\"npm version\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/structures\"><img src=\"https://img.shields.io/npm/dt/@discordjs/structures.svg?maxAge=3600\" alt=\"npm downloads\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Tests status\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/commits/main/packages/structures\"><img alt=\"Last commit.\" src=\"https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fstructures\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t\t<a href=\"https://codecov.io/gh/discordjs/discord.js\"><img src=\"https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=structures\" alt=\"Code coverage\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## About\n\n`@discordjs/structures` is a low level wrapper around Discord JSON Objects, meant to be a foundation to build upon in a higher level library.\n\n## Installation\n\n**Node.js 22.12.0 or newer is required.**\n\n```sh\nnpm install @discordjs/structures\nyarn add @discordjs/structures\npnpm add @discordjs/structures\nbun add @discordjs/structures\n```\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Documentation][documentation]\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [npm][npm]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the\n[documentation][documentation].  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs/packages/structures/stable\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/structures\n[npm]: https://www.npmjs.com/package/@discordjs/structures\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/structures/__tests__/Mixin.test.ts",
    "content": "import { describe, test, expect } from 'vitest';\nimport { kData, kPatch } from '../src/utils/symbols.js';\nimport type { APIData } from './mixinClasses.js';\nimport { Base, Mixed, MixedWithExtended } from './mixinClasses.js';\n\ndescribe('Mixin function', () => {\n\tconst data: APIData = {\n\t\tid: '1',\n\t\tproperty1: 23,\n\t};\n\n\ttest('Mixed class has all getters', () => {\n\t\tconst instance = new Mixed(data);\n\t\texpect(instance.id).toBe(data.id);\n\t\texpect(instance.property1).toBe(data.property1);\n\t\texpect(instance.property2).toBe(data.property2);\n\t});\n\n\ttest('Mixed class has all methods', () => {\n\t\tconst instance = new Mixed(data);\n\t\texpect(instance.getId()).toBe(data.id);\n\t\texpect(instance.getProperty1()).toBe(data.property1);\n\t\texpect(instance.getProperty2()).toBe(data.property2);\n\t\texpect(instance.getProperties()).toEqual({\n\t\t\tproperty1: data.property1,\n\t\t\tproperty2: data.property2,\n\t\t});\n\t});\n\n\ttest('Mixed with extended class has all getters', () => {\n\t\tconst instance = new MixedWithExtended(data);\n\t\texpect(instance.id).toBe(data.id);\n\t\texpect(instance.property1).toBe(data.property1);\n\t\texpect(instance.property2).toBe(data.property2);\n\t\texpect(instance.isExtended).toBe(true);\n\t});\n\n\ttest('Mixed with extended class has all methods', () => {\n\t\tconst instance = new MixedWithExtended(data);\n\t\texpect(instance.getId()).toBe(data.id);\n\t\texpect(instance.getProperty1()).toBe(data.property1);\n\t\texpect(instance.getProperty2()).toBe(data.property2);\n\t\texpect(instance.getProperties()).toEqual({\n\t\t\tproperty1: data.property1,\n\t\t\tproperty2: data.property2,\n\t\t});\n\t});\n\n\ttest('Mixed class calls construct methods on construct', () => {\n\t\tconst instance1 = new Mixed(data);\n\t\tconst instance2 = new MixedWithExtended(data);\n\t\texpect(instance1.constructCalled).toBe(true);\n\t\texpect(instance2.constructCalled).toBe(true);\n\t});\n\n\ttest('Mixed class respects mixin data optimizations', () => {\n\t\texpect(typeof Object.getOwnPropertyDescriptor(Mixed.DataTemplate, 'mixinOptimize')?.set).toBe('function');\n\t\tconst missingOptimizedInstance = new Mixed(data);\n\t\tconst alreadyOptimizedInstance = new Mixed({ ...data, mixinOptimize: 'true', baseOptimize: 'true' });\n\t\tconst baseOptimizedInstance = new Base({ ...data, mixinOptimize: 'true', baseOptimize: 'true' });\n\n\t\texpect(missingOptimizedInstance.baseOptimize).toBe(null);\n\t\texpect(missingOptimizedInstance.mixinOptimize).toBe(null);\n\t\t// Setters pass this\n\t\texpect('baseOptimize' in missingOptimizedInstance[kData]).toBe(true);\n\t\texpect('mixinOptimize' in missingOptimizedInstance[kData]).toBe(true);\n\t\texpect(missingOptimizedInstance[kData].baseOptimize).toBeUndefined();\n\t\texpect(missingOptimizedInstance[kData].mixinOptimize).toBeUndefined();\n\n\t\texpect(alreadyOptimizedInstance.baseOptimize).toBe(true);\n\t\texpect(alreadyOptimizedInstance.mixinOptimize).toBe(true);\n\t\t// Setters pass this\n\t\texpect('baseOptimize' in alreadyOptimizedInstance[kData]).toBe(true);\n\t\texpect('mixinOptimize' in alreadyOptimizedInstance[kData]).toBe(true);\n\t\texpect(alreadyOptimizedInstance[kData].baseOptimize).toBeUndefined();\n\t\texpect(alreadyOptimizedInstance[kData].mixinOptimize).toBeUndefined();\n\t\texpect(alreadyOptimizedInstance.toJSON()).toEqual({ ...data, mixinOptimize: 'true', baseOptimize: 'true' });\n\n\t\talreadyOptimizedInstance[kPatch]({ mixinOptimize: '', baseOptimize: '' });\n\n\t\texpect(alreadyOptimizedInstance.baseOptimize).toBe(false);\n\t\texpect(alreadyOptimizedInstance.mixinOptimize).toBe(false);\n\t\t// Setters pass this\n\t\texpect('baseOptimize' in alreadyOptimizedInstance[kData]).toBe(true);\n\t\texpect('mixinOptimize' in alreadyOptimizedInstance[kData]).toBe(true);\n\t\texpect(alreadyOptimizedInstance[kData].baseOptimize).toBeUndefined();\n\t\texpect(alreadyOptimizedInstance[kData].mixinOptimize).toBeUndefined();\n\n\t\t// Ensure mixin optimizations don't happen on base (ie overwritten DataTemplate)\n\t\texpect(baseOptimizedInstance.baseOptimize).toBe(true);\n\t\texpect('mixinOptimize' in baseOptimizedInstance).toBe(false);\n\t\t// Setters pass this\n\t\texpect('baseOptimize' in baseOptimizedInstance[kData]).toBe(true);\n\t\texpect('mixinOptimize' in baseOptimizedInstance[kData]).toBe(true);\n\t\texpect(baseOptimizedInstance[kData].baseOptimize).toBeUndefined();\n\t\texpect(baseOptimizedInstance[kData].mixinOptimize).toBe('true');\n\t});\n});\n"
  },
  {
    "path": "packages/structures/__tests__/Structure.test.ts",
    "content": "import { describe, test, expect, beforeEach } from 'vitest';\nimport { DataTemplatePropertyName, OptimizeDataPropertyName, Structure } from '../src/Structure.js';\nimport { kData, kPatch } from '../src/utils/symbols.js';\n\ndescribe('Base Structure', () => {\n\tconst data = { test: true, patched: false, removed: true };\n\tlet struct: Structure<typeof data>;\n\tbeforeEach(() => {\n\t\t// @ts-expect-error Structure constructor is protected\n\t\tstruct = new Structure(data);\n\t\t// @ts-expect-error Structure.DataTemplate is protected\n\t\tStructure.DataTemplate = {};\n\t});\n\n\ttest('Data reference is not identical (clone via Object.assign)', () => {\n\t\texpect(struct[kData]).not.toBe(data);\n\t\texpect(struct[kData]).toEqual(data);\n\t});\n\n\ttest('Remove properties via template (constructor)', () => {\n\t\t// @ts-expect-error Structure.DataTemplate is protected\n\t\tStructure.DataTemplate = { set removed(_) {} };\n\t\t// @ts-expect-error Structure constructor is protected\n\t\tconst templatedStruct: Structure<typeof data> = new Structure(data);\n\t\texpect(templatedStruct[kData].removed).toBe(undefined);\n\t\t// Setters still exist and pass \"in\" test unfortunately\n\t\texpect('removed' in templatedStruct[kData]).toBe(true);\n\t\texpect(templatedStruct[kData]).toEqual({ test: true, patched: false });\n\t});\n\n\ttest('patch clones data and updates in place', () => {\n\t\tconst dataBefore = struct[kData];\n\t\tconst patched = struct[kPatch]({ patched: true });\n\t\texpect(patched[kData].patched).toBe(true);\n\t\t// Patch in place\n\t\texpect(struct[kData]).toBe(patched[kData]);\n\t\t// Clones\n\t\texpect(dataBefore.patched).toBe(false);\n\t\texpect(dataBefore).not.toBe(patched[kData]);\n\t});\n\n\ttest('Remove properties via template ([kPatch])', () => {\n\t\t// @ts-expect-error Structure.DataTemplate is protected\n\t\tStructure.DataTemplate = { set removed(_) {} };\n\t\t// @ts-expect-error Structure constructor is protected\n\t\tconst templatedStruct: Structure<typeof data> = new Structure(data);\n\t\ttemplatedStruct[kPatch]({ removed: false });\n\t\texpect(templatedStruct[kData].removed).toBe(undefined);\n\t\t// Setters still exist and pass \"in\" test unfortunately\n\t\texpect('removed' in templatedStruct[kData]).toBe(true);\n\t\texpect(templatedStruct[kData]).toEqual({ test: true, patched: false });\n\t});\n\n\ttest('toJSON clones but retains data equality', () => {\n\t\tconst json = struct.toJSON();\n\t\texpect(json).not.toBe(data);\n\t\texpect(json).not.toBe(struct[kData]);\n\t\texpect(struct[kData]).toEqual(json);\n\t});\n\n\ttest(\"XPropertyName variable matches the actual property's names\", () => {\n\t\texpect(Structure[DataTemplatePropertyName]).toStrictEqual({});\n\t\texpect(struct[OptimizeDataPropertyName]).toBeTypeOf('function');\n\t});\n});\n"
  },
  {
    "path": "packages/structures/__tests__/channels.test.ts",
    "content": "import type {\n\tAPIAnnouncementThreadChannel,\n\tAPIDMChannel,\n\tAPIGroupDMChannel,\n\tAPIGuildCategoryChannel,\n\tAPIGuildForumChannel,\n\tAPIGuildMediaChannel,\n\tAPIGuildStageVoiceChannel,\n\tAPIGuildVoiceChannel,\n\tAPINewsChannel,\n\tAPIPrivateThreadChannel,\n\tAPIPublicThreadChannel,\n\tAPITextChannel,\n} from 'discord-api-types/v10';\nimport {\n\tForumLayoutType,\n\tSortOrderType,\n\tChannelType,\n\tOverwriteType,\n\tThreadAutoArchiveDuration,\n\tVideoQualityMode,\n\tChannelFlags,\n} from 'discord-api-types/v10';\nimport { describe, expect, test } from 'vitest';\nimport {\n\tAnnouncementChannel,\n\tAnnouncementThreadChannel,\n\tCategoryChannel,\n\tDMChannel,\n\tForumChannel,\n\tForumTag,\n\tGroupDMChannel,\n\tMediaChannel,\n\tPermissionOverwrite,\n\tPrivateThreadChannel,\n\tPublicThreadChannel,\n\tStageChannel,\n\tTextChannel,\n\tThreadMetadata,\n\tVoiceChannel,\n} from '../src/channels/index.js';\nimport { kData } from '../src/utils/symbols.js';\n\ndescribe('text channel', () => {\n\tconst data: APITextChannel = {\n\t\tid: '1',\n\t\tname: 'test',\n\t\ttype: ChannelType.GuildText,\n\t\tposition: 0,\n\t\tguild_id: '2',\n\t\tlast_message_id: '3',\n\t\tlast_pin_timestamp: '2020-10-10T13:50:17.209Z',\n\t\tnsfw: true,\n\t\tparent_id: '4',\n\t\tpermission_overwrites: [\n\t\t\t{\n\t\t\t\tallow: '123',\n\t\t\t\tdeny: '456',\n\t\t\t\ttype: OverwriteType.Member,\n\t\t\t\tid: '5',\n\t\t\t},\n\t\t],\n\t\trate_limit_per_user: 9,\n\t\ttopic: 'hello',\n\t\tdefault_auto_archive_duration: ThreadAutoArchiveDuration.OneHour,\n\t\tdefault_thread_rate_limit_per_user: 30,\n\t};\n\n\ttest('TextChannel has all properties', () => {\n\t\tconst instance = new TextChannel(data);\n\t\texpect(instance.id).toBe(data.id);\n\t\texpect(instance.name).toBe(data.name);\n\t\texpect(instance.position).toBe(data.position);\n\t\texpect(instance.defaultAutoArchiveDuration).toBe(data.default_auto_archive_duration);\n\t\texpect(instance.defaultThreadRateLimitPerUser).toBe(data.default_thread_rate_limit_per_user);\n\t\texpect(instance.flags?.toJSON()).toBe(data.flags);\n\t\texpect(instance.guildId).toBe(data.guild_id);\n\t\texpect(instance.lastMessageId).toBe(data.last_message_id);\n\t\texpect(instance.lastPinTimestamp).toBe(Date.parse(data.last_pin_timestamp!));\n\t\texpect(instance.lastPinAt?.toISOString()).toBe(data.last_pin_timestamp);\n\t\texpect(instance.nsfw).toBe(data.nsfw);\n\t\texpect(instance.parentId).toBe(data.parent_id);\n\t\texpect(instance[kData].permission_overwrites).toEqual(data.permission_overwrites);\n\t\texpect(instance.rateLimitPerUser).toBe(data.rate_limit_per_user);\n\t\texpect(instance.topic).toBe(data.topic);\n\t\texpect(instance.type).toBe(ChannelType.GuildText);\n\t\texpect(instance.url).toBe('https://discord.com/channels/2/1');\n\t\texpect(instance.toJSON()).toEqual(data);\n\t});\n\n\ttest('type guards', () => {\n\t\tconst instance = new TextChannel(data);\n\t\texpect(instance.isDMBased()).toBe(false);\n\t\texpect(instance.isGuildBased()).toBe(true);\n\t\texpect(instance.isPermissionCapable()).toBe(true);\n\t\texpect(instance.isTextBased()).toBe(true);\n\t\texpect(instance.isThread()).toBe(false);\n\t\texpect(instance.isThreadOnly()).toBe(false);\n\t\texpect(instance.isVoiceBased()).toBe(false);\n\t\texpect(instance.isWebhookCapable()).toBe(true);\n\t});\n\n\ttest('PermissionOverwrite sub-structure', () => {\n\t\tconst instances = data.permission_overwrites?.map((overwrite) => new PermissionOverwrite(overwrite));\n\t\texpect(instances?.map((overwrite) => overwrite.toJSON())).toEqual(data.permission_overwrites);\n\t\texpect(instances?.[0]?.allow?.toJSON()).toBe(data.permission_overwrites?.[0]?.allow);\n\t\texpect(instances?.[0]?.deny?.toJSON()).toBe(data.permission_overwrites?.[0]?.deny);\n\t\texpect(instances?.[0]?.id).toBe(data.permission_overwrites?.[0]?.id);\n\t\texpect(instances?.[0]?.type).toBe(data.permission_overwrites?.[0]?.type);\n\t});\n});\n\ndescribe('announcement channel', () => {\n\tconst data: APINewsChannel = {\n\t\tid: '1',\n\t\tname: 'test',\n\t\ttype: ChannelType.GuildAnnouncement,\n\t\tposition: 0,\n\t\tguild_id: '2',\n\t\tlast_message_id: '3',\n\t\tlast_pin_timestamp: null,\n\t\tnsfw: true,\n\t\tparent_id: '4',\n\t\trate_limit_per_user: 9,\n\t\ttopic: 'hello',\n\t\tdefault_auto_archive_duration: ThreadAutoArchiveDuration.OneHour,\n\t\tdefault_thread_rate_limit_per_user: 30,\n\t};\n\n\ttest('AnnouncementChannel has all properties', () => {\n\t\tconst instance = new AnnouncementChannel(data);\n\t\texpect(instance.id).toBe(data.id);\n\t\texpect(instance.name).toBe(data.name);\n\t\texpect(instance.position).toBe(data.position);\n\t\texpect(instance.defaultAutoArchiveDuration).toBe(data.default_auto_archive_duration);\n\t\texpect(instance.defaultThreadRateLimitPerUser).toBe(data.default_thread_rate_limit_per_user);\n\t\texpect(instance.flags?.toJSON()).toBe(data.flags);\n\t\texpect(instance.guildId).toBe(data.guild_id);\n\t\texpect(instance.lastMessageId).toBe(data.last_message_id);\n\t\texpect(instance.lastPinTimestamp).toBe(null);\n\t\texpect(instance.lastPinAt).toBe(data.last_pin_timestamp);\n\t\texpect(instance.nsfw).toBe(data.nsfw);\n\t\texpect(instance.parentId).toBe(data.parent_id);\n\t\texpect(instance[kData].permission_overwrites).toEqual(data.permission_overwrites);\n\t\texpect(instance.rateLimitPerUser).toBe(data.rate_limit_per_user);\n\t\texpect(instance.topic).toBe(data.topic);\n\t\texpect(instance.type).toBe(ChannelType.GuildAnnouncement);\n\t\texpect(instance.url).toBe('https://discord.com/channels/2/1');\n\t\texpect(instance.toJSON()).toEqual(data);\n\t});\n\n\ttest('type guards', () => {\n\t\tconst instance = new AnnouncementChannel(data);\n\t\texpect(instance.isDMBased()).toBe(false);\n\t\texpect(instance.isGuildBased()).toBe(true);\n\t\texpect(instance.isPermissionCapable()).toBe(true);\n\t\texpect(instance.isTextBased()).toBe(true);\n\t\texpect(instance.isThread()).toBe(false);\n\t\texpect(instance.isThreadOnly()).toBe(false);\n\t\texpect(instance.isVoiceBased()).toBe(false);\n\t\texpect(instance.isWebhookCapable()).toBe(true);\n\t});\n});\n\ndescribe('category channel', () => {\n\tconst data: APIGuildCategoryChannel = {\n\t\tid: '1',\n\t\tname: 'test',\n\t\ttype: ChannelType.GuildCategory,\n\t\tposition: 0,\n\t\tguild_id: '2',\n\t\tpermission_overwrites: [\n\t\t\t{\n\t\t\t\tallow: '123',\n\t\t\t\tdeny: '456',\n\t\t\t\ttype: OverwriteType.Member,\n\t\t\t\tid: '5',\n\t\t\t},\n\t\t],\n\t};\n\n\ttest('CategoryChannel has all properties', () => {\n\t\tconst instance = new CategoryChannel(data);\n\t\texpect(instance.id).toBe(data.id);\n\t\texpect(instance.name).toBe(data.name);\n\t\texpect(instance.position).toBe(data.position);\n\t\texpect(instance.flags?.toJSON()).toBe(data.flags);\n\t\texpect(instance.guildId).toBe(data.guild_id);\n\t\texpect(instance[kData].permission_overwrites).toEqual(data.permission_overwrites);\n\t\texpect(instance.type).toBe(ChannelType.GuildCategory);\n\t\texpect(instance.url).toBe('https://discord.com/channels/2/1');\n\t\texpect(instance.toJSON()).toEqual(data);\n\t});\n\n\ttest('type guards', () => {\n\t\tconst instance = new CategoryChannel(data);\n\t\texpect(instance.isDMBased()).toBe(false);\n\t\texpect(instance.isGuildBased()).toBe(true);\n\t\texpect(instance.isPermissionCapable()).toBe(true);\n\t\texpect(instance.isTextBased()).toBe(false);\n\t\texpect(instance.isThread()).toBe(false);\n\t\texpect(instance.isThreadOnly()).toBe(false);\n\t\texpect(instance.isVoiceBased()).toBe(false);\n\t\texpect(instance.isWebhookCapable()).toBe(false);\n\t});\n});\n\ndescribe('DM channel', () => {\n\tconst dataNoRecipients: APIDMChannel = {\n\t\tid: '1',\n\t\ttype: ChannelType.DM,\n\t\tlast_message_id: '3',\n\t\tlast_pin_timestamp: '2020-10-10T13:50:17.209Z',\n\t\tname: null,\n\t};\n\n\tconst data = {\n\t\t...dataNoRecipients,\n\t\trecipients: [\n\t\t\t{\n\t\t\t\tavatar: '123',\n\t\t\t\tdiscriminator: '0',\n\t\t\t\tglobal_name: 'tester',\n\t\t\t\tid: '1',\n\t\t\t\tusername: 'test',\n\t\t\t},\n\t\t],\n\t};\n\n\ttest('DMChannel has all properties', () => {\n\t\tconst instance = new DMChannel(data);\n\t\texpect(instance.id).toBe(data.id);\n\t\texpect(instance.name).toBe(data.name);\n\t\texpect(instance.flags?.toJSON()).toBe(data.flags);\n\t\texpect(instance.lastMessageId).toBe(data.last_message_id);\n\t\texpect(instance.lastPinTimestamp).toBe(Date.parse(data.last_pin_timestamp!));\n\t\texpect(instance.lastPinAt?.toISOString()).toBe(data.last_pin_timestamp);\n\t\texpect(instance[kData].recipients).toEqual(data.recipients);\n\t\texpect(instance.type).toBe(ChannelType.DM);\n\t\texpect(instance.url).toBe('https://discord.com/channels/@me/1');\n\t\texpect(instance.toJSON()).toEqual(data);\n\t});\n\n\ttest('DMChannel with no recipients', () => {\n\t\tconst instance = new DMChannel(dataNoRecipients);\n\t\texpect(instance[kData].recipients).toEqual(dataNoRecipients.recipients);\n\t\texpect(instance.toJSON()).toEqual(dataNoRecipients);\n\t});\n\n\ttest('type guards', () => {\n\t\tconst instance = new DMChannel(data);\n\t\texpect(instance.isDMBased()).toBe(true);\n\t\texpect(instance.isGuildBased()).toBe(false);\n\t\texpect(instance.isPermissionCapable()).toBe(false);\n\t\texpect(instance.isTextBased()).toBe(true);\n\t\texpect(instance.isThread()).toBe(false);\n\t\texpect(instance.isThreadOnly()).toBe(false);\n\t\texpect(instance.isVoiceBased()).toBe(false);\n\t\texpect(instance.isWebhookCapable()).toBe(false);\n\t});\n});\n\ndescribe('GroupDM channel', () => {\n\tconst data: APIGroupDMChannel = {\n\t\tid: '1',\n\t\ttype: ChannelType.GroupDM,\n\t\tlast_message_id: '3',\n\t\tname: 'name',\n\t\trecipients: [\n\t\t\t{\n\t\t\t\tavatar: '123',\n\t\t\t\tdiscriminator: '0',\n\t\t\t\tglobal_name: 'tester',\n\t\t\t\tid: '1',\n\t\t\t\tusername: 'test',\n\t\t\t},\n\t\t],\n\t\tlast_pin_timestamp: null,\n\t\tapplication_id: '34',\n\t\ticon: 'abc',\n\t\tmanaged: true,\n\t\towner_id: '567',\n\t};\n\n\ttest('GroupDMChannel has all properties', () => {\n\t\tconst instance = new GroupDMChannel(data);\n\t\texpect(instance.id).toBe(data.id);\n\t\texpect(instance.name).toBe(data.name);\n\t\texpect(instance.flags?.toJSON()).toBe(data.flags);\n\t\texpect(instance.lastMessageId).toBe(data.last_message_id);\n\t\texpect(instance[kData].recipients).toEqual(data.recipients);\n\t\texpect(instance.applicationId).toBe(data.application_id);\n\t\texpect(instance.managed).toBe(data.managed);\n\t\texpect(instance.ownerId).toBe(data.owner_id);\n\t\texpect(instance.type).toBe(ChannelType.GroupDM);\n\t\texpect(instance.icon).toBe(data.icon);\n\t\texpect(instance.url).toBe('https://discord.com/channels/@me/1');\n\t\texpect(instance.toJSON()).toEqual(data);\n\t});\n\n\ttest('type guards', () => {\n\t\tconst instance = new GroupDMChannel(data);\n\t\texpect(instance.isDMBased()).toBe(true);\n\t\texpect(instance.isGuildBased()).toBe(false);\n\t\texpect(instance.isPermissionCapable()).toBe(false);\n\t\texpect(instance.isTextBased()).toBe(true);\n\t\texpect(instance.isThread()).toBe(false);\n\t\texpect(instance.isThreadOnly()).toBe(false);\n\t\texpect(instance.isVoiceBased()).toBe(false);\n\t\texpect(instance.isWebhookCapable()).toBe(false);\n\t});\n});\n\ndescribe('forum channel', () => {\n\tconst dataNoTags: Omit<APIGuildForumChannel, 'available_tags'> = {\n\t\tid: '1',\n\t\tname: 'test',\n\t\ttype: ChannelType.GuildForum,\n\t\tposition: 0,\n\t\tguild_id: '2',\n\t\tnsfw: true,\n\t\tparent_id: '4',\n\t\tpermission_overwrites: [\n\t\t\t{\n\t\t\t\tallow: '123',\n\t\t\t\tdeny: '456',\n\t\t\t\ttype: OverwriteType.Member,\n\t\t\t\tid: '5',\n\t\t\t},\n\t\t],\n\t\ttopic: 'hello',\n\t\tdefault_auto_archive_duration: ThreadAutoArchiveDuration.OneHour,\n\t\tdefault_thread_rate_limit_per_user: 30,\n\t\tdefault_forum_layout: ForumLayoutType.GalleryView,\n\t\tdefault_reaction_emoji: {\n\t\t\temoji_id: '159',\n\t\t\temoji_name: null,\n\t\t},\n\t\tdefault_sort_order: SortOrderType.LatestActivity,\n\t};\n\tconst data: APIGuildForumChannel = {\n\t\t...dataNoTags,\n\t\tavailable_tags: [\n\t\t\t{\n\t\t\t\tname: 'emoji',\n\t\t\t\temoji_name: '😀',\n\t\t\t\tmoderated: false,\n\t\t\t\tid: '789',\n\t\t\t\temoji_id: null,\n\t\t\t},\n\t\t],\n\t};\n\n\ttest('ForumChannel has all properties', () => {\n\t\tconst instance = new ForumChannel(data);\n\t\texpect(instance.id).toBe(data.id);\n\t\texpect(instance.name).toBe(data.name);\n\t\texpect(instance.position).toBe(data.position);\n\t\texpect(instance.defaultAutoArchiveDuration).toBe(data.default_auto_archive_duration);\n\t\texpect(instance.defaultThreadRateLimitPerUser).toBe(data.default_thread_rate_limit_per_user);\n\t\texpect(instance.flags?.toJSON()).toBe(data.flags);\n\t\texpect(instance.guildId).toBe(data.guild_id);\n\t\texpect(instance.nsfw).toBe(data.nsfw);\n\t\texpect(instance.parentId).toBe(data.parent_id);\n\t\texpect(instance[kData].permission_overwrites).toEqual(data.permission_overwrites);\n\t\texpect(instance.defaultForumLayout).toBe(data.default_forum_layout);\n\t\texpect(instance.defaultReactionEmoji).toBe(data.default_reaction_emoji);\n\t\texpect(instance.defaultSortOrder).toBe(data.default_sort_order);\n\t\texpect(instance[kData].available_tags).toEqual(data.available_tags);\n\t\texpect(instance.topic).toBe(data.topic);\n\t\texpect(instance.type).toBe(ChannelType.GuildForum);\n\t\texpect(instance.url).toBe('https://discord.com/channels/2/1');\n\t\texpect(instance.toJSON()).toEqual(data);\n\t});\n\n\ttest('type guards', () => {\n\t\tconst instance = new ForumChannel(data);\n\t\texpect(instance.isDMBased()).toBe(false);\n\t\texpect(instance.isGuildBased()).toBe(true);\n\t\texpect(instance.isPermissionCapable()).toBe(true);\n\t\texpect(instance.isTextBased()).toBe(false);\n\t\texpect(instance.isThread()).toBe(false);\n\t\texpect(instance.isThreadOnly()).toBe(true);\n\t\texpect(instance.isVoiceBased()).toBe(false);\n\t\texpect(instance.isWebhookCapable()).toBe(true);\n\t});\n\n\ttest('ForumTag has all properties', () => {\n\t\tconst instances = data.available_tags.map((tag) => new ForumTag(tag));\n\t\texpect(instances.map((tag) => tag.toJSON())).toEqual(data.available_tags);\n\t\texpect(instances[0]?.id).toBe(data.available_tags[0]?.id);\n\t\texpect(instances[0]?.emojiId).toBe(data.available_tags[0]?.emoji_id);\n\t\texpect(instances[0]?.emojiName).toBe(data.available_tags[0]?.emoji_name);\n\t\texpect(instances[0]?.name).toBe(data.available_tags[0]?.name);\n\t\texpect(instances[0]?.moderated).toBe(data.available_tags[0]?.moderated);\n\t\texpect(instances[0]?.emoji).toBe(data.available_tags[0]?.emoji_name);\n\t});\n\n\ttest('omitted property from ForumChannel', () => {\n\t\tconst instance = new ForumChannel(dataNoTags);\n\t\texpect(instance.toJSON()).toEqual(dataNoTags);\n\t});\n});\n\ndescribe('media channel', () => {\n\tconst data: APIGuildMediaChannel = {\n\t\tid: '1',\n\t\tname: 'test',\n\t\ttype: ChannelType.GuildMedia,\n\t\tposition: 0,\n\t\tguild_id: '2',\n\t\tnsfw: true,\n\t\tparent_id: '4',\n\t\tpermission_overwrites: [\n\t\t\t{\n\t\t\t\tallow: '123',\n\t\t\t\tdeny: '456',\n\t\t\t\ttype: OverwriteType.Member,\n\t\t\t\tid: '5',\n\t\t\t},\n\t\t],\n\t\ttopic: 'hello',\n\t\tdefault_auto_archive_duration: ThreadAutoArchiveDuration.OneHour,\n\t\tdefault_thread_rate_limit_per_user: 30,\n\t\tavailable_tags: [\n\t\t\t{\n\t\t\t\tname: 'emoji',\n\t\t\t\temoji_name: null,\n\t\t\t\tmoderated: false,\n\t\t\t\tid: '789',\n\t\t\t\temoji_id: '444',\n\t\t\t},\n\t\t],\n\t\tdefault_reaction_emoji: {\n\t\t\temoji_id: '159',\n\t\t\temoji_name: null,\n\t\t},\n\t\tdefault_sort_order: SortOrderType.LatestActivity,\n\t};\n\n\ttest('MediaChannel has all properties', () => {\n\t\tconst instance = new MediaChannel(data);\n\t\texpect(instance.id).toBe(data.id);\n\t\texpect(instance.name).toBe(data.name);\n\t\texpect(instance.position).toBe(data.position);\n\t\texpect(instance.defaultAutoArchiveDuration).toBe(data.default_auto_archive_duration);\n\t\texpect(instance.defaultThreadRateLimitPerUser).toBe(data.default_thread_rate_limit_per_user);\n\t\texpect(instance.flags?.toJSON()).toBe(data.flags);\n\t\texpect(instance.guildId).toBe(data.guild_id);\n\t\texpect(instance.nsfw).toBe(data.nsfw);\n\t\texpect(instance.parentId).toBe(data.parent_id);\n\t\texpect(instance[kData].permission_overwrites).toEqual(data.permission_overwrites);\n\t\texpect(instance[kData].available_tags).toEqual(data.available_tags);\n\t\texpect(instance.topic).toBe(data.topic);\n\t\texpect(instance.type).toBe(ChannelType.GuildMedia);\n\t\texpect(instance.url).toBe('https://discord.com/channels/2/1');\n\t\texpect(instance.toJSON()).toEqual(data);\n\t});\n\n\ttest('type guards', () => {\n\t\tconst instance = new MediaChannel(data);\n\t\texpect(instance.isDMBased()).toBe(false);\n\t\texpect(instance.isGuildBased()).toBe(true);\n\t\texpect(instance.isPermissionCapable()).toBe(true);\n\t\texpect(instance.isTextBased()).toBe(false);\n\t\texpect(instance.isThread()).toBe(false);\n\t\texpect(instance.isThreadOnly()).toBe(true);\n\t\texpect(instance.isVoiceBased()).toBe(false);\n\t\texpect(instance.isWebhookCapable()).toBe(true);\n\t});\n\n\ttest('ForumTag has all properties', () => {\n\t\tconst instances = data.available_tags.map((tag) => new ForumTag(tag));\n\t\texpect(instances.map((tag) => tag.toJSON())).toEqual(data.available_tags);\n\t\texpect(instances[0]?.emoji).toBe(`<:_:${data.available_tags[0]?.emoji_id}>`);\n\t});\n});\n\ndescribe('voice channel', () => {\n\tconst data: APIGuildVoiceChannel = {\n\t\tid: '1',\n\t\tname: 'test',\n\t\ttype: ChannelType.GuildVoice,\n\t\tposition: 0,\n\t\tguild_id: '2',\n\t\tlast_message_id: '3',\n\t\tnsfw: true,\n\t\tparent_id: '4',\n\t\tpermission_overwrites: [\n\t\t\t{\n\t\t\t\tallow: '123',\n\t\t\t\tdeny: '456',\n\t\t\t\ttype: OverwriteType.Member,\n\t\t\t\tid: '5',\n\t\t\t},\n\t\t],\n\t\trate_limit_per_user: 9,\n\t\tbitrate: 7,\n\t\trtc_region: 'somewhere',\n\t\tuser_limit: 100,\n\t\tvideo_quality_mode: VideoQualityMode.Full,\n\t};\n\n\ttest('VoiceChannel has all properties', () => {\n\t\tconst instance = new VoiceChannel(data);\n\t\texpect(instance.id).toBe(data.id);\n\t\texpect(instance.name).toBe(data.name);\n\t\texpect(instance.position).toBe(data.position);\n\t\texpect(instance.bitrate).toBe(data.bitrate);\n\t\texpect(instance.rtcRegion).toBe(data.rtc_region);\n\t\texpect(instance.flags?.toJSON()).toBe(data.flags);\n\t\texpect(instance.guildId).toBe(data.guild_id);\n\t\texpect(instance.lastMessageId).toBe(data.last_message_id);\n\t\texpect(instance.videoQualityMode).toBe(data.video_quality_mode);\n\t\texpect(instance.userLimit).toBe(data.user_limit);\n\t\texpect(instance.nsfw).toBe(data.nsfw);\n\t\texpect(instance.parentId).toBe(data.parent_id);\n\t\texpect(instance[kData].permission_overwrites).toEqual(data.permission_overwrites);\n\t\texpect(instance.rateLimitPerUser).toBe(data.rate_limit_per_user);\n\t\texpect(instance.type).toBe(ChannelType.GuildVoice);\n\t\texpect(instance.url).toBe('https://discord.com/channels/2/1');\n\t\texpect(instance.toJSON()).toEqual(data);\n\t});\n\n\ttest('type guards', () => {\n\t\tconst instance = new VoiceChannel(data);\n\t\texpect(instance.isDMBased()).toBe(false);\n\t\texpect(instance.isGuildBased()).toBe(true);\n\t\texpect(instance.isPermissionCapable()).toBe(true);\n\t\texpect(instance.isTextBased()).toBe(true);\n\t\texpect(instance.isThread()).toBe(false);\n\t\texpect(instance.isThreadOnly()).toBe(false);\n\t\texpect(instance.isVoiceBased()).toBe(true);\n\t\texpect(instance.isWebhookCapable()).toBe(true);\n\t});\n});\n\ndescribe('stage channel', () => {\n\tconst data: APIGuildStageVoiceChannel = {\n\t\tid: '1',\n\t\tname: 'test',\n\t\ttype: ChannelType.GuildStageVoice,\n\t\tposition: 0,\n\t\tguild_id: '2',\n\t\tlast_message_id: '3',\n\t\tnsfw: true,\n\t\tparent_id: '4',\n\t\tpermission_overwrites: [\n\t\t\t{\n\t\t\t\tallow: '123',\n\t\t\t\tdeny: '456',\n\t\t\t\ttype: OverwriteType.Member,\n\t\t\t\tid: '5',\n\t\t\t},\n\t\t],\n\t\trate_limit_per_user: 9,\n\t\tbitrate: 7,\n\t\trtc_region: 'somewhere',\n\t\tuser_limit: 100,\n\t\tvideo_quality_mode: VideoQualityMode.Full,\n\t};\n\n\ttest('StageChannel has all properties', () => {\n\t\tconst instance = new StageChannel(data);\n\t\texpect(instance.id).toBe(data.id);\n\t\texpect(instance.name).toBe(data.name);\n\t\texpect(instance.position).toBe(data.position);\n\t\texpect(instance.bitrate).toBe(data.bitrate);\n\t\texpect(instance.rtcRegion).toBe(data.rtc_region);\n\t\texpect(instance.flags?.toJSON()).toBe(data.flags);\n\t\texpect(instance.guildId).toBe(data.guild_id);\n\t\texpect(instance.lastMessageId).toBe(data.last_message_id);\n\t\texpect(instance.videoQualityMode).toBe(data.video_quality_mode);\n\t\texpect(instance.nsfw).toBe(data.nsfw);\n\t\texpect(instance.parentId).toBe(data.parent_id);\n\t\texpect(instance[kData].permission_overwrites).toEqual(data.permission_overwrites);\n\t\texpect(instance.rateLimitPerUser).toBe(data.rate_limit_per_user);\n\t\texpect(instance.type).toBe(ChannelType.GuildStageVoice);\n\t\texpect(instance.url).toBe('https://discord.com/channels/2/1');\n\t\texpect(instance.toJSON()).toEqual(data);\n\t});\n\n\ttest('type guards', () => {\n\t\tconst instance = new StageChannel(data);\n\t\texpect(instance.isDMBased()).toBe(false);\n\t\texpect(instance.isGuildBased()).toBe(true);\n\t\texpect(instance.isPermissionCapable()).toBe(true);\n\t\texpect(instance.isTextBased()).toBe(true);\n\t\texpect(instance.isThread()).toBe(false);\n\t\texpect(instance.isThreadOnly()).toBe(false);\n\t\texpect(instance.isVoiceBased()).toBe(true);\n\t\texpect(instance.isWebhookCapable()).toBe(true);\n\t});\n});\n\ndescribe('thread channels', () => {\n\tconst dataNoTags: Omit<APIPublicThreadChannel, 'applied_tags'> = {\n\t\tid: '1',\n\t\tname: 'test',\n\t\ttype: ChannelType.PublicThread,\n\t\tguild_id: '2',\n\t\tlast_message_id: '3',\n\t\tlast_pin_timestamp: null,\n\t\tnsfw: true,\n\t\tparent_id: '4',\n\t\trate_limit_per_user: 9,\n\t};\n\n\tconst dataPublic: APIPublicThreadChannel = {\n\t\t...dataNoTags,\n\t\tapplied_tags: ['567'],\n\t};\n\n\tconst dataAnnounce: APIAnnouncementThreadChannel = {\n\t\t...dataPublic,\n\t\tthread_metadata: {\n\t\t\tarchive_timestamp: '2024-09-08T12:01:02.345Z',\n\t\t\tarchived: false,\n\t\t\tauto_archive_duration: ThreadAutoArchiveDuration.ThreeDays,\n\t\t\tlocked: true,\n\t\t},\n\t\tflags: ChannelFlags.Pinned,\n\t\ttype: ChannelType.AnnouncementThread,\n\t};\n\n\tconst dataPrivate: APIPrivateThreadChannel = {\n\t\t...dataPublic,\n\t\tthread_metadata: {\n\t\t\t...dataAnnounce.thread_metadata!,\n\t\t\tcreate_timestamp: '2023-01-02T15:13:11.987Z',\n\t\t\tinvitable: true,\n\t\t},\n\t\ttype: ChannelType.PrivateThread,\n\t};\n\n\ttest('PublicThreadChannel has all properties', () => {\n\t\tconst instance = new PublicThreadChannel(dataPublic);\n\t\texpect(instance.id).toBe(dataPublic.id);\n\t\texpect(instance.name).toBe(dataPublic.name);\n\t\texpect(instance.flags?.toJSON()).toBe(dataPublic.flags);\n\t\texpect(instance.guildId).toBe(dataPublic.guild_id);\n\t\texpect(instance.lastMessageId).toBe(dataPublic.last_message_id);\n\t\texpect(instance.nsfw).toBe(dataPublic.nsfw);\n\t\texpect(instance.parentId).toBe(dataPublic.parent_id);\n\t\texpect(instance.rateLimitPerUser).toBe(dataPublic.rate_limit_per_user);\n\t\texpect(instance.type).toBe(ChannelType.PublicThread);\n\t\texpect(instance.appliedTags).toEqual(dataPublic.applied_tags);\n\t\texpect(instance.memberCount).toBe(dataPublic.member_count);\n\t\texpect(instance.messageCount).toBe(dataPublic.message_count);\n\t\texpect(instance.totalMessageSent).toBe(dataPublic.total_message_sent);\n\t\texpect(instance.url).toBe('https://discord.com/channels/2/1');\n\t\texpect(instance.toJSON()).toEqual(dataPublic);\n\t});\n\n\ttest('type guards PublicThread', () => {\n\t\tconst instance = new PublicThreadChannel(dataPublic);\n\t\texpect(instance.isDMBased()).toBe(false);\n\t\texpect(instance.isGuildBased()).toBe(true);\n\t\texpect(instance.isPermissionCapable()).toBe(false);\n\t\texpect(instance.isTextBased()).toBe(true);\n\t\texpect(instance.isThread()).toBe(true);\n\t\texpect(instance.isThreadOnly()).toBe(false);\n\t\texpect(instance.isVoiceBased()).toBe(false);\n\t\texpect(instance.isWebhookCapable()).toBe(false);\n\t});\n\n\ttest('PrivateThreadChannel has all properties', () => {\n\t\tconst instance = new PrivateThreadChannel(dataPrivate);\n\t\texpect(instance.id).toBe(dataPrivate.id);\n\t\texpect(instance.name).toBe(dataPrivate.name);\n\t\texpect(instance.flags?.toJSON()).toBe(dataPrivate.flags);\n\t\texpect(instance.guildId).toBe(dataPrivate.guild_id);\n\t\texpect(instance.lastMessageId).toBe(dataPrivate.last_message_id);\n\t\texpect(instance.nsfw).toBe(dataPrivate.nsfw);\n\t\texpect(instance.parentId).toBe(dataPrivate.parent_id);\n\t\texpect(instance.rateLimitPerUser).toBe(dataPrivate.rate_limit_per_user);\n\t\texpect(instance[kData].thread_metadata).toEqual(dataPrivate.thread_metadata);\n\t\texpect(instance.type).toBe(ChannelType.PrivateThread);\n\t\texpect(instance.url).toBe('https://discord.com/channels/2/1');\n\t\texpect(instance.toJSON()).toEqual(dataPrivate);\n\t});\n\n\ttest('type guards PrivateThread', () => {\n\t\tconst instance = new PrivateThreadChannel(dataPrivate);\n\t\texpect(instance.isDMBased()).toBe(false);\n\t\texpect(instance.isGuildBased()).toBe(true);\n\t\texpect(instance.isPermissionCapable()).toBe(false);\n\t\texpect(instance.isTextBased()).toBe(true);\n\t\texpect(instance.isThread()).toBe(true);\n\t\texpect(instance.isThreadOnly()).toBe(false);\n\t\texpect(instance.isVoiceBased()).toBe(false);\n\t\texpect(instance.isWebhookCapable()).toBe(false);\n\t});\n\n\ttest('AnnouncementThreadChannel has all properties', () => {\n\t\tconst instance = new AnnouncementThreadChannel(dataAnnounce);\n\t\texpect(instance.id).toBe(dataAnnounce.id);\n\t\texpect(instance.name).toBe(dataAnnounce.name);\n\t\texpect(instance.flags?.toJSON()).toBe(dataAnnounce.flags);\n\t\texpect(instance.guildId).toBe(dataAnnounce.guild_id);\n\t\texpect(instance.lastMessageId).toBe(dataAnnounce.last_message_id);\n\t\texpect(instance.nsfw).toBe(dataAnnounce.nsfw);\n\t\texpect(instance.parentId).toBe(dataAnnounce.parent_id);\n\t\texpect(instance.rateLimitPerUser).toBe(dataAnnounce.rate_limit_per_user);\n\t\texpect(instance[kData].thread_metadata).toEqual(dataAnnounce.thread_metadata);\n\t\texpect(instance.type).toBe(ChannelType.AnnouncementThread);\n\t\texpect(instance.url).toBe('https://discord.com/channels/2/1');\n\t\texpect(instance.toJSON()).toEqual(dataAnnounce);\n\t});\n\n\ttest('type guards AnnouncementThread', () => {\n\t\tconst instance = new AnnouncementThreadChannel(dataAnnounce);\n\t\texpect(instance.isDMBased()).toBe(false);\n\t\texpect(instance.isGuildBased()).toBe(true);\n\t\texpect(instance.isPermissionCapable()).toBe(false);\n\t\texpect(instance.isTextBased()).toBe(true);\n\t\texpect(instance.isThread()).toBe(true);\n\t\texpect(instance.isThreadOnly()).toBe(false);\n\t\texpect(instance.isVoiceBased()).toBe(false);\n\t\texpect(instance.isWebhookCapable()).toBe(false);\n\t});\n\n\ttest('omitted property from PublicThread', () => {\n\t\tconst instance = new PublicThreadChannel(dataNoTags);\n\t\texpect(instance.toJSON()).toEqual(dataNoTags);\n\t\texpect(instance.appliedTags).toBe(null);\n\t});\n\n\ttest('ThreadMetadata has all properties', () => {\n\t\tconst instance = new ThreadMetadata(dataPrivate.thread_metadata!);\n\t\texpect(instance.toJSON()).toEqual(dataPrivate.thread_metadata);\n\t\texpect(instance.archived).toBe(dataPrivate.thread_metadata?.archived);\n\t\texpect(instance.archivedAt?.toISOString()).toBe(dataPrivate.thread_metadata?.archive_timestamp);\n\t\texpect(instance.archivedTimestamp).toBe(Date.parse(dataPrivate.thread_metadata!.archive_timestamp));\n\t\texpect(instance.createdAt?.toISOString()).toBe(dataPrivate.thread_metadata?.create_timestamp);\n\t\texpect(instance.createdTimestamp).toBe(Date.parse(dataPrivate.thread_metadata!.create_timestamp!));\n\t\texpect(instance.autoArchiveDuration).toBe(dataPrivate.thread_metadata?.auto_archive_duration);\n\t\texpect(instance.invitable).toBe(dataPrivate.thread_metadata?.invitable);\n\t\texpect(instance.locked).toBe(dataPrivate.thread_metadata?.locked);\n\t});\n});\n"
  },
  {
    "path": "packages/structures/__tests__/invite.test.ts",
    "content": "import type { APIExtendedInvite, APIInvite } from 'discord-api-types/v10';\nimport { InviteTargetType, InviteType } from 'discord-api-types/v10';\nimport { describe, expect, test } from 'vitest';\nimport { Invite } from '../src/invites/Invite.js';\nimport { dateToDiscordISOTimestamp } from '../src/utils/optimization.js';\nimport { kPatch } from '../src/utils/symbols.js';\n\ndescribe('Invite', () => {\n\t// TODO: Check if omitting `expires_at` is appropriate\n\n\tconst dataNoCode: Omit<APIInvite, 'code' | 'expires_at'> = {\n\t\ttype: InviteType.Guild,\n\t\tchannel: null,\n\t\tapproximate_member_count: 15,\n\t\tapproximate_presence_count: 35,\n\t\ttarget_type: InviteTargetType.EmbeddedApplication,\n\t};\n\n\tconst data: Omit<APIInvite, 'expires_at'> = {\n\t\t...dataNoCode,\n\t\tcode: '123',\n\t};\n\n\tconst dataExtended: Omit<APIExtendedInvite, 'expires_at'> = {\n\t\t...data,\n\t\tcreated_at: '2020-10-10T13:50:17.209000+00:00',\n\t\tmax_age: 12,\n\t\tmax_uses: 34,\n\t\ttemporary: false,\n\t\tuses: 5,\n\t};\n\n\ttest('Invite has all properties', () => {\n\t\tconst instance = new Invite(data);\n\t\texpect(instance.type).toBe(data.type);\n\t\texpect(instance.code).toBe(data.code);\n\t\texpect(instance.createdAt).toBe(null);\n\t\texpect(instance.createdTimestamp).toBe(null);\n\t\texpect(instance.maxAge).toBe(undefined);\n\t\texpect(instance.maxUses).toBe(undefined);\n\t\texpect(instance.approximateMemberCount).toBe(data.approximate_member_count);\n\t\texpect(instance.approximatePresenceCount).toBe(data.approximate_presence_count);\n\t\texpect(instance.targetType).toBe(data.target_type);\n\t\texpect(instance.temporary).toBe(undefined);\n\t\texpect(instance.uses).toBe(undefined);\n\t\texpect(instance.expiresTimestamp).toBe(null);\n\t\texpect(instance.expiresAt).toBe(null);\n\t\texpect(instance.url).toBe('https://discord.gg/123');\n\t\texpect(instance.toJSON()).toEqual(data);\n\t\texpect(`${instance}`).toBe('https://discord.gg/123');\n\t\texpect(instance.valueOf()).toBe(data.code);\n\t});\n\n\ttest('extended Invite has all properties', () => {\n\t\tconst instance = new Invite(dataExtended);\n\t\texpect(instance.type).toBe(data.type);\n\t\texpect(instance.code).toBe(dataExtended.code);\n\t\texpect(dateToDiscordISOTimestamp(instance.createdAt!)).toBe(dataExtended.created_at);\n\t\texpect(instance.createdTimestamp).toBe(Date.parse(dataExtended.created_at));\n\t\texpect(instance.maxAge).toBe(dataExtended.max_age);\n\t\texpect(instance.maxUses).toBe(dataExtended.max_uses);\n\t\texpect(instance.approximateMemberCount).toBe(dataExtended.approximate_member_count);\n\t\texpect(instance.approximatePresenceCount).toBe(dataExtended.approximate_presence_count);\n\t\texpect(instance.targetType).toBe(dataExtended.target_type);\n\t\texpect(instance.temporary).toBe(dataExtended.temporary);\n\t\texpect(instance.uses).toBe(dataExtended.uses);\n\t\texpect(instance.expiresTimestamp).toStrictEqual(Date.parse('2020-10-10T13:50:29.209000+00:00'));\n\t\texpect(instance.expiresAt).toStrictEqual(new Date('2020-10-10T13:50:29.209000+00:00'));\n\t\texpect(instance.url).toBe('https://discord.gg/123');\n\t\texpect(instance.toJSON()).toEqual({ ...dataExtended, expires_at: '2020-10-10T13:50:29.209000+00:00' });\n\t});\n\n\ttest('Invite with omitted properties', () => {\n\t\tconst instance = new Invite(dataNoCode);\n\t\texpect(instance.toJSON()).toEqual(dataNoCode);\n\t\texpect(instance.url).toBe(null);\n\t\texpect(instance.code).toBe(undefined);\n\t\texpect(`${instance}`).toBe('');\n\t\texpect(instance.valueOf()).toEqual(Object.prototype.valueOf.apply(instance));\n\t});\n\n\ttest('Invite with expiration', () => {\n\t\tconst instance = new Invite({ ...dataExtended, expires_at: '2020-10-10T13:50:29.209000+00:00' });\n\t\texpect(instance.toJSON()).toEqual({ ...dataExtended, expires_at: '2020-10-10T13:50:29.209000+00:00' });\n\t});\n\n\ttest('Patching Invite works in place', () => {\n\t\tconst instance1 = new Invite(data);\n\t\tconst instance2 = instance1[kPatch]({ max_age: 34 });\n\t\texpect(instance1.toJSON()).not.toEqual(data);\n\t\texpect(instance2).toBe(instance1);\n\t});\n});\n"
  },
  {
    "path": "packages/structures/__tests__/message.test.ts",
    "content": "import { DiscordSnowflake } from '@sapphire/snowflake';\nimport type {\n\tAPIActionRowComponent,\n\tAPIButtonComponent,\n\tAPIChannelSelectComponent,\n\tAPIContainerComponent,\n\tAPIFileComponent,\n\tAPIMediaGalleryComponent,\n\tAPIMentionableSelectComponent,\n\tAPIMessage,\n\tAPIRoleSelectComponent,\n\tAPISectionComponent,\n\tAPISeparatorComponent,\n\tAPIStringSelectComponent,\n\tAPIUser,\n\tAPIUserSelectComponent,\n} from 'discord-api-types/v10';\nimport {\n\tMessageReferenceType,\n\tMessageType,\n\tMessageFlags,\n\tComponentType,\n\tButtonStyle,\n\tSeparatorSpacingSize,\n\tChannelType,\n\tSelectMenuDefaultValueType,\n} from 'discord-api-types/v10';\nimport { describe, expect, test } from 'vitest';\nimport { Attachment } from '../src/messages/Attachment.js';\nimport { Message } from '../src/messages/Message.js';\nimport { ContainerComponent } from '../src/messages/components/ContainerComponent.js';\nimport { Embed } from '../src/messages/embeds/Embed.js';\nimport { User } from '../src/users/User.js';\nimport { dateToDiscordISOTimestamp } from '../src/utils/optimization.js';\n\nconst user: APIUser = {\n\tusername: 'user',\n\tavatar: 'abcd123',\n\tglobal_name: 'User',\n\tdiscriminator: '0',\n\tid: '3',\n};\n\ndescribe('message with embeds and attachments', () => {\n\tconst timestamp = '2025-10-09T17:48:20.192000+00:00';\n\tconst data: APIMessage = {\n\t\tid: DiscordSnowflake.generate({ timestamp: Date.parse(timestamp) }).toString(),\n\t\ttype: MessageType.Default,\n\t\tposition: 10,\n\t\tchannel_id: '2',\n\t\tauthor: user,\n\t\tattachments: [\n\t\t\t{\n\t\t\t\tfilename: 'file.txt',\n\t\t\t\tdescription: 'describe attachment',\n\t\t\t\tid: '0',\n\t\t\t\tproxy_url: 'https://media.example.com/attachment/123.txt',\n\t\t\t\tsize: 5,\n\t\t\t\turl: 'https://example.com/attachment/123.txt',\n\t\t\t},\n\t\t],\n\t\tcontent: 'something <&5> <&6>',\n\t\tedited_timestamp: '2025-10-09T17:50:20.292000+00:00',\n\t\tembeds: [\n\t\t\t{\n\t\t\t\tauthor: {\n\t\t\t\t\tname: 'embed author',\n\t\t\t\t\ticon_url: 'https://discord.js.org/static/logo.svg',\n\t\t\t\t},\n\t\t\t\tcolor: 255,\n\t\t\t\tdescription: 'describe me',\n\t\t\t\tfields: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'field name',\n\t\t\t\t\t\tvalue: 'field value',\n\t\t\t\t\t\tinline: false,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tfooter: {\n\t\t\t\t\ttext: 'footer',\n\t\t\t\t},\n\t\t\t\timage: {\n\t\t\t\t\turl: 'https://discord.js.org/static/logo.svg',\n\t\t\t\t},\n\t\t\t\tthumbnail: {\n\t\t\t\t\turl: 'https://discord.js.org/static/logo.svg',\n\t\t\t\t},\n\t\t\t\ttitle: 'Title',\n\t\t\t\ttimestamp: '2025-10-19T21:39:40.193000+00:00',\n\t\t\t},\n\t\t],\n\t\tmention_everyone: false,\n\t\tmention_roles: ['5', '6'],\n\t\tmentions: [user],\n\t\tpinned: false,\n\t\ttimestamp,\n\t\ttts: false,\n\t\tflags: MessageFlags.SuppressNotifications,\n\t};\n\n\ttest('Message has all properties', () => {\n\t\tconst instance = new Message(data);\n\t\texpect(instance.id).toBe(data.id);\n\t\texpect(instance.channelId).toBe(data.channel_id);\n\t\texpect(instance.position).toBe(data.position);\n\t\texpect(instance.content).toBe(data.content);\n\t\texpect(instance.createdTimestamp).toBe(Date.parse(data.timestamp));\n\t\texpect(dateToDiscordISOTimestamp(instance.createdAt!)).toBe(data.timestamp);\n\t\texpect(instance.flags?.toJSON()).toBe(data.flags);\n\t\texpect(instance.editedTimestamp).toBe(Date.parse(data.edited_timestamp!));\n\t\texpect(dateToDiscordISOTimestamp(instance.editedAt!)).toBe(data.edited_timestamp);\n\t\texpect(instance.nonce).toBe(data.nonce);\n\t\texpect(instance.pinned).toBe(data.pinned);\n\t\texpect(instance.tts).toBe(data.tts);\n\t\texpect(instance.webhookId).toBe(data.webhook_id);\n\t\texpect(instance.type).toBe(MessageType.Default);\n\t\texpect(instance.toJSON()).toEqual(data);\n\t});\n\n\ttest('Attachment sub-structure', () => {\n\t\tconst instances = data.attachments?.map((attachment) => new Attachment(attachment));\n\t\texpect(instances?.map((attachment) => attachment.toJSON())).toEqual(data.attachments);\n\t\texpect(instances?.[0]?.description).toBe(data.attachments?.[0]?.description);\n\t\texpect(instances?.[0]?.filename).toBe(data.attachments?.[0]?.filename);\n\t\texpect(instances?.[0]?.id).toBe(data.attachments?.[0]?.id);\n\t\texpect(instances?.[0]?.size).toBe(data.attachments?.[0]?.size);\n\t\texpect(instances?.[0]?.url).toBe(data.attachments?.[0]?.url);\n\t\texpect(instances?.[0]?.proxyURL).toBe(data.attachments?.[0]?.proxy_url);\n\t});\n\n\ttest('Embed sub-structure', () => {\n\t\tconst instances = data.embeds?.map((embed) => new Embed(embed));\n\t\texpect(instances?.map((embed) => embed.toJSON())).toEqual(data.embeds);\n\t\texpect(instances?.[0]?.description).toBe(data.embeds?.[0]?.description);\n\t\texpect(instances?.[0]?.color).toBe(data.embeds?.[0]?.color);\n\t\texpect(instances?.[0]?.timestamp).toBe(Date.parse(data.embeds![0]!.timestamp!));\n\t\texpect(instances?.[0]?.title).toBe(data.embeds?.[0]?.title);\n\t\texpect(instances?.[0]?.url).toBe(data.embeds?.[0]?.url);\n\t\texpect(instances?.[0]?.type).toBe(data.embeds?.[0]?.type);\n\t});\n\n\ttest('User sub-structure', () => {\n\t\tconst instance = new User(data.author);\n\t\tconst instances = data.mentions.map((user) => new User(user));\n\t\texpect(instance.toJSON()).toEqual(data.author);\n\t\texpect(instances.map((user) => user.toJSON())).toEqual(data.mentions);\n\t\texpect(instance.avatar).toBe(data.author.avatar);\n\t\texpect(instance.discriminator).toBe(data.author.discriminator);\n\t\texpect(instance.displayName).toBe(data.author.global_name);\n\t\texpect(instance.globalName).toBe(data.author.global_name);\n\t\texpect(instance.id).toBe(data.author.id);\n\t\texpect(instance.username).toBe(data.author.username);\n\t});\n});\n\ndescribe('message with components', () => {\n\tconst timestamp = '2025-10-10T15:48:20.192000+00:00';\n\tconst buttonRow: APIActionRowComponent<APIButtonComponent> = {\n\t\ttype: ComponentType.ActionRow,\n\t\tid: 5,\n\t\tcomponents: [\n\t\t\t{\n\t\t\t\ttype: ComponentType.Button,\n\t\t\t\tstyle: ButtonStyle.Danger,\n\t\t\t\tcustom_id: 'danger',\n\t\t\t\tdisabled: false,\n\t\t\t\temoji: {\n\t\t\t\t\tanimated: false,\n\t\t\t\t\tid: '12345',\n\t\t\t\t\tname: 'emoji',\n\t\t\t\t},\n\t\t\t\tid: 6,\n\t\t\t\tlabel: 'Danger button',\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: ComponentType.Button,\n\t\t\t\tstyle: ButtonStyle.Link,\n\t\t\t\turl: 'https://discord.js.org/',\n\t\t\t\tdisabled: false,\n\t\t\t\tid: 7,\n\t\t\t\tlabel: 'DJS',\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: ComponentType.Button,\n\t\t\t\tstyle: ButtonStyle.Premium,\n\t\t\t\tsku_id: '9876',\n\t\t\t\tdisabled: false,\n\t\t\t\tid: 8,\n\t\t\t},\n\t\t],\n\t};\n\tconst file: APIFileComponent = {\n\t\ttype: ComponentType.File,\n\t\tfile: {\n\t\t\turl: 'attachment://file.txt',\n\t\t\tattachment_id: '0',\n\t\t\tcontent_type: 'text/plain',\n\t\t\tflags: 0,\n\t\t},\n\t\tid: 9,\n\t\tspoiler: true,\n\t};\n\tconst mediaGallery: APIMediaGalleryComponent = {\n\t\ttype: ComponentType.MediaGallery,\n\t\titems: [\n\t\t\t{\n\t\t\t\tmedia: {\n\t\t\t\t\turl: 'https://discord.js.org/static/logo.svg',\n\t\t\t\t\tcontent_type: 'image/svg+xml',\n\t\t\t\t\theight: 50,\n\t\t\t\t\twidth: 50,\n\t\t\t\t},\n\t\t\t\tdescription: 'Logo',\n\t\t\t\tspoiler: false,\n\t\t\t},\n\t\t],\n\t\tid: 10,\n\t};\n\tconst section: APISectionComponent = {\n\t\ttype: ComponentType.Section,\n\t\taccessory: {\n\t\t\ttype: ComponentType.Thumbnail,\n\t\t\tmedia: {\n\t\t\t\turl: 'https://discord.js.org/static/logo.svg',\n\t\t\t},\n\t\t\tdescription: 'Logo thumbnail',\n\t\t\tid: 13,\n\t\t\tspoiler: false,\n\t\t},\n\t\tcomponents: [\n\t\t\t{\n\t\t\t\ttype: ComponentType.TextDisplay,\n\t\t\t\tcontent: 'Text',\n\t\t\t\tid: 14,\n\t\t\t},\n\t\t],\n\t\tid: 12,\n\t};\n\tconst separator: APISeparatorComponent = {\n\t\ttype: ComponentType.Separator,\n\t\tdivider: true,\n\t\tid: 15,\n\t\tspacing: SeparatorSpacingSize.Large,\n\t};\n\tconst channelRow: APIActionRowComponent<APIChannelSelectComponent> = {\n\t\ttype: ComponentType.ActionRow,\n\t\tid: 16,\n\t\tcomponents: [\n\t\t\t{\n\t\t\t\ttype: ComponentType.ChannelSelect,\n\t\t\t\tcustom_id: 'channel',\n\t\t\t\tchannel_types: [ChannelType.GuildCategory, ChannelType.GuildText],\n\t\t\t\tdefault_values: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: '123456789012345678',\n\t\t\t\t\t\ttype: SelectMenuDefaultValueType.Channel,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: '123456789012345679',\n\t\t\t\t\t\ttype: SelectMenuDefaultValueType.Channel,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdisabled: false,\n\t\t\t\tid: 17,\n\t\t\t\tmax_values: 2,\n\t\t\t\tmin_values: 0,\n\t\t\t\tplaceholder: '(none)',\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t],\n\t};\n\tconst mentionRow: APIActionRowComponent<APIMentionableSelectComponent> = {\n\t\ttype: ComponentType.ActionRow,\n\t\tid: 18,\n\t\tcomponents: [\n\t\t\t{\n\t\t\t\ttype: ComponentType.MentionableSelect,\n\t\t\t\tcustom_id: 'mention',\n\t\t\t\tdefault_values: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: '123456789012345678',\n\t\t\t\t\t\ttype: SelectMenuDefaultValueType.User,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: '123456789012345679',\n\t\t\t\t\t\ttype: SelectMenuDefaultValueType.Role,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdisabled: false,\n\t\t\t\tid: 19,\n\t\t\t\tmax_values: 2,\n\t\t\t\tmin_values: 0,\n\t\t\t\tplaceholder: '(none)',\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t],\n\t};\n\tconst roleRow: APIActionRowComponent<APIRoleSelectComponent> = {\n\t\ttype: ComponentType.ActionRow,\n\t\tid: 20,\n\t\tcomponents: [\n\t\t\t{\n\t\t\t\ttype: ComponentType.RoleSelect,\n\t\t\t\tcustom_id: 'role',\n\t\t\t\tdefault_values: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: '123456789012345678',\n\t\t\t\t\t\ttype: SelectMenuDefaultValueType.Role,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: '123456789012345679',\n\t\t\t\t\t\ttype: SelectMenuDefaultValueType.Role,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdisabled: false,\n\t\t\t\tid: 21,\n\t\t\t\tmax_values: 2,\n\t\t\t\tmin_values: 0,\n\t\t\t\tplaceholder: '(none)',\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t],\n\t};\n\tconst userRow: APIActionRowComponent<APIUserSelectComponent> = {\n\t\ttype: ComponentType.ActionRow,\n\t\tid: 22,\n\t\tcomponents: [\n\t\t\t{\n\t\t\t\ttype: ComponentType.UserSelect,\n\t\t\t\tcustom_id: 'user',\n\t\t\t\tdefault_values: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: '123456789012345678',\n\t\t\t\t\t\ttype: SelectMenuDefaultValueType.User,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: '123456789012345679',\n\t\t\t\t\t\ttype: SelectMenuDefaultValueType.User,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdisabled: false,\n\t\t\t\tid: 23,\n\t\t\t\tmax_values: 2,\n\t\t\t\tmin_values: 0,\n\t\t\t\tplaceholder: '(none)',\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t],\n\t};\n\tconst stringRow: APIActionRowComponent<APIStringSelectComponent> = {\n\t\ttype: ComponentType.ActionRow,\n\t\tid: 24,\n\t\tcomponents: [\n\t\t\t{\n\t\t\t\ttype: ComponentType.StringSelect,\n\t\t\t\tcustom_id: 'string',\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tlabel: 'one',\n\t\t\t\t\t\tvalue: '1',\n\t\t\t\t\t\tdefault: true,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tlabel: 'two',\n\t\t\t\t\t\tvalue: '2',\n\t\t\t\t\t\tdefault: false,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tlabel: 'three',\n\t\t\t\t\t\tvalue: '3',\n\t\t\t\t\t\tdescription: 'third',\n\t\t\t\t\t\temoji: {\n\t\t\t\t\t\t\tid: '3333333333333333333',\n\t\t\t\t\t\t\tname: '3',\n\t\t\t\t\t\t\tanimated: false,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdisabled: false,\n\t\t\t\tid: 25,\n\t\t\t\tmax_values: 2,\n\t\t\t\tmin_values: 0,\n\t\t\t\tplaceholder: '(none)',\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t],\n\t};\n\tconst container: APIContainerComponent = {\n\t\ttype: ComponentType.Container,\n\t\taccent_color: 255,\n\t\tid: 4,\n\t\tcomponents: [\n\t\t\tbuttonRow,\n\t\t\tfile,\n\t\t\tmediaGallery,\n\t\t\tsection,\n\t\t\tseparator,\n\t\t\tchannelRow,\n\t\t\tmentionRow,\n\t\t\troleRow,\n\t\t\tuserRow,\n\t\t\tstringRow,\n\t\t],\n\t\tspoiler: true,\n\t};\n\tconst data: APIMessage = {\n\t\tid: DiscordSnowflake.generate({ timestamp: Date.parse(timestamp) }).toString(),\n\t\ttype: MessageType.Reply,\n\t\tposition: 15,\n\t\tchannel_id: '2',\n\t\tauthor: user,\n\t\tattachments: [\n\t\t\t{\n\t\t\t\tfilename: 'file.txt',\n\t\t\t\tdescription: 'describe attachment',\n\t\t\t\tid: '0',\n\t\t\t\tproxy_url: 'https://media.example.com/attachment/123.txt',\n\t\t\t\tsize: 5,\n\t\t\t\turl: 'https://example.com/attachment/123.txt',\n\t\t\t},\n\t\t],\n\t\tcontent: '',\n\t\tedited_timestamp: '2025-10-10T15:50:20.292000+00:00',\n\t\tembeds: [],\n\t\tcomponents: [container],\n\t\tmessage_reference: {\n\t\t\tchannel_id: '505050505050505050',\n\t\t\tmessage_id: '606060606060606060',\n\t\t\tguild_id: '707070707070707070',\n\t\t\ttype: MessageReferenceType.Default,\n\t\t},\n\t\tmention_everyone: false,\n\t\tmention_roles: ['5', '6'],\n\t\tmentions: [user],\n\t\tpinned: false,\n\t\ttimestamp,\n\t\ttts: false,\n\t\tflags: MessageFlags.IsComponentsV2 | MessageFlags.Ephemeral,\n\t};\n\n\ttest('Message has all properties', () => {\n\t\tconst instance = new Message(data);\n\t\texpect(instance.id).toBe(data.id);\n\t\texpect(instance.channelId).toBe(data.channel_id);\n\t\texpect(instance.position).toBe(data.position);\n\t\texpect(instance.content).toBe(data.content);\n\t\texpect(instance.createdTimestamp).toBe(Date.parse(data.timestamp));\n\t\texpect(dateToDiscordISOTimestamp(instance.createdAt!)).toBe(data.timestamp);\n\t\texpect(instance.flags?.toJSON()).toBe(data.flags);\n\t\texpect(instance.editedTimestamp).toBe(Date.parse(data.edited_timestamp!));\n\t\texpect(dateToDiscordISOTimestamp(instance.editedAt!)).toBe(data.edited_timestamp);\n\t\texpect(instance.nonce).toBe(data.nonce);\n\t\texpect(instance.pinned).toBe(data.pinned);\n\t\texpect(instance.tts).toBe(data.tts);\n\t\texpect(instance.webhookId).toBe(data.webhook_id);\n\t\texpect(instance.type).toBe(MessageType.Reply);\n\t\texpect(instance.toJSON()).toEqual(data);\n\t});\n\n\ttest('Attachment sub-structure', () => {\n\t\tconst instances = data.attachments?.map((attachment) => new Attachment(attachment));\n\t\texpect(instances?.map((attachment) => attachment.toJSON())).toEqual(data.attachments);\n\t\texpect(instances?.[0]?.description).toBe(data.attachments?.[0]?.description);\n\t\texpect(instances?.[0]?.filename).toBe(data.attachments?.[0]?.filename);\n\t\texpect(instances?.[0]?.id).toBe(data.attachments?.[0]?.id);\n\t\texpect(instances?.[0]?.size).toBe(data.attachments?.[0]?.size);\n\t\texpect(instances?.[0]?.url).toBe(data.attachments?.[0]?.url);\n\t\texpect(instances?.[0]?.proxyURL).toBe(data.attachments?.[0]?.proxy_url);\n\t});\n\n\ttest('Component sub-structures', () => {\n\t\tconst containerInstance = new ContainerComponent(data.components?.[0] as APIContainerComponent);\n\t\texpect(containerInstance.toJSON()).toEqual(container);\n\t\texpect(containerInstance.type).toBe(container.type);\n\t\texpect(containerInstance.id).toBe(container.id);\n\t\texpect(containerInstance.spoiler).toBe(container.spoiler);\n\t});\n});\n"
  },
  {
    "path": "packages/structures/__tests__/mixinClasses.ts",
    "content": "import { Mixin } from '../src/Mixin.js';\nimport type { MixinTypes } from '../src/MixinTypes.d.ts';\nimport { Structure } from '../src/Structure.js';\nimport { kData, kMixinConstruct, kMixinToJSON, kPatch } from '../src/utils/symbols.js';\n\nexport interface APIData {\n\tbaseOptimize?: string;\n\tid: string;\n\tmixinOptimize?: string;\n\tproperty1?: number;\n\tproperty2?: boolean;\n}\n\nexport class Base<Omitted extends keyof APIData | '' = ''> extends Structure<APIData, Omitted> {\n\tpublic static override readonly DataTemplate = {\n\t\tset baseOptimize(_: unknown) {},\n\t};\n\n\tpublic baseOptimize: boolean | null = null;\n\n\tpublic constructor(data: APIData) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n\n\tpublic override [kPatch](data: Partial<APIData>) {\n\t\tsuper[kPatch](data);\n\t\treturn this;\n\t}\n\n\tpublic override optimizeData(data: Partial<APIData>) {\n\t\tif ('baseOptimize' in data) {\n\t\t\tthis.baseOptimize = Boolean(data.baseOptimize);\n\t\t}\n\t}\n\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\tpublic getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic override toJSON() {\n\t\tconst data = super.toJSON();\n\t\tif (this.baseOptimize) {\n\t\t\tdata.baseOptimize = String(this.baseOptimize);\n\t\t}\n\n\t\treturn data;\n\t}\n}\n\nexport interface MixinProperty1<Omitted extends keyof APIData | '' = ''> extends Base<Omitted> {\n\tmixinOptimize: boolean | null;\n}\nexport class MixinProperty1 {\n\tpublic static readonly DataTemplate = {\n\t\tset mixinOptimize(_: unknown) {},\n\t};\n\n\tpublic [kMixinConstruct]() {\n\t\tthis.mixinOptimize = null;\n\t}\n\n\tpublic optimizeData(data: Partial<APIData>) {\n\t\tif ('mixinOptimize' in data) {\n\t\t\tthis.mixinOptimize = Boolean(data.mixinOptimize);\n\t\t}\n\t}\n\n\tpublic get property1() {\n\t\treturn this[kData].property1;\n\t}\n\n\tpublic getProperty1() {\n\t\treturn this.property1;\n\t}\n\n\tprotected [kMixinToJSON](data: Partial<APIData>) {\n\t\tif (this.mixinOptimize) {\n\t\t\tdata.mixinOptimize = String(this.mixinOptimize);\n\t\t}\n\t}\n}\n\nexport interface MixinProperty2<Omitted extends keyof APIData | '' = ''> extends Base<Omitted> {\n\tconstructCalled: boolean;\n}\nexport class MixinProperty2 {\n\tpublic [kMixinConstruct]() {\n\t\tthis.constructCalled = true;\n\t}\n\n\tpublic get property2() {\n\t\treturn this[kData].property2;\n\t}\n\n\tpublic getProperty2() {\n\t\treturn this.property2;\n\t}\n}\n\nexport class ExtendedMixinProperty2 extends MixinProperty2 {\n\t// eslint-disable-next-line @typescript-eslint/class-literal-property-style\n\tpublic get isExtended() {\n\t\treturn true;\n\t}\n}\n\nexport interface Mixed extends MixinTypes<Base, [MixinProperty1, MixinProperty2]> {}\nexport class Mixed extends Base {\n\tpublic getProperties() {\n\t\treturn { property1: this.property1, property2: this.property2 };\n\t}\n}\n\nMixin(Mixed, [MixinProperty1, MixinProperty2]);\n\nexport interface MixedWithExtended extends MixinTypes<Base, [MixinProperty1, ExtendedMixinProperty2]> {}\nexport class MixedWithExtended extends Base {\n\tpublic getProperties() {\n\t\treturn {\n\t\t\tproperty1: this.property1,\n\t\t\tproperty2: this.property2,\n\t\t};\n\t}\n}\n\n// Intentionally don't directly mix Property 2\nMixin(MixedWithExtended, [MixinProperty1, ExtendedMixinProperty2]);\n"
  },
  {
    "path": "packages/structures/__tests__/types/Mixin.test-d.ts",
    "content": "import { expectTypeOf } from 'vitest';\nimport type { MixinTypes } from '../../src/MixinTypes.d.ts';\nimport type { kMixinConstruct } from '../../src/utils/symbols.js';\nimport type { MixinProperty1, Base, MixinProperty2 } from '../mixinClasses.js';\n\ndeclare const extendsNoOmit: Omit<MixinProperty1, keyof Base | typeof kMixinConstruct>;\ndeclare const extendsOmitProperty1: Omit<MixinProperty1<'property1'>, keyof Base | typeof kMixinConstruct>;\ndeclare const extendsBothNoOmit: Omit<MixinProperty1 & MixinProperty2, keyof Base | typeof kMixinConstruct>;\ndeclare const extendsBothOmitProperty1: Omit<\n\tMixinProperty1<'property1'> & MixinProperty2<'property1'>,\n\tkeyof Base | typeof kMixinConstruct\n>;\ndeclare const extendsBothOmitBoth: Omit<\n\tMixinProperty1<'property1'> & MixinProperty2<'property2'>,\n\tkeyof Base | typeof kMixinConstruct\n>;\n\nexpectTypeOf(extendsNoOmit).toEqualTypeOf<MixinTypes<Base, [MixinProperty1]>>();\nexpectTypeOf(extendsOmitProperty1).toEqualTypeOf<MixinTypes<Base<'property1'>, [MixinProperty1<'property1'>]>>();\nexpectTypeOf(extendsOmitProperty1).not.toEqualTypeOf<MixinTypes<Base, [MixinProperty1]>>();\nexpectTypeOf(extendsNoOmit).not.toEqualTypeOf<MixinTypes<Base<'property1'>, [MixinProperty1<'property1'>]>>();\n\nexpectTypeOf(extendsBothNoOmit).toEqualTypeOf<MixinTypes<Base, [MixinProperty1, MixinProperty2]>>();\n// Since MixinProperty2 doesn't utilize the type of property1 in kData, this works and is ok\nexpectTypeOf(extendsBothOmitProperty1).toEqualTypeOf<\n\tMixinTypes<Base<'property1'>, [MixinProperty1<'property1'>, MixinProperty2]>\n>();\nexpectTypeOf(extendsBothOmitProperty1).not.toEqualTypeOf<MixinTypes<Base, [MixinProperty1, MixinProperty2]>>();\n// Since MixinProperty2 doesn't utilize the type of property1 in kData, this works and is ok\nexpectTypeOf(extendsBothNoOmit).not.toEqualTypeOf<\n\tMixinTypes<Base<'property1'>, [MixinProperty1<'property1'>, MixinProperty2]>\n>();\n\n// Earlier mixins in the list must specify all properties because of the way merging works\nexpectTypeOf(extendsBothOmitBoth).toEqualTypeOf<\n\tMixinTypes<Base<'property1' | 'property2'>, [MixinProperty1<'property1' | 'property2'>, MixinProperty2<'property2'>]>\n>();\n\nexpectTypeOf<MixinTypes<Base<'property1'>, [MixinProperty1]>>().toBeNever();\n// @ts-expect-error Shouldn't be able to assign non identical omits\nexpectTypeOf<MixinTypes<Base, [MixinProperty1<'property1'>]>>()\n\t// Separate line so ts-expect-error doesn't match this ever\n\t.toBeNever();\n"
  },
  {
    "path": "packages/structures/__tests__/types/channels.test-d.ts",
    "content": "import type { ChannelType, GuildChannelType, GuildTextChannelType, ThreadChannelType } from 'discord-api-types/v10';\nimport { expectTypeOf } from 'vitest';\nimport type { Channel } from '../../src/channels/Channel.js';\n\ndeclare const channel: Channel;\n\nif (channel.isGuildBased()) {\n\texpectTypeOf(channel.guildId).toBeString();\n\texpectTypeOf(channel.type).toEqualTypeOf<GuildChannelType>();\n\n\tif (channel.isDMBased()) {\n\t\texpectTypeOf(channel).toBeNever();\n\t}\n\n\tif (channel.isPermissionCapable()) {\n\t\texpectTypeOf(channel.type).toEqualTypeOf<\n\t\t\tExclude<GuildChannelType, ChannelType.GuildDirectory | ThreadChannelType>\n\t\t>();\n\t}\n\n\tif (channel.isTextBased()) {\n\t\texpectTypeOf(channel.type).toEqualTypeOf<GuildTextChannelType>();\n\t}\n\n\tif (channel.isWebhookCapable()) {\n\t\texpectTypeOf(channel.type).toEqualTypeOf<\n\t\t\tChannelType.GuildForum | ChannelType.GuildMedia | Exclude<GuildTextChannelType, ThreadChannelType>\n\t\t>();\n\t}\n\n\tif (channel.isThread()) {\n\t\texpectTypeOf(channel.type).toEqualTypeOf<ThreadChannelType>();\n\t}\n\n\tif (channel.isThreadOnly()) {\n\t\texpectTypeOf(channel.type).toEqualTypeOf<ChannelType.GuildForum | ChannelType.GuildMedia>();\n\t}\n\n\tif (channel.isVoiceBased()) {\n\t\texpectTypeOf(channel.type).toEqualTypeOf<ChannelType.GuildStageVoice | ChannelType.GuildVoice>();\n\t\tif (!channel.isTextBased()) {\n\t\t\texpectTypeOf(channel).toBeNever();\n\t\t}\n\n\t\tif (!channel.isWebhookCapable()) {\n\t\t\texpectTypeOf(channel).toBeNever();\n\t\t}\n\t}\n}\n\nif (channel.isDMBased()) {\n\texpectTypeOf(channel.type).toEqualTypeOf<ChannelType.DM | ChannelType.GroupDM>();\n\n\tif (channel.isGuildBased()) {\n\t\texpectTypeOf(channel).toBeNever();\n\t}\n\n\tif (channel.isPermissionCapable()) {\n\t\texpectTypeOf(channel).toBeNever();\n\t}\n\n\tif (channel.isWebhookCapable()) {\n\t\texpectTypeOf(channel).toBeNever();\n\t}\n\n\tif (channel.isVoiceBased()) {\n\t\texpectTypeOf(channel).toBeNever();\n\t}\n\n\tif (channel.isThread()) {\n\t\texpectTypeOf(channel).toBeNever();\n\t}\n\n\tif (channel.isThreadOnly()) {\n\t\texpectTypeOf(channel).toBeNever();\n\t}\n\n\tif (channel.isTextBased()) {\n\t\texpectTypeOf(channel.type).toEqualTypeOf<ChannelType.DM | ChannelType.GroupDM>();\n\t}\n}\n"
  },
  {
    "path": "packages/structures/api-extractor.json",
    "content": "{\n\t\"extends\": \"../../api-extractor.json\",\n\t\"docModel\": {\n\t\t\"projectFolderUrl\": \"https://github.com/discordjs/discord.js/tree/main/packages/structures\"\n\t},\n\t\"compiler\": {\n\t\t\"overrideTsconfig\": {\n\t\t\t\"exclude\": [\"src/**/*.d.ts\"]\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/structures/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t\t{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length %}\\\n\t\\n### New Contributors\\n\n\t{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\\\n\t\t* @{{ contributor.username }} made their first contribution in #{{ contributor.pr_number }}\n\t{% endfor %}\\\n{% endif %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"@discordjs/structures@[0-9]*\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/structures/docs/README.md",
    "content": "## [View the documentation here.](https://discord.js.org/docs/packages/structures/main)\n"
  },
  {
    "path": "packages/structures/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/structures\",\n\t\"version\": \"0.1.0\",\n\t\"description\": \"Wrapper around Discord's structures\",\n\t\"scripts\": {\n\t\t\"build\": \"tsc --noEmit && tsup\",\n\t\t\"build:docs\": \"tsc -p tsconfig.docs.json && cpy \\\"./src/*.d.ts\\\" \\\"./dist-docs\\\"\",\n\t\t\"test\": \"vitest run --config ../../vitest.config.ts\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src\",\n\t\t\"fmt\": \"pnpm run format\",\n\t\t\"docs\": \"pnpm run build:docs && api-extractor run --local --minify && generate-split-documentation\",\n\t\t\"prepack\": \"pnpm run build && pnpm run lint\",\n\t\t\"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/structures/*'\",\n\t\t\"release\": \"cliff-jumper\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"main\": \"./dist/index.js\",\n\t\"module\": \"./dist/index.mjs\",\n\t\"types\": \"./dist/index.d.ts\",\n\t\"directories\": {\n\t\t\"lib\": \"src\",\n\t\t\"test\": \"__tests__\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\",\n\t\t\"Chai Kohen <chaikohen@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"discord\",\n\t\t\"api\",\n\t\t\"discordapp\",\n\t\t\"discordjs\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/structures\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"dependencies\": {\n\t\t\"@discordjs/formatters\": \"workspace:^\",\n\t\t\"@sapphire/snowflake\": \"^3.5.5\",\n\t\t\"discord-api-types\": \"^0.38.41\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@discordjs/api-extractor\": \"workspace:^\",\n\t\t\"@discordjs/scripts\": \"workspace:^\",\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@types/node\": \"^22.19.11\",\n\t\t\"@vitest/coverage-v8\": \"^4.0.18\",\n\t\t\"cpy-cli\": \"^6.0.0\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"esbuild-plugin-version-injector\": \"^1.2.1\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vitest\": \"^4.0.18\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/Mixin.ts",
    "content": "import { DataTemplatePropertyName, OptimizeDataPropertyName, type Structure } from './Structure.js';\nimport { kMixinConstruct, kMixinToJSON } from './utils/symbols.js';\n\nexport type Mixinable<ClassType> = new (...args: unknown[]) => ClassType;\n\nexport type MixinBase<BaseClass extends Structure<{}>> =\n\tBaseClass extends Structure<infer DataType, infer Omitted> ? Structure<DataType, Omitted> : never;\n\n/**\n * Copies the prototype (getters, setters, and methods) of all mixins to the destination class.\n * For type information see {@link MixinTypes}\n *\n * @param destination - The class to apply the mixins to, must extend the base that the mixins expect it to.\n * @param mixins - Classes that contain \"pure\" prototypes to be copied on top of the destination class prototype\n * @remarks All mixins should be \"pure\" in that they only contain getters, setters, and methods.\n * The runtime code will only copy these, and adding properties to the class only results\n * in the types of the mixed class being wrong.\n * @example\n * ```\n * // Interface merging on the mixin to give type access to props on the base and kData that are available once copied\n * interface TextMixin extends Channel {}\n * class TextMixin {\n * \t// Methods / getters\n * }\n *\n * // Interface merging on the mixed class to give it accurate type information within the declaration and when instantiated\n * interface TextChannel extends MixinTypes<Channel, [TextMixin]> {}\n * class TextChannel extends Channel {}\n *\n * // Apply for runtime\n * Mixin(TextChannel, [TextMixin])\n * ```\n * @typeParam DestinationClass - The class to be mixed, ensures that the mixins provided can be used with this destination\n */\nexport function Mixin<DestinationClass extends typeof Structure<{}>>(\n\tdestination: DestinationClass,\n\tmixins: Mixinable<MixinBase<DestinationClass['prototype']>>[],\n) {\n\tconst dataTemplates: Record<string, unknown>[] = [];\n\tconst dataOptimizations: ((data: unknown) => void)[] = [];\n\tconst enrichToJSONs: ((data: Partial<unknown>) => void)[] = [];\n\tconst constructors: ((data: Partial<unknown>) => void)[] = [];\n\n\tfor (const mixin of mixins) {\n\t\t// The entire prototype chain, in reverse order, since we want to copy it all\n\t\tconst prototypeChain: MixinBase<DestinationClass['prototype']>[] = [];\n\t\tlet extendedClass = mixin;\n\t\twhile (extendedClass.prototype !== undefined) {\n\t\t\tif (\n\t\t\t\tDataTemplatePropertyName in extendedClass &&\n\t\t\t\ttypeof extendedClass.DataTemplate === 'object' &&\n\t\t\t\t// eslint-disable-next-line no-eq-null, eqeqeq\n\t\t\t\textendedClass.DataTemplate != null\n\t\t\t) {\n\t\t\t\tdataTemplates.push(extendedClass.DataTemplate as Record<string, unknown>);\n\t\t\t}\n\n\t\t\tprototypeChain.unshift(extendedClass.prototype);\n\t\t\textendedClass = Object.getPrototypeOf(extendedClass);\n\t\t}\n\n\t\tfor (const prototype of prototypeChain) {\n\t\t\t// Symboled data isn't traversed by Object.entries, we can handle it here\n\t\t\tif (prototype[kMixinConstruct]) {\n\t\t\t\tconstructors.push(prototype[kMixinConstruct]);\n\t\t\t}\n\n\t\t\tif (prototype[kMixinToJSON]) {\n\t\t\t\tenrichToJSONs.push(prototype[kMixinToJSON]);\n\t\t\t}\n\n\t\t\t// Copy instance methods and setters / getters\n\t\t\tconst originalDescriptors = Object.getOwnPropertyDescriptors(prototype);\n\t\t\tconst usingDescriptors: { [prop: string]: PropertyDescriptor } = {};\n\t\t\tfor (const [prop, descriptor] of Object.entries(originalDescriptors)) {\n\t\t\t\t// Drop constructor\n\t\t\t\tif (['constructor'].includes(prop)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Special case for optimize function, we want to combine these\n\t\t\t\tif (prop === OptimizeDataPropertyName) {\n\t\t\t\t\tif (typeof descriptor.value !== 'function')\n\t\t\t\t\t\tthrow new RangeError(`Expected ${prop} to be a function, received ${typeof descriptor.value} instead.`);\n\t\t\t\t\tdataOptimizations.push(descriptor.value);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Shouldn't be anything other than these without being instantiated, but just in case\n\t\t\t\tif (\n\t\t\t\t\ttypeof descriptor.get !== 'undefined' ||\n\t\t\t\t\ttypeof descriptor.set !== 'undefined' ||\n\t\t\t\t\ttypeof descriptor.value === 'function'\n\t\t\t\t) {\n\t\t\t\t\tusingDescriptors[prop] = descriptor;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tObject.defineProperties(destination.prototype, usingDescriptors);\n\t\t}\n\t}\n\n\t// Set the function to call any mixed constructors\n\tif (constructors.length > 0) {\n\t\tObject.defineProperty(destination.prototype, kMixinConstruct, {\n\t\t\twritable: true,\n\t\t\tenumerable: false,\n\t\t\tconfigurable: true,\n\t\t\t// eslint-disable-next-line func-name-matching\n\t\t\tvalue: function _mixinConstructors(data: Partial<unknown>) {\n\t\t\t\tfor (const construct of constructors) {\n\t\t\t\t\tconstruct.call(this, data);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t}\n\n\t// Combine all optimizations into a single function\n\tconst baseOptimize = Object.getOwnPropertyDescriptor(destination, OptimizeDataPropertyName);\n\tif (baseOptimize && typeof baseOptimize.value === 'function') {\n\t\t// call base last (mimic constructor behavior)\n\t\tdataOptimizations.push(baseOptimize.value);\n\t}\n\n\tconst superOptimize = Object.getOwnPropertyDescriptor(\n\t\tObject.getPrototypeOf(destination).prototype,\n\t\tOptimizeDataPropertyName,\n\t);\n\t// the mixin base optimize should call super, so we can ignore the super in that case\n\tif (!baseOptimize && superOptimize && typeof superOptimize.value === 'function') {\n\t\t// call super first (mimic constructor behavior)\n\t\tdataOptimizations.unshift(superOptimize.value);\n\t}\n\n\t// If there's more than one optimization or if there's an optimization that isn't on the destination (base)\n\tif (dataOptimizations.length > 1 || (dataOptimizations.length === 1 && !baseOptimize)) {\n\t\tObject.defineProperty(destination.prototype, OptimizeDataPropertyName, {\n\t\t\twritable: true,\n\t\t\tenumerable: false,\n\t\t\tconfigurable: true,\n\t\t\t// eslint-disable-next-line func-name-matching\n\t\t\tvalue: function _mixinOptimizeData(data: unknown) {\n\t\t\t\tfor (const optimization of dataOptimizations) {\n\t\t\t\t\toptimization.call(this, data);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t}\n\n\tif (enrichToJSONs.length > 0) {\n\t\tObject.defineProperty(destination.prototype, kMixinToJSON, {\n\t\t\twritable: true,\n\t\t\tenumerable: false,\n\t\t\tconfigurable: true,\n\t\t\t// eslint-disable-next-line func-name-matching\n\t\t\tvalue: function _mixinToJSON(data: Partial<unknown>) {\n\t\t\t\tfor (const enricher of enrichToJSONs) {\n\t\t\t\t\tenricher.call(this, data);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t}\n\n\t// Copy the properties (setters) of each mixins template to the destinations template\n\tif (dataTemplates.length > 0) {\n\t\tif (!Object.getOwnPropertyDescriptor(destination, DataTemplatePropertyName)) {\n\t\t\tObject.defineProperty(destination, DataTemplatePropertyName, {\n\t\t\t\tvalue: Object.defineProperties({}, Object.getOwnPropertyDescriptors(destination[DataTemplatePropertyName])),\n\t\t\t\twritable: true,\n\t\t\t\tenumerable: true,\n\t\t\t\tconfigurable: true,\n\t\t\t});\n\t\t}\n\n\t\tfor (const template of dataTemplates) {\n\t\t\tObject.defineProperties(destination[DataTemplatePropertyName], Object.getOwnPropertyDescriptors(template));\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/MixinTypes.d.ts",
    "content": "import type { MixinBase } from './Mixin.js';\nimport type { Structure } from './Structure.js';\nimport type { kData, kMixinConstruct } from './utils/symbols.js';\nimport type { CollapseUnion, MergePrototypes } from './utils/types.js';\n\n/**\n * Type utility to provide accurate types for the runtime effects of {@link Mixin}\n *\n * @typeParam BaseClass - The class that is being directly extended, must match the class that the mixins are expecting\n * @typeParam Mixins - The mixins that will be applied to this class via a {@link Mixin} call\n */\nexport type MixinTypes<BaseClass extends Structure<{}>, Mixins extends readonly MixinBase<BaseClass>[]> = CollapseUnion<\n\tBaseClass extends Structure<infer DataType, infer Omitted>\n\t\t? Mixins[number] extends Structure<DataType, Omitted>\n\t\t\t? // prettier-ignore\n\t\t\t\tStructure<DataType, Omitted>[typeof kData] extends\n\t\t\t\t// @ts-expect-error kData is protected\n\t\t\t\tMixins[number][typeof kData]\n\t\t\t\t? Omit<MergePrototypes<Mixins>, keyof BaseClass | typeof kMixinConstruct>\n\t\t\t\t: never\n\t\t\t: never\n\t\t: never\n>;\n"
  },
  {
    "path": "packages/structures/src/Structure.ts",
    "content": "import { kClone, kData, kMixinConstruct, kMixinToJSON, kPatch } from './utils/symbols.js';\nimport type { ReplaceOmittedWithUnknown } from './utils/types.js';\n\nexport const DataTemplatePropertyName = 'DataTemplate';\nexport const OptimizeDataPropertyName = 'optimizeData';\n\n/**\n * Represents a data model from the Discord API\n *\n * @privateRemarks\n * Explanation of the type complexity surround Structure:\n *\n * There are two layers of Omitted generics, one here, which allows omitting things at the library level so we do not accidentally\n * access them, in addition to whatever the user does at the layer above.\n *\n * The second layer, in the exported structure is effectively a type cast that allows the getters types to match whatever data template is used\n *\n * In order to safely set and access this data, the constructor and patch take data as \"partial\" and forcibly assigns it to kData. To accommodate this,\n * kData stores properties as `unknown` when it is omitted, which allows accessing the property in getters even when it may not actually be present.\n * This is the most technically correct way of representing the value, especially since there is no way to guarantee runtime matches the \"type cast.\"\n */\nexport abstract class Structure<DataType extends {}, Omitted extends keyof DataType | '' = ''> {\n\t/**\n\t * A construct function used when mixing to allow mixins to set optimized property defaults\n\t *\n\t * @internal\n\t * @remarks This should only be used to set defaults, setting optimized values should be done\n\t * in the mixins `optimizeData` method, which will be called automatically.\n\t * @param data - The full API data received by the Structure\n\t */\n\tprotected [kMixinConstruct]?(data: Partial<DataType>): void;\n\n\t/**\n\t * A function used when mixing to allow mixins to add properties to the result of toJSON\n\t *\n\t * @internal\n\t * @remarks This should only be used to add properties that the mixin optimizes, if the raw\n\t * JSON data is unchanged the property will already be returned.\n\t * @param data - The result of the base class toJSON Structure before it gets returned\n\t */\n\tprotected [kMixinToJSON]?(data: Partial<DataType>): void;\n\n\t/**\n\t * The template used for removing data from the raw data stored for each Structure.\n\t *\n\t * @remarks This template should be overridden in all subclasses to provide more accurate type information.\n\t * The template in the base {@link Structure} class will have no effect on most subclasses for this reason.\n\t */\n\tprotected static readonly DataTemplate: Record<string, unknown> = {};\n\n\t/**\n\t * @returns A cloned version of the data template, ready to create a new data object.\n\t */\n\tprivate getDataTemplate() {\n\t\treturn Object.create((this.constructor as typeof Structure).DataTemplate);\n\t}\n\n\t/**\n\t * The raw data from the API for this structure\n\t *\n\t * @internal\n\t */\n\tprotected [kData]: Readonly<ReplaceOmittedWithUnknown<Omitted, DataType>>;\n\n\t/**\n\t * Creates a new structure to represent API data\n\t *\n\t * @param data - the data from the API that this structure will represent\n\t * @remarks To be made public in subclasses\n\t * @internal\n\t */\n\tpublic constructor(data: Readonly<Partial<DataType>>, ..._rest: unknown[]) {\n\t\tthis[kData] = Object.assign(this.getDataTemplate(), data);\n\t\tthis[kMixinConstruct]?.(data);\n\t}\n\n\t/**\n\t * Patches the raw data of this object in place\n\t *\n\t * @param data - the updated data from the API to patch with\n\t * @remarks To be made public in subclasses\n\t * @returns this\n\t * @internal\n\t */\n\tprotected [kPatch](data: Readonly<Partial<DataType>>): this {\n\t\tthis[kData] = Object.assign(this.getDataTemplate(), this[kData], data);\n\t\tthis.optimizeData(data);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Creates a clone of this structure\n\t *\n\t * @returns a clone of this\n\t * @internal\n\t */\n\tprotected [kClone](patchPayload?: Readonly<Partial<DataType>>): typeof this {\n\t\tconst clone = this.toJSON();\n\t\t// @ts-expect-error constructor is of abstract class is unknown\n\t\treturn new this.constructor(\n\t\t\t// Ensure the ts-expect-error only applies to the constructor call\n\t\t\tpatchPayload ? Object.assign(clone, patchPayload) : clone,\n\t\t);\n\t}\n\n\t/**\n\t * Function called to ensure stored raw data is in optimized formats, used in tandem with a data template\n\t *\n\t * @example created_timestamp is an ISO string, this can be stored in optimized form as a number\n\t * @param _data - the raw data received from the API to optimize\n\t * @remarks Implementation to be done in subclasses and mixins where needed.\n\t * For typescript users, mixins must use the closest ancestors access modifier.\n\t * @remarks Automatically called in Structure[kPatch] but must be called manually in the constructor\n\t * of any class implementing this method.\n\t * @remarks Additionally, when implementing, ensure to call `super._optimizeData` if any class in the super chain aside\n\t * from Structure contains an implementation.\n\t * Note: mixins do not need to call super ever as the process of mixing walks the prototype chain.\n\t * @virtual\n\t * @internal\n\t */\n\tprotected optimizeData(_data: Partial<DataType>) {}\n\n\t/**\n\t * Transforms this object to its JSON format with raw API data (or close to it),\n\t * automatically called by `JSON.stringify()` when this structure is stringified\n\t *\n\t * @remarks\n\t * The type of this data is determined by omissions at runtime and is only guaranteed for default omissions\n\t * @privateRemarks\n\t * When omitting properties at the library level, this must be overridden to re-add those properties\n\t */\n\tpublic toJSON(): DataType {\n\t\t// This will be DataType provided nothing is omitted, when omits occur, subclass needs to overwrite this.\n\t\tconst data =\n\t\t\t// Spread is way faster than structuredClone, but is shallow. So use it only if there is no nested objects\n\t\t\t(\n\t\t\t\tObject.values(this[kData]).some((value) => typeof value === 'object' && value !== null)\n\t\t\t\t\t? structuredClone(this[kData])\n\t\t\t\t\t: { ...this[kData] }\n\t\t\t) as DataType;\n\t\tthis[kMixinToJSON]?.(data);\n\t\treturn data;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/automoderation/AutoModerationRule.ts",
    "content": "import type { APIAutoModerationRule } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents an auto moderation rule on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has substructure `TriggerMetadata` which needs to be instantiated and stored by an extending class using it\n * @remarks intentionally does not export `exemptRoles` and `exemptChannels` so that extending classes can resolve `Snowflake[]` to `Role[]` and `Channel[]`, respectively\n */\nexport class AutoModerationRule<Omitted extends keyof APIAutoModerationRule | '' = ''> extends Structure<\n\tAPIAutoModerationRule,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each auto moderation rule\n\t */\n\tpublic static override DataTemplate: Partial<APIAutoModerationRule> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the auto moderation rule\n\t */\n\tpublic constructor(data: Partialize<APIAutoModerationRule, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id of this rule\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The id of the guild which this rule belongs to\n\t */\n\tpublic get guildId() {\n\t\treturn this[kData].guild_id;\n\t}\n\n\t/**\n\t * The rule name\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * The user who first created this rule\n\t */\n\tpublic get creatorId() {\n\t\treturn this[kData].creator_id;\n\t}\n\n\t/**\n\t * The rule event type\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-event-types}\n\t */\n\tpublic get eventType() {\n\t\treturn this[kData].event_type;\n\t}\n\n\t/**\n\t * The rule trigger type\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-types}\n\t */\n\tpublic get triggerType() {\n\t\treturn this[kData].trigger_type;\n\t}\n\n\t/**\n\t * Whether the rule is enabled\n\t */\n\tpublic get enabled() {\n\t\treturn this[kData].enabled;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/automoderation/AutoModerationRuleTriggerMetadata.ts",
    "content": "import type { APIAutoModerationRuleTriggerMetadata, AutoModerationRuleTriggerType } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents an auto moderation rule trigger metadata on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class AutoModerationRuleTriggerMetadata<\n\tOmitted extends keyof APIAutoModerationRuleTriggerMetadata | '' = '',\n> extends Structure<APIAutoModerationRuleTriggerMetadata, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each auto moderation rule trigger metadata\n\t */\n\tpublic static override DataTemplate: Partial<APIAutoModerationRuleTriggerMetadata> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the auto moderation rule trigger metadata\n\t */\n\tpublic constructor(data: Partialize<APIAutoModerationRuleTriggerMetadata, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * Substrings which will be searched for in content (Maximum of 1000)\n\t *\n\t * A keyword can be a phrase which contains multiple words.\n\t *\n\t * Wildcard symbols can be used to customize how each keyword will be matched. Each keyword must be 60 characters or less.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-keyword-matching-strategies | Keyword matching strategies}\n\t *\n\t * Associated trigger types: {@link AutoModerationRuleTriggerType.Keyword}, {@link AutoModerationRuleTriggerType.MemberProfile}\n\t */\n\tpublic get keywordFilter() {\n\t\treturn this[kData].keyword_filter;\n\t}\n\n\t/**\n\t * Regular expression patterns which will be matched against content (Maximum of 10)\n\t *\n\t * Only Rust flavored regex is currently supported, which can be tested in online editors such as {@link https://rustexp.lpil.uk/ | Rustexp}.\n\t *\n\t * Each regex pattern must be 260 characters or less.\n\t *\n\t * Associated trigger types: {@link AutoModerationRuleTriggerType.Keyword}, {@link AutoModerationRuleTriggerType.MemberProfile}\n\t */\n\tpublic get regexPatterns() {\n\t\treturn this[kData].regex_patterns;\n\t}\n\n\t/**\n\t * The internally pre-defined wordsets which will be searched for in content\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-keyword-preset-types | Keyword preset types}\n\t *\n\t * Associated trigger types: {@link AutoModerationRuleTriggerType.KeywordPreset}\n\t */\n\tpublic get presets() {\n\t\treturn this[kData].presets;\n\t}\n\n\t/**\n\t * Substrings which should not trigger the rule (Maximum of 100 or 1000).\n\t *\n\t * Wildcard symbols can be used to customize how each keyword will be matched (see Keyword matching strategies).\n\t *\n\t * Each `allow_list` keyword can be a phrase which contains multiple words.\n\t *\n\t * Rules with `KEYWORD` triggerType accept a maximum of 100 keywords.\n\t *\n\t * Rules with `KEYWORD_PRESET` triggerType accept a maximum of 1000 keywords.\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-types | triggerType}\n\t * @see {@link https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-keyword-matching-strategies | Keyword matching strategies}\n\t *\n\t * Associated trigger types: {@link AutoModerationRuleTriggerType.Keyword}, {@link AutoModerationRuleTriggerType.KeywordPreset}, {@link AutoModerationRuleTriggerType.MemberProfile}\n\t */\n\tpublic get allowList() {\n\t\treturn this[kData].allow_list;\n\t}\n\n\t/**\n\t * Total number of unique role and user mentions allowed per message (Maximum of 50)\n\t *\n\t * Associated trigger types: {@link AutoModerationRuleTriggerType.MentionSpam}\n\t */\n\tpublic get mentionTotalLimit() {\n\t\treturn this[kData].mention_total_limit;\n\t}\n\n\t/**\n\t * Whether to automatically detect mention raids\n\t *\n\t * Associated trigger types: {@link AutoModerationRuleTriggerType.MentionSpam}\n\t */\n\tpublic get mentionRaidProtectionEnabled() {\n\t\treturn this[kData].mention_raid_protection_enabled;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/automoderation/actions/AutoModerationAction.ts",
    "content": "import type { APIAutoModerationAction } from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\n/**\n * Represents an auto moderation action on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has substructure `ActionMetadata` which needs to be instantiated and stored by an extending class using it\n */\nexport class AutoModerationAction<Omitted extends keyof APIAutoModerationAction | '' = ''> extends Structure<\n\tAPIAutoModerationAction,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each auto moderation action\n\t */\n\tpublic static override DataTemplate: Partial<APIAutoModerationAction> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the auto moderation action\n\t */\n\tpublic constructor(data: Partialize<APIAutoModerationAction, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The action type\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-types}\n\t */\n\tpublic get type() {\n\t\treturn this[kData].type;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/automoderation/actions/AutoModerationActionMetadata.ts",
    "content": "import type {\n\tAPIAutoModerationActionMetadata,\n\tAutoModerationActionType,\n\tAutoModerationRuleTriggerType,\n} from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\n/**\n * Represents an auto moderation action metadata on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class AutoModerationActionMetadata<\n\tOmitted extends keyof APIAutoModerationActionMetadata | '' = '',\n> extends Structure<APIAutoModerationActionMetadata, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each auto moderation action metadata\n\t */\n\tpublic static override DataTemplate: Partial<APIAutoModerationActionMetadata> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the auto moderation action metadata\n\t */\n\tpublic constructor(data: Partialize<APIAutoModerationActionMetadata, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * Channel to which user content should be logged. This must be an existing channel\n\t *\n\t * Associated action types: {@link AutoModerationActionType.SendAlertMessage}\n\t */\n\tpublic get channelId() {\n\t\treturn this[kData].channel_id;\n\t}\n\n\t/**\n\t * Timeout duration in seconds. Maximum of 2419200 seconds (4 weeks).\n\t *\n\t * A `TIMEOUT` action can only be set up for {@link AutoModerationRuleTriggerType.Keyword} and {@link AutoModerationRuleTriggerType.MentionSpam}.\n\t *\n\t * The `MODERATE_MEMBERS` permission is required to use {@link AutoModerationActionType.Timeout} actions.\n\t *\n\t * Associated action types: {@link AutoModerationActionType.Timeout}\n\t */\n\tpublic get durationSeconds() {\n\t\treturn this[kData].duration_seconds;\n\t}\n\n\t/**\n\t * Additional explanation that will be shown to members whenever their message is blocked. Maximum of 150 characters\n\t *\n\t * Associated action types: {@link AutoModerationActionType.BlockMessage}\n\t */\n\tpublic get customMessage() {\n\t\treturn this[kData].custom_message;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/automoderation/actions/index.ts",
    "content": "export * from './AutoModerationAction.js';\nexport * from './AutoModerationActionMetadata.js';\n"
  },
  {
    "path": "packages/structures/src/automoderation/index.ts",
    "content": "export * from './actions/index.js';\n\nexport * from './AutoModerationRule.js';\nexport * from './AutoModerationRuleTriggerMetadata.js';\n"
  },
  {
    "path": "packages/structures/src/bitfields/AttachmentFlagsBitField.ts",
    "content": "import { AttachmentFlags } from 'discord-api-types/v10';\nimport { BitField } from './BitField.js';\n\n/**\n * Data structure that makes it easy to interact with a {@link Attachment#flags} bitfield.\n */\nexport class AttachmentFlagsBitField extends BitField<keyof typeof AttachmentFlags> {\n\t/**\n\t * Numeric attachment flags.\n\t */\n\tpublic static override readonly Flags = AttachmentFlags;\n\n\tpublic override toJSON() {\n\t\treturn super.toJSON(true);\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/bitfields/BitField.ts",
    "content": "import type { EnumLike, NonAbstract, RecursiveReadonlyArray } from '../utils/types.js';\n\n// TODO: this currently is mostly copied from mainlib discord.js v14 and definitely needs a refactor in a later iteration\n\n/**\n * Data that can be resolved to give a bit field. This can be:\n * A bit number (this can be a number literal or a value taken from {@link (BitField:class).Flags})\n * A string bit number\n * An instance of BitField\n * An Array of BitFieldResolvable\n */\nexport type BitFieldResolvable<Flags extends string> =\n\t| Flags\n\t| Readonly<BitField<Flags>>\n\t| RecursiveReadonlyArray<Flags | Readonly<BitField<Flags>> | bigint | number | `${bigint}`>\n\t| bigint\n\t| number\n\t| `${bigint}`;\n\n/**\n * Data structure that makes it easy to interact with a bit field.\n */\nexport abstract class BitField<Flags extends string> {\n\t/**\n\t * Numeric bit field flags.\n\t *\n\t * @remarks Defined in extension classes\n\t */\n\tpublic static readonly Flags: EnumLike<unknown, bigint | number> = {};\n\n\tpublic static readonly DefaultBit: bigint = 0n;\n\n\t/**\n\t * Bitfield of the packed bits\n\t */\n\tpublic bitField: bigint;\n\n\tdeclare public ['constructor']: NonAbstract<typeof BitField<Flags>>;\n\n\t/**\n\t * @param bits - Bit(s) to read from\n\t */\n\tpublic constructor(bits: BitFieldResolvable<Flags> = this.constructor.DefaultBit) {\n\t\tthis.bitField = this.constructor.resolve(bits);\n\t}\n\n\t/**\n\t * Checks whether the bit field has a bit, or any of multiple bits.\n\t *\n\t * @param bit - Bit(s) to check for\n\t * @returns Whether the bit field has the bit(s)\n\t */\n\tpublic any(bit: BitFieldResolvable<Flags>) {\n\t\treturn (this.bitField & this.constructor.resolve(bit)) !== this.constructor.DefaultBit;\n\t}\n\n\t/**\n\t * Checks if this bit field equals another\n\t *\n\t * @param bit - Bit(s) to check for\n\t * @returns Whether this bit field equals the other\n\t */\n\tpublic equals(bit: BitFieldResolvable<Flags>) {\n\t\treturn this.bitField === this.constructor.resolve(bit);\n\t}\n\n\t/**\n\t * Checks whether the bit field has a bit, or multiple bits.\n\t *\n\t * @param bit - Bit(s) to check for\n\t * @returns Whether the bit field has the bit(s)\n\t */\n\tpublic has(bit: BitFieldResolvable<Flags>, ..._hasParams: unknown[]) {\n\t\tconst resolvedBit = this.constructor.resolve(bit);\n\t\treturn (this.bitField & resolvedBit) === resolvedBit;\n\t}\n\n\t/**\n\t * Gets all given bits that are missing from the bit field.\n\t *\n\t * @param bits - Bit(s) to check for\n\t * @param hasParams -  Additional parameters for the has method, if any\n\t * @returns A bit field containing the missing bits\n\t */\n\tpublic missing(bits: BitFieldResolvable<Flags>, ...hasParams: readonly unknown[]) {\n\t\treturn new this.constructor(bits).remove(this).toArray(...hasParams);\n\t}\n\n\t/**\n\t * Freezes these bits, making them immutable.\n\t *\n\t * @returns This bit field but frozen\n\t */\n\tpublic freeze() {\n\t\treturn Object.freeze(this);\n\t}\n\n\t/**\n\t * Adds bits to these ones.\n\t *\n\t * @param bits - Bits to add\n\t * @returns These bits or new BitField if the instance is frozen.\n\t */\n\tpublic add(...bits: BitFieldResolvable<Flags>[]) {\n\t\tlet total = this.constructor.DefaultBit;\n\t\tfor (const bit of bits) {\n\t\t\ttotal |= this.constructor.resolve(bit);\n\t\t}\n\n\t\tif (Object.isFrozen(this)) return new this.constructor(this.bitField | total);\n\t\tthis.bitField |= total;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes bits from these.\n\t *\n\t * @param bits - Bits to remove\n\t * @returns These bits or new BitField if the instance is frozen.\n\t */\n\tpublic remove(...bits: BitFieldResolvable<Flags>[]) {\n\t\tlet total = this.constructor.DefaultBit;\n\t\tfor (const bit of bits) {\n\t\t\ttotal |= this.constructor.resolve(bit);\n\t\t}\n\n\t\tif (Object.isFrozen(this)) return new this.constructor(this.bitField & ~total);\n\t\tthis.bitField &= ~total;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets an object mapping field names to a boolean indicating whether the bit is available.\n\t *\n\t * @param hasParams - Additional parameters for the has method, if any\n\t * @returns An object mapping field names to a boolean indicating whether the bit is available\n\t */\n\tpublic serialize(...hasParams: readonly unknown[]) {\n\t\tconst serialized: Partial<Record<keyof Flags, boolean>> = {};\n\t\tfor (const [flag, bit] of Object.entries(this.constructor.Flags)) {\n\t\t\tif (Number.isNaN(Number(flag))) serialized[flag as keyof Flags] = this.has(bit as bigint | number, ...hasParams);\n\t\t}\n\n\t\treturn serialized;\n\t}\n\n\t/**\n\t * Gets an Array of bit field names based on the bits available.\n\t *\n\t * @param hasParams - Additional parameters for the has method, if any\n\t * @returns An Array of bit field names\n\t */\n\tpublic toArray(...hasParams: readonly unknown[]) {\n\t\treturn [...this[Symbol.iterator](...hasParams)];\n\t}\n\n\tpublic toJSON(asNumber?: boolean) {\n\t\tif (asNumber) {\n\t\t\tif (this.bitField > Number.MAX_SAFE_INTEGER) {\n\t\t\t\tthrow new RangeError(\n\t\t\t\t\t`Cannot convert bitfield value ${this.bitField} to number, as it is bigger than ${Number.MAX_SAFE_INTEGER} (the maximum safe integer)`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn Number(this.bitField);\n\t\t}\n\n\t\treturn this.bitField.toString();\n\t}\n\n\tpublic valueOf() {\n\t\treturn this.bitField;\n\t}\n\n\tpublic *[Symbol.iterator](...hasParams: unknown[]) {\n\t\tfor (const bitName of Object.keys(this.constructor.Flags)) {\n\t\t\tif (Number.isNaN(Number(bitName)) && this.has(bitName as Flags, ...hasParams)) yield bitName as Flags;\n\t\t}\n\t}\n\n\t/**\n\t * Resolves bit fields to their numeric form.\n\t *\n\t * @param bit - bit(s) to resolve\n\t * @returns the numeric value of the bit fields\n\t */\n\tpublic static resolve<Flags extends string = string>(bit: BitFieldResolvable<Flags>): bigint {\n\t\tconst DefaultBit = this.DefaultBit;\n\t\tif (typeof bit === 'bigint' && bit >= DefaultBit) return bit;\n\t\tif (typeof bit === 'number' && BigInt(bit) >= DefaultBit) return BigInt(bit);\n\t\tif (bit instanceof BitField) return bit.bitField;\n\t\tif (Array.isArray(bit)) {\n\t\t\treturn bit.map((bit_) => this.resolve(bit_)).reduce((prev, bit_) => prev | bit_, DefaultBit);\n\t\t}\n\n\t\tif (typeof bit === 'string') {\n\t\t\tif (!Number.isNaN(Number(bit))) return BigInt(bit);\n\t\t\tif (bit in this.Flags) return this.Flags[bit as keyof typeof this.Flags];\n\t\t}\n\n\t\tthrow new Error(`BitFieldInvalid: ${JSON.stringify(bit)}`);\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/bitfields/ChannelFlagsBitField.ts",
    "content": "import { ChannelFlags } from 'discord-api-types/v10';\nimport { BitField } from './BitField.js';\n\n/**\n * Data structure that makes it easy to interact with a {@link (Channel:class).flags} bitfield.\n */\nexport class ChannelFlagsBitField extends BitField<keyof typeof ChannelFlags> {\n\t/**\n\t * Numeric guild channel flags.\n\t */\n\tpublic static override readonly Flags = ChannelFlags;\n\n\tpublic override toJSON() {\n\t\treturn super.toJSON(true);\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/bitfields/MessageFlagsBitField.ts",
    "content": "import { MessageFlags } from 'discord-api-types/v10';\nimport { BitField } from './BitField.js';\n\n/**\n * Data structure that makes it easy to interact with a {@link Message#flags} bitfield.\n */\nexport class MessageFlagsBitField extends BitField<keyof typeof MessageFlags> {\n\t/**\n\t * Numeric message flags.\n\t */\n\tpublic static override readonly Flags = MessageFlags;\n\n\tpublic override toJSON() {\n\t\treturn super.toJSON(true);\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/bitfields/PermissionsBitField.ts",
    "content": "/* eslint-disable unicorn/consistent-function-scoping */\nimport { PermissionFlagsBits } from 'discord-api-types/v10';\nimport type { BitFieldResolvable } from './BitField.js';\nimport { BitField } from './BitField.js';\n\n/**\n * Data structure that makes it easy to interact with a permission bit field. All {@link GuildMember}s have a set of\n * permissions in their guild, and each channel in the guild may also have {@link PermissionOverwrite}s for the member\n * that override their default permissions.\n */\nexport class PermissionsBitField extends BitField<keyof typeof PermissionFlagsBits> {\n\t/**\n\t * Numeric permission flags.\n\t *\n\t * @see {@link https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags}\n\t */\n\tpublic static override Flags = PermissionFlagsBits;\n\n\t/**\n\t * Bit field representing every permission combined\n\t */\n\tpublic static readonly All = Object.values(PermissionFlagsBits).reduce((all, perm) => all | perm, 0n);\n\n\t/**\n\t * Bit field representing the default permissions for users\n\t */\n\tpublic static readonly Default = 104_324_673n;\n\n\t/**\n\t * Bit field representing the permissions required for moderators of stage channels\n\t */\n\tpublic static readonly StageModerator =\n\t\tPermissionFlagsBits.ManageChannels | PermissionFlagsBits.MuteMembers | PermissionFlagsBits.MoveMembers;\n\n\t/**\n\t * Gets all given bits that are missing from the bit field.\n\t *\n\t * @param bits - Bit(s) to check for\n\t * @param checkAdmin - Whether to allow the administrator permission to override\n\t * @returns A bit field containing the missing permissions\n\t */\n\tpublic override missing(bits: BitFieldResolvable<keyof typeof PermissionFlagsBits>, checkAdmin = true) {\n\t\treturn checkAdmin && this.has(PermissionFlagsBits.Administrator) ? [] : super.missing(bits);\n\t}\n\n\t/**\n\t * Checks whether the bit field has a permission, or any of multiple permissions.\n\t *\n\t * @param permission - Permission(s) to check for\n\t * @param checkAdmin - Whether to allow the administrator permission to override\n\t * @returns Whether the bit field has the permission(s)\n\t */\n\tpublic override any(permission: BitFieldResolvable<keyof typeof PermissionFlagsBits>, checkAdmin = true) {\n\t\treturn (checkAdmin && super.has(PermissionFlagsBits.Administrator)) || super.any(permission);\n\t}\n\n\t/**\n\t * Checks whether the bit field has a permission, or multiple permissions.\n\t *\n\t * @param permission - Permission(s) to check for\n\t * @param checkAdmin - Whether to allow the administrator permission to override\n\t * @returns Whether the bit field has the permission(s)\n\t */\n\tpublic override has(permission: BitFieldResolvable<keyof typeof PermissionFlagsBits>, checkAdmin = true) {\n\t\treturn (checkAdmin && super.has(PermissionFlagsBits.Administrator)) || super.has(permission);\n\t}\n\n\t/**\n\t * Gets an Array of bitfield names based on the permissions available.\n\t *\n\t * @returns An Array of permission names\n\t */\n\tpublic override toArray() {\n\t\treturn super.toArray(false);\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/bitfields/SKUFlagsBitField.ts",
    "content": "import { SKUFlags } from 'discord-api-types/v10';\nimport { BitField } from './BitField.js';\n\n/**\n * Data structure that makes it easy to interact with an {@link SKUFlags} bitfield.\n */\nexport class SKUFlagsBitField extends BitField<keyof typeof SKUFlags> {\n\t/**\n\t * Numeric SKU flags.\n\t */\n\tpublic static override readonly Flags = SKUFlags;\n\n\tpublic override toJSON() {\n\t\treturn super.toJSON(true);\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/bitfields/index.ts",
    "content": "export * from './BitField.js';\n\nexport * from './AttachmentFlagsBitField.js';\nexport * from './ChannelFlagsBitField.js';\nexport * from './MessageFlagsBitField.js';\nexport * from './PermissionsBitField.js';\nexport * from './SKUFlagsBitField.js';\n"
  },
  {
    "path": "packages/structures/src/channels/AnnouncementChannel.ts",
    "content": "import type { APINewsChannel, ChannelType } from 'discord-api-types/v10';\nimport { Mixin } from '../Mixin.js';\nimport type { MixinTypes } from '../MixinTypes.d.ts';\nimport type { Partialize } from '../utils/types.js';\nimport { Channel } from './Channel.js';\nimport { ChannelParentMixin } from './mixins/ChannelParentMixin.js';\nimport { ChannelPermissionMixin } from './mixins/ChannelPermissionMixin.js';\nimport { ChannelPinMixin } from './mixins/ChannelPinMixin.js';\nimport { ChannelSlowmodeMixin } from './mixins/ChannelSlowmodeMixin.js';\nimport { ChannelTopicMixin } from './mixins/ChannelTopicMixin.js';\nimport { TextChannelMixin } from './mixins/TextChannelMixin.js';\n\nexport interface AnnouncementChannel<Omitted extends keyof APINewsChannel | '' = ''> extends MixinTypes<\n\tChannel<ChannelType.GuildAnnouncement>,\n\t[\n\t\tTextChannelMixin<ChannelType.GuildAnnouncement>,\n\t\tChannelParentMixin<ChannelType.GuildAnnouncement>,\n\t\tChannelPermissionMixin<ChannelType.GuildAnnouncement>,\n\t\tChannelPinMixin<ChannelType.GuildAnnouncement>,\n\t\tChannelSlowmodeMixin<ChannelType.GuildAnnouncement>,\n\t\tChannelTopicMixin<ChannelType.GuildAnnouncement>,\n\t]\n> {}\n\n/**\n * Sample Implementation of a structure for announcement channels, usable by direct end consumers.\n */\nexport class AnnouncementChannel<Omitted extends keyof APINewsChannel | '' = ''> extends Channel<\n\tChannelType.GuildAnnouncement,\n\tOmitted\n> {\n\tpublic constructor(data: Partialize<APINewsChannel, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n}\n\nMixin(AnnouncementChannel, [\n\tTextChannelMixin,\n\tChannelParentMixin,\n\tChannelPermissionMixin,\n\tChannelPinMixin,\n\tChannelSlowmodeMixin,\n\tChannelTopicMixin,\n]);\n"
  },
  {
    "path": "packages/structures/src/channels/AnnouncementThreadChannel.ts",
    "content": "import type { APIAnnouncementThreadChannel, ChannelType } from 'discord-api-types/v10';\nimport { Mixin } from '../Mixin.js';\nimport type { MixinTypes } from '../MixinTypes.d.ts';\nimport type { Partialize } from '../utils/types.js';\nimport { Channel } from './Channel.js';\nimport { ChannelOwnerMixin } from './mixins/ChannelOwnerMixin.js';\nimport { ChannelParentMixin } from './mixins/ChannelParentMixin.js';\nimport { ChannelPinMixin } from './mixins/ChannelPinMixin.js';\nimport { ChannelSlowmodeMixin } from './mixins/ChannelSlowmodeMixin.js';\nimport { GuildChannelMixin } from './mixins/GuildChannelMixin.js';\nimport { TextChannelMixin } from './mixins/TextChannelMixin.js';\nimport { ThreadChannelMixin } from './mixins/ThreadChannelMixin.js';\n\nexport interface AnnouncementThreadChannel<\n\tOmitted extends keyof APIAnnouncementThreadChannel | '' = '',\n> extends MixinTypes<\n\tChannel<ChannelType.AnnouncementThread>,\n\t[\n\t\tTextChannelMixin<ChannelType.AnnouncementThread>,\n\t\tChannelOwnerMixin<ChannelType.AnnouncementThread>,\n\t\tChannelParentMixin<ChannelType.AnnouncementThread>,\n\t\tChannelPinMixin<ChannelType.AnnouncementThread>,\n\t\tChannelSlowmodeMixin<ChannelType.AnnouncementThread>,\n\t\tGuildChannelMixin<ChannelType.AnnouncementThread>,\n\t\tThreadChannelMixin<ChannelType.AnnouncementThread>,\n\t]\n> {}\n\n/**\n * Sample Implementation of a structure for announcement threads, usable by direct end consumers.\n */\nexport class AnnouncementThreadChannel<Omitted extends keyof APIAnnouncementThreadChannel | '' = ''> extends Channel<\n\tChannelType.AnnouncementThread,\n\tOmitted\n> {\n\tpublic constructor(data: Partialize<APIAnnouncementThreadChannel, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData?.(data);\n\t}\n}\n\nMixin(AnnouncementThreadChannel, [\n\tTextChannelMixin,\n\tChannelOwnerMixin,\n\tChannelParentMixin,\n\tChannelPinMixin,\n\tChannelSlowmodeMixin,\n\tGuildChannelMixin,\n\tThreadChannelMixin,\n]);\n"
  },
  {
    "path": "packages/structures/src/channels/CategoryChannel.ts",
    "content": "import type { APIGuildCategoryChannel, ChannelType } from 'discord-api-types/v10';\nimport { Mixin } from '../Mixin.js';\nimport type { MixinTypes } from '../MixinTypes.d.ts';\nimport type { Partialize } from '../utils/types.js';\nimport { Channel } from './Channel.js';\nimport { ChannelPermissionMixin } from './mixins/ChannelPermissionMixin.js';\nimport { GuildChannelMixin } from './mixins/GuildChannelMixin.js';\n\nexport interface CategoryChannel<Omitted extends keyof APIGuildCategoryChannel | '' = ''> extends MixinTypes<\n\tChannel<ChannelType.GuildCategory>,\n\t[ChannelPermissionMixin<ChannelType.GuildCategory>, GuildChannelMixin<ChannelType.GuildCategory>]\n> {}\n\n/**\n * Sample Implementation of a structure for category channels, usable by direct end consumers.\n */\nexport class CategoryChannel<Omitted extends keyof APIGuildCategoryChannel | '' = ''> extends Channel<\n\tChannelType.GuildCategory,\n\tOmitted\n> {\n\tpublic constructor(data: Partialize<APIGuildCategoryChannel, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n}\n\nMixin(CategoryChannel, [ChannelPermissionMixin, GuildChannelMixin]);\n"
  },
  {
    "path": "packages/structures/src/channels/Channel.ts",
    "content": "import { DiscordSnowflake } from '@sapphire/snowflake';\nimport type { APIChannel, APIPartialChannel, ChannelType, ChannelFlags } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { ChannelFlagsBitField } from '../bitfields/ChannelFlagsBitField.js';\nimport { kData } from '../utils/symbols.js';\nimport { isFieldSet, isIdSet } from '../utils/type-guards.js';\nimport type { Partialize } from '../utils/types.js';\nimport type { ChannelPermissionMixin } from './mixins/ChannelPermissionMixin.js';\nimport type { ChannelWebhookMixin } from './mixins/ChannelWebhookMixin.js';\nimport type { DMChannelMixin } from './mixins/DMChannelMixin.js';\nimport type { GuildChannelMixin } from './mixins/GuildChannelMixin.js';\nimport type { TextChannelMixin } from './mixins/TextChannelMixin.js';\nimport type { ThreadChannelMixin } from './mixins/ThreadChannelMixin.js';\nimport type { ThreadOnlyChannelMixin } from './mixins/ThreadOnlyChannelMixin.js';\nimport type { VoiceChannelMixin } from './mixins/VoiceChannelMixin.js';\n\nexport type PartialChannel = Channel<ChannelType, Exclude<keyof APIChannel, keyof APIPartialChannel>>;\n\n/**\n * The data stored by a {@link Channel} structure based on its {@link (Channel:class).\"type\"} property.\n */\nexport type ChannelDataType<Type extends ChannelType | 'unknown'> = Type extends ChannelType\n\t? Extract<APIChannel, { type: Type }>\n\t: APIPartialChannel;\n\n/**\n * Represents any channel on Discord.\n *\n * @typeParam Type - Specify the type of the channel being constructed for more accurate data types\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks Although this class _can_ be instantiated directly for any channel type,\n * it's intended to be subclassed with the appropriate mixins for each channel type.\n */\nexport class Channel<\n\tType extends ChannelType | 'unknown' = ChannelType,\n\tOmitted extends keyof ChannelDataType<Type> | '' = '',\n> extends Structure<ChannelDataType<Type>, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each Channel.\n\t *\n\t * @remarks This template is only guaranteed to apply to channels constructed directly via `new Channel()`.\n\t * Use the appropriate subclass template to remove data from that channel type.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIChannel> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the channel\n\t */\n\tpublic constructor(data: Partialize<ChannelDataType<Type>, Omitted>) {\n\t\tsuper(data as ChannelDataType<Type>);\n\t}\n\n\t/**\n\t * The id of the channel\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The type of the channel\n\t */\n\tpublic get type() {\n\t\t// This cast can be incorrect when type is omitted and if the wrong type of channel was constructed\n\t\treturn this[kData].type as Type extends 'unknown' ? number : Type;\n\t}\n\n\t/**\n\t * The name of the channel, null for DMs\n\t *\n\t * @privateRemarks The type of `name` can be narrowed in Guild Channels and DM channels to string and null respectively,\n\t * respecting Omit behaviors\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * The flags that are applied to the channel.\n\t *\n\t * @privateRemarks The type of `flags` can be narrowed in Guild Channels and DMChannel to ChannelFlags, and in GroupDM channel\n\t * to null, respecting Omit behaviors\n\t */\n\tpublic get flags() {\n\t\treturn isFieldSet(this[kData], 'flags', 'number')\n\t\t\t? new ChannelFlagsBitField(this[kData].flags as ChannelFlags)\n\t\t\t: null;\n\t}\n\n\t/**\n\t * The timestamp the channel was created at\n\t */\n\tpublic get createdTimestamp() {\n\t\treturn isIdSet(this.id) ? DiscordSnowflake.timestampFrom(this.id) : null;\n\t}\n\n\t/**\n\t * The time the channel was created at\n\t */\n\tpublic get createdAt() {\n\t\tconst createdTimestamp = this.createdTimestamp;\n\t\treturn createdTimestamp ? new Date(createdTimestamp) : null;\n\t}\n\n\t/**\n\t * Indicates whether this channel is a thread channel\n\t *\n\t * @privateRemarks Overridden to `true` on `ThreadChannelMixin`\n\t */\n\tpublic isThread(): this is ThreadChannelMixin & this {\n\t\treturn false;\n\t}\n\n\t/**\n\t * Indicates whether this channel can contain messages\n\t *\n\t * @privateRemarks Overridden to `true` on `TextChannelMixin`\n\t */\n\tpublic isTextBased(): this is TextChannelMixin & this {\n\t\treturn false;\n\t}\n\n\t/**\n\t * Indicates whether this channel is in a guild\n\t *\n\t * @privateRemarks Overridden to `true` on `GuildChannelMixin`\n\t */\n\tpublic isGuildBased(): this is GuildChannelMixin & this {\n\t\treturn false;\n\t}\n\n\t/**\n\t * Indicates whether this channel is a DM or DM Group\n\t *\n\t * @privateRemarks Overridden to `true` on `DMChannelMixin`\n\t */\n\tpublic isDMBased(): this is DMChannelMixin & this {\n\t\treturn false;\n\t}\n\n\t/**\n\t * Indicates whether this channel has voice connection capabilities\n\t *\n\t * @privateRemarks Overridden to `true` on `VoiceChannelMixin`\n\t */\n\tpublic isVoiceBased(): this is VoiceChannelMixin & this {\n\t\treturn false;\n\t}\n\n\t/**\n\t * Indicates whether this channel only allows thread creation\n\t *\n\t * @privateRemarks Overridden to `true` on `ThreadOnlyChannelMixin`\n\t */\n\tpublic isThreadOnly(): this is ThreadOnlyChannelMixin & this {\n\t\treturn false;\n\t}\n\n\t/**\n\t * Indicates whether this channel can have permission overwrites\n\t *\n\t * @privateRemarks Overridden to `true` on `ChannelPermissionsMixin`\n\t */\n\tpublic isPermissionCapable(): this is ChannelPermissionMixin & this {\n\t\treturn false;\n\t}\n\n\t/**\n\t * Indicates whether this channel can have webhooks\n\t *\n\t * @privateRemarks Overridden to `true` on `ChannelWebhooksMixin`\n\t */\n\tpublic isWebhookCapable(): this is ChannelWebhookMixin & this {\n\t\treturn false;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/DMChannel.ts",
    "content": "import type { APIDMChannel, ChannelType } from 'discord-api-types/v10';\nimport { Mixin } from '../Mixin.js';\nimport type { MixinTypes } from '../MixinTypes.d.ts';\nimport type { Partialize } from '../utils/types.js';\nimport { Channel } from './Channel.js';\nimport { ChannelPinMixin } from './mixins/ChannelPinMixin.js';\nimport { DMChannelMixin } from './mixins/DMChannelMixin.js';\nimport { TextChannelMixin } from './mixins/TextChannelMixin.js';\n\nexport interface DMChannel<Omitted extends keyof APIDMChannel | '' = ''> extends MixinTypes<\n\tChannel<ChannelType.DM>,\n\t[DMChannelMixin<ChannelType.DM>, TextChannelMixin<ChannelType.DM>, ChannelPinMixin<ChannelType.DM>]\n> {}\n\n/**\n * Sample Implementation of a structure for dm channels, usable by direct end consumers.\n */\nexport class DMChannel<Omitted extends keyof APIDMChannel | '' = ''> extends Channel<ChannelType.DM, Omitted> {\n\tpublic constructor(data: Partialize<APIDMChannel, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n}\n\nMixin(DMChannel, [DMChannelMixin, TextChannelMixin, ChannelPinMixin]);\n"
  },
  {
    "path": "packages/structures/src/channels/ForumChannel.ts",
    "content": "import type { APIGuildForumChannel, ChannelType } from 'discord-api-types/v10';\nimport { Mixin } from '../Mixin.js';\nimport type { MixinTypes } from '../MixinTypes.d.ts';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\nimport { Channel } from './Channel.js';\nimport { ChannelParentMixin } from './mixins/ChannelParentMixin.js';\nimport { ChannelPermissionMixin } from './mixins/ChannelPermissionMixin.js';\nimport { ChannelTopicMixin } from './mixins/ChannelTopicMixin.js';\nimport { ThreadOnlyChannelMixin } from './mixins/ThreadOnlyChannelMixin.js';\n\nexport interface ForumChannel<Omitted extends keyof APIGuildForumChannel | '' = ''> extends MixinTypes<\n\tChannel<ChannelType.GuildForum>,\n\t[\n\t\tChannelParentMixin<ChannelType.GuildForum>,\n\t\tChannelPermissionMixin<ChannelType.GuildForum>,\n\t\tChannelTopicMixin<ChannelType.GuildForum>,\n\t\tThreadOnlyChannelMixin<ChannelType.GuildForum>,\n\t]\n> {}\n\n/**\n * Sample Implementation of a structure for forum channels, usable by direct end consumers.\n */\nexport class ForumChannel<Omitted extends keyof APIGuildForumChannel | '' = ''> extends Channel<\n\tChannelType.GuildForum,\n\tOmitted\n> {\n\tpublic constructor(data: Partialize<APIGuildForumChannel, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n\n\t/**\n\t * The default forum layout view used to display posts in this channel.\n\t * Defaults to 0, which indicates a layout view has not been set by a channel admin.\n\t */\n\tpublic get defaultForumLayout() {\n\t\treturn this[kData].default_forum_layout;\n\t}\n}\n\nMixin(ForumChannel, [ChannelParentMixin, ChannelPermissionMixin, ChannelTopicMixin, ThreadOnlyChannelMixin]);\n"
  },
  {
    "path": "packages/structures/src/channels/ForumTag.ts",
    "content": "import type { APIGuildForumTag } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents metadata of a thread channel on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class ForumTag<Omitted extends keyof APIGuildForumTag | '' = ''> extends Structure<APIGuildForumTag, Omitted> {\n\tpublic constructor(data: Partialize<APIGuildForumTag, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id of the tag.\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The name of the tag.\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * Whether this tag can only be added to or removed from threads by a member with the {@link discord-api-types/v10#(PermissionFlagsBits:variable) | ManageThreads} permission.\n\t */\n\tpublic get moderated() {\n\t\treturn this[kData].moderated;\n\t}\n\n\t/**\n\t * The id of a guild's custom emoji.\n\t */\n\tpublic get emojiId() {\n\t\treturn this[kData].emoji_id;\n\t}\n\n\t/**\n\t * The unicode character of the emoji.\n\t */\n\tpublic get emojiName() {\n\t\treturn this[kData].emoji_name;\n\t}\n\n\t/**\n\t * The textual representation of this tag's emoji. Either a unicode character or a guild emoji mention.\n\t */\n\tpublic get emoji() {\n\t\treturn this.emojiName ?? `<:_:${this.emojiId}>`;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/GroupDMChannel.ts",
    "content": "import type { APIGroupDMChannel, ChannelType } from 'discord-api-types/v10';\nimport { Mixin } from '../Mixin.js';\nimport type { MixinTypes } from '../MixinTypes.d.ts';\nimport type { Partialize } from '../utils/types.js';\nimport { Channel } from './Channel.js';\nimport { ChannelOwnerMixin } from './mixins/ChannelOwnerMixin.js';\nimport { DMChannelMixin } from './mixins/DMChannelMixin.js';\nimport { GroupDMMixin } from './mixins/GroupDMMixin.js';\nimport { TextChannelMixin } from './mixins/TextChannelMixin.js';\n\nexport interface GroupDMChannel<Omitted extends keyof APIGroupDMChannel | '' = ''> extends MixinTypes<\n\tChannel<ChannelType.GroupDM>,\n\t[\n\t\tDMChannelMixin<ChannelType.GroupDM>,\n\t\tTextChannelMixin<ChannelType.GroupDM>,\n\t\tChannelOwnerMixin<ChannelType.GroupDM>,\n\t\tGroupDMMixin,\n\t]\n> {}\n\n/**\n * Sample Implementation of a structure for group dm channels, usable by direct end consumers.\n */\nexport class GroupDMChannel<Omitted extends keyof APIGroupDMChannel | '' = ''> extends Channel<\n\tChannelType.GroupDM,\n\tOmitted\n> {\n\tpublic constructor(data: Partialize<APIGroupDMChannel, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n}\n\nMixin(GroupDMChannel, [DMChannelMixin, TextChannelMixin, ChannelOwnerMixin, GroupDMMixin]);\n"
  },
  {
    "path": "packages/structures/src/channels/MediaChannel.ts",
    "content": "import type { APIGuildMediaChannel, ChannelType } from 'discord-api-types/v10';\nimport { Mixin } from '../Mixin.js';\nimport type { MixinTypes } from '../MixinTypes.d.ts';\nimport type { Partialize } from '../utils/types.js';\nimport { Channel } from './Channel.js';\nimport { ChannelParentMixin } from './mixins/ChannelParentMixin.js';\nimport { ChannelPermissionMixin } from './mixins/ChannelPermissionMixin.js';\nimport { ChannelTopicMixin } from './mixins/ChannelTopicMixin.js';\nimport { ThreadOnlyChannelMixin } from './mixins/ThreadOnlyChannelMixin.js';\n\nexport interface MediaChannel<Omitted extends keyof APIGuildMediaChannel | '' = ''> extends MixinTypes<\n\tChannel<ChannelType.GuildMedia>,\n\t[\n\t\tChannelParentMixin<ChannelType.GuildMedia>,\n\t\tChannelPermissionMixin<ChannelType.GuildMedia>,\n\t\tChannelTopicMixin<ChannelType.GuildMedia>,\n\t\tThreadOnlyChannelMixin<ChannelType.GuildMedia>,\n\t]\n> {}\n\n/**\n * Sample Implementation of a structure for media channels, usable by direct end consumers.\n */\nexport class MediaChannel<Omitted extends keyof APIGuildMediaChannel | '' = ''> extends Channel<\n\tChannelType.GuildMedia,\n\tOmitted\n> {\n\tpublic constructor(data: Partialize<APIGuildMediaChannel, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n}\n\nMixin(MediaChannel, [ChannelParentMixin, ChannelPermissionMixin, ChannelTopicMixin, ThreadOnlyChannelMixin]);\n"
  },
  {
    "path": "packages/structures/src/channels/PermissionOverwrite.ts",
    "content": "import type { APIOverwrite } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { PermissionsBitField } from '../bitfields/PermissionsBitField.js';\nimport { kAllow, kData, kDeny } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents metadata of a thread channel on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class PermissionOverwrite<Omitted extends keyof APIOverwrite | '' = 'allow' | 'deny'> extends Structure<\n\tAPIOverwrite,\n\tOmitted\n> {\n\tprotected [kAllow]: bigint | null = null;\n\n\tprotected [kDeny]: bigint | null = null;\n\n\tpublic constructor(data: Partialize<APIOverwrite, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n\n\t/**\n\t * The template used for removing data from the raw data stored for each ThreadMetadata\n\t *\n\t * @remarks This template has defaults, if you want to remove additional data and keep the defaults,\n\t * use `Object.defineProperties`. To override the defaults, set this value directly.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIOverwrite> = {\n\t\tset allow(_: string) {},\n\t\tset deny(_: string) {},\n\t};\n\n\t/**\n\t * {@inheritDoc Structure.optimizeData}\n\t */\n\tprotected override optimizeData(data: Partial<APIOverwrite>) {\n\t\tif (data.allow) {\n\t\t\tthis[kAllow] = BigInt(data.allow);\n\t\t}\n\n\t\tif (data.deny) {\n\t\t\tthis[kDeny] = BigInt(data.deny);\n\t\t}\n\t}\n\n\t/**\n\t * The permission bit set allowed by this overwrite.\n\t */\n\tpublic get allow() {\n\t\tconst allow = this[kAllow];\n\t\treturn typeof allow === 'bigint' ? new PermissionsBitField(allow) : null;\n\t}\n\n\t/**\n\t * The permission bit set denied by this overwrite.\n\t */\n\tpublic get deny() {\n\t\tconst deny = this[kDeny];\n\t\treturn typeof deny === 'bigint' ? new PermissionsBitField(deny) : null;\n\t}\n\n\t/**\n\t * The role or user id for this overwrite.\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The type of this overwrite.\n\t */\n\tpublic get type() {\n\t\treturn this[kData].type;\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.toJSON}\n\t */\n\tpublic override toJSON() {\n\t\tconst clone = super.toJSON();\n\t\tif (this[kAllow]) {\n\t\t\tclone.allow = this[kAllow].toString();\n\t\t}\n\n\t\tif (this[kDeny]) {\n\t\t\tclone.deny = this[kDeny].toString();\n\t\t}\n\n\t\treturn clone;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/PrivateThreadChannel.ts",
    "content": "import type { APIPrivateThreadChannel, ChannelType } from 'discord-api-types/v10';\nimport { Mixin } from '../Mixin.js';\nimport type { MixinTypes } from '../MixinTypes.d.ts';\nimport type { Partialize } from '../utils/types.js';\nimport { Channel } from './Channel.js';\nimport { ChannelOwnerMixin } from './mixins/ChannelOwnerMixin.js';\nimport { ChannelParentMixin } from './mixins/ChannelParentMixin.js';\nimport { ChannelPinMixin } from './mixins/ChannelPinMixin.js';\nimport { ChannelSlowmodeMixin } from './mixins/ChannelSlowmodeMixin.js';\nimport { TextChannelMixin } from './mixins/TextChannelMixin.js';\nimport { ThreadChannelMixin } from './mixins/ThreadChannelMixin.js';\n\nexport interface PrivateThreadChannel<Omitted extends keyof APIPrivateThreadChannel | '' = ''> extends MixinTypes<\n\tChannel<ChannelType.PrivateThread>,\n\t[\n\t\tTextChannelMixin<ChannelType.PrivateThread>,\n\t\tChannelOwnerMixin<ChannelType.PrivateThread>,\n\t\tChannelParentMixin<ChannelType.PrivateThread>,\n\t\tChannelPinMixin<ChannelType.PrivateThread>,\n\t\tChannelSlowmodeMixin<ChannelType.PrivateThread>,\n\t\tThreadChannelMixin<ChannelType.PrivateThread>,\n\t]\n> {}\n\n/**\n * Sample Implementation of a structure for private thread channels, usable by direct end consumers.\n */\nexport class PrivateThreadChannel<Omitted extends keyof APIPrivateThreadChannel | '' = ''> extends Channel<\n\tChannelType.PrivateThread,\n\tOmitted\n> {\n\tpublic constructor(data: Partialize<APIPrivateThreadChannel, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n}\n\nMixin(PrivateThreadChannel, [\n\tTextChannelMixin,\n\tChannelOwnerMixin,\n\tChannelParentMixin,\n\tChannelPinMixin,\n\tChannelSlowmodeMixin,\n\tThreadChannelMixin,\n]);\n"
  },
  {
    "path": "packages/structures/src/channels/PublicThreadChannel.ts",
    "content": "import type { APIPublicThreadChannel, ChannelType } from 'discord-api-types/v10';\nimport { Mixin } from '../Mixin.js';\nimport type { MixinTypes } from '../MixinTypes.d.ts';\nimport type { Partialize } from '../utils/types.js';\nimport { Channel } from './Channel.js';\nimport { AppliedTagsMixin } from './mixins/AppliedTagsMixin.js';\nimport { ChannelOwnerMixin } from './mixins/ChannelOwnerMixin.js';\nimport { ChannelParentMixin } from './mixins/ChannelParentMixin.js';\nimport { ChannelPinMixin } from './mixins/ChannelPinMixin.js';\nimport { ChannelSlowmodeMixin } from './mixins/ChannelSlowmodeMixin.js';\nimport { TextChannelMixin } from './mixins/TextChannelMixin.js';\nimport { ThreadChannelMixin } from './mixins/ThreadChannelMixin.js';\n\nexport interface PublicThreadChannel<Omitted extends keyof APIPublicThreadChannel | '' = ''> extends MixinTypes<\n\tChannel<ChannelType.PublicThread>,\n\t[\n\t\tTextChannelMixin<ChannelType.PublicThread>,\n\t\tChannelOwnerMixin<ChannelType.PublicThread>,\n\t\tChannelParentMixin<ChannelType.PublicThread>,\n\t\tChannelPinMixin<ChannelType.PublicThread>,\n\t\tChannelSlowmodeMixin<ChannelType.PublicThread>,\n\t\tThreadChannelMixin<ChannelType.PublicThread>,\n\t\tAppliedTagsMixin,\n\t]\n> {}\n\n/**\n * Sample Implementation of a structure for public thread channels, usable by direct end consumers.\n */\nexport class PublicThreadChannel<Omitted extends keyof APIPublicThreadChannel | '' = ''> extends Channel<\n\tChannelType.PublicThread,\n\tOmitted\n> {\n\tpublic constructor(data: Partialize<APIPublicThreadChannel, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n}\n\nMixin(PublicThreadChannel, [\n\tTextChannelMixin,\n\tChannelOwnerMixin,\n\tChannelParentMixin,\n\tChannelPinMixin,\n\tChannelSlowmodeMixin,\n\tThreadChannelMixin,\n\tAppliedTagsMixin,\n]);\n"
  },
  {
    "path": "packages/structures/src/channels/StageChannel.ts",
    "content": "import type { APIGuildStageVoiceChannel, ChannelType } from 'discord-api-types/v10';\nimport { Mixin } from '../Mixin.js';\nimport type { MixinTypes } from '../MixinTypes.d.ts';\nimport type { Partialize } from '../utils/types.js';\nimport { Channel } from './Channel.js';\nimport { ChannelParentMixin } from './mixins/ChannelParentMixin.js';\nimport { ChannelPermissionMixin } from './mixins/ChannelPermissionMixin.js';\nimport { ChannelSlowmodeMixin } from './mixins/ChannelSlowmodeMixin.js';\nimport { ChannelWebhookMixin } from './mixins/ChannelWebhookMixin.js';\nimport { VoiceChannelMixin } from './mixins/VoiceChannelMixin.js';\n\nexport interface StageChannel<Omitted extends keyof APIGuildStageVoiceChannel | '' = ''> extends MixinTypes<\n\tChannel<ChannelType.GuildStageVoice>,\n\t[\n\t\tChannelParentMixin<ChannelType.GuildStageVoice>,\n\t\tChannelPermissionMixin<ChannelType.GuildStageVoice>,\n\t\tChannelSlowmodeMixin<ChannelType.GuildStageVoice>,\n\t\tChannelWebhookMixin<ChannelType.GuildStageVoice>,\n\t\tVoiceChannelMixin<ChannelType.GuildStageVoice>,\n\t]\n> {}\n\nexport class StageChannel<Omitted extends keyof APIGuildStageVoiceChannel | '' = ''> extends Channel<\n\tChannelType.GuildStageVoice,\n\tOmitted\n> {\n\tpublic constructor(data: Partialize<APIGuildStageVoiceChannel, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n}\n\nMixin(StageChannel, [\n\tChannelParentMixin,\n\tChannelPermissionMixin,\n\tChannelSlowmodeMixin,\n\tChannelWebhookMixin,\n\tVoiceChannelMixin,\n]);\n"
  },
  {
    "path": "packages/structures/src/channels/TextChannel.ts",
    "content": "import type { APITextChannel, ChannelType } from 'discord-api-types/v10';\nimport { Mixin } from '../Mixin.js';\nimport type { MixinTypes } from '../MixinTypes.d.ts';\nimport type { Partialize } from '../utils/types.js';\nimport { Channel } from './Channel.js';\nimport { ChannelParentMixin } from './mixins/ChannelParentMixin.js';\nimport { ChannelPermissionMixin } from './mixins/ChannelPermissionMixin.js';\nimport { ChannelPinMixin } from './mixins/ChannelPinMixin.js';\nimport { ChannelSlowmodeMixin } from './mixins/ChannelSlowmodeMixin.js';\nimport { ChannelTopicMixin } from './mixins/ChannelTopicMixin.js';\nimport { TextChannelMixin } from './mixins/TextChannelMixin.js';\n\nexport interface TextChannel<Omitted extends keyof APITextChannel | '' = ''> extends MixinTypes<\n\tChannel<ChannelType.GuildText>,\n\t[\n\t\tTextChannelMixin<ChannelType.GuildText>,\n\t\tChannelParentMixin<ChannelType.GuildText>,\n\t\tChannelPermissionMixin<ChannelType.GuildText>,\n\t\tChannelPinMixin<ChannelType.GuildText>,\n\t\tChannelSlowmodeMixin<ChannelType.GuildText>,\n\t\tChannelTopicMixin<ChannelType.GuildText>,\n\t]\n> {}\n\nexport class TextChannel<Omitted extends keyof APITextChannel | '' = ''> extends Channel<\n\tChannelType.GuildText,\n\tOmitted\n> {\n\tpublic constructor(data: Partialize<APITextChannel, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n}\n\nMixin(TextChannel, [\n\tTextChannelMixin,\n\tChannelParentMixin,\n\tChannelPermissionMixin,\n\tChannelPinMixin,\n\tChannelSlowmodeMixin,\n\tChannelTopicMixin,\n]);\n"
  },
  {
    "path": "packages/structures/src/channels/ThreadMetadata.ts",
    "content": "import type { APIThreadMetadata } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kArchiveTimestamp, kCreatedTimestamp, kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents metadata of a thread channel on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class ThreadMetadata<\n\tOmitted extends keyof APIThreadMetadata | '' = 'archive_timestamp' | 'create_timestamp',\n> extends Structure<APIThreadMetadata, Omitted> {\n\tprotected [kArchiveTimestamp]: number | null = null;\n\n\tprotected [kCreatedTimestamp]: number | null = null;\n\n\tpublic constructor(data: Partialize<APIThreadMetadata, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n\n\t/**\n\t * The template used for removing data from the raw data stored for each ThreadMetadata\n\t *\n\t * @remarks This template has defaults, if you want to remove additional data and keep the defaults,\n\t * use `Object.defineProperties`. To override the defaults, set this value directly.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIThreadMetadata> = {\n\t\tset create_timestamp(_: string) {},\n\t\tset archive_timestamp(_: string) {},\n\t};\n\n\t/**\n\t * {@inheritDoc Structure.optimizeData}\n\t */\n\tprotected override optimizeData(data: Partial<APIThreadMetadata>) {\n\t\tif (data.create_timestamp) {\n\t\t\tthis[kCreatedTimestamp] = Date.parse(data.create_timestamp);\n\t\t}\n\n\t\tif (data.archive_timestamp) {\n\t\t\tthis[kArchiveTimestamp] = Date.parse(data.archive_timestamp);\n\t\t}\n\t}\n\n\t/**\n\t * Whether the thread is archived.\n\t */\n\tpublic get archived() {\n\t\treturn this[kData].archived;\n\t}\n\n\t/**\n\t * The timestamp when the thread's archive status was last changed, used for calculating recent activity.\n\t */\n\tpublic get archivedTimestamp() {\n\t\treturn this[kArchiveTimestamp];\n\t}\n\n\t/**\n\t * The timestamp when the thread was created; only populated for threads created after 2022-01-09.\n\t */\n\tpublic get createdTimestamp() {\n\t\treturn this[kCreatedTimestamp];\n\t}\n\n\t/**\n\t * The thread will stop showing in the channel list after auto_archive_duration minutes of inactivity,\n\t */\n\tpublic get autoArchiveDuration() {\n\t\treturn this[kData].auto_archive_duration;\n\t}\n\n\t/**\n\t * Whether non-moderators can add other non-moderators to a thread; only available on private threads.\n\t */\n\tpublic get invitable() {\n\t\treturn this[kData].invitable;\n\t}\n\n\t/**\n\t * Whether the thread is locked; when a thread is locked, only users with {@link discord-api-types/v10#(PermissionFlagsBits:variable) | ManageThreads} can unarchive it.\n\t */\n\tpublic get locked() {\n\t\treturn this[kData].locked;\n\t}\n\n\t/**\n\t * The time the thread was archived at\n\t */\n\tpublic get archivedAt() {\n\t\tconst archivedTimestamp = this.archivedTimestamp;\n\t\treturn archivedTimestamp ? new Date(archivedTimestamp) : null;\n\t}\n\n\t/**\n\t * The time the thread was created at\n\t */\n\tpublic get createdAt() {\n\t\tconst createdTimestamp = this.createdTimestamp;\n\t\treturn createdTimestamp ? new Date(createdTimestamp) : null;\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.toJSON}\n\t */\n\tpublic override toJSON() {\n\t\tconst data = super.toJSON();\n\t\tif (this[kArchiveTimestamp]) {\n\t\t\tdata.archive_timestamp = new Date(this[kArchiveTimestamp]).toISOString();\n\t\t}\n\n\t\tif (this[kCreatedTimestamp]) {\n\t\t\tdata.create_timestamp = new Date(this[kCreatedTimestamp]).toISOString();\n\t\t}\n\n\t\treturn data;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/VoiceChannel.ts",
    "content": "import type { APIGuildVoiceChannel, ChannelType } from 'discord-api-types/v10';\nimport { Mixin } from '../Mixin.js';\nimport type { MixinTypes } from '../MixinTypes.d.ts';\nimport type { Partialize } from '../utils/types.js';\nimport { Channel } from './Channel.js';\nimport { ChannelParentMixin } from './mixins/ChannelParentMixin.js';\nimport { ChannelPermissionMixin } from './mixins/ChannelPermissionMixin.js';\nimport { ChannelSlowmodeMixin } from './mixins/ChannelSlowmodeMixin.js';\nimport { ChannelWebhookMixin } from './mixins/ChannelWebhookMixin.js';\nimport { VoiceChannelMixin } from './mixins/VoiceChannelMixin.js';\n\nexport interface VoiceChannel<Omitted extends keyof APIGuildVoiceChannel | '' = ''> extends MixinTypes<\n\tChannel<ChannelType.GuildVoice>,\n\t[\n\t\tChannelParentMixin<ChannelType.GuildVoice>,\n\t\tChannelPermissionMixin<ChannelType.GuildVoice>,\n\t\tChannelSlowmodeMixin<ChannelType.GuildVoice>,\n\t\tChannelWebhookMixin<ChannelType.GuildVoice>,\n\t\tVoiceChannelMixin<ChannelType.GuildVoice>,\n\t]\n> {}\n\nexport class VoiceChannel<Omitted extends keyof APIGuildVoiceChannel | '' = ''> extends Channel<\n\tChannelType.GuildVoice,\n\tOmitted\n> {\n\tpublic constructor(data: Partialize<APIGuildVoiceChannel, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n}\n\nMixin(VoiceChannel, [\n\tChannelParentMixin,\n\tChannelPermissionMixin,\n\tChannelSlowmodeMixin,\n\tChannelWebhookMixin,\n\tVoiceChannelMixin,\n]);\n"
  },
  {
    "path": "packages/structures/src/channels/index.ts",
    "content": "export * from './mixins/index.js';\n\nexport * from './ForumTag.js';\nexport * from './PermissionOverwrite.js';\nexport * from './ThreadMetadata.js';\n\nexport * from './Channel.js';\n\nexport * from './AnnouncementChannel.js';\nexport * from './AnnouncementThreadChannel.js';\nexport * from './CategoryChannel.js';\n// export * from './DirectoryChannel.js';\nexport * from './DMChannel.js';\nexport * from './ForumChannel.js';\nexport * from './GroupDMChannel.js';\nexport * from './MediaChannel.js';\nexport * from './PrivateThreadChannel.js';\nexport * from './PublicThreadChannel.js';\nexport * from './StageChannel.js';\nexport * from './TextChannel.js';\nexport * from './VoiceChannel.js';\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/AppliedTagsMixin.ts",
    "content": "import type { ChannelType } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Channel } from '../Channel.js';\n\nexport interface AppliedTagsMixin extends Channel<ChannelType.PublicThread> {}\n\nexport class AppliedTagsMixin {\n\t/**\n\t * The ids of the set of tags that have been applied to a thread in a {@link (ForumChannel:class)} or a {@link (MediaChannel:class)}.\n\t */\n\tpublic get appliedTags(): readonly string[] | null {\n\t\treturn Array.isArray(this[kData].applied_tags) ? this[kData].applied_tags : null;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/ChannelOwnerMixin.ts",
    "content": "import type { ChannelType, ThreadChannelType } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Channel } from '../Channel.js';\n\nexport interface ChannelOwnerMixin<Type extends ChannelType.GroupDM | ThreadChannelType> extends Channel<Type> {}\n\nexport class ChannelOwnerMixin<Type extends ChannelType.GroupDM | ThreadChannelType> {\n\t/**\n\t * The id of the creator of the group DM or thread\n\t */\n\tpublic get ownerId() {\n\t\treturn this[kData].owner_id;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/ChannelParentMixin.ts",
    "content": "import type { ChannelType, GuildChannelType } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport { GuildChannelMixin } from './GuildChannelMixin.js';\n\nexport class ChannelParentMixin<\n\tType extends Exclude<GuildChannelType, ChannelType.GuildCategory | ChannelType.GuildDirectory>,\n> extends GuildChannelMixin<Type> {\n\t/**\n\t * The id of the parent category for a channel (each parent category can contain up to 50 channels) or id of the parent channel for a thread\n\t */\n\tpublic get parentId() {\n\t\treturn this[kData].parent_id;\n\t}\n\n\t/**\n\t * Whether the channel is nsfw\n\t */\n\tpublic get nsfw() {\n\t\treturn this[kData].nsfw;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/ChannelPermissionMixin.ts",
    "content": "import type { ChannelType, GuildChannelType, ThreadChannelType } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Channel } from '../Channel.js';\n\nexport interface ChannelPermissionMixin<\n\tType extends Exclude<GuildChannelType, ChannelType.GuildDirectory | ThreadChannelType> = Exclude<\n\t\tGuildChannelType,\n\t\tChannelType.GuildDirectory | ThreadChannelType\n\t>,\n> extends Channel<Type> {}\n\n/**\n * @remarks has an array of sub-structures {@link PermissionOverwrite} that extending mixins should add to their DataTemplate and _optimizeData\n */\nexport class ChannelPermissionMixin<\n\tType extends Exclude<GuildChannelType, ChannelType.GuildDirectory | ThreadChannelType> = Exclude<\n\t\tGuildChannelType,\n\t\tChannelType.GuildDirectory | ThreadChannelType\n\t>,\n> {\n\t/**\n\t * The sorting position of the channel\n\t */\n\tpublic get position() {\n\t\treturn this[kData].position;\n\t}\n\n\t/**\n\t * Indicates whether this channel can have permission overwrites\n\t */\n\tpublic isPermissionCapable(): this is ChannelPermissionMixin & this {\n\t\treturn true;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/ChannelPinMixin.ts",
    "content": "import type { ChannelType, ThreadChannelType } from 'discord-api-types/v10';\nimport { kLastPinTimestamp, kMixinConstruct, kMixinToJSON } from '../../utils/symbols.js';\nimport type { Channel, ChannelDataType } from '../Channel.js';\n\nexport interface ChannelPinMixin<\n\tType extends ChannelType.DM | ChannelType.GuildAnnouncement | ChannelType.GuildText | ThreadChannelType,\n> extends Channel<Type> {}\n\nexport class ChannelPinMixin<\n\tType extends ChannelType.DM | ChannelType.GuildAnnouncement | ChannelType.GuildText | ThreadChannelType,\n> {\n\t/**\n\t * The timestamp of when the last pin in the channel happened\n\t */\n\tdeclare protected [kLastPinTimestamp]: number | null;\n\n\t/**\n\t * The template used for removing data from the raw data stored for each Channel.\n\t */\n\tpublic static readonly DataTemplate: Partial<\n\t\tChannelDataType<ChannelType.DM | ChannelType.GuildAnnouncement | ChannelType.GuildText | ThreadChannelType>\n\t> = {\n\t\tset last_pin_timestamp(_: string) {},\n\t};\n\n\tpublic [kMixinConstruct]() {\n\t\tthis[kLastPinTimestamp] ??= null;\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.optimizeData}\n\t */\n\tprotected optimizeData(data: Partial<ChannelDataType<Type>>) {\n\t\tif (data.last_pin_timestamp) {\n\t\t\tthis[kLastPinTimestamp] = Date.parse(data.last_pin_timestamp);\n\t\t}\n\t}\n\n\t/**\n\t * The timestamp of when the last pin in the channel happened.\n\t */\n\tpublic get lastPinTimestamp() {\n\t\treturn this[kLastPinTimestamp];\n\t}\n\n\t/**\n\t * The Date of when the last pin in the channel happened\n\t */\n\tpublic get lastPinAt() {\n\t\tconst lastPinTimestamp = this.lastPinTimestamp;\n\t\treturn lastPinTimestamp ? new Date(lastPinTimestamp) : null;\n\t}\n\n\t/**\n\t * Adds data from optimized properties omitted from [kData].\n\t *\n\t * @param data - the result of {@link (Structure:class).toJSON}\n\t */\n\tprotected [kMixinToJSON](data: Partial<ChannelDataType<Type>>) {\n\t\tdata.last_pin_timestamp = this[kLastPinTimestamp] ? new Date(this[kLastPinTimestamp]).toISOString() : null;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/ChannelSlowmodeMixin.ts",
    "content": "import type { GuildTextChannelType } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport { TextChannelMixin } from './TextChannelMixin.js';\n\nexport class ChannelSlowmodeMixin<Type extends GuildTextChannelType> extends TextChannelMixin<Type> {\n\t/**\n\t * The rate limit per user (slowmode) of this channel.\n\t */\n\tpublic get rateLimitPerUser() {\n\t\treturn this[kData].rate_limit_per_user;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/ChannelTopicMixin.ts",
    "content": "import type { ChannelType } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Channel } from '../Channel.js';\nimport { ChannelWebhookMixin } from './ChannelWebhookMixin.js';\n\nexport interface ChannelTopicMixin<\n\tType extends ChannelType.GuildAnnouncement | ChannelType.GuildForum | ChannelType.GuildMedia | ChannelType.GuildText,\n> extends Channel<Type> {}\n\nexport class ChannelTopicMixin<\n\tType extends ChannelType.GuildAnnouncement | ChannelType.GuildForum | ChannelType.GuildMedia | ChannelType.GuildText,\n> extends ChannelWebhookMixin<Type> {\n\t/**\n\t * The topic of this channel.\n\t */\n\tpublic get topic() {\n\t\treturn this[kData].topic;\n\t}\n\n\t/**\n\t * The duration after which new threads get archived by default on this channel.\n\t */\n\tpublic get defaultAutoArchiveDuration() {\n\t\treturn this[kData].default_auto_archive_duration;\n\t}\n\n\t/**\n\t * The default value for rate limit per user (slowmode) on new threads in this channel.\n\t */\n\tpublic get defaultThreadRateLimitPerUser() {\n\t\treturn this[kData].default_thread_rate_limit_per_user;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/ChannelWebhookMixin.ts",
    "content": "import type { ChannelType, GuildTextChannelType, ThreadChannelType } from 'discord-api-types/v10';\nimport type { Channel } from '../Channel.js';\n\nexport interface ChannelWebhookMixin<\n\tType extends ChannelType.GuildForum | ChannelType.GuildMedia | Exclude<GuildTextChannelType, ThreadChannelType> =\n\t\t| ChannelType.GuildForum\n\t\t| ChannelType.GuildMedia\n\t\t| Exclude<GuildTextChannelType, ThreadChannelType>,\n> extends Channel<Type> {}\n\nexport class ChannelWebhookMixin<\n\tType extends ChannelType.GuildForum | ChannelType.GuildMedia | Exclude<GuildTextChannelType, ThreadChannelType> =\n\t\t| ChannelType.GuildForum\n\t\t| ChannelType.GuildMedia\n\t\t| Exclude<GuildTextChannelType, ThreadChannelType>,\n> {\n\t/**\n\t * Indicates whether this channel can have webhooks\n\t */\n\tpublic isWebhookCapable(): this is ChannelWebhookMixin & this {\n\t\treturn true;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/DMChannelMixin.ts",
    "content": "import { channelLink } from '@discordjs/formatters';\nimport type { ChannelType } from 'discord-api-types/v10';\nimport type { User } from '../../users/User.js';\nimport type { Channel } from '../Channel.js';\n\nexport interface DMChannelMixin<\n\tType extends ChannelType.DM | ChannelType.GroupDM = ChannelType.DM | ChannelType.GroupDM,\n> extends Channel<Type> {}\n\n/**\n * @remarks has recipients, an array of sub-structures {@link User} that extending mixins should add to their DataTemplate and _optimizeData\n */\nexport class DMChannelMixin<Type extends ChannelType.DM | ChannelType.GroupDM = ChannelType.DM | ChannelType.GroupDM> {\n\t/**\n\t * The URL to this channel.\n\t */\n\tpublic get url() {\n\t\treturn channelLink(this.id);\n\t}\n\n\t/**\n\t * Indicates whether this channel is a DM or DM Group\n\t */\n\tpublic isDMBased(): this is DMChannelMixin & this {\n\t\treturn true;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/GroupDMMixin.ts",
    "content": "import type { ChannelType } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Channel } from '../Channel.js';\n\nexport interface GroupDMMixin extends Channel<ChannelType.GroupDM> {}\n\nexport class GroupDMMixin {\n\t/**\n\t * The icon hash of the group DM.\n\t */\n\tpublic get icon() {\n\t\treturn this[kData].icon;\n\t}\n\n\t/**\n\t * Whether the channel is managed by an application via the `gdm.join` OAuth2 scope.\n\t */\n\tpublic get managed() {\n\t\treturn this[kData].managed;\n\t}\n\n\t/**\n\t * The application id of the group DM creator if it is bot-created.\n\t */\n\tpublic get applicationId() {\n\t\treturn this[kData].application_id;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/GuildChannelMixin.ts",
    "content": "import { channelLink } from '@discordjs/formatters';\nimport type { GuildChannelType } from 'discord-api-types/v10';\nimport { ChannelFlagsBitField } from '../../bitfields/ChannelFlagsBitField.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Channel } from '../Channel.js';\n\nexport interface GuildChannelMixin<Type extends GuildChannelType = GuildChannelType> extends Channel<Type> {}\n\nexport class GuildChannelMixin<Type extends GuildChannelType = GuildChannelType> {\n\t/**\n\t * The flags that are applied to the channel.\n\t *\n\t * @privateRemarks The type of `flags` can be narrowed in Guild Channels and DMChannel to ChannelFlags, and in GroupDM channel\n\t * to null, respecting Omit behaviors\n\t */\n\tpublic get flags() {\n\t\treturn this[kData].flags ? new ChannelFlagsBitField(this[kData].flags) : null;\n\t}\n\n\t/**\n\t * THe id of the guild this channel is in.\n\t */\n\tpublic get guildId() {\n\t\treturn this[kData].guild_id!;\n\t}\n\n\t/**\n\t * The URL to this channel.\n\t */\n\tpublic get url() {\n\t\treturn channelLink(this.id, this.guildId);\n\t}\n\n\t/**\n\t * Indicates whether this channel is in a guild\n\t */\n\tpublic isGuildBased(): this is GuildChannelMixin & this {\n\t\treturn true;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/TextChannelMixin.ts",
    "content": "import type { TextChannelType } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Channel } from '../Channel.js';\n\nexport interface TextChannelMixin<Type extends TextChannelType = TextChannelType> extends Channel<Type> {}\n\nexport class TextChannelMixin<Type extends TextChannelType = TextChannelType> {\n\t/**\n\t * The id of the last message sent in this channel.\n\t */\n\tpublic get lastMessageId() {\n\t\treturn this[kData].last_message_id;\n\t}\n\n\t/**\n\t * Indicates whether this channel can contain messages\n\t */\n\tpublic isTextBased(): this is TextChannelMixin & this {\n\t\treturn true;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/ThreadChannelMixin.ts",
    "content": "import type { ThreadChannelType } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Channel } from '../Channel.js';\n\nexport interface ThreadChannelMixin<Type extends ThreadChannelType = ThreadChannelType> extends Channel<Type> {}\n\n/**\n * @remarks has a sub-structure {@link ThreadMetadata} that extending mixins should add to their DataTemplate and _optimizeData\n */\nexport class ThreadChannelMixin<Type extends ThreadChannelType = ThreadChannelType> {\n\t/**\n\t * The approximate count of users in a thread, stops counting at 50\n\t */\n\tpublic get memberCount() {\n\t\treturn this[kData].member_count;\n\t}\n\n\t/**\n\t * The number of messages (not including the initial message or deleted messages) in a thread.\n\t */\n\tpublic get messageCount() {\n\t\treturn this[kData].message_count;\n\t}\n\n\t/**\n\t * The number of messages ever sent in a thread, it's similar to message_count on message creation,\n\t * but will not decrement the number when a message is deleted.\n\t */\n\tpublic get totalMessageSent() {\n\t\treturn this[kData].total_message_sent;\n\t}\n\n\t/**\n\t * Indicates whether this channel is a thread channel\n\t */\n\tpublic isThread(): this is ThreadChannelMixin & this {\n\t\treturn true;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/ThreadOnlyChannelMixin.ts",
    "content": "import type { ChannelType } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Channel } from '../Channel.js';\n\nexport interface ThreadOnlyChannelMixin<\n\tType extends ChannelType.GuildForum | ChannelType.GuildMedia = ChannelType.GuildForum | ChannelType.GuildMedia,\n> extends Channel<Type> {}\n\n/**\n * @remarks has an array of sub-structures {@link ForumTag} that extending mixins should add to their DataTemplate and _optimizeData\n */\nexport class ThreadOnlyChannelMixin<\n\tType extends ChannelType.GuildForum | ChannelType.GuildMedia = ChannelType.GuildForum | ChannelType.GuildMedia,\n> {\n\t/**\n\t * The emoji to show in the add reaction button on a thread in this channel.\n\t */\n\tpublic get defaultReactionEmoji() {\n\t\treturn this[kData].default_reaction_emoji;\n\t}\n\n\t/**\n\t * The default sort order type used to order posts in this channel.\n\t *\n\t * @defaultValue `null` – indicates a preferred sort order hasn't been set.\n\t */\n\tpublic get defaultSortOrder() {\n\t\treturn this[kData].default_sort_order!;\n\t}\n\n\t/**\n\t * Indicates whether this channel only allows thread creation\n\t */\n\tpublic isThreadOnly(): this is ThreadOnlyChannelMixin & this {\n\t\treturn true;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/VoiceChannelMixin.ts",
    "content": "import type { ChannelType } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Channel } from '../Channel.js';\nimport { TextChannelMixin } from './TextChannelMixin.js';\n\nexport interface VoiceChannelMixin<\n\tType extends ChannelType.GuildStageVoice | ChannelType.GuildVoice =\n\t\t| ChannelType.GuildStageVoice\n\t\t| ChannelType.GuildVoice,\n> extends Channel<Type> {}\n\nexport class VoiceChannelMixin<\n\tType extends ChannelType.GuildStageVoice | ChannelType.GuildVoice =\n\t\t| ChannelType.GuildStageVoice\n\t\t| ChannelType.GuildVoice,\n> extends TextChannelMixin<Type> {\n\t/**\n\t * The bitrate (in bits) of the voice channel.\n\t */\n\tpublic get bitrate() {\n\t\treturn this[kData].bitrate!;\n\t}\n\n\t/**\n\t * The voice region id for this channel, automatic when set to null.\n\t */\n\tpublic get rtcRegion() {\n\t\treturn this[kData].rtc_region!;\n\t}\n\n\t/**\n\t * The camera video quality mode of the voice channel, {@link discord-api-types/v10#(VideoQualityMode:enum) | Auto} when not present.\n\t */\n\tpublic get videoQualityMode() {\n\t\treturn this[kData].video_quality_mode!;\n\t}\n\n\t/**\n\t * The user limit of the voice channel.\n\t */\n\tpublic get userLimit() {\n\t\treturn this[kData].user_limit!;\n\t}\n\n\t/**\n\t * Indicates whether this channel has voice connection capabilities\n\t */\n\tpublic override isVoiceBased(): this is VoiceChannelMixin & this {\n\t\treturn true;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/channels/mixins/index.ts",
    "content": "export * from './AppliedTagsMixin.js';\nexport * from './ChannelOwnerMixin.js';\nexport * from './ChannelParentMixin.js';\nexport * from './ChannelPermissionMixin.js';\nexport * from './ChannelPinMixin.js';\nexport * from './ChannelSlowmodeMixin.js';\nexport * from './ChannelTopicMixin.js';\nexport * from './ChannelWebhookMixin.js';\nexport * from './DMChannelMixin.js';\nexport * from './GroupDMMixin.js';\nexport * from './GuildChannelMixin.js';\nexport * from './TextChannelMixin.js';\nexport * from './ThreadChannelMixin.js';\nexport * from './ThreadOnlyChannelMixin.js';\nexport * from './VoiceChannelMixin.js';\n"
  },
  {
    "path": "packages/structures/src/emojis/Emoji.ts",
    "content": "import { DiscordSnowflake } from '@sapphire/snowflake';\nimport type { APIEmoji } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport { isIdSet } from '../utils/type-guards.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents any emoji on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has substructure `User` which needs to be instantiated and stored by an extending class using it\n * @remarks intentionally does not export `roles` so that extending classes can resolve `Snowflake[]` to `Role[]`\n */\nexport class Emoji<Omitted extends keyof APIEmoji | '' = ''> extends Structure<APIEmoji, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each emoji\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIEmoji> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the emoji\n\t */\n\tpublic constructor(data: Partialize<APIEmoji, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The emoji's id\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The name of the emoji\n\t *\n\t * @remarks can be null only in reaction emoji objects\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * Whether this emoji must be wrapped in colons\n\t */\n\tpublic get requireColons() {\n\t\treturn this[kData].require_colons;\n\t}\n\n\t/**\n\t * Whether the emoji is managed\n\t */\n\tpublic get managed() {\n\t\treturn this[kData].managed;\n\t}\n\n\t/**\n\t * Whether the emoji is animated\n\t */\n\tpublic get animated() {\n\t\treturn this[kData].animated;\n\t}\n\n\t/**\n\t * Whether the emoji can be used\n\t *\n\t * @remarks May be false due to loss of server boosts\n\t */\n\tpublic get available() {\n\t\treturn this[kData].available;\n\t}\n\n\t/**\n\t * The timestamp the emoji was created at\n\t */\n\tpublic get createdTimestamp() {\n\t\treturn isIdSet(this.id) ? DiscordSnowflake.timestampFrom(this.id) : null;\n\t}\n\n\t/**\n\t * The time the emoji was created at\n\t */\n\tpublic get createdAt() {\n\t\tconst createdTimestamp = this.createdTimestamp;\n\t\treturn createdTimestamp ? new Date(createdTimestamp) : null;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/emojis/index.ts",
    "content": "export * from './Emoji.js';\n"
  },
  {
    "path": "packages/structures/src/entitlements/Entitlement.ts",
    "content": "import { DiscordSnowflake } from '@sapphire/snowflake';\nimport type { APIEntitlement } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { dateToDiscordISOTimestamp } from '../utils/optimization.js';\nimport { kData, kStartsTimestamp, kEndsTimestamp } from '../utils/symbols.js';\nimport { isIdSet } from '../utils/type-guards.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents any entitlement on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class Entitlement<Omitted extends keyof APIEntitlement | '' = 'ends_at' | 'starts_at'> extends Structure<\n\tAPIEntitlement,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each entitlement\n\t *\n\t * @remarks This template has defaults, if you want to remove additional data and keep the defaults,\n\t * use `Object.defineProperties`. To override the defaults, set this value directly.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIEntitlement> = {\n\t\tset starts_at(_: string) {},\n\t\tset ends_at(_: string) {},\n\t};\n\n\tprotected [kStartsTimestamp]: number | null = null;\n\n\tprotected [kEndsTimestamp]: number | null = null;\n\n\t/**\n\t * @param data - The raw data received from the API for the entitlement\n\t */\n\tpublic constructor(data: Partialize<APIEntitlement, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.optimizeData}\n\t */\n\tprotected override optimizeData(data: Partial<APIEntitlement>) {\n\t\tif (data.starts_at) {\n\t\t\tthis[kStartsTimestamp] = Date.parse(data.starts_at);\n\t\t}\n\n\t\tif (data.ends_at) {\n\t\t\tthis[kEndsTimestamp] = Date.parse(data.ends_at);\n\t\t}\n\t}\n\n\t/**\n\t * The id of the entitlement\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The id of the SKU\n\t */\n\tpublic get skuId() {\n\t\treturn this[kData].sku_id;\n\t}\n\n\t/**\n\t * The id of the parent application\n\t */\n\tpublic get applicationId() {\n\t\treturn this[kData].application_id;\n\t}\n\n\t/**\n\t * The id of the user that is granted access to the entitlement's SKU\n\t */\n\tpublic get userId() {\n\t\treturn this[kData].user_id;\n\t}\n\n\t/**\n\t * Type of entitlement\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/entitlement#entitlement-object-entitlement-types}\n\t */\n\tpublic get type() {\n\t\treturn this[kData].type;\n\t}\n\n\t/**\n\t * Whether the entitlement was deleted\n\t */\n\tpublic get deleted() {\n\t\treturn this[kData].deleted;\n\t}\n\n\t/**\n\t * Start date at which the entitlement is valid\n\t */\n\tpublic get startsAt() {\n\t\tconst timestamp = this.startsTimestamp;\n\t\treturn timestamp ? new Date(timestamp) : null;\n\t}\n\n\t/**\n\t * Timestamp of the start date at which the entitlement is valid\n\t */\n\tpublic get startsTimestamp() {\n\t\treturn this[kStartsTimestamp];\n\t}\n\n\t/**\n\t * End date at which the entitlement is valid\n\t */\n\tpublic get endsAt() {\n\t\tconst timestamp = this.endsTimestamp;\n\t\treturn timestamp ? new Date(timestamp) : null;\n\t}\n\n\t/**\n\t * Timestamp of the end date at which the entitlement is valid\n\t */\n\tpublic get endsTimestamp() {\n\t\treturn this[kEndsTimestamp];\n\t}\n\n\t/**\n\t * Id of the guild that is granted access to the entitlement's SKU\n\t */\n\tpublic get guildId() {\n\t\treturn this[kData].guild_id;\n\t}\n\n\t/**\n\t * For consumable items, whether the entitlement has been consumed\n\t */\n\tpublic get consumed() {\n\t\treturn this[kData].consumed;\n\t}\n\n\t/**\n\t * The timestamp the entitlement was created at\n\t */\n\tpublic get createdTimestamp() {\n\t\treturn isIdSet(this.id) ? DiscordSnowflake.timestampFrom(this.id) : null;\n\t}\n\n\t/**\n\t * The time the entitlement was created at\n\t */\n\tpublic get createdAt() {\n\t\tconst createdTimestamp = this.createdTimestamp;\n\t\treturn createdTimestamp ? new Date(createdTimestamp) : null;\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.toJSON}\n\t */\n\tpublic override toJSON() {\n\t\tconst clone = super.toJSON();\n\n\t\tconst startsAtTimestamp = this[kStartsTimestamp];\n\t\tconst endsAtTimestamp = this[kEndsTimestamp];\n\n\t\tif (startsAtTimestamp) {\n\t\t\tclone.starts_at = dateToDiscordISOTimestamp(new Date(startsAtTimestamp));\n\t\t}\n\n\t\tif (endsAtTimestamp) {\n\t\t\tclone.ends_at = dateToDiscordISOTimestamp(new Date(endsAtTimestamp));\n\t\t}\n\n\t\treturn clone;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/entitlements/index.ts",
    "content": "export * from './Entitlement.js';\n"
  },
  {
    "path": "packages/structures/src/index.ts",
    "content": "export * from './automoderation/index.js';\nexport * from './bitfields/index.js';\nexport * from './channels/index.js';\nexport * from './emojis/index.js';\nexport * from './entitlements/index.js';\nexport * from './interactions/index.js';\nexport * from './invites/index.js';\nexport * from './messages/index.js';\nexport * from './polls/index.js';\nexport * from './skus/index.js';\nexport * from './soundboards/index.js';\nexport * from './stageInstances/index.js';\nexport * from './stickers/index.js';\nexport * from './teams/index.js';\nexport * from './users/index.js';\nexport * from './webhooks/index.js';\nexport * from './voice/index.js';\nexport * from './Structure.js';\nexport * from './subscriptions/index.js';\nexport * from './Mixin.js';\nexport * from './utils/optimization.js';\nexport type * from './utils/types.js';\nexport type * from './MixinTypes.d.ts';\n"
  },
  {
    "path": "packages/structures/src/interactions/ResolvedInteractionData.ts",
    "content": "import type { APIInteractionDataResolved } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents data for users, members, channels, and roles in the message's auto-populated select menus.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has substructures `User`, `Channel`, `Role`, `Message`, `GuildMember`, `Attachment`,  which need to be instantiated and stored by an extending class using it\n */\nexport abstract class ResolvedInteractionData<\n\tOmitted extends keyof APIInteractionDataResolved | '' = '',\n> extends Structure<APIInteractionDataResolved, Omitted> {\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIInteractionDataResolved, Omitted>) {\n\t\tsuper(data);\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/interactions/index.ts",
    "content": "export * from './ResolvedInteractionData.js';\n"
  },
  {
    "path": "packages/structures/src/invites/Invite.ts",
    "content": "import { type APIInvite, type APIExtendedInvite, RouteBases } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { dateToDiscordISOTimestamp } from '../utils/optimization.js';\nimport { kData, kExpiresTimestamp, kCreatedTimestamp } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\nexport interface APIActualInvite extends APIInvite, Partial<Omit<APIExtendedInvite, keyof APIInvite>> {}\n\n/**\n * Represents an invitation to a Discord channel\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class Invite<Omitted extends keyof APIActualInvite | '' = 'created_at' | 'expires_at'> extends Structure<\n\tAPIActualInvite,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each Invite\n\t *\n\t * @remarks This template has defaults, if you want to remove additional data and keep the defaults,\n\t * use `Object.defineProperties`. To override the defaults, set this value directly.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIActualInvite> = {\n\t\tset created_at(_: string) {},\n\t\tset expires_at(_: string) {},\n\t};\n\n\t/**\n\t * Optimized storage of {@link discord-api-types/v10#(APIActualInvite:interface).expires_at}\n\t *\n\t * @internal\n\t */\n\tprotected [kExpiresTimestamp]: number | null = null;\n\n\t/**\n\t * Optimized storage of {@link discord-api-types/v10#(APIActualInvite:interface).created_at}\n\t *\n\t * @internal\n\t */\n\tprotected [kCreatedTimestamp]: number | null = null;\n\n\t/**\n\t * @param data - The raw data received from the API for the invite\n\t */\n\tpublic constructor(data: Partialize<APIActualInvite, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.optimizeData}\n\t *\n\t * @internal\n\t */\n\tprotected override optimizeData(data: Partial<APIActualInvite>) {\n\t\tif (data.expires_at) {\n\t\t\tthis[kExpiresTimestamp] = Date.parse(data.expires_at);\n\t\t}\n\n\t\tif (data.created_at) {\n\t\t\tthis[kCreatedTimestamp] = Date.parse(data.created_at);\n\t\t}\n\t}\n\n\t/**\n\t * The code for this invite\n\t */\n\tpublic get code() {\n\t\treturn this[kData].code;\n\t}\n\n\t/**\n\t * The target type (for voice channel invites)\n\t */\n\tpublic get targetType() {\n\t\treturn this[kData].target_type;\n\t}\n\n\t/**\n\t * The type of this invite\n\t */\n\tpublic get type() {\n\t\treturn this[kData].type;\n\t}\n\n\t/**\n\t * The approximate number of online members of the guild this invite is for\n\t *\n\t * @remarks Only available when the invite was fetched from `GET /invites/<code>` with counts\n\t */\n\tpublic get approximatePresenceCount() {\n\t\treturn this[kData].approximate_presence_count;\n\t}\n\n\t/**\n\t * The approximate total number of members of the guild this invite is for\n\t *\n\t * @remarks Only available when the invite was fetched from `GET /invites/<code>` with counts\n\t */\n\tpublic get approximateMemberCount() {\n\t\treturn this[kData].approximate_member_count;\n\t}\n\n\t/**\n\t * The timestamp this invite will expire at\n\t */\n\tpublic get expiresTimestamp() {\n\t\tif (this[kExpiresTimestamp]) {\n\t\t\treturn this[kExpiresTimestamp];\n\t\t}\n\n\t\tconst createdTimestamp = this.createdTimestamp;\n\t\tconst maxAge = this.maxAge;\n\t\tif (createdTimestamp && maxAge) {\n\t\t\tthis[kExpiresTimestamp] = createdTimestamp + (maxAge as number) * 1_000;\n\t\t}\n\n\t\treturn this[kExpiresTimestamp];\n\t}\n\n\t/**\n\t * The time the invite will expire at\n\t */\n\tpublic get expiresAt() {\n\t\tconst expiresTimestamp = this.expiresTimestamp;\n\t\treturn expiresTimestamp ? new Date(expiresTimestamp) : null;\n\t}\n\n\t/**\n\t * The number of times this invite has been used\n\t */\n\tpublic get uses() {\n\t\treturn this[kData].uses;\n\t}\n\n\t/**\n\t * The maximum number of times this invite can be used\n\t */\n\tpublic get maxUses() {\n\t\treturn this[kData].max_uses;\n\t}\n\n\t/**\n\t * The maximum age of the invite, in seconds, 0 for non-expiring\n\t */\n\tpublic get maxAge() {\n\t\treturn this[kData].max_age;\n\t}\n\n\t/**\n\t * Whether this invite only grants temporary membership\n\t */\n\tpublic get temporary() {\n\t\treturn this[kData].temporary;\n\t}\n\n\t/**\n\t * The timestamp this invite was created at\n\t */\n\tpublic get createdTimestamp() {\n\t\treturn this[kCreatedTimestamp];\n\t}\n\n\t/**\n\t * The time the invite was created at\n\t */\n\tpublic get createdAt() {\n\t\tconst createdTimestamp = this.createdTimestamp;\n\t\treturn createdTimestamp ? new Date(createdTimestamp) : null;\n\t}\n\n\t/**\n\t * The URL to the invite\n\t */\n\tpublic get url() {\n\t\treturn this.code ? `${RouteBases.invite}/${this.code}` : null;\n\t}\n\n\t/**\n\t * When concatenated with a string, this automatically concatenates the invite's URL instead of the object.\n\t *\n\t * @returns The URL to the invite or an empty string if it doesn't have a code\n\t */\n\tpublic override toString() {\n\t\treturn this.url ?? '';\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.toJSON}\n\t */\n\tpublic override toJSON() {\n\t\tconst clone = super.toJSON();\n\t\tif (this[kExpiresTimestamp]) {\n\t\t\tclone.expires_at = dateToDiscordISOTimestamp(new Date(this[kExpiresTimestamp]));\n\t\t}\n\n\t\tif (this[kCreatedTimestamp]) {\n\t\t\tclone.created_at = dateToDiscordISOTimestamp(new Date(this[kCreatedTimestamp]));\n\t\t}\n\n\t\treturn clone;\n\t}\n\n\t/**\n\t * Returns the primitive value of the specified object.\n\t */\n\tpublic override valueOf() {\n\t\treturn this.code ?? super.valueOf();\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/invites/index.ts",
    "content": "export * from './Invite.js';\n"
  },
  {
    "path": "packages/structures/src/messages/ApplicationCommandInteractionMetadata.ts",
    "content": "import type { APIApplicationCommandInteractionMetadata, InteractionType } from 'discord-api-types/v10';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\nimport { InteractionMetadata } from './InteractionMetadata.js';\n\n/**\n * Represents metadata about the application command interaction causing a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has a substructure `User` which needs to be instantiated and stored by an extending class using it\n */\nexport class ApplicationCommandInteractionMetadata<\n\tOmitted extends keyof APIApplicationCommandInteractionMetadata | '' = '',\n> extends InteractionMetadata<InteractionType.ApplicationCommand, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each ApplicationCommandInteractionMetadata.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIApplicationCommandInteractionMetadata> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIApplicationCommandInteractionMetadata, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id of the message the command was run on\n\t */\n\tpublic get targetMessageId() {\n\t\treturn this[kData].target_message_id;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/Attachment.ts",
    "content": "import type { APIAttachment, AttachmentFlags } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { AttachmentFlagsBitField } from '../bitfields/AttachmentFlagsBitField.js';\nimport { kData } from '../utils/symbols.js';\nimport { isFieldSet } from '../utils/type-guards.js';\nimport type { Partialize } from '../utils/types.js';\n\nexport class Attachment<Omitted extends keyof APIAttachment | '' = ''> extends Structure<APIAttachment, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each Attachment.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIAttachment> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIAttachment, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id of the attachment\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The name of the attached file\n\t */\n\tpublic get filename() {\n\t\treturn this[kData].filename;\n\t}\n\n\t/**\n\t * The title of the file\n\t */\n\tpublic get title() {\n\t\treturn this[kData].title;\n\t}\n\n\t/**\n\t * The description for the file\n\t */\n\tpublic get description() {\n\t\treturn this[kData].description;\n\t}\n\n\t/**\n\t * The attachment's media type\n\t */\n\tpublic get contentType() {\n\t\treturn this[kData].content_type;\n\t}\n\n\t/**\n\t * The size of the file in bytes\n\t */\n\tpublic get size() {\n\t\treturn this[kData].size;\n\t}\n\n\t/**\n\t * The source URL of the file\n\t */\n\tpublic get url() {\n\t\treturn this[kData].url;\n\t}\n\n\t/**\n\t * A proxied URL of the file\n\t */\n\tpublic get proxyURL() {\n\t\treturn this[kData].proxy_url;\n\t}\n\n\t/**\n\t * The height of the file (if image)\n\t */\n\tpublic get height() {\n\t\treturn this[kData].height;\n\t}\n\n\t/**\n\t * The width of the file (if image)\n\t */\n\tpublic get width() {\n\t\treturn this[kData].width;\n\t}\n\n\t/**\n\t * Whether this attachment is ephemeral\n\t */\n\tpublic get ephemeral() {\n\t\treturn this[kData].ephemeral;\n\t}\n\n\t/**\n\t * The duration of the audio file\n\t */\n\tpublic get durationSecs() {\n\t\treturn this[kData].duration_secs;\n\t}\n\n\t/**\n\t * Base64 encoded bytearray representing a sampled waveform\n\t */\n\tpublic get waveform() {\n\t\treturn this[kData].waveform;\n\t}\n\n\t/**\n\t * Attachment flags combined as a bitfield\n\t */\n\tpublic get flags() {\n\t\treturn isFieldSet(this[kData], 'flags', 'number')\n\t\t\t? new AttachmentFlagsBitField(this[kData].flags as AttachmentFlags)\n\t\t\t: null;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/ChannelMention.ts",
    "content": "import type { APIChannelMention } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents the mention of a channel on a message on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class ChannelMention<Omitted extends keyof APIChannelMention | '' = ''> extends Structure<\n\tAPIChannelMention,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each ChannelMention.\n\t */\n\tpublic static override DataTemplate: Partial<APIChannelMention> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the channel mention\n\t */\n\tpublic constructor(data: Partialize<APIChannelMention, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The type of the mentioned channel\n\t */\n\tpublic get type() {\n\t\treturn this[kData].type;\n\t}\n\n\t/**\n\t * The name of the mentioned channel\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * The id of the mentioned channel\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The id of the guild the mentioned channel is in\n\t */\n\tpublic get guildId() {\n\t\treturn this[kData].guild_id;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/InteractionMetadata.ts",
    "content": "import type { APIMessageInteractionMetadata, InteractionType } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\nexport type InteractionMetadataType<Type extends InteractionType> = Extract<\n\tAPIMessageInteractionMetadata,\n\t{ type: Type }\n>;\n\n/**\n * Represents metadata about the interaction causing a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has a substructure `User` which needs to be instantiated and stored by an extending class using it\n */\nexport abstract class InteractionMetadata<\n\tType extends InteractionType,\n\tOmitted extends keyof InteractionMetadataType<Type> | '' = '',\n> extends Structure<InteractionMetadataType<Type>, Omitted> {\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<InteractionMetadataType<Type>, Omitted>) {\n\t\tsuper(data as InteractionMetadataType<Type>);\n\t}\n\n\t/**\n\t * The id of the interaction\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The id of the original response message, present only on follow-up messages\n\t */\n\tpublic get originalResponseMessageId() {\n\t\treturn this[kData].original_response_message_id;\n\t}\n\n\t/**\n\t * The type of interaction\n\t */\n\tpublic get type() {\n\t\treturn this[kData].type;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/Message.ts",
    "content": "import { DiscordSnowflake } from '@sapphire/snowflake';\nimport type { APIMessage, MessageFlags } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { MessageFlagsBitField } from '../bitfields/MessageFlagsBitField.js';\nimport { dateToDiscordISOTimestamp } from '../utils/optimization.js';\nimport { kData, kEditedTimestamp } from '../utils/symbols.js';\nimport { isFieldSet, isIdSet } from '../utils/type-guards.js';\nimport type { Partialize } from '../utils/types.js';\n\n// TODO: missing substructures: application\n\n/**\n * Represents a message on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has substructures `Message`, `Channel`, `MessageActivity`, `MessageCall`, `MessageReference`, `Attachment`, `Application`, `ChannelMention`, `Reaction`, `Poll`, `ResolvedInteractionData`, `RoleSubscriptionData`, `Sticker`, all the different `Component`s, ... which need to be instantiated and stored by an extending class using it\n */\nexport class Message<Omitted extends keyof APIMessage | '' = 'edited_timestamp' | 'timestamp'> extends Structure<\n\tAPIMessage,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each Message\n\t */\n\tpublic static override DataTemplate: Partial<APIMessage> = {\n\t\tset timestamp(_: string) {},\n\t\tset edited_timestamp(_: string) {},\n\t};\n\n\tprotected [kEditedTimestamp]: number | null = null;\n\n\t/**\n\t * @param data - The raw data received from the API for the message\n\t */\n\tpublic constructor(data: Partialize<APIMessage, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.optimizeData}\n\t *\n\t * @internal\n\t */\n\tprotected override optimizeData(data: Partial<APIMessage>) {\n\t\tif (data.edited_timestamp) {\n\t\t\tthis[kEditedTimestamp] = Date.parse(data.edited_timestamp);\n\t\t}\n\t}\n\n\t/**\n\t * The message's id\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The id of the interaction's application, if this message is a reply to an interaction\n\t */\n\tpublic get applicationId() {\n\t\treturn this[kData].application_id;\n\t}\n\n\t/**\n\t * The channel's id this message was sent in\n\t */\n\tpublic get channelId() {\n\t\treturn this[kData].channel_id;\n\t}\n\n\t/**\n\t * The timestamp this message was created at\n\t */\n\tpublic get createdTimestamp() {\n\t\treturn isIdSet(this.id) ? DiscordSnowflake.timestampFrom(this.id) : null;\n\t}\n\n\t/**\n\t * The time the message was created at\n\t */\n\tpublic get createdAt() {\n\t\tconst createdTimestamp = this.createdTimestamp;\n\t\treturn createdTimestamp ? new Date(createdTimestamp) : null;\n\t}\n\n\t/**\n\t * The content of the message\n\t */\n\tpublic get content() {\n\t\treturn this[kData].content;\n\t}\n\n\t/**\n\t * The timestamp this message was last edited at, or `null` if it never was edited\n\t */\n\tpublic get editedTimestamp() {\n\t\treturn this[kEditedTimestamp];\n\t}\n\n\t/**\n\t * The time the message was last edited at, or `null` if it never was edited\n\t */\n\tpublic get editedAt() {\n\t\tconst editedTimestamp = this.editedTimestamp;\n\t\treturn editedTimestamp ? new Date(editedTimestamp) : null;\n\t}\n\n\t/**\n\t * The flags of this message as a bit field\n\t */\n\tpublic get flags() {\n\t\treturn isFieldSet(this[kData], 'flags', 'number')\n\t\t\t? new MessageFlagsBitField(this[kData].flags as MessageFlags)\n\t\t\t: null;\n\t}\n\n\t/**\n\t * The nonce used when sending this message.\n\t *\n\t * @remarks This is only present in MESSAGE_CREATE event, if a nonce was provided when sending\n\t */\n\tpublic get nonce() {\n\t\treturn this[kData].nonce;\n\t}\n\n\t/**\n\t * Whether this message is pinned in its channel\n\t */\n\tpublic get pinned() {\n\t\treturn this[kData].pinned;\n\t}\n\n\t/**\n\t * A generally increasing integer (there may be gaps or duplicates) that represents the approximate position of the message in a thread\n\t * It can be used to estimate the relative position of the message in a thread in company with `totalMessageSent` on parent thread\n\t */\n\tpublic get position() {\n\t\treturn this[kData].position;\n\t}\n\n\t/**\n\t * Whether this message was a TTS message\n\t */\n\tpublic get tts() {\n\t\treturn this[kData].tts;\n\t}\n\n\t/**\n\t * The type of message\n\t */\n\tpublic get type() {\n\t\treturn this[kData].type;\n\t}\n\n\t/**\n\t * If the message is generated by a webhook, this is the webhook's id\n\t */\n\tpublic get webhookId() {\n\t\treturn this[kData].webhook_id;\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.toJSON}\n\t */\n\tpublic override toJSON() {\n\t\tconst clone = super.toJSON();\n\t\tif (this[kEditedTimestamp]) {\n\t\t\tclone.edited_timestamp = dateToDiscordISOTimestamp(new Date(this[kEditedTimestamp]));\n\t\t}\n\n\t\tconst createdAt = this.createdAt;\n\t\tif (createdAt) {\n\t\t\tclone.timestamp = dateToDiscordISOTimestamp(createdAt);\n\t\t}\n\n\t\treturn clone;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/MessageActivity.ts",
    "content": "import type { APIMessageActivity } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\nexport class MessageActivity<Omitted extends keyof APIMessageActivity | '' = ''> extends Structure<\n\tAPIMessageActivity,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each MessageActivity.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIMessageActivity> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIMessageActivity, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The party id from a Rich Presence event\n\t */\n\tpublic get partyId() {\n\t\treturn this[kData].party_id;\n\t}\n\n\t/**\n\t * The type of message activity\n\t */\n\tpublic get type() {\n\t\treturn this[kData].type;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/MessageCall.ts",
    "content": "import type { APIMessageCall } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { dateToDiscordISOTimestamp } from '../utils/optimization.js';\nimport { kEndedTimestamp } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\nexport class MessageCall<Omitted extends keyof APIMessageCall | '' = 'ended_timestamp'> extends Structure<\n\tAPIMessageCall,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each MessageCall\n\t */\n\tpublic static override DataTemplate: Partial<APIMessageCall> = {\n\t\tset ended_timestamp(_: string) {},\n\t};\n\n\tprotected [kEndedTimestamp]: number | null = null;\n\n\t/**\n\t * @param data - The raw data received from the API for the message call\n\t */\n\tpublic constructor(data: Partialize<APIMessageCall, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.optimizeData}\n\t *\n\t * @internal\n\t */\n\tprotected override optimizeData(data: Partial<APIMessageCall>) {\n\t\tif (data.ended_timestamp) {\n\t\t\tthis[kEndedTimestamp] = Date.parse(data.ended_timestamp);\n\t\t}\n\t}\n\n\t/**\n\t * The timestamp this call ended at, or `null` if it didn't end yet\n\t */\n\tpublic get endedTimestamp() {\n\t\treturn this[kEndedTimestamp];\n\t}\n\n\t/**\n\t * The time the call ended at, or `null` if it didn't end yet\n\t */\n\tpublic get endedAt() {\n\t\tconst endedTimestamp = this.endedTimestamp;\n\t\treturn endedTimestamp ? new Date(endedTimestamp) : null;\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.toJSON}\n\t */\n\tpublic override toJSON() {\n\t\tconst clone = super.toJSON();\n\t\tif (this[kEndedTimestamp]) {\n\t\t\tclone.ended_timestamp = dateToDiscordISOTimestamp(new Date(this[kEndedTimestamp]));\n\t\t}\n\n\t\treturn clone;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/MessageComponentInteractionMetadata.ts",
    "content": "import type { APIMessageComponentInteractionMetadata, InteractionType } from 'discord-api-types/v10';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\nimport { InteractionMetadata } from './InteractionMetadata.js';\n\n/**\n * Represents metadata about the message component interaction causing a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class MessageComponentInteractionMetadata<\n\tOmitted extends keyof APIMessageComponentInteractionMetadata | '' = '',\n> extends InteractionMetadata<InteractionType.MessageComponent, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each MessageComponentInteractionMetadata.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIMessageComponentInteractionMetadata> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIMessageComponentInteractionMetadata, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id of the message that contained the interactive component\n\t */\n\tpublic get interactedMessageId() {\n\t\treturn this[kData].interacted_message_id;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/MessageReference.ts",
    "content": "import { MessageReferenceType, type APIMessageReference } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents the reference to another message on a message on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class MessageReference<Omitted extends keyof APIMessageReference | '' = ''> extends Structure<\n\tAPIMessageReference,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each MessageReference.\n\t */\n\tpublic static override DataTemplate: Partial<APIMessageReference> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the message reference\n\t */\n\tpublic constructor(data: Partialize<APIMessageReference, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The type of this reference\n\t */\n\tpublic get type() {\n\t\treturn 'type' in this[kData] ? (this[kData].type as MessageReferenceType) : MessageReferenceType.Default;\n\t}\n\n\t/**\n\t * The id of the referenced message\n\t */\n\tpublic get messageId() {\n\t\treturn this[kData].message_id;\n\t}\n\n\t/**\n\t * The id of the channel the referenced message was sent in\n\t */\n\tpublic get channelId() {\n\t\treturn this[kData].channel_id;\n\t}\n\n\t/**\n\t * The id of the guild the referenced message was sent in\n\t */\n\tpublic get guildId() {\n\t\treturn this[kData].guild_id;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/ModalSubmitInteractionMetadata.ts",
    "content": "import type { APIModalSubmitInteractionMetadata, InteractionType } from 'discord-api-types/v10';\nimport type { Partialize } from '../utils/types.js';\nimport { InteractionMetadata } from './InteractionMetadata.js';\n\n/**\n * Represents metadata about the modal submit interaction causing a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has a substructure `InteractionMetadata` which needs to be instantiated and stored by an extending class using it\n */\nexport class ModalSubmitInteractionMetadata<\n\tOmitted extends keyof APIModalSubmitInteractionMetadata | '' = '',\n> extends InteractionMetadata<InteractionType.ModalSubmit, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each ModalSubmitInteractionMetadata.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIModalSubmitInteractionMetadata> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIModalSubmitInteractionMetadata, Omitted>) {\n\t\tsuper(data);\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/Reaction.ts",
    "content": "import type { APIReaction } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kBurstColors, kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents a reaction on a message on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has substructures `Emoji`, `ReactionCountDetails` which need to be instantiated and stored by an extending class using it\n */\nexport class Reaction<Omitted extends keyof APIReaction | '' = ''> extends Structure<APIReaction, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each Reaction.\n\t */\n\tpublic static override DataTemplate: Partial<APIReaction> = {\n\t\tset burst_colors(_: string[]) {},\n\t};\n\n\tprotected [kBurstColors]: number[] | null = null;\n\n\t/**\n\t * @param data - The raw data received from the API for the reaction\n\t */\n\tpublic constructor(data: Partialize<APIReaction, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.optimizeData}\n\t *\n\t * @internal\n\t */\n\tprotected override optimizeData(data: Partial<APIReaction>) {\n\t\tif (data.burst_colors) {\n\t\t\tthis[kBurstColors] = data.burst_colors.map((color) => Number.parseInt(color, 16));\n\t\t}\n\t}\n\n\t/**\n\t * The amount how often this emoji has been used to react (including super reacts)\n\t */\n\tpublic get count() {\n\t\treturn this[kData].count;\n\t}\n\n\t/**\n\t * Whether the current user has reacted using this emoji\n\t */\n\tpublic get me() {\n\t\treturn this[kData].me;\n\t}\n\n\t/**\n\t * Whether the current user has super-reacted using this emoji\n\t */\n\tpublic get meBurst() {\n\t\treturn this[kData].me_burst;\n\t}\n\n\t/**\n\t * The colors used for super reaction\n\t */\n\tpublic get burstColors() {\n\t\treturn this[kBurstColors];\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.toJSON}\n\t */\n\tpublic override toJSON() {\n\t\tconst clone = super.toJSON();\n\t\tif (this[kBurstColors]) {\n\t\t\tclone.burst_colors = this[kBurstColors].map((color) => `#${color.toString(16).padStart(6, '0')}`);\n\t\t}\n\n\t\treturn clone;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/ReactionCountDetails.ts",
    "content": "import type { APIReactionCountDetails } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents the usage count of a reaction on a message on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class ReactionCountDetails<Omitted extends keyof APIReactionCountDetails | '' = ''> extends Structure<\n\tAPIReactionCountDetails,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each ReactionCountDetails.\n\t */\n\tpublic static override DataTemplate: Partial<APIReactionCountDetails> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the reaction count details\n\t */\n\tpublic constructor(data: Partialize<APIReactionCountDetails, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The amount how often this emoji has been used to react (excluding super reacts)\n\t */\n\tpublic get normal() {\n\t\treturn this[kData].normal;\n\t}\n\n\t/**\n\t * The amount how often this emoji has been used to super-react\n\t */\n\tpublic get burst() {\n\t\treturn this[kData].burst;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/RoleSubscriptionData.ts",
    "content": "import type { APIMessageRoleSubscriptionData } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents metadata about the role subscription causing a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport abstract class RoleSubscriptionData<\n\tOmitted extends keyof APIMessageRoleSubscriptionData | '' = '',\n> extends Structure<APIMessageRoleSubscriptionData, Omitted> {\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIMessageRoleSubscriptionData, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id of the SKU and listing the user is subscribed to\n\t */\n\tpublic get roleSubscriptionListingId() {\n\t\treturn this[kData].role_subscription_listing_id;\n\t}\n\n\t/**\n\t * The name of the tier the user is subscribed to\n\t */\n\tpublic get tierName() {\n\t\treturn this[kData].tier_name;\n\t}\n\n\t/**\n\t * The number of months the user has been subscribed for\n\t */\n\tpublic get totalMonthsSubscribed() {\n\t\treturn this[kData].total_months_subscribed;\n\t}\n\n\t/**\n\t * Whether this notification is for a renewal\n\t */\n\tpublic get isRenewal() {\n\t\treturn this[kData].is_renewal;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/ActionRowComponent.ts",
    "content": "import type { APIActionRowComponent, APIComponentInActionRow, ComponentType } from 'discord-api-types/v10';\nimport type { Partialize } from '../../utils/types.js';\nimport type { ComponentDataType } from './Component.js';\nimport { Component } from './Component.js';\n\n/**\n * Represents an action row component on a message or modal.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has `Component`s as substructures which need to be instantiated and stored by an extending class using it\n */\nexport class ActionRowComponent<\n\tType extends APIComponentInActionRow,\n\tOmitted extends keyof APIActionRowComponent<Type> | '' = '',\n> extends Component<ComponentDataType<ComponentType.ActionRow>, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each ActionRowComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<ComponentDataType<ComponentType.ActionRow>> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the action row\n\t */\n\tpublic constructor(data: Partialize<ComponentDataType<ComponentType.ActionRow>, Omitted>) {\n\t\tsuper(data);\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/ButtonComponent.ts",
    "content": "import type { APIButtonComponent, APIButtonComponentWithCustomId, ButtonStyle } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\nimport { Component } from './Component.js';\n\n/**\n * The data stored by a {@link ButtonComponent} structure based on its {@link (ButtonComponent:class).\"style\"} property.\n */\nexport type ButtonDataType<Style extends ButtonStyle> = Style extends\n\t| ButtonStyle.Danger\n\t| ButtonStyle.Primary\n\t| ButtonStyle.Secondary\n\t| ButtonStyle.Success\n\t? APIButtonComponentWithCustomId\n\t: Extract<APIButtonComponent, { style: Style }>;\n\nexport abstract class ButtonComponent<\n\tStyle extends ButtonStyle,\n\tOmitted extends keyof ButtonDataType<Style> | '' = '',\n> extends Component<ButtonDataType<Style>, Omitted> {\n\t/**\n\t * @param data - The raw data received from the API for the button\n\t */\n\tpublic constructor(data: Partialize<ButtonDataType<Style>, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The style of the button\n\t */\n\tpublic get style() {\n\t\treturn this[kData].style;\n\t}\n\n\t/**\n\t * The status of the button\n\t */\n\tpublic get disabled() {\n\t\treturn typeof this[kData].disabled === 'boolean' ? this[kData].disabled : null;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/ChannelSelectMenuComponent.ts",
    "content": "import type { APIChannelSelectComponent, ChannelType } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\nimport { SelectMenuComponent } from './SelectMenuComponent.js';\n\n/**\n * Represents a channel select menu component.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has `SelectMenuDefaultValue`s as substructures which need to be instantiated and stored by an extending class using it\n */\nexport class ChannelSelectMenuComponent<\n\tOmitted extends keyof APIChannelSelectComponent | '' = '',\n> extends SelectMenuComponent<APIChannelSelectComponent, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each ChannelSelectMenuComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIChannelSelectComponent> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the channel select menu\n\t */\n\tpublic constructor(data: Partialize<APIChannelSelectComponent, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The list of channel types to include in the channel select component\n\t */\n\tpublic get channelTypes() {\n\t\treturn Array.isArray(this[kData].channel_types) ? (this[kData].channel_types as readonly ChannelType[]) : null;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/Component.ts",
    "content": "import type { APIBaseComponent, APIMessageComponent, APIModalComponent, ComponentType } from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\n/**\n * The data stored by a {@link Component} structure based on its {@link (Component:class).\"type\"} property.\n */\nexport type ComponentDataType<Type extends ComponentType | 'unknown'> = Type extends ComponentType\n\t? Extract<APIMessageComponent | APIModalComponent, { type: Type }>\n\t: APIBaseComponent<ComponentType>;\nexport abstract class Component<\n\tType extends APIMessageComponent | APIModalComponent,\n\tOmitted extends keyof Type | '' = '',\n> extends Structure<Type, Omitted> {\n\t/**\n\t * @param data - The raw data received from the API for the component\n\t */\n\tpublic constructor(data: Partialize<Type, Omitted>) {\n\t\tsuper(data as Type);\n\t}\n\n\t/**\n\t * 32 bit integer used as an optional identifier for component\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The type of the component\n\t */\n\tpublic get type() {\n\t\treturn this[kData].type;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/ComponentEmoji.ts",
    "content": "import type { APIMessageComponentEmoji } from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\nexport class ComponentEmoji<Omitted extends keyof APIMessageComponentEmoji | '' = ''> extends Structure<\n\tAPIMessageComponentEmoji,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each ComponentEmoji.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIMessageComponentEmoji> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the component emoji\n\t */\n\tpublic constructor(data: Partialize<APIMessageComponentEmoji, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id of the emoji\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The name of the emoji\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * Whether this emoji is animated\n\t */\n\tpublic get animated() {\n\t\treturn this[kData].animated;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/ContainerComponent.ts",
    "content": "import type { APIContainerComponent } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\nimport { Component } from './Component.js';\n\n/**\n * Represents a container component on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has `Component`s as substructures which need to be instantiated and stored by an extending class using it\n */\nexport class ContainerComponent<Omitted extends keyof APIContainerComponent | '' = ''> extends Component<\n\tAPIContainerComponent,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each ContainerComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIContainerComponent> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the container\n\t */\n\tpublic constructor(data: Partialize<APIContainerComponent, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * Color for the accent on the container as RGB\n\t */\n\tpublic get accentColor() {\n\t\treturn this[kData].accent_color;\n\t}\n\n\t/**\n\t * The hexadecimal version of the accent color, with a leading hash\n\t */\n\tpublic get hexAccentColor() {\n\t\tconst accentColor = this.accentColor;\n\t\tif (typeof accentColor !== 'number') return accentColor;\n\t\treturn `#${accentColor.toString(16).padStart(6, '0')}`;\n\t}\n\n\t/**\n\t * Whether the container should be a spoiler (or blurred out)\n\t */\n\tpublic get spoiler() {\n\t\treturn this[kData].spoiler;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/FileComponent.ts",
    "content": "import type { APIFileComponent } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\nimport { Component } from './Component.js';\n\n/**\n * Represents a file component on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has a substructure `UnfurledMediaItem` which needs to be instantiated and stored by an extending class using it\n */\nexport class FileComponent<Omitted extends keyof APIFileComponent | '' = ''> extends Component<\n\tAPIFileComponent,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each FileComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIFileComponent> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the file component\n\t */\n\tpublic constructor(data: Partialize<APIFileComponent, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * Whether the media should be a spoiler (or blurred out)\n\t */\n\tpublic get spoiler() {\n\t\treturn this[kData].spoiler;\n\t}\n\n\t/**\n\t * The name of the file\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * The size of the file in bytes\n\t */\n\tpublic get size() {\n\t\treturn this[kData].size;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/FileUploadComponent.ts",
    "content": "import type { APIFileUploadComponent } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\nimport { Component } from './Component.js';\n\n/**\n * Represents a file upload component on a modal.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class FileUploadComponent<Omitted extends keyof APIFileUploadComponent | '' = ''> extends Component<\n\tAPIFileUploadComponent,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each FileUploadComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIFileUploadComponent> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the file upload component\n\t */\n\tpublic constructor(data: Partialize<APIFileUploadComponent, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The custom id to be sent in the interaction when the modal gets submitted\n\t */\n\tpublic get customId() {\n\t\treturn this[kData].custom_id;\n\t}\n\n\t/**\n\t * The maximum number of items that can be uploaded\n\t */\n\tpublic get maxValues() {\n\t\treturn this[kData].max_values;\n\t}\n\n\t/**\n\t * The minimum number of items that must be uploaded\n\t */\n\tpublic get minValues() {\n\t\treturn this[kData].min_values;\n\t}\n\n\t/**\n\t * Whether the file upload requires files to be uploaded before submitting the modal\n\t */\n\tpublic get required() {\n\t\treturn this[kData].required;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/InteractiveButtonComponent.ts",
    "content": "import type { APIButtonComponentWithCustomId, ButtonStyle } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\nimport type { ButtonDataType } from './ButtonComponent.js';\nimport { LabeledButtonComponent } from './LabeledButtonComponent.js';\n\n/**\n * Represents a button causing a message component interaction on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class InteractiveButtonComponent<\n\tStyle extends ButtonStyle.Danger | ButtonStyle.Primary | ButtonStyle.Secondary | ButtonStyle.Success,\n\tOmitted extends keyof APIButtonComponentWithCustomId | '' = '',\n> extends LabeledButtonComponent<Style, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each InteractiveButtonComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIButtonComponentWithCustomId> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the interactive button\n\t */\n\tpublic constructor(data: Partialize<APIButtonComponentWithCustomId, Omitted>) {\n\t\tsuper(data as ButtonDataType<Style>);\n\t}\n\n\t/**\n\t * The custom id to be sent in the interaction when clicked\n\t */\n\tpublic get customId() {\n\t\treturn this[kData].custom_id;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/LabelComponent.ts",
    "content": "import type { APILabelComponent, ComponentType } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\nimport type { ComponentDataType } from './Component.js';\nimport { Component } from './Component.js';\n\n/**\n * Represents a label component on a modal.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has `Component`s as substructures which need to be instantiated and stored by an extending class using it\n */\nexport class LabelComponent<Omitted extends keyof APILabelComponent | '' = ''> extends Component<\n\tComponentDataType<ComponentType.Label>,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each LabelComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<ComponentDataType<ComponentType.Label>> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the label\n\t */\n\tpublic constructor(data: Partialize<ComponentDataType<ComponentType.Label>, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The label text\n\t */\n\tpublic get label() {\n\t\treturn this[kData].label;\n\t}\n\n\t/**\n\t * An optional description text for the label\n\t */\n\tpublic get description() {\n\t\treturn this[kData].description;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/LabeledButtonComponent.ts",
    "content": "import type { ButtonStyle } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\nimport type { ButtonDataType } from './ButtonComponent.js';\nimport { ButtonComponent } from './ButtonComponent.js';\n\n/**\n * Base class for all buttons that can have a label on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has a substructure `ComponentEmoji` which needs to be instantiated and stored by an extending class using it\n */\nexport abstract class LabeledButtonComponent<\n\tStyle extends Exclude<ButtonStyle, ButtonStyle.Premium>,\n\tOmitted extends keyof ButtonDataType<Style> | '' = '',\n> extends ButtonComponent<Style, Omitted> {\n\t/**\n\t * @param data - The raw data received from the API for the button\n\t */\n\tpublic constructor(data: Partialize<ButtonDataType<Style>, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The label to be displayed on the button\n\t */\n\tpublic get label() {\n\t\treturn this[kData].label;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/LinkButtonComponent.ts",
    "content": "import type { APIButtonComponentWithURL, ButtonStyle } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\nimport { LabeledButtonComponent } from './LabeledButtonComponent.js';\n\n/**\n * Represents a button linking to an URL on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class LinkButtonComponent<\n\tOmitted extends keyof APIButtonComponentWithURL | '' = '',\n> extends LabeledButtonComponent<ButtonStyle.Link, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each LinkButtonComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIButtonComponentWithURL> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the link button\n\t */\n\tpublic constructor(data: Partialize<APIButtonComponentWithURL, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The URL to direct users to when clicked\n\t */\n\tpublic get url() {\n\t\treturn this[kData].url;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/MediaGalleryComponent.ts",
    "content": "import type { APIMediaGalleryComponent } from 'discord-api-types/v10';\nimport type { Partialize } from '../../utils/types.js';\nimport { Component } from './Component.js';\n\n/**\n * Represents a media gallery component on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has `MediaGalleryItem`s as substructures which need to be instantiated and stored by an extending class using it\n */\nexport class MediaGalleryComponent<Omitted extends keyof APIMediaGalleryComponent | '' = ''> extends Component<\n\tAPIMediaGalleryComponent,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each MediaGalleryComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIMediaGalleryComponent> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the media gallery\n\t */\n\tpublic constructor(data: Partialize<APIMediaGalleryComponent, Omitted>) {\n\t\tsuper(data);\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/MediaGalleryItem.ts",
    "content": "import type { APIMediaGalleryItem } from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\n/**\n * Represents an item in a media gallery on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has a substructure `UnfurledMediaItem` which needs to be instantiated and stored by an extending class using it\n */\nexport class MediaGalleryItem<Omitted extends keyof APIMediaGalleryItem | '' = ''> extends Structure<\n\tAPIMediaGalleryItem,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each MediaGalleryItem.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIMediaGalleryItem> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the media gallery item\n\t */\n\tpublic constructor(data: Partialize<APIMediaGalleryItem, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * Alt text for the media\n\t */\n\tpublic get description() {\n\t\treturn this[kData].description;\n\t}\n\n\t/**\n\t * Whether the media should be a spoiler (or blurred out)\n\t */\n\tpublic get spoiler() {\n\t\treturn this[kData].spoiler;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/MentionableSelectMenuComponent.ts",
    "content": "import type { APIMentionableSelectComponent } from 'discord-api-types/v10';\nimport type { Partialize } from '../../utils/types.js';\nimport { SelectMenuComponent } from './SelectMenuComponent.js';\n\n/**\n * Represents a mentionable select menu component.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has `SelectMenuDefaultValue`s as substructures which need to be instantiated and stored by an extending class using it\n */\nexport class MentionableSelectMenuComponent<\n\tOmitted extends keyof APIMentionableSelectComponent | '' = '',\n> extends SelectMenuComponent<APIMentionableSelectComponent, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each MentionableSelectMenuComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIMentionableSelectComponent> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the mentionable select menu\n\t */\n\tpublic constructor(data: Partialize<APIMentionableSelectComponent, Omitted>) {\n\t\tsuper(data);\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/PremiumButtonComponent.ts",
    "content": "import type { APIButtonComponentWithSKUId, ButtonStyle } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\nimport { ButtonComponent } from './ButtonComponent.js';\n\n/**\n * Represents a button used to buy an SKU from a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class PremiumButtonComponent<\n\tOmitted extends keyof APIButtonComponentWithSKUId | '' = '',\n> extends ButtonComponent<ButtonStyle.Premium, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each PremiumButtonComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIButtonComponentWithSKUId> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the premium button\n\t */\n\tpublic constructor(data: Partialize<APIButtonComponentWithSKUId, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id for a purchasable SKU\n\t */\n\tpublic get skuId() {\n\t\treturn this[kData].sku_id;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/RoleSelectMenuComponent.ts",
    "content": "import type { APIRoleSelectComponent } from 'discord-api-types/v10';\nimport type { Partialize } from '../../utils/types.js';\nimport { SelectMenuComponent } from './SelectMenuComponent.js';\n\n/**\n * Represents a role select menu component.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has `SelectMenuDefaultValue`s as substructures which need to be instantiated and stored by an extending class using it\n */\nexport class RoleSelectMenuComponent<\n\tOmitted extends keyof APIRoleSelectComponent | '' = '',\n> extends SelectMenuComponent<APIRoleSelectComponent, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each RoleSelectMenuComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIRoleSelectComponent> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the role select menu\n\t */\n\tpublic constructor(data: Partialize<APIRoleSelectComponent, Omitted>) {\n\t\tsuper(data);\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/SectionComponent.ts",
    "content": "import type { APISectionComponent } from 'discord-api-types/v10';\nimport type { Partialize } from '../../utils/types.js';\nimport { Component } from './Component.js';\n\n/**\n * Represents a section component on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has `Component`s as substructures which need to be instantiated and stored by an extending class using it\n */\nexport class SectionComponent<Omitted extends keyof APISectionComponent | '' = ''> extends Component<\n\tAPISectionComponent,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each SectionComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APISectionComponent> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the section\n\t */\n\tpublic constructor(data: Partialize<APISectionComponent, Omitted>) {\n\t\tsuper(data);\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/SelectMenuComponent.ts",
    "content": "import type { APISelectMenuComponent } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\nimport { Component } from './Component.js';\n\nexport abstract class SelectMenuComponent<\n\tType extends APISelectMenuComponent,\n\tOmitted extends keyof Type | '' = '',\n> extends Component<Type, Omitted> {\n\t/**\n\t * @param data - The raw data received from the API for the select menu\n\t */\n\tpublic constructor(data: Partialize<Type, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The customId to be sent in the interaction when a selection is made\n\t */\n\tpublic get customId() {\n\t\treturn this[kData].custom_id;\n\t}\n\n\t/**\n\t * Whether the select menu is disabled\n\t */\n\tpublic get disabled() {\n\t\treturn this[kData].disabled;\n\t}\n\n\t/**\n\t * The maximum number of items that can be chosen\n\t */\n\tpublic get maxValues() {\n\t\treturn this[kData].max_values;\n\t}\n\n\t/**\n\t * The minimum number of items that must be chosen\n\t */\n\tpublic get minValues() {\n\t\treturn this[kData].min_values;\n\t}\n\n\t/**\n\t * Custom placeholder text if nothing is selected\n\t */\n\tpublic get placeholder() {\n\t\treturn this[kData].placeholder;\n\t}\n\n\t/**\n\t * Whether a selection is required\n\t */\n\tpublic get required() {\n\t\treturn this[kData].required;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/SelectMenuDefaultValue.ts",
    "content": "import type { APISelectMenuDefaultValue, SelectMenuDefaultValueType } from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\nexport class SelectMenuDefaultValue<\n\tType extends SelectMenuDefaultValueType,\n\tOmitted extends keyof APISelectMenuDefaultValue<Type> | '' = '',\n> extends Structure<APISelectMenuDefaultValue<Type>, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each SelectMenuDefaultValue.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APISelectMenuDefaultValue<SelectMenuDefaultValueType>> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the select menu default value\n\t */\n\tpublic constructor(data: Partialize<APISelectMenuDefaultValue<Type>, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\tpublic get type() {\n\t\treturn this[kData].type;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/SeparatorComponent.ts",
    "content": "import type { APISeparatorComponent } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\nimport { Component } from './Component.js';\n\n/**\n * Represents a separator component on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class SeparatorComponent<Omitted extends keyof APISeparatorComponent | '' = ''> extends Component<\n\tAPISeparatorComponent,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each SeparatorComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APISeparatorComponent> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the separator\n\t */\n\tpublic constructor(data: Partialize<APISeparatorComponent, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * Whether a visual divider should be displayed in the component\n\t */\n\tpublic get divider() {\n\t\treturn this[kData].divider;\n\t}\n\n\t/**\n\t * The size of the separator padding\n\t */\n\tpublic get spacing() {\n\t\treturn this[kData].spacing;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/StringSelectMenuComponent.ts",
    "content": "import type { APIStringSelectComponent } from 'discord-api-types/v10';\nimport type { Partialize } from '../../utils/types.js';\nimport { SelectMenuComponent } from './SelectMenuComponent.js';\n\n/**\n * Represents a string select menu component.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has `StringSelectMenuOption`s as substructures which need to be instantiated and stored by an extending class using it\n */\nexport class StringSelectMenuComponent<\n\tOmitted extends keyof APIStringSelectComponent | '' = '',\n> extends SelectMenuComponent<APIStringSelectComponent, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each StringSelectMenuComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIStringSelectComponent> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the string select menu\n\t */\n\tpublic constructor(data: Partialize<APIStringSelectComponent, Omitted>) {\n\t\tsuper(data);\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/StringSelectMenuOption.ts",
    "content": "import type { APISelectMenuOption } from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\n/**\n * Represents an option in a string select menu component.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has a substructure `ComponentEmoji` which needs to be instantiated and stored by an extending class using it\n */\nexport class StringSelectMenuOption<Omitted extends keyof APISelectMenuOption | '' = ''> extends Structure<\n\tAPISelectMenuOption,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each StringSelectMenuOption.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APISelectMenuOption> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the string select menu option\n\t */\n\tpublic constructor(data: Partialize<APISelectMenuOption, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * Whether this option should be already-selected by default\n\t */\n\tpublic get default() {\n\t\treturn this[kData].default;\n\t}\n\n\t/**\n\t * An additional description of the option\n\t */\n\tpublic get description() {\n\t\treturn this[kData].description;\n\t}\n\n\t/**\n\t * The user-facing name of the option\n\t */\n\tpublic get label() {\n\t\treturn this[kData].label;\n\t}\n\n\t/**\n\t * The dev-defined value of the option\n\t */\n\tpublic get value() {\n\t\treturn this[kData].value;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/TextDisplayComponent.ts",
    "content": "import type { APITextDisplayComponent } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\nimport { Component } from './Component.js';\n\n/**\n * Represents a text display component on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class TextDisplayComponent<Omitted extends keyof APITextDisplayComponent | '' = ''> extends Component<\n\tAPITextDisplayComponent,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each TextDisplayComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APITextDisplayComponent> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the text display\n\t */\n\tpublic constructor(data: Partialize<APITextDisplayComponent, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * Text that will be displayed similar to a message\n\t */\n\tpublic get content() {\n\t\treturn this[kData].content;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/TextInputComponent.ts",
    "content": "import type { APITextInputComponent } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\nimport { Component } from './Component.js';\n\n/**\n * Represents a text input component on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class TextInputComponent<Omitted extends keyof APITextInputComponent | '' = ''> extends Component<\n\tAPITextInputComponent,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each TextInputComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APITextInputComponent> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the text input\n\t */\n\tpublic constructor(data: Partialize<APITextInputComponent, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The custom id for the text input\n\t */\n\tpublic get customId() {\n\t\treturn this[kData].custom_id;\n\t}\n\n\t/**\n\t * Text that appears on top of the text input field\n\t */\n\tpublic get label() {\n\t\treturn this[kData].label;\n\t}\n\n\t/**\n\t * The maximal length of text input\n\t */\n\tpublic get maxLength() {\n\t\treturn this[kData].max_length;\n\t}\n\n\t/**\n\t * The minimal length of text input\n\t */\n\tpublic get minLength() {\n\t\treturn this[kData].min_length;\n\t}\n\n\t/**\n\t * The placeholder for the text input\n\t */\n\tpublic get placeholder() {\n\t\treturn this[kData].placeholder;\n\t}\n\n\t/**\n\t * Whether this text input is required\n\t */\n\tpublic get required() {\n\t\treturn this[kData].required;\n\t}\n\n\t/**\n\t * One of text input styles\n\t */\n\tpublic get style() {\n\t\treturn this[kData].style;\n\t}\n\n\t/**\n\t * The pre-filled text in the text input\n\t */\n\tpublic get value() {\n\t\treturn this[kData].value;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/ThumbnailComponent.ts",
    "content": "import type { APIThumbnailComponent } from 'discord-api-types/v10';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\nimport { Component } from './Component.js';\n\n/**\n * Represents a thumbnail component on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has a substructure `UnfurledMediaItem` which needs to be instantiated and stored by an extending class using it\n */\nexport class ThumbnailComponent<Omitted extends keyof APIThumbnailComponent | '' = ''> extends Component<\n\tAPIThumbnailComponent,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each ThumbnailComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIThumbnailComponent> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the thumbnail\n\t */\n\tpublic constructor(data: Partialize<APIThumbnailComponent, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * Alt text for the media\n\t */\n\tpublic get description() {\n\t\treturn this[kData].description;\n\t}\n\n\t/**\n\t * Whether the thumbnail should be a spoiler (or blurred out)\n\t */\n\tpublic get spoiler() {\n\t\treturn this[kData].spoiler;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/UnfurledMediaItem.ts",
    "content": "import type { APIUnfurledMediaItem } from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\n// TODO: add `flags` as a BitField class and appropriate getter, once it gets properly documented\n\n/**\n * Represents a media  item in a component on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class UnfurledMediaItem<Omitted extends keyof APIUnfurledMediaItem | '' = ''> extends Structure<\n\tAPIUnfurledMediaItem,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each UnfurledMediaItem.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIUnfurledMediaItem> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the unfurled media item\n\t */\n\tpublic constructor(data: Partialize<APIUnfurledMediaItem, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id of the uploaded attachment\n\t */\n\tpublic get attachmentId() {\n\t\treturn this[kData].attachment_id;\n\t}\n\n\t/**\n\t * The media type of the content\n\t */\n\tpublic get contentType() {\n\t\treturn this[kData].content_type;\n\t}\n\n\t/**\n\t * The height of the media item (if image)\n\t */\n\tpublic get height() {\n\t\treturn this[kData].height;\n\t}\n\n\t/**\n\t * The proxied URL of the media item\n\t */\n\tpublic get proxyURL() {\n\t\treturn this[kData].proxy_url;\n\t}\n\n\t/**\n\t * Supports arbitrary URLs and attachment:// references\n\t */\n\tpublic get url() {\n\t\treturn this[kData].url;\n\t}\n\n\t/**\n\t * The width of the media item (if image)\n\t */\n\tpublic get width() {\n\t\treturn this[kData].width;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/UserSelectMenuComponent.ts",
    "content": "import type { APIUserSelectComponent } from 'discord-api-types/v10';\nimport type { Partialize } from '../../utils/types.js';\nimport { SelectMenuComponent } from './SelectMenuComponent.js';\n\n/**\n * Represents a user select menu component.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has `SelectMenuDefaultValue`s as substructures which need to be instantiated and stored by an extending class using it\n */\nexport class UserSelectMenuComponent<\n\tOmitted extends keyof APIUserSelectComponent | '' = '',\n> extends SelectMenuComponent<APIUserSelectComponent, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each UserSelectMenuComponent.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIUserSelectComponent> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the user select menu\n\t */\n\tpublic constructor(data: Partialize<APIUserSelectComponent, Omitted>) {\n\t\tsuper(data);\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/components/index.ts",
    "content": "export * from './ActionRowComponent.js';\nexport * from './ButtonComponent.js';\nexport * from './ChannelSelectMenuComponent.js';\nexport * from './Component.js';\nexport * from './ContainerComponent.js';\nexport * from './FileComponent.js';\nexport * from './FileUploadComponent.js';\nexport * from './InteractiveButtonComponent.js';\nexport * from './LinkButtonComponent.js';\nexport * from './MediaGalleryComponent.js';\nexport * from './MentionableSelectMenuComponent.js';\nexport * from './LabeledButtonComponent.js';\nexport * from './PremiumButtonComponent.js';\nexport * from './RoleSelectMenuComponent.js';\nexport * from './SectionComponent.js';\nexport * from './SelectMenuComponent.js';\nexport * from './SeparatorComponent.js';\nexport * from './StringSelectMenuComponent.js';\nexport * from './TextDisplayComponent.js';\nexport * from './TextInputComponent.js';\nexport * from './ThumbnailComponent.js';\nexport * from './UserSelectMenuComponent.js';\n\nexport * from './ComponentEmoji.js';\nexport * from './MediaGalleryItem.js';\nexport * from './SelectMenuDefaultValue.js';\nexport * from './StringSelectMenuOption.js';\nexport * from './UnfurledMediaItem.js';\n"
  },
  {
    "path": "packages/structures/src/messages/embeds/Embed.ts",
    "content": "import type { APIEmbed } from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { dateToDiscordISOTimestamp } from '../../utils/optimization.js';\nimport { kCreatedTimestamp, kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\n/**\n * Represents an embed on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has substructures `EmbedAuthor`, `EmbedFooter`, `EmbedField`, `EmbedImage`, `EmbedThumbnail`, `EmbedProvider`, `EmbedVideo` which need to be instantiated and stored by an extending class using it\n */\nexport class Embed<Omitted extends keyof APIEmbed | '' = ''> extends Structure<APIEmbed, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each Embed.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIEmbed> = {\n\t\tset timestamp(_: string) {},\n\t};\n\n\tprotected [kCreatedTimestamp]: number | null = null;\n\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIEmbed, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.optimizeData}\n\t *\n\t * @internal\n\t */\n\tprotected override optimizeData(data: Partial<APIEmbed>) {\n\t\tif (data.timestamp) {\n\t\t\tthis[kCreatedTimestamp] = Date.parse(data.timestamp);\n\t\t}\n\t}\n\n\t/**\n\t * The color code of the embed\n\t */\n\tpublic get color() {\n\t\treturn this[kData].color;\n\t}\n\n\t/**\n\t * The hexadecimal version of the embed color, with a leading hash\n\t */\n\tpublic get hexColor() {\n\t\tconst color = this.color;\n\t\tif (typeof color !== 'number') return color;\n\t\treturn `#${color.toString(16).padStart(6, '0')}`;\n\t}\n\n\t/**\n\t * The description of the embed\n\t */\n\tpublic get description() {\n\t\treturn this[kData].description;\n\t}\n\n\t/**\n\t * THe title of the embed\n\t */\n\tpublic get title() {\n\t\treturn this[kData].title;\n\t}\n\n\t/**\n\t * The timestamp of the embed content\n\t */\n\tpublic get timestamp() {\n\t\treturn this[kCreatedTimestamp];\n\t}\n\n\t/**\n\t * The type of embed (always \"rich\" for webhook embeds)\n\t */\n\tpublic get type() {\n\t\treturn this[kData].type;\n\t}\n\n\t/**\n\t * The URL of the embed\n\t */\n\tpublic get url() {\n\t\treturn this[kData].url;\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.toJSON}\n\t */\n\tpublic override toJSON() {\n\t\tconst clone = super.toJSON();\n\t\tif (this[kCreatedTimestamp]) {\n\t\t\tclone.timestamp = dateToDiscordISOTimestamp(new Date(this[kCreatedTimestamp]));\n\t\t}\n\n\t\treturn clone;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/embeds/EmbedAuthor.ts",
    "content": "import type { APIEmbedAuthor } from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\n/**\n * Represents author data in an embed on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class EmbedAuthor<Omitted extends keyof APIEmbedAuthor | '' = ''> extends Structure<APIEmbedAuthor, Omitted> {\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIEmbedAuthor, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The name of the author\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * The URL of author icon\n\t */\n\tpublic get iconURL() {\n\t\treturn this[kData].icon_url;\n\t}\n\n\t/**\n\t * A proxied URL of author icon\n\t */\n\tpublic get proxyIconURL() {\n\t\treturn this[kData].proxy_icon_url;\n\t}\n\n\t/**\n\t * The URL of the author\n\t */\n\tpublic get url() {\n\t\treturn this[kData].url;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/embeds/EmbedField.ts",
    "content": "import type { APIEmbedField } from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\n/**\n * Represents a field's data in an embed on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class EmbedField<Omitted extends keyof APIEmbedField | '' = ''> extends Structure<APIEmbedField, Omitted> {\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIEmbedField, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The name of the field\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * The value of the field\n\t */\n\tpublic get value() {\n\t\treturn this[kData].value;\n\t}\n\n\t/**\n\t * Whether this field should display inline\n\t */\n\tpublic get inline() {\n\t\treturn this[kData].inline;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/embeds/EmbedFooter.ts",
    "content": "import type { APIEmbedFooter } from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\n/**\n * Represents footer data in an embed on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class EmbedFooter<Omitted extends keyof APIEmbedFooter | '' = ''> extends Structure<APIEmbedFooter, Omitted> {\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIEmbedFooter, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The footer text\n\t */\n\tpublic get text() {\n\t\treturn this[kData].text;\n\t}\n\n\t/**\n\t * The URL of the footer icon\n\t */\n\tpublic get iconURL() {\n\t\treturn this[kData].icon_url;\n\t}\n\n\t/**\n\t * A proxied URL of the footer icon\n\t */\n\tpublic get proxyIconURL() {\n\t\treturn this[kData].proxy_icon_url;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/embeds/EmbedImage.ts",
    "content": "import type { APIEmbedImage } from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\n/**\n * Represents image data in an embed on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class EmbedImage<Omitted extends keyof APIEmbedImage | '' = ''> extends Structure<APIEmbedImage, Omitted> {\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIEmbedImage, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The height of the image\n\t */\n\tpublic get height() {\n\t\treturn this[kData].height;\n\t}\n\n\t/**\n\t * The width of the image\n\t */\n\tpublic get width() {\n\t\treturn this[kData].width;\n\t}\n\n\t/**\n\t * A proxied URL of the image\n\t */\n\tpublic get proxyURL() {\n\t\treturn this[kData].proxy_url;\n\t}\n\n\t/**\n\t * Source URL of the image\n\t */\n\tpublic get url() {\n\t\treturn this[kData].url;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/embeds/EmbedProvider.ts",
    "content": "import type { APIEmbedProvider } from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\n/**\n * Represents provider data in an embed on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class EmbedProvider<Omitted extends keyof APIEmbedProvider | '' = ''> extends Structure<\n\tAPIEmbedProvider,\n\tOmitted\n> {\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIEmbedProvider, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The name of the provider\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * The URL of the provider\n\t */\n\tpublic get url() {\n\t\treturn this[kData].url;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/embeds/EmbedThumbnail.ts",
    "content": "import type { APIEmbedThumbnail } from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\n/**\n * Represents thumbnail data in an embed on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class EmbedThumbnail<Omitted extends keyof APIEmbedThumbnail | '' = ''> extends Structure<\n\tAPIEmbedThumbnail,\n\tOmitted\n> {\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIEmbedThumbnail, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The height of the thumbnail\n\t */\n\tpublic get height() {\n\t\treturn this[kData].height;\n\t}\n\n\t/**\n\t * The width of the thumbnail\n\t */\n\tpublic get width() {\n\t\treturn this[kData].width;\n\t}\n\n\t/**\n\t * A proxied URL of the thumbnail\n\t */\n\tpublic get proxyURL() {\n\t\treturn this[kData].proxy_url;\n\t}\n\n\t/**\n\t * The source URL of the thumbnail\n\t */\n\tpublic get url() {\n\t\treturn this[kData].url;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/embeds/EmbedVideo.ts",
    "content": "import type { APIEmbedVideo } from 'discord-api-types/v10';\nimport { Structure } from '../../Structure.js';\nimport { kData } from '../../utils/symbols.js';\nimport type { Partialize } from '../../utils/types.js';\n\n/**\n * Represents video data in an embed on a message.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class EmbedVideo<Omitted extends keyof APIEmbedVideo | '' = ''> extends Structure<APIEmbedVideo, Omitted> {\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIEmbedVideo, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The height of the video\n\t */\n\tpublic get height() {\n\t\treturn this[kData].height;\n\t}\n\n\t/**\n\t * The width of the video\n\t */\n\tpublic get width() {\n\t\treturn this[kData].width;\n\t}\n\n\t/**\n\t * A proxied URL of the video\n\t */\n\tpublic get proxyURL() {\n\t\treturn this[kData].proxy_url;\n\t}\n\n\t/**\n\t * The source URL of the video\n\t */\n\tpublic get url() {\n\t\treturn this[kData].url;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/messages/embeds/index.ts",
    "content": "export * from './Embed.js';\nexport * from './EmbedAuthor.js';\nexport * from './EmbedField.js';\nexport * from './EmbedFooter.js';\nexport * from './EmbedImage.js';\nexport * from './EmbedProvider.js';\nexport * from './EmbedThumbnail.js';\nexport * from './EmbedVideo.js';\n"
  },
  {
    "path": "packages/structures/src/messages/index.ts",
    "content": "export * from './components/index.js';\nexport * from './embeds/index.js';\n\nexport * from './ApplicationCommandInteractionMetadata.js';\nexport * from './Attachment.js';\nexport * from './ChannelMention.js';\nexport * from './InteractionMetadata.js';\nexport * from './Message.js';\nexport * from './MessageActivity.js';\nexport * from './MessageCall.js';\nexport * from './MessageComponentInteractionMetadata.js';\nexport * from './MessageReference.js';\nexport * from './ModalSubmitInteractionMetadata.js';\nexport * from './Reaction.js';\nexport * from './ReactionCountDetails.js';\nexport * from './RoleSubscriptionData.js';\n"
  },
  {
    "path": "packages/structures/src/polls/Poll.ts",
    "content": "import type { APIPoll } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { dateToDiscordISOTimestamp } from '../utils/optimization.js';\nimport { kData, kExpiresTimestamp } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents a poll on a message on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has substructures `PollMedia`, `PollAnswer`, `PollResults` which need to be instantiated and stored by an extending class using it\n */\nexport class Poll<Omitted extends keyof APIPoll | '' = ''> extends Structure<APIPoll, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each Poll.\n\t */\n\tpublic static override DataTemplate: Partial<APIPoll> = {\n\t\tset expiry(_: string) {},\n\t};\n\n\t/**\n\t * Optimized storage of {@link discord-api-types/v10#(APIPoll:interface).expiry}\n\t *\n\t * @internal\n\t */\n\tprotected [kExpiresTimestamp]: number | null = null;\n\n\t/**\n\t * @param data - The raw data received from the API for the poll\n\t */\n\tpublic constructor(data: Partialize<APIPoll, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.optimizeData}\n\t *\n\t * @internal\n\t */\n\tprotected override optimizeData(data: Partial<APIPoll>) {\n\t\tif (data.expiry) {\n\t\t\tthis[kExpiresTimestamp] = Date.parse(data.expiry);\n\t\t}\n\t}\n\n\t/**\n\t * Whether a user can select multiple answers\n\t */\n\tpublic get allowMultiselect() {\n\t\treturn this[kData].allow_multiselect;\n\t}\n\n\t/**\n\t * The layout type of the poll\n\t */\n\tpublic get layoutType() {\n\t\treturn this[kData].layout_type;\n\t}\n\n\t/**\n\t * The timestamp this poll will expire at\n\t */\n\tpublic get expiresTimestamp() {\n\t\treturn this[kExpiresTimestamp];\n\t}\n\n\t/**\n\t * The time the poll will expire at\n\t */\n\tpublic get expiresAt() {\n\t\tconst expiresTimestamp = this.expiresTimestamp;\n\t\treturn expiresTimestamp ? new Date(expiresTimestamp) : null;\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.toJSON}\n\t */\n\tpublic override toJSON() {\n\t\tconst clone = super.toJSON();\n\t\tif (this[kExpiresTimestamp]) {\n\t\t\tclone.expiry = dateToDiscordISOTimestamp(new Date(this[kExpiresTimestamp]));\n\t\t}\n\n\t\treturn clone;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/polls/PollAnswer.ts",
    "content": "import type { APIPollAnswer } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents an answer to a poll on a message on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has a substructure `PollMedia` which need to be instantiated and stored by an extending class using it\n */\nexport class PollAnswer<Omitted extends keyof APIPollAnswer | '' = ''> extends Structure<APIPollAnswer, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each PollAnswer.\n\t */\n\tpublic static override DataTemplate: Partial<APIPollAnswer> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the poll answer\n\t */\n\tpublic constructor(data: Partialize<APIPollAnswer, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id of the poll answer\n\t */\n\tpublic get answerId() {\n\t\treturn this[kData].answer_id;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/polls/PollAnswerCount.ts",
    "content": "import type { APIPollAnswerCount } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents the counts of answers to a poll on a message on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class PollAnswerCount<Omitted extends keyof APIPollAnswerCount | '' = ''> extends Structure<\n\tAPIPollAnswerCount,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each PollAnswerCount.\n\t */\n\tpublic static override DataTemplate: Partial<APIPollAnswerCount> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the poll answer count\n\t */\n\tpublic constructor(data: Partialize<APIPollAnswerCount, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id of the poll answer\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The number of votes for this answer\n\t */\n\tpublic get count() {\n\t\treturn this[kData].count;\n\t}\n\n\t/**\n\t * Whether the current user voted for this answer\n\t */\n\tpublic get meVoted() {\n\t\treturn this[kData].me_voted;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/polls/PollMedia.ts",
    "content": "import type { APIPollMedia } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents a field of a poll on a message on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has a substructure `Emoji` which need to be instantiated and stored by an extending class using it\n */\nexport class PollMedia<Omitted extends keyof APIPollMedia | '' = ''> extends Structure<APIPollMedia, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each PollMedia.\n\t */\n\tpublic static override DataTemplate: Partial<APIPollMedia> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the poll media\n\t */\n\tpublic constructor(data: Partialize<APIPollMedia, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The text of the poll field\n\t */\n\tpublic get text() {\n\t\treturn this[kData].text;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/polls/PollResults.ts",
    "content": "import type { APIPollResults } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents the results of a poll on a message on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has a substructure `PollAnswerCount` which need to be instantiated and stored by an extending class using it\n */\nexport class PollResults<Omitted extends keyof APIPollResults | '' = ''> extends Structure<APIPollResults, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each PollResults.\n\t */\n\tpublic static override DataTemplate: Partial<APIPollResults> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the poll results\n\t */\n\tpublic constructor(data: Partialize<APIPollResults, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * Whether the votes have been precisely counted\n\t */\n\tpublic get isFinalized() {\n\t\treturn this[kData].is_finalized;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/polls/index.ts",
    "content": "export * from './Poll.js';\nexport * from './PollAnswer.js';\nexport * from './PollAnswerCount.js';\nexport * from './PollMedia.js';\nexport * from './PollResults.js';\n"
  },
  {
    "path": "packages/structures/src/skus/SKU.ts",
    "content": "import type { SKUFlags, APISKU } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { SKUFlagsBitField } from '../bitfields/SKUFlagsBitField.js';\nimport { kData } from '../utils/symbols.js';\nimport { isFieldSet } from '../utils/type-guards.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents any SKU (stock-keeping units) on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class SKU<Omitted extends keyof APISKU | '' = ''> extends Structure<APISKU, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each SKU\n\t */\n\tpublic static override readonly DataTemplate: Partial<APISKU> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the SKU\n\t */\n\tpublic constructor(data: Partialize<APISKU, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * Id of the SKU\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * Type of SKU\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/sku#sku-object-sku-types}\n\t */\n\tpublic get type() {\n\t\treturn this[kData].type;\n\t}\n\n\t/**\n\t * Id of the parent application\n\t */\n\tpublic get applicationId() {\n\t\treturn this[kData].application_id;\n\t}\n\n\t/**\n\t * Customer-facing name of your premium offering\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * System-generated URL slug based on the SKU's name\n\t */\n\tpublic get slug() {\n\t\treturn this[kData].slug;\n\t}\n\n\t/**\n\t * SKU flags combined as a bitfield\n\t */\n\tpublic get flags() {\n\t\treturn isFieldSet(this[kData], 'flags', 'number') ? new SKUFlagsBitField(this[kData].flags as SKUFlags) : null;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/skus/index.ts",
    "content": "export * from './SKU.js';\n"
  },
  {
    "path": "packages/structures/src/soundboards/SoundboardSound.ts",
    "content": "import { DiscordSnowflake } from '@sapphire/snowflake';\nimport type { APISoundboardSound } from 'discord-api-types/v10';\nimport { Structure } from '../Structure';\nimport { kData } from '../utils/symbols';\nimport { isIdSet } from '../utils/type-guards';\nimport type { Partialize } from '../utils/types';\n\n/**\n * Represents any soundboard sound on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has substructure `User` which needs to be instantiated and stored by an extending class using it\n */\nexport class SoundboardSound<Omitted extends keyof APISoundboardSound | '' = ''> extends Structure<\n\tAPISoundboardSound,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each soundboard sound.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APISoundboardSound> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the soundboard sound\n\t */\n\tpublic constructor(data: Partialize<APISoundboardSound, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The name of this sound\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * The id of this sound\n\t */\n\tpublic get soundId() {\n\t\treturn this[kData].sound_id;\n\t}\n\n\t/**\n\t * The volume of this sound, from 0 to 1\n\t */\n\tpublic get volume() {\n\t\treturn this[kData].volume;\n\t}\n\n\t/**\n\t * The id of this sound's custom emoji\n\t */\n\tpublic get emojiId() {\n\t\treturn this[kData].emoji_id;\n\t}\n\n\t/**\n\t * The unicode character of this sound's standard emoji\n\t */\n\tpublic get emojiName() {\n\t\treturn this[kData].emoji_name;\n\t}\n\n\t/**\n\t * The id of the guild this sound is in\n\t */\n\tpublic get guildId() {\n\t\treturn this[kData].guild_id;\n\t}\n\n\t/**\n\t * Whether this sound can be used, may be false due to loss of server boosts\n\t */\n\tpublic get available() {\n\t\treturn this[kData].available;\n\t}\n\n\t/**\n\t * The timestamp this sound was created at\n\t *\n\t * @remarks only available for guild soundboard sounds\n\t */\n\tpublic get createdTimestamp() {\n\t\treturn isIdSet(this[kData].sound_id) && isIdSet(this[kData].guild_id)\n\t\t\t? DiscordSnowflake.timestampFrom(this[kData].sound_id)\n\t\t\t: null;\n\t}\n\n\t/**\n\t * The time this sound was created at\n\t *\n\t * @remarks only available for guild soundboard sounds\n\t */\n\tpublic get createdAt() {\n\t\tconst createdTimestamp = this.createdTimestamp;\n\n\t\treturn createdTimestamp ? new Date(createdTimestamp) : null;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/soundboards/index.ts",
    "content": "export * from './SoundboardSound.js';\n"
  },
  {
    "path": "packages/structures/src/stageInstances/StageInstance.ts",
    "content": "import { DiscordSnowflake } from '@sapphire/snowflake';\nimport type { APIStageInstance } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport { isIdSet } from '../utils/type-guards.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents any stage instance on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class StageInstance<Omitted extends keyof APIStageInstance | '' = ''> extends Structure<\n\tAPIStageInstance,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each stage instance\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIStageInstance> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the stage instance\n\t */\n\tpublic constructor(data: Partialize<APIStageInstance, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The stage instance's id\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The guild id of the associated stage channel\n\t */\n\tpublic get guildId() {\n\t\treturn this[kData].guild_id;\n\t}\n\n\t/**\n\t * The id of the associated stage channel\n\t */\n\tpublic get channelId() {\n\t\treturn this[kData].channel_id;\n\t}\n\n\t/**\n\t * The topic of the stage instance (1-120 characters)\n\t */\n\tpublic get topic() {\n\t\treturn this[kData].topic;\n\t}\n\n\t/**\n\t * The privacy level of the stage instance\n\t */\n\tpublic get privacyLevel() {\n\t\treturn this[kData].privacy_level;\n\t}\n\n\t/**\n\t * The id of the scheduled event for this stage instance\n\t */\n\tpublic get guildScheduledEventId() {\n\t\treturn this[kData].guild_scheduled_event_id;\n\t}\n\n\t/**\n\t * The timestamp the stage instance was created at\n\t */\n\tpublic get createdTimestamp() {\n\t\treturn isIdSet(this.id) ? DiscordSnowflake.timestampFrom(this.id) : null;\n\t}\n\n\t/**\n\t * The time the stage instance was created at\n\t */\n\tpublic get createdAt() {\n\t\tconst createdTimestamp = this.createdTimestamp;\n\t\treturn createdTimestamp ? new Date(createdTimestamp) : null;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/stageInstances/index.ts",
    "content": "export * from './StageInstance.js';\n"
  },
  {
    "path": "packages/structures/src/stickers/Sticker.ts",
    "content": "import { DiscordSnowflake } from '@sapphire/snowflake';\nimport type { APISticker } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport { isIdSet } from '../utils/type-guards.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents a sticker on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class Sticker<Omitted extends keyof APISticker | '' = ''> extends Structure<APISticker, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each SitckerItem.\n\t */\n\tpublic static override DataTemplate: Partial<APISticker> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the sticker item\n\t */\n\tpublic constructor(data: Partialize<APISticker, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id of the sticker\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The name of the sticker\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * The format type of the sticker\n\t */\n\tpublic get formatType() {\n\t\treturn this[kData].format_type;\n\t}\n\n\t/**\n\t * Whether this guild sticker can be used, may be false due to loss of Server Boosts\n\t */\n\tpublic get available() {\n\t\treturn this[kData].available;\n\t}\n\n\t/**\n\t * The description of the sticker\n\t */\n\tpublic get description() {\n\t\treturn this[kData].description;\n\t}\n\n\t/**\n\t * The autocomplete/suggestion tags for the sticker\n\t */\n\tpublic get tags() {\n\t\treturn this[kData].tags;\n\t}\n\n\t/**\n\t * The type of this sticker\n\t */\n\tpublic get type() {\n\t\treturn this[kData].type;\n\t}\n\n\t/**\n\t * The timestamp the sticker was created at\n\t */\n\tpublic get createdTimestamp() {\n\t\treturn isIdSet(this.id) ? DiscordSnowflake.timestampFrom(this.id) : null;\n\t}\n\n\t/**\n\t * The time the sticker was created at\n\t */\n\tpublic get createdAt() {\n\t\tconst createdTimestamp = this.createdTimestamp;\n\t\treturn createdTimestamp ? new Date(createdTimestamp) : null;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/stickers/StickerPack.ts",
    "content": "import { DiscordSnowflake } from '@sapphire/snowflake';\nimport type { APIStickerPack } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport { isIdSet } from '../utils/type-guards.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents a sticker pack on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has substructure `Sticker` which needs to be instantiated and stored by an extending class using it\n */\nexport class StickerPack<Omitted extends keyof APIStickerPack | '' = ''> extends Structure<APIStickerPack, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each sticker pack\n\t */\n\tpublic static override DataTemplate: Partial<APIStickerPack> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the sticker pack\n\t */\n\tpublic constructor(data: Partialize<APIStickerPack, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id of the sticker pack\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The name of the sticker pack\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * The id of the pack's SKU\n\t */\n\tpublic get skuId() {\n\t\treturn this[kData].sku_id;\n\t}\n\n\t/**\n\t * The id of a sticker in the pack which is shown as the pack's icon\n\t */\n\tpublic get coverStickerId() {\n\t\treturn this[kData].cover_sticker_id;\n\t}\n\n\t/**\n\t * The description of the sticker pack\n\t */\n\tpublic get description() {\n\t\treturn this[kData].description;\n\t}\n\n\t/**\n\t * The id of the sticker pack's banner image\n\t *\n\t * @see {@link https://discord.com/developers/docs/reference#image-formatting}\n\t */\n\tpublic get bannerAssetId() {\n\t\treturn this[kData].banner_asset_id;\n\t}\n\n\t/**\n\t * The timestamp the sticker pack was created at\n\t */\n\tpublic get createdTimestamp() {\n\t\treturn isIdSet(this.id) ? DiscordSnowflake.timestampFrom(this.id) : null;\n\t}\n\n\t/**\n\t * The time the sticker pack was created at\n\t */\n\tpublic get createdAt() {\n\t\tconst createdTimestamp = this.createdTimestamp;\n\t\treturn createdTimestamp ? new Date(createdTimestamp) : null;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/stickers/index.ts",
    "content": "export * from './Sticker.js';\nexport * from './StickerPack.js';\n"
  },
  {
    "path": "packages/structures/src/subscriptions/Subscription.ts",
    "content": "import { DiscordSnowflake } from '@sapphire/snowflake';\nimport type { APISubscription, SubscriptionStatus } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { dateToDiscordISOTimestamp } from '../utils/optimization.js';\nimport {\n\tkData,\n\tkCurrentPeriodStartTimestamp,\n\tkCurrentPeriodEndTimestamp,\n\tkCanceledTimestamp,\n} from '../utils/symbols.js';\nimport { isIdSet } from '../utils/type-guards.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents any subscription on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class Subscription<\n\tOmitted extends keyof APISubscription | '' = 'canceled_at' | 'current_period_end' | 'current_period_start',\n> extends Structure<APISubscription, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each subscription\n\t */\n\tpublic static override readonly DataTemplate: Partial<APISubscription> = {\n\t\tset current_period_start(_: string) {},\n\t\tset current_period_end(_: string) {},\n\t\tset canceled_at(_: string) {},\n\t};\n\n\tprotected [kCurrentPeriodStartTimestamp]: number | null = null;\n\n\tprotected [kCurrentPeriodEndTimestamp]: number | null = null;\n\n\tprotected [kCanceledTimestamp]: number | null = null;\n\n\t/**\n\t * @param data - The raw data received from the API for the subscription\n\t */\n\tpublic constructor(data: Partialize<APISubscription, Omitted>) {\n\t\tsuper(data);\n\t\tthis.optimizeData(data);\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.optimizeData}\n\t */\n\tprotected override optimizeData(data: Partial<APISubscription>) {\n\t\tconst currentPeriodStartTimestamp = data.current_period_start;\n\t\tconst currentPeriodEndTimestamp = data.current_period_end;\n\t\tconst canceledTimestamp = data.canceled_at;\n\n\t\tif (currentPeriodStartTimestamp) {\n\t\t\tthis[kCurrentPeriodStartTimestamp] = Date.parse(currentPeriodStartTimestamp);\n\t\t}\n\n\t\tif (currentPeriodEndTimestamp) {\n\t\t\tthis[kCurrentPeriodEndTimestamp] = Date.parse(currentPeriodEndTimestamp);\n\t\t}\n\n\t\tif (canceledTimestamp) {\n\t\t\tthis[kCanceledTimestamp] = Date.parse(canceledTimestamp);\n\t\t}\n\t}\n\n\t/**\n\t * The subscription's id\n\t *\n\t * @remarks The start of a subscription is determined by its id. When the subscription renews, its current period is updated.\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * Id of the user who is subscribed\n\t */\n\tpublic get userId() {\n\t\treturn this[kData].user_id;\n\t}\n\n\t/**\n\t * List of SKUs subscribed to\n\t */\n\tpublic get skuIds() {\n\t\treturn this[kData].sku_ids;\n\t}\n\n\t/**\n\t * List of entitlements granted for this subscription\n\t */\n\tpublic get entitlementIds() {\n\t\treturn this[kData].entitlement_ids;\n\t}\n\n\t/**\n\t * List of SKUs that this user will be subscribed to at renewal\n\t */\n\tpublic get renewalSkuIds() {\n\t\treturn this[kData].renewal_sku_ids;\n\t}\n\n\t/**\n\t * Timestamp of start of the current subscription period\n\t */\n\tpublic get currentPeriodStartTimestamp() {\n\t\treturn this[kCurrentPeriodStartTimestamp];\n\t}\n\n\t/**\n\t * The time at which the current subscription period will start\n\t */\n\tpublic get currentPeriodStartAt() {\n\t\tconst startTimestamp = this.currentPeriodStartTimestamp;\n\t\treturn startTimestamp ? new Date(startTimestamp) : null;\n\t}\n\n\t/**\n\t * Timestamp of end of the current subscription period\n\t */\n\tpublic get currentPeriodEndTimestamp() {\n\t\treturn this[kCurrentPeriodEndTimestamp];\n\t}\n\n\t/**\n\t * The time at which the current subscription period will end\n\t */\n\tpublic get currentPeriodEndsAt() {\n\t\tconst endTimestamp = this.currentPeriodEndTimestamp;\n\t\treturn endTimestamp ? new Date(endTimestamp) : null;\n\t}\n\n\t/**\n\t * The {@link SubscriptionStatus} of the current subscription\n\t */\n\tpublic get status() {\n\t\treturn this[kData].status;\n\t}\n\n\t/**\n\t * Timestamp when the subscription was canceled\n\t */\n\tpublic get canceledTimestamp() {\n\t\treturn this[kCanceledTimestamp];\n\t}\n\n\t/**\n\t * The time when the subscription was canceled\n\t *\n\t * @remarks This is populated when the {@link Subscription#status} transitions to {@link SubscriptionStatus.Ending}.\n\t */\n\tpublic get canceledAt() {\n\t\tconst canceledTimestamp = this.canceledTimestamp;\n\t\treturn canceledTimestamp ? new Date(canceledTimestamp) : null;\n\t}\n\n\t/**\n\t * ISO3166-1 alpha-2 country code of the payment source used to purchase the subscription. Missing unless queried with a private OAuth scope.\n\t */\n\tpublic get country() {\n\t\treturn this[kData].country;\n\t}\n\n\t/**\n\t * The timestamp the subscription was created at\n\t */\n\tpublic get createdTimestamp() {\n\t\treturn isIdSet(this.id) ? DiscordSnowflake.timestampFrom(this.id) : null;\n\t}\n\n\t/**\n\t * The time the subscription was created at\n\t */\n\tpublic get createdAt() {\n\t\tconst createdTimestamp = this.createdTimestamp;\n\t\treturn createdTimestamp ? new Date(createdTimestamp) : null;\n\t}\n\n\t/**\n\t * {@inheritDoc Structure.toJSON}\n\t */\n\tpublic override toJSON() {\n\t\tconst clone = super.toJSON();\n\n\t\tconst currentPeriodStartTimestamp = this[kCurrentPeriodStartTimestamp];\n\t\tconst currentPeriodEndTimestamp = this[kCurrentPeriodEndTimestamp];\n\t\tconst canceledTimestamp = this[kCanceledTimestamp];\n\n\t\tif (currentPeriodEndTimestamp) {\n\t\t\tclone.current_period_end = dateToDiscordISOTimestamp(new Date(currentPeriodEndTimestamp));\n\t\t}\n\n\t\tif (currentPeriodStartTimestamp) {\n\t\t\tclone.current_period_start = dateToDiscordISOTimestamp(new Date(currentPeriodStartTimestamp));\n\t\t}\n\n\t\tif (canceledTimestamp) {\n\t\t\tclone.canceled_at = dateToDiscordISOTimestamp(new Date(canceledTimestamp));\n\t\t}\n\n\t\treturn clone;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/subscriptions/index.ts",
    "content": "export * from './Subscription.js';\n"
  },
  {
    "path": "packages/structures/src/teams/Team.ts",
    "content": "import { DiscordSnowflake } from '@sapphire/snowflake';\nimport type { APITeam } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport { isIdSet } from '../utils/type-guards.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents any team on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has substructure `TeamMember` which needs to be instantiated and stored by an extending class using it\n */\nexport class Team<Omitted extends keyof APITeam | '' = ''> extends Structure<APITeam, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each team.\n\t */\n\tpublic static override readonly DataTemplate: Partial<APITeam> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the team.\n\t */\n\tpublic constructor(data: Partialize<APITeam, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * Hash of the image of the team's icon\n\t */\n\tpublic get icon() {\n\t\treturn this[kData].icon;\n\t}\n\n\t/**\n\t * The unique id of the team\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * Name of the team\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * User ID of the current team owner\n\t */\n\tpublic get ownerUserId() {\n\t\treturn this[kData].owner_user_id;\n\t}\n\n\t/**\n\t * The timestamp the team was created at\n\t */\n\tpublic get createdTimestamp() {\n\t\treturn isIdSet(this.id) ? DiscordSnowflake.timestampFrom(this.id) : null;\n\t}\n\n\t/**\n\t * The time the team was created at\n\t */\n\tpublic get createdAt() {\n\t\tconst createdTimestamp = this.createdTimestamp;\n\t\treturn createdTimestamp ? new Date(createdTimestamp) : null;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/teams/TeamMember.ts",
    "content": "import type { APITeamMember } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents any team member on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has substructure `User` which needs to be instantiated and stored by an extending class using it\n */\nexport class TeamMember<Omitted extends keyof APITeamMember | '' = ''> extends Structure<APITeamMember, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each team member\n\t */\n\tpublic static override readonly DataTemplate: Partial<APITeamMember> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the team member\n\t */\n\tpublic constructor(data: Partialize<APITeamMember, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * User's membership state on the team\n\t *\n\t * @see {@link https://discord.com/developers/docs/topics/teams#data-models-membership-state-enum}\n\t */\n\tpublic get membershipState() {\n\t\treturn this[kData].membership_state;\n\t}\n\n\t/**\n\t * Id of the parent team of which they are a member\n\t */\n\tpublic get teamId() {\n\t\treturn this[kData].team_id;\n\t}\n\n\t/**\n\t * Role of the team member\n\t *\n\t * @see {@link https://discord.com/developers/docs/topics/teams#team-member-roles-team-member-role-types}\n\t */\n\tpublic get role() {\n\t\treturn this[kData].role;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/teams/index.ts",
    "content": "export * from './Team.js';\nexport * from './TeamMember.js';\n"
  },
  {
    "path": "packages/structures/src/users/AvatarDecorationData.ts",
    "content": "import type { APIAvatarDecorationData } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents metadata of an avatar decoration of a User.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class AvatarDecorationData<Omitted extends keyof APIAvatarDecorationData | '' = ''> extends Structure<\n\tAPIAvatarDecorationData,\n\tOmitted\n> {\n\t/**\n\t * The template used for removing data from the raw data stored for each Connection\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIAvatarDecorationData> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIAvatarDecorationData, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id of the SKU this avatar decoration is part of.\n\t */\n\tpublic get skuId() {\n\t\treturn this[kData].sku_id;\n\t}\n\n\t/**\n\t * The asset of this avatar decoration.\n\t */\n\tpublic get asset() {\n\t\treturn this[kData].asset;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/users/Connection.ts",
    "content": "import type { APIConnection } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents a user's connection on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class Connection<Omitted extends keyof APIConnection | '' = ''> extends Structure<APIConnection, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each Connection\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIConnection> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the connection\n\t */\n\tpublic constructor(data: Partialize<APIConnection, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id of the connection account\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The username of the connection account\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * The type of service this connection is for\n\t */\n\tpublic get type() {\n\t\treturn this[kData].type;\n\t}\n\n\t/**\n\t * Whether the connection is revoked\n\t */\n\tpublic get revoked() {\n\t\treturn this[kData].revoked ?? false;\n\t}\n\n\t/**\n\t * Whether the connection is verified\n\t */\n\tpublic get verified() {\n\t\treturn this[kData].verified;\n\t}\n\n\t/**\n\t * Whether friend sync is enabled for this connection\n\t */\n\tpublic get friendSync() {\n\t\treturn this[kData].friend_sync;\n\t}\n\n\t/**\n\t * Whether activities related to this connection are shown in the users presence\n\t */\n\tpublic get showActivity() {\n\t\treturn this[kData].show_activity;\n\t}\n\n\t/**\n\t * Whether this connection has an Oauth2 token for console voice transfer\n\t */\n\tpublic get twoWayLink() {\n\t\treturn this[kData].two_way_link;\n\t}\n\n\t/**\n\t * The visibility state for this connection\n\t */\n\tpublic get visibility() {\n\t\treturn this[kData].visibility;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/users/User.ts",
    "content": "import { DiscordSnowflake } from '@sapphire/snowflake';\nimport type { APIUser } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport { isIdSet } from '../utils/type-guards.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents any user on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has a substructure `AvatarDecorationData`, which needs to be instantiated and stored by an extending class using it\n */\nexport class User<Omitted extends keyof APIUser | '' = ''> extends Structure<APIUser, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each User\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIUser> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the user\n\t */\n\tpublic constructor(data: Partialize<APIUser, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The user's id\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The username of the user\n\t */\n\tpublic get username() {\n\t\treturn this[kData].username;\n\t}\n\n\t/**\n\t * The user's 4 digit tag, if a bot\n\t */\n\tpublic get discriminator() {\n\t\treturn this[kData].discriminator;\n\t}\n\n\t/**\n\t * The user's display name, the application name for bots\n\t */\n\tpublic get globalName() {\n\t\treturn this[kData].global_name;\n\t}\n\n\t/**\n\t * The name displayed in the client for this user when no nickname is set\n\t */\n\tpublic get displayName() {\n\t\treturn this.globalName ?? this.username;\n\t}\n\n\t/**\n\t * The user avatar's hash\n\t */\n\tpublic get avatar() {\n\t\treturn this[kData].avatar;\n\t}\n\n\t/**\n\t * Whether the user is a bot\n\t */\n\tpublic get bot() {\n\t\treturn this[kData].bot ?? false;\n\t}\n\n\t/**\n\t * Whether the user is an Official Discord System user\n\t */\n\tpublic get system() {\n\t\treturn this[kData].system ?? false;\n\t}\n\n\t/**\n\t * Whether the user has mfa enabled\n\t *\n\t * @remarks This property is only set when the user was fetched with an OAuth2 token and the `identify` scope\n\t */\n\tpublic get mfaEnabled() {\n\t\treturn this[kData].mfa_enabled;\n\t}\n\n\t/**\n\t * The user's banner hash\n\t *\n\t * @remarks This property is only set when the user was manually fetched\n\t */\n\tpublic get banner() {\n\t\treturn this[kData].banner;\n\t}\n\n\t/**\n\t * The base 10 accent color of the user's banner\n\t *\n\t * @remarks This property is only set when the user was manually fetched\n\t */\n\tpublic get accentColor() {\n\t\treturn this[kData].accent_color;\n\t}\n\n\t/**\n\t * The user's primary Discord language\n\t *\n\t * @remarks This property is only set when the user was fetched with an Oauth2 token and the `identify` scope\n\t */\n\tpublic get locale() {\n\t\treturn this[kData].locale;\n\t}\n\n\t/**\n\t * Whether the email on the user's account has been verified\n\t *\n\t * @remarks This property is only set when the user was fetched with an OAuth2 token and the `email` scope\n\t */\n\tpublic get verified() {\n\t\treturn this[kData].verified;\n\t}\n\n\t/**\n\t * The user's email\n\t *\n\t * @remarks This property is only set when the user was fetched with an OAuth2 token and the `email` scope\n\t */\n\tpublic get email() {\n\t\treturn this[kData].email;\n\t}\n\n\t/**\n\t * The type of nitro subscription on the user's account\n\t *\n\t * @remarks This property is only set when the user was fetched with an OAuth2 token and the `identify` scope\n\t */\n\tpublic get premiumType() {\n\t\treturn this[kData].premium_type;\n\t}\n\n\t/**\n\t * The timestamp the user was created at\n\t */\n\tpublic get createdTimestamp() {\n\t\treturn isIdSet(this.id) ? DiscordSnowflake.timestampFrom(this.id) : null;\n\t}\n\n\t/**\n\t * The time the user was created at\n\t */\n\tpublic get createdAt() {\n\t\tconst createdTimestamp = this.createdTimestamp;\n\t\treturn createdTimestamp ? new Date(createdTimestamp) : null;\n\t}\n\n\t/**\n\t * The hexadecimal version of the user accent color, with a leading hash\n\t *\n\t * @remarks This property is only set when the user was manually fetched\n\t */\n\tpublic get hexAccentColor() {\n\t\tconst accentColor = this.accentColor;\n\t\tif (typeof accentColor !== 'number') return accentColor;\n\t\treturn `#${accentColor.toString(16).padStart(6, '0')}`;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/users/index.ts",
    "content": "export * from './AvatarDecorationData.js';\nexport * from './User.js';\nexport * from './Connection.js';\n"
  },
  {
    "path": "packages/structures/src/utils/optimization.ts",
    "content": "export function extendTemplate<SuperTemplate extends Record<string, unknown>>(\n\tsuperTemplate: SuperTemplate,\n\tadditions: Record<string, unknown>,\n): Record<string, unknown> & SuperTemplate {\n\treturn Object.defineProperties(additions, Object.getOwnPropertyDescriptors(superTemplate)) as Record<\n\t\tstring,\n\t\tunknown\n\t> &\n\t\tSuperTemplate;\n}\n\n/**\n * Turns a JavaScript Date object into the timestamp format used by Discord in payloads.\n * E.g. `2025-11-16T14:09:25.239000+00:00`\n *\n * @private\n * @param date a Date instance\n * @returns an ISO8601 timestamp with microseconds precision and explicit +00:00 timezone\n */\nexport function dateToDiscordISOTimestamp(date: Date) {\n\treturn `${date.getUTCFullYear()}-${(date.getUTCMonth() + 1).toString().padStart(2, '0')}-${date.getUTCDate().toString().padStart(2, '0')}T${date.getUTCHours().toString().padStart(2, '0')}:${date.getUTCMinutes().toString().padStart(2, '0')}:${date.getUTCSeconds().toString().padStart(2, '0')}.${date.getUTCMilliseconds().toString().padEnd(6, '0')}+00:00`;\n}\n"
  },
  {
    "path": "packages/structures/src/utils/symbols.ts",
    "content": "export const kData = Symbol.for('djs.structures.data');\nexport const kClone = Symbol.for('djs.structures.clone');\nexport const kPatch = Symbol.for('djs.structures.patch');\nexport const kExpiresTimestamp = Symbol.for('djs.structures.expiresTimestamp');\nexport const kEndedTimestamp = Symbol.for('djs.structures.endedTimestamp');\nexport const kCreatedTimestamp = Symbol.for('djs.structures.createdTimestamp');\nexport const kEditedTimestamp = Symbol.for('djs.structures.editedTimestamp');\nexport const kArchiveTimestamp = Symbol.for('djs.structures.archiveTimestamp');\n\nexport const kStartsTimestamp = Symbol.for('djs.structures.startsTimestamp');\nexport const kEndsTimestamp = Symbol.for('djs.structures.endsTimestamp');\n\nexport const kCurrentPeriodStartTimestamp = Symbol.for('djs.structures.currentPeriodStartTimestamp');\nexport const kCurrentPeriodEndTimestamp = Symbol.for('djs.structures.currentPeriodEndTimestamp');\nexport const kCanceledTimestamp = Symbol.for('djs.structures.canceledTimestamp');\n\nexport const kAllow = Symbol.for('djs.structures.allow');\nexport const kDeny = Symbol.for('djs.structures.deny');\n\nexport const kBurstColors = Symbol.for('djs.structures.burstColors');\n\nexport const kLastPinTimestamp = Symbol.for('djs.structures.lastPinTimestamp');\n\nexport const kMixinConstruct = Symbol.for('djs.structures.mixin.construct');\nexport const kMixinToJSON = Symbol.for('djs.structures.mixin.toJSON');\n"
  },
  {
    "path": "packages/structures/src/utils/type-guards.ts",
    "content": "export function isIdSet(id: unknown): id is bigint | string {\n\treturn typeof id === 'string' || typeof id === 'bigint';\n}\n\ninterface TypeMap {\n\tbigint: bigint;\n\tboolean: boolean;\n\tfunction(...args: any[]): unknown;\n\tnumber: number;\n\tobject: object;\n\tstring: string;\n\tsymbol: symbol;\n\tundefined: undefined;\n}\n\nexport type TypeofType = keyof TypeMap;\n\nfunction hasProperty<Value extends object, Key extends string>(\n\tdata: Value,\n\tfieldName: Key,\n): data is Record<Key, unknown> & Value {\n\treturn fieldName in data;\n}\n\nexport function isFieldSet<Value extends object, Key extends string, Type extends TypeofType>(\n\tdata: Value,\n\tfieldName: Key,\n\ttype: Type,\n): data is Record<Key, TypeMap[Type]> & Value {\n\t// eslint-disable-next-line valid-typeof\n\treturn hasProperty(data, fieldName) && typeof data[fieldName] === type;\n}\n"
  },
  {
    "path": "packages/structures/src/utils/types.ts",
    "content": "export type ReplaceOmittedWithUnknown<Omitted extends keyof Data | '', Data> = {\n\t[Key in keyof Data]: Key extends Omitted ? unknown : Data[Key];\n};\n\nexport type CollapseUnion<Type> = Type extends infer Union ? { [Key in keyof Union]: Union[Key] } : never;\n\nexport type OptionalPropertyNames<Type> = {\n\t[Key in keyof Type]-?: {} extends { [Prop in Key]: Type[Key] } ? Key : never;\n}[keyof Type];\n\nexport type MergePrototype<Class1, Class2> = Pick<Class1, Exclude<keyof Class1, keyof Class2>> &\n\tPick<Class2, Exclude<keyof Class2, OptionalPropertyNames<Class2>>> &\n\tPick<Class2, Exclude<OptionalPropertyNames<Class2>, keyof Class1>> & {\n\t\t[Prop in OptionalPropertyNames<Class2> & keyof Class1]: Class1[Prop] | Exclude<Class2[Prop], undefined>;\n\t};\n\nexport type MergePrototypes<ClassArray extends readonly unknown[]> = ClassArray extends [infer Class1]\n\t? Class1\n\t: ClassArray extends [infer Class1, ...infer Rest]\n\t\t? MergePrototype<Class1, MergePrototypes<Rest>>\n\t\t: never;\n\nexport interface RecursiveReadonlyArray<ItemType> extends ReadonlyArray<ItemType | RecursiveReadonlyArray<ItemType>> {}\n\nexport type EnumLike<Enum, Value> = Record<keyof Enum, Value>;\n\nexport type If<Check, Value, True, False = never> = Check extends Value ? (Value extends Check ? True : False) : False;\n\nexport type NonAbstract<Type extends abstract new (...args: any) => any> = Type extends abstract new (\n\t...args: infer Args\n) => infer Instance\n\t? Pick<Type, keyof Type> & (new (...args: Args) => Instance)\n\t: never;\n\nexport type Partialize<Type, Omitted extends keyof Type | ''> = Omit<Type, Omitted> &\n\tPartial<Pick<Type, Exclude<Omitted, ''>>>;\n"
  },
  {
    "path": "packages/structures/src/voice/VoiceRegion.ts",
    "content": "import type { APIVoiceRegion } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents any voice region on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n */\nexport class VoiceRegion<Omitted extends keyof APIVoiceRegion | '' = ''> extends Structure<APIVoiceRegion, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each voice region\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIVoiceRegion> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the voice region\n\t */\n\tpublic constructor(data: Partialize<APIVoiceRegion, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * Unique id for the region\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * Name of the region\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * `true` for a single server that is closest to the current user's client\n\t */\n\tpublic get optimal() {\n\t\treturn this[kData].optimal;\n\t}\n\n\t/**\n\t * Whether this is a deprecated voice region (avoid switching to these)\n\t */\n\tpublic get deprecated() {\n\t\treturn this[kData].deprecated;\n\t}\n\n\t/**\n\t * Whether this is a custom voice region (used for events/etc)\n\t */\n\tpublic get custom() {\n\t\treturn this[kData].custom;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/voice/VoiceState.ts",
    "content": "import type { APIVoiceState } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents any voice state on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has substructure `GuildMember` which needs to be instantiated and stored by an extending class using it\n */\nexport class VoiceState<Omitted extends keyof APIVoiceState | '' = ''> extends Structure<APIVoiceState, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each voice state\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIVoiceState> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the voice state\n\t */\n\tpublic constructor(data: Partialize<APIVoiceState, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The guild id this voice state is for\n\t */\n\tpublic get guildId() {\n\t\treturn this[kData].guild_id;\n\t}\n\n\t/**\n\t * The channel id this user is connected to\n\t */\n\tpublic get channelId() {\n\t\treturn this[kData].channel_id;\n\t}\n\n\t/**\n\t * The user id this voice state is for\n\t */\n\tpublic get userId() {\n\t\treturn this[kData].user_id;\n\t}\n\n\t/**\n\t * The session id for this voice state\n\t */\n\tpublic get sessionId() {\n\t\treturn this[kData].session_id;\n\t}\n\n\t/**\n\t * Whether this user is deafened by the server\n\t */\n\tpublic get deaf() {\n\t\treturn this[kData].deaf;\n\t}\n\n\t/**\n\t * Whether this user is muted by the server\n\t */\n\tpublic get mute() {\n\t\treturn this[kData].mute;\n\t}\n\n\t/**\n\t * Whether this user is locally deafened\n\t */\n\tpublic get selfDeaf() {\n\t\treturn this[kData].self_deaf;\n\t}\n\n\t/**\n\t * Whether this user is locally muted\n\t */\n\tpublic get selfMute() {\n\t\treturn this[kData].self_mute;\n\t}\n\n\t/**\n\t * Whether this user is streaming using \"Go Live\"\n\t */\n\tpublic get selfStream() {\n\t\treturn this[kData].self_stream;\n\t}\n\n\t/**\n\t * Whether this user's camera is enabled\n\t */\n\tpublic get selfVideo() {\n\t\treturn this[kData].self_video;\n\t}\n\n\t/**\n\t * Whether this user's permission to speak is denied\n\t */\n\tpublic get suppress() {\n\t\treturn this[kData].suppress;\n\t}\n\n\t/**\n\t * The time at which the user requested to speak\n\t */\n\tpublic get requestToSpeakTimestamp() {\n\t\treturn this[kData].request_to_speak_timestamp;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/voice/index.ts",
    "content": "export * from './VoiceState.js';\nexport * from './VoiceRegion.js';\n"
  },
  {
    "path": "packages/structures/src/webhooks/Webhook.ts",
    "content": "import { DiscordSnowflake } from '@sapphire/snowflake';\nimport type { APIWebhook } from 'discord-api-types/v10';\nimport { Structure } from '../Structure.js';\nimport { kData } from '../utils/symbols.js';\nimport { isIdSet } from '../utils/type-guards.js';\nimport type { Partialize } from '../utils/types.js';\n\n/**\n * Represents any webhook on Discord.\n *\n * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`\n * @remarks has substructures `User`, `Guild`, `Channel` which need to be instantiated and stored by an extending class using it\n */\nexport class Webhook<Omitted extends keyof APIWebhook | '' = ''> extends Structure<APIWebhook, Omitted> {\n\t/**\n\t * The template used for removing data from the raw data stored for each webhook\n\t */\n\tpublic static override readonly DataTemplate: Partial<APIWebhook> = {};\n\n\t/**\n\t * @param data - The raw data received from the API for the webhook\n\t */\n\tpublic constructor(data: Partialize<APIWebhook, Omitted>) {\n\t\tsuper(data);\n\t}\n\n\t/**\n\t * The id of the webhook\n\t */\n\tpublic get id() {\n\t\treturn this[kData].id;\n\t}\n\n\t/**\n\t * The type of the webhook\n\t *\n\t * @see {@link https://discord.com/developers/docs/resources/webhook#webhook-object-webhook-types}\n\t */\n\tpublic get type() {\n\t\treturn this[kData].type;\n\t}\n\n\t/**\n\t * The guild id this webhook is for, if any\n\t */\n\tpublic get guildId() {\n\t\treturn this[kData].guild_id;\n\t}\n\n\t/**\n\t * The channel id this webhook is for, if any\n\t */\n\tpublic get channelId() {\n\t\treturn this[kData].channel_id;\n\t}\n\n\t/**\n\t * The default name of the webhook\n\t */\n\tpublic get name() {\n\t\treturn this[kData].name;\n\t}\n\n\t/**\n\t * The default user avatar hash of the webhook\n\t *\n\t * @see {@link https://discord.com/developers/docs/reference#image-formatting}\n\t */\n\tpublic get avatar() {\n\t\treturn this[kData].avatar;\n\t}\n\n\t/**\n\t * The secure token of the webhook (returned for incoming webhooks)\n\t */\n\tpublic get token() {\n\t\treturn this[kData].token;\n\t}\n\n\t/**\n\t * The id of the bot/OAuth2 application that created this webhook\n\t */\n\tpublic get applicationId() {\n\t\treturn this[kData].application_id;\n\t}\n\n\t/**\n\t * The url used for executing the webhook (returned by the webhooks OAuth2 flow)\n\t */\n\tpublic get url() {\n\t\treturn this[kData].url;\n\t}\n\n\t/**\n\t * The timestamp the webhook was created at\n\t */\n\tpublic get createdTimestamp() {\n\t\treturn isIdSet(this.id) ? DiscordSnowflake.timestampFrom(this.id) : null;\n\t}\n\n\t/**\n\t * The time the webhook was created at\n\t */\n\tpublic get createdAt() {\n\t\tconst createdTimestamp = this.createdTimestamp;\n\t\treturn createdTimestamp ? new Date(createdTimestamp) : null;\n\t}\n}\n"
  },
  {
    "path": "packages/structures/src/webhooks/index.ts",
    "content": "export * from './Webhook.js';\n"
  },
  {
    "path": "packages/structures/tsconfig.docs.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.docs.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist-docs\"\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/structures/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/structures/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"],\n\t\"compilerOptions\": {\n\t\t\"experimentalDecorators\": false\n\t}\n}\n"
  },
  {
    "path": "packages/structures/tsconfig.test.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"noEmit\": true,\n\t\t\"skipLibCheck\": true\n\t},\n\t\"include\": [\"__tests__/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/structures/tsup.config.ts",
    "content": "import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector';\nimport { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tesbuildPlugins: [esbuildPluginVersionInjector()],\n});\n"
  },
  {
    "path": "packages/ui/.cliff-jumperrc.json",
    "content": "{\n\t\"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n\t\"name\": \"ui\",\n\t\"org\": \"discordjs\",\n\t\"packagePath\": \"packages/ui\",\n\t\"identifierBase\": false\n}\n"
  },
  {
    "path": "packages/ui/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\nstorybook-static\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/ui/.lintstagedrc.cjs",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/ui/.prettierignore",
    "content": ".turbo\ncoverage\ndist\nstorybook-static\ntsup.config.bundled*\nvite.config.ts.timestamp*\n"
  },
  {
    "path": "packages/ui/.prettierrc.cjs",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/ui/.storybook/main.ts",
    "content": "import type { StorybookConfig } from '@storybook/react-vite';\n\nexport default {\n\tstories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n\taddons: ['@storybook/addon-links', '@storybook/addon-themes', '@storybook/addon-docs'],\n\tcore: {\n\t\tbuilder: '@storybook/builder-vite',\n\t},\n\tframework: {\n\t\tname: '@storybook/react-vite',\n\t\toptions: {},\n\t},\n} satisfies StorybookConfig;\n"
  },
  {
    "path": "packages/ui/.storybook/preview.css",
    "content": "html {\n\tcolor-scheme: light;\n}\n\nhtml.dark {\n\tcolor-scheme: dark;\n}\n"
  },
  {
    "path": "packages/ui/.storybook/preview.ts",
    "content": "import type { Preview } from '@storybook/react';\nimport { withThemeByClassName } from '@storybook/addon-themes';\n\nimport '@unocss/reset/tailwind-compat.css';\nimport './preview.css';\nimport 'virtual:uno.css';\n\nexport default {\n\tparameters: {\n\t\tactions: { argTypesRegex: '^on[A-Z].*' },\n\t\tcontrols: {\n\t\t\tmatchers: {\n\t\t\t\tcolor: /(background|color)$/i,\n\t\t\t\tdate: /Date$/,\n\t\t\t},\n\t\t},\n\t},\n} satisfies Preview;\n\nexport const decorators = [\n\twithThemeByClassName({\n\t\tthemes: {\n\t\t\tlight: 'bg-light-600',\n\t\t\tdark: 'dark bg-dark-600',\n\t\t},\n\t\tdefaultTheme: 'light',\n\t}),\n];\n"
  },
  {
    "path": "packages/ui/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/ui/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested.  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/ui\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/ui/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"@discordjs/ui-components@[0-9]*\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/ui/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/ui\",\n\t\"private\": true,\n\t\"version\": \"0.1.0\",\n\t\"description\": \"\",\n\t\"scripts\": {\n\t\t\"build\": \"tsc --noEmit && vite build\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src\",\n\t\t\"prepack\": \"pnpm run build && pnpm run lint\",\n\t\t\"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/ui/*'\",\n\t\t\"release\": \"cliff-jumper\",\n\t\t\"storybook\": \"storybook dev -p 6006\",\n\t\t\"build-storybook\": \"storybook build\",\n\t\t\"chromatic\": \"chromatic\"\n\t},\n\t\"type\": \"module\",\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t}\n\t\t}\n\t},\n\t\"module\": \"./dist/index.js\",\n\t\"types\": \"./dist/index.d.ts\",\n\t\"sideEffects\": false,\n\t\"directories\": {\n\t\t\"lib\": \"src\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/ui\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"@ariakit/react\": \"^0.4.21\",\n\t\t\"@react-icons/all-files\": \"^4.1.0\",\n\t\t\"react\": \"^19.2.4\",\n\t\t\"react-dom\": \"^19.2.4\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@react-icons/all-files\": \"^4.1.0\",\n\t\t\"@storybook/addon-docs\": \"^10.2.10\",\n\t\t\"@storybook/addon-links\": \"^10.2.10\",\n\t\t\"@storybook/addon-themes\": \"^10.2.10\",\n\t\t\"@storybook/builder-vite\": \"^10.2.10\",\n\t\t\"@storybook/react\": \"^10.2.10\",\n\t\t\"@storybook/react-vite\": \"^10.2.10\",\n\t\t\"@types/node\": \"^24.10.13\",\n\t\t\"@types/react\": \"^19.2.14\",\n\t\t\"@types/react-dom\": \"^19.2.3\",\n\t\t\"@unocss/eslint-plugin\": \"^66.6.0\",\n\t\t\"@unocss/reset\": \"^66.6.0\",\n\t\t\"@vitejs/plugin-react\": \"^5.1.4\",\n\t\t\"chromatic\": \"^13.3.5\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"prop-types\": \"^15.8.1\",\n\t\t\"storybook\": \"^10.2.10\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"unocss\": \"^66.6.0\",\n\t\t\"vite\": \"^7.3.1\",\n\t\t\"vite-plugin-dts\": \"^4.5.4\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/Alert.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react';\nimport { Alert } from './Alert.jsx';\n\nexport default {\n\ttitle: 'Alert',\n\tcomponent: Alert,\n\ttags: ['autodocs'],\n} satisfies Meta<typeof Alert>;\n\ntype Story = StoryObj<typeof Alert>;\n\nexport const Default = {\n\trender: ({ children, ...args }) => <Alert {...args}>{children}</Alert>,\n\targs: {\n\t\ttype: 'info',\n\t\ttitle: 'Test',\n\t\tchildren: 'Test Content',\n\t},\n} satisfies Story;\n"
  },
  {
    "path": "packages/ui/src/lib/components/Alert.tsx",
    "content": "import { VscFlame } from '@react-icons/all-files/vsc/VscFlame';\nimport { VscInfo } from '@react-icons/all-files/vsc/VscInfo';\nimport { VscWarning } from '@react-icons/all-files/vsc/VscWarning';\nimport type { PropsWithChildren } from 'react';\n\nexport interface IAlert {\n\treadonly title?: string | undefined;\n\treadonly type: 'danger' | 'info' | 'success' | 'warning';\n}\n\nfunction resolveType(type: IAlert['type']) {\n\tswitch (type) {\n\t\tcase 'danger': {\n\t\t\treturn {\n\t\t\t\ttext: 'text-red-500',\n\t\t\t\tborder: 'border-red-500',\n\t\t\t\ticon: <VscWarning size={20} />,\n\t\t\t};\n\t\t}\n\n\t\tcase 'info': {\n\t\t\treturn {\n\t\t\t\ttext: 'text-blue-500',\n\t\t\t\tborder: 'border-blue-500',\n\t\t\t\ticon: <VscInfo size={20} />,\n\t\t\t};\n\t\t}\n\n\t\tcase 'success': {\n\t\t\treturn {\n\t\t\t\ttext: 'text-green-500',\n\t\t\t\tborder: 'border-green-500',\n\t\t\t\ticon: <VscFlame size={20} />,\n\t\t\t};\n\t\t}\n\n\t\tcase 'warning': {\n\t\t\treturn {\n\t\t\t\ttext: 'text-yellow-500',\n\t\t\t\tborder: 'border-yellow-500',\n\t\t\t\ticon: <VscWarning size={20} />,\n\t\t\t};\n\t\t}\n\t}\n}\n\nexport function Alert({ title, type, children }: PropsWithChildren<IAlert>) {\n\tconst { text, border, icon } = resolveType(type);\n\n\treturn (\n\t\t<div className=\"mb-4 mt-6\">\n\t\t\t<div className=\"relative flex\">\n\t\t\t\t<div className=\"p-4\">{children}</div>\n\t\t\t\t<div className=\"pointer-events-none absolute h-full w-full flex\">\n\t\t\t\t\t<div className={`w-4 shrink-0 border-b-2 border-l-2 border-t-2 rounded-bl-1.5 rounded-tl-1.5 ${border}`} />\n\t\t\t\t\t<div className={`relative border-b-2 ${border}`}>\n\t\t\t\t\t\t<div className={`pointer-events-auto flex place-items-center gap-2 px-2 -translate-y-50% ${text}`}>\n\t\t\t\t\t\t\t{icon}\n\t\t\t\t\t\t\t{title ? <span className={`font-semibold ${text}`}>{title}</span> : null}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className={`flex-1 border-b-2 border-r-2 border-t-2 rounded-br-1.5 rounded-tr-1.5 ${border}`} />\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/Section.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react';\nimport { Section } from './Section.jsx';\n\nexport default {\n\ttitle: 'Section',\n\tcomponent: Section,\n\ttags: ['autodocs'],\n} satisfies Meta<typeof Section>;\n\ntype Story = StoryObj<typeof Section>;\n\nexport const Default = {\n\trender: ({ children, ...args }) => <Section {...args}>{children}</Section>,\n\targs: {\n\t\ttitle: 'Test',\n\t\tchildren: 'Test Content',\n\t},\n} satisfies Story;\n"
  },
  {
    "path": "packages/ui/src/lib/components/Section.tsx",
    "content": "'use client';\n\nimport { Disclosure, DisclosureContent, useDisclosureStore } from '@ariakit/react/disclosure';\nimport { VscChevronDown } from '@react-icons/all-files/vsc/VscChevronDown';\nimport type { JSX, PropsWithChildren } from 'react';\n\nexport interface SectionOptions {\n\treadonly background?: boolean | undefined;\n\treadonly buttonClassName?: string;\n\treadonly className?: string;\n\treadonly defaultClosed?: boolean | undefined;\n\treadonly gutter?: boolean | undefined;\n\treadonly icon?: JSX.Element | undefined;\n\treadonly padded?: boolean | undefined;\n\treadonly title: string;\n}\n\nexport function Section({\n\ttitle,\n\ticon,\n\tpadded = false,\n\tdefaultClosed = false,\n\tbackground = false,\n\tgutter = false,\n\tchildren,\n\tclassName = '',\n\tbuttonClassName = '',\n}: PropsWithChildren<SectionOptions>) {\n\tconst disclosure = useDisclosureStore({ defaultOpen: !defaultClosed });\n\tconst disclosureState = disclosure.getState();\n\n\treturn (\n\t\t<div className={`flex flex-col ${className}`}>\n\t\t\t<Disclosure\n\t\t\t\tclassName={\n\t\t\t\t\tbuttonClassName\n\t\t\t\t\t\t? buttonClassName\n\t\t\t\t\t\t: 'hover:bg-light-800 active:bg-light-900 dark:bg-dark-400 dark:hover:bg-dark-300 dark:active:bg-dark-200 focus:ring-width-2 focus:ring-blurple rounded bg-white p-3 outline-none focus:ring'\n\t\t\t\t}\n\t\t\t\tstore={disclosure}\n\t\t\t>\n\t\t\t\t<div className=\"flex flex-row place-content-between place-items-center\">\n\t\t\t\t\t<div className=\"flex flex-row place-items-center gap-3\">\n\t\t\t\t\t\t{icon ?? null}\n\t\t\t\t\t\t<span className=\"font-semibold\">{title}</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<VscChevronDown\n\t\t\t\t\t\tclassName={`transform transition duration-150 ease-in-out ${disclosureState.open ? 'rotate-180' : 'rotate-0'}`}\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</Disclosure>\n\t\t\t<DisclosureContent\n\t\t\t\tclassName={`${background ? 'bg-light-700 dark:bg-dark-500 rounded' : ''}  ${gutter ? 'mt-2' : ''}`}\n\t\t\t\tstore={disclosure}\n\t\t\t>\n\t\t\t\t{padded ? <div className=\"mx-2 px-0 py-5 md:mx-6.5 md:px-4.5\">{children}</div> : children}\n\t\t\t</DisclosureContent>\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/DiscordMessages.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react';\nimport { DiscordMessage } from './Message.jsx';\nimport { DiscordMessageEmbed } from './MessageEmbed.jsx';\nimport { DiscordMessages } from './Messages.jsx';\n\nexport default {\n\ttitle: 'DiscordMessages',\n\tcomponent: DiscordMessages,\n\ttags: ['autodocs'],\n} satisfies Meta<typeof DiscordMessages>;\n\ntype Story = StoryObj<typeof DiscordMessages>;\n\nexport const Default = {\n\trender: ({ ...args }) => (\n\t\t<DiscordMessages {...args}>\n\t\t\t<DiscordMessage\n\t\t\t\tauthor={{\n\t\t\t\t\tavatar: '/assets/discordjs.png',\n\t\t\t\t\tbot: true,\n\t\t\t\t\ttime: 'Today at 21:00',\n\t\t\t\t\tusername: 'Guide Bot',\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\tA _`DiscordMessage`_ must be within _`DiscordMessages`_.\n\t\t\t</DiscordMessage>\n\t\t\t<DiscordMessage\n\t\t\t\tauthor={{\n\t\t\t\t\tavatar: '/assets/discordjs.png',\n\t\t\t\t\tbot: true,\n\t\t\t\t\ttime: 'Today at 21:01',\n\t\t\t\t\tusername: 'Guide Bot',\n\t\t\t\t}}\n\t\t\t\treply={{\n\t\t\t\t\tauthor: {\n\t\t\t\t\t\tavatar: '/assets/discordjs.png',\n\t\t\t\t\t\tbot: true,\n\t\t\t\t\t\tusername: 'Guide Bot',\n\t\t\t\t\t},\n\t\t\t\t\tcontent: 'A _`DiscordMessage`_ must be within _`DiscordMessages`_.',\n\t\t\t\t}}\n\t\t\t\ttime=\"21:02\"\n\t\t\t>\n\t\t\t\tIt's much better to see the source code of this page to replicate and learn!\n\t\t\t</DiscordMessage>\n\t\t\t<DiscordMessage\n\t\t\t\tauthor={{\n\t\t\t\t\tavatar: '/assets/discordjs.png',\n\t\t\t\t\tbot: true,\n\t\t\t\t\ttime: 'Today at 21:02',\n\t\t\t\t\tusername: 'Guide Bot',\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\tThis message depicts the use of embeds.\n\t\t\t\t<>\n\t\t\t\t\t<DiscordMessageEmbed\n\t\t\t\t\t\tauthor={{\n\t\t\t\t\t\t\tavatar: '/assets/discordjs.png',\n\t\t\t\t\t\t\tusername: 'Guide Bot',\n\t\t\t\t\t\t\turl: 'https://discord.js.org',\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tfooter={{\n\t\t\t\t\t\t\tcontent: 'Sometimes, titles just have to be.',\n\t\t\t\t\t\t\ticon: '/assets/discordjs.png',\n\t\t\t\t\t\t\ttimestamp: 'Today at 21:02',\n\t\t\t\t\t\t}}\n\t\t\t\t\t\ttitle={{ title: 'An amazing title', url: 'https://discord.js.org' }}\n\t\t\t\t\t>\n\t\t\t\t\t\tThis is a description. You can put a description here. It must be descriptive!\n\t\t\t\t\t</DiscordMessageEmbed>\n\t\t\t\t\t<DiscordMessageEmbed\n\t\t\t\t\t\tauthor={{\n\t\t\t\t\t\t\tavatar: '/assets/discordjs.png',\n\t\t\t\t\t\t\tusername: 'Guide Bot',\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tfooter={{ content: \"When one amazing title just wasn't enough.\" }}\n\t\t\t\t\t\tthumbnail={{\n\t\t\t\t\t\t\talt: 'discord.js logo',\n\t\t\t\t\t\t\timage: '/assets/discordjs.png',\n\t\t\t\t\t\t}}\n\t\t\t\t\t\ttitle={{ title: 'Another amazing title' }}\n\t\t\t\t\t>\n\t\t\t\t\t\tMultiple embeds!\n\t\t\t\t\t</DiscordMessageEmbed>\n\t\t\t\t\t<DiscordMessageEmbed\n\t\t\t\t\t\tauthor={{\n\t\t\t\t\t\t\tavatar: '/assets/discordjs.png',\n\t\t\t\t\t\t\tusername: 'Guide Bot',\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tfields={[\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: 'First field',\n\t\t\t\t\t\t\t\tvalue: 'Some value',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tname: 'Another field',\n\t\t\t\t\t\t\t\tvalue: 'Another value',\n\t\t\t\t\t\t\t\tinline: 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\tname: 'A third field',\n\t\t\t\t\t\t\t\tvalue: 'That is inline',\n\t\t\t\t\t\t\t\tinline: 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\tname: 'At last',\n\t\t\t\t\t\t\t\tvalue: 'This is the last field',\n\t\t\t\t\t\t\t\tinline: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t]}\n\t\t\t\t\t\tfooter={{ timestamp: 'Today at 21:02' }}\n\t\t\t\t\t\timage={{\n\t\t\t\t\t\t\talt: 'discord.js logo',\n\t\t\t\t\t\t\turl: '/assets/discordjs.png',\n\t\t\t\t\t\t\twidth: 300,\n\t\t\t\t\t\t\theight: 300,\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tthumbnail={{\n\t\t\t\t\t\t\talt: 'discord.js logo',\n\t\t\t\t\t\t\timage: '/assets/discordjs.png',\n\t\t\t\t\t\t}}\n\t\t\t\t\t\ttitle={{ title: 'Fields are also supported!' }}\n\t\t\t\t\t/>\n\t\t\t\t</>\n\t\t\t</DiscordMessage>\n\t\t\t<DiscordMessage\n\t\t\t\tauthor={{\n\t\t\t\t\tavatar: '/assets/discordjs.png',\n\t\t\t\t\tbot: true,\n\t\t\t\t\ttime: 'Today at 21:03',\n\t\t\t\t\tusername: 'Guide Bot',\n\t\t\t\t}}\n\t\t\t\tinteraction={{\n\t\t\t\t\tauthor: {\n\t\t\t\t\t\tavatar: '/assets/discordjs.png',\n\t\t\t\t\t\tbot: true,\n\t\t\t\t\t\tusername: 'Guide Bot',\n\t\t\t\t\t},\n\t\t\t\t\tcommand: '/interaction',\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\tInteractions are supported! I definitely used a command.\n\t\t\t</DiscordMessage>\n\t\t\t<DiscordMessage\n\t\t\t\tauthor={{\n\t\t\t\t\tavatar: '/assets/discordjs.png',\n\t\t\t\t\tbot: true,\n\t\t\t\t\tverified: true,\n\t\t\t\t\tcolor: 'text-red-500',\n\t\t\t\t\ttime: 'Today at 21:04',\n\t\t\t\t\tusername: 'Guide Bot',\n\t\t\t\t}}\n\t\t\t\treply={{\n\t\t\t\t\tauthor: {\n\t\t\t\t\t\tavatar: '/assets/snek-bot.jpeg',\n\t\t\t\t\t\tbot: true,\n\t\t\t\t\t\tverified: true,\n\t\t\t\t\t\tcolor: 'text-blue-500',\n\t\t\t\t\t\tusername: 'Snek Bot',\n\t\t\t\t\t},\n\t\t\t\t\tcontent: 'You can also have verified bots, like me!',\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\tDisplay colors are supported as well!\n\t\t\t</DiscordMessage>\n\t\t</DiscordMessages>\n\t),\n\targs: {\n\t\trounded: false,\n\t},\n} satisfies Story;\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/Message.tsx",
    "content": "import type { PropsWithChildren, ReactNode } from 'react';\nimport { DiscordMessageAuthor, type IDiscordMessageAuthor } from './MessageAuthor.js';\nimport { DiscordMessageInteraction, type IDiscordMessageInteraction } from './MessageInteraction.js';\nimport { DiscordMessageReply, type IDiscordMessageReply } from './MessageReply.js';\n\nexport interface IDiscordMessage {\n\treadonly author?: IDiscordMessageAuthor | undefined;\n\treadonly authorNode?: ReactNode | undefined;\n\treadonly followUp?: boolean;\n\treadonly interaction?: IDiscordMessageInteraction | undefined;\n\treadonly interactionNode?: ReactNode | undefined;\n\treadonly reply?: IDiscordMessageReply | undefined;\n\treadonly replyNode?: ReactNode | undefined;\n\treadonly time?: string | undefined;\n}\n\nexport function DiscordMessage({\n\treply,\n\treplyNode,\n\tinteraction,\n\tinteractionNode,\n\tauthor,\n\tauthorNode,\n\tfollowUp,\n\ttime,\n\tchildren,\n}: PropsWithChildren<IDiscordMessage>) {\n\treturn (\n\t\t<div className=\"relative\" id=\"outer-message-wrapper\">\n\t\t\t<div\n\t\t\t\tclassName={`group py-0.5 pl-18 pr-12 leading-snug hover:bg-[rgb(4_4_5)]/7 ${followUp ? '' : 'mt-4'}`}\n\t\t\t\tid=\"message-wrapper\"\n\t\t\t>\n\t\t\t\t{(reply || replyNode) && !followUp ? reply ? <DiscordMessageReply {...reply} /> : (replyNode ?? null) : null}\n\t\t\t\t{(interaction || interactionNode) && !(reply || replyNode) && !followUp ? (\n\t\t\t\t\tinteraction ? (\n\t\t\t\t\t\t<DiscordMessageInteraction {...interaction} />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t(interactionNode ?? null)\n\t\t\t\t\t)\n\t\t\t\t) : null}\n\t\t\t\t<div className=\"static\" id=\"content-wrapper\">\n\t\t\t\t\t{followUp ? (\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tclassName=\"absolute left-0 mr-1 hidden h-5.5 w-[56px] cursor-default select-none text-right text-xs text-[rgb(163_166_170)] leading-loose group-hover:inline-block\"\n\t\t\t\t\t\t\tid=\"time\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{time}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t) : author ? (\n\t\t\t\t\t\t<DiscordMessageAuthor {...author} />\n\t\t\t\t\t) : (\n\t\t\t\t\t\tauthorNode\n\t\t\t\t\t)}\n\t\t\t\t\t<div className=\"text-white [&>p]:m-0 [&>p]:leading-snug\" id=\"message-content\">\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/MessageAuthor.tsx",
    "content": "import { FiCheck } from '@react-icons/all-files/fi/FiCheck';\n\nexport interface IDiscordMessageAuthor {\n\treadonly avatar: string;\n\treadonly bot?: boolean;\n\treadonly color?: string;\n\treadonly time: string;\n\treadonly username: string;\n\treadonly verified?: boolean;\n}\n\nexport function DiscordMessageAuthor({ avatar, bot, verified, color, time, username }: IDiscordMessageAuthor) {\n\treturn (\n\t\t<>\n\t\t\t<img\n\t\t\t\talt={`${username}'s avatar`}\n\t\t\t\tclassName=\"absolute left-[16px] mt-0.5 h-10 w-10 cursor-pointer select-none rounded-full\"\n\t\t\t\tsrc={avatar}\n\t\t\t/>\n\t\t\t<h2 className=\"m-0 flex place-items-center text-size-inherit font-medium leading-snug\" id=\"user-info\">\n\t\t\t\t<span className=\"inline-flex place-items-center\" id=\"username\">\n\t\t\t\t\t<span className={`mr-1.5 cursor-pointer text-base font-medium hover:underline ${color ?? 'text-white'}`}>\n\t\t\t\t\t\t{username}\n\t\t\t\t\t</span>\n\t\t\t\t\t{bot ? (\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tclassName=\"mr-1 inline-flex place-items-center rounded bg-blurple px-1 vertical-top text-[0.7rem]/4 text-white font-normal\"\n\t\t\t\t\t\t\tid=\"bot\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{verified ? <FiCheck className=\"mr-0.5 inline-block stroke-3\" /> : null} BOT\n\t\t\t\t\t\t</span>\n\t\t\t\t\t) : null}\n\t\t\t\t</span>\n\t\t\t\t<span className=\"ml-1 cursor-default text-xs text-[rgb(163_166_170)] leading-snug\" id=\"time\">\n\t\t\t\t\t{time}\n\t\t\t\t</span>\n\t\t\t</h2>\n\t\t</>\n\t);\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/MessageAuthorReply.tsx",
    "content": "import { FiCheck } from '@react-icons/all-files/fi/FiCheck';\n\nexport interface IDiscordMessageAuthorReply {\n\treadonly avatar: string;\n\treadonly bot?: boolean;\n\treadonly color?: string;\n\treadonly username: string;\n\treadonly verified?: boolean;\n}\n\nexport function DiscordMessageAuthorReply({ avatar, bot, verified, color, username }: IDiscordMessageAuthorReply) {\n\treturn (\n\t\t<>\n\t\t\t<img alt={`${username}'s avatar`} className=\"mr-1.5 h-4 w-4 select-none rounded-full\" src={avatar} />\n\t\t\t{bot ? (\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"mr-1 inline-flex place-items-center rounded bg-blurple px-1 vertical-top text-[0.7rem]/4 text-white font-normal\"\n\t\t\t\t\tid=\"bot\"\n\t\t\t\t>\n\t\t\t\t\t{verified ? <FiCheck className=\"mr-0.5 inline-block stroke-3\" /> : null} BOT\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t<span className={`mr-1 cursor-pointer select-none text-sm font-medium leading-snug ${color ?? 'text-white'}`}>\n\t\t\t\t{username}\n\t\t\t</span>\n\t\t</>\n\t);\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/MessageBaseReply.tsx",
    "content": "import type { PropsWithChildren, ReactNode } from 'react';\nimport { DiscordMessageAuthorReply, type IDiscordMessageAuthorReply } from './MessageAuthorReply.js';\n\nexport function DiscordMessageBaseReply({\n\tauthor,\n\tauthorNode,\n\tchildren,\n}: PropsWithChildren<{\n\treadonly author?: IDiscordMessageAuthorReply | undefined;\n\treadonly authorNode?: ReactNode | undefined;\n}>) {\n\treturn (\n\t\t<div\n\t\t\tclassName=\"relative mb-1 flex place-items-center before:absolute before:bottom-0 before:left-[-36px] before:right-full before:top-[50%] before:mr-1 before:block before:border-l-2 before:border-t-2 before:border-[rgb(79_84_92)] before:rounded-tl-1.5 before:content-none\"\n\t\t\tid=\"reply-wrapper\"\n\t\t>\n\t\t\t<div className=\"flex place-items-center [&>span]:opacity-60\">\n\t\t\t\t{author ? <DiscordMessageAuthorReply {...author} /> : authorNode}\n\t\t\t</div>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/MessageEmbed.tsx",
    "content": "import type { PropsWithChildren, ReactNode } from 'react';\nimport { DiscordMessageEmbedAuthor, type IDiscordMessageEmbedAuthor } from './MessageEmbedAuthor.js';\nimport type { IDiscordMessageEmbedField } from './MessageEmbedField.js';\nimport { DiscordMessageEmbedFields } from './MessageEmbedFields.js';\nimport { DiscordMessageEmbedFooter, type IDiscordMessageEmbedFooter } from './MessageEmbedFooter.js';\nimport { DiscordMessageEmbedImage, type IDiscordMessageEmbedImage } from './MessageEmbedImage.js';\nimport { DiscordMessageEmbedThumbnail, type IDiscordMessageEmbedThumbnail } from './MessageEmbedThumbnail.js';\nimport { DiscordMessageEmbedTitle, type IDiscordMessageEmbedTitle } from './MessageEmbedTitle.js';\n\nexport interface IDiscordMessageEmbed {\n\treadonly author?: IDiscordMessageEmbedAuthor | undefined;\n\treadonly authorNode?: ReactNode | undefined;\n\treadonly fields?: IDiscordMessageEmbedField[];\n\treadonly footer?: IDiscordMessageEmbedFooter | undefined;\n\treadonly footerNode?: ReactNode | undefined;\n\treadonly image?: IDiscordMessageEmbedImage;\n\treadonly thumbnail?: IDiscordMessageEmbedThumbnail;\n\treadonly title?: IDiscordMessageEmbedTitle | undefined;\n\treadonly titleNode?: ReactNode | undefined;\n}\n\nexport function DiscordMessageEmbed({\n\tauthor,\n\tauthorNode,\n\tfields,\n\ttitle,\n\ttitleNode,\n\timage,\n\tchildren,\n\tthumbnail,\n\tfooter,\n\tfooterNode,\n}: PropsWithChildren<IDiscordMessageEmbed>) {\n\treturn (\n\t\t<div className=\"py-0.5\" id=\"outer-embed-wrapper\">\n\t\t\t<div className=\"grid max-w-max border-l-4 border-l-blurple rounded bg-[rgb(47_49_54)]\" id=\"embed-wrapper\">\n\t\t\t\t<div className=\"max-w-128 flex\">\n\t\t\t\t\t<div className=\"pb-4 pl-3 pr-4 pt-2\">\n\t\t\t\t\t\t{author ? <DiscordMessageEmbedAuthor {...author} /> : (authorNode ?? null)}\n\t\t\t\t\t\t{title ? <DiscordMessageEmbedTitle {...title} /> : (titleNode ?? null)}\n\t\t\t\t\t\t{children ? <div className=\"mt-2 text-sm\">{children}</div> : null}\n\t\t\t\t\t\t{fields ? <DiscordMessageEmbedFields fields={fields} /> : null}\n\t\t\t\t\t\t{image ? <DiscordMessageEmbedImage {...image} /> : null}\n\t\t\t\t\t\t{footer ? <DiscordMessageEmbedFooter {...footer} /> : (footerNode ?? null)}\n\t\t\t\t\t</div>\n\n\t\t\t\t\t{thumbnail ? <DiscordMessageEmbedThumbnail {...thumbnail} /> : null}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/MessageEmbedAuthor.tsx",
    "content": "export interface IDiscordMessageEmbedAuthor {\n\treadonly avatar: string;\n\treadonly url?: string;\n\treadonly username: string;\n}\n\nexport function DiscordMessageEmbedAuthor({ avatar, url, username }: IDiscordMessageEmbedAuthor) {\n\treturn (\n\t\t<div className=\"mt-2 flex place-items-center\">\n\t\t\t<img alt={`${username}'s avatar`} className=\"mr-2 h-6 w-6 select-none rounded-full\" src={avatar} />\n\t\t\t{url ? (\n\t\t\t\t<a\n\t\t\t\t\tclassName=\"text-sm font-medium hover:underline\"\n\t\t\t\t\thref={url}\n\t\t\t\t\trel=\"noreferrer noopener external\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t>\n\t\t\t\t\t{username}\n\t\t\t\t</a>\n\t\t\t) : (\n\t\t\t\t<span className=\"text-sm font-medium\">{username}</span>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/MessageEmbedField.tsx",
    "content": "export interface IDiscordMessageEmbedField {\n\treadonly inline?: boolean;\n\treadonly name: string;\n\treadonly value: string;\n}\n\nexport function DiscordMessageEmbedField({ name, value, inline }: IDiscordMessageEmbedField) {\n\treturn (\n\t\t<div className={`${inline ? 'sm:col-span-4' : 'sm:col-span-12'} flex flex-col`}>\n\t\t\t<span className=\"font-medium\">{name}</span>\n\t\t\t<span className=\"text-gray-300\">{value}</span>\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/MessageEmbedFields.tsx",
    "content": "import { DiscordMessageEmbedField, type IDiscordMessageEmbedField } from './MessageEmbedField.js';\n\nexport interface IDiscordMessageEmbedFields {\n\treadonly fields: IDiscordMessageEmbedField[];\n}\n\nexport function DiscordMessageEmbedFields({ fields }: IDiscordMessageEmbedFields) {\n\treturn (\n\t\t<div className=\"grid grid-cols-1 mt-2 gap-2 sm:grid-cols-12\">\n\t\t\t{fields.map((field, idx) => (\n\t\t\t\t<DiscordMessageEmbedField key={idx} {...field} />\n\t\t\t))}\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/MessageEmbedFooter.tsx",
    "content": "export interface IDiscordMessageEmbedFooter {\n\treadonly content?: string;\n\treadonly icon?: string;\n\treadonly timestamp?: string;\n}\n\nexport function DiscordMessageEmbedFooter({ content, icon, timestamp }: IDiscordMessageEmbedFooter) {\n\treturn (\n\t\t<div className=\"mt-2 flex items-center text-xs\">\n\t\t\t{icon ? <img alt=\"Icon\" className=\"mr-2 rounded-full\" height=\"20\" src={icon} width=\"20\" /> : null}\n\n\t\t\t{content}\n\t\t\t{content && timestamp ? <span className=\"mx-1 font-medium\">•</span> : null}\n\t\t\t{timestamp}\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/MessageEmbedImage.tsx",
    "content": "export interface IDiscordMessageEmbedImage {\n\treadonly alt: string;\n\treadonly height: number;\n\treadonly url: string;\n\treadonly width: number;\n}\n\nexport function DiscordMessageEmbedImage({ alt, height, url, width }: IDiscordMessageEmbedImage) {\n\treturn <img alt={alt} className=\"mt-4\" height={height} src={url} width={width} />;\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/MessageEmbedThumbnail.tsx",
    "content": "export interface IDiscordMessageEmbedThumbnail {\n\treadonly alt: string;\n\treadonly image: string;\n}\n\nexport function DiscordMessageEmbedThumbnail({ alt, image }: IDiscordMessageEmbedThumbnail) {\n\treturn <img alt={alt} className=\"mr-4 mt-4 aspect-square h-20\" height={80} src={image} width={80} />;\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/MessageEmbedTitle.tsx",
    "content": "export interface IDiscordMessageEmbedTitle {\n\treadonly title: string;\n\treadonly url?: string;\n}\n\nexport function DiscordMessageEmbedTitle({ title, url }: IDiscordMessageEmbedTitle) {\n\treturn url ? (\n\t\t<a\n\t\t\tclassName=\"mt-2 text-blue-500 font-medium hover:underline\"\n\t\t\thref={url}\n\t\t\trel=\"noreferrer noopener external\"\n\t\t\ttarget=\"_blank\"\n\t\t>\n\t\t\t{title}\n\t\t</a>\n\t) : (\n\t\t<div className=\"mt-2 font-medium\">{title}</div>\n\t);\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/MessageInteraction.tsx",
    "content": "import type { ReactNode } from 'react';\nimport type { IDiscordMessageAuthorReply } from './MessageAuthorReply.js';\nimport { DiscordMessageBaseReply } from './MessageBaseReply.js';\n\nexport interface IDiscordMessageInteraction {\n\treadonly author?: IDiscordMessageAuthorReply | undefined;\n\treadonly authorNode?: ReactNode | undefined;\n\treadonly command?: string;\n}\n\nexport function DiscordMessageInteraction({ author, authorNode, command }: IDiscordMessageInteraction) {\n\treturn (\n\t\t<DiscordMessageBaseReply author={author} authorNode={authorNode}>\n\t\t\t<span className=\"mr-1 select-none text-sm text-white leading-snug\">used</span>\n\t\t\t<div className=\"cursor-pointer text-sm text-blurple leading-snug hover:underline\">{command}</div>\n\t\t</DiscordMessageBaseReply>\n\t);\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/MessageReply.tsx",
    "content": "import type { ReactNode } from 'react';\nimport type { IDiscordMessageAuthorReply } from './MessageAuthorReply.js';\nimport { DiscordMessageBaseReply } from './MessageBaseReply.js';\n\nexport interface IDiscordMessageReply {\n\treadonly author?: IDiscordMessageAuthorReply | undefined;\n\treadonly authorNode?: ReactNode | undefined;\n\treadonly content: string;\n}\n\nexport function DiscordMessageReply({ author, authorNode, content }: IDiscordMessageReply) {\n\treturn (\n\t\t<DiscordMessageBaseReply author={author} authorNode={authorNode}>\n\t\t\t<div className=\"cursor-pointer select-none text-sm text-[rgb(163_166_170)] leading-snug hover:text-white\">\n\t\t\t\t{content}\n\t\t\t</div>\n\t\t</DiscordMessageBaseReply>\n\t);\n}\n"
  },
  {
    "path": "packages/ui/src/lib/components/discord/Messages.tsx",
    "content": "import type { PropsWithChildren } from 'react';\n\nexport interface IDiscordMessages {\n\treadonly rounded?: boolean;\n}\n\nexport function DiscordMessages({ rounded, children }: PropsWithChildren<IDiscordMessages>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={`font-source-sans-pro bg-[rgb(54_57_63)] pb-4 pt-0.1 ${rounded ? 'rounded' : ''}`}\n\t\t\tid=\"messages-wrapper\"\n\t\t>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n"
  },
  {
    "path": "packages/ui/src/lib/index.ts",
    "content": "export * from './components/Alert.js';\nexport * from './components/Section.js';\n\nexport * from './components/discord/Message.js';\nexport * from './components/discord/MessageAuthor.js';\nexport * from './components/discord/MessageAuthorReply.js';\nexport * from './components/discord/MessageBaseReply.js';\nexport * from './components/discord/MessageEmbed.js';\nexport * from './components/discord/MessageEmbedAuthor.js';\nexport * from './components/discord/MessageEmbedFooter.js';\nexport * from './components/discord/MessageEmbedTitle.js';\nexport * from './components/discord/MessageInteraction.js';\nexport * from './components/discord/MessageReply.js';\nexport * from './components/discord/Messages.js';\n"
  },
  {
    "path": "packages/ui/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.tsx\",\n\t\t\"*.js\",\n\t\t\"*.jsx\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.tsx\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.jsx\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/ui/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"jsx\": \"preserve\",\n\t\t\"baseUrl\": \".\",\n\t\t\"outDir\": \"dist\",\n\t\t\"noEmit\": true,\n\t\t\"skipLibCheck\": true,\n\t\t\"paths\": {\n\t\t\t\"~/*\": [\"./src/*\"]\n\t\t}\n\t},\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.tsx\", \"src/**/*.js\", \"src/**/*.jsx\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/ui/vite.config.ts",
    "content": "import react from '@vitejs/plugin-react';\nimport Unocss from 'unocss/vite';\nimport { defineConfig } from 'vite';\nimport dts from 'vite-plugin-dts';\n\nexport default defineConfig({\n\tplugins: [\n\t\tdts(),\n\t\treact(),\n\t\tUnocss({\n\t\t\tcontent: { pipeline: { include: ['.storybook/preview.ts'] } },\n\t\t\tconfigFile: '../../unocss.config.ts',\n\t\t}),\n\t],\n\tbuild: {\n\t\tlib: {\n\t\t\tentry: [\n\t\t\t\t'src/lib/index.ts',\n\t\t\t\t'src/lib/components/Alert.tsx',\n\t\t\t\t'src/lib/components/Section.tsx',\n\t\t\t\t'src/lib/components/discord/Message.tsx',\n\t\t\t\t'src/lib/components/discord/MessageAuthor.tsx',\n\t\t\t\t'src/lib/components/discord/MessageAuthorReply.tsx',\n\t\t\t\t'src/lib/components/discord/MessageBaseReply.tsx',\n\t\t\t\t'src/lib/components/discord/MessageEmbed.tsx',\n\t\t\t\t'src/lib/components/discord/MessageEmbedAuthor.tsx',\n\t\t\t\t'src/lib/components/discord/MessageEmbedField.tsx',\n\t\t\t\t'src/lib/components/discord/MessageEmbedFields.tsx',\n\t\t\t\t'src/lib/components/discord/MessageEmbedFooter.tsx',\n\t\t\t\t'src/lib/components/discord/MessageEmbedImage.tsx',\n\t\t\t\t'src/lib/components/discord/MessageEmbedThumbnail.tsx',\n\t\t\t\t'src/lib/components/discord/MessageEmbedTitle.tsx',\n\t\t\t\t'src/lib/components/discord/MessageInteraction.tsx',\n\t\t\t\t'src/lib/components/discord/MessageReply.tsx',\n\t\t\t\t'src/lib/components/discord/Messages.tsx',\n\t\t\t],\n\t\t\tformats: ['es'],\n\t\t\tname: 'ui',\n\t\t},\n\t\trollupOptions: {\n\t\t\texternal: [\n\t\t\t\t'react',\n\t\t\t\t'react-dom',\n\t\t\t\t'@ariakit/react/disclosure',\n\t\t\t\t'@react-icons/all-files/vsc/VscFlame',\n\t\t\t\t'@react-icons/all-files/vsc/VscInfo',\n\t\t\t\t'@react-icons/all-files/vsc/VscWarning',\n\t\t\t\t'@react-icons/all-files/vsc/VscChevronDown',\n\t\t\t\t'@react-icons/all-files/fi/FiCheck',\n\t\t\t],\n\t\t},\n\t},\n});\n"
  },
  {
    "path": "packages/util/.cliff-jumperrc.json",
    "content": "{\n\t\"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n\t\"name\": \"util\",\n\t\"org\": \"discordjs\",\n\t\"packagePath\": \"packages/util\",\n\t\"identifierBase\": false\n}\n"
  },
  {
    "path": "packages/util/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\ndist-docs\n\n# Docs\ndocs/**/*\n!docs/README.md\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/util/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/util/.prettierignore",
    "content": ".turbo\ncoverage\ndist\ndist-docs\ndocs/docs.api.json\nCHANGELOG.md\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/util/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/util/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n# [@discordjs/util@1.1.1](https://github.com/discordjs/discord.js/compare/@discordjs/util@1.1.0...@discordjs/util@1.1.1) - (2024-09-01)\n\n# [@discordjs/util@1.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/util@1.0.2...@discordjs/util@1.1.0) - (2024-05-04)\n\n## Bug Fixes\n\n- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))\n\n## Documentation\n\n- Remove duplicated words (#10178) ([26af386](https://github.com/discordjs/discord.js/commit/26af3868a5648042b7715a14b8ed8dd2f478345c))\n- Split docs.api.json into multiple json files ([597340f](https://github.com/discordjs/discord.js/commit/597340f288437c35da8c703d9b621274de60d880))\n\n## Features\n\n- Local and preview detection ([79fbda3](https://github.com/discordjs/discord.js/commit/79fbda3aac6d4f0f8bfb193e797d09cbe331d315))\n- Add support for `using` keyword on discord.js `Client` and `WebSocketManager` (#10063) ([543d617](https://github.com/discordjs/discord.js/commit/543d61737e0709b9d88029d01156d48cfcaf3bcc))\n\n## Refactor\n\n- Docs (#10126) ([18cce83](https://github.com/discordjs/discord.js/commit/18cce83d80598c430218775c53441b6b2ecdc776))\n\n# [@discordjs/util@1.0.2](https://github.com/discordjs/discord.js/compare/@discordjs/util@1.0.1...@discordjs/util@1.0.2) - (2023-11-12)\n\n## Documentation\n\n- **create-discord-bot:** Support bun in create-discord-bot (#9798) ([7157748](https://github.com/discordjs/discord.js/commit/7157748fe3a69265896adf0450cd3f37acbcf97b))\n\n# [@discordjs/util@1.0.1](https://github.com/discordjs/discord.js/compare/@discordjs/util@1.0.0...@discordjs/util@1.0.1) - (2023-08-17)\n\n## Documentation\n\n- Update Node.js requirement to 16.11.0 (#9764) ([188877c](https://github.com/discordjs/discord.js/commit/188877c50af70f0d5cffb246620fa277435c6ce6))\n\n# [@discordjs/util@1.0.0](https://github.com/discordjs/discord.js/compare/@discordjs/util@0.3.1...@discordjs/util@1.0.0) - (2023-07-31)\n\n## Features\n\n- No-de-no-de, now with extra buns (#9683) ([386f206](https://github.com/discordjs/discord.js/commit/386f206caf74a04c426799af9796ca96dcb37056))\n  - **BREAKING CHANGE:** The REST and RequestManager classes now extend AsyncEventEmitter\nfrom `@vladfrangu/async_event_emitter`, which aids in cross-compatibility\nbetween Node, Deno, Bun, CF Workers, Vercel Functions, etc.\n  - **BREAKING CHANGE:** DefaultUserAgentAppendix has been adapted to support multiple\ndifferent platforms (previously mentioned Deno, Bun, CF Workers, etc)\n  - **BREAKING CHANGE:** the entry point for `@discordjs/rest` will now differ\nin non-node-like environments (CF Workers, etc.)\n  - **Co-authored-by:** Suneet Tipirneni <77477100+suneettipirneni@users.noreply.github.com>\n  - **Co-authored-by:** Jiralite <33201955+Jiralite@users.noreply.github.com>\n  - **Co-authored-by:** suneettipirneni <suneettipirneni@icloud.com>\n\n# [@discordjs/util@0.3.1](https://github.com/discordjs/discord.js/compare/@discordjs/util@0.3.0...@discordjs/util@0.3.1) - (2023-05-01)\n\n## Refactor\n\n- **ShardClientUtil:** Logic de-duplication (#9491) ([a9f2bff](https://github.com/discordjs/discord.js/commit/a9f2bff82a18c6a3afdee99e5830e1d7b4da65dc))\n\n# [@discordjs/util@0.3.0](https://github.com/discordjs/discord.js/compare/@discordjs/util@0.2.0...@discordjs/util@0.3.0) - (2023-05-01)\n\n## Bug Fixes\n\n- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2))\n- **scripts:** Accessing tsComment ([d8d5f31](https://github.com/discordjs/discord.js/commit/d8d5f31d3927fd1de62f1fa3a1a6e454243ad87b))\n\n## Documentation\n\n- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9))\n\n## Features\n\n- **website:** Render syntax and mdx on the server (#9086) ([ee5169e](https://github.com/discordjs/discord.js/commit/ee5169e0aadd7bbfcd752aae614ec0f69602b68b))\n\n# [@discordjs/util@0.2.0](https://github.com/discordjs/discord.js/compare/@discordjs/util@0.1.0...@discordjs/util@0.2.0) - (2023-03-12)\n\n## Bug Fixes\n\n- Pin @types/node version ([9d8179c](https://github.com/discordjs/discord.js/commit/9d8179c6a78e1c7f9976f852804055964d5385d4))\n\n## Features\n\n- **website:** Add support for source file links (#9048) ([f6506e9](https://github.com/discordjs/discord.js/commit/f6506e99c496683ee0ab67db0726b105b929af38))\n- **core:** Implement some ws send events (#8941) ([816aed4](https://github.com/discordjs/discord.js/commit/816aed478e3035060697092d52ad2b58106be0ee))\n- Web-components (#8715) ([0ac3e76](https://github.com/discordjs/discord.js/commit/0ac3e766bd9dbdeb106483fa4bb085d74de346a2))\n\n# [@discordjs/util@0.1.0](https://github.com/discordjs/discord.js/tree/@discordjs/util@0.1.0) - (2022-10-03)\n\n## Features\n\n- Add `@discordjs/util` (#8591) ([b2ec865](https://github.com/discordjs/discord.js/commit/b2ec865765bf94181473864a627fb63ea8173fd3))\n"
  },
  {
    "path": "packages/util/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2022 Noel Buechler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/util/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/commits/main/packages/util\"><img alt=\"Last commit.\" src=\"https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Futil\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## About\n\n`@discordjs/util` is a collection of utility functions for use with discord.js.\n\n## Installation\n\n**Node.js 22.12.0 or newer is required.**\n\n```sh\nnpm install @discordjs/util\nyarn add @discordjs/util\npnpm add @discordjs/util\nbun add @discordjs/util\n```\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Documentation][documentation]\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [npm][npm]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the\n[documentation][documentation].  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs/packages/util/stable\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/util\n[npm]: https://www.npmjs.com/package/@discordjs/util\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/util/__tests__/Equatable.test.ts",
    "content": "import { describe, test, expect } from 'vitest';\nimport { isEquatable } from '../src/index.js';\n\ndescribe('isEquatable', () => {\n\ttest('returns true if the object is equatable', () => {\n\t\texpect(isEquatable({ equals: () => true })).toBeTruthy();\n\t});\n\n\ttest('returns false if the object is not equatable', () => {\n\t\texpect(isEquatable({})).toBeFalsy();\n\t\texpect(isEquatable(null)).toBeFalsy();\n\t\texpect(isEquatable(undefined)).toBeFalsy();\n\t\texpect(isEquatable(1)).toBeFalsy();\n\t\texpect(isEquatable('')).toBeFalsy();\n\t\texpect(isEquatable([])).toBeFalsy();\n\t\texpect(isEquatable(() => {})).toBeFalsy();\n\t});\n});\n"
  },
  {
    "path": "packages/util/__tests__/JSONEncodable.test.ts",
    "content": "import { describe, test, expect } from 'vitest';\nimport { isJSONEncodable, type JSONEncodable } from '../src/index.js';\n\nclass Encodable implements JSONEncodable<{}> {\n\tpublic toJSON() {\n\t\treturn {};\n\t}\n}\n\ndescribe('isJSONEncodable', () => {\n\ttest('returns true if the object is JSON encodable', () => {\n\t\texpect(isJSONEncodable({ toJSON: () => ({}) })).toBeTruthy();\n\t\texpect(isJSONEncodable(new Encodable())).toBeTruthy();\n\t});\n\n\ttest('returns false if the object is not JSON encodable', () => {\n\t\texpect(isJSONEncodable({})).toBeFalsy();\n\t\texpect(isJSONEncodable(null)).toBeFalsy();\n\t\texpect(isJSONEncodable(undefined)).toBeFalsy();\n\t\texpect(isJSONEncodable(1)).toBeFalsy();\n\t\texpect(isJSONEncodable('')).toBeFalsy();\n\t\texpect(isJSONEncodable([])).toBeFalsy();\n\t\texpect(isJSONEncodable(() => {})).toBeFalsy();\n\t});\n});\n"
  },
  {
    "path": "packages/util/__tests__/embedLength.test.ts",
    "content": "import { describe, expect, test } from 'vitest';\nimport { embedLength } from '../src/functions/embedLength.js';\n\ndescribe('embedLength', () => {\n\ttest('GIVEN an embed with specific amount of characters THEN returns amount of characters', () => {\n\t\tconst embed = {\n\t\t\ttitle: 'yeet',\n\t\t\tdescription: 'yeet',\n\t\t\tfields: [{ name: 'yeet', value: 'yeet' }],\n\t\t\tauthor: { name: 'yeet' },\n\t\t\tfooter: { text: 'yeet' },\n\t\t};\n\n\t\texpect(embedLength(embed)).toEqual('yeet'.length * 6);\n\t});\n\n\ttest('GIVEN an embed with zero characters THEN returns amount of characters', () => {\n\t\texpect(embedLength({})).toEqual(0);\n\t});\n});\n"
  },
  {
    "path": "packages/util/__tests__/lazy.test.ts",
    "content": "/**\n * Copyright 2020 The Sapphire Community and its contributors\n *\n * Use of this source code is governed by an MIT-style\n * license that can be found in the LICENSE file or at\n * https://github.com/sapphiredev/utilities/blob/main/LICENSE.md.\n */\n\nimport { describe, test, expect, vi } from 'vitest';\nimport { lazy } from '../src/index.js';\n\ndescribe('lazy', () => {\n\ttest('GIVEN string callback THEN returns the same', () => {\n\t\tconst callback = vi.fn(() => 'Lorem Ipsum');\n\n\t\tconst lazyStoredValue = lazy(callback);\n\n\t\texpect(lazyStoredValue()).toEqual('Lorem Ipsum');\n\t});\n\n\ttest('GIVEN string callback with cached value THEN returns the same', () => {\n\t\tconst callback = vi.fn(() => 'Lorem Ipsum');\n\n\t\tconst lazyStoredValue = lazy(callback);\n\n\t\tlazyStoredValue();\n\t\tconst cachedValue = lazyStoredValue();\n\n\t\texpect(callback).toHaveBeenCalledOnce();\n\t\texpect(cachedValue).toEqual('Lorem Ipsum');\n\t});\n});\n"
  },
  {
    "path": "packages/util/__tests__/range.test.ts",
    "content": "import { describe, test, expect } from 'vitest';\nimport { range } from '../src/index.js';\n\ndescribe('range', () => {\n\ttest('GIVEN valid range and then valid numbers are returned', () => {\n\t\texpect([...range(5)]).toEqual([0, 1, 2, 3, 4]);\n\t});\n\n\ttest('GIVEN valid range with start and end THEN valid numbers are returned', () => {\n\t\texpect([...range({ start: 0, end: 5 })]).toEqual([0, 1, 2, 3, 4]);\n\t});\n\n\ttest('GIVEN valid range with start, end and step THEN valid numbers are returned', () => {\n\t\texpect([...range({ start: 0, end: 11, step: 2 })]).toEqual([0, 2, 4, 6, 8, 10]);\n\t});\n});\n"
  },
  {
    "path": "packages/util/__tests__/types/Equatable.test-d.ts",
    "content": "import { expectTypeOf } from 'vitest';\nimport { isEquatable, type Equatable } from '../../src/index.js';\n\ndeclare const unknownObj: unknown;\n\nif (isEquatable(unknownObj)) {\n\texpectTypeOf(unknownObj).toEqualTypeOf<Equatable<unknown>>();\n\texpectTypeOf(unknownObj.equals(unknownObj)).toEqualTypeOf<boolean>();\n}\n"
  },
  {
    "path": "packages/util/__tests__/types/JSONEncodable.test-d.ts",
    "content": "import { expectTypeOf } from 'vitest';\nimport { isJSONEncodable, type JSONEncodable } from '../../src/index.js';\n\ndeclare const unknownObj: unknown;\n\nif (isJSONEncodable(unknownObj)) {\n\texpectTypeOf(unknownObj).toEqualTypeOf<JSONEncodable<unknown>>();\n\texpectTypeOf(unknownObj.toJSON()).toEqualTypeOf<unknown>();\n}\n"
  },
  {
    "path": "packages/util/api-extractor.json",
    "content": "{\n\t\"extends\": \"../../api-extractor.json\",\n\t\"docModel\": {\n\t\t\"projectFolderUrl\": \"https://github.com/discordjs/discord.js/tree/main/packages/util\"\n\t}\n}\n"
  },
  {
    "path": "packages/util/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t\t{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length %}\\\n\t\\n### New Contributors\\n\n\t{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\\\n\t\t* @{{ contributor.username }} made their first contribution in #{{ contributor.pr_number }}\n\t{% endfor %}\\\n{% endif %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"@discordjs/util@[0-9]*\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/util/docs/README.md",
    "content": "## [View the documentation here.](https://discord.js.org/docs/packages/util/main)\n"
  },
  {
    "path": "packages/util/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/util\",\n\t\"version\": \"1.1.1\",\n\t\"description\": \"Utilities shared across Discord.js packages\",\n\t\"scripts\": {\n\t\t\"build\": \"tsc --noEmit && tsup\",\n\t\t\"build:docs\": \"tsc -p tsconfig.docs.json\",\n\t\t\"test\": \"vitest run --config ../../vitest.config.ts\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src\",\n\t\t\"fmt\": \"pnpm run format\",\n\t\t\"docs\": \"pnpm run build:docs && api-extractor run --local --minify && generate-split-documentation\",\n\t\t\"prepack\": \"pnpm run lint && pnpm run test && pnpm run build\",\n\t\t\"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/util/*'\",\n\t\t\"release\": \"cliff-jumper\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"main\": \"./dist/index.js\",\n\t\"module\": \"./dist/index.mjs\",\n\t\"types\": \"./dist/index.d.ts\",\n\t\"directories\": {\n\t\t\"lib\": \"src\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"Amish Shah <amishshah.2k@gmail.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"api\",\n\t\t\"bot\",\n\t\t\"client\",\n\t\t\"node\",\n\t\t\"discordjs\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/util\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"discord-api-types\": \"^0.38.41\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@discordjs/api-extractor\": \"workspace:^\",\n\t\t\"@discordjs/scripts\": \"workspace:^\",\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@types/node\": \"^22.19.11\",\n\t\t\"@vitest/coverage-v8\": \"^4.0.18\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"esbuild-plugin-version-injector\": \"^1.2.1\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vitest\": \"^4.0.18\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/util/src/Equatable.ts",
    "content": "/**\n * Represents a structure that can be checked against another\n * given structure for equality\n *\n * @typeParam Value - The type of object to compare the current object to\n */\nexport interface Equatable<Value> {\n\t/**\n\t * Whether or not this is equal to another structure\n\t */\n\tequals(other: Value): boolean;\n}\n\n/**\n * Indicates if an object is equatable or not.\n *\n * @param maybeEquatable - The object to check against\n */\nexport function isEquatable(maybeEquatable: unknown): maybeEquatable is Equatable<unknown> {\n\treturn maybeEquatable !== null && typeof maybeEquatable === 'object' && 'equals' in maybeEquatable;\n}\n"
  },
  {
    "path": "packages/util/src/RawFile.ts",
    "content": "import type { Buffer } from 'node:buffer';\n\n/**\n * Represents a file to be added to a request with multipart/form-data encoding\n */\nexport interface RawFile {\n\t/**\n\t * Content-Type of the file.\n\t * If not provided, it will be inferred from the file data when possible\n\t *\n\t * @example 'image/png'\n\t * @example 'application/pdf'\n\t */\n\tcontentType?: string;\n\t/**\n\t * The actual data for the file\n\t */\n\tdata: Buffer | Uint8Array | boolean | number | string;\n\t/**\n\t * An explicit key to use for the formdata field for this file.\n\t * When not provided, the index of the file in the files array is used in the form `files[${index}]`.\n\t * If you wish to alter the placeholder snowflake, you must provide this property in the same form (`files[${placeholder}]`)\n\t */\n\tkey?: string;\n\t/**\n\t * The name of the file. This is the actual filename that will be used when uploading to Discord.\n\t * This is also the name you'll use to reference the file with attachment:// URLs.\n\t *\n\t * @example 'image.png'\n\t * @example 'document.pdf'\n\t * @example 'SPOILER_secret.jpeg'\n\t */\n\tname: string;\n}\n"
  },
  {
    "path": "packages/util/src/encodables.ts",
    "content": "import type { RawFile } from './RawFile.js';\n\n/**\n * Represents an object capable of representing itself as a JSON object\n *\n * @typeParam Value - The JSON type corresponding to {@link JSONEncodable.toJSON} outputs.\n */\nexport interface JSONEncodable<Value> {\n\t/**\n\t * Transforms this object to its JSON format\n\t */\n\ttoJSON(): Value;\n}\n\n/**\n * Indicates if an object is encodable or not.\n *\n * @param maybeEncodable - The object to check against\n */\nexport function isJSONEncodable(maybeEncodable: unknown): maybeEncodable is JSONEncodable<unknown> {\n\treturn maybeEncodable !== null && typeof maybeEncodable === 'object' && 'toJSON' in maybeEncodable;\n}\n\n/**\n * Result of encoding an object that includes file attachments\n *\n * @typeParam BodyValue - The JSON body type\n */\nexport interface FileBodyEncodableResult<BodyValue> {\n\t/**\n\t * The JSON body to send with the request\n\t */\n\tbody: BodyValue;\n\t/**\n\t * The files to attach to the request\n\t */\n\tfiles: RawFile[];\n}\n\n/**\n * Represents an object capable of representing itself as a request body with file attachments.\n * Objects implementing this interface can separate JSON body data from binary file data,\n * which is necessary for multipart/form-data requests.\n *\n * @typeParam BodyValue - The JSON body type\n */\nexport interface FileBodyEncodable<BodyValue> {\n\t/**\n\t * Transforms this object to its file body format, separating the JSON body from file attachments.\n\t */\n\ttoFileBody(): FileBodyEncodableResult<BodyValue>;\n}\n\n/**\n * Indicates if an object is file body encodable or not.\n *\n * @param maybeEncodable - The object to check against\n */\nexport function isFileBodyEncodable(maybeEncodable: unknown): maybeEncodable is FileBodyEncodable<unknown> {\n\treturn maybeEncodable !== null && typeof maybeEncodable === 'object' && 'toFileBody' in maybeEncodable;\n}\n"
  },
  {
    "path": "packages/util/src/functions/calculateShardId.ts",
    "content": "/**\n * Calculates the shard id for a given guild id.\n *\n * @param guildId - The guild id to calculate the shard id for\n * @param shardCount - The total number of shards\n */\nexport function calculateShardId(guildId: string, shardCount: number) {\n\treturn Number(BigInt(guildId) >> 22n) % shardCount;\n}\n"
  },
  {
    "path": "packages/util/src/functions/embedLength.ts",
    "content": "import type { APIEmbed } from 'discord-api-types/v10';\n\n/**\n * Calculates the length of an embed.\n *\n * @param data - The embed data to check\n */\nexport function embedLength(data: APIEmbed) {\n\treturn (\n\t\t(data.title?.length ?? 0) +\n\t\t(data.description?.length ?? 0) +\n\t\t(data.fields?.reduce((prev, curr) => prev + curr.name.length + curr.value.length, 0) ?? 0) +\n\t\t(data.footer?.text.length ?? 0) +\n\t\t(data.author?.name.length ?? 0)\n\t);\n}\n"
  },
  {
    "path": "packages/util/src/functions/index.ts",
    "content": "export * from './calculateShardId.js';\nexport * from './embedLength.js';\nexport * from './lazy.js';\nexport * from './range.js';\nexport * from './runtime.js';\nexport * from './userAgentAppendix.js';\n"
  },
  {
    "path": "packages/util/src/functions/lazy.ts",
    "content": "/**\n * Lazy is a wrapper around a value that is computed lazily. It is useful for\n * cases where the value is expensive to compute and the computation may not\n * be needed at all.\n *\n * @param cb - The callback to lazily evaluate\n * @typeParam Value - The type of the value\n * @example\n * ```ts\n * const value = lazy(() => computeExpensiveValue());\n * ```\n */\n// eslint-disable-next-line promise/prefer-await-to-callbacks\nexport function lazy<Value>(cb: () => Value): () => Value {\n\tlet defaultValue: Value;\n\t// eslint-disable-next-line promise/prefer-await-to-callbacks\n\treturn () => (defaultValue ??= cb());\n}\n"
  },
  {
    "path": "packages/util/src/functions/range.ts",
    "content": "/**\n * Options for creating a range\n */\nexport interface RangeOptions {\n\t/**\n\t * The end of the range (exclusive)\n\t */\n\tend: number;\n\t/**\n\t * The start of the range (inclusive)\n\t */\n\tstart: number;\n\t/**\n\t * The amount to increment by\n\t *\n\t * @defaultValue `1`\n\t */\n\tstep?: number;\n}\n\n/**\n * A generator to yield numbers in a given range\n *\n * @remarks\n * This method is end-exclusive, for example the last number yielded by `range(5)` is 4. If you\n * prefer for the end to be included add 1 to the range or `end` option.\n * @param range - A number representing the range to yield (exclusive) or an object with start, end and step\n * @example\n * Basic range\n * ```ts\n * for (const number of range(5)) {\n *  console.log(number);\n * }\n * // Prints 0, 1, 2, 3, 4\n * ```\n * @example\n * Range with a step\n * ```ts\n * for (const number of range({ start: 3, end: 10, step: 2 })) {\n * \tconsole.log(number);\n * }\n * // Prints 3, 5, 7, 9\n * ```\n */\nexport function* range(range: RangeOptions | number) {\n\tlet rangeEnd: number;\n\tlet start = 0;\n\tlet step = 1;\n\n\tif (typeof range === 'number') {\n\t\trangeEnd = range;\n\t} else {\n\t\tstart = range.start;\n\t\trangeEnd = range.end;\n\t\tstep = range.step ?? 1;\n\t}\n\n\tfor (let index = start; index < rangeEnd; index += step) {\n\t\tyield index;\n\t}\n}\n"
  },
  {
    "path": "packages/util/src/functions/runtime.ts",
    "content": "/* eslint-disable n/prefer-global/process */\n\nexport function shouldUseGlobalFetchAndWebSocket() {\n\t// Browser env and deno when ran directly\n\tif (typeof globalThis.process === 'undefined') {\n\t\treturn 'fetch' in globalThis && 'WebSocket' in globalThis;\n\t}\n\n\tif ('versions' in globalThis.process) {\n\t\treturn 'deno' in globalThis.process.versions || 'bun' in globalThis.process.versions;\n\t}\n\n\treturn false;\n}\n"
  },
  {
    "path": "packages/util/src/functions/userAgentAppendix.ts",
    "content": "/* eslint-disable n/prefer-global/process */\n\n/**\n * Resolves the user agent appendix string for the current environment.\n */\nexport function getUserAgentAppendix(): string {\n\t// https://vercel.com/docs/concepts/functions/edge-functions/edge-runtime#check-if-you're-running-on-the-edge-runtime\n\t// @ts-expect-error Vercel Edge functions\n\tif (typeof globalThis.EdgeRuntime !== 'undefined') {\n\t\treturn 'Vercel-Edge-Functions';\n\t}\n\n\t// @ts-expect-error Cloudflare Workers\n\tif (typeof globalThis.R2 !== 'undefined' && typeof globalThis.WebSocketPair !== 'undefined') {\n\t\t// https://developers.cloudflare.com/workers/runtime-apis/web-standards/#navigatoruseragent\n\t\treturn 'Cloudflare-Workers';\n\t}\n\n\t// https://docs.netlify.com/edge-functions/api/#netlify-global-object\n\t// @ts-expect-error Netlify Edge functions\n\tif (typeof globalThis.Netlify !== 'undefined') {\n\t\treturn 'Netlify-Edge-Functions';\n\t}\n\n\t// Most (if not all) edge environments will have `process` defined. Within a web browser we'll extract it using `navigator.userAgent`.\n\tif (typeof globalThis.process !== 'object') {\n\t\tif (typeof globalThis.navigator === 'object') {\n\t\t\treturn globalThis.navigator.userAgent;\n\t\t}\n\n\t\treturn 'UnknownEnvironment';\n\t}\n\n\tif ('versions' in globalThis.process) {\n\t\tif ('deno' in globalThis.process.versions) {\n\t\t\treturn `Deno/${globalThis.process.versions.deno}`;\n\t\t}\n\n\t\tif ('bun' in globalThis.process.versions) {\n\t\t\treturn `Bun/${globalThis.process.versions.bun}`;\n\t\t}\n\n\t\tif ('node' in globalThis.process.versions) {\n\t\t\treturn `Node.js/${globalThis.process.versions.node}`;\n\t\t}\n\t}\n\n\treturn 'UnknownEnvironment';\n}\n"
  },
  {
    "path": "packages/util/src/gatewayRateLimitError.ts",
    "content": "import type { GatewayOpcodeRateLimitMetadataMap, GatewayRateLimitedDispatchData } from 'discord-api-types/v10';\n\n/**\n * Represents the error thrown when the gateway emits a `RATE_LIMITED` event after a certain request.\n */\nexport class GatewayRateLimitError extends Error {\n\tpublic override readonly name = GatewayRateLimitError.name;\n\n\tpublic constructor(\n\t\t/**\n\t\t * The data associated with the rate limit event\n\t\t */\n\t\tpublic readonly data: GatewayRateLimitedDispatchData<keyof GatewayOpcodeRateLimitMetadataMap>,\n\t\t/**\n\t\t * The payload data that lead to this rate limit\n\t\t *\n\t\t * @privateRemarks\n\t\t * Too complicated to type properly here (i.e. extract the ['data']\n\t\t * of event payloads that have t = keyof GatewayOpcodeRateLimitMetadataMap)\n\t\t */\n\t\tpublic readonly payload: unknown,\n\t) {\n\t\tsuper(`Request with opcode ${data.opcode} was rate limited. Retry after ${data.retry_after} seconds.`);\n\t}\n}\n"
  },
  {
    "path": "packages/util/src/index.ts",
    "content": "export type * from './types.js';\nexport * from './functions/index.js';\nexport * from './encodables.js';\nexport type * from './RawFile.js';\nexport * from './Equatable.js';\nexport * from './gatewayRateLimitError.js';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/util#readme | @discordjs/util} version\n * that you are currently using.\n *\n * @privateRemarks This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild.\n */\nexport const version = '[VI]{{inject}}[/VI]' as string;\n"
  },
  {
    "path": "packages/util/src/types.ts",
    "content": "/**\n * Represents a type that may or may not be a promise\n */\nexport type Awaitable<Value> = PromiseLike<Value> | Value;\n"
  },
  {
    "path": "packages/util/tsconfig.docs.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.docs.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist-docs\"\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/util/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/util/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/util/tsconfig.test.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"noEmit\": true,\n\t\t\"skipLibCheck\": true\n\t},\n\t\"include\": [\"__tests__/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/util/tsup.config.ts",
    "content": "import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector';\nimport { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tesbuildPlugins: [esbuildPluginVersionInjector()],\n});\n"
  },
  {
    "path": "packages/voice/.cliff-jumperrc.json",
    "content": "{\n\t\"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n\t\"name\": \"voice\",\n\t\"org\": \"discordjs\",\n\t\"packagePath\": \"packages/voice\",\n\t\"identifierBase\": false\n}\n"
  },
  {
    "path": "packages/voice/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\ndist-docs\n\n# Docs\ndocs/**/*\n!docs/README.md\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/voice/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/voice/.prettierignore",
    "content": ".turbo\ncoverage\ndist\ndist-docs\ndocs/docs.api.json\nCHANGELOG.md\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/voice/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/voice/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n# [@discordjs/voice@0.19.2](https://github.com/discordjs/discord.js/compare/@discordjs/voice@0.19.1...@discordjs/voice@0.19.2) - (2026-03-13)\n\n## Bug Fixes\n\n- **voice:** Strip padding from packets and add guards (#11449) ([c486fb8](https://github.com/discordjs/discord.js/commit/c486fb81274a33baa22bcbd18bb5ff1dd6b58875)) by @Snazzah\n\n# [@discordjs/voice@0.19.1](https://github.com/discordjs/discord.js/compare/@discordjs/voice@0.19.0...@discordjs/voice@0.19.1) - (2026-03-09)\n\n## Bug Fixes\n\n- **voice:** Always install Davey as DAVE is becoming required (#11385) ([323d8e7](https://github.com/discordjs/discord.js/commit/323d8e757129fe1a885cf5a7887212d5e0941f8d)) by @vladfrangu\n- **voice:** Handle negative timeouts (#11362) ([5f93fbd](https://github.com/discordjs/discord.js/commit/5f93fbd0f21d1556c5ee6cb9f7c2e4d67ede19ca)) by @markokajzer\n- **voice:** Handle multiple transitions simultaneously (#11100) ([c4fc79a](https://github.com/discordjs/discord.js/commit/c4fc79a3cd2d271b75651d95a06c2e26709025d0)) by @Snazzah\n- Replace usages of `Buffer#slice()` with `Buffer#subarray()` (#11326) ([87b359e](https://github.com/discordjs/discord.js/commit/87b359e44d9965fcaf61e75df6c5c48d5a892155)) by @almeidx\n- **guide:** Miscellaneous fixes (#11147) ([a97ac82](https://github.com/discordjs/discord.js/commit/a97ac82619f0a807a7b816afa0140ba9161aa50d)) by @Jiralite\n- Adjust types for typescript upgrade (#11132) ([612c49b](https://github.com/discordjs/discord.js/commit/612c49b54618824b815278129765e308fe1da76c)) by @almeidx\n\n## Documentation\n\n- **voice:** Add DAVE dependency section (#11061) ([4db1092](https://github.com/discordjs/discord.js/commit/4db1092f8f5d7ba50f4bdc3f5e1bac4581e22a1c)) by @jNullj\n\n## Refactor\n\n- Remove builders and formatters re-export (#11361) ([84b85f4](https://github.com/discordjs/discord.js/commit/84b85f4c91e83b40eb2bd74d61304fcfdcabf6d5)) by @didinele\n\n## Testing\n\n- Fix type errors (#11325) ([5888663](https://github.com/discordjs/discord.js/commit/5888663392485d35b2538f042c48efea3b93cd54)) by @almeidx\n\n# [@discordjs/voice@0.19.0](https://github.com/discordjs/discord.js/compare/@discordjs/voice@0.18.0...@discordjs/voice@0.19.0) - (2025-08-17)\n\n## Bug Fixes\n\n- **voice:** Mark stream as ended (#10455) ([bc3a0c8](https://github.com/discordjs/discord.js/commit/bc3a0c83890cdc9b8ca6abd1fde59053d3c6d905)) by @nyapat\n\n## Documentation\n\n- Replace Discord API with Discord Developers (#10968) ([3a060f7](https://github.com/discordjs/discord.js/commit/3a060f74945da78535440890be0a5df8bd0ee36b)) by @Jiralite\n- Add missing, fix existing (#10842) ([e094faf](https://github.com/discordjs/discord.js/commit/e094faf225e53e7e5ad94f9f62ecb5d3a225a56b)) by @almeidx\n- Export all visible symbols (#10760) ([78d512c](https://github.com/discordjs/discord.js/commit/78d512c347320e5d4bf97f7f0c89d3469d923af8)) by @almeidx\n- Guide setup (#10862) ([2184085](https://github.com/discordjs/discord.js/commit/2184085fdaf00c982130212eb27ab878df2c3e1e)) by @iCrawl\n- Fix close tags (#10756) ([5c49b6d](https://github.com/discordjs/discord.js/commit/5c49b6d9af9b0e69c4792ef4be831607675d418c)) by @Jiralite\n- Typos (#10628) ([a696005](https://github.com/discordjs/discord.js/commit/a69600546a33b1599fbf6c8cc44caaf307a12a7e)) by @Jiralite\n\n## Features\n\n- Implement DAVE end-to-end encryption (#10921) ([8bdea62](https://github.com/discordjs/discord.js/commit/8bdea6232b1db20c615614a8f8baea2347c4466b)) by @Snazzah\n- **voice:** Use voice gateway v8 (#10918) ([d40ceed](https://github.com/discordjs/discord.js/commit/d40ceedad40a8a0b64c173706fc6eea780a5477c)) by @Snazzah\n- Print out support for aes-256-gcm in native node:crypto (#10764) ([19d48f6](https://github.com/discordjs/discord.js/commit/19d48f6d6cb8218b896ddf69be313ebe05a96996)) by @vladfrangu\n\n## Build\n\n- Bump Node.js to 22.12.0 (#10726) ([3db8ce7](https://github.com/discordjs/discord.js/commit/3db8ce70a2d20bd2def70a2c839b015bc24195eb)) by @Jiralite\n  - **BREAKING CHANGE:** Node.js 22.12.0 or above is required.\n- Bump Node.js to 20 (#10616) ([e89c6b6](https://github.com/discordjs/discord.js/commit/e89c6b66ac6503c2f120539f4820e72589be3f94)) by @Jiralite\n  - **BREAKING CHANGE:** Node.js 20 or above is required.\n\n### New Contributors\n\n* @Snazzah made their first contribution in #10921\n* @nsgpriyanshu made their first contribution in #10428\n\n# [@discordjs/voice@0.18.0](https://github.com/discordjs/discord.js/compare/@discordjs/voice@0.17.0...@discordjs/voice@0.18.0) - (2024-11-17)\n\n## Features\n\n- **voice:** Add new encryption methods, remove old methods (#10451) ([9f8b9b1](https://github.com/discordjs/discord.js/commit/9f8b9b1d66edcc84ecf396d807dee7cf39f760c8)) by @nyapat\n  - **BREAKING CHANGE:** This library no longer supports using `tweetnacl` as an encryption library due to Discord deprecating the algorithms that `tweetnacl` helped us support (read more [here](https://discord.com/developers/docs/change-log#voice-encryption-modes)). Please migrate to one of: `sodium-native`, `sodium`, `@stablelib/xchacha20poly1305`, `@noble/ciphers` or `libsodium-wrappers` unless your system supports `aes-256-gcm` (verify by running `require('node:crypto').getCiphers().includes('aes-256-gcm')`).\n\n## Testing\n\n- Replace jest with vitest (#10472) ([24128a3](https://github.com/discordjs/discord.js/commit/24128a3c459ed0c3eb0932308f03ecc55e3c60f1)) by @nyapat\n\n### New Contributors\n\n* @Yareaj made their first contribution in #10575\n\n# [@discordjs/voice@0.17.0](https://github.com/discordjs/discord.js/compare/@discordjs/voice@0.16.0...@discordjs/voice@0.17.0) - (2024-05-04)\n\n## Bug Fixes\n\n- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))\n- **TransformerGraph:** Explicitly include input args for readable input cases instead of just for string input cases (#9793) ([788888a](https://github.com/discordjs/discord.js/commit/788888ab9ad17f1c8d85d68656c617334feb4361))\n- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2))\n\n## Documentation\n\n- Split docs.api.json into multiple json files ([597340f](https://github.com/discordjs/discord.js/commit/597340f288437c35da8c703d9b621274de60d880))\n- **create-discord-bot:** Support bun in create-discord-bot (#9798) ([7157748](https://github.com/discordjs/discord.js/commit/7157748fe3a69265896adf0450cd3f37acbcf97b))\n- Update Node.js requirement to 16.11.0 (#9764) ([188877c](https://github.com/discordjs/discord.js/commit/188877c50af70f0d5cffb246620fa277435c6ce6))\n- Include StreamType enum description in new docs (#9457) ([36216c0](https://github.com/discordjs/discord.js/commit/36216c0e1a0c99e5200de97f08d054e278fd3f0f))\n- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9))\n\n## Features\n\n- Local and preview detection ([79fbda3](https://github.com/discordjs/discord.js/commit/79fbda3aac6d4f0f8bfb193e797d09cbe331d315))\n\n## Refactor\n\n- Docs (#10126) ([18cce83](https://github.com/discordjs/discord.js/commit/18cce83d80598c430218775c53441b6b2ecdc776))\n- Move `getNode`/`canEnableFFmpegOptimizations` into a lazy loaded call (#9918) ([637e1a4](https://github.com/discordjs/discord.js/commit/637e1a4ddb6d5810deb31c5b90400ca277218270))\n\n# [@discordjs/voice@0.16.1](https://github.com/discordjs/discord.js/compare/@discordjs/voice@0.16.0...@discordjs/voice@0.16.1) - (2023-11-12)\n\n## Bug Fixes\n\n- **TransformerGraph:** Explicitly include input args for readable input cases instead of just for string input cases (#9793) ([788888a](https://github.com/discordjs/discord.js/commit/788888ab9ad17f1c8d85d68656c617334feb4361))\n- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2))\n\n## Documentation\n\n- **create-discord-bot:** Support bun in create-discord-bot (#9798) ([7157748](https://github.com/discordjs/discord.js/commit/7157748fe3a69265896adf0450cd3f37acbcf97b))\n- Update Node.js requirement to 16.11.0 (#9764) ([188877c](https://github.com/discordjs/discord.js/commit/188877c50af70f0d5cffb246620fa277435c6ce6))\n- Include StreamType enum description in new docs (#9457) ([36216c0](https://github.com/discordjs/discord.js/commit/36216c0e1a0c99e5200de97f08d054e278fd3f0f))\n- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9))\n\n## Refactor\n\n- Move `getNode`/`canEnableFFmpegOptimizations` into a lazy loaded call (#9918) ([637e1a4](https://github.com/discordjs/discord.js/commit/637e1a4ddb6d5810deb31c5b90400ca277218270))\n\n# [@discordjs/voice@0.16.0](https://github.com/discordjs/discord.js/compare/@discordjs/voice@0.15.0...@discordjs/voice@0.16.0) - (2023-04-01)\n\n## Bug Fixes\n\n- **scripts:** Accessing tsComment ([d8d5f31](https://github.com/discordjs/discord.js/commit/d8d5f31d3927fd1de62f1fa3a1a6e454243ad87b))\n\n## Features\n\n- **website:** Render syntax and mdx on the server (#9086) ([ee5169e](https://github.com/discordjs/discord.js/commit/ee5169e0aadd7bbfcd752aae614ec0f69602b68b))\n\n## Refactor\n\n- Compare with `undefined` directly (#9191) ([869153c](https://github.com/discordjs/discord.js/commit/869153c3fdf155783e7c0ecebd3627b087c3a026))\n\n# [@discordjs/voice@0.15.0](https://github.com/discordjs/discord.js/compare/@discordjs/voice@0.14.0...@discordjs/voice@0.15.0) - (2023-03-12)\n\n## Bug Fixes\n\n- **Voice:** Send keep alives without awaiting a response (#9202) ([c6d98fa](https://github.com/discordjs/discord.js/commit/c6d98fa0c55a482cd4a81abd6f08290c29839b1b))\n\n## Documentation\n\n- Fix version export (#9049) ([8b70f49](https://github.com/discordjs/discord.js/commit/8b70f497a1207e30edebdecd12b926c981c13d28))\n\n## Features\n\n- **website:** Add support for source file links (#9048) ([f6506e9](https://github.com/discordjs/discord.js/commit/f6506e99c496683ee0ab67db0726b105b929af38))\n\n# [@discordjs/voice@0.14.0](https://github.com/discordjs/discord.js/compare/@discordjs/voice@0.13.0...@discordjs/voice@0.14.0) - (2022-11-28)\n\n## Bug Fixes\n\n- Voice postbuild script (#8741) ([5ffabb1](https://github.com/discordjs/discord.js/commit/5ffabb119fa3a35266ab31545a4a4b9a049eacce))\n- Pin @types/node version ([9d8179c](https://github.com/discordjs/discord.js/commit/9d8179c6a78e1c7f9976f852804055964d5385d4))\n\n## Features\n\n- New select menus (#8793) ([5152abf](https://github.com/discordjs/discord.js/commit/5152abf7285581abf7689e9050fdc56c4abb1e2b))\n\n# [@discordjs/voice@0.13.0](https://github.com/discordjs/discord.js/compare/@discordjs/voice@0.11.0...@discordjs/voice@0.13.0) - (2022-10-08)\n\n## Bug Fixes\n\n- Footer / sidebar / deprecation alert ([ba3e0ed](https://github.com/discordjs/discord.js/commit/ba3e0ed348258fe8e51eefb4aa7379a1230616a9))\n\n## Documentation\n\n- Change name (#8604) ([dd5a089](https://github.com/discordjs/discord.js/commit/dd5a08944c258a847fc4377f1d5e953264ab47d0))\n\n## Features\n\n- Web-components (#8715) ([0ac3e76](https://github.com/discordjs/discord.js/commit/0ac3e766bd9dbdeb106483fa4bb085d74de346a2))\n- **website:** Show `constructor` information (#8540) ([e42fd16](https://github.com/discordjs/discord.js/commit/e42fd1636973b10dd7ed6fb4280ee1a4a8f82007))\n- **WebSocketShard:** Support new resume url (#8480) ([bc06cc6](https://github.com/discordjs/discord.js/commit/bc06cc638d2f57ab5c600e8cdb6afc8eb2180166))\n\n## Refactor\n\n- Website components (#8600) ([c334157](https://github.com/discordjs/discord.js/commit/c3341570d983aea9ecc419979d5a01de658c9d67))\n- Use `eslint-config-neon` for packages. (#8579) ([edadb9f](https://github.com/discordjs/discord.js/commit/edadb9fe5dfd9ff51a3cfc9b25cb242d3f9f5241))\n- Docs design (#8487) ([4ab1d09](https://github.com/discordjs/discord.js/commit/4ab1d09997a18879a9eb9bda39df6f15aa22557e))\n\n# [@discordjs/voice@0.11.0](https://github.com/discordjs/discord.js/compare/@discordjs/voice@0.10.0...@discordjs/voice@0.11.0) - (2022-07-17)\n\n## Bug Fixes\n\n- **VoiceReceiver:** ParsePacket correctly (#8277) ([1a6ddbb](https://github.com/discordjs/discord.js/commit/1a6ddbbe7b99b5eff4617b99399965740c38490b))\n- **recorder-example:** Bump dependencies (#8123) ([10ba008](https://github.com/discordjs/discord.js/commit/10ba0080cc20c44389779416b6a8215603eca6ca))\n- **SpeakingMap:** Allow docgen to detect event name (#8236) ([c271e05](https://github.com/discordjs/discord.js/commit/c271e05223d84f643314be649344a2cfe514923f))\n- **codecov:** Use cobertura (#8235) ([fd1c240](https://github.com/discordjs/discord.js/commit/fd1c24036f3c1835b918a12be8760d46f80460ac))\n- **voice:** Re-add accidental removal of postbuild script ([f8739bd](https://github.com/discordjs/discord.js/commit/f8739bd9c0c691c9593761237189dc529ed0b0a3))\n\n## Documentation\n\n- Add codecov coverage badge to readmes (#8226) ([f6db285](https://github.com/discordjs/discord.js/commit/f6db285c073898a749fe4591cbd4463d1896daf5))\n- Remove Music bot in voice examples (#8203) ([741b3c8](https://github.com/discordjs/discord.js/commit/741b3c8e279c1cc6ba862bc83299d369bc6c1bc6))\n\n## Features\n\n- **builder:** Add max min length in string option (#8214) ([96c8d21](https://github.com/discordjs/discord.js/commit/96c8d21f95eb366c46ae23505ba9054f44821b25))\n- Add website documentation early mvp (#8183) ([d95197c](https://github.com/discordjs/discord.js/commit/d95197cc78593df4d0a8d1cc492b0e41b4ab58b8))\n- **docgen:** Proper event parsing for typescript ([d4b41dd](https://github.com/discordjs/discord.js/commit/d4b41dd0815b493b599d4f4d1b6dd18cd99f91ea))\n- **docgen:** Update typedoc ([b3346f4](https://github.com/discordjs/discord.js/commit/b3346f4b9b3d4f96443506643d4631dc1c6d7b21))\n- Website (#8043) ([127931d](https://github.com/discordjs/discord.js/commit/127931d1df7a2a5c27923c2f2151dbf3824e50cc))\n- **docgen:** Typescript support ([3279b40](https://github.com/discordjs/discord.js/commit/3279b40912e6aa61507bedb7db15a2b8668de44b))\n- Docgen package (#8029) ([8b979c0](https://github.com/discordjs/discord.js/commit/8b979c0245c42fd824d8e98745ee869f5360fc86))\n- Add scripts package for locally used scripts ([f2ae1f9](https://github.com/discordjs/discord.js/commit/f2ae1f9348bfd893332a9060f71a8a5f272a1b8b))\n\n## Refactor\n\n- Move all the config files to root (#8033) ([769ea0b](https://github.com/discordjs/discord.js/commit/769ea0bfe78c4f1d413c6b397c604ffe91e39c6a))\n\n## Typings\n\n- **voice:** Bring back typed events (#8109) ([70b42bb](https://github.com/discordjs/discord.js/commit/70b42bb64a4f83da0da242569b9c7921c8d1e26f))\n\n# [@discordjs/voice@0.10.0](https://github.com/discordjs/discord.js/compare/@discordjs/voice@0.16.1...@discordjs/voice@0.10.0) - (2022-06-04)\n\n## Styling\n\n- Cleanup tests and tsup configs ([6b8ef20](https://github.com/discordjs/discord.js/commit/6b8ef20cb3af5b5cfd176dd0aa0a1a1e98551629))\n\n# [@discordjs/voice@0.8.0](https://github.com/discordjs/discord.js/compare/@discordjs/voice@0.7.5...@discordjs/voice@0.8.0) - (2022-01-24)\n\n## Refactor\n\n- PresenceUpdate and demuxProbe (#7248) ([1745973](https://github.com/discordjs/discord.js/commit/174597302408f13c5bb685e2fb02ae2137cb481d))\n\n## Testing\n\n- **voice:** Fix tests ([62c74b8](https://github.com/discordjs/discord.js/commit/62c74b8333066465e5bd295b8b102b35a506751d))\n- Fix voice secretbox tests ([4a2dbd6](https://github.com/discordjs/discord.js/commit/4a2dbd62382f904d596b34da0116d50e724b81c4))\n- Fix voice tests ([b593bd3](https://github.com/discordjs/discord.js/commit/b593bd32a98282a92fa28f2fb0a8ef239866622c))\n"
  },
  {
    "path": "packages/voice/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2022 Noel Buechler\n   Copyright 2020 Amish Shah\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/voice/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/voice\"><img src=\"https://img.shields.io/npm/v/@discordjs/voice.svg?maxAge=3600\" alt=\"npm version\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/voice\"><img src=\"https://img.shields.io/npm/dt/@discordjs/voice.svg?maxAge=3600\" alt=\"npm downloads\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/commits/main/packages/voice\"><img alt=\"Last commit.\" src=\"https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fvoice\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t\t<a href=\"https://codecov.io/gh/discordjs/discord.js\"><img src=\"https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=voice\" alt=\"Code coverage\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## About\n\n`@discordjs/voice` is a TypeScript implementation of the Discord Voice API for Node.js.\n\n**Features:**\n\n- Send and receive\\* audio in Discord voice-based channels\n- A strong focus on reliability and predictable behavior\n- Horizontal scalability and libraries other than [discord.js](https://discord.js.org/) are supported with custom adapters\n- A robust audio processing system that can handle a wide range of audio sources\n\n\\*_Audio receive is not documented by Discord so stable support is not guaranteed_\n\n## Installation\n\n**Node.js 22.12.0 or newer is required.**\n\n```sh\nnpm install @discordjs/voice\nyarn add @discordjs/voice\npnpm add @discordjs/voice\nbun add @discordjs/voice\n```\n\n## Dependencies\n\nThis library has several optional dependencies to support a variety\nof different platforms. Install one dependency from each of the\ncategories shown below. The dependencies are listed in order of\npreference for performance. If you can't install one of the options,\ntry installing another.\n\n**Encryption Libraries (npm install):**\n\n> [!NOTE]\n> You only need to install one of these libraries if your system does not support `aes-256-gcm` (verify by running `require('node:crypto').getCiphers().includes('aes-256-gcm')`).\n\n- `sodium-native`: ^3.3.0\n- `sodium`: ^3.0.2\n- `@stablelib/xchacha20poly1305`: ^2.0.0\n- `@noble/ciphers`: ^1.0.0\n- `libsodium-wrappers`: ^0.7.9\n\n**DAVE Protocol Libraries (e2ee)**\n\n> [!NOTE]\n> At this time, `@snazzah/davey` is the only supported DAVE protocol library in this package, and comes pre-installed. In the future, we may support other libraries once they are created.\n\n- `@snazzah/davey`: ^0.1.6\n\n**Opus Libraries (npm install):**\n\n- `@discordjs/opus`: ^0.4.0\n- `opusscript`: ^0.0.7\n\n**FFmpeg:**\n\n- [`FFmpeg`](https://ffmpeg.org/) (installed and added to environment)\n- `ffmpeg-static`: ^4.2.7 (npm install)\n\n## Examples\n\nThe [voice-examples][voice-examples] repository contains examples on how to use this package. Feel free to check them out if you need a nudge in the right direction.\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Documentation][documentation]\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [npm][npm]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the\n[documentation][documentation].  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs/packages/voice/stable\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/voice\n[npm]: https://www.npmjs.com/package/@discordjs/voice\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n[voice-examples]: https://github.com/discordjs/voice-examples\n"
  },
  {
    "path": "packages/voice/__mocks__/rtp.ts",
    "content": "import { Buffer } from 'node:buffer';\n\n// The following constants are silence packets collected from various platforms because Discord did not previously send header extensions\n// The header extension (extra data in decrypted vs opusFrame) can be detected in the position of {encrypted.subarray(12,14)} if it is equal to 0xbe,0xde\n// The header extension length will then follow as an integer and can be removed from the decrypted data (see ../src/receive/VoiceReceiver.ts:parsePacket)\n\nexport const RTP_PACKET_DESKTOP = {\n\tssrc: 341_124,\n\tpacket: Buffer.from([\n\t\t0x90, 0x78, 0x27, 0xe9, 0xf7, 0xcb, 0xbc, 0xd1, 0x0, 0x5, 0x34, 0x84, 0xbe, 0xde, 0x0, 0x1, 0x8a, 0xbb, 0xe2, 0x97,\n\t\t0x21, 0x9f, 0x1f, 0x67, 0xcd, 0x17, 0x91, 0x56, 0x43, 0xa0, 0x98, 0xfd, 0xa9, 0x25, 0x81, 0x63, 0x13, 0xb4, 0x1e,\n\t\t0xae, 0x88, 0xe4, 0x0, 0xed, 0x0, 0x0, 0x0,\n\t]),\n\tdecrypted: Buffer.from([0x10, 0xff, 0x90, 0x0, 0xf8, 0xff, 0xfe]),\n\topusFrame: Buffer.from([0xf8, 0xff, 0xfe]),\n};\n\nexport const RTP_PACKET_CHROME = {\n\tssrc: 172_360,\n\tpacket: Buffer.from([\n\t\t0x80, 0x78, 0x46, 0xdf, 0x27, 0x59, 0x2a, 0xd7, 0x0, 0x2, 0xa1, 0x48, 0x42, 0x9e, 0x53, 0xec, 0x73, 0xc1, 0x71,\n\t\t0x22, 0x71, 0x60, 0x90, 0xff, 0x1b, 0x20, 0x47, 0x2c, 0xdc, 0x86, 0xc4, 0x9a, 0x0, 0x0, 0x0,\n\t]),\n\tdecrypted: Buffer.from([0xf8, 0xff, 0xfe]),\n\topusFrame: Buffer.from([0xf8, 0xff, 0xfe]),\n};\n\nexport const RTP_PACKET_ANDROID = {\n\tssrc: 172_596,\n\tpacket: Buffer.from([\n\t\t0x90, 0x78, 0x39, 0xd0, 0xe0, 0x59, 0xf5, 0x47, 0x0, 0x2, 0xa2, 0x34, 0xbe, 0xde, 0x0, 0x1, 0x12, 0x6d, 0x87, 0x56,\n\t\t0x25, 0xc8, 0x3e, 0x96, 0xc0, 0x71, 0x9a, 0x1, 0x83, 0xe, 0x1, 0x62, 0x91, 0x95, 0x1f, 0x76, 0x57, 0x15, 0x41, 0xab,\n\t\t0xee, 0x5b, 0xac, 0x8b, 0x0, 0x0, 0x0,\n\t]),\n\tdecrypted: Buffer.from([0x10, 0xff, 0x90, 0x0, 0xf8, 0xff, 0xfe]),\n\topusFrame: Buffer.from([0xf8, 0xff, 0xfe]),\n};\n\nexport const XCHACHA20_SAMPLE = {\n\tencrypted: Buffer.from([\n\t\t144, 120, 86, 102, 191, 243, 52, 48, 0, 0, 191, 25, 190, 222, 0, 2, 211, 29, 103, 76, 73, 102, 37, 162, 65, 41, 39,\n\t\t252, 26, 85, 90, 228, 241, 169, 112, 65, 95, 183, 236, 4, 87, 207, 215, 195, 180, 39, 60, 224, 221, 89, 32, 187,\n\t\t208, 228, 145, 252, 132, 189, 103, 208, 180, 183, 217, 50, 70, 86, 20, 28, 142, 66, 251, 122, 214, 17, 7, 173, 203,\n\t\t117, 148, 232, 118, 103, 8, 136, 227, 136, 249, 243, 135, 41, 31, 103, 146, 15, 1, 0, 0,\n\t]),\n\tkey: new Uint8Array([\n\t\t105, 217, 109, 27, 247, 101, 71, 49, 71, 151, 172, 85, 91, 11, 201, 23, 43, 242, 147, 81, 96, 60, 157, 50, 63, 200,\n\t\t133, 174, 108, 144, 251, 110,\n\t]),\n\n\tdecrypted: Buffer.from([\n\t\t0x32, 0x64, 0xe6, 0x62, 0x10, 0xe3, 0x90, 0x02, 0x78, 0x07, 0xd6, 0x2f, 0x52, 0x23, 0x20, 0x9a, 0xab, 0x2c, 0xcc,\n\t\t0x1c, 0x88, 0x8e, 0xcb, 0xd9, 0x4d, 0xe5, 0x33, 0x7a, 0x4b, 0x2b, 0xed, 0xa7, 0xaf, 0x5f, 0x8d, 0xb2, 0x59, 0x99,\n\t\t0x75, 0x36, 0xf2, 0x88, 0xf5, 0xc7, 0x9f, 0x47, 0xaf, 0x92, 0x5a, 0x96, 0x3b, 0xd8, 0x9f, 0x3a, 0xb4, 0x13, 0xce,\n\t\t0x2f, 0xae, 0x0a, 0x37,\n\t]),\n};\n\nexport const AES256GCM_SAMPLE = {\n\tencrypted: Buffer.from([\n\t\t128, 120, 163, 156, 159, 11, 131, 240, 0, 0, 197, 183, 175, 91, 102, 101, 195, 6, 200, 143, 117, 72, 108, 44, 165,\n\t\t123, 121, 49, 111, 38, 3, 0, 0, 0, 90,\n\t]),\n\tkey: Buffer.from([\n\t\t109, 77, 195, 27, 111, 50, 231, 84, 179, 255, 217, 217, 34, 227, 19, 106, 195, 20, 150, 237, 38, 4, 101, 210, 5, 90,\n\t\t8, 241, 58, 223, 24, 24,\n\t]),\n\n\tdecrypted: Buffer.from([0xf8, 0xff, 0xfe]),\n};\n"
  },
  {
    "path": "packages/voice/__tests__/AudioPlayer.test.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\n/* eslint-disable @typescript-eslint/dot-notation */\n\nimport { Buffer } from 'node:buffer';\nimport { once } from 'node:events';\nimport process from 'node:process';\nimport { Readable } from 'node:stream';\nimport { describe, test, expect, vitest, type MockedFunction, beforeEach, afterEach } from 'vitest';\nimport { addAudioPlayer, deleteAudioPlayer } from '../src/DataStore';\nimport { VoiceConnection, VoiceConnectionStatus } from '../src/VoiceConnection';\nimport type { AudioPlayer } from '../src/audio/AudioPlayer';\nimport { createAudioPlayer, AudioPlayerStatus, SILENCE_FRAME } from '../src/audio/AudioPlayer';\nimport { AudioPlayerError } from '../src/audio/AudioPlayerError';\nimport { AudioResource } from '../src/audio/AudioResource';\nimport { NoSubscriberBehavior } from '../src/index';\n\nvitest.mock('../src/DataStore', () => ({\n\taddAudioPlayer: vitest.fn(),\n\tdeleteAudioPlayer: vitest.fn(),\n}));\n\nvitest.mock('../src/VoiceConnection', async (importOriginal) => {\n\t// eslint-disable-next-line @typescript-eslint/consistent-type-imports\n\tconst actual = await importOriginal<typeof import('../src/VoiceConnection')>();\n\tconst VoiceConnection = vitest.fn();\n\tVoiceConnection.prototype.setSpeaking = vitest.fn();\n\tVoiceConnection.prototype.dispatchAudio = vitest.fn();\n\tVoiceConnection.prototype.prepareAudioPacket = vitest.fn();\n\treturn {\n\t\t...actual,\n\t\tVoiceConnection,\n\t};\n});\n\nvitest.mock('../src/audio/AudioPlayerError', () => ({\n\tAudioPlayerError: vitest.fn(),\n}));\n\nfunction* silence() {\n\twhile (true) {\n\t\tyield Buffer.from([0xf8, 0xff, 0xfe]);\n\t}\n}\n\nfunction createVoiceConnectionMock() {\n\tconst connection = new VoiceConnection({} as any, {} as any);\n\tconnection.state = {\n\t\tstatus: VoiceConnectionStatus.Signalling,\n\t\tadapter: {\n\t\t\tsendPayload: vitest.fn(),\n\t\t\tdestroy: vitest.fn(),\n\t\t},\n\t};\n\tconnection.subscribe = vitest.fn((player) => player['subscribe'](connection));\n\treturn connection;\n}\n\nasync function wait() {\n\t// eslint-disable-next-line no-promise-executor-return\n\treturn new Promise((resolve) => process.nextTick(resolve));\n}\n\nasync function started(resource: AudioResource) {\n\twhile (!resource.started) {\n\t\tawait wait();\n\t}\n\n\treturn resource;\n}\n\nlet player: AudioPlayer | undefined;\n\nbeforeEach(() => {\n\tvitest.resetAllMocks();\n});\n\nafterEach(() => {\n\tplayer?.stop(true);\n});\n\ndescribe('State transitions', () => {\n\ttest('Starts in Idle state', () => {\n\t\tplayer = createAudioPlayer();\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Idle);\n\t\texpect(addAudioPlayer).toBeCalledTimes(0);\n\t\texpect(deleteAudioPlayer).toBeCalledTimes(0);\n\t});\n\n\ttest('Playing resource with pausing and resuming', async () => {\n\t\t// Call AudioResource constructor directly to avoid analyzing pipeline for stream\n\t\tconst resource = await started(new AudioResource([], [Readable.from(silence())], null, 5));\n\t\tplayer = createAudioPlayer();\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Idle);\n\n\t\t// Pause and unpause should not affect the status of an Idle player\n\t\texpect(player.pause()).toEqual(false);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Idle);\n\t\texpect(player.unpause()).toEqual(false);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Idle);\n\t\texpect(addAudioPlayer).toBeCalledTimes(0);\n\n\t\tplayer.play(resource);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\t\texpect(addAudioPlayer).toBeCalledTimes(1);\n\n\t\t// Expect pause() to return true and transition to paused state\n\t\texpect(player.pause()).toEqual(true);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Paused);\n\n\t\t// further calls to pause() should be unsuccessful\n\t\texpect(player.pause()).toEqual(false);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Paused);\n\n\t\t// unpause() should transition back to Playing\n\t\texpect(player.unpause()).toEqual(true);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\n\t\t// further calls to unpause() should be unsuccessful\n\t\texpect(player.unpause()).toEqual(false);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\n\t\t// The audio player should not have been deleted throughout these changes\n\t\texpect(deleteAudioPlayer).toBeCalledTimes(0);\n\t});\n\n\ttest('Playing to Stopping', async () => {\n\t\tconst resource = await started(new AudioResource([], [Readable.from(silence())], null, 5));\n\t\tplayer = createAudioPlayer();\n\n\t\t// stop() shouldn't do anything in Idle state\n\t\texpect(player.stop(true)).toEqual(false);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Idle);\n\n\t\tplayer.play(resource);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\t\texpect(addAudioPlayer).toBeCalledTimes(1);\n\t\texpect(deleteAudioPlayer).toBeCalledTimes(0);\n\n\t\texpect(player.stop()).toEqual(true);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\t\texpect(addAudioPlayer).toBeCalledTimes(1);\n\t\texpect(deleteAudioPlayer).toBeCalledTimes(0);\n\t\texpect(resource.silenceRemaining).toEqual(5);\n\t});\n\n\ttest('Buffering to Playing', async () => {\n\t\tconst resource = new AudioResource([], [Readable.from(silence())], null, 5);\n\t\tplayer = createAudioPlayer();\n\n\t\tplayer.play(resource);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Buffering);\n\n\t\tawait started(resource);\n\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\t\texpect(addAudioPlayer).toHaveBeenCalled();\n\t\texpect(deleteAudioPlayer).not.toHaveBeenCalled();\n\t});\n\n\tdescribe('NoSubscriberBehavior transitions', () => {\n\t\ttest('NoSubscriberBehavior.Pause', async () => {\n\t\t\tconst connection = createVoiceConnectionMock();\n\t\t\tif (connection.state.status !== VoiceConnectionStatus.Signalling) {\n\t\t\t\tthrow new Error('Voice connection should have been Signalling');\n\t\t\t}\n\n\t\t\tconst resource = await started(new AudioResource([], [Readable.from(silence())], null, 5));\n\t\t\tplayer = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Pause } });\n\t\t\tconnection.subscribe(player);\n\n\t\t\tplayer.play(resource);\n\t\t\texpect(player.checkPlayable()).toEqual(true);\n\t\t\tplayer['_stepPrepare']();\n\t\t\texpect(player.state.status).toEqual(AudioPlayerStatus.AutoPaused);\n\n\t\t\tconnection.state = {\n\t\t\t\t...connection.state,\n\t\t\t\tstatus: VoiceConnectionStatus.Ready,\n\t\t\t\tnetworking: null as any,\n\t\t\t};\n\n\t\t\texpect(player.checkPlayable()).toEqual(true);\n\t\t\tplayer['_stepPrepare']();\n\t\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\t\t});\n\n\t\ttest('NoSubscriberBehavior.Play', async () => {\n\t\t\tconst resource = await started(new AudioResource([], [Readable.from(silence())], null, 5));\n\t\t\tplayer = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Play } });\n\n\t\t\tplayer.play(resource);\n\t\t\texpect(player.checkPlayable()).toEqual(true);\n\t\t\tplayer['_stepPrepare']();\n\t\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\t\t});\n\n\t\ttest('NoSubscriberBehavior.Stop', async () => {\n\t\t\tconst resource = await started(new AudioResource([], [Readable.from(silence())], null, 5));\n\t\t\tplayer = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Stop } });\n\n\t\t\tplayer.play(resource);\n\t\t\texpect(addAudioPlayer).toBeCalledTimes(1);\n\t\t\texpect(player.checkPlayable()).toEqual(true);\n\t\t\tplayer['_stepPrepare']();\n\t\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Idle);\n\t\t\texpect(deleteAudioPlayer).toBeCalledTimes(1);\n\t\t});\n\t});\n\n\ttest('Normal playing state', async () => {\n\t\tconst connection = createVoiceConnectionMock();\n\t\tif (connection.state.status !== VoiceConnectionStatus.Signalling) {\n\t\t\tthrow new Error('Voice connection should have been Signalling');\n\t\t}\n\n\t\tconnection.state = {\n\t\t\t...connection.state,\n\t\t\tstatus: VoiceConnectionStatus.Ready,\n\t\t\tnetworking: null as any,\n\t\t};\n\n\t\tconst buffer = Buffer.from([1, 2, 4, 8]);\n\t\tconst resource = await started(\n\t\t\tnew AudioResource([], [Readable.from([buffer, buffer, buffer, buffer, buffer])], null, 5),\n\t\t);\n\t\tplayer = createAudioPlayer();\n\t\tconnection.subscribe(player);\n\n\t\tplayer.play(resource);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\t\texpect(addAudioPlayer).toBeCalledTimes(1);\n\t\texpect(player.checkPlayable()).toEqual(true);\n\n\t\t// Run through a few packet cycles\n\t\tfor (let index = 1; index <= 5; index++) {\n\t\t\tplayer['_stepDispatch']();\n\t\t\texpect(connection.dispatchAudio).toHaveBeenCalledTimes(index);\n\n\t\t\tawait wait(); // Wait for the stream\n\n\t\t\tplayer['_stepPrepare']();\n\t\t\texpect(connection.prepareAudioPacket).toHaveBeenCalledTimes(index);\n\t\t\texpect(connection.prepareAudioPacket).toHaveBeenLastCalledWith(buffer);\n\t\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\t\t\tif (player.state.status === AudioPlayerStatus.Playing) {\n\t\t\t\texpect(player.state.playbackDuration).toStrictEqual(index * 20);\n\t\t\t}\n\t\t}\n\n\t\t// Expect silence to be played\n\t\tplayer['_stepDispatch']();\n\t\texpect(connection.dispatchAudio).toHaveBeenCalledTimes(6);\n\t\tawait wait();\n\t\tplayer['_stepPrepare']();\n\t\tconst prepareAudioPacket = connection.prepareAudioPacket as unknown as MockedFunction<\n\t\t\ttypeof connection.prepareAudioPacket\n\t\t>;\n\t\texpect(prepareAudioPacket).toHaveBeenCalledTimes(6);\n\t\texpect(prepareAudioPacket.mock.calls[5]![0]).toEqual(silence().next().value);\n\n\t\tplayer.stop(true);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Idle);\n\t\texpect(connection.setSpeaking).toBeCalledTimes(1);\n\t\texpect(connection.setSpeaking).toHaveBeenLastCalledWith(false);\n\t\texpect(deleteAudioPlayer).toHaveBeenCalledTimes(1);\n\t});\n\n\ttest('stop() causes resource to use silence padding frames', async () => {\n\t\tconst connection = createVoiceConnectionMock();\n\t\tif (connection.state.status !== VoiceConnectionStatus.Signalling) {\n\t\t\tthrow new Error('Voice connection should have been Signalling');\n\t\t}\n\n\t\tconnection.state = {\n\t\t\t...connection.state,\n\t\t\tstatus: VoiceConnectionStatus.Ready,\n\t\t\tnetworking: null as any,\n\t\t};\n\n\t\tconst buffer = Buffer.from([1, 2, 4, 8]);\n\t\tconst resource = await started(\n\t\t\tnew AudioResource([], [Readable.from([buffer, buffer, buffer, buffer, buffer])], null, 5),\n\t\t);\n\t\tplayer = createAudioPlayer();\n\t\tconnection.subscribe(player);\n\n\t\tplayer.play(resource);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\t\texpect(addAudioPlayer).toBeCalledTimes(1);\n\t\texpect(player.checkPlayable()).toEqual(true);\n\n\t\tplayer.stop();\n\n\t\t// Run through a few packet cycles\n\t\tfor (let index = 1; index <= 5; index++) {\n\t\t\tplayer['_stepDispatch']();\n\t\t\texpect(connection.dispatchAudio).toHaveBeenCalledTimes(index);\n\n\t\t\tawait wait(); // Wait for the stream\n\n\t\t\tplayer['_stepPrepare']();\n\t\t\texpect(connection.prepareAudioPacket).toHaveBeenCalledTimes(index);\n\t\t\texpect(connection.prepareAudioPacket).toHaveBeenLastCalledWith(SILENCE_FRAME);\n\t\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\t\t\tif (player.state.status === AudioPlayerStatus.Playing) {\n\t\t\t\texpect(player.state.playbackDuration).toStrictEqual(index * 20);\n\t\t\t}\n\t\t}\n\n\t\tawait wait();\n\t\texpect(player.checkPlayable()).toEqual(false);\n\t\tconst prepareAudioPacket = connection.prepareAudioPacket as unknown as MockedFunction<\n\t\t\ttypeof connection.prepareAudioPacket\n\t\t>;\n\t\texpect(prepareAudioPacket).toHaveBeenCalledTimes(5);\n\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Idle);\n\t\texpect(connection.setSpeaking).toBeCalledTimes(1);\n\t\texpect(connection.setSpeaking).toHaveBeenLastCalledWith(false);\n\t\texpect(deleteAudioPlayer).toHaveBeenCalledTimes(1);\n\t});\n\n\ttest('Plays silence 5 times for unreadable stream before quitting', async () => {\n\t\tconst connection = createVoiceConnectionMock();\n\t\tif (connection.state.status !== VoiceConnectionStatus.Signalling) {\n\t\t\tthrow new Error('Voice connection should have been Signalling');\n\t\t}\n\n\t\tconnection.state = {\n\t\t\t...connection.state,\n\t\t\tstatus: VoiceConnectionStatus.Ready,\n\t\t\tnetworking: null as any,\n\t\t};\n\n\t\tconst resource = await started(new AudioResource([], [Readable.from([1])], null, 0));\n\t\tresource.playStream.read();\n\t\tplayer = createAudioPlayer({ behaviors: { maxMissedFrames: 5 } });\n\t\tconnection.subscribe(player);\n\n\t\tplayer.play(resource);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\t\texpect(addAudioPlayer).toBeCalledTimes(1);\n\t\texpect(player.checkPlayable()).toEqual(true);\n\n\t\tconst prepareAudioPacket = connection.prepareAudioPacket as unknown as MockedFunction<\n\t\t\ttypeof connection.prepareAudioPacket\n\t\t>;\n\n\t\t// Run through a few packet cycles\n\t\tfor (let index = 1; index <= 5; index++) {\n\t\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\t\t\tif (player.state.status !== AudioPlayerStatus.Playing) throw new Error('Error');\n\t\t\texpect(player.state.playbackDuration).toStrictEqual((index - 1) * 20);\n\t\t\texpect(player.state.missedFrames).toEqual(index - 1);\n\t\t\tplayer['_stepDispatch']();\n\t\t\texpect(connection.dispatchAudio).toHaveBeenCalledTimes(index);\n\t\t\tplayer['_stepPrepare']();\n\t\t\texpect(prepareAudioPacket).toHaveBeenCalledTimes(index);\n\t\t\texpect(prepareAudioPacket.mock.calls[index - 1]![0]).toEqual(silence().next().value);\n\t\t}\n\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Idle);\n\t\texpect(connection.setSpeaking).toBeCalledTimes(1);\n\t\texpect(connection.setSpeaking).toHaveBeenLastCalledWith(false);\n\t\texpect(deleteAudioPlayer).toHaveBeenCalledTimes(1);\n\t});\n\n\ttest('checkPlayable() transitions to Idle for unreadable stream', async () => {\n\t\tconst resource = await started(new AudioResource([], [Readable.from([1])], null, 0));\n\t\tplayer = createAudioPlayer();\n\t\tplayer.play(resource);\n\t\texpect(player.checkPlayable()).toEqual(true);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\t\tfor (let index = 0; index < 3; index++) {\n\t\t\tresource.playStream.read();\n\t\t\tawait wait();\n\t\t}\n\n\t\texpect(resource.playStream.readableEnded).toEqual(true);\n\t\texpect(player.checkPlayable()).toEqual(false);\n\t\texpect(player.state.status).toEqual(AudioPlayerStatus.Idle);\n\t});\n});\n\ntest('play() throws when playing a resource that has already ended', async () => {\n\tconst resource = await started(new AudioResource([], [Readable.from([1])], null, 5));\n\tplayer = createAudioPlayer();\n\tplayer.play(resource);\n\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\tfor (let index = 0; index < 3; index++) {\n\t\tresource.playStream.read();\n\t\tawait wait();\n\t}\n\n\texpect(resource.playStream.readableEnded).toEqual(true);\n\tplayer.stop(true);\n\texpect(player.state.status).toEqual(AudioPlayerStatus.Idle);\n\texpect(() => player?.play(resource)).toThrow();\n});\n\ntest('Propagates errors from streams', async () => {\n\tconst resource = await started(new AudioResource([], [Readable.from(silence())], null, 5));\n\tplayer = createAudioPlayer();\n\tplayer.play(resource);\n\texpect(player.state.status).toEqual(AudioPlayerStatus.Playing);\n\tconst error = new Error('AudioPlayer test error');\n\tprocess.nextTick(() => resource.playStream.emit('error', error));\n\tconst res = await once(player, 'error');\n\tconst playerError = res[0] as AudioPlayerError;\n\texpect(playerError).toBeInstanceOf(AudioPlayerError);\n\texpect(AudioPlayerError).toHaveBeenCalledWith(error, resource);\n\texpect(player.state.status).toEqual(AudioPlayerStatus.Idle);\n});\n"
  },
  {
    "path": "packages/voice/__tests__/AudioReceiveStream.test.ts",
    "content": "/* eslint-disable no-promise-executor-return */\nimport { Buffer } from 'node:buffer';\nimport { describe, test, expect } from 'vitest';\nimport { SILENCE_FRAME } from '../src/audio/AudioPlayer';\nimport { AudioReceiveStream, EndBehaviorType } from '../src/receive/AudioReceiveStream';\n\nconst DUMMY_BUFFER = Buffer.allocUnsafe(16);\n\nasync function wait(ms: number) {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function stepSilence(stream: AudioReceiveStream, increment: number) {\n\tstream.push(SILENCE_FRAME);\n\tawait wait(increment);\n\texpect(stream.readable).toEqual(true);\n}\n\ndescribe('AudioReceiveStream', () => {\n\ttest('Manual end behavior', async () => {\n\t\tconst stream = new AudioReceiveStream({ end: { behavior: EndBehaviorType.Manual } });\n\t\tstream.push(DUMMY_BUFFER);\n\t\texpect(stream.readable).toEqual(true);\n\t\tawait wait(200);\n\t\tstream.push(DUMMY_BUFFER);\n\t\texpect(stream.readable).toEqual(true);\n\t\tstream.push(null);\n\t\tawait wait(200);\n\t\texpect(stream.readable).toEqual(false);\n\t});\n\n\ttest('AfterSilence end behavior', async () => {\n\t\tconst duration = 100;\n\t\tconst increment = 20;\n\n\t\tconst stream = new AudioReceiveStream({ end: { behavior: EndBehaviorType.AfterSilence, duration } });\n\t\tstream.resume();\n\n\t\tfor (let step = increment; step < duration / 2; step += increment) {\n\t\t\tawait stepSilence(stream, increment);\n\t\t}\n\n\t\tstream.push(DUMMY_BUFFER);\n\n\t\tawait wait(duration);\n\t\texpect(stream.readableEnded).toEqual(true);\n\t});\n\n\ttest('AfterInactivity end behavior', async () => {\n\t\tconst duration = 100;\n\t\tconst increment = 20;\n\n\t\tconst stream = new AudioReceiveStream({ end: { behavior: EndBehaviorType.AfterInactivity, duration: 100 } });\n\t\tstream.resume();\n\n\t\tfor (let index = increment; index < duration / 2; index += increment) {\n\t\t\tawait stepSilence(stream, increment);\n\t\t}\n\n\t\tstream.push(DUMMY_BUFFER);\n\n\t\tfor (let index = increment; index < duration; index += increment) {\n\t\t\tawait stepSilence(stream, increment);\n\t\t}\n\n\t\tawait wait(increment);\n\t\texpect(stream.readableEnded).toEqual(false);\n\n\t\tawait wait(duration - increment);\n\n\t\texpect(stream.readableEnded).toEqual(true);\n\t});\n\n\ttest('Stream ends after pushing null', async () => {\n\t\tconst stream = new AudioReceiveStream({ end: { behavior: EndBehaviorType.AfterInactivity, duration: 100 } });\n\t\tstream.resume();\n\n\t\tstream.push(DUMMY_BUFFER);\n\n\t\texpect(stream.readable).toEqual(true);\n\t\texpect(stream.readableEnded).toEqual(false);\n\t\texpect(stream.destroyed).toEqual(false);\n\n\t\tstream.push(null);\n\t\tawait wait(50);\n\n\t\texpect(stream.readable).toEqual(false);\n\t\texpect(stream.readableEnded).toEqual(true);\n\t\texpect(stream.destroyed).toEqual(true);\n\t});\n});\n"
  },
  {
    "path": "packages/voice/__tests__/AudioResource.test.ts",
    "content": "import { Buffer } from 'node:buffer';\nimport process from 'node:process';\nimport { PassThrough, Readable } from 'node:stream';\nimport { opus, VolumeTransformer } from 'prism-media';\nimport { describe, test, expect, vitest, type MockedFunction, beforeAll, beforeEach } from 'vitest';\nimport { SILENCE_FRAME } from '../src/audio/AudioPlayer';\nimport { AudioResource, createAudioResource, NO_CONSTRAINT, VOLUME_CONSTRAINT } from '../src/audio/AudioResource';\nimport { findPipeline as _findPipeline, StreamType, TransformerType, type Edge } from '../src/audio/TransformerGraph';\n\nvitest.mock('../src/audio/TransformerGraph');\n\nasync function wait() {\n\t// eslint-disable-next-line no-promise-executor-return\n\treturn new Promise((resolve) => process.nextTick(resolve));\n}\n\nasync function started(resource: AudioResource) {\n\twhile (!resource.started) {\n\t\tawait wait();\n\t}\n\n\treturn resource;\n}\n\nconst findPipeline = _findPipeline as unknown as MockedFunction<typeof _findPipeline>;\n\nbeforeAll(() => {\n\t// @ts-expect-error: No type\n\tfindPipeline.mockImplementation((from: StreamType, constraint: (path: Edge[]) => boolean) => {\n\t\tconst base = [\n\t\t\t{\n\t\t\t\tcost: 1,\n\t\t\t\ttransformer: () => new PassThrough(),\n\t\t\t\ttype: TransformerType.FFmpegPCM,\n\t\t\t},\n\t\t];\n\t\tif (constraint === VOLUME_CONSTRAINT) {\n\t\t\tbase.push({\n\t\t\t\tcost: 1,\n\t\t\t\t// Transformer type shouldn't matter: we are not testing prism-media, but rather the expectation that the stream is VolumeTransformer\n\t\t\t\ttransformer: () => new VolumeTransformer({ type: 's16le' } as any),\n\t\t\t\ttype: TransformerType.InlineVolume,\n\t\t\t});\n\t\t}\n\n\t\treturn base as any[];\n\t});\n});\n\nbeforeEach(() => {\n\tfindPipeline.mockClear();\n});\n\ndescribe('createAudioResource', () => {\n\ttest('Creates a resource from string path', () => {\n\t\tconst resource = createAudioResource('mypath.mp3');\n\t\texpect(findPipeline).toHaveBeenCalledWith(StreamType.Arbitrary, NO_CONSTRAINT);\n\t\texpect(resource.volume).toBeUndefined();\n\t});\n\n\ttest('Creates a resource from string path (volume)', () => {\n\t\tconst resource = createAudioResource('mypath.mp3', { inlineVolume: true });\n\t\texpect(findPipeline).toHaveBeenCalledWith(StreamType.Arbitrary, VOLUME_CONSTRAINT);\n\t\texpect(resource.volume).toBeInstanceOf(VolumeTransformer);\n\t});\n\n\ttest('Only infers type if not explicitly given', () => {\n\t\tconst resource = createAudioResource(new opus.Encoder({ rate: 48_000, channels: 2, frameSize: 960 }), {\n\t\t\tinputType: StreamType.Arbitrary,\n\t\t});\n\t\texpect(findPipeline).toHaveBeenCalledWith(StreamType.Arbitrary, NO_CONSTRAINT);\n\t\texpect(resource.volume).toBeUndefined();\n\t});\n\n\ttest('Infers from opus.Encoder', () => {\n\t\tconst resource = createAudioResource(new opus.Encoder({ rate: 48_000, channels: 2, frameSize: 960 }), {\n\t\t\tinlineVolume: true,\n\t\t});\n\t\texpect(findPipeline).toHaveBeenCalledWith(StreamType.Opus, VOLUME_CONSTRAINT);\n\t\texpect(resource.volume).toBeInstanceOf(VolumeTransformer);\n\t\texpect(resource.encoder).toBeInstanceOf(opus.Encoder);\n\t});\n\n\ttest('Infers from opus.OggDemuxer', () => {\n\t\tconst resource = createAudioResource(new opus.OggDemuxer());\n\t\texpect(findPipeline).toHaveBeenCalledWith(StreamType.Opus, NO_CONSTRAINT);\n\t\texpect(resource.volume).toBeUndefined();\n\t\texpect(resource.encoder).toBeUndefined();\n\t});\n\n\ttest('Infers from opus.WebmDemuxer', () => {\n\t\tconst resource = createAudioResource(new opus.WebmDemuxer());\n\t\texpect(findPipeline).toHaveBeenCalledWith(StreamType.Opus, NO_CONSTRAINT);\n\t\texpect(resource.volume).toBeUndefined();\n\t});\n\n\ttest('Infers from opus.Decoder', () => {\n\t\tconst resource = createAudioResource(new opus.Decoder({ rate: 48_000, channels: 2, frameSize: 960 }));\n\t\texpect(findPipeline).toHaveBeenCalledWith(StreamType.Raw, NO_CONSTRAINT);\n\t\texpect(resource.volume).toBeUndefined();\n\t});\n\n\ttest('Infers from VolumeTransformer', () => {\n\t\t// Transformer type shouldn't matter: we are not testing prism-media, but rather the expectation that the stream is VolumeTransformer\n\t\tconst stream = new VolumeTransformer({ type: 's16le' } as any);\n\t\tconst resource = createAudioResource(stream, { inlineVolume: true });\n\t\texpect(findPipeline).toHaveBeenCalledWith(StreamType.Raw, NO_CONSTRAINT);\n\t\texpect(resource.volume).toEqual(stream);\n\t});\n\n\ttest('Falls back to Arbitrary for unknown stream type', () => {\n\t\tconst resource = createAudioResource(new PassThrough());\n\t\texpect(findPipeline).toHaveBeenCalledWith(StreamType.Arbitrary, NO_CONSTRAINT);\n\t\texpect(resource.volume).toBeUndefined();\n\t});\n\n\ttest('Appends silence frames when ended', async () => {\n\t\tconst stream = Readable.from(Buffer.from([1]));\n\n\t\tconst resource = new AudioResource([], [stream], null, 5);\n\n\t\tawait started(resource);\n\t\texpect(resource.readable).toEqual(true);\n\t\texpect(resource.read()).toEqual(Buffer.from([1]));\n\t\tfor (let index = 0; index < 5; index++) {\n\t\t\tawait wait();\n\t\t\texpect(resource.readable).toEqual(true);\n\t\t\texpect(resource.read()).toEqual(SILENCE_FRAME);\n\t\t}\n\n\t\tawait wait();\n\t\texpect(resource.readable).toEqual(false);\n\t\texpect(resource.read()).toEqual(null);\n\t});\n});\n"
  },
  {
    "path": "packages/voice/__tests__/DataStore.test.ts",
    "content": "/* eslint-disable @typescript-eslint/dot-notation */\nimport { GatewayOpcodes } from 'discord-api-types/v10';\nimport { describe, test, expect, vitest, type Mocked, beforeEach } from 'vitest';\nimport * as DataStore from '../src/DataStore';\nimport type { VoiceConnection } from '../src/VoiceConnection';\nimport * as _AudioPlayer from '../src/audio/AudioPlayer';\n\nvitest.mock('../src/VoiceConnection');\nvitest.mock('../src/audio/AudioPlayer');\n\nconst AudioPlayer = _AudioPlayer as unknown as Mocked<typeof _AudioPlayer>;\n\nfunction createVoiceConnection(joinConfig: Pick<DataStore.JoinConfig, 'group' | 'guildId'>): VoiceConnection {\n\treturn {\n\t\tjoinConfig: { channelId: '123', selfMute: false, selfDeaf: true, ...joinConfig },\n\t} as any;\n}\n\nasync function waitForEventLoop() {\n\t// eslint-disable-next-line no-promise-executor-return\n\treturn new Promise((resolve) => setImmediate(resolve));\n}\n\nbeforeEach(() => {\n\tconst groups = DataStore.getGroups();\n\tfor (const groupKey of groups.keys()) {\n\t\tgroups.delete(groupKey);\n\t}\n\n\tgroups.set('default', new Map());\n});\n\nconst voiceConnectionDefault = createVoiceConnection({ guildId: '123', group: 'default' });\nconst voiceConnectionAbc = createVoiceConnection({ guildId: '123', group: 'abc' });\n\ndescribe('DataStore', () => {\n\ttest('VoiceConnection join payload creation', () => {\n\t\tconst joinConfig: DataStore.JoinConfig = {\n\t\t\tguildId: '123',\n\t\t\tchannelId: '123',\n\t\t\tselfDeaf: true,\n\t\t\tselfMute: false,\n\t\t\tgroup: 'default',\n\t\t};\n\t\texpect(DataStore.createJoinVoiceChannelPayload(joinConfig)).toStrictEqual({\n\t\t\top: GatewayOpcodes.VoiceStateUpdate,\n\t\t\t// eslint-disable-next-line id-length\n\t\t\td: {\n\t\t\t\tguild_id: joinConfig.guildId,\n\t\t\t\tchannel_id: joinConfig.channelId,\n\t\t\t\tself_deaf: joinConfig.selfDeaf,\n\t\t\t\tself_mute: joinConfig.selfMute,\n\t\t\t},\n\t\t});\n\t});\n\ttest('VoiceConnection management respects group', () => {\n\t\tDataStore.trackVoiceConnection(voiceConnectionDefault);\n\t\tDataStore.trackVoiceConnection(voiceConnectionAbc);\n\t\texpect(DataStore.getVoiceConnection('123')).toEqual(voiceConnectionDefault);\n\t\texpect(DataStore.getVoiceConnection('123', 'default')).toEqual(voiceConnectionDefault);\n\t\texpect(DataStore.getVoiceConnection('123', 'abc')).toEqual(voiceConnectionAbc);\n\n\t\texpect([...DataStore.getGroups().keys()]).toEqual(['default', 'abc']);\n\n\t\texpect([...DataStore.getVoiceConnections().values()]).toEqual([voiceConnectionDefault]);\n\t\texpect([...DataStore.getVoiceConnections('default').values()]).toEqual([voiceConnectionDefault]);\n\t\texpect([...DataStore.getVoiceConnections('abc')!.values()]).toEqual([voiceConnectionAbc]);\n\n\t\tDataStore.untrackVoiceConnection(voiceConnectionDefault);\n\t\texpect(DataStore.getVoiceConnection('123')).toBeUndefined();\n\t\texpect(DataStore.getVoiceConnection('123', 'abc')).toEqual(voiceConnectionAbc);\n\t});\n\ttest('Managing Audio Players', async () => {\n\t\tconst player = DataStore.addAudioPlayer(new AudioPlayer.AudioPlayer());\n\t\tconst dispatchSpy = vitest.spyOn(player as any, '_stepDispatch');\n\t\tconst prepareSpy = vitest.spyOn(player as any, '_stepPrepare');\n\t\texpect(DataStore.hasAudioPlayer(player)).toEqual(true);\n\t\texpect(DataStore.addAudioPlayer(player)).toEqual(player);\n\t\tDataStore.deleteAudioPlayer(player);\n\t\t// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression\n\t\texpect(DataStore.deleteAudioPlayer(player)).toBeUndefined();\n\t\texpect(DataStore.hasAudioPlayer(player)).toEqual(false);\n\t\t// Tests audio cycle with nextTime === -1\n\t\tawait waitForEventLoop();\n\t\texpect(dispatchSpy).toHaveBeenCalledTimes(0);\n\t\texpect(prepareSpy).toHaveBeenCalledTimes(0);\n\t});\n\ttest('Preparing Audio Frames', async () => {\n\t\t// Test functional player\n\t\tconst player2 = DataStore.addAudioPlayer(new AudioPlayer.AudioPlayer());\n\t\tplayer2['checkPlayable'] = vitest.fn(() => true);\n\t\tconst player3 = DataStore.addAudioPlayer(new AudioPlayer.AudioPlayer());\n\t\tconst dispatchSpy2 = vitest.spyOn(player2 as any, '_stepDispatch');\n\t\tconst prepareSpy2 = vitest.spyOn(player2 as any, '_stepPrepare');\n\t\tconst dispatchSpy3 = vitest.spyOn(player3 as any, '_stepDispatch');\n\t\tconst prepareSpy3 = vitest.spyOn(player3 as any, '_stepPrepare');\n\t\tawait waitForEventLoop();\n\t\tDataStore.deleteAudioPlayer(player2);\n\t\tawait waitForEventLoop();\n\t\tDataStore.deleteAudioPlayer(player3);\n\t\texpect(dispatchSpy2).toHaveBeenCalledTimes(1);\n\t\texpect(prepareSpy2).toHaveBeenCalledTimes(1);\n\t\texpect(dispatchSpy3).toHaveBeenCalledTimes(0);\n\t\texpect(prepareSpy3).toHaveBeenCalledTimes(0);\n\t});\n});\n"
  },
  {
    "path": "packages/voice/__tests__/SSRCMap.test.ts",
    "content": "import { type EventEmitter, once } from 'node:events';\nimport process from 'node:process';\nimport { describe, test, expect } from 'vitest';\nimport { SSRCMap, type VoiceUserData } from '../src/receive/SSRCMap';\n\nasync function onceOrThrow<Emitter extends EventEmitter>(target: Emitter, event: string, after: number) {\n\treturn new Promise((resolve, reject) => {\n\t\ttarget.on(event, resolve);\n\t\tsetTimeout(() => reject(new Error('Time up')), after);\n\t});\n}\n\ndescribe('SSRCMap', () => {\n\ttest('update persists data and emits correctly', async () => {\n\t\tconst fixture1: VoiceUserData = {\n\t\t\taudioSSRC: 1,\n\t\t\tuserId: '123',\n\t\t};\n\n\t\tconst fixture2: VoiceUserData = {\n\t\t\t...fixture1,\n\t\t\tvideoSSRC: 2,\n\t\t};\n\n\t\tconst map = new SSRCMap();\n\t\tprocess.nextTick(() => map.update(fixture1));\n\t\tlet [oldData, newData] = await once(map, 'update');\n\t\texpect(oldData).toBeUndefined();\n\t\texpect(newData).toMatchObject(fixture1);\n\t\texpect(map.get(fixture1.audioSSRC)).toMatchObject(fixture1);\n\n\t\tprocess.nextTick(() => map.update(fixture2));\n\t\t[oldData, newData] = await once(map, 'update');\n\t\texpect(oldData).toMatchObject(fixture1);\n\t\texpect(newData).toMatchObject(fixture2);\n\t\texpect(map.get(fixture1.userId)).toMatchObject(fixture2);\n\t});\n\n\ttest('delete removes data and emits correctly', async () => {\n\t\tconst fixture1: VoiceUserData = {\n\t\t\taudioSSRC: 1,\n\t\t\tuserId: '123',\n\t\t};\n\t\tconst map = new SSRCMap();\n\n\t\tmap.delete(fixture1.audioSSRC);\n\t\tawait expect(onceOrThrow(map, 'delete', 5)).rejects.toThrow();\n\n\t\tmap.update(fixture1);\n\t\tprocess.nextTick(() => map.delete(fixture1.audioSSRC));\n\t\tawait expect(once(map, 'delete')).resolves.toMatchObject([fixture1]);\n\n\t\tmap.delete(fixture1.audioSSRC);\n\t\tawait expect(onceOrThrow(map, 'delete', 5)).rejects.toThrow();\n\n\t\tmap.update(fixture1);\n\t\tprocess.nextTick(() => map.delete(fixture1.userId));\n\t\tawait expect(once(map, 'delete')).resolves.toMatchObject([fixture1]);\n\t\texpect(map.get(fixture1.audioSSRC)).toBeUndefined();\n\t});\n});\n"
  },
  {
    "path": "packages/voice/__tests__/Secretbox.test.ts",
    "content": "import { Buffer } from 'node:buffer';\nimport { test, expect, vitest } from 'vitest';\nimport { methods, secretboxLoadPromise } from '../src/util/Secretbox';\n\nvitest.mock('@noble/ciphers/chacha.js');\n\n// TODO: what is this even testing exactly?\ntest.skip('Does not throw error with a package installed', async () => {\n\t// The async loop in Secretbox will not have finished importing unless we wait\n\tawait secretboxLoadPromise;\n\n\texpect(() =>\n\t\tmethods.crypto_aead_xchacha20poly1305_ietf_decrypt(\n\t\t\tBuffer.from(''),\n\t\t\tBuffer.from(''),\n\t\t\tBuffer.from(''),\n\t\t\tBuffer.from(''),\n\t\t),\n\t).not.toThrowError();\n});\n"
  },
  {
    "path": "packages/voice/__tests__/SpeakingMap.test.ts",
    "content": "import { describe, test, expect, vitest } from 'vitest';\nimport { SpeakingMap } from '../src/receive/SpeakingMap';\nimport { noop } from '../src/util/util';\n\nvitest.useFakeTimers();\n\ndescribe('SpeakingMap', () => {\n\ttest('Emits start and end', () => {\n\t\tconst speaking = new SpeakingMap();\n\t\tconst userId = '123';\n\n\t\tconst starts: string[] = [];\n\t\tconst ends: string[] = [];\n\n\t\tspeaking.on('start', (userId) => void starts.push(userId));\n\t\tspeaking.on('end', (userId) => void ends.push(userId));\n\n\t\tfor (let index = 0; index < 10; index++) {\n\t\t\tspeaking.onPacket(userId);\n\t\t\tsetTimeout(noop, SpeakingMap.DELAY / 2);\n\t\t\tvitest.advanceTimersToNextTimer();\n\n\t\t\texpect(starts).toEqual([userId]);\n\t\t\texpect(ends).toEqual([]);\n\t\t}\n\n\t\tvitest.advanceTimersToNextTimer();\n\t\texpect(ends).toEqual([userId]);\n\n\t\tspeaking.onPacket(userId);\n\t\tvitest.advanceTimersToNextTimer();\n\t\texpect(starts).toEqual([userId, userId]);\n\t});\n});\n"
  },
  {
    "path": "packages/voice/__tests__/TransformerGraph.test.ts",
    "content": "import { describe, test, expect } from 'vitest';\nimport { findPipeline, StreamType, TransformerType, type Edge } from '../src/audio/TransformerGraph';\n\nconst noConstraint = () => true;\n\n/**\n * Converts a pipeline into an easier-to-parse list of stream types within the pipeline\n *\n * @param pipeline - The pipeline of edges returned by findPipeline(...)\n */\nfunction reducePath(pipeline: Edge[]) {\n\tconst streams = [pipeline[0]!.from.type];\n\tfor (const edge of pipeline.slice(1)) {\n\t\tstreams.push(edge.from.type);\n\t}\n\n\tstreams.push(pipeline[pipeline.length - 1]!.to.type);\n\treturn streams;\n}\n\nconst isVolume = (edge: Edge) => edge.type === TransformerType.InlineVolume;\nconst containsVolume = (edges: Edge[]) => edges.some(isVolume);\n\ndescribe('findPipeline (no constraints)', () => {\n\ttest.each([StreamType.Arbitrary, StreamType.OggOpus, StreamType.WebmOpus, StreamType.Raw])(\n\t\t'%s maps to opus with no inline volume',\n\t\t(type) => {\n\t\t\tconst pipeline = findPipeline(type, noConstraint);\n\t\t\tconst path = reducePath(pipeline);\n\t\t\texpect(path.length).toBeGreaterThanOrEqual(2);\n\t\t\texpect(path[0]).toEqual(type);\n\t\t\texpect(path.pop()).toEqual(StreamType.Opus);\n\t\t\texpect(pipeline.some(isVolume)).toEqual(false);\n\t\t},\n\t);\n\n\ttest('opus is unchanged', () => {\n\t\texpect(findPipeline(StreamType.Opus, noConstraint)).toHaveLength(0);\n\t});\n});\n\ndescribe('findPipeline (volume constraint)', () => {\n\ttest.each(Object.values(StreamType))('%s maps to opus with inline volume', (type) => {\n\t\tconst pipeline = findPipeline(type, containsVolume);\n\t\tconst path = reducePath(pipeline);\n\t\texpect(path.length).toBeGreaterThanOrEqual(2);\n\t\texpect(path[0]).toEqual(type);\n\t\texpect(path.pop()).toEqual(StreamType.Opus);\n\t\texpect(pipeline.some(isVolume)).toEqual(true);\n\t});\n});\n"
  },
  {
    "path": "packages/voice/__tests__/VoiceConnection.test.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\n/* eslint-disable @typescript-eslint/dot-notation */\nimport { EventEmitter } from 'node:events';\nimport type { Mocked } from 'vitest';\nimport { vitest, describe, test, expect, beforeEach } from 'vitest';\nimport * as _DataStore from '../src/DataStore';\nimport {\n\tcreateVoiceConnection,\n\tVoiceConnection,\n\tVoiceConnectionDisconnectReason,\n\tVoiceConnectionStatus,\n\ttype VoiceConnectionConnectingState,\n\ttype VoiceConnectionReadyState,\n\ttype VoiceConnectionSignallingState,\n} from '../src/VoiceConnection';\nimport * as _AudioPlayer from '../src/audio/AudioPlayer';\nimport { PlayerSubscription as _PlayerSubscription } from '../src/audio/PlayerSubscription';\nimport * as Networking from '../src/networking/Networking';\nimport type { DiscordGatewayAdapterLibraryMethods } from '../src/util/adapter';\n\nvitest.mock('../src/audio/AudioPlayer');\nvitest.mock('../src/audio/PlayerSubscription');\nvitest.mock('../src/DataStore');\nvitest.mock('../src/networking/Networking', async (importOriginal) => {\n\t// eslint-disable-next-line @typescript-eslint/consistent-type-imports\n\tconst actual = await importOriginal<typeof import('../src/networking/Networking')>();\n\tconst Networking = actual.Networking;\n\tNetworking.prototype['createWebSocket'] = vitest.fn();\n\treturn {\n\t\t...actual,\n\t\tNetworking,\n\t};\n});\n\nconst DataStore = _DataStore as unknown as Mocked<typeof _DataStore>;\nconst AudioPlayer = _AudioPlayer as unknown as Mocked<typeof _AudioPlayer>;\nconst PlayerSubscription = _PlayerSubscription as unknown as Mocked<typeof _PlayerSubscription>;\n\nconst _NetworkingClass = Networking.Networking;\n// eslint-disable-next-line prefer-arrow-callback\nvitest.spyOn(Networking, 'Networking').mockImplementation(function Networking(...args) {\n\treturn new _NetworkingClass(...args);\n});\n\nfunction createFakeAdapter() {\n\tconst sendPayload = vitest.fn();\n\tsendPayload.mockReturnValue(true);\n\tconst destroy = vitest.fn();\n\tconst libMethods: Partial<DiscordGatewayAdapterLibraryMethods> = {};\n\treturn {\n\t\tsendPayload,\n\t\tdestroy,\n\t\tlibMethods,\n\t\tcreator: vitest.fn((methods) => {\n\t\t\tObject.assign(libMethods, methods);\n\t\t\treturn {\n\t\t\t\tsendPayload,\n\t\t\t\tdestroy,\n\t\t\t};\n\t\t}),\n\t};\n}\n\nfunction createJoinConfig() {\n\treturn {\n\t\tchannelId: '1',\n\t\tguildId: '2',\n\t\tselfDeaf: true,\n\t\tselfMute: false,\n\t\tgroup: 'default',\n\t};\n}\n\nfunction createFakeVoiceConnection() {\n\tconst adapter = createFakeAdapter();\n\tconst joinConfig = createJoinConfig();\n\tconst voiceConnection = new VoiceConnection(joinConfig, {\n\t\tdebug: false,\n\t\tadapterCreator: adapter.creator,\n\t});\n\treturn { adapter, joinConfig, voiceConnection };\n}\n\nbeforeEach(() => {\n\tDataStore.createJoinVoiceChannelPayload.mockReset();\n\tDataStore.getVoiceConnection.mockReset();\n\tDataStore.trackVoiceConnection.mockReset();\n\tDataStore.untrackVoiceConnection.mockReset();\n});\n\ndescribe('createVoiceConnection', () => {\n\ttest('New voice connection', () => {\n\t\tconst mockPayload = Symbol('mock') as any;\n\t\tDataStore.createJoinVoiceChannelPayload.mockImplementation(() => mockPayload);\n\t\tconst adapter = createFakeAdapter();\n\t\tconst joinConfig = createJoinConfig();\n\t\tconst voiceConnection = createVoiceConnection(joinConfig, {\n\t\t\tdebug: false,\n\t\t\tadapterCreator: adapter.creator,\n\t\t});\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Signalling);\n\t\texpect(DataStore.getVoiceConnection).toHaveBeenCalledTimes(1);\n\t\texpect(DataStore.trackVoiceConnection).toHaveBeenCalledWith(voiceConnection);\n\t\texpect(DataStore.untrackVoiceConnection).not.toHaveBeenCalled();\n\t\texpect(adapter.sendPayload).toHaveBeenCalledWith(mockPayload);\n\t});\n\n\ttest('New voice connection with adapter failure', () => {\n\t\tconst mockPayload = Symbol('mock') as any;\n\t\tDataStore.createJoinVoiceChannelPayload.mockImplementation(() => mockPayload);\n\t\tconst adapter = createFakeAdapter();\n\t\tadapter.sendPayload.mockReturnValue(false);\n\t\tconst joinConfig = createJoinConfig();\n\t\tconst voiceConnection = createVoiceConnection(joinConfig, {\n\t\t\tdebug: false,\n\t\t\tadapterCreator: adapter.creator,\n\t\t});\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Disconnected);\n\t\texpect(DataStore.getVoiceConnection).toHaveBeenCalledTimes(1);\n\t\texpect(DataStore.trackVoiceConnection).toHaveBeenCalledWith(voiceConnection);\n\t\texpect(DataStore.untrackVoiceConnection).not.toHaveBeenCalled();\n\t\texpect(adapter.sendPayload).toHaveBeenCalledWith(mockPayload);\n\t});\n\n\ttest('Reconfiguring existing connection', () => {\n\t\tconst mockPayload = Symbol('mock') as any;\n\n\t\tDataStore.createJoinVoiceChannelPayload.mockImplementation(() => mockPayload);\n\n\t\tconst existingAdapter = createFakeAdapter();\n\t\tconst existingJoinConfig = createJoinConfig();\n\t\tconst existingVoiceConnection = new VoiceConnection(existingJoinConfig, {\n\t\t\tdebug: false,\n\t\t\tadapterCreator: existingAdapter.creator,\n\t\t});\n\n\t\tconst stateSetter = vitest.spyOn(existingVoiceConnection, 'state', 'set');\n\n\t\tDataStore.getVoiceConnection.mockImplementation((guildId, group = 'default') =>\n\t\t\tguildId === existingJoinConfig.guildId && group === existingJoinConfig.group\n\t\t\t\t? existingVoiceConnection\n\t\t\t\t: undefined,\n\t\t);\n\n\t\tconst newAdapter = createFakeAdapter();\n\t\tconst newJoinConfig = createJoinConfig();\n\t\tconst newVoiceConnection = createVoiceConnection(newJoinConfig, {\n\t\t\tdebug: false,\n\t\t\tadapterCreator: newAdapter.creator,\n\t\t});\n\t\texpect(DataStore.getVoiceConnection).toHaveBeenCalledWith(newJoinConfig.guildId, newJoinConfig.group);\n\t\texpect(DataStore.trackVoiceConnection).not.toHaveBeenCalled();\n\t\texpect(DataStore.untrackVoiceConnection).not.toHaveBeenCalled();\n\t\texpect(newAdapter.creator).not.toHaveBeenCalled();\n\t\texpect(existingAdapter.sendPayload).toHaveBeenCalledWith(mockPayload);\n\t\texpect(newVoiceConnection).toEqual(existingVoiceConnection);\n\t\texpect(stateSetter).not.toHaveBeenCalled();\n\t});\n\n\ttest('Calls rejoin() on existing disconnected connection', () => {\n\t\tconst mockPayload = Symbol('mock') as any;\n\n\t\tDataStore.createJoinVoiceChannelPayload.mockImplementation(() => mockPayload);\n\n\t\tconst existingAdapter = createFakeAdapter();\n\t\tconst existingJoinConfig = createJoinConfig();\n\t\tconst existingVoiceConnection = new VoiceConnection(existingJoinConfig, {\n\t\t\tdebug: false,\n\t\t\tadapterCreator: existingAdapter.creator,\n\t\t});\n\t\texistingVoiceConnection.state = {\n\t\t\tstatus: VoiceConnectionStatus.Disconnected,\n\t\t\tadapter: existingAdapter,\n\t\t\treason: VoiceConnectionDisconnectReason.EndpointRemoved,\n\t\t};\n\n\t\tconst rejoinSpy = vitest.spyOn(existingVoiceConnection, 'rejoin');\n\n\t\tDataStore.getVoiceConnection.mockImplementation((guildId, group = 'default') =>\n\t\t\tguildId === existingJoinConfig.guildId && group === existingJoinConfig.group\n\t\t\t\t? existingVoiceConnection\n\t\t\t\t: undefined,\n\t\t);\n\n\t\tconst newAdapter = createFakeAdapter();\n\t\tconst newJoinConfig = createJoinConfig();\n\t\tconst { guildId, group, ...rejoinConfig } = newJoinConfig;\n\t\tconst newVoiceConnection = createVoiceConnection(newJoinConfig, {\n\t\t\tdebug: false,\n\t\t\tadapterCreator: newAdapter.creator,\n\t\t});\n\t\texpect(DataStore.getVoiceConnection).toHaveBeenCalledWith(newJoinConfig.guildId, newJoinConfig.group);\n\t\texpect(DataStore.trackVoiceConnection).not.toHaveBeenCalled();\n\t\texpect(DataStore.untrackVoiceConnection).not.toHaveBeenCalled();\n\t\texpect(newAdapter.creator).not.toHaveBeenCalled();\n\t\texpect(rejoinSpy).toHaveBeenCalledWith(rejoinConfig);\n\t\texpect(newVoiceConnection).toEqual(existingVoiceConnection);\n\t});\n\n\ttest('Reconfiguring existing connection with adapter failure', () => {\n\t\tconst mockPayload = Symbol('mock') as any;\n\n\t\tDataStore.createJoinVoiceChannelPayload.mockImplementation(() => mockPayload);\n\n\t\tconst existingAdapter = createFakeAdapter();\n\t\tconst existingJoinConfig = createJoinConfig();\n\t\tconst existingVoiceConnection = new VoiceConnection(existingJoinConfig, {\n\t\t\tdebug: false,\n\t\t\tadapterCreator: existingAdapter.creator,\n\t\t});\n\n\t\tDataStore.getVoiceConnection.mockImplementation((guildId, group = 'default') =>\n\t\t\tguildId === existingJoinConfig.guildId && group === existingJoinConfig.group\n\t\t\t\t? existingVoiceConnection\n\t\t\t\t: undefined,\n\t\t);\n\n\t\tconst newAdapter = createFakeAdapter();\n\t\tconst newJoinConfig = createJoinConfig();\n\t\texistingAdapter.sendPayload.mockReturnValue(false);\n\t\tconst newVoiceConnection = createVoiceConnection(newJoinConfig, {\n\t\t\tdebug: false,\n\t\t\tadapterCreator: newAdapter.creator,\n\t\t});\n\t\texpect(DataStore.getVoiceConnection).toHaveBeenCalledWith(newJoinConfig.guildId, newJoinConfig.group);\n\t\texpect(DataStore.trackVoiceConnection).not.toHaveBeenCalled();\n\t\texpect(DataStore.untrackVoiceConnection).not.toHaveBeenCalled();\n\t\texpect(newAdapter.creator).not.toHaveBeenCalled();\n\t\texpect(existingAdapter.sendPayload).toHaveBeenCalledWith(mockPayload);\n\t\texpect(newVoiceConnection).toEqual(existingVoiceConnection);\n\t\texpect(newVoiceConnection.state.status).toEqual(VoiceConnectionStatus.Disconnected);\n\t});\n});\n\ndescribe('VoiceConnection#addServerPacket', () => {\n\ttest('Stores the packet and attempts to configure networking', () => {\n\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\t\tvoiceConnection.configureNetworking = vitest.fn();\n\t\tconst dummy = {\n\t\t\tendpoint: 'discord.com',\n\t\t\tguild_id: 123,\n\t\t\ttoken: 'abc',\n\t\t} as any;\n\t\tvoiceConnection['addServerPacket'](dummy);\n\t\texpect(voiceConnection['packets'].server).toEqual(dummy);\n\t\texpect(voiceConnection.configureNetworking).toHaveBeenCalled();\n\t});\n\n\ttest('Overwrites existing packet', () => {\n\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\t\tvoiceConnection['packets'].server = Symbol('old') as any;\n\t\tvoiceConnection.configureNetworking = vitest.fn();\n\t\tconst dummy = {\n\t\t\tendpoint: 'discord.com',\n\t\t\tguild_id: 123,\n\t\t\ttoken: 'abc',\n\t\t} as any;\n\t\tvoiceConnection['addServerPacket'](dummy);\n\t\texpect(voiceConnection['packets'].server).toEqual(dummy);\n\t\texpect(voiceConnection.configureNetworking).toHaveBeenCalled();\n\t});\n\n\ttest('Disconnects when given a null endpoint', () => {\n\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\t\tvoiceConnection['packets'].server = Symbol('old') as any;\n\t\tvoiceConnection.configureNetworking = vitest.fn();\n\t\tconst dummy = {\n\t\t\tendpoint: null,\n\t\t\tguild_id: 123,\n\t\t\ttoken: 'abc',\n\t\t} as any;\n\t\tvoiceConnection['addServerPacket'](dummy);\n\t\texpect(voiceConnection['packets'].server).toEqual(dummy);\n\t\texpect(voiceConnection.configureNetworking).not.toHaveBeenCalled();\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Disconnected);\n\t});\n});\n\ndescribe('VoiceConnection#addStatePacket', () => {\n\ttest('State is assigned to joinConfig', () => {\n\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\t\tvoiceConnection['addStatePacket']({\n\t\t\tself_deaf: true,\n\t\t\tself_mute: true,\n\t\t\tchannel_id: '123',\n\t\t} as any);\n\n\t\texpect(voiceConnection.joinConfig).toMatchObject({\n\t\t\tselfDeaf: true,\n\t\t\tselfMute: true,\n\t\t\tchannelId: '123',\n\t\t});\n\n\t\tvoiceConnection['addStatePacket']({\n\t\t\tself_mute: false,\n\t\t} as any);\n\n\t\texpect(voiceConnection.joinConfig).toMatchObject({\n\t\t\tselfDeaf: true,\n\t\t\tselfMute: false,\n\t\t\tchannelId: '123',\n\t\t});\n\t});\n});\n\ndescribe('VoiceConnection#configureNetworking', () => {\n\ttest('Only creates Networking instance when both packets are present and not destroyed', () => {\n\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Signalling);\n\n\t\tvoiceConnection.configureNetworking();\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Signalling);\n\t\tconst adapter = (voiceConnection.state as VoiceConnectionSignallingState).adapter;\n\n\t\tconst state = {\n\t\t\tsession_id: 'abc',\n\t\t\tuser_id: '123',\n\t\t} as any;\n\n\t\tconst server = {\n\t\t\tendpoint: 'def',\n\t\t\tguild_id: '123',\n\t\t\ttoken: 'xyz',\n\t\t} as any;\n\n\t\tObject.assign(voiceConnection['packets'], { state, server: undefined });\n\t\tvoiceConnection.configureNetworking();\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Signalling);\n\t\texpect(Networking.Networking).toHaveBeenCalledTimes(0);\n\n\t\tObject.assign(voiceConnection['packets'], { state: undefined, server });\n\t\tvoiceConnection.configureNetworking();\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Signalling);\n\t\texpect(Networking.Networking).toHaveBeenCalledTimes(0);\n\n\t\tObject.assign(voiceConnection['packets'], { state, server });\n\t\tvoiceConnection.state = { status: VoiceConnectionStatus.Destroyed };\n\t\tvoiceConnection.configureNetworking();\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Destroyed);\n\t\texpect(Networking.Networking).toHaveBeenCalledTimes(0);\n\n\t\tvoiceConnection.state = { status: VoiceConnectionStatus.Signalling, adapter };\n\t\tvoiceConnection.configureNetworking();\n\t\texpect(Networking.Networking).toHaveBeenCalledTimes(1);\n\t\texpect(Networking.Networking).toHaveBeenCalledWith(\n\t\t\t{\n\t\t\t\tendpoint: server.endpoint,\n\t\t\t\tserverId: server.guild_id,\n\t\t\t\ttoken: server.token,\n\t\t\t\tsessionId: state.session_id,\n\t\t\t\tuserId: state.user_id,\n\t\t\t},\n\t\t\t{\n\t\t\t\tdaveEncryption: true,\n\t\t\t\tdebug: false,\n\t\t\t\tdecryptionFailureTolerance: undefined,\n\t\t\t},\n\t\t);\n\t\texpect(voiceConnection.state).toMatchObject({\n\t\t\tstatus: VoiceConnectionStatus.Connecting,\n\t\t\tadapter,\n\t\t});\n\t\texpect((voiceConnection.state as unknown as VoiceConnectionConnectingState).networking).toBeInstanceOf(\n\t\t\t_NetworkingClass,\n\t\t);\n\t});\n});\n\ndescribe('VoiceConnection#onNetworkingClose', () => {\n\ttest('Does nothing in destroyed state', () => {\n\t\tconst { voiceConnection, adapter } = createFakeVoiceConnection();\n\t\tvoiceConnection.state = {\n\t\t\tstatus: VoiceConnectionStatus.Destroyed,\n\t\t};\n\t\tvoiceConnection['onNetworkingClose'](1_000);\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Destroyed);\n\t\texpect(adapter.sendPayload).not.toHaveBeenCalled();\n\t});\n\n\ttest('Disconnects for code 4014', () => {\n\t\tconst { voiceConnection, adapter } = createFakeVoiceConnection();\n\t\tvoiceConnection['onNetworkingClose'](4_014);\n\t\texpect(voiceConnection.state).toMatchObject({\n\t\t\tstatus: VoiceConnectionStatus.Disconnected,\n\t\t\tcloseCode: 4_014,\n\t\t});\n\t\texpect(adapter.sendPayload).not.toHaveBeenCalled();\n\t});\n\n\ttest('Attempts rejoin for codes != 4014', () => {\n\t\tconst dummyPayload = Symbol('dummy') as any;\n\t\tconst { voiceConnection, adapter, joinConfig } = createFakeVoiceConnection();\n\t\tDataStore.createJoinVoiceChannelPayload.mockImplementation((config) =>\n\t\t\tconfig === joinConfig ? dummyPayload : undefined,\n\t\t);\n\t\tvoiceConnection['onNetworkingClose'](1_234);\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Signalling);\n\t\texpect(adapter.sendPayload).toHaveBeenCalledWith(dummyPayload);\n\t\texpect(voiceConnection.rejoinAttempts).toEqual(1);\n\t});\n\n\ttest('Attempts rejoin for codes != 4014 (with adapter failure)', () => {\n\t\tconst dummyPayload = Symbol('dummy') as any;\n\t\tconst { voiceConnection, adapter, joinConfig } = createFakeVoiceConnection();\n\t\tDataStore.createJoinVoiceChannelPayload.mockImplementation((config) =>\n\t\t\tconfig === joinConfig ? dummyPayload : undefined,\n\t\t);\n\t\tadapter.sendPayload.mockReturnValue(false);\n\t\tvoiceConnection['onNetworkingClose'](1_234);\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Disconnected);\n\t\texpect(adapter.sendPayload).toHaveBeenCalledWith(dummyPayload);\n\t\texpect(voiceConnection.rejoinAttempts).toEqual(1);\n\t});\n});\n\ndescribe('VoiceConnection#onNetworkingStateChange', () => {\n\ttest('Does nothing when status code identical', () => {\n\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\t\tconst stateSetter = vitest.spyOn(voiceConnection, 'state', 'set');\n\t\tvoiceConnection['onNetworkingStateChange'](\n\t\t\t{ code: Networking.NetworkingStatusCode.Ready } as any,\n\t\t\t{ code: Networking.NetworkingStatusCode.Ready } as any,\n\t\t);\n\t\tvoiceConnection['onNetworkingStateChange'](\n\t\t\t{ code: Networking.NetworkingStatusCode.Closed } as any,\n\t\t\t{ code: Networking.NetworkingStatusCode.Closed } as any,\n\t\t);\n\t\texpect(stateSetter).not.toHaveBeenCalled();\n\t});\n\n\ttest('Does nothing when not in Ready or Connecting states', () => {\n\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\t\tconst stateSetter = vitest.spyOn(voiceConnection, 'state', 'set');\n\t\tconst call = [\n\t\t\t{ code: Networking.NetworkingStatusCode.Ready } as any,\n\t\t\t{ code: Networking.NetworkingStatusCode.Closed } as any,\n\t\t];\n\t\tvoiceConnection['_state'] = { status: VoiceConnectionStatus.Signalling } as any;\n\t\tvoiceConnection['onNetworkingStateChange'](call[0], call[1]);\n\t\tvoiceConnection['_state'] = { status: VoiceConnectionStatus.Disconnected } as any;\n\t\tvoiceConnection['onNetworkingStateChange'](call[0], call[1]);\n\t\tvoiceConnection['_state'] = { status: VoiceConnectionStatus.Destroyed } as any;\n\t\tvoiceConnection['onNetworkingStateChange'](call[0], call[1]);\n\t\texpect(stateSetter).not.toHaveBeenCalled();\n\t});\n\n\ttest('Transitions to Ready', () => {\n\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\t\tconst stateSetter = vitest.spyOn(voiceConnection, 'state', 'set');\n\t\tvoiceConnection['_state'] = {\n\t\t\t...(voiceConnection.state as VoiceConnectionSignallingState),\n\t\t\tstatus: VoiceConnectionStatus.Connecting,\n\t\t\tnetworking: new Networking.Networking({} as any, {}),\n\t\t};\n\n\t\tvoiceConnection['onNetworkingStateChange'](\n\t\t\t{ code: Networking.NetworkingStatusCode.Closed } as any,\n\t\t\t{ code: Networking.NetworkingStatusCode.Ready } as any,\n\t\t);\n\n\t\texpect(stateSetter).toHaveBeenCalledTimes(1);\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Ready);\n\t});\n\n\ttest('Transitions to Connecting', () => {\n\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\t\tconst stateSetter = vitest.spyOn(voiceConnection, 'state', 'set');\n\t\tvoiceConnection['_state'] = {\n\t\t\t...(voiceConnection.state as VoiceConnectionSignallingState),\n\t\t\tstatus: VoiceConnectionStatus.Connecting,\n\t\t\tnetworking: new Networking.Networking({} as any, {}),\n\t\t};\n\n\t\tvoiceConnection['onNetworkingStateChange'](\n\t\t\t{ code: Networking.NetworkingStatusCode.Ready } as any,\n\t\t\t{ code: Networking.NetworkingStatusCode.Identifying } as any,\n\t\t);\n\n\t\texpect(stateSetter).toHaveBeenCalledTimes(1);\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Connecting);\n\t});\n});\n\ndescribe('VoiceConnection#destroy', () => {\n\ttest('Throws when in Destroyed state', () => {\n\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\t\tvoiceConnection.state = { status: VoiceConnectionStatus.Destroyed };\n\t\texpect(() => voiceConnection.destroy()).toThrow();\n\t});\n\n\ttest('Cleans up in a valid, destroyable state', () => {\n\t\tconst { voiceConnection, joinConfig, adapter } = createFakeVoiceConnection();\n\t\tDataStore.getVoiceConnection.mockImplementation((guildId, group = 'default') =>\n\t\t\tguildId === joinConfig.guildId && group === joinConfig.group ? voiceConnection : undefined,\n\t\t);\n\t\tconst dummy = Symbol('dummy');\n\t\tDataStore.createJoinVoiceChannelPayload.mockImplementation(() => dummy as any);\n\t\tvoiceConnection.destroy();\n\t\texpect(DataStore.getVoiceConnection).toHaveReturnedWith(voiceConnection);\n\t\texpect(DataStore.untrackVoiceConnection).toHaveBeenCalledWith(voiceConnection);\n\t\texpect(DataStore.createJoinVoiceChannelPayload.mock.calls[0]?.[0]).toMatchObject({\n\t\t\tchannelId: null,\n\t\t\tguildId: joinConfig.guildId,\n\t\t});\n\t\texpect(adapter.sendPayload).toHaveBeenCalledWith(dummy);\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Destroyed);\n\t});\n});\n\ndescribe('VoiceConnection#disconnect', () => {\n\ttest('Fails in Destroyed and Signalling states', () => {\n\t\tconst { voiceConnection, adapter } = createFakeVoiceConnection();\n\t\tvoiceConnection.state = { status: VoiceConnectionStatus.Destroyed };\n\t\texpect(voiceConnection.disconnect()).toEqual(false);\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Destroyed);\n\n\t\tvoiceConnection.state = { status: VoiceConnectionStatus.Signalling, adapter };\n\t\texpect(voiceConnection.disconnect()).toEqual(false);\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Signalling);\n\t});\n\n\ttest('Disconnects - available adapter', () => {\n\t\tconst { voiceConnection, adapter } = createFakeVoiceConnection();\n\t\tvoiceConnection.state = {\n\t\t\tstatus: VoiceConnectionStatus.Ready,\n\t\t\tadapter,\n\t\t\tnetworking: new Networking.Networking({} as any, {}),\n\t\t};\n\t\tconst leavePayload = Symbol('dummy');\n\t\tDataStore.createJoinVoiceChannelPayload.mockImplementation(() => leavePayload as any);\n\t\texpect(voiceConnection.disconnect()).toEqual(true);\n\t\texpect(voiceConnection.joinConfig).toMatchObject({\n\t\t\tchannelId: null,\n\t\t\tguildId: '2',\n\t\t\tselfDeaf: true,\n\t\t\tselfMute: false,\n\t\t});\n\t\texpect(DataStore.createJoinVoiceChannelPayload).toHaveBeenCalledWith(voiceConnection.joinConfig);\n\t\texpect(adapter.sendPayload).toHaveBeenCalledWith(leavePayload);\n\t\texpect(voiceConnection.state).toMatchObject({\n\t\t\tstatus: VoiceConnectionStatus.Disconnected,\n\t\t\treason: VoiceConnectionDisconnectReason.Manual,\n\t\t});\n\t});\n\n\ttest('Disconnects - unavailable adapter', () => {\n\t\tconst { voiceConnection, adapter } = createFakeVoiceConnection();\n\t\tvoiceConnection.state = {\n\t\t\tstatus: VoiceConnectionStatus.Ready,\n\t\t\tadapter,\n\t\t\tnetworking: new Networking.Networking({} as any, {}),\n\t\t};\n\t\tadapter.sendPayload.mockImplementation(() => false);\n\t\texpect(voiceConnection.disconnect()).toEqual(false);\n\t\texpect(voiceConnection.state).toMatchObject({\n\t\t\tstatus: VoiceConnectionStatus.Disconnected,\n\t\t\treason: VoiceConnectionDisconnectReason.AdapterUnavailable,\n\t\t});\n\t});\n});\n\ndescribe('VoiceConnection#rejoin', () => {\n\ttest('Rejoins in a disconnected state', () => {\n\t\tconst dummy = Symbol('dummy') as any;\n\t\tDataStore.createJoinVoiceChannelPayload.mockImplementation(() => dummy);\n\n\t\tconst { voiceConnection, adapter } = createFakeVoiceConnection();\n\t\tvoiceConnection.state = {\n\t\t\t...(voiceConnection.state as VoiceConnectionSignallingState),\n\t\t\tstatus: VoiceConnectionStatus.Disconnected,\n\t\t\treason: VoiceConnectionDisconnectReason.WebSocketClose,\n\t\t\tcloseCode: 1_000,\n\t\t};\n\t\texpect(voiceConnection.rejoin()).toEqual(true);\n\t\texpect(voiceConnection.rejoinAttempts).toEqual(1);\n\t\texpect(adapter.sendPayload).toHaveBeenCalledWith(dummy);\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Signalling);\n\t});\n\n\ttest('Rejoins in a ready state', () => {\n\t\tconst dummy = Symbol('dummy') as any;\n\t\tDataStore.createJoinVoiceChannelPayload.mockImplementation(() => dummy);\n\n\t\tconst { voiceConnection, adapter } = createFakeVoiceConnection();\n\t\tvoiceConnection.state = {\n\t\t\t...(voiceConnection.state as VoiceConnectionReadyState),\n\t\t\tstatus: VoiceConnectionStatus.Ready,\n\t\t};\n\t\texpect(voiceConnection.rejoin()).toEqual(true);\n\t\texpect(voiceConnection.rejoinAttempts).toEqual(0);\n\t\texpect(adapter.sendPayload).toHaveBeenCalledWith(dummy);\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Ready);\n\t});\n\n\ttest('Stays in the disconnected state when the adapter fails', () => {\n\t\tconst dummy = Symbol('dummy') as any;\n\t\tDataStore.createJoinVoiceChannelPayload.mockImplementation(() => dummy);\n\n\t\tconst { voiceConnection, adapter } = createFakeVoiceConnection();\n\t\tvoiceConnection.state = {\n\t\t\t...(voiceConnection.state as VoiceConnectionSignallingState),\n\t\t\tstatus: VoiceConnectionStatus.Disconnected,\n\t\t\treason: VoiceConnectionDisconnectReason.WebSocketClose,\n\t\t\tcloseCode: 1_000,\n\t\t};\n\t\tadapter.sendPayload.mockReturnValue(false);\n\t\texpect(voiceConnection.rejoin()).toEqual(false);\n\t\texpect(voiceConnection.rejoinAttempts).toEqual(1);\n\t\texpect(adapter.sendPayload).toHaveBeenCalledWith(dummy);\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Disconnected);\n\t});\n});\n\ndescribe('VoiceConnection#subscribe', () => {\n\ttest('Does nothing in Destroyed state', () => {\n\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\t\tconst player = new AudioPlayer.AudioPlayer();\n\t\tplayer['subscribe'] = vitest.fn();\n\t\tvoiceConnection.state = { status: VoiceConnectionStatus.Destroyed };\n\t\texpect(voiceConnection.subscribe(player)).toBeUndefined();\n\t\texpect(player['subscribe']).not.toHaveBeenCalled();\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Destroyed);\n\t});\n\n\ttest('Subscribes in a live state', () => {\n\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\t\tconst adapter = (voiceConnection.state as VoiceConnectionSignallingState).adapter;\n\t\tconst player = new AudioPlayer.AudioPlayer();\n\t\tconst dummy = Symbol('dummy');\n\t\tplayer['subscribe'] = vitest.fn().mockImplementation(() => dummy);\n\t\texpect(voiceConnection.subscribe(player)).toEqual(dummy);\n\t\texpect(player['subscribe']).toHaveBeenCalledWith(voiceConnection);\n\t\texpect(voiceConnection.state).toMatchObject({\n\t\t\tstatus: VoiceConnectionStatus.Signalling,\n\t\t\tadapter,\n\t\t});\n\t});\n});\n\ndescribe('VoiceConnection#onSubscriptionRemoved', () => {\n\ttest('Does nothing in Destroyed state', () => {\n\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\t\tconst subscription = new PlayerSubscription(voiceConnection, new AudioPlayer.AudioPlayer());\n\t\tsubscription.unsubscribe = vitest.fn();\n\n\t\tvoiceConnection.state = { status: VoiceConnectionStatus.Destroyed };\n\t\tvoiceConnection['onSubscriptionRemoved'](subscription);\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Destroyed);\n\t\texpect(subscription.unsubscribe).not.toHaveBeenCalled();\n\t});\n\n\ttest('Does nothing when subscription is not the same as the stored one', () => {\n\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\t\tconst subscription = new PlayerSubscription(voiceConnection, new AudioPlayer.AudioPlayer());\n\t\tsubscription.unsubscribe = vitest.fn();\n\n\t\tvoiceConnection.state = { ...(voiceConnection.state as VoiceConnectionSignallingState), subscription };\n\t\tvoiceConnection['onSubscriptionRemoved'](Symbol('new subscription') as any);\n\t\texpect(voiceConnection.state).toMatchObject({\n\t\t\tstatus: VoiceConnectionStatus.Signalling,\n\t\t\tsubscription,\n\t\t});\n\t\texpect(subscription.unsubscribe).not.toHaveBeenCalled();\n\t});\n\n\ttest('Unsubscribes in a live state with matching subscription', () => {\n\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\t\tconst subscription = new PlayerSubscription(voiceConnection, new AudioPlayer.AudioPlayer());\n\t\tsubscription.unsubscribe = vitest.fn();\n\n\t\tvoiceConnection.state = { ...(voiceConnection.state as VoiceConnectionSignallingState), subscription };\n\t\tvoiceConnection['onSubscriptionRemoved'](subscription);\n\t\texpect(voiceConnection.state).toEqual({\n\t\t\t...voiceConnection.state,\n\t\t\tsubscription: undefined,\n\t\t});\n\t\texpect(subscription.unsubscribe).toHaveBeenCalledTimes(1);\n\t});\n\n\tdescribe('updateReceiveBindings', () => {\n\t\ttest('Applies and removes udp listeners', () => {\n\t\t\t// Arrange\n\t\t\tconst ws = new EventEmitter() as any;\n\n\t\t\tconst oldNetworking = new Networking.Networking({} as any, {});\n\t\t\toldNetworking.state = {\n\t\t\t\tcode: Networking.NetworkingStatusCode.Ready,\n\t\t\t\tconnectionData: {} as any,\n\t\t\t\tconnectionOptions: {} as any,\n\t\t\t\tudp: new EventEmitter() as any,\n\t\t\t\tws,\n\t\t\t};\n\n\t\t\tconst newNetworking = new Networking.Networking({} as any, {});\n\t\t\tnewNetworking.state = {\n\t\t\t\t...oldNetworking.state,\n\t\t\t\tudp: new EventEmitter() as any,\n\t\t\t};\n\n\t\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\n\t\t\t// Act\n\t\t\tvoiceConnection['updateReceiveBindings'](newNetworking.state, oldNetworking.state);\n\n\t\t\t// Assert\n\t\t\texpect(oldNetworking.state.udp.listenerCount('message')).toEqual(0);\n\t\t\texpect(newNetworking.state.udp.listenerCount('message')).toEqual(1);\n\t\t\texpect(voiceConnection.receiver.connectionData).toEqual(newNetworking.state.connectionData);\n\t\t});\n\n\t\ttest('Applies and removes ws listeners', () => {\n\t\t\t// Arrange\n\t\t\tconst udp = new EventEmitter() as any;\n\n\t\t\tconst oldNetworking = new Networking.Networking({} as any, {});\n\t\t\toldNetworking.state = {\n\t\t\t\tcode: Networking.NetworkingStatusCode.Ready,\n\t\t\t\tconnectionData: {} as any,\n\t\t\t\tconnectionOptions: {} as any,\n\t\t\t\tudp,\n\t\t\t\tws: new EventEmitter() as any,\n\t\t\t};\n\n\t\t\tconst newNetworking = new Networking.Networking({} as any, {});\n\t\t\tnewNetworking.state = {\n\t\t\t\t...oldNetworking.state,\n\t\t\t\tws: new EventEmitter() as any,\n\t\t\t};\n\n\t\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\n\t\t\t// Act\n\t\t\tvoiceConnection['updateReceiveBindings'](newNetworking.state, oldNetworking.state);\n\n\t\t\t// Assert\n\t\t\texpect(oldNetworking.state.ws.listenerCount('packet')).toEqual(0);\n\t\t\texpect(newNetworking.state.ws.listenerCount('packet')).toEqual(1);\n\t\t\texpect(voiceConnection.receiver.connectionData).toEqual(newNetworking.state.connectionData);\n\t\t});\n\n\t\ttest('Applies initial listeners', () => {\n\t\t\t// Arrange\n\n\t\t\tconst newNetworking = new Networking.Networking({} as any, {});\n\t\t\tnewNetworking.state = {\n\t\t\t\tcode: Networking.NetworkingStatusCode.Ready,\n\t\t\t\tconnectionData: {} as any,\n\t\t\t\tconnectionOptions: {} as any,\n\t\t\t\tudp: new EventEmitter() as any,\n\t\t\t\tws: new EventEmitter() as any,\n\t\t\t};\n\n\t\t\tconst { voiceConnection } = createFakeVoiceConnection();\n\n\t\t\t// Act\n\t\t\tvoiceConnection['updateReceiveBindings'](newNetworking.state, undefined);\n\n\t\t\t// Assert\n\t\t\texpect(newNetworking.state.ws.listenerCount('packet')).toEqual(1);\n\t\t\texpect(newNetworking.state.udp.listenerCount('message')).toEqual(1);\n\t\t\texpect(voiceConnection.receiver.connectionData).toEqual(newNetworking.state.connectionData);\n\t\t});\n\t});\n});\n\ndescribe('Adapter', () => {\n\ttest('onVoiceServerUpdate', () => {\n\t\tconst { adapter, voiceConnection } = createFakeVoiceConnection();\n\t\tvoiceConnection['addServerPacket'] = vitest.fn();\n\t\tconst dummy = Symbol('dummy') as any;\n\t\tadapter.libMethods.onVoiceServerUpdate!(dummy);\n\t\texpect(voiceConnection['addServerPacket']).toHaveBeenCalledWith(dummy);\n\t});\n\n\ttest('onVoiceStateUpdate', () => {\n\t\tconst { adapter, voiceConnection } = createFakeVoiceConnection();\n\t\tvoiceConnection['addStatePacket'] = vitest.fn();\n\t\tconst dummy = Symbol('dummy') as any;\n\t\tadapter.libMethods.onVoiceStateUpdate!(dummy);\n\t\texpect(voiceConnection['addStatePacket']).toHaveBeenCalledWith(dummy);\n\t});\n\n\ttest('destroy', () => {\n\t\tconst { adapter, voiceConnection } = createFakeVoiceConnection();\n\t\tadapter.libMethods.destroy!();\n\t\texpect(voiceConnection.state.status).toEqual(VoiceConnectionStatus.Destroyed);\n\t\texpect(adapter.sendPayload).not.toHaveBeenCalled();\n\t});\n});\n"
  },
  {
    "path": "packages/voice/__tests__/VoiceReceiver.test.ts",
    "content": "/* eslint-disable id-length */\n/* eslint-disable @typescript-eslint/dot-notation */\nimport { Buffer } from 'node:buffer';\nimport { once } from 'node:events';\nimport process from 'node:process';\nimport { VoiceOpcodes } from 'discord-api-types/voice/v8';\nimport { describe, test, expect, vitest, beforeEach } from 'vitest';\nimport {\n\tRTP_PACKET_DESKTOP,\n\tRTP_PACKET_CHROME,\n\tRTP_PACKET_ANDROID,\n\tXCHACHA20_SAMPLE,\n\tAES256GCM_SAMPLE,\n} from '../__mocks__/rtp';\nimport { VoiceConnection, VoiceConnectionStatus } from '../src/VoiceConnection';\nimport { VoiceReceiver } from '../src/receive/VoiceReceiver';\n\nvitest.mock('../src/VoiceConnection', async (importOriginal) => {\n\t// eslint-disable-next-line @typescript-eslint/consistent-type-imports\n\tconst actual = await importOriginal<typeof import('../src/VoiceConnection')>();\n\treturn {\n\t\t...actual,\n\t\tVoiceConnection: vitest.fn(),\n\t};\n});\n\nvitest.mock('../src/receive/SSRCMap');\n\nasync function nextTick() {\n\t// eslint-disable-next-line no-promise-executor-return\n\treturn new Promise((resolve) => process.nextTick(resolve));\n}\n\ndescribe('VoiceReceiver', () => {\n\tlet voiceConnection: VoiceConnection;\n\tlet receiver: VoiceReceiver;\n\n\tbeforeEach(() => {\n\t\tvoiceConnection = new VoiceConnection({} as any, {} as any);\n\t\tvoiceConnection.state = {\n\t\t\tstatus: VoiceConnectionStatus.Signalling,\n\t\t} as any;\n\t\treceiver = new VoiceReceiver(voiceConnection);\n\t\treceiver['connectionData'] = {\n\t\t\tencryptionMode: 'dummy',\n\t\t\tnonceBuffer: Buffer.alloc(0),\n\t\t\tsecretKey: Buffer.alloc(0),\n\t\t};\n\t});\n\n\ttest.each([\n\t\t['RTP Packet Desktop', RTP_PACKET_DESKTOP],\n\t\t['RTP Packet Chrome', RTP_PACKET_CHROME],\n\t\t['RTP Packet Android', RTP_PACKET_ANDROID],\n\t])('onUdpMessage: decrypt from %s', async (_testName, RTP_PACKET) => {\n\t\treceiver['decrypt'] = vitest.fn().mockImplementationOnce(() => RTP_PACKET.decrypted);\n\n\t\tconst spy = vitest.spyOn(receiver.ssrcMap, 'get');\n\t\tspy.mockImplementation(() => ({\n\t\t\taudioSSRC: RTP_PACKET.ssrc,\n\t\t\tuserId: '123',\n\t\t}));\n\n\t\tconst stream = receiver.subscribe('123');\n\n\t\treceiver['onUdpMessage'](RTP_PACKET.packet);\n\t\tawait nextTick();\n\t\texpect(stream.read()).toEqual(RTP_PACKET.opusFrame);\n\t});\n\n\ttest('onUdpMessage: <8 bytes packet', () => {\n\t\texpect(() => receiver['onUdpMessage'](Buffer.alloc(4))).not.toThrow();\n\t});\n\n\ttest('onUdpMessage: destroys stream on decrypt failure', async () => {\n\t\treceiver['decrypt'] = vitest.fn().mockImplementationOnce(() => null);\n\n\t\tconst spy = vitest.spyOn(receiver.ssrcMap, 'get');\n\t\tspy.mockImplementation(() => ({\n\t\t\taudioSSRC: RTP_PACKET_DESKTOP.ssrc,\n\t\t\tuserId: '123',\n\t\t}));\n\n\t\tconst stream = receiver.subscribe('123');\n\n\t\tconst errorEvent = once(stream, 'error');\n\n\t\treceiver['onUdpMessage'](RTP_PACKET_DESKTOP.packet);\n\t\tawait nextTick();\n\t\tawait expect(errorEvent).resolves.toMatchObject([expect.any(Error)]);\n\t\texpect(receiver.subscriptions.size).toEqual(0);\n\t});\n\n\ttest('subscribe: only allows one subscribe stream per SSRC', () => {\n\t\tconst spy = vitest.spyOn(receiver.ssrcMap, 'get');\n\t\tspy.mockImplementation(() => ({\n\t\t\taudioSSRC: RTP_PACKET_DESKTOP.ssrc,\n\t\t\tuserId: '123',\n\t\t}));\n\n\t\tconst stream = receiver.subscribe('123');\n\t\texpect(receiver.subscribe('123')).toEqual(stream);\n\t});\n\n\tdescribe('onWsPacket', () => {\n\t\ttest('CLIENT_DISCONNECT packet', () => {\n\t\t\tconst spy = vitest.spyOn(receiver.ssrcMap, 'delete');\n\t\t\treceiver['onWsPacket']({\n\t\t\t\top: VoiceOpcodes.ClientDisconnect,\n\t\t\t\td: {\n\t\t\t\t\tuser_id: '123abc',\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(spy).toHaveBeenCalledWith('123abc');\n\t\t});\n\n\t\ttest('SPEAKING packet', () => {\n\t\t\tconst spy = vitest.spyOn(receiver.ssrcMap, 'update');\n\t\t\treceiver['onWsPacket']({\n\t\t\t\top: VoiceOpcodes.Speaking,\n\t\t\t\td: {\n\t\t\t\t\tssrc: 123,\n\t\t\t\t\tuser_id: '123abc',\n\t\t\t\t\tspeaking: 1,\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(spy).toHaveBeenCalledWith({\n\t\t\t\taudioSSRC: 123,\n\t\t\t\tuserId: '123abc',\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('decrypt', () => {\n\t\ttest('decrypt: aead_xchacha20_poly1305_rtpsize', () => {\n\t\t\tconst nonceSpace = Buffer.alloc(24);\n\n\t\t\tconst decrypted = receiver['decrypt'](\n\t\t\t\tXCHACHA20_SAMPLE.encrypted,\n\t\t\t\t'aead_xchacha20_poly1305_rtpsize',\n\t\t\t\tnonceSpace,\n\t\t\t\tXCHACHA20_SAMPLE.key,\n\t\t\t);\n\n\t\t\tconst expectedNonce = Buffer.concat([\n\t\t\t\tXCHACHA20_SAMPLE.encrypted.subarray(XCHACHA20_SAMPLE.encrypted.length - 4),\n\t\t\t\tBuffer.alloc(20),\n\t\t\t]);\n\n\t\t\texpect(nonceSpace.equals(expectedNonce)).toEqual(true);\n\t\t\texpect(decrypted.equals(XCHACHA20_SAMPLE.decrypted)).toEqual(true);\n\t\t});\n\n\t\ttest('decrypt: aead_aes256gcm_rtpsize', () => {\n\t\t\tconst nonceSpace = Buffer.alloc(12);\n\n\t\t\tconst decrypted = receiver['decrypt'](\n\t\t\t\tAES256GCM_SAMPLE.encrypted,\n\t\t\t\t'aead_aes256_gcm_rtpsize',\n\t\t\t\tnonceSpace,\n\t\t\t\tAES256GCM_SAMPLE.key,\n\t\t\t);\n\n\t\t\tconst expectedNonce = Buffer.concat([\n\t\t\t\tAES256GCM_SAMPLE.encrypted.subarray(AES256GCM_SAMPLE.encrypted.length - 4),\n\t\t\t\tBuffer.alloc(8),\n\t\t\t]);\n\n\t\t\texpect(nonceSpace.equals(expectedNonce)).toEqual(true);\n\t\t\texpect(decrypted.equals(AES256GCM_SAMPLE.decrypted)).toEqual(true);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/voice/__tests__/VoiceUDPSocket.test.ts",
    "content": "import { Buffer } from 'node:buffer';\nimport { createSocket as _createSocket } from 'node:dgram';\nimport { EventEmitter } from 'node:events';\nimport type { MockedFunction } from 'vitest';\nimport { describe, test, expect, vitest, beforeEach, afterEach } from 'vitest';\nimport { VoiceUDPSocket } from '../src/networking/VoiceUDPSocket';\n\nvitest.mock('node:dgram');\nvitest.useFakeTimers();\n\nconst createSocket = _createSocket as unknown as MockedFunction<typeof _createSocket>;\n\nbeforeEach(() => {\n\tcreateSocket.mockReset();\n});\n\nclass FakeSocket extends EventEmitter {\n\tpublic send(_buffer: Buffer, _port: number, _address: string) {}\n\n\tpublic close() {\n\t\tthis.emit('close');\n\t}\n}\n\n// ip = 91.90.123.93, port = 54148\nconst VALID_RESPONSE = Buffer.from([\n\t0x0, 0x2, 0x0, 0x46, 0x0, 0x4, 0xeb, 0x23, 0x39, 0x31, 0x2e, 0x39, 0x30, 0x2e, 0x31, 0x32, 0x33, 0x2e, 0x39, 0x33,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n\t0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd3, 0x84,\n]);\n\nasync function wait() {\n\treturn new Promise((resolve) => {\n\t\tsetImmediate(resolve);\n\t\tvitest.advanceTimersToNextTimer();\n\t});\n}\n\ndescribe('VoiceUDPSocket#performIPDiscovery', () => {\n\tlet socket: VoiceUDPSocket;\n\n\tafterEach(() => {\n\t\tsocket.destroy();\n\t});\n\n\t/*\n\t\tEnsures that the UDP socket sends data and parses the response correctly\n\t*/\n\ttest('Resolves and cleans up with a successful flow', async () => {\n\t\tconst fake = new FakeSocket();\n\t\tfake.send = vitest.fn().mockImplementation((_buffer: Buffer, _port: number, _address: string) => {\n\t\t\tfake.emit('message', VALID_RESPONSE);\n\t\t});\n\t\tcreateSocket.mockImplementation((_type) => fake as any);\n\t\tsocket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25_565 });\n\n\t\texpect(createSocket).toHaveBeenCalledWith('udp4');\n\t\texpect(fake.listenerCount('message')).toEqual(1);\n\t\tawait expect(socket.performIPDiscovery(1_234)).resolves.toEqual({\n\t\t\tip: '91.90.123.93',\n\t\t\tport: 54_148,\n\t\t});\n\t\t// Ensure clean up occurs\n\t\texpect(fake.listenerCount('message')).toEqual(1);\n\t});\n\n\t/*\n\t\tIn the case where an unrelated message is received before the IP discovery buffer,\n\t\tthe UDP socket should wait indefinitely until the correct buffer arrives.\n\t*/\n\ttest('Waits for a valid response in an unexpected flow', async () => {\n\t\tconst fake = new FakeSocket();\n\t\tconst fakeResponse = Buffer.from([1, 2, 3, 4, 5]);\n\t\tfake.send = vitest.fn().mockImplementation(async (_buffer: Buffer, _port: number, _address: string) => {\n\t\t\tfake.emit('message', fakeResponse);\n\t\t\tawait wait();\n\t\t\tfake.emit('message', VALID_RESPONSE);\n\t\t});\n\t\tcreateSocket.mockImplementation(() => fake as any);\n\t\tsocket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25_565 });\n\n\t\texpect(createSocket).toHaveBeenCalledWith('udp4');\n\t\texpect(fake.listenerCount('message')).toEqual(1);\n\t\tawait expect(socket.performIPDiscovery(1_234)).resolves.toEqual({\n\t\t\tip: '91.90.123.93',\n\t\t\tport: 54_148,\n\t\t});\n\t\t// Ensure clean up occurs\n\t\texpect(fake.listenerCount('message')).toEqual(1);\n\t});\n\n\ttest('Rejects if socket closes before IP discovery can be completed', async () => {\n\t\tconst fake = new FakeSocket();\n\t\tfake.send = vitest.fn().mockImplementation(async (_buffer: Buffer, _port: number, _address: string) => {\n\t\t\tawait wait();\n\t\t\tfake.close();\n\t\t});\n\t\tcreateSocket.mockImplementation(() => fake as any);\n\t\tsocket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25_565 });\n\n\t\texpect(createSocket).toHaveBeenCalledWith('udp4');\n\t\tawait expect(socket.performIPDiscovery(1_234)).rejects.toThrowError();\n\t});\n\n\ttest('Stays alive when messages are echoed back', async () => {\n\t\tconst fake = new FakeSocket();\n\t\tfake.send = vitest.fn().mockImplementation(async (buffer: Buffer) => {\n\t\t\tawait wait();\n\t\t\tfake.emit('message', buffer);\n\t\t});\n\t\tcreateSocket.mockImplementation(() => fake as any);\n\t\tsocket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25_565 });\n\n\t\tlet closed = false;\n\t\tsocket.on('close', () => (closed = true));\n\n\t\tfor (let index = 0; index < 30; index++) {\n\t\t\tvitest.advanceTimersToNextTimer();\n\t\t\tawait wait();\n\t\t}\n\n\t\texpect(closed).toEqual(false);\n\t});\n\n\ttest('Recovers from intermittent responses', async () => {\n\t\tconst fake = new FakeSocket();\n\t\tconst fakeSend = vitest.fn();\n\t\tfake.send = fakeSend;\n\t\tcreateSocket.mockImplementation(() => fake as any);\n\t\tsocket = new VoiceUDPSocket({ ip: '1.2.3.4', port: 25_565 });\n\n\t\tlet closed = false;\n\n\t\tsocket.on('close', () => (closed = true));\n\n\t\tfor (let index = 0; index < 10; index++) {\n\t\t\tvitest.advanceTimersToNextTimer();\n\t\t\tawait wait();\n\t\t}\n\n\t\tfakeSend.mockImplementation(async (buffer: Buffer) => {\n\t\t\tawait wait();\n\t\t\tfake.emit('message', buffer);\n\t\t});\n\t\texpect(closed).toEqual(false);\n\t\tfor (let index = 0; index < 30; index++) {\n\t\t\tvitest.advanceTimersToNextTimer();\n\t\t\tawait wait();\n\t\t}\n\n\t\texpect(closed).toEqual(false);\n\t});\n});\n"
  },
  {
    "path": "packages/voice/__tests__/VoiceWebSocket.test.ts",
    "content": "import { type EventEmitter, once } from 'node:events';\nimport { VoiceOpcodes } from 'discord-api-types/voice/v8';\nimport { describe, test, expect, beforeEach } from 'vitest';\nimport WS from 'vitest-websocket-mock';\nimport { VoiceWebSocket } from '../src/networking/VoiceWebSocket';\n\nbeforeEach(() => {\n\tWS.clean();\n});\n\nasync function onceIgnoreError<Emitter extends EventEmitter>(target: Emitter, event: string) {\n\treturn new Promise((resolve) => {\n\t\ttarget.on(event, resolve);\n\t});\n}\n\nasync function onceOrThrow<Emitter extends EventEmitter>(target: Emitter, event: string, after: number) {\n\treturn new Promise((resolve, reject) => {\n\t\ttarget.on(event, resolve);\n\t\tsetTimeout(() => reject(new Error('Time up')), after);\n\t});\n}\n\n// TODO: Fix voice tests\n\ndescribe.skip('VoiceWebSocket: packet parsing', () => {\n\ttest('Parses and emits packets', async () => {\n\t\tconst endpoint = 'ws://localhost:1234';\n\t\tconst server = new WS(endpoint, { jsonProtocol: true });\n\t\tconst ws = new VoiceWebSocket(endpoint, false);\n\t\tawait server.connected;\n\t\tconst dummy = { value: 3 };\n\t\tconst rcv = once(ws, 'packet');\n\t\tserver.send(dummy);\n\t\tawait expect(rcv).resolves.toEqual([dummy]);\n\t});\n\n\ttest('Recovers from invalid packets', async () => {\n\t\tconst endpoint = 'ws://localhost:1234';\n\t\tconst server = new WS(endpoint);\n\t\tconst ws = new VoiceWebSocket(endpoint, false);\n\t\tawait server.connected;\n\n\t\tlet rcv = once(ws, 'packet');\n\t\tserver.send('asdf');\n\t\tawait expect(rcv).rejects.toThrowError();\n\n\t\tconst dummy = { op: 1_234 };\n\t\trcv = once(ws, 'packet');\n\t\tserver.send(JSON.stringify(dummy));\n\t\tawait expect(rcv).resolves.toEqual([dummy]);\n\t});\n});\n\ndescribe.skip('VoiceWebSocket: event propagation', () => {\n\ttest('open', async () => {\n\t\tconst endpoint = 'ws://localhost:1234';\n\t\tconst server = new WS(endpoint);\n\t\tconst ws = new VoiceWebSocket(endpoint, false);\n\t\tconst rcv = once(ws, 'open');\n\t\tawait server.connected;\n\t\tawait expect(rcv).resolves.toBeTruthy();\n\t});\n\n\ttest('close (clean)', async () => {\n\t\tconst endpoint = 'ws://localhost:1234';\n\t\tconst server = new WS(endpoint);\n\t\tconst ws = new VoiceWebSocket(endpoint, false);\n\t\tawait server.connected;\n\t\tconst rcv = once(ws, 'close');\n\t\tserver.close();\n\t\tawait expect(rcv).resolves.toBeTruthy();\n\t});\n\n\ttest('close (error)', async () => {\n\t\tconst endpoint = 'ws://localhost:1234';\n\t\tconst server = new WS(endpoint);\n\t\tconst ws = new VoiceWebSocket(endpoint, false);\n\t\tawait server.connected;\n\t\tconst rcvError = once(ws, 'error');\n\t\tconst rcvClose = onceIgnoreError(ws, 'close');\n\t\tserver.error();\n\t\tawait expect(rcvError).resolves.toBeTruthy();\n\t\tawait expect(rcvClose).resolves.toBeTruthy();\n\t});\n});\n\ndescribe.skip('VoiceWebSocket: heartbeating', () => {\n\ttest('Normal heartbeat flow', async () => {\n\t\tconst endpoint = 'ws://localhost:1234';\n\t\tconst server = new WS(endpoint, { jsonProtocol: true });\n\t\tconst ws = new VoiceWebSocket(endpoint, false);\n\t\tawait server.connected;\n\t\tconst rcv = onceOrThrow(ws, 'close', 750);\n\t\tws.setHeartbeatInterval(50);\n\t\tfor (let index = 0; index < 10; index++) {\n\t\t\tconst packet: any = await server.nextMessage;\n\t\t\texpect(packet).toMatchObject({\n\t\t\t\top: VoiceOpcodes.Heartbeat,\n\t\t\t});\n\t\t\tserver.send({\n\t\t\t\top: VoiceOpcodes.HeartbeatAck,\n\t\t\t\t// eslint-disable-next-line id-length\n\t\t\t\td: packet.d,\n\t\t\t});\n\t\t\texpect(ws.ping).toBeGreaterThanOrEqual(0);\n\t\t}\n\n\t\tws.setHeartbeatInterval(-1);\n\t\tawait expect(rcv).rejects.toThrowError();\n\t});\n\n\ttest('Closes when no ack is received', async () => {\n\t\tconst endpoint = 'ws://localhost:1234';\n\t\tconst server = new WS(endpoint, { jsonProtocol: true });\n\t\tconst ws = new VoiceWebSocket(endpoint, false);\n\t\tws.on('error', () => {});\n\t\tawait server.connected;\n\t\tconst rcv = onceIgnoreError(ws, 'close');\n\t\tws.setHeartbeatInterval(50);\n\t\tawait expect(rcv).resolves.toBeTruthy();\n\t\texpect(ws.ping).toBeUndefined();\n\t\texpect(server.messages.length).toEqual(3);\n\t});\n});\n"
  },
  {
    "path": "packages/voice/__tests__/abortAfter.test.ts",
    "content": "import { describe, test, expect, vitest } from 'vitest';\nimport { abortAfter } from '../src/util/abortAfter';\n\nvitest.useFakeTimers();\n\nconst clearTimeoutSpy = vitest.spyOn(global, 'clearTimeout');\n\ndescribe('abortAfter', () => {\n\ttest('Aborts after the given delay', () => {\n\t\tconst [ac, signal] = abortAfter(100);\n\t\texpect(ac.signal).toEqual(signal);\n\t\texpect(signal.aborted).toEqual(false);\n\t\tvitest.runAllTimers();\n\t\texpect(signal.aborted).toEqual(true);\n\t});\n\n\ttest('Cleans up when manually aborted', () => {\n\t\tconst [ac, signal] = abortAfter(100);\n\t\texpect(ac.signal).toEqual(signal);\n\t\texpect(signal.aborted).toEqual(false);\n\t\tclearTimeoutSpy.mockClear();\n\t\tac.abort();\n\t\texpect(clearTimeoutSpy).toHaveBeenCalledTimes(1);\n\t});\n});\n"
  },
  {
    "path": "packages/voice/__tests__/demuxProbe.test.ts",
    "content": "import { Buffer } from 'node:buffer';\nimport EventEmitter, { once } from 'node:events';\nimport process from 'node:process';\nimport { Readable } from 'node:stream';\nimport { opus as _opus } from 'prism-media';\nimport { describe, test, expect, vitest, type Mock, beforeAll, beforeEach, type Mocked } from 'vitest';\nimport { StreamType } from '../src/audio/index';\nimport { demuxProbe } from '../src/util/demuxProbe';\n\nvitest.mock('prism-media');\n\nconst WebmDemuxer = _opus.WebmDemuxer as unknown as Mocked<typeof _opus.WebmDemuxer>;\nconst OggDemuxer = _opus.OggDemuxer as unknown as Mocked<typeof _opus.OggDemuxer>;\n\nasync function nextTick() {\n\t// eslint-disable-next-line no-promise-executor-return\n\treturn new Promise((resolve) => process.nextTick(resolve));\n}\n\nasync function* gen(num: number) {\n\tfor (let index = 0; index < num; index++) {\n\t\tyield Buffer.from([index]);\n\t\tawait nextTick();\n\t}\n}\n\nfunction range(num: number) {\n\treturn Buffer.from(Array.from(Array.from({ length: num }).keys()));\n}\n\nconst validHead = Buffer.from([\n\t0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x01, 0x02, 0x38, 0x01, 0x80, 0xbb, 0, 0, 0, 0, 0,\n]);\n\nconst invalidHead = Buffer.from([\n\t0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x01, 0x01, 0x38, 0x01, 0x80, 0xbb, 0, 0, 0, 0, 0,\n]);\n\nasync function collectStream(stream: Readable): Promise<Buffer> {\n\tlet output = Buffer.alloc(0);\n\tawait once(stream, 'readable');\n\tfor await (const data of stream) {\n\t\toutput = Buffer.concat([output, data]);\n\t}\n\n\treturn output;\n}\n\ndescribe('demuxProbe', () => {\n\tconst webmWrite: Mock<(buffer: Buffer) => void> = vitest.fn();\n\tconst oggWrite: Mock<(buffer: Buffer) => void> = vitest.fn();\n\n\tbeforeAll(() => {\n\t\t(WebmDemuxer as any).prototype = {\n\t\t\t...WebmDemuxer,\n\t\t\t...EventEmitter.prototype,\n\t\t\twrite: webmWrite,\n\t\t};\n\t\t(OggDemuxer as any).prototype = {\n\t\t\t...OggDemuxer,\n\t\t\t...EventEmitter.prototype,\n\t\t\twrite: oggWrite,\n\t\t};\n\t});\n\n\tbeforeEach(() => {\n\t\twebmWrite.mockReset();\n\t\toggWrite.mockReset();\n\t});\n\n\ttest('Defaults to arbitrary', async () => {\n\t\tconst stream = Readable.from(gen(10), { objectMode: false });\n\t\tconst probe = await demuxProbe(stream);\n\t\texpect(probe.type).toEqual(StreamType.Arbitrary);\n\t\tawait expect(collectStream(probe.stream)).resolves.toEqual(range(10));\n\t});\n\n\ttest('Detects WebM', async () => {\n\t\tconst stream = Readable.from(gen(10), { objectMode: false });\n\t\twebmWrite.mockImplementation(function mock(this: EventEmitter, data: Buffer) {\n\t\t\tif (data[0] === 5) this.emit('head', validHead);\n\t\t});\n\t\tconst probe = await demuxProbe(stream);\n\t\texpect(probe.type).toEqual(StreamType.WebmOpus);\n\t\tawait expect(collectStream(probe.stream)).resolves.toEqual(range(10));\n\t});\n\n\ttest('Detects Ogg', async () => {\n\t\tconst stream = Readable.from(gen(10), { objectMode: false });\n\t\toggWrite.mockImplementation(function mock(this: EventEmitter, data: Buffer) {\n\t\t\tif (data[0] === 5) this.emit('head', validHead);\n\t\t});\n\t\tconst probe = await demuxProbe(stream);\n\t\texpect(probe.type).toEqual(StreamType.OggOpus);\n\t\tawait expect(collectStream(probe.stream)).resolves.toEqual(range(10));\n\t});\n\n\ttest('Rejects invalid OpusHead', async () => {\n\t\tconst stream = Readable.from(gen(10), { objectMode: false });\n\t\toggWrite.mockImplementation(function mock(this: EventEmitter, data: Buffer) {\n\t\t\tif (data[0] === 5) this.emit('head', invalidHead);\n\t\t});\n\t\tconst probe = await demuxProbe(stream);\n\t\texpect(probe.type).toEqual(StreamType.Arbitrary);\n\t\tawait expect(collectStream(probe.stream)).resolves.toEqual(range(10));\n\t});\n\n\ttest('Gives up on larger streams', async () => {\n\t\tconst stream = Readable.from(gen(8_192), { objectMode: false });\n\t\tconst probe = await demuxProbe(stream);\n\t\texpect(probe.type).toEqual(StreamType.Arbitrary);\n\t\tawait expect(collectStream(probe.stream)).resolves.toEqual(range(8_192));\n\t});\n\n\ttest('Propagates errors', async () => {\n\t\tconst testError = new Error('test error');\n\t\tconst stream = new Readable({\n\t\t\tread() {\n\t\t\t\tthis.destroy(testError);\n\t\t\t},\n\t\t});\n\t\tawait expect(demuxProbe(stream)).rejects.toEqual(testError);\n\t});\n});\n"
  },
  {
    "path": "packages/voice/__tests__/entersState.test.ts",
    "content": "import { EventEmitter } from 'node:events';\nimport process from 'node:process';\nimport { describe, test, expect, vitest, beforeEach } from 'vitest';\nimport { VoiceConnectionStatus, type VoiceConnection } from '../src/VoiceConnection';\nimport { entersState } from '../src/util/entersState';\n\nfunction createFakeVoiceConnection(status = VoiceConnectionStatus.Signalling) {\n\tconst vc = new EventEmitter() as any;\n\tvc.state = { status };\n\treturn vc as VoiceConnection;\n}\n\nbeforeEach(() => {\n\tvitest.useFakeTimers();\n});\n\ndescribe('entersState', () => {\n\ttest('Returns the target once the state has been entered before timeout', async () => {\n\t\tvitest.useRealTimers();\n\t\tconst vc = createFakeVoiceConnection();\n\t\tprocess.nextTick(() => vc.emit(VoiceConnectionStatus.Ready, null as any, null as any));\n\t\tconst result = await entersState(vc, VoiceConnectionStatus.Ready, 1_000);\n\t\texpect(result).toEqual(vc);\n\t});\n\n\ttest('Rejects once the timeout is exceeded', async () => {\n\t\tconst vc = createFakeVoiceConnection();\n\t\tconst promise = entersState(vc, VoiceConnectionStatus.Ready, 1_000);\n\t\tvitest.runAllTimers();\n\t\tawait expect(promise).rejects.toThrowError();\n\t});\n\n\ttest('Returns the target once the state has been entered before signal is aborted', async () => {\n\t\tvitest.useRealTimers();\n\t\tconst vc = createFakeVoiceConnection();\n\t\tconst ac = new AbortController();\n\t\tprocess.nextTick(() => vc.emit(VoiceConnectionStatus.Ready, null as any, null as any));\n\t\tconst result = await entersState(vc, VoiceConnectionStatus.Ready, ac.signal);\n\t\texpect(result).toEqual(vc);\n\t});\n\n\ttest('Rejects once the signal is aborted', async () => {\n\t\tconst vc = createFakeVoiceConnection();\n\t\tconst ac = new AbortController();\n\t\tconst promise = entersState(vc, VoiceConnectionStatus.Ready, ac.signal);\n\t\tac.abort();\n\t\tawait expect(promise).rejects.toThrowError();\n\t});\n\n\ttest('Resolves immediately when target already in desired state', async () => {\n\t\tconst vc = createFakeVoiceConnection();\n\t\tawait expect(entersState(vc, VoiceConnectionStatus.Signalling, 1_000)).resolves.toEqual(vc);\n\t});\n});\n"
  },
  {
    "path": "packages/voice/__tests__/joinVoiceChannel.test.ts",
    "content": "import { describe, test, expect, vitest, beforeAll, beforeEach } from 'vitest';\nimport * as VoiceConnection from '../src/VoiceConnection';\nimport { joinVoiceChannel } from '../src/joinVoiceChannel';\n\nconst adapterCreator = () => ({ destroy: vitest.fn(), send: vitest.fn() }) as any;\nconst createVoiceConnection = vitest.spyOn(VoiceConnection, 'createVoiceConnection');\n\nbeforeAll(() => {\n\tcreateVoiceConnection.mockImplementation(() => null as any);\n});\n\nbeforeEach(() => {\n\tcreateVoiceConnection.mockClear();\n});\n\ndescribe('joinVoiceChannel', () => {\n\ttest('Uses default group', () => {\n\t\tjoinVoiceChannel({\n\t\t\tchannelId: '123',\n\t\t\tguildId: '456',\n\t\t\tadapterCreator,\n\t\t});\n\t\texpect(createVoiceConnection.mock.calls[0]?.[0]).toMatchObject({\n\t\t\tchannelId: '123',\n\t\t\tguildId: '456',\n\t\t\tgroup: 'default',\n\t\t});\n\t});\n\n\ttest('Respects custom group', () => {\n\t\tjoinVoiceChannel({\n\t\t\tchannelId: '123',\n\t\t\tguildId: '456',\n\t\t\tgroup: 'abc',\n\t\t\tadapterCreator,\n\t\t});\n\t\texpect(createVoiceConnection.mock.calls[0]?.[0]).toMatchObject({\n\t\t\tchannelId: '123',\n\t\t\tguildId: '456',\n\t\t\tgroup: 'abc',\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/voice/api-extractor.json",
    "content": "{\n\t\"extends\": \"../../api-extractor.json\",\n\t\"docModel\": {\n\t\t\"projectFolderUrl\": \"https://github.com/discordjs/discord.js/tree/main/packages/voice\"\n\t}\n}\n"
  },
  {
    "path": "packages/voice/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t\t{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length %}\\\n\t\\n### New Contributors\\n\n\t{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\\\n\t\t* @{{ contributor.username }} made their first contribution in #{{ contributor.pr_number }}\n\t{% endfor %}\\\n{% endif %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"@discordjs/voice@[0-9]*\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/voice/docs/README.md",
    "content": "## [View the documentation here.](https://discord.js.org/docs/packages/voice/main)\n"
  },
  {
    "path": "packages/voice/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/voice\",\n\t\"version\": \"0.19.2\",\n\t\"description\": \"Implementation of the Discord Voice API for Node.js\",\n\t\"scripts\": {\n\t\t\"build\": \"tsc --noEmit && tsup && node scripts/postbuild.mjs\",\n\t\t\"build:docs\": \"tsc -p tsconfig.docs.json\",\n\t\t\"test\": \"vitest run --config ../../vitest.config.ts\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src __tests__\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src __tests__\",\n\t\t\"fmt\": \"pnpm run format\",\n\t\t\"docs\": \"pnpm run build:docs && api-extractor run --local --minify && generate-split-documentation\",\n\t\t\"prepack\": \"pnpm run lint && pnpm run test && pnpm run build\",\n\t\t\"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/voice/*'\",\n\t\t\"release\": \"cliff-jumper\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"main\": \"./dist/index.js\",\n\t\"module\": \"./dist/index.mjs\",\n\t\"types\": \"./dist/index.d.ts\",\n\t\"directories\": {\n\t\t\"lib\": \"src\",\n\t\t\"test\": \"__tests__\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"Amish Shah <amishshah.2k@gmail.com>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"discord\",\n\t\t\"discord.js\",\n\t\t\"audio\",\n\t\t\"voice\",\n\t\t\"streaming\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/voice\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"@snazzah/davey\": \"^0.1.9\",\n\t\t\"@types/ws\": \"^8.18.1\",\n\t\t\"discord-api-types\": \"^0.38.41\",\n\t\t\"prism-media\": \"^1.3.5\",\n\t\t\"tslib\": \"^2.8.1\",\n\t\t\"ws\": \"^8.19.0\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@discordjs/api-extractor\": \"workspace:^\",\n\t\t\"@discordjs/opus\": \"^0.10.0\",\n\t\t\"@discordjs/scripts\": \"workspace:^\",\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@noble/ciphers\": \"^2.1.1\",\n\t\t\"@types/node\": \"^22.19.11\",\n\t\t\"@vitest/coverage-v8\": \"^4.0.18\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"esbuild-plugin-version-injector\": \"^1.2.1\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vitest\": \"^4.0.18\",\n\t\t\"vitest-websocket-mock\": \"^0.5.0\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/voice/scripts/postbuild.mjs",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nconst data = await readFile('./dist/index.mjs', 'utf8');\nawait writeFile(\n\t'./dist/index.mjs',\n\t`import { createRequire as topLevelCreateRequire } from \"module\";\nconst require = topLevelCreateRequire(import.meta.url);\n${data}`,\n);\n"
  },
  {
    "path": "packages/voice/src/DataStore.ts",
    "content": "import { GatewayOpcodes } from 'discord-api-types/v10';\nimport type { VoiceConnection } from './VoiceConnection';\nimport type { AudioPlayer } from './audio/index';\n\nexport interface JoinConfig {\n\tchannelId: string | null;\n\tgroup: string;\n\tguildId: string;\n\tselfDeaf: boolean;\n\tselfMute: boolean;\n}\n\n/**\n * Sends a voice state update to the main websocket shard of a guild, to indicate joining/leaving/moving across\n * voice channels.\n *\n * @param config - The configuration to use when joining the voice channel\n */\nexport function createJoinVoiceChannelPayload(config: JoinConfig) {\n\treturn {\n\t\top: GatewayOpcodes.VoiceStateUpdate,\n\t\t// eslint-disable-next-line id-length\n\t\td: {\n\t\t\tguild_id: config.guildId,\n\t\t\tchannel_id: config.channelId,\n\t\t\tself_deaf: config.selfDeaf,\n\t\t\tself_mute: config.selfMute,\n\t\t},\n\t};\n}\n\n// Voice Connections\nconst groups = new Map<string, Map<string, VoiceConnection>>();\ngroups.set('default', new Map());\n\nfunction getOrCreateGroup(group: string) {\n\tconst existing = groups.get(group);\n\tif (existing) return existing;\n\tconst map = new Map<string, VoiceConnection>();\n\tgroups.set(group, map);\n\treturn map;\n}\n\n/**\n * Retrieves the map of group names to maps of voice connections. By default, all voice connections\n * are created under the 'default' group.\n *\n * @returns The group map\n */\nexport function getGroups() {\n\treturn groups;\n}\n\n/**\n * Retrieves all the voice connections under the 'default' group.\n *\n * @param group - The group to look up\n * @returns The map of voice connections\n */\nexport function getVoiceConnections(group?: 'default'): Map<string, VoiceConnection>;\n\n/**\n * Retrieves all the voice connections under the given group name.\n *\n * @param group - The group to look up\n * @returns The map of voice connections\n */\nexport function getVoiceConnections(group: string): Map<string, VoiceConnection> | undefined;\n\n/**\n * Retrieves all the voice connections under the given group name. Defaults to the 'default' group.\n *\n * @param group - The group to look up\n * @returns The map of voice connections\n */\nexport function getVoiceConnections(group = 'default') {\n\treturn groups.get(group);\n}\n\n/**\n * Finds a voice connection with the given guild id and group. Defaults to the 'default' group.\n *\n * @param guildId - The guild id of the voice connection\n * @param group - the group that the voice connection was registered with\n * @returns The voice connection, if it exists\n */\nexport function getVoiceConnection(guildId: string, group = 'default') {\n\treturn getVoiceConnections(group)?.get(guildId);\n}\n\nexport function untrackVoiceConnection(voiceConnection: VoiceConnection) {\n\treturn getVoiceConnections(voiceConnection.joinConfig.group)?.delete(voiceConnection.joinConfig.guildId);\n}\n\nexport function trackVoiceConnection(voiceConnection: VoiceConnection) {\n\treturn getOrCreateGroup(voiceConnection.joinConfig.group).set(voiceConnection.joinConfig.guildId, voiceConnection);\n}\n\n// Audio Players\n\n// Each audio packet is 20ms long\nconst FRAME_LENGTH = 20;\n\nlet audioCycleInterval: NodeJS.Timeout | undefined;\nlet nextTime = -1;\n\n/**\n * A list of created audio players that are still active and haven't been destroyed.\n */\nconst audioPlayers: AudioPlayer[] = [];\n\n/**\n * Called roughly every 20 milliseconds. Dispatches audio from all players, and then gets the players to prepare\n * the next audio frame.\n */\nfunction audioCycleStep() {\n\tif (nextTime === -1) return;\n\n\tnextTime += FRAME_LENGTH;\n\tconst available = audioPlayers.filter((player) => player.checkPlayable());\n\n\tfor (const player of available) {\n\t\t// eslint-disable-next-line @typescript-eslint/dot-notation\n\t\tplayer['_stepDispatch']();\n\t}\n\n\tprepareNextAudioFrame(available);\n}\n\n/**\n * Recursively gets the players that have been passed as parameters to prepare audio frames that can be played\n * at the start of the next cycle.\n */\nfunction prepareNextAudioFrame(players: AudioPlayer[]) {\n\tconst nextPlayer = players.shift();\n\n\tif (!nextPlayer) {\n\t\tif (nextTime !== -1) {\n\t\t\taudioCycleInterval = setTimeout(() => audioCycleStep(), Math.max(1, nextTime - Date.now()));\n\t\t}\n\n\t\treturn;\n\t}\n\n\t// eslint-disable-next-line @typescript-eslint/dot-notation\n\tnextPlayer['_stepPrepare']();\n\n\t// setImmediate to avoid long audio player chains blocking other scheduled tasks\n\tsetImmediate(() => prepareNextAudioFrame(players));\n}\n\n/**\n * Checks whether or not the given audio player is being driven by the data store clock.\n *\n * @param target - The target to test for\n * @returns `true` if it is being tracked, `false` otherwise\n */\nexport function hasAudioPlayer(target: AudioPlayer) {\n\treturn audioPlayers.includes(target);\n}\n\n/**\n * Adds an audio player to the data store tracking list, if it isn't already there.\n *\n * @param player - The player to track\n */\nexport function addAudioPlayer(player: AudioPlayer) {\n\tif (hasAudioPlayer(player)) return player;\n\taudioPlayers.push(player);\n\tif (audioPlayers.length === 1) {\n\t\tnextTime = Date.now();\n\t\tsetImmediate(() => audioCycleStep());\n\t}\n\n\treturn player;\n}\n\n/**\n * Removes an audio player from the data store tracking list, if it is present there.\n */\nexport function deleteAudioPlayer(player: AudioPlayer) {\n\tconst index = audioPlayers.indexOf(player);\n\tif (index === -1) return;\n\taudioPlayers.splice(index, 1);\n\tif (audioPlayers.length === 0) {\n\t\tnextTime = -1;\n\t\tif (audioCycleInterval !== undefined) clearTimeout(audioCycleInterval);\n\t}\n}\n"
  },
  {
    "path": "packages/voice/src/VoiceConnection.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\nimport type { Buffer } from 'node:buffer';\nimport { EventEmitter } from 'node:events';\nimport type { GatewayVoiceServerUpdateDispatchData, GatewayVoiceStateUpdateDispatchData } from 'discord-api-types/v10';\nimport type { JoinConfig } from './DataStore';\nimport {\n\tgetVoiceConnection,\n\tcreateJoinVoiceChannelPayload,\n\ttrackVoiceConnection,\n\tuntrackVoiceConnection,\n} from './DataStore';\nimport type { AudioPlayer } from './audio/AudioPlayer';\nimport type { PlayerSubscription } from './audio/PlayerSubscription';\nimport type { VoiceWebSocket, VoiceUDPSocket } from './networking';\nimport { Networking, NetworkingStatusCode, type NetworkingState } from './networking/Networking';\nimport { VoiceReceiver } from './receive/index';\nimport type { DiscordGatewayAdapterImplementerMethods } from './util/adapter';\nimport { noop } from './util/util';\nimport type { CreateVoiceConnectionOptions } from './index';\n\n/**\n * The various status codes a voice connection can hold at any one time.\n */\nexport enum VoiceConnectionStatus {\n\t/**\n\t * The `VOICE_SERVER_UPDATE` and `VOICE_STATE_UPDATE` packets have been received, now attempting to establish a voice connection.\n\t */\n\tConnecting = 'connecting',\n\n\t/**\n\t * The voice connection has been destroyed and untracked, it cannot be reused.\n\t */\n\tDestroyed = 'destroyed',\n\n\t/**\n\t * The voice connection has either been severed or not established.\n\t */\n\tDisconnected = 'disconnected',\n\n\t/**\n\t * A voice connection has been established, and is ready to be used.\n\t */\n\tReady = 'ready',\n\n\t/**\n\t * Sending a packet to the main Discord gateway to indicate we want to change our voice state.\n\t */\n\tSignalling = 'signalling',\n}\n\n/**\n * The state that a VoiceConnection will be in when it is waiting to receive a VOICE_SERVER_UPDATE and\n * VOICE_STATE_UPDATE packet from Discord, provided by the adapter.\n */\nexport interface VoiceConnectionSignallingState {\n\tadapter: DiscordGatewayAdapterImplementerMethods;\n\tstatus: VoiceConnectionStatus.Signalling;\n\tsubscription?: PlayerSubscription | undefined;\n}\n\n/**\n * The reasons a voice connection can be in the disconnected state.\n */\nexport enum VoiceConnectionDisconnectReason {\n\t/**\n\t * When the WebSocket connection has been closed.\n\t */\n\tWebSocketClose,\n\n\t/**\n\t * When the adapter was unable to send a message requested by the VoiceConnection.\n\t */\n\tAdapterUnavailable,\n\n\t/**\n\t * When a VOICE_SERVER_UPDATE packet is received with a null endpoint, causing the connection to be severed.\n\t */\n\tEndpointRemoved,\n\n\t/**\n\t * When a manual disconnect was requested.\n\t */\n\tManual,\n}\n\n/**\n * The state that a VoiceConnection will be in when it is not connected to a Discord voice server nor is\n * it attempting to connect. You can manually attempt to reconnect using VoiceConnection#reconnect.\n */\nexport interface VoiceConnectionDisconnectedBaseState {\n\tadapter: DiscordGatewayAdapterImplementerMethods;\n\tstatus: VoiceConnectionStatus.Disconnected;\n\tsubscription?: PlayerSubscription | undefined;\n}\n\n/**\n * The state that a VoiceConnection will be in when it is not connected to a Discord voice server nor is\n * it attempting to connect. You can manually attempt to reconnect using VoiceConnection#reconnect.\n */\nexport interface VoiceConnectionDisconnectedOtherState extends VoiceConnectionDisconnectedBaseState {\n\treason: Exclude<VoiceConnectionDisconnectReason, VoiceConnectionDisconnectReason.WebSocketClose>;\n}\n\n/**\n * The state that a VoiceConnection will be in when its WebSocket connection was closed.\n * You can manually attempt to reconnect using VoiceConnection#reconnect.\n */\nexport interface VoiceConnectionDisconnectedWebSocketState extends VoiceConnectionDisconnectedBaseState {\n\t/**\n\t * The close code of the WebSocket connection to the Discord voice server.\n\t */\n\tcloseCode: number;\n\n\treason: VoiceConnectionDisconnectReason.WebSocketClose;\n}\n\n/**\n * The states that a VoiceConnection can be in when it is not connected to a Discord voice server nor is\n * it attempting to connect. You can manually attempt to connect using VoiceConnection#reconnect.\n */\nexport type VoiceConnectionDisconnectedState =\n\t| VoiceConnectionDisconnectedOtherState\n\t| VoiceConnectionDisconnectedWebSocketState;\n\n/**\n * The state that a VoiceConnection will be in when it is establishing a connection to a Discord\n * voice server.\n */\nexport interface VoiceConnectionConnectingState {\n\tadapter: DiscordGatewayAdapterImplementerMethods;\n\tnetworking: Networking;\n\tstatus: VoiceConnectionStatus.Connecting;\n\tsubscription?: PlayerSubscription | undefined;\n}\n\n/**\n * The state that a VoiceConnection will be in when it has an active connection to a Discord\n * voice server.\n */\nexport interface VoiceConnectionReadyState {\n\tadapter: DiscordGatewayAdapterImplementerMethods;\n\tnetworking: Networking;\n\tstatus: VoiceConnectionStatus.Ready;\n\tsubscription?: PlayerSubscription | undefined;\n}\n\n/**\n * The state that a VoiceConnection will be in when it has been permanently been destroyed by the\n * user and untracked by the library. It cannot be reconnected, instead, a new VoiceConnection\n * needs to be established.\n */\nexport interface VoiceConnectionDestroyedState {\n\tstatus: VoiceConnectionStatus.Destroyed;\n}\n\n/**\n * The various states that a voice connection can be in.\n */\nexport type VoiceConnectionState =\n\t| VoiceConnectionConnectingState\n\t| VoiceConnectionDestroyedState\n\t| VoiceConnectionDisconnectedState\n\t| VoiceConnectionReadyState\n\t| VoiceConnectionSignallingState;\n\nexport interface VoiceConnection extends EventEmitter {\n\t/**\n\t * Emitted when there is an error emitted from the voice connection\n\t *\n\t * @eventProperty\n\t */\n\ton(event: 'error', listener: (error: Error) => void): this;\n\t/**\n\t * Emitted debugging information about the voice connection\n\t *\n\t * @eventProperty\n\t */\n\ton(event: 'debug', listener: (message: string) => void): this;\n\t/**\n\t * Emitted when the state of the voice connection changes\n\t *\n\t * @eventProperty\n\t */\n\ton(event: 'stateChange', listener: (oldState: VoiceConnectionState, newState: VoiceConnectionState) => void): this;\n\t/**\n\t * Emitted when the end-to-end encrypted session has transitioned\n\t *\n\t * @eventProperty\n\t */\n\ton(event: 'transitioned', listener: (transitionId: number) => void): this;\n\t/**\n\t * Emitted when the state of the voice connection changes to a specific status\n\t *\n\t * @eventProperty\n\t */\n\ton<Event extends VoiceConnectionStatus>(\n\t\tevent: Event,\n\t\tlistener: (oldState: VoiceConnectionState, newState: VoiceConnectionState & { status: Event }) => void,\n\t): this;\n}\n\n/**\n * A connection to the voice server of a Guild, can be used to play audio in voice channels.\n */\nexport class VoiceConnection extends EventEmitter {\n\t/**\n\t * The number of consecutive rejoin attempts. Initially 0, and increments for each rejoin.\n\t * When a connection is successfully established, it resets to 0.\n\t */\n\tpublic rejoinAttempts: number;\n\n\t/**\n\t * The state of the voice connection.\n\t */\n\tprivate _state: VoiceConnectionState;\n\n\t/**\n\t * A configuration storing all the data needed to reconnect to a Guild's voice server.\n\t *\n\t * @internal\n\t */\n\tpublic readonly joinConfig: JoinConfig;\n\n\t/**\n\t * The two packets needed to successfully establish a voice connection. They are received\n\t * from the main Discord gateway after signalling to change the voice state.\n\t */\n\tprivate readonly packets: {\n\t\tserver: GatewayVoiceServerUpdateDispatchData | undefined;\n\t\tstate: GatewayVoiceStateUpdateDispatchData | undefined;\n\t};\n\n\t/**\n\t * The receiver of this voice connection. You should join the voice channel with `selfDeaf` set\n\t * to false for this feature to work properly.\n\t */\n\tpublic readonly receiver: VoiceReceiver;\n\n\t/**\n\t * The debug logger function, if debugging is enabled.\n\t */\n\tprivate readonly debug: ((message: string) => void) | null;\n\n\t/**\n\t * The options used to create this voice connection.\n\t */\n\tprivate readonly options: CreateVoiceConnectionOptions;\n\n\t/**\n\t * Creates a new voice connection.\n\t *\n\t * @param joinConfig - The data required to establish the voice connection\n\t * @param options - The options used to create this voice connection\n\t */\n\tpublic constructor(joinConfig: JoinConfig, options: CreateVoiceConnectionOptions) {\n\t\tsuper();\n\n\t\tthis.debug = options.debug ? (message: string) => this.emit('debug', message) : null;\n\t\tthis.rejoinAttempts = 0;\n\n\t\tthis.receiver = new VoiceReceiver(this);\n\n\t\tthis.onNetworkingClose = this.onNetworkingClose.bind(this);\n\t\tthis.onNetworkingStateChange = this.onNetworkingStateChange.bind(this);\n\t\tthis.onNetworkingError = this.onNetworkingError.bind(this);\n\t\tthis.onNetworkingDebug = this.onNetworkingDebug.bind(this);\n\t\tthis.onNetworkingTransitioned = this.onNetworkingTransitioned.bind(this);\n\n\t\tconst adapter = options.adapterCreator({\n\t\t\tonVoiceServerUpdate: (data) => this.addServerPacket(data),\n\t\t\tonVoiceStateUpdate: (data) => this.addStatePacket(data),\n\t\t\tdestroy: () => this.destroy(false),\n\t\t});\n\n\t\tthis._state = { status: VoiceConnectionStatus.Signalling, adapter };\n\n\t\tthis.packets = {\n\t\t\tserver: undefined,\n\t\t\tstate: undefined,\n\t\t};\n\n\t\tthis.joinConfig = joinConfig;\n\t\tthis.options = options;\n\t}\n\n\t/**\n\t * The current state of the voice connection.\n\t *\n\t * @remarks\n\t * The setter will perform clean-up operations where necessary.\n\t */\n\tpublic get state() {\n\t\treturn this._state;\n\t}\n\n\tpublic set state(newState: VoiceConnectionState) {\n\t\tconst oldState = this._state;\n\t\tconst oldNetworking = Reflect.get(oldState, 'networking') as Networking | undefined;\n\t\tconst newNetworking = Reflect.get(newState, 'networking') as Networking | undefined;\n\n\t\tconst oldSubscription = Reflect.get(oldState, 'subscription') as PlayerSubscription | undefined;\n\t\tconst newSubscription = Reflect.get(newState, 'subscription') as PlayerSubscription | undefined;\n\n\t\tif (oldNetworking !== newNetworking) {\n\t\t\tif (oldNetworking) {\n\t\t\t\toldNetworking.on('error', noop);\n\t\t\t\toldNetworking.off('debug', this.onNetworkingDebug);\n\t\t\t\toldNetworking.off('error', this.onNetworkingError);\n\t\t\t\toldNetworking.off('close', this.onNetworkingClose);\n\t\t\t\toldNetworking.off('stateChange', this.onNetworkingStateChange);\n\t\t\t\toldNetworking.off('transitioned', this.onNetworkingTransitioned);\n\t\t\t\toldNetworking.destroy();\n\t\t\t}\n\n\t\t\tif (newNetworking) this.updateReceiveBindings(newNetworking.state, oldNetworking?.state);\n\t\t}\n\n\t\tif (newState.status === VoiceConnectionStatus.Ready) {\n\t\t\tthis.rejoinAttempts = 0;\n\t\t} else if (newState.status === VoiceConnectionStatus.Destroyed) {\n\t\t\tfor (const stream of this.receiver.subscriptions.values()) {\n\t\t\t\tif (!stream.destroyed) stream.destroy();\n\t\t\t}\n\t\t}\n\n\t\t// If destroyed, the adapter can also be destroyed so it can be cleaned up by the user\n\t\tif (oldState.status !== VoiceConnectionStatus.Destroyed && newState.status === VoiceConnectionStatus.Destroyed) {\n\t\t\toldState.adapter.destroy();\n\t\t}\n\n\t\tthis._state = newState;\n\n\t\tif (oldSubscription && oldSubscription !== newSubscription) {\n\t\t\toldSubscription.unsubscribe();\n\t\t}\n\n\t\tthis.emit('stateChange', oldState, newState);\n\t\tif (oldState.status !== newState.status) {\n\t\t\tthis.emit(newState.status, oldState, newState as any);\n\t\t}\n\t}\n\n\t/**\n\t * Registers a `VOICE_SERVER_UPDATE` packet to the voice connection. This will cause it to reconnect using the\n\t * new data provided in the packet.\n\t *\n\t * @param packet - The received `VOICE_SERVER_UPDATE` packet\n\t */\n\tprivate addServerPacket(packet: GatewayVoiceServerUpdateDispatchData) {\n\t\tthis.packets.server = packet;\n\t\tif (packet.endpoint) {\n\t\t\tthis.configureNetworking();\n\t\t} else if (this.state.status !== VoiceConnectionStatus.Destroyed) {\n\t\t\tthis.state = {\n\t\t\t\t...this.state,\n\t\t\t\tstatus: VoiceConnectionStatus.Disconnected,\n\t\t\t\treason: VoiceConnectionDisconnectReason.EndpointRemoved,\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Registers a `VOICE_STATE_UPDATE` packet to the voice connection. Most importantly, it stores the id of the\n\t * channel that the client is connected to.\n\t *\n\t * @param packet - The received `VOICE_STATE_UPDATE` packet\n\t */\n\tprivate addStatePacket(packet: GatewayVoiceStateUpdateDispatchData) {\n\t\tthis.packets.state = packet;\n\n\t\tif (packet.self_deaf !== undefined) this.joinConfig.selfDeaf = packet.self_deaf;\n\t\tif (packet.self_mute !== undefined) this.joinConfig.selfMute = packet.self_mute;\n\t\tif (packet.channel_id) this.joinConfig.channelId = packet.channel_id;\n\t\t/*\n\t\t\tthe channel_id being null doesn't necessarily mean it was intended for the client to leave the voice channel\n\t\t\tas it may have disconnected due to network failure. This will be gracefully handled once the voice websocket\n\t\t\tdies, and then it is up to the user to decide how they wish to handle this.\n\t\t*/\n\t}\n\n\t/**\n\t * Called when the networking state changes, and the new ws/udp packet/message handlers need to be rebound\n\t * to the new instances.\n\t *\n\t * @param newState - The new networking state\n\t * @param oldState - The old networking state, if there is one\n\t */\n\tprivate updateReceiveBindings(newState: NetworkingState, oldState?: NetworkingState) {\n\t\tconst oldWs = Reflect.get(oldState ?? {}, 'ws') as VoiceWebSocket | undefined;\n\t\tconst newWs = Reflect.get(newState, 'ws') as VoiceWebSocket | undefined;\n\t\tconst oldUdp = Reflect.get(oldState ?? {}, 'udp') as VoiceUDPSocket | undefined;\n\t\tconst newUdp = Reflect.get(newState, 'udp') as VoiceUDPSocket | undefined;\n\n\t\tif (oldWs !== newWs) {\n\t\t\toldWs?.off('packet', this.receiver.onWsPacket);\n\t\t\tnewWs?.on('packet', this.receiver.onWsPacket);\n\t\t}\n\n\t\tif (oldUdp !== newUdp) {\n\t\t\toldUdp?.off('message', this.receiver.onUdpMessage);\n\t\t\tnewUdp?.on('message', this.receiver.onUdpMessage);\n\t\t}\n\n\t\tthis.receiver.connectionData = Reflect.get(newState, 'connectionData') ?? {};\n\t}\n\n\t/**\n\t * Attempts to configure a networking instance for this voice connection using the received packets.\n\t * Both packets are required, and any existing networking instance will be destroyed.\n\t *\n\t * @remarks\n\t * This is called when the voice server of the connection changes, e.g. if the bot is moved into a\n\t * different channel in the same guild but has a different voice server. In this instance, the connection\n\t * needs to be re-established to the new voice server.\n\t *\n\t * The connection will transition to the Connecting state when this is called.\n\t */\n\tpublic configureNetworking() {\n\t\tconst { server, state } = this.packets;\n\t\tif (!server || !state || this.state.status === VoiceConnectionStatus.Destroyed || !server.endpoint) return;\n\n\t\tconst networking = new Networking(\n\t\t\t{\n\t\t\t\tendpoint: server.endpoint,\n\t\t\t\tserverId: server.guild_id,\n\t\t\t\ttoken: server.token,\n\t\t\t\tsessionId: state.session_id,\n\t\t\t\tuserId: state.user_id,\n\t\t\t\tchannelId: state.channel_id!,\n\t\t\t},\n\t\t\t{\n\t\t\t\tdebug: Boolean(this.debug),\n\t\t\t\tdaveEncryption: this.options.daveEncryption ?? true,\n\t\t\t\tdecryptionFailureTolerance: this.options.decryptionFailureTolerance,\n\t\t\t},\n\t\t);\n\n\t\tnetworking.once('close', this.onNetworkingClose);\n\t\tnetworking.on('stateChange', this.onNetworkingStateChange);\n\t\tnetworking.on('error', this.onNetworkingError);\n\t\tnetworking.on('debug', this.onNetworkingDebug);\n\t\tnetworking.on('transitioned', this.onNetworkingTransitioned);\n\n\t\tthis.state = {\n\t\t\t...this.state,\n\t\t\tstatus: VoiceConnectionStatus.Connecting,\n\t\t\tnetworking,\n\t\t};\n\t}\n\n\t/**\n\t * Called when the networking instance for this connection closes. If the close code is 4014 (do not reconnect),\n\t * the voice connection will transition to the Disconnected state which will store the close code. You can\n\t * decide whether or not to reconnect when this occurs by listening for the state change and calling reconnect().\n\t *\n\t * @remarks\n\t * If the close code was anything other than 4014, it is likely that the closing was not intended, and so the\n\t * VoiceConnection will signal to Discord that it would like to rejoin the channel. This automatically attempts\n\t * to re-establish the connection. This would be seen as a transition from the Ready state to the Signalling state.\n\t * @param code - The close code\n\t */\n\tprivate onNetworkingClose(code: number) {\n\t\tif (this.state.status === VoiceConnectionStatus.Destroyed) return;\n\t\t// If networking closes, try to connect to the voice channel again.\n\t\tif (code === 4_014) {\n\t\t\t// Disconnected - networking is already destroyed here\n\t\t\tthis.state = {\n\t\t\t\t...this.state,\n\t\t\t\tstatus: VoiceConnectionStatus.Disconnected,\n\t\t\t\treason: VoiceConnectionDisconnectReason.WebSocketClose,\n\t\t\t\tcloseCode: code,\n\t\t\t};\n\t\t} else {\n\t\t\tthis.state = {\n\t\t\t\t...this.state,\n\t\t\t\tstatus: VoiceConnectionStatus.Signalling,\n\t\t\t};\n\t\t\tthis.rejoinAttempts++;\n\t\t\tif (!this.state.adapter.sendPayload(createJoinVoiceChannelPayload(this.joinConfig))) {\n\t\t\t\tthis.state = {\n\t\t\t\t\t...this.state,\n\t\t\t\t\tstatus: VoiceConnectionStatus.Disconnected,\n\t\t\t\t\treason: VoiceConnectionDisconnectReason.AdapterUnavailable,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Called when the state of the networking instance changes. This is used to derive the state of the voice connection.\n\t *\n\t * @param oldState - The previous state\n\t * @param newState - The new state\n\t */\n\tprivate onNetworkingStateChange(oldState: NetworkingState, newState: NetworkingState) {\n\t\tthis.updateReceiveBindings(newState, oldState);\n\t\tif (oldState.code === newState.code) return;\n\t\tif (this.state.status !== VoiceConnectionStatus.Connecting && this.state.status !== VoiceConnectionStatus.Ready)\n\t\t\treturn;\n\n\t\tif (newState.code === NetworkingStatusCode.Ready) {\n\t\t\tthis.state = {\n\t\t\t\t...this.state,\n\t\t\t\tstatus: VoiceConnectionStatus.Ready,\n\t\t\t};\n\t\t} else if (newState.code !== NetworkingStatusCode.Closed) {\n\t\t\tthis.state = {\n\t\t\t\t...this.state,\n\t\t\t\tstatus: VoiceConnectionStatus.Connecting,\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Propagates errors from the underlying network instance.\n\t *\n\t * @param error - The error to propagate\n\t */\n\tprivate onNetworkingError(error: Error) {\n\t\tthis.emit('error', error);\n\t}\n\n\t/**\n\t * Propagates debug messages from the underlying network instance.\n\t *\n\t * @param message - The debug message to propagate\n\t */\n\tprivate onNetworkingDebug(message: string) {\n\t\tthis.debug?.(`[NW] ${message}`);\n\t}\n\n\t/**\n\t * Propagates transitions from the underlying network instance.\n\t *\n\t * @param transitionId - The transition id\n\t */\n\tprivate onNetworkingTransitioned(transitionId: number) {\n\t\tthis.emit('transitioned', transitionId);\n\t}\n\n\t/**\n\t * Prepares an audio packet for dispatch.\n\t *\n\t * @param buffer - The Opus packet to prepare\n\t */\n\tpublic prepareAudioPacket(buffer: Buffer) {\n\t\tconst state = this.state;\n\t\tif (state.status !== VoiceConnectionStatus.Ready) return;\n\t\treturn state.networking.prepareAudioPacket(buffer);\n\t}\n\n\t/**\n\t * Dispatches the previously prepared audio packet (if any)\n\t */\n\tpublic dispatchAudio() {\n\t\tconst state = this.state;\n\t\tif (state.status !== VoiceConnectionStatus.Ready) return;\n\t\treturn state.networking.dispatchAudio();\n\t}\n\n\t/**\n\t * Prepares an audio packet and dispatches it immediately.\n\t *\n\t * @param buffer - The Opus packet to play\n\t */\n\tpublic playOpusPacket(buffer: Buffer) {\n\t\tconst state = this.state;\n\t\tif (state.status !== VoiceConnectionStatus.Ready) return;\n\t\tstate.networking.prepareAudioPacket(buffer);\n\t\treturn state.networking.dispatchAudio();\n\t}\n\n\t/**\n\t * Destroys the VoiceConnection, preventing it from connecting to voice again.\n\t * This method should be called when you no longer require the VoiceConnection to\n\t * prevent memory leaks.\n\t *\n\t * @param adapterAvailable - Whether the adapter can be used\n\t */\n\tpublic destroy(adapterAvailable = true) {\n\t\tif (this.state.status === VoiceConnectionStatus.Destroyed) {\n\t\t\tthrow new Error('Cannot destroy VoiceConnection - it has already been destroyed');\n\t\t}\n\n\t\tif (getVoiceConnection(this.joinConfig.guildId, this.joinConfig.group) === this) {\n\t\t\tuntrackVoiceConnection(this);\n\t\t}\n\n\t\tif (adapterAvailable) {\n\t\t\tthis.state.adapter.sendPayload(createJoinVoiceChannelPayload({ ...this.joinConfig, channelId: null }));\n\t\t}\n\n\t\tthis.state = {\n\t\t\tstatus: VoiceConnectionStatus.Destroyed,\n\t\t};\n\t}\n\n\t/**\n\t * Disconnects the VoiceConnection, allowing the possibility of rejoining later on.\n\t *\n\t * @returns `true` if the connection was successfully disconnected\n\t */\n\tpublic disconnect() {\n\t\tif (\n\t\t\tthis.state.status === VoiceConnectionStatus.Destroyed ||\n\t\t\tthis.state.status === VoiceConnectionStatus.Signalling\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.joinConfig.channelId = null;\n\t\tif (!this.state.adapter.sendPayload(createJoinVoiceChannelPayload(this.joinConfig))) {\n\t\t\tthis.state = {\n\t\t\t\tadapter: this.state.adapter,\n\t\t\t\tsubscription: this.state.subscription,\n\t\t\t\tstatus: VoiceConnectionStatus.Disconnected,\n\t\t\t\treason: VoiceConnectionDisconnectReason.AdapterUnavailable,\n\t\t\t};\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.state = {\n\t\t\tadapter: this.state.adapter,\n\t\t\treason: VoiceConnectionDisconnectReason.Manual,\n\t\t\tstatus: VoiceConnectionStatus.Disconnected,\n\t\t};\n\t\treturn true;\n\t}\n\n\t/**\n\t * Attempts to rejoin (better explanation soon:tm:)\n\t *\n\t * @remarks\n\t * Calling this method successfully will automatically increment the `rejoinAttempts` counter,\n\t * which you can use to inform whether or not you'd like to keep attempting to reconnect your\n\t * voice connection.\n\t *\n\t * A state transition from Disconnected to Signalling will be observed when this is called.\n\t */\n\tpublic rejoin(joinConfig?: Omit<JoinConfig, 'group' | 'guildId'>) {\n\t\tif (this.state.status === VoiceConnectionStatus.Destroyed) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst notReady = this.state.status !== VoiceConnectionStatus.Ready;\n\n\t\tif (notReady) this.rejoinAttempts++;\n\t\tObject.assign(this.joinConfig, joinConfig);\n\t\tif (this.state.adapter.sendPayload(createJoinVoiceChannelPayload(this.joinConfig))) {\n\t\t\tif (notReady) {\n\t\t\t\tthis.state = {\n\t\t\t\t\t...this.state,\n\t\t\t\t\tstatus: VoiceConnectionStatus.Signalling,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tthis.state = {\n\t\t\tadapter: this.state.adapter,\n\t\t\tsubscription: this.state.subscription,\n\t\t\tstatus: VoiceConnectionStatus.Disconnected,\n\t\t\treason: VoiceConnectionDisconnectReason.AdapterUnavailable,\n\t\t};\n\t\treturn false;\n\t}\n\n\t/**\n\t * Updates the speaking status of the voice connection. This is used when audio players are done playing audio,\n\t * and need to signal that the connection is no longer playing audio.\n\t *\n\t * @param enabled - Whether or not to show as speaking\n\t */\n\tpublic setSpeaking(enabled: boolean) {\n\t\tif (this.state.status !== VoiceConnectionStatus.Ready) return false;\n\t\t// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression\n\t\treturn this.state.networking.setSpeaking(enabled);\n\t}\n\n\t/**\n\t * Subscribes to an audio player, allowing the player to play audio on this voice connection.\n\t *\n\t * @param player - The audio player to subscribe to\n\t * @returns The created subscription\n\t */\n\tpublic subscribe(player: AudioPlayer) {\n\t\tif (this.state.status === VoiceConnectionStatus.Destroyed) return;\n\n\t\t// eslint-disable-next-line @typescript-eslint/dot-notation\n\t\tconst subscription = player['subscribe'](this);\n\n\t\tthis.state = {\n\t\t\t...this.state,\n\t\t\tsubscription,\n\t\t};\n\n\t\treturn subscription;\n\t}\n\n\t/**\n\t * The latest ping (in milliseconds) for the WebSocket connection and audio playback for this voice\n\t * connection, if this data is available.\n\t *\n\t * @remarks\n\t * For this data to be available, the VoiceConnection must be in the Ready state, and its underlying\n\t * WebSocket connection and UDP socket must have had at least one ping-pong exchange.\n\t */\n\tpublic get ping() {\n\t\tif (\n\t\t\tthis.state.status === VoiceConnectionStatus.Ready &&\n\t\t\tthis.state.networking.state.code === NetworkingStatusCode.Ready\n\t\t) {\n\t\t\treturn {\n\t\t\t\tws: this.state.networking.state.ws.ping,\n\t\t\t\tudp: this.state.networking.state.udp.ping,\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tws: undefined,\n\t\t\tudp: undefined,\n\t\t};\n\t}\n\n\t/**\n\t * The current voice privacy code of the encrypted session.\n\t *\n\t * @remarks\n\t * For this data to be available, the VoiceConnection must be in the Ready state,\n\t * and the connection would have to be end-to-end encrypted.\n\t */\n\tpublic get voicePrivacyCode() {\n\t\tif (\n\t\t\tthis.state.status === VoiceConnectionStatus.Ready &&\n\t\t\tthis.state.networking.state.code === NetworkingStatusCode.Ready\n\t\t) {\n\t\t\treturn this.state.networking.state.dave?.voicePrivacyCode ?? undefined;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Gets the verification code for a user in the session.\n\t *\n\t * @throws Will throw if end-to-end encryption is not on or if the user id provided is not in the session.\n\t */\n\tpublic async getVerificationCode(userId: string): Promise<string> {\n\t\tif (\n\t\t\tthis.state.status === VoiceConnectionStatus.Ready &&\n\t\t\tthis.state.networking.state.code === NetworkingStatusCode.Ready &&\n\t\t\tthis.state.networking.state.dave\n\t\t) {\n\t\t\treturn this.state.networking.state.dave.getVerificationCode(userId);\n\t\t}\n\n\t\tthrow new Error('Session not available');\n\t}\n\n\t/**\n\t * Called when a subscription of this voice connection to an audio player is removed.\n\t *\n\t * @param subscription - The removed subscription\n\t */\n\tprotected onSubscriptionRemoved(subscription: PlayerSubscription) {\n\t\tif (this.state.status !== VoiceConnectionStatus.Destroyed && this.state.subscription === subscription) {\n\t\t\tthis.state = {\n\t\t\t\t...this.state,\n\t\t\t\tsubscription: undefined,\n\t\t\t};\n\t\t}\n\t}\n}\n\n/**\n * Creates a new voice connection.\n *\n * @param joinConfig - The data required to establish the voice connection\n * @param options - The options to use when joining the voice channel\n */\nexport function createVoiceConnection(joinConfig: JoinConfig, options: CreateVoiceConnectionOptions) {\n\tconst payload = createJoinVoiceChannelPayload(joinConfig);\n\tconst existing = getVoiceConnection(joinConfig.guildId, joinConfig.group);\n\tif (existing && existing.state.status !== VoiceConnectionStatus.Destroyed) {\n\t\tif (existing.state.status === VoiceConnectionStatus.Disconnected) {\n\t\t\texisting.rejoin({\n\t\t\t\tchannelId: joinConfig.channelId,\n\t\t\t\tselfDeaf: joinConfig.selfDeaf,\n\t\t\t\tselfMute: joinConfig.selfMute,\n\t\t\t});\n\t\t} else if (!existing.state.adapter.sendPayload(payload)) {\n\t\t\texisting.state = {\n\t\t\t\t...existing.state,\n\t\t\t\tstatus: VoiceConnectionStatus.Disconnected,\n\t\t\t\treason: VoiceConnectionDisconnectReason.AdapterUnavailable,\n\t\t\t};\n\t\t}\n\n\t\treturn existing;\n\t}\n\n\tconst voiceConnection = new VoiceConnection(joinConfig, options);\n\ttrackVoiceConnection(voiceConnection);\n\tif (\n\t\tvoiceConnection.state.status !== VoiceConnectionStatus.Destroyed &&\n\t\t!voiceConnection.state.adapter.sendPayload(payload)\n\t) {\n\t\tvoiceConnection.state = {\n\t\t\t...voiceConnection.state,\n\t\t\tstatus: VoiceConnectionStatus.Disconnected,\n\t\t\treason: VoiceConnectionDisconnectReason.AdapterUnavailable,\n\t\t};\n\t}\n\n\treturn voiceConnection;\n}\n"
  },
  {
    "path": "packages/voice/src/audio/AudioPlayer.ts",
    "content": "/* eslint-disable @typescript-eslint/prefer-ts-expect-error, @typescript-eslint/method-signature-style */\nimport { Buffer } from 'node:buffer';\nimport { EventEmitter } from 'node:events';\nimport { addAudioPlayer, deleteAudioPlayer } from '../DataStore';\nimport { VoiceConnectionStatus, type VoiceConnection } from '../VoiceConnection';\nimport { noop } from '../util/util';\nimport { AudioPlayerError } from './AudioPlayerError';\nimport type { AudioResource } from './AudioResource';\nimport { PlayerSubscription } from './PlayerSubscription';\n\n// The Opus \"silent\" frame\nexport const SILENCE_FRAME = Buffer.from([0xf8, 0xff, 0xfe]);\n\n/**\n * Describes the behavior of the player when an audio packet is played but there are no available\n * voice connections to play to.\n */\nexport enum NoSubscriberBehavior {\n\t/**\n\t * Pauses playing the stream until a voice connection becomes available.\n\t */\n\tPause = 'pause',\n\n\t/**\n\t * Continues to play through the resource regardless.\n\t */\n\tPlay = 'play',\n\n\t/**\n\t * The player stops and enters the Idle state.\n\t */\n\tStop = 'stop',\n}\n\nexport enum AudioPlayerStatus {\n\t/**\n\t * When the player has paused itself. Only possible with the \"pause\" no subscriber behavior.\n\t */\n\tAutoPaused = 'autopaused',\n\n\t/**\n\t * When the player is waiting for an audio resource to become readable before transitioning to Playing.\n\t */\n\tBuffering = 'buffering',\n\n\t/**\n\t * When there is currently no resource for the player to be playing.\n\t */\n\tIdle = 'idle',\n\n\t/**\n\t * When the player has been manually paused.\n\t */\n\tPaused = 'paused',\n\n\t/**\n\t * When the player is actively playing an audio resource.\n\t */\n\tPlaying = 'playing',\n}\n\n/**\n * Options that can be passed when creating an audio player, used to specify its behavior.\n */\nexport interface CreateAudioPlayerOptions {\n\tbehaviors?: {\n\t\tmaxMissedFrames?: number;\n\t\tnoSubscriber?: NoSubscriberBehavior;\n\t};\n\tdebug?: boolean;\n}\n\n/**\n * The state that an AudioPlayer is in when it has no resource to play. This is the starting state.\n */\nexport interface AudioPlayerIdleState {\n\tstatus: AudioPlayerStatus.Idle;\n}\n\n/**\n * The state that an AudioPlayer is in when it is waiting for a resource to become readable. Once this\n * happens, the AudioPlayer will enter the Playing state. If the resource ends/errors before this, then\n * it will re-enter the Idle state.\n */\nexport interface AudioPlayerBufferingState {\n\tonFailureCallback: () => void;\n\tonReadableCallback: () => void;\n\tonStreamError: (error: Error) => void;\n\t/**\n\t * The resource that the AudioPlayer is waiting for\n\t */\n\tresource: AudioResource;\n\tstatus: AudioPlayerStatus.Buffering;\n}\n\n/**\n * The state that an AudioPlayer is in when it is actively playing an AudioResource. When playback ends,\n * it will enter the Idle state.\n */\nexport interface AudioPlayerPlayingState {\n\t/**\n\t * The number of consecutive times that the audio resource has been unable to provide an Opus frame.\n\t */\n\tmissedFrames: number;\n\tonStreamError: (error: Error) => void;\n\n\t/**\n\t * The playback duration in milliseconds of the current audio resource. This includes filler silence packets\n\t * that have been played when the resource was buffering.\n\t */\n\tplaybackDuration: number;\n\n\t/**\n\t * The resource that is being played.\n\t */\n\tresource: AudioResource;\n\n\tstatus: AudioPlayerStatus.Playing;\n}\n\n/**\n * The state that an AudioPlayer is in when it has either been explicitly paused by the user, or done\n * automatically by the AudioPlayer itself if there are no available subscribers.\n */\nexport interface AudioPlayerPausedState {\n\tonStreamError: (error: Error) => void;\n\t/**\n\t * The playback duration in milliseconds of the current audio resource. This includes filler silence packets\n\t * that have been played when the resource was buffering.\n\t */\n\tplaybackDuration: number;\n\n\t/**\n\t * The current resource of the audio player.\n\t */\n\tresource: AudioResource;\n\n\t/**\n\t * How many silence packets still need to be played to avoid audio interpolation due to the stream suddenly pausing.\n\t */\n\tsilencePacketsRemaining: number;\n\n\tstatus: AudioPlayerStatus.AutoPaused | AudioPlayerStatus.Paused;\n}\n\n/**\n * The various states that the player can be in.\n */\nexport type AudioPlayerState =\n\t| AudioPlayerBufferingState\n\t| AudioPlayerIdleState\n\t| AudioPlayerPausedState\n\t| AudioPlayerPlayingState;\n\nexport interface AudioPlayer extends EventEmitter {\n\t/**\n\t * Emitted when there is an error emitted from the audio resource played by the audio player\n\t *\n\t * @eventProperty\n\t */\n\ton(event: 'error', listener: (error: AudioPlayerError) => void): this;\n\t/**\n\t * Emitted debugging information about the audio player\n\t *\n\t * @eventProperty\n\t */\n\ton(event: 'debug', listener: (message: string) => void): this;\n\t/**\n\t * Emitted when the state of the audio player changes\n\t *\n\t * @eventProperty\n\t */\n\ton(event: 'stateChange', listener: (oldState: AudioPlayerState, newState: AudioPlayerState) => void): this;\n\t/**\n\t * Emitted when the audio player is subscribed to a voice connection\n\t *\n\t * @eventProperty\n\t */\n\ton(event: 'subscribe' | 'unsubscribe', listener: (subscription: PlayerSubscription) => void): this;\n\t/**\n\t * Emitted when the status of state changes to a specific status\n\t *\n\t * @eventProperty\n\t */\n\ton<Event extends AudioPlayerStatus>(\n\t\tevent: Event,\n\t\tlistener: (oldState: AudioPlayerState, newState: AudioPlayerState & { status: Event }) => void,\n\t): this;\n}\n\n/**\n * Stringifies an AudioPlayerState instance.\n *\n * @param state - The state to stringify\n */\nfunction stringifyState(state: AudioPlayerState) {\n\treturn JSON.stringify({\n\t\t...state,\n\t\tresource: Reflect.has(state, 'resource'),\n\t\tstepTimeout: Reflect.has(state, 'stepTimeout'),\n\t});\n}\n\n/**\n * Used to play audio resources (i.e. tracks, streams) to voice connections.\n *\n * @remarks\n * Audio players are designed to be re-used - even if a resource has finished playing, the player itself\n * can still be used.\n *\n * The AudioPlayer drives the timing of playback, and therefore is unaffected by voice connections\n * becoming unavailable. Its behavior in these scenarios can be configured.\n */\nexport class AudioPlayer extends EventEmitter {\n\t/**\n\t * The state that the AudioPlayer is in.\n\t */\n\tprivate _state: AudioPlayerState;\n\n\t/**\n\t * A list of VoiceConnections that are registered to this AudioPlayer. The player will attempt to play audio\n\t * to the streams in this list.\n\t */\n\tprivate readonly subscribers: PlayerSubscription[] = [];\n\n\t/**\n\t * The behavior that the player should follow when it enters certain situations.\n\t */\n\tprivate readonly behaviors: {\n\t\tmaxMissedFrames: number;\n\t\tnoSubscriber: NoSubscriberBehavior;\n\t};\n\n\t/**\n\t * The debug logger function, if debugging is enabled.\n\t */\n\tprivate readonly debug: ((message: string) => void) | null;\n\n\t/**\n\t * Creates a new AudioPlayer.\n\t */\n\tpublic constructor(options: CreateAudioPlayerOptions = {}) {\n\t\tsuper();\n\t\tthis._state = { status: AudioPlayerStatus.Idle };\n\t\tthis.behaviors = {\n\t\t\tnoSubscriber: NoSubscriberBehavior.Pause,\n\t\t\tmaxMissedFrames: 5,\n\t\t\t...options.behaviors,\n\t\t};\n\t\tthis.debug = options.debug === false ? null : (message: string) => this.emit('debug', message);\n\t}\n\n\t/**\n\t * A list of subscribed voice connections that can currently receive audio to play.\n\t */\n\tpublic get playable() {\n\t\treturn this.subscribers\n\t\t\t.filter(({ connection }) => connection.state.status === VoiceConnectionStatus.Ready)\n\t\t\t.map(({ connection }) => connection);\n\t}\n\n\t/**\n\t * Subscribes a VoiceConnection to the audio player's play list. If the VoiceConnection is already subscribed,\n\t * then the existing subscription is used.\n\t *\n\t * @remarks\n\t * This method should not be directly called. Instead, use VoiceConnection#subscribe.\n\t * @param connection - The connection to subscribe\n\t * @returns The new subscription if the voice connection is not yet subscribed, otherwise the existing subscription\n\t */\n\t// @ts-ignore\n\tprivate subscribe(connection: VoiceConnection) {\n\t\tconst existingSubscription = this.subscribers.find((subscription) => subscription.connection === connection);\n\t\tif (!existingSubscription) {\n\t\t\tconst subscription = new PlayerSubscription(connection, this);\n\t\t\tthis.subscribers.push(subscription);\n\t\t\tsetImmediate(() => this.emit('subscribe', subscription));\n\t\t\treturn subscription;\n\t\t}\n\n\t\treturn existingSubscription;\n\t}\n\n\t/**\n\t * Unsubscribes a subscription - i.e. removes a voice connection from the play list of the audio player.\n\t *\n\t * @remarks\n\t * This method should not be directly called. Instead, use PlayerSubscription#unsubscribe.\n\t * @param subscription - The subscription to remove\n\t * @returns Whether or not the subscription existed on the player and was removed\n\t */\n\t// @ts-ignore\n\tprivate unsubscribe(subscription: PlayerSubscription) {\n\t\tconst index = this.subscribers.indexOf(subscription);\n\t\tconst exists = index !== -1;\n\t\tif (exists) {\n\t\t\tthis.subscribers.splice(index, 1);\n\t\t\tsubscription.connection.setSpeaking(false);\n\t\t\tthis.emit('unsubscribe', subscription);\n\t\t}\n\n\t\treturn exists;\n\t}\n\n\t/**\n\t * The state that the player is in.\n\t *\n\t * @remarks\n\t * The setter will perform clean-up operations where necessary.\n\t */\n\tpublic get state() {\n\t\treturn this._state;\n\t}\n\n\tpublic set state(newState: AudioPlayerState) {\n\t\tconst oldState = this._state;\n\t\tconst newResource = Reflect.get(newState, 'resource') as AudioResource | undefined;\n\n\t\tif (oldState.status !== AudioPlayerStatus.Idle && oldState.resource !== newResource) {\n\t\t\toldState.resource.playStream.on('error', noop);\n\t\t\toldState.resource.playStream.off('error', oldState.onStreamError);\n\t\t\toldState.resource.audioPlayer = undefined;\n\t\t\toldState.resource.playStream.destroy();\n\t\t\toldState.resource.playStream.read(); // required to ensure buffered data is drained, prevents memory leak\n\t\t}\n\n\t\t// When leaving the Buffering state (or buffering a new resource), then remove the event listeners from it\n\t\tif (\n\t\t\toldState.status === AudioPlayerStatus.Buffering &&\n\t\t\t(newState.status !== AudioPlayerStatus.Buffering || newState.resource !== oldState.resource)\n\t\t) {\n\t\t\toldState.resource.playStream.off('end', oldState.onFailureCallback);\n\t\t\toldState.resource.playStream.off('close', oldState.onFailureCallback);\n\t\t\toldState.resource.playStream.off('finish', oldState.onFailureCallback);\n\t\t\toldState.resource.playStream.off('readable', oldState.onReadableCallback);\n\t\t}\n\n\t\t// transitioning into an idle should ensure that connections stop speaking\n\t\tif (newState.status === AudioPlayerStatus.Idle) {\n\t\t\tthis._signalStopSpeaking();\n\t\t\tdeleteAudioPlayer(this);\n\t\t}\n\n\t\t// attach to the global audio player timer\n\t\tif (newResource) {\n\t\t\taddAudioPlayer(this);\n\t\t}\n\n\t\t// playing -> playing state changes should still transition if a resource changed (seems like it would be useful!)\n\t\tconst didChangeResources =\n\t\t\toldState.status !== AudioPlayerStatus.Idle &&\n\t\t\tnewState.status === AudioPlayerStatus.Playing &&\n\t\t\toldState.resource !== newState.resource;\n\n\t\tthis._state = newState;\n\n\t\tthis.emit('stateChange', oldState, this._state);\n\t\tif (oldState.status !== newState.status || didChangeResources) {\n\t\t\tthis.emit(newState.status, oldState, this._state as any);\n\t\t}\n\n\t\tthis.debug?.(`state change:\\nfrom ${stringifyState(oldState)}\\nto ${stringifyState(newState)}`);\n\t}\n\n\t/**\n\t * Plays a new resource on the player. If the player is already playing a resource, the existing resource is destroyed\n\t * (it cannot be reused, even in another player) and is replaced with the new resource.\n\t *\n\t * @remarks\n\t * The player will transition to the Playing state once playback begins, and will return to the Idle state once\n\t * playback is ended.\n\t *\n\t * If the player was previously playing a resource and this method is called, the player will not transition to the\n\t * Idle state during the swap over.\n\t * @param resource - The resource to play\n\t * @throws Will throw if attempting to play an audio resource that has already ended, or is being played by another player\n\t */\n\tpublic play<Metadata>(resource: AudioResource<Metadata>) {\n\t\tif (resource.ended) {\n\t\t\tthrow new Error('Cannot play a resource that has already ended.');\n\t\t}\n\n\t\tif (resource.audioPlayer) {\n\t\t\tif (resource.audioPlayer === this) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthrow new Error('Resource is already being played by another audio player.');\n\t\t}\n\n\t\tresource.audioPlayer = this;\n\n\t\t// Attach error listeners to the stream that will propagate the error and then return to the Idle\n\t\t// state if the resource is still being used.\n\t\tconst onStreamError = (error: Error) => {\n\t\t\tif (this.state.status !== AudioPlayerStatus.Idle) {\n\t\t\t\tthis.emit('error', new AudioPlayerError(error, this.state.resource));\n\t\t\t}\n\n\t\t\tif (this.state.status !== AudioPlayerStatus.Idle && this.state.resource === resource) {\n\t\t\t\tthis.state = {\n\t\t\t\t\tstatus: AudioPlayerStatus.Idle,\n\t\t\t\t};\n\t\t\t}\n\t\t};\n\n\t\tresource.playStream.once('error', onStreamError);\n\n\t\tif (resource.started) {\n\t\t\tthis.state = {\n\t\t\t\tstatus: AudioPlayerStatus.Playing,\n\t\t\t\tmissedFrames: 0,\n\t\t\t\tplaybackDuration: 0,\n\t\t\t\tresource,\n\t\t\t\tonStreamError,\n\t\t\t};\n\t\t} else {\n\t\t\tconst onReadableCallback = () => {\n\t\t\t\tif (this.state.status === AudioPlayerStatus.Buffering && this.state.resource === resource) {\n\t\t\t\t\tthis.state = {\n\t\t\t\t\t\tstatus: AudioPlayerStatus.Playing,\n\t\t\t\t\t\tmissedFrames: 0,\n\t\t\t\t\t\tplaybackDuration: 0,\n\t\t\t\t\t\tresource,\n\t\t\t\t\t\tonStreamError,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst onFailureCallback = () => {\n\t\t\t\tif (this.state.status === AudioPlayerStatus.Buffering && this.state.resource === resource) {\n\t\t\t\t\tthis.state = {\n\t\t\t\t\t\tstatus: AudioPlayerStatus.Idle,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tresource.playStream.once('readable', onReadableCallback);\n\n\t\t\tresource.playStream.once('end', onFailureCallback);\n\t\t\tresource.playStream.once('close', onFailureCallback);\n\t\t\tresource.playStream.once('finish', onFailureCallback);\n\n\t\t\tthis.state = {\n\t\t\t\tstatus: AudioPlayerStatus.Buffering,\n\t\t\t\tresource,\n\t\t\t\tonReadableCallback,\n\t\t\t\tonFailureCallback,\n\t\t\t\tonStreamError,\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Pauses playback of the current resource, if any.\n\t *\n\t * @param interpolateSilence - If true, the player will play 5 packets of silence after pausing to prevent audio glitches\n\t * @returns `true` if the player was successfully paused, otherwise `false`\n\t */\n\tpublic pause(interpolateSilence = true) {\n\t\tif (this.state.status !== AudioPlayerStatus.Playing) return false;\n\t\tthis.state = {\n\t\t\t...this.state,\n\t\t\tstatus: AudioPlayerStatus.Paused,\n\t\t\tsilencePacketsRemaining: interpolateSilence ? 5 : 0,\n\t\t};\n\t\treturn true;\n\t}\n\n\t/**\n\t * Unpauses playback of the current resource, if any.\n\t *\n\t * @returns `true` if the player was successfully unpaused, otherwise `false`\n\t */\n\tpublic unpause() {\n\t\tif (this.state.status !== AudioPlayerStatus.Paused) return false;\n\t\tthis.state = {\n\t\t\t...this.state,\n\t\t\tstatus: AudioPlayerStatus.Playing,\n\t\t\tmissedFrames: 0,\n\t\t};\n\t\treturn true;\n\t}\n\n\t/**\n\t * Stops playback of the current resource and destroys the resource. The player will either transition to the Idle state,\n\t * or remain in its current state until the silence padding frames of the resource have been played.\n\t *\n\t * @param force - If true, will force the player to enter the Idle state even if the resource has silence padding frames\n\t * @returns `true` if the player will come to a stop, otherwise `false`\n\t */\n\tpublic stop(force = false) {\n\t\tif (this.state.status === AudioPlayerStatus.Idle) return false;\n\t\tif (force || this.state.resource.silencePaddingFrames === 0) {\n\t\t\tthis.state = {\n\t\t\t\tstatus: AudioPlayerStatus.Idle,\n\t\t\t};\n\t\t} else if (this.state.resource.silenceRemaining === -1) {\n\t\t\tthis.state.resource.silenceRemaining = this.state.resource.silencePaddingFrames;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Checks whether the underlying resource (if any) is playable (readable)\n\t *\n\t * @returns `true` if the resource is playable, otherwise `false`\n\t */\n\tpublic checkPlayable() {\n\t\tconst state = this._state;\n\t\tif (state.status === AudioPlayerStatus.Idle || state.status === AudioPlayerStatus.Buffering) return false;\n\n\t\t// If the stream has been destroyed or is no longer readable, then transition to the Idle state.\n\t\tif (!state.resource.readable) {\n\t\t\tthis.state = {\n\t\t\t\tstatus: AudioPlayerStatus.Idle,\n\t\t\t};\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Called roughly every 20ms by the global audio player timer. Dispatches any audio packets that are buffered\n\t * by the active connections of this audio player.\n\t */\n\t// @ts-ignore\n\tprivate _stepDispatch() {\n\t\tconst state = this._state;\n\n\t\t// Guard against the Idle state\n\t\tif (state.status === AudioPlayerStatus.Idle || state.status === AudioPlayerStatus.Buffering) return;\n\n\t\t// Dispatch any audio packets that were prepared in the previous cycle\n\t\tfor (const connection of this.playable) {\n\t\t\tconnection.dispatchAudio();\n\t\t}\n\t}\n\n\t/**\n\t * Called roughly every 20ms by the global audio player timer. Attempts to read an audio packet from the\n\t * underlying resource of the stream, and then has all the active connections of the audio player prepare it\n\t * (encrypt it, append header data) so that it is ready to play at the start of the next cycle.\n\t */\n\t// @ts-ignore\n\tprivate _stepPrepare() {\n\t\tconst state = this._state;\n\n\t\t// Guard against the Idle state\n\t\tif (state.status === AudioPlayerStatus.Idle || state.status === AudioPlayerStatus.Buffering) return;\n\n\t\t// List of connections that can receive the packet\n\t\tconst playable = this.playable;\n\n\t\t/* If the player was previously in the AutoPaused state, check to see whether there are newly available\n\t\t   connections, allowing us to transition out of the AutoPaused state back into the Playing state */\n\t\tif (state.status === AudioPlayerStatus.AutoPaused && playable.length > 0) {\n\t\t\tthis.state = {\n\t\t\t\t...state,\n\t\t\t\tstatus: AudioPlayerStatus.Playing,\n\t\t\t\tmissedFrames: 0,\n\t\t\t};\n\t\t}\n\n\t\t/* If the player is (auto)paused, check to see whether silence packets should be played and\n\t\t   set a timeout to begin the next cycle, ending the current cycle here. */\n\t\tif (state.status === AudioPlayerStatus.Paused || state.status === AudioPlayerStatus.AutoPaused) {\n\t\t\tif (state.silencePacketsRemaining > 0) {\n\t\t\t\tstate.silencePacketsRemaining--;\n\t\t\t\tthis._preparePacket(SILENCE_FRAME, playable, state);\n\t\t\t\tif (state.silencePacketsRemaining === 0) {\n\t\t\t\t\tthis._signalStopSpeaking();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are no available connections in this cycle, observe the configured \"no subscriber\" behavior.\n\t\tif (playable.length === 0) {\n\t\t\tif (this.behaviors.noSubscriber === NoSubscriberBehavior.Pause) {\n\t\t\t\tthis.state = {\n\t\t\t\t\t...state,\n\t\t\t\t\tstatus: AudioPlayerStatus.AutoPaused,\n\t\t\t\t\tsilencePacketsRemaining: 5,\n\t\t\t\t};\n\t\t\t\treturn;\n\t\t\t} else if (this.behaviors.noSubscriber === NoSubscriberBehavior.Stop) {\n\t\t\t\tthis.stop(true);\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Attempt to read an Opus packet from the resource. If there isn't an available packet,\n\t\t * play a silence packet. If there are 5 consecutive cycles with failed reads, then the\n\t\t * playback will end.\n\t\t */\n\t\tconst packet: Buffer | null = state.resource.read();\n\n\t\tif (state.status === AudioPlayerStatus.Playing) {\n\t\t\tif (packet) {\n\t\t\t\tthis._preparePacket(packet, playable, state);\n\t\t\t\tstate.missedFrames = 0;\n\t\t\t} else {\n\t\t\t\tthis._preparePacket(SILENCE_FRAME, playable, state);\n\t\t\t\tstate.missedFrames++;\n\t\t\t\tif (state.missedFrames >= this.behaviors.maxMissedFrames) {\n\t\t\t\t\tthis.stop();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Signals to all the subscribed connections that they should send a packet to Discord indicating\n\t * they are no longer speaking. Called once playback of a resource ends.\n\t */\n\tprivate _signalStopSpeaking() {\n\t\tfor (const { connection } of this.subscribers) {\n\t\t\tconnection.setSpeaking(false);\n\t\t}\n\t}\n\n\t/**\n\t * Instructs the given connections to each prepare this packet to be played at the start of the\n\t * next cycle.\n\t *\n\t * @param packet - The Opus packet to be prepared by each receiver\n\t * @param receivers - The connections that should play this packet\n\t */\n\tprivate _preparePacket(\n\t\tpacket: Buffer,\n\t\treceivers: VoiceConnection[],\n\t\tstate: AudioPlayerPausedState | AudioPlayerPlayingState,\n\t) {\n\t\tstate.playbackDuration += 20;\n\t\tfor (const connection of receivers) {\n\t\t\tconnection.prepareAudioPacket(packet);\n\t\t}\n\t}\n}\n\n/**\n * Creates a new AudioPlayer to be used.\n */\nexport function createAudioPlayer(options?: CreateAudioPlayerOptions) {\n\treturn new AudioPlayer(options);\n}\n"
  },
  {
    "path": "packages/voice/src/audio/AudioPlayerError.ts",
    "content": "import type { AudioResource } from './AudioResource';\n\n/**\n * An error emitted by an AudioPlayer. Contains an attached resource to aid with\n * debugging and identifying where the error came from.\n */\nexport class AudioPlayerError extends Error {\n\t/**\n\t * The resource associated with the audio player at the time the error was thrown.\n\t */\n\tpublic readonly resource: AudioResource;\n\n\tpublic constructor(error: Error, resource: AudioResource) {\n\t\tsuper(error.message);\n\t\tthis.resource = resource;\n\t\tthis.name = error.name;\n\t\tthis.stack = error.stack!;\n\t}\n}\n"
  },
  {
    "path": "packages/voice/src/audio/AudioResource.ts",
    "content": "import type { Buffer } from 'node:buffer';\nimport { pipeline, type Readable } from 'node:stream';\nimport prism from 'prism-media';\nimport { noop } from '../util/util';\nimport { SILENCE_FRAME, type AudioPlayer } from './AudioPlayer';\nimport { findPipeline, StreamType, TransformerType, type Edge } from './TransformerGraph';\n\n/**\n * Options that are set when creating a new audio resource.\n *\n * @typeParam Metadata - the type for the metadata (if any) of the audio resource\n */\nexport interface CreateAudioResourceOptions<Metadata> {\n\t/**\n\t * Whether or not inline volume should be enabled. If enabled, you will be able to change the volume\n\t * of the stream on-the-fly. However, this also increases the performance cost of playback. Defaults to `false`.\n\t */\n\tinlineVolume?: boolean;\n\n\t/**\n\t * The type of the input stream. Defaults to `StreamType.Arbitrary`.\n\t */\n\tinputType?: StreamType;\n\n\t/**\n\t * Optional metadata that can be attached to the resource (e.g. track title, random id).\n\t * This is useful for identification purposes when the resource is passed around in events.\n\t * See {@link AudioResource.metadata}\n\t */\n\tmetadata?: Metadata;\n\n\t/**\n\t * The number of silence frames to append to the end of the resource's audio stream, to prevent interpolation glitches.\n\t * Defaults to 5.\n\t */\n\tsilencePaddingFrames?: number;\n}\n\n/**\n * Represents an audio resource that can be played by an audio player.\n *\n * @typeParam Metadata - the type for the metadata (if any) of the audio resource\n */\nexport class AudioResource<Metadata = unknown> {\n\t/**\n\t * An object-mode Readable stream that emits Opus packets. This is what is played by audio players.\n\t */\n\tpublic readonly playStream: Readable;\n\n\t/**\n\t * The pipeline used to convert the input stream into a playable format. For example, this may\n\t * contain an FFmpeg component for arbitrary inputs, and it may contain a VolumeTransformer component\n\t * for resources with inline volume transformation enabled.\n\t */\n\tpublic readonly edges: readonly Edge[];\n\n\t/**\n\t * Optional metadata that can be used to identify the resource.\n\t */\n\tpublic metadata: Metadata;\n\n\t/**\n\t * If the resource was created with inline volume transformation enabled, then this will be a\n\t * prism-media VolumeTransformer. You can use this to alter the volume of the stream.\n\t */\n\tpublic readonly volume?: prism.VolumeTransformer;\n\n\t/**\n\t * If using an Opus encoder to create this audio resource, then this will be a prism-media opus.Encoder.\n\t * You can use this to control settings such as bitrate, FEC, PLP.\n\t */\n\tpublic readonly encoder?: prism.opus.Encoder;\n\n\t/**\n\t * The audio player that the resource is subscribed to, if any.\n\t */\n\tpublic audioPlayer?: AudioPlayer | undefined;\n\n\t/**\n\t * The playback duration of this audio resource, given in milliseconds.\n\t */\n\tpublic playbackDuration = 0;\n\n\t/**\n\t * Whether or not the stream for this resource has started (data has become readable)\n\t */\n\tpublic started = false;\n\n\t/**\n\t * The number of silence frames to append to the end of the resource's audio stream, to prevent interpolation glitches.\n\t */\n\tpublic readonly silencePaddingFrames: number;\n\n\t/**\n\t * The number of remaining silence frames to play. If -1, the frames have not yet started playing.\n\t */\n\tpublic silenceRemaining = -1;\n\n\tpublic constructor(\n\t\tedges: readonly Edge[],\n\t\tstreams: readonly Readable[],\n\t\tmetadata: Metadata,\n\t\tsilencePaddingFrames: number,\n\t) {\n\t\tthis.edges = edges;\n\t\tthis.playStream = streams.length > 1 ? (pipeline(streams, noop) as any as Readable) : streams[0]!;\n\t\tthis.metadata = metadata;\n\t\tthis.silencePaddingFrames = silencePaddingFrames;\n\n\t\tfor (const stream of streams) {\n\t\t\tif (stream instanceof prism.VolumeTransformer) {\n\t\t\t\tthis.volume = stream;\n\t\t\t} else if (stream instanceof prism.opus.Encoder) {\n\t\t\t\tthis.encoder = stream;\n\t\t\t}\n\t\t}\n\n\t\tthis.playStream.once('readable', () => (this.started = true));\n\t}\n\n\t/**\n\t * Whether this resource is readable. If the underlying resource is no longer readable, this will still return true\n\t * while there are silence padding frames left to play.\n\t */\n\tpublic get readable() {\n\t\tif (this.silenceRemaining === 0) return false;\n\t\tconst real = this.playStream.readable;\n\t\tif (!real) {\n\t\t\tif (this.silenceRemaining === -1) this.silenceRemaining = this.silencePaddingFrames;\n\t\t\treturn this.silenceRemaining !== 0;\n\t\t}\n\n\t\treturn real;\n\t}\n\n\t/**\n\t * Whether this resource has ended or not.\n\t */\n\tpublic get ended() {\n\t\treturn this.playStream.readableEnded || this.playStream.destroyed || this.silenceRemaining === 0;\n\t}\n\n\t/**\n\t * Attempts to read an Opus packet from the audio resource. If a packet is available, the playbackDuration\n\t * is incremented.\n\t *\n\t * @remarks\n\t * It is advisable to check that the playStream is readable before calling this method. While no runtime\n\t * errors will be thrown, you should check that the resource is still available before attempting to\n\t * read from it.\n\t * @internal\n\t */\n\tpublic read(): Buffer | null {\n\t\tif (this.silenceRemaining === 0) {\n\t\t\treturn null;\n\t\t} else if (this.silenceRemaining > 0) {\n\t\t\tthis.silenceRemaining--;\n\t\t\treturn SILENCE_FRAME;\n\t\t}\n\n\t\tconst packet = this.playStream.read() as Buffer | null;\n\t\tif (packet) {\n\t\t\tthis.playbackDuration += 20;\n\t\t}\n\n\t\treturn packet;\n\t}\n}\n\n/**\n * Ensures that a path contains at least one volume transforming component.\n *\n * @param path - The path to validate constraints on\n */\nexport const VOLUME_CONSTRAINT = (path: Edge[]) => path.some((edge) => edge.type === TransformerType.InlineVolume);\n\nexport const NO_CONSTRAINT = () => true;\n\n/**\n * Tries to infer the type of a stream to aid with transcoder pipelining.\n *\n * @param stream - The stream to infer the type of\n */\nexport function inferStreamType(stream: Readable): {\n\thasVolume: boolean;\n\tstreamType: StreamType;\n} {\n\tif (stream instanceof prism.opus.Encoder) {\n\t\treturn { streamType: StreamType.Opus, hasVolume: false };\n\t} else if (stream instanceof prism.opus.Decoder) {\n\t\treturn { streamType: StreamType.Raw, hasVolume: false };\n\t} else if (stream instanceof prism.VolumeTransformer) {\n\t\treturn { streamType: StreamType.Raw, hasVolume: true };\n\t} else if (stream instanceof prism.opus.OggDemuxer) {\n\t\treturn { streamType: StreamType.Opus, hasVolume: false };\n\t} else if (stream instanceof prism.opus.WebmDemuxer) {\n\t\treturn { streamType: StreamType.Opus, hasVolume: false };\n\t}\n\n\treturn { streamType: StreamType.Arbitrary, hasVolume: false };\n}\n\n/**\n * Creates an audio resource that can be played by audio players.\n *\n * @remarks\n * If the input is given as a string, then the inputType option will be overridden and FFmpeg will be used.\n *\n * If the input is not in the correct format, then a pipeline of transcoders and transformers will be created\n * to ensure that the resultant stream is in the correct format for playback. This could involve using FFmpeg,\n * Opus transcoders, and Ogg/WebM demuxers.\n * @param input - The resource to play\n * @param options - Configurable options for creating the resource\n * @typeParam Metadata - the type for the metadata (if any) of the audio resource\n */\nexport function createAudioResource<Metadata>(\n\tinput: Readable | string,\n\toptions: CreateAudioResourceOptions<Metadata> &\n\t\tPick<\n\t\t\tMetadata extends null | undefined\n\t\t\t\t? CreateAudioResourceOptions<Metadata>\n\t\t\t\t: Required<CreateAudioResourceOptions<Metadata>>,\n\t\t\t'metadata'\n\t\t>,\n): AudioResource<Metadata extends null | undefined ? null : Metadata>;\n\n/**\n * Creates an audio resource that can be played by audio players.\n *\n * @remarks\n * If the input is given as a string, then the inputType option will be overridden and FFmpeg will be used.\n *\n * If the input is not in the correct format, then a pipeline of transcoders and transformers will be created\n * to ensure that the resultant stream is in the correct format for playback. This could involve using FFmpeg,\n * Opus transcoders, and Ogg/WebM demuxers.\n * @param input - The resource to play\n * @param options - Configurable options for creating the resource\n * @typeParam Metadata - the type for the metadata (if any) of the audio resource\n */\nexport function createAudioResource<Metadata extends null | undefined>(\n\tinput: Readable | string,\n\toptions?: Omit<CreateAudioResourceOptions<Metadata>, 'metadata'>,\n): AudioResource<null>;\n\n/**\n * Creates an audio resource that can be played by audio players.\n *\n * @remarks\n * If the input is given as a string, then the inputType option will be overridden and FFmpeg will be used.\n *\n * If the input is not in the correct format, then a pipeline of transcoders and transformers will be created\n * to ensure that the resultant stream is in the correct format for playback. This could involve using FFmpeg,\n * Opus transcoders, and Ogg/WebM demuxers.\n * @param input - The resource to play\n * @param options - Configurable options for creating the resource\n * @typeParam Metadata - the type for the metadata (if any) of the audio resource\n */\nexport function createAudioResource<Metadata>(\n\tinput: Readable | string,\n\toptions: CreateAudioResourceOptions<Metadata> = {},\n): AudioResource<Metadata> {\n\tlet inputType = options.inputType;\n\tlet needsInlineVolume = Boolean(options.inlineVolume);\n\n\t// string inputs can only be used with FFmpeg\n\tif (typeof input === 'string') {\n\t\tinputType = StreamType.Arbitrary;\n\t} else if (inputType === undefined) {\n\t\tconst analysis = inferStreamType(input);\n\t\tinputType = analysis.streamType;\n\t\tneedsInlineVolume = needsInlineVolume && !analysis.hasVolume;\n\t}\n\n\tconst transformerPipeline = findPipeline(inputType, needsInlineVolume ? VOLUME_CONSTRAINT : NO_CONSTRAINT);\n\n\tif (transformerPipeline.length === 0) {\n\t\tif (typeof input === 'string') throw new Error(`Invalid pipeline constructed for string resource '${input}'`);\n\t\t// No adjustments required\n\t\treturn new AudioResource<Metadata>(\n\t\t\t[],\n\t\t\t[input],\n\t\t\t(options.metadata ?? null) as Metadata,\n\t\t\toptions.silencePaddingFrames ?? 5,\n\t\t);\n\t}\n\n\tconst streams = transformerPipeline.map((edge) => edge.transformer(input));\n\tif (typeof input !== 'string') streams.unshift(input);\n\n\treturn new AudioResource<Metadata>(\n\t\ttransformerPipeline,\n\t\tstreams,\n\t\t(options.metadata ?? null) as Metadata,\n\t\toptions.silencePaddingFrames ?? 5,\n\t);\n}\n"
  },
  {
    "path": "packages/voice/src/audio/PlayerSubscription.ts",
    "content": "/* eslint-disable @typescript-eslint/dot-notation */\nimport type { VoiceConnection } from '../VoiceConnection';\nimport type { AudioPlayer } from './AudioPlayer';\n\n/**\n * Represents a subscription of a voice connection to an audio player, allowing\n * the audio player to play audio on the voice connection.\n */\nexport class PlayerSubscription {\n\t/**\n\t * The voice connection of this subscription.\n\t */\n\tpublic readonly connection: VoiceConnection;\n\n\t/**\n\t * The audio player of this subscription.\n\t */\n\tpublic readonly player: AudioPlayer;\n\n\tpublic constructor(connection: VoiceConnection, player: AudioPlayer) {\n\t\tthis.connection = connection;\n\t\tthis.player = player;\n\t}\n\n\t/**\n\t * Unsubscribes the connection from the audio player, meaning that the\n\t * audio player cannot stream audio to it until a new subscription is made.\n\t */\n\tpublic unsubscribe() {\n\t\tthis.connection['onSubscriptionRemoved'](this);\n\t\tthis.player['unsubscribe'](this);\n\t}\n}\n"
  },
  {
    "path": "packages/voice/src/audio/TransformerGraph.ts",
    "content": "import type { Readable } from 'node:stream';\nimport prism from 'prism-media';\n\n/**\n * This module creates a Transformer Graph to figure out what the most efficient way\n * of transforming the input stream into something playable would be.\n */\n\nconst FFMPEG_PCM_ARGUMENTS = ['-analyzeduration', '0', '-loglevel', '0', '-f', 's16le', '-ar', '48000', '-ac', '2'];\nconst FFMPEG_OPUS_ARGUMENTS = [\n\t'-analyzeduration',\n\t'0',\n\t'-loglevel',\n\t'0',\n\t'-acodec',\n\t'libopus',\n\t'-f',\n\t'opus',\n\t'-ar',\n\t'48000',\n\t'-ac',\n\t'2',\n];\n\n/**\n * The different types of stream that can exist within the pipeline.\n */\nexport enum StreamType {\n\t/**\n\t * The type of the stream at this point is unknown.\n\t */\n\tArbitrary = 'arbitrary',\n\t/**\n\t * The stream at this point is Opus audio encoded in an Ogg wrapper.\n\t */\n\tOggOpus = 'ogg/opus',\n\t/**\n\t * The stream at this point is Opus audio, and the stream is in object-mode. This is ready to play.\n\t */\n\tOpus = 'opus',\n\t/**\n\t * The stream at this point is s16le PCM.\n\t */\n\tRaw = 'raw',\n\t/**\n\t * The stream at this point is Opus audio encoded in a WebM wrapper.\n\t */\n\tWebmOpus = 'webm/opus',\n}\n\n/**\n * The different types of transformers that can exist within the pipeline.\n */\nexport enum TransformerType {\n\tFFmpegOgg = 'ffmpeg ogg',\n\tFFmpegPCM = 'ffmpeg pcm',\n\tInlineVolume = 'volume transformer',\n\tOggOpusDemuxer = 'ogg/opus demuxer',\n\tOpusDecoder = 'opus decoder',\n\tOpusEncoder = 'opus encoder',\n\tWebmOpusDemuxer = 'webm/opus demuxer',\n}\n\n/**\n * Represents a pathway from one stream type to another using a transformer.\n */\nexport interface Edge {\n\tcost: number;\n\tfrom: Node;\n\tto: Node;\n\ttransformer(input: Readable | string): Readable;\n\ttype: TransformerType;\n}\n\n/**\n * Represents a type of stream within the graph, e.g. an Opus stream, or a stream of raw audio.\n */\nexport class Node {\n\t/**\n\t * The outbound edges from this node.\n\t */\n\tpublic readonly edges: Edge[] = [];\n\n\t/**\n\t * The type of stream for this node.\n\t */\n\tpublic readonly type: StreamType;\n\n\tpublic constructor(type: StreamType) {\n\t\tthis.type = type;\n\t}\n\n\t/**\n\t * Creates an outbound edge from this node.\n\t *\n\t * @param edge - The edge to create\n\t */\n\tpublic addEdge(edge: Omit<Edge, 'from'>) {\n\t\tthis.edges.push({ ...edge, from: this });\n\t}\n}\n\n// Create a node for each stream type\nlet NODES: Map<StreamType, Node> | null = null;\n\n/**\n * Gets a node from its stream type.\n *\n * @param type - The stream type of the target node\n */\nexport function getNode(type: StreamType) {\n\tconst node = (NODES ??= initializeNodes()).get(type);\n\tif (!node) throw new Error(`Node type '${type}' does not exist!`);\n\treturn node;\n}\n\n// Try to enable FFmpeg Ogg optimizations\nfunction canEnableFFmpegOptimizations(): boolean {\n\ttry {\n\t\treturn prism.FFmpeg.getInfo().output.includes('--enable-libopus');\n\t} catch {}\n\n\treturn false;\n}\n\nfunction initializeNodes(): Map<StreamType, Node> {\n\tconst nodes = new Map<StreamType, Node>();\n\tfor (const streamType of Object.values(StreamType)) {\n\t\tnodes.set(streamType, new Node(streamType));\n\t}\n\n\tnodes.get(StreamType.Raw)!.addEdge({\n\t\ttype: TransformerType.OpusEncoder,\n\t\tto: nodes.get(StreamType.Opus)!,\n\t\tcost: 1.5,\n\t\ttransformer: () => new prism.opus.Encoder({ rate: 48_000, channels: 2, frameSize: 960 }),\n\t});\n\n\tnodes.get(StreamType.Opus)!.addEdge({\n\t\ttype: TransformerType.OpusDecoder,\n\t\tto: nodes.get(StreamType.Raw)!,\n\t\tcost: 1.5,\n\t\ttransformer: () => new prism.opus.Decoder({ rate: 48_000, channels: 2, frameSize: 960 }),\n\t});\n\n\tnodes.get(StreamType.OggOpus)!.addEdge({\n\t\ttype: TransformerType.OggOpusDemuxer,\n\t\tto: nodes.get(StreamType.Opus)!,\n\t\tcost: 1,\n\t\ttransformer: () => new prism.opus.OggDemuxer(),\n\t});\n\n\tnodes.get(StreamType.WebmOpus)!.addEdge({\n\t\ttype: TransformerType.WebmOpusDemuxer,\n\t\tto: nodes.get(StreamType.Opus)!,\n\t\tcost: 1,\n\t\ttransformer: () => new prism.opus.WebmDemuxer(),\n\t});\n\n\tconst FFMPEG_PCM_EDGE: Omit<Edge, 'from'> = {\n\t\ttype: TransformerType.FFmpegPCM,\n\t\tto: nodes.get(StreamType.Raw)!,\n\t\tcost: 2,\n\t\ttransformer: (input) =>\n\t\t\tnew prism.FFmpeg({\n\t\t\t\targs: ['-i', typeof input === 'string' ? input : '-', ...FFMPEG_PCM_ARGUMENTS],\n\t\t\t}),\n\t};\n\n\tnodes.get(StreamType.Arbitrary)!.addEdge(FFMPEG_PCM_EDGE);\n\tnodes.get(StreamType.OggOpus)!.addEdge(FFMPEG_PCM_EDGE);\n\tnodes.get(StreamType.WebmOpus)!.addEdge(FFMPEG_PCM_EDGE);\n\n\tnodes.get(StreamType.Raw)!.addEdge({\n\t\ttype: TransformerType.InlineVolume,\n\t\tto: nodes.get(StreamType.Raw)!,\n\t\tcost: 0.5,\n\t\ttransformer: () => new prism.VolumeTransformer({ type: 's16le' }),\n\t});\n\n\tif (canEnableFFmpegOptimizations()) {\n\t\tconst FFMPEG_OGG_EDGE: Omit<Edge, 'from'> = {\n\t\t\ttype: TransformerType.FFmpegOgg,\n\t\t\tto: nodes.get(StreamType.OggOpus)!,\n\t\t\tcost: 2,\n\t\t\ttransformer: (input) =>\n\t\t\t\tnew prism.FFmpeg({\n\t\t\t\t\targs: ['-i', typeof input === 'string' ? input : '-', ...FFMPEG_OPUS_ARGUMENTS],\n\t\t\t\t}),\n\t\t};\n\t\tnodes.get(StreamType.Arbitrary)!.addEdge(FFMPEG_OGG_EDGE);\n\t\t// Include Ogg and WebM as well in case they have different sampling rates or are mono instead of stereo\n\t\t// at the moment, this will not do anything. However, if/when detection for correct Opus headers is\n\t\t// implemented, this will help inform the voice engine that it is able to transcode the audio.\n\t\tnodes.get(StreamType.OggOpus)!.addEdge(FFMPEG_OGG_EDGE);\n\t\tnodes.get(StreamType.WebmOpus)!.addEdge(FFMPEG_OGG_EDGE);\n\t}\n\n\treturn nodes;\n}\n\n/**\n * Represents a step in the path from node A to node B.\n */\ninterface Step {\n\t/**\n\t * The cost of the steps after this step.\n\t */\n\tcost: number;\n\n\t/**\n\t * The edge associated with this step.\n\t */\n\tedge?: Edge;\n\n\t/**\n\t * The next step.\n\t */\n\tnext?: Step;\n}\n\n/**\n * Finds the shortest cost path from node A to node B.\n *\n * @param from - The start node\n * @param constraints - Extra validation for a potential solution. Takes a path, returns true if the path is valid\n * @param goal - The target node\n * @param path - The running path\n * @param depth - The number of remaining recursions\n */\nfunction findPath(\n\tfrom: Node,\n\tconstraints: (path: Edge[]) => boolean,\n\tgoal = getNode(StreamType.Opus),\n\tpath: Edge[] = [],\n\tdepth = 5,\n): Step {\n\tif (from === goal && constraints(path)) {\n\t\treturn { cost: 0 };\n\t} else if (depth === 0) {\n\t\treturn { cost: Number.POSITIVE_INFINITY };\n\t}\n\n\tlet currentBest: Step | undefined;\n\tfor (const edge of from.edges) {\n\t\tif (currentBest && edge.cost > currentBest.cost) continue;\n\t\tconst next = findPath(edge.to, constraints, goal, [...path, edge], depth - 1);\n\t\tconst cost = edge.cost + next.cost;\n\t\tif (!currentBest || cost < currentBest.cost) {\n\t\t\tcurrentBest = { cost, edge, next };\n\t\t}\n\t}\n\n\treturn currentBest ?? { cost: Number.POSITIVE_INFINITY };\n}\n\n/**\n * Takes the solution from findPath and assembles it into a list of edges.\n *\n * @param step - The first step of the path\n */\nfunction constructPipeline(step: Step) {\n\tconst edges = [];\n\tlet current: Step | undefined = step;\n\twhile (current?.edge) {\n\t\tedges.push(current.edge);\n\t\tcurrent = current.next;\n\t}\n\n\treturn edges;\n}\n\n/**\n * Finds the lowest-cost pipeline to convert the input stream type into an Opus stream.\n *\n * @param from - The stream type to start from\n * @param constraint - Extra constraints that may be imposed on potential solution\n */\nexport function findPipeline(from: StreamType, constraint: (path: Edge[]) => boolean) {\n\treturn constructPipeline(findPath(getNode(from), constraint));\n}\n"
  },
  {
    "path": "packages/voice/src/audio/index.ts",
    "content": "export {\n\tAudioPlayer,\n\tAudioPlayerStatus,\n\ttype AudioPlayerState,\n\tNoSubscriberBehavior,\n\tcreateAudioPlayer,\n\ttype AudioPlayerBufferingState,\n\ttype AudioPlayerIdleState,\n\ttype AudioPlayerPausedState,\n\ttype AudioPlayerPlayingState,\n\ttype CreateAudioPlayerOptions,\n} from './AudioPlayer';\n\nexport { AudioPlayerError } from './AudioPlayerError';\n\nexport { AudioResource, type CreateAudioResourceOptions, createAudioResource } from './AudioResource';\n\nexport { PlayerSubscription } from './PlayerSubscription';\n\nexport { StreamType, type Edge, TransformerType, Node } from './TransformerGraph';\n"
  },
  {
    "path": "packages/voice/src/index.ts",
    "content": "export * from './joinVoiceChannel';\nexport * from './audio/index';\nexport * from './util/index';\nexport * from './receive/index';\n\nexport {\n\tNetworking,\n\ttype ConnectionData,\n\ttype ConnectionOptions,\n\ttype NetworkingState,\n\ttype NetworkingResumingState,\n\ttype NetworkingSelectingProtocolState,\n\ttype NetworkingUdpHandshakingState,\n\ttype NetworkingClosedState,\n\ttype NetworkingIdentifyingState,\n\ttype NetworkingOpeningWsState,\n\ttype NetworkingReadyState,\n\tNetworkingStatusCode,\n\tVoiceUDPSocket,\n\tVoiceWebSocket,\n\ttype SocketConfig,\n\tDAVESession,\n} from './networking/index.js';\n\nexport {\n\tVoiceConnection,\n\ttype VoiceConnectionState,\n\tVoiceConnectionStatus,\n\ttype VoiceConnectionConnectingState,\n\ttype VoiceConnectionDestroyedState,\n\ttype VoiceConnectionDisconnectedState,\n\ttype VoiceConnectionDisconnectedBaseState,\n\ttype VoiceConnectionDisconnectedOtherState,\n\ttype VoiceConnectionDisconnectedWebSocketState,\n\tVoiceConnectionDisconnectReason,\n\ttype VoiceConnectionReadyState,\n\ttype VoiceConnectionSignallingState,\n} from './VoiceConnection';\n\nexport { type JoinConfig, getVoiceConnection, getVoiceConnections, getGroups } from './DataStore';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/voice#readme | @discordjs/voice} version\n * that you are currently using.\n */\n// This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild\nexport const version = '[VI]{{inject}}[/VI]' as string;\n"
  },
  {
    "path": "packages/voice/src/joinVoiceChannel.ts",
    "content": "import type { JoinConfig } from './DataStore';\nimport { createVoiceConnection } from './VoiceConnection';\nimport type { DiscordGatewayAdapterCreator } from './util/adapter';\n\n/**\n * The options that can be given when creating a voice connection.\n */\nexport interface CreateVoiceConnectionOptions {\n\tadapterCreator: DiscordGatewayAdapterCreator;\n\n\t/**\n\t * Whether to use the DAVE protocol for end-to-end encryption. Defaults to true.\n\t */\n\tdaveEncryption?: boolean | undefined;\n\n\t/**\n\t * If true, debug messages will be enabled for the voice connection and its\n\t * related components. Defaults to false.\n\t */\n\tdebug?: boolean | undefined;\n\n\t/**\n\t * The amount of consecutive decryption failures needed to try to\n\t * re-initialize the end-to-end encrypted session to recover. Defaults to 24.\n\t */\n\tdecryptionFailureTolerance?: number | undefined;\n}\n\n/**\n * The options that can be given when joining a voice channel.\n */\nexport interface JoinVoiceChannelOptions {\n\t/**\n\t * The id of the Discord voice channel to join.\n\t */\n\tchannelId: string;\n\n\t/**\n\t * An optional group identifier for the voice connection.\n\t */\n\tgroup?: string;\n\n\t/**\n\t * The id of the guild that the voice channel belongs to.\n\t */\n\tguildId: string;\n\n\t/**\n\t * Whether to join the channel deafened (defaults to true)\n\t */\n\tselfDeaf?: boolean;\n\n\t/**\n\t * Whether to join the channel muted (defaults to true)\n\t */\n\tselfMute?: boolean;\n}\n\n/**\n * Creates a VoiceConnection to a Discord voice channel.\n *\n * @param options - the options for joining the voice channel\n */\nexport function joinVoiceChannel(options: CreateVoiceConnectionOptions & JoinVoiceChannelOptions) {\n\tconst joinConfig: JoinConfig = {\n\t\tselfDeaf: true,\n\t\tselfMute: false,\n\t\tgroup: 'default',\n\t\t...options,\n\t};\n\n\treturn createVoiceConnection(joinConfig, {\n\t\tadapterCreator: options.adapterCreator,\n\t\tdebug: options.debug,\n\t\tdaveEncryption: options.daveEncryption,\n\t\tdecryptionFailureTolerance: options.decryptionFailureTolerance,\n\t});\n}\n"
  },
  {
    "path": "packages/voice/src/networking/DAVESession.ts",
    "content": "import { Buffer } from 'node:buffer';\nimport { EventEmitter } from 'node:events';\nimport Davey from '@snazzah/davey';\nimport type { VoiceDavePrepareEpochData, VoiceDavePrepareTransitionData } from 'discord-api-types/voice/v8';\nimport { SILENCE_FRAME } from '../audio/AudioPlayer';\n\ninterface SessionMethods {\n\tcanPassthrough(userId: string): boolean;\n\tdecrypt(userId: string, mediaType: 0 | 1, packet: Buffer): Buffer;\n\tencryptOpus(packet: Buffer): Buffer;\n\tgetSerializedKeyPackage(): Buffer;\n\tgetVerificationCode(userId: string): Promise<string>;\n\tprocessCommit(commit: Buffer): void;\n\tprocessProposals(optype: 0 | 1, proposals: Buffer, recognizedUserIds?: string[]): ProposalsResult;\n\tprocessWelcome(welcome: Buffer): void;\n\tready: boolean;\n\treinit(protocolVersion: number, userId: string, channelId: string): void;\n\treset(): void;\n\tsetExternalSender(externalSender: Buffer): void;\n\tsetPassthroughMode(passthrough: boolean, expiry: number): void;\n\tvoicePrivacyCode: string;\n}\n\ninterface ProposalsResult {\n\tcommit?: Buffer;\n\twelcome?: Buffer;\n}\n\n/**\n * The amount of seconds that a previous transition should be valid for.\n */\nconst TRANSITION_EXPIRY = 10;\n\n/**\n * The arbitrary amount of seconds to allow passthrough for mid-downgrade.\n * Generally, transitions last about 3 seconds maximum, but this should cover for when connections are delayed.\n */\nconst TRANSITION_EXPIRY_PENDING_DOWNGRADE = 24;\n\n/**\n * The amount of packets to allow decryption failure for until we deem the transition bad and re-initialize.\n * Usually 4 packets on a good connection may slip past when entering a new session.\n * After re-initializing, 5-24 packets may fail to decrypt after.\n */\nexport const DEFAULT_DECRYPTION_FAILURE_TOLERANCE = 36;\n\ninterface TransitionResult {\n\tsuccess: boolean;\n\ttransitionId: number;\n}\n/**\n * Options that dictate the session behavior.\n */\nexport interface DAVESessionOptions {\n\tdecryptionFailureTolerance?: number | undefined;\n}\n\n/**\n * The maximum DAVE protocol version supported.\n */\nexport function getMaxProtocolVersion(): number {\n\treturn Davey.DAVE_PROTOCOL_VERSION;\n}\n\nexport interface DAVESession extends EventEmitter {\n\ton(event: 'error', listener: (error: Error) => void): this;\n\ton(event: 'debug', listener: (message: string) => void): this;\n\ton(event: 'keyPackage', listener: (message: Buffer) => void): this;\n\ton(event: 'invalidateTransition', listener: (transitionId: number) => void): this;\n}\n\n/**\n * Manages the DAVE protocol group session.\n */\nexport class DAVESession extends EventEmitter {\n\t/**\n\t * The channel id represented by this session.\n\t */\n\tpublic channelId: string;\n\n\t/**\n\t * The user id represented by this session.\n\t */\n\tpublic userId: string;\n\n\t/**\n\t * The protocol version being used.\n\t */\n\tpublic protocolVersion: number;\n\n\t/**\n\t * The last transition id executed.\n\t */\n\tpublic lastTransitionId?: number | undefined;\n\n\t/**\n\t * The pending transitions, mapped by their ID and the protocol version.\n\t */\n\tprivate pendingTransitions = new Map<number, number>();\n\n\t/**\n\t * Whether this session was downgraded previously.\n\t */\n\tprivate downgraded = false;\n\n\t/**\n\t * The amount of consecutive failures encountered when decrypting.\n\t */\n\tprivate consecutiveFailures = 0;\n\n\t/**\n\t * The amount of consecutive failures needed to attempt to recover.\n\t */\n\tprivate readonly failureTolerance: number;\n\n\t/**\n\t * Whether this session is currently re-initializing due to an invalid transition.\n\t */\n\tpublic reinitializing = false;\n\n\t/**\n\t * The underlying DAVE Session of this wrapper.\n\t */\n\tpublic session: SessionMethods | undefined;\n\n\tpublic constructor(protocolVersion: number, userId: string, channelId: string, options: DAVESessionOptions) {\n\t\tsuper();\n\n\t\tthis.protocolVersion = protocolVersion;\n\t\tthis.userId = userId;\n\t\tthis.channelId = channelId;\n\t\tthis.failureTolerance = options.decryptionFailureTolerance ?? DEFAULT_DECRYPTION_FAILURE_TOLERANCE;\n\t}\n\n\t/**\n\t * The current voice privacy code of the session. Will be `null` if there is no session.\n\t */\n\tpublic get voicePrivacyCode(): string | null {\n\t\tif (this.protocolVersion === 0 || !this.session?.voicePrivacyCode) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.session.voicePrivacyCode;\n\t}\n\n\t/**\n\t * Gets the verification code for a user in the session.\n\t *\n\t * @throws Will throw if there is not an active session or the user id provided is invalid or not in the session.\n\t */\n\tpublic async getVerificationCode(userId: string): Promise<string> {\n\t\tif (!this.session) throw new Error('Session not available');\n\t\treturn this.session.getVerificationCode(userId);\n\t}\n\n\t/**\n\t * Re-initializes (or initializes) the underlying session.\n\t */\n\tpublic reinit() {\n\t\tif (this.protocolVersion > 0) {\n\t\t\tif (this.session) {\n\t\t\t\tthis.session.reinit(this.protocolVersion, this.userId, this.channelId);\n\t\t\t\tthis.emit('debug', `Session reinitialized for protocol version ${this.protocolVersion}`);\n\t\t\t} else {\n\t\t\t\tthis.session = new Davey.DAVESession(this.protocolVersion, this.userId, this.channelId);\n\t\t\t\tthis.emit('debug', `Session initialized for protocol version ${this.protocolVersion}`);\n\t\t\t}\n\n\t\t\tthis.emit('keyPackage', this.session!.getSerializedKeyPackage());\n\t\t} else if (this.session) {\n\t\t\tthis.session.reset();\n\t\t\tthis.session.setPassthroughMode(true, TRANSITION_EXPIRY);\n\t\t\tthis.emit('debug', 'Session reset');\n\t\t}\n\t}\n\n\t/**\n\t * Set the external sender for this session.\n\t *\n\t * @param externalSender - The external sender\n\t */\n\tpublic setExternalSender(externalSender: Buffer) {\n\t\tif (!this.session) throw new Error('No session available');\n\t\tthis.session.setExternalSender(externalSender);\n\t\tthis.emit('debug', 'Set MLS external sender');\n\t}\n\n\t/**\n\t * Prepare for a transition.\n\t *\n\t * @param data - The transition data\n\t * @returns Whether we should signal to the voice server that we are ready\n\t */\n\tpublic prepareTransition(data: VoiceDavePrepareTransitionData) {\n\t\tthis.emit('debug', `Preparing for transition (${data.transition_id}, v${data.protocol_version})`);\n\t\tthis.pendingTransitions.set(data.transition_id, data.protocol_version);\n\n\t\t// When the included transition id is 0, the transition is for (re)initialization and it can be executed immediately.\n\t\tif (data.transition_id === 0) {\n\t\t\tthis.executeTransition(data.transition_id);\n\t\t} else {\n\t\t\tif (data.protocol_version === 0) this.session?.setPassthroughMode(true, TRANSITION_EXPIRY_PENDING_DOWNGRADE);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Execute a transition.\n\t *\n\t * @param transitionId - The transition id to execute on\n\t */\n\tpublic executeTransition(transitionId: number) {\n\t\tthis.emit('debug', `Executing transition (${transitionId})`);\n\t\tif (!this.pendingTransitions.has(transitionId)) {\n\t\t\tthis.emit('debug', `Received execute transition, but we don't have a pending transition for ${transitionId}`);\n\t\t\treturn false;\n\t\t}\n\n\t\tconst oldVersion = this.protocolVersion;\n\t\tthis.protocolVersion = this.pendingTransitions.get(transitionId)!;\n\n\t\t// Handle upgrades & defer downgrades\n\t\tif (oldVersion !== this.protocolVersion && this.protocolVersion === 0) {\n\t\t\tthis.downgraded = true;\n\t\t\tthis.emit('debug', 'Session downgraded');\n\t\t} else if (transitionId > 0 && this.downgraded) {\n\t\t\tthis.downgraded = false;\n\t\t\tthis.session?.setPassthroughMode(true, TRANSITION_EXPIRY);\n\t\t\tthis.emit('debug', 'Session upgraded');\n\t\t}\n\n\t\t// In the future we'd want to signal to the DAVESession to transition also, but it only supports v1 at this time\n\t\tthis.reinitializing = false;\n\t\tthis.lastTransitionId = transitionId;\n\t\tthis.emit('debug', `Transition executed (v${oldVersion} -> v${this.protocolVersion}, id: ${transitionId})`);\n\n\t\tthis.pendingTransitions.delete(transitionId);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Prepare for a new epoch.\n\t *\n\t * @param data - The epoch data\n\t */\n\tpublic prepareEpoch(data: VoiceDavePrepareEpochData) {\n\t\tthis.emit('debug', `Preparing for epoch (${data.epoch})`);\n\t\tif (data.epoch === 1) {\n\t\t\tthis.protocolVersion = data.protocol_version;\n\t\t\tthis.reinit();\n\t\t}\n\t}\n\n\t/**\n\t * Recover from an invalid transition by re-initializing.\n\t *\n\t * @param transitionId - The transition id to invalidate\n\t */\n\tpublic recoverFromInvalidTransition(transitionId: number) {\n\t\tif (this.reinitializing) return;\n\t\tthis.emit('debug', `Invalidating transition ${transitionId}`);\n\t\tthis.reinitializing = true;\n\t\tthis.consecutiveFailures = 0;\n\t\tthis.emit('invalidateTransition', transitionId);\n\t\tthis.reinit();\n\t}\n\n\t/**\n\t * Processes proposals from the MLS group.\n\t *\n\t * @param payload - The binary message payload\n\t * @param connectedClients - The set of connected client IDs\n\t * @returns The payload to send back to the voice server, if there is one\n\t */\n\tpublic processProposals(payload: Buffer, connectedClients: Set<string>): Buffer | undefined {\n\t\tif (!this.session) throw new Error('No session available');\n\t\tconst optype = payload.readUInt8(0) as 0 | 1;\n\t\tconst { commit, welcome } = this.session.processProposals(\n\t\t\toptype,\n\t\t\tpayload.subarray(1),\n\t\t\tArray.from(connectedClients),\n\t\t);\n\t\tthis.emit('debug', 'MLS proposals processed');\n\t\tif (!commit) return;\n\t\treturn welcome ? Buffer.concat([commit, welcome]) : commit;\n\t}\n\n\t/**\n\t * Processes a commit from the MLS group.\n\t *\n\t * @param payload - The payload\n\t * @returns The transaction id and whether it was successful\n\t */\n\tpublic processCommit(payload: Buffer): TransitionResult {\n\t\tif (!this.session) throw new Error('No session available');\n\t\tconst transitionId = payload.readUInt16BE(0);\n\t\ttry {\n\t\t\tthis.session.processCommit(payload.subarray(2));\n\t\t\tif (transitionId === 0) {\n\t\t\t\tthis.reinitializing = false;\n\t\t\t\tthis.lastTransitionId = transitionId;\n\t\t\t} else {\n\t\t\t\tthis.pendingTransitions.set(transitionId, this.protocolVersion);\n\t\t\t}\n\n\t\t\tthis.emit('debug', `MLS commit processed (transition id: ${transitionId})`);\n\t\t\treturn { transitionId, success: true };\n\t\t} catch (error) {\n\t\t\tthis.emit('debug', `MLS commit errored from transition ${transitionId}: ${error}`);\n\t\t\tthis.recoverFromInvalidTransition(transitionId);\n\t\t\treturn { transitionId, success: false };\n\t\t}\n\t}\n\n\t/**\n\t * Processes a welcome from the MLS group.\n\t *\n\t * @param payload - The payload\n\t * @returns The transaction id and whether it was successful\n\t */\n\tpublic processWelcome(payload: Buffer): TransitionResult {\n\t\tif (!this.session) throw new Error('No session available');\n\t\tconst transitionId = payload.readUInt16BE(0);\n\t\ttry {\n\t\t\tthis.session.processWelcome(payload.subarray(2));\n\t\t\tif (transitionId === 0) {\n\t\t\t\tthis.reinitializing = false;\n\t\t\t\tthis.lastTransitionId = transitionId;\n\t\t\t} else {\n\t\t\t\tthis.pendingTransitions.set(transitionId, this.protocolVersion);\n\t\t\t}\n\n\t\t\tthis.emit('debug', `MLS welcome processed (transition id: ${transitionId})`);\n\t\t\treturn { transitionId, success: true };\n\t\t} catch (error) {\n\t\t\tthis.emit('debug', `MLS welcome errored from transition ${transitionId}: ${error}`);\n\t\t\tthis.recoverFromInvalidTransition(transitionId);\n\t\t\treturn { transitionId, success: false };\n\t\t}\n\t}\n\n\t/**\n\t * Encrypt a packet using end-to-end encryption.\n\t *\n\t * @param packet - The packet to encrypt\n\t */\n\tpublic encrypt(packet: Buffer) {\n\t\tif (this.protocolVersion === 0 || !this.session?.ready || packet.equals(SILENCE_FRAME)) return packet;\n\t\treturn this.session.encryptOpus(packet);\n\t}\n\n\t/**\n\t * Decrypt a packet using end-to-end encryption.\n\t *\n\t * @param packet - The packet to decrypt\n\t * @param userId - The user id that sent the packet\n\t * @returns The decrypted packet, or `null` if the decryption failed but should be ignored\n\t */\n\tpublic decrypt(packet: Buffer, userId: string) {\n\t\tconst canDecrypt = this.session?.ready && (this.protocolVersion !== 0 || this.session?.canPassthrough(userId));\n\t\tif (packet.equals(SILENCE_FRAME) || !canDecrypt || !this.session) return packet;\n\t\ttry {\n\t\t\t// @ts-expect-error - const enum is exported and works (todo: drop const modifier on Davey end)\n\t\t\tconst buffer = this.session.decrypt(userId, Davey.MediaType.AUDIO, packet);\n\t\t\tthis.consecutiveFailures = 0;\n\t\t\treturn buffer;\n\t\t} catch (error) {\n\t\t\tif (!this.reinitializing && this.pendingTransitions.size === 0) {\n\t\t\t\tthis.consecutiveFailures++;\n\t\t\t\tthis.emit('debug', `Failed to decrypt a packet (${this.consecutiveFailures} consecutive fails)`);\n\t\t\t\tif (this.consecutiveFailures > this.failureTolerance) {\n\t\t\t\t\tif (this.lastTransitionId) this.recoverFromInvalidTransition(this.lastTransitionId);\n\t\t\t\t\telse throw error;\n\t\t\t\t}\n\t\t\t} else if (this.reinitializing) {\n\t\t\t\tthis.emit('debug', 'Failed to decrypt a packet (reinitializing session)');\n\t\t\t} else if (this.pendingTransitions.size > 0) {\n\t\t\t\tthis.emit('debug', `Failed to decrypt a packet (${this.pendingTransitions.size} pending transition[s])`);\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Resets the session.\n\t */\n\tpublic destroy() {\n\t\ttry {\n\t\t\tthis.session?.reset();\n\t\t} catch {}\n\t}\n}\n"
  },
  {
    "path": "packages/voice/src/networking/Networking.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n/* eslint-disable id-length */\n/* eslint-disable @typescript-eslint/unbound-method */\nimport { Buffer } from 'node:buffer';\nimport crypto from 'node:crypto';\nimport { EventEmitter } from 'node:events';\nimport type { VoiceReceivePayload, VoiceSpeakingFlags } from 'discord-api-types/voice/v8';\nimport { VoiceEncryptionMode, VoiceOpcodes } from 'discord-api-types/voice/v8';\nimport type { CloseEvent } from 'ws';\nimport * as secretbox from '../util/Secretbox';\nimport { RTP_OPUS_PAYLOAD_TYPE } from '../util/constants';\nimport { noop } from '../util/util';\nimport { DAVESession, getMaxProtocolVersion } from './DAVESession';\nimport { VoiceUDPSocket } from './VoiceUDPSocket';\nimport type { BinaryWebSocketMessage } from './VoiceWebSocket';\nimport { VoiceWebSocket } from './VoiceWebSocket';\n\n// The number of audio channels required by Discord\nconst CHANNELS = 2;\nconst TIMESTAMP_INC = (48_000 / 100) * CHANNELS;\nconst MAX_NONCE_SIZE = 2 ** 32 - 1;\n\nexport const SUPPORTED_ENCRYPTION_MODES: VoiceEncryptionMode[] = [VoiceEncryptionMode.AeadXChaCha20Poly1305RtpSize];\n\n// Just in case there's some system that doesn't come with aes-256-gcm, conditionally add it as supported\nif (crypto.getCiphers().includes('aes-256-gcm')) {\n\tSUPPORTED_ENCRYPTION_MODES.unshift(VoiceEncryptionMode.AeadAes256GcmRtpSize);\n}\n\n/**\n * The different statuses that a networking instance can hold. The order\n * of the states between OpeningWs and Ready is chronological (first the\n * instance enters OpeningWs, then it enters Identifying etc.)\n */\nexport enum NetworkingStatusCode {\n\tOpeningWs,\n\tIdentifying,\n\tUdpHandshaking,\n\tSelectingProtocol,\n\tReady,\n\tResuming,\n\tClosed,\n}\n\n/**\n * The initial Networking state. Instances will be in this state when a WebSocket connection to a Discord\n * voice gateway is being opened.\n */\nexport interface NetworkingOpeningWsState {\n\tcode: NetworkingStatusCode.OpeningWs;\n\tconnectionOptions: ConnectionOptions;\n\tws: VoiceWebSocket;\n}\n\n/**\n * The state that a Networking instance will be in when it is attempting to authorize itself.\n */\nexport interface NetworkingIdentifyingState {\n\tcode: NetworkingStatusCode.Identifying;\n\tconnectionOptions: ConnectionOptions;\n\tws: VoiceWebSocket;\n}\n\n/**\n * The state that a Networking instance will be in when opening a UDP connection to the IP and port provided\n * by Discord, as well as performing IP discovery.\n */\nexport interface NetworkingUdpHandshakingState {\n\tcode: NetworkingStatusCode.UdpHandshaking;\n\tconnectionData: Pick<ConnectionData, 'connectedClients' | 'ssrc'>;\n\tconnectionOptions: ConnectionOptions;\n\tudp: VoiceUDPSocket;\n\tws: VoiceWebSocket;\n}\n\n/**\n * The state that a Networking instance will be in when selecting an encryption protocol for audio packets.\n */\nexport interface NetworkingSelectingProtocolState {\n\tcode: NetworkingStatusCode.SelectingProtocol;\n\tconnectionData: Pick<ConnectionData, 'connectedClients' | 'ssrc'>;\n\tconnectionOptions: ConnectionOptions;\n\tudp: VoiceUDPSocket;\n\tws: VoiceWebSocket;\n}\n\n/**\n * The state that a Networking instance will be in when it has a fully established connection to a Discord\n * voice server.\n */\nexport interface NetworkingReadyState {\n\tcode: NetworkingStatusCode.Ready;\n\tconnectionData: ConnectionData;\n\tconnectionOptions: ConnectionOptions;\n\tdave?: DAVESession | undefined;\n\tpreparedPacket?: Buffer | undefined;\n\tudp: VoiceUDPSocket;\n\tws: VoiceWebSocket;\n}\n\n/**\n * The state that a Networking instance will be in when its connection has been dropped unexpectedly, and it\n * is attempting to resume an existing session.\n */\nexport interface NetworkingResumingState {\n\tcode: NetworkingStatusCode.Resuming;\n\tconnectionData: ConnectionData;\n\tconnectionOptions: ConnectionOptions;\n\tdave?: DAVESession | undefined;\n\tpreparedPacket?: Buffer | undefined;\n\tudp: VoiceUDPSocket;\n\tws: VoiceWebSocket;\n}\n\n/**\n * The state that a Networking instance will be in when it has been destroyed. It cannot be recovered from this\n * state.\n */\nexport interface NetworkingClosedState {\n\tcode: NetworkingStatusCode.Closed;\n}\n\n/**\n * The various states that a networking instance can be in.\n */\nexport type NetworkingState =\n\t| NetworkingClosedState\n\t| NetworkingIdentifyingState\n\t| NetworkingOpeningWsState\n\t| NetworkingReadyState\n\t| NetworkingResumingState\n\t| NetworkingSelectingProtocolState\n\t| NetworkingUdpHandshakingState;\n\n/**\n * Details required to connect to the Discord voice gateway. These details\n * are first received on the main bot gateway, in the form of VOICE_SERVER_UPDATE\n * and VOICE_STATE_UPDATE packets.\n */\nexport interface ConnectionOptions {\n\tchannelId: string;\n\tendpoint: string;\n\tserverId: string;\n\tsessionId: string;\n\ttoken: string;\n\tuserId: string;\n}\n\n/**\n * Information about the current connection, e.g. which encryption mode is to be used on\n * the connection, timing information for playback of streams.\n */\nexport interface ConnectionData {\n\tconnectedClients: Set<string>;\n\tencryptionMode: string;\n\tnonce: number;\n\tnonceBuffer: Buffer;\n\tpacketsPlayed: number;\n\tsecretKey: Uint8Array;\n\tsequence: number;\n\tspeaking: boolean;\n\tssrc: number;\n\ttimestamp: number;\n}\n\n/**\n * Options for networking that dictate behavior.\n */\nexport interface NetworkingOptions {\n\tdaveEncryption?: boolean | undefined;\n\tdebug?: boolean | undefined;\n\tdecryptionFailureTolerance?: number | undefined;\n}\n\n/**\n * An empty buffer that is reused in packet encryption by many different networking instances.\n */\nconst nonce = Buffer.alloc(24);\n\nexport interface Networking extends EventEmitter {\n\t/**\n\t * Debug event for Networking.\n\t *\n\t * @eventProperty\n\t */\n\ton(event: 'debug', listener: (message: string) => void): this;\n\ton(event: 'error', listener: (error: Error) => void): this;\n\ton(event: 'stateChange', listener: (oldState: NetworkingState, newState: NetworkingState) => void): this;\n\ton(event: 'close', listener: (code: number) => void): this;\n\ton(event: 'transitioned', listener: (transitionId: number) => void): this;\n}\n\n/**\n * Stringifies a NetworkingState.\n *\n * @param state - The state to stringify\n */\nfunction stringifyState(state: NetworkingState) {\n\treturn JSON.stringify({\n\t\t...state,\n\t\tws: Reflect.has(state, 'ws'),\n\t\tudp: Reflect.has(state, 'udp'),\n\t});\n}\n\n/**\n * Chooses an encryption mode from a list of given options. Chooses the most preferred option.\n *\n * @param options - The available encryption options\n */\nfunction chooseEncryptionMode(options: VoiceEncryptionMode[]): VoiceEncryptionMode {\n\tconst option = options.find((option) => SUPPORTED_ENCRYPTION_MODES.includes(option));\n\tif (!option) {\n\t\t// This should only ever happen if the gateway does not give us any encryption modes we support.\n\t\tthrow new Error(`No compatible encryption modes. Available include: ${options.join(', ')}`);\n\t}\n\n\treturn option;\n}\n\n/**\n * Returns a random number that is in the range of n bits.\n *\n * @param numberOfBits - The number of bits\n */\nfunction randomNBit(numberOfBits: number) {\n\treturn Math.floor(Math.random() * 2 ** numberOfBits);\n}\n\n/**\n * Manages the networking required to maintain a voice connection and dispatch audio packets\n */\nexport class Networking extends EventEmitter {\n\tprivate _state: NetworkingState;\n\n\t/**\n\t * The debug logger function, if debugging is enabled.\n\t */\n\tprivate readonly debug: ((message: string) => void) | null;\n\n\t/**\n\t * The options used to create this Networking instance.\n\t */\n\tprivate readonly options: NetworkingOptions;\n\n\t/**\n\t * Creates a new Networking instance.\n\t */\n\tpublic constructor(connectionOptions: ConnectionOptions, options: NetworkingOptions) {\n\t\tsuper();\n\n\t\tthis.onWsOpen = this.onWsOpen.bind(this);\n\t\tthis.onChildError = this.onChildError.bind(this);\n\t\tthis.onWsPacket = this.onWsPacket.bind(this);\n\t\tthis.onWsBinary = this.onWsBinary.bind(this);\n\t\tthis.onWsClose = this.onWsClose.bind(this);\n\t\tthis.onWsDebug = this.onWsDebug.bind(this);\n\t\tthis.onUdpDebug = this.onUdpDebug.bind(this);\n\t\tthis.onUdpClose = this.onUdpClose.bind(this);\n\t\tthis.onDaveDebug = this.onDaveDebug.bind(this);\n\t\tthis.onDaveKeyPackage = this.onDaveKeyPackage.bind(this);\n\t\tthis.onDaveInvalidateTransition = this.onDaveInvalidateTransition.bind(this);\n\n\t\tthis.debug = options?.debug ? (message: string) => this.emit('debug', message) : null;\n\n\t\tthis._state = {\n\t\t\tcode: NetworkingStatusCode.OpeningWs,\n\t\t\tws: this.createWebSocket(connectionOptions.endpoint),\n\t\t\tconnectionOptions,\n\t\t};\n\t\tthis.options = options;\n\t}\n\n\t/**\n\t * Destroys the Networking instance, transitioning it into the Closed state.\n\t */\n\tpublic destroy() {\n\t\tthis.state = {\n\t\t\tcode: NetworkingStatusCode.Closed,\n\t\t};\n\t}\n\n\t/**\n\t * The current state of the networking instance.\n\t *\n\t * @remarks\n\t * The setter will perform clean-up operations where necessary.\n\t */\n\tpublic get state(): NetworkingState {\n\t\treturn this._state;\n\t}\n\n\tpublic set state(newState: NetworkingState) {\n\t\tconst oldWs = Reflect.get(this._state, 'ws') as VoiceWebSocket | undefined;\n\t\tconst newWs = Reflect.get(newState, 'ws') as VoiceWebSocket | undefined;\n\t\tif (oldWs && oldWs !== newWs) {\n\t\t\t// The old WebSocket is being freed - remove all handlers from it\n\t\t\toldWs.off('debug', this.onWsDebug);\n\t\t\toldWs.on('error', noop);\n\t\t\toldWs.off('error', this.onChildError);\n\t\t\toldWs.off('open', this.onWsOpen);\n\t\t\toldWs.off('packet', this.onWsPacket);\n\t\t\toldWs.off('binary', this.onWsBinary);\n\t\t\toldWs.off('close', this.onWsClose);\n\t\t\toldWs.destroy();\n\t\t}\n\n\t\tconst oldUdp = Reflect.get(this._state, 'udp') as VoiceUDPSocket | undefined;\n\t\tconst newUdp = Reflect.get(newState, 'udp') as VoiceUDPSocket | undefined;\n\n\t\tif (oldUdp && oldUdp !== newUdp) {\n\t\t\toldUdp.on('error', noop);\n\t\t\toldUdp.off('error', this.onChildError);\n\t\t\toldUdp.off('close', this.onUdpClose);\n\t\t\toldUdp.off('debug', this.onUdpDebug);\n\t\t\toldUdp.destroy();\n\t\t}\n\n\t\tconst oldDave = Reflect.get(this._state, 'dave') as DAVESession | undefined;\n\t\tconst newDave = Reflect.get(newState, 'dave') as DAVESession | undefined;\n\n\t\tif (oldDave && oldDave !== newDave) {\n\t\t\toldDave.off('error', this.onChildError);\n\t\t\toldDave.off('debug', this.onDaveDebug);\n\t\t\toldDave.off('keyPackage', this.onDaveKeyPackage);\n\t\t\toldDave.off('invalidateTransition', this.onDaveInvalidateTransition);\n\t\t\toldDave.destroy();\n\t\t}\n\n\t\tconst oldState = this._state;\n\t\tthis._state = newState;\n\t\tthis.emit('stateChange', oldState, newState);\n\n\t\tthis.debug?.(`state change:\\nfrom ${stringifyState(oldState)}\\nto ${stringifyState(newState)}`);\n\t}\n\n\t/**\n\t * Creates a new WebSocket to a Discord Voice gateway.\n\t *\n\t * @param endpoint - The endpoint to connect to\n\t * @param lastSequence - The last sequence to set for this WebSocket\n\t */\n\tprivate createWebSocket(endpoint: string, lastSequence?: number) {\n\t\tconst ws = new VoiceWebSocket(`wss://${endpoint}?v=8`, Boolean(this.debug));\n\n\t\tif (lastSequence !== undefined) {\n\t\t\tws.sequence = lastSequence;\n\t\t}\n\n\t\tws.on('error', this.onChildError);\n\t\tws.once('open', this.onWsOpen);\n\t\tws.on('packet', this.onWsPacket);\n\t\tws.on('binary', this.onWsBinary);\n\t\tws.once('close', this.onWsClose);\n\t\tws.on('debug', this.onWsDebug);\n\n\t\treturn ws;\n\t}\n\n\t/**\n\t * Creates a new DAVE session for this voice connection if we can create one.\n\t *\n\t * @param protocolVersion - The protocol version to use\n\t */\n\tprivate createDaveSession(protocolVersion: number) {\n\t\tif (\n\t\t\tthis.options.daveEncryption === false ||\n\t\t\t(this.state.code !== NetworkingStatusCode.SelectingProtocol &&\n\t\t\t\tthis.state.code !== NetworkingStatusCode.Ready &&\n\t\t\t\tthis.state.code !== NetworkingStatusCode.Resuming)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst session = new DAVESession(\n\t\t\tprotocolVersion,\n\t\t\tthis.state.connectionOptions.userId,\n\t\t\tthis.state.connectionOptions.channelId,\n\t\t\t{\n\t\t\t\tdecryptionFailureTolerance: this.options.decryptionFailureTolerance,\n\t\t\t},\n\t\t);\n\n\t\tsession.on('error', this.onChildError);\n\t\tsession.on('debug', this.onDaveDebug);\n\t\tsession.on('keyPackage', this.onDaveKeyPackage);\n\t\tsession.on('invalidateTransition', this.onDaveInvalidateTransition);\n\t\tsession.reinit();\n\n\t\treturn session;\n\t}\n\n\t/**\n\t * Propagates errors from the children VoiceWebSocket, VoiceUDPSocket and DAVESession.\n\t *\n\t * @param error - The error that was emitted by a child\n\t */\n\tprivate onChildError(error: Error) {\n\t\tthis.emit('error', error);\n\t}\n\n\t/**\n\t * Called when the WebSocket opens. Depending on the state that the instance is in,\n\t * it will either identify with a new session, or it will attempt to resume an existing session.\n\t */\n\tprivate onWsOpen() {\n\t\tif (this.state.code === NetworkingStatusCode.OpeningWs) {\n\t\t\tthis.state.ws.sendPacket({\n\t\t\t\top: VoiceOpcodes.Identify,\n\t\t\t\td: {\n\t\t\t\t\tserver_id: this.state.connectionOptions.serverId,\n\t\t\t\t\tuser_id: this.state.connectionOptions.userId,\n\t\t\t\t\tsession_id: this.state.connectionOptions.sessionId,\n\t\t\t\t\ttoken: this.state.connectionOptions.token,\n\t\t\t\t\tmax_dave_protocol_version: this.options.daveEncryption === false ? 0 : getMaxProtocolVersion(),\n\t\t\t\t},\n\t\t\t});\n\t\t\tthis.state = {\n\t\t\t\t...this.state,\n\t\t\t\tcode: NetworkingStatusCode.Identifying,\n\t\t\t};\n\t\t} else if (this.state.code === NetworkingStatusCode.Resuming) {\n\t\t\tthis.state.ws.sendPacket({\n\t\t\t\top: VoiceOpcodes.Resume,\n\t\t\t\td: {\n\t\t\t\t\tserver_id: this.state.connectionOptions.serverId,\n\t\t\t\t\tsession_id: this.state.connectionOptions.sessionId,\n\t\t\t\t\ttoken: this.state.connectionOptions.token,\n\t\t\t\t\tseq_ack: this.state.ws.sequence,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Called when the WebSocket closes. Based on the reason for closing (given by the code parameter),\n\t * the instance will either attempt to resume, or enter the closed state and emit a 'close' event\n\t * with the close code, allowing the user to decide whether or not they would like to reconnect.\n\t *\n\t * @param code - The close code\n\t */\n\tprivate onWsClose({ code }: CloseEvent) {\n\t\tconst canResume = code === 4_015 || code < 4_000;\n\t\tif (canResume && this.state.code === NetworkingStatusCode.Ready) {\n\t\t\tconst lastSequence = this.state.ws.sequence;\n\t\t\tthis.state = {\n\t\t\t\t...this.state,\n\t\t\t\tcode: NetworkingStatusCode.Resuming,\n\t\t\t\tws: this.createWebSocket(this.state.connectionOptions.endpoint, lastSequence),\n\t\t\t};\n\t\t} else if (this.state.code !== NetworkingStatusCode.Closed) {\n\t\t\tthis.destroy();\n\t\t\tthis.emit('close', code);\n\t\t}\n\t}\n\n\t/**\n\t * Called when the UDP socket has closed itself if it has stopped receiving replies from Discord.\n\t */\n\tprivate onUdpClose() {\n\t\tif (this.state.code === NetworkingStatusCode.Ready) {\n\t\t\tconst lastSequence = this.state.ws.sequence;\n\t\t\tthis.state = {\n\t\t\t\t...this.state,\n\t\t\t\tcode: NetworkingStatusCode.Resuming,\n\t\t\t\tws: this.createWebSocket(this.state.connectionOptions.endpoint, lastSequence),\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Called when a packet is received on the connection's WebSocket.\n\t *\n\t * @param packet - The received packet\n\t */\n\tprivate onWsPacket(packet: VoiceReceivePayload) {\n\t\tif (packet.op === VoiceOpcodes.Hello && this.state.code !== NetworkingStatusCode.Closed) {\n\t\t\tthis.state.ws.setHeartbeatInterval(packet.d.heartbeat_interval);\n\t\t} else if (packet.op === VoiceOpcodes.Ready && this.state.code === NetworkingStatusCode.Identifying) {\n\t\t\tconst { ip, port, ssrc, modes } = packet.d;\n\n\t\t\tconst udp = new VoiceUDPSocket({ ip, port });\n\t\t\tudp.on('error', this.onChildError);\n\t\t\tudp.on('debug', this.onUdpDebug);\n\t\t\tudp.once('close', this.onUdpClose);\n\t\t\tudp\n\t\t\t\t.performIPDiscovery(ssrc)\n\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then\n\t\t\t\t.then((localConfig) => {\n\t\t\t\t\tif (this.state.code !== NetworkingStatusCode.UdpHandshaking) return;\n\t\t\t\t\tthis.state.ws.sendPacket({\n\t\t\t\t\t\top: VoiceOpcodes.SelectProtocol,\n\t\t\t\t\t\td: {\n\t\t\t\t\t\t\tprotocol: 'udp',\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\taddress: localConfig.ip,\n\t\t\t\t\t\t\t\tport: localConfig.port,\n\t\t\t\t\t\t\t\tmode: chooseEncryptionMode(modes),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\tthis.state = {\n\t\t\t\t\t\t...this.state,\n\t\t\t\t\t\tcode: NetworkingStatusCode.SelectingProtocol,\n\t\t\t\t\t};\n\t\t\t\t})\n\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then, promise/prefer-await-to-callbacks\n\t\t\t\t.catch((error: Error) => this.emit('error', error));\n\n\t\t\tthis.state = {\n\t\t\t\t...this.state,\n\t\t\t\tcode: NetworkingStatusCode.UdpHandshaking,\n\t\t\t\tudp,\n\t\t\t\tconnectionData: {\n\t\t\t\t\tssrc,\n\t\t\t\t\tconnectedClients: new Set(),\n\t\t\t\t},\n\t\t\t};\n\t\t} else if (\n\t\t\tpacket.op === VoiceOpcodes.SessionDescription &&\n\t\t\tthis.state.code === NetworkingStatusCode.SelectingProtocol\n\t\t) {\n\t\t\tconst { mode: encryptionMode, secret_key: secretKey, dave_protocol_version: daveProtocolVersion } = packet.d;\n\t\t\tthis.state = {\n\t\t\t\t...this.state,\n\t\t\t\tcode: NetworkingStatusCode.Ready,\n\t\t\t\tdave: this.createDaveSession(daveProtocolVersion),\n\t\t\t\tconnectionData: {\n\t\t\t\t\t...this.state.connectionData,\n\t\t\t\t\tencryptionMode,\n\t\t\t\t\tsecretKey: new Uint8Array(secretKey),\n\t\t\t\t\tsequence: randomNBit(16),\n\t\t\t\t\ttimestamp: randomNBit(32),\n\t\t\t\t\tnonce: 0,\n\t\t\t\t\tnonceBuffer: encryptionMode === 'aead_aes256_gcm_rtpsize' ? Buffer.alloc(12) : Buffer.alloc(24),\n\t\t\t\t\tspeaking: false,\n\t\t\t\t\tpacketsPlayed: 0,\n\t\t\t\t},\n\t\t\t};\n\t\t} else if (packet.op === VoiceOpcodes.Resumed && this.state.code === NetworkingStatusCode.Resuming) {\n\t\t\tthis.state = {\n\t\t\t\t...this.state,\n\t\t\t\tcode: NetworkingStatusCode.Ready,\n\t\t\t};\n\t\t\tthis.state.connectionData.speaking = false;\n\t\t} else if (\n\t\t\t(packet.op === VoiceOpcodes.ClientsConnect || packet.op === VoiceOpcodes.ClientDisconnect) &&\n\t\t\t(this.state.code === NetworkingStatusCode.Ready ||\n\t\t\t\tthis.state.code === NetworkingStatusCode.UdpHandshaking ||\n\t\t\t\tthis.state.code === NetworkingStatusCode.SelectingProtocol ||\n\t\t\t\tthis.state.code === NetworkingStatusCode.Resuming)\n\t\t) {\n\t\t\tconst { connectionData } = this.state;\n\t\t\tif (packet.op === VoiceOpcodes.ClientsConnect)\n\t\t\t\tfor (const id of packet.d.user_ids) connectionData.connectedClients.add(id);\n\t\t\telse {\n\t\t\t\tconnectionData.connectedClients.delete(packet.d.user_id);\n\t\t\t}\n\t\t} else if (\n\t\t\t(this.state.code === NetworkingStatusCode.Ready || this.state.code === NetworkingStatusCode.Resuming) &&\n\t\t\tthis.state.dave\n\t\t) {\n\t\t\tif (packet.op === VoiceOpcodes.DavePrepareTransition) {\n\t\t\t\tconst sendReady = this.state.dave.prepareTransition(packet.d);\n\t\t\t\tif (sendReady)\n\t\t\t\t\tthis.state.ws.sendPacket({\n\t\t\t\t\t\top: VoiceOpcodes.DaveTransitionReady,\n\t\t\t\t\t\td: { transition_id: packet.d.transition_id },\n\t\t\t\t\t});\n\t\t\t\tif (packet.d.transition_id === 0) {\n\t\t\t\t\tthis.emit('transitioned', 0);\n\t\t\t\t}\n\t\t\t} else if (packet.op === VoiceOpcodes.DaveExecuteTransition) {\n\t\t\t\tconst transitioned = this.state.dave.executeTransition(packet.d.transition_id);\n\t\t\t\tif (transitioned) this.emit('transitioned', packet.d.transition_id);\n\t\t\t} else if (packet.op === VoiceOpcodes.DavePrepareEpoch) this.state.dave.prepareEpoch(packet.d);\n\t\t}\n\t}\n\n\t/**\n\t * Called when a binary message is received on the connection's WebSocket.\n\t *\n\t * @param message - The received message\n\t */\n\tprivate onWsBinary(message: BinaryWebSocketMessage) {\n\t\tif (this.state.code === NetworkingStatusCode.Ready && this.state.dave) {\n\t\t\tif (message.op === VoiceOpcodes.DaveMlsExternalSender) {\n\t\t\t\tthis.state.dave.setExternalSender(message.payload);\n\t\t\t} else if (message.op === VoiceOpcodes.DaveMlsProposals) {\n\t\t\t\tconst payload = this.state.dave.processProposals(message.payload, this.state.connectionData.connectedClients);\n\t\t\t\tif (payload) this.state.ws.sendBinaryMessage(VoiceOpcodes.DaveMlsCommitWelcome, payload);\n\t\t\t} else if (message.op === VoiceOpcodes.DaveMlsAnnounceCommitTransition) {\n\t\t\t\tconst { transitionId, success } = this.state.dave.processCommit(message.payload);\n\t\t\t\tif (success) {\n\t\t\t\t\tif (transitionId === 0) this.emit('transitioned', transitionId);\n\t\t\t\t\telse\n\t\t\t\t\t\tthis.state.ws.sendPacket({\n\t\t\t\t\t\t\top: VoiceOpcodes.DaveTransitionReady,\n\t\t\t\t\t\t\td: { transition_id: transitionId },\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (message.op === VoiceOpcodes.DaveMlsWelcome) {\n\t\t\t\tconst { transitionId, success } = this.state.dave.processWelcome(message.payload);\n\t\t\t\tif (success) {\n\t\t\t\t\tif (transitionId === 0) this.emit('transitioned', transitionId);\n\t\t\t\t\telse\n\t\t\t\t\t\tthis.state.ws.sendPacket({\n\t\t\t\t\t\t\top: VoiceOpcodes.DaveTransitionReady,\n\t\t\t\t\t\t\td: { transition_id: transitionId },\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Called when a new key package is ready to be sent to the voice server.\n\t *\n\t * @param keyPackage - The new key package\n\t */\n\tprivate onDaveKeyPackage(keyPackage: Buffer) {\n\t\tif (this.state.code === NetworkingStatusCode.SelectingProtocol || this.state.code === NetworkingStatusCode.Ready)\n\t\t\tthis.state.ws.sendBinaryMessage(VoiceOpcodes.DaveMlsKeyPackage, keyPackage);\n\t}\n\n\t/**\n\t * Called when the DAVE session wants to invalidate their transition and re-initialize.\n\t *\n\t * @param transitionId - The transition to invalidate\n\t */\n\tprivate onDaveInvalidateTransition(transitionId: number) {\n\t\tif (this.state.code === NetworkingStatusCode.SelectingProtocol || this.state.code === NetworkingStatusCode.Ready)\n\t\t\tthis.state.ws.sendPacket({\n\t\t\t\top: VoiceOpcodes.DaveMlsInvalidCommitWelcome,\n\t\t\t\td: { transition_id: transitionId },\n\t\t\t});\n\t}\n\n\t/**\n\t * Propagates debug messages from the child WebSocket.\n\t *\n\t * @param message - The emitted debug message\n\t */\n\tprivate onWsDebug(message: string) {\n\t\tthis.debug?.(`[WS] ${message}`);\n\t}\n\n\t/**\n\t * Propagates debug messages from the child UDPSocket.\n\t *\n\t * @param message - The emitted debug message\n\t */\n\tprivate onUdpDebug(message: string) {\n\t\tthis.debug?.(`[UDP] ${message}`);\n\t}\n\n\t/**\n\t * Propagates debug messages from the child DAVESession.\n\t *\n\t * @param message - The emitted debug message\n\t */\n\tprivate onDaveDebug(message: string) {\n\t\tthis.debug?.(`[DAVE] ${message}`);\n\t}\n\n\t/**\n\t * Prepares an Opus packet for playback. This includes attaching metadata to it and encrypting it.\n\t * It will be stored within the instance, and can be played by dispatchAudio()\n\t *\n\t * @remarks\n\t * Calling this method while there is already a prepared audio packet that has not yet been dispatched\n\t * will overwrite the existing audio packet. This should be avoided.\n\t * @param opusPacket - The Opus packet to encrypt\n\t * @returns The audio packet that was prepared\n\t */\n\tpublic prepareAudioPacket(opusPacket: Buffer) {\n\t\tconst state = this.state;\n\t\tif (state.code !== NetworkingStatusCode.Ready) return;\n\t\tstate.preparedPacket = this.createAudioPacket(opusPacket, state.connectionData, state.dave);\n\t\treturn state.preparedPacket;\n\t}\n\n\t/**\n\t * Dispatches the audio packet previously prepared by prepareAudioPacket(opusPacket). The audio packet\n\t * is consumed and cannot be dispatched again.\n\t */\n\tpublic dispatchAudio() {\n\t\tconst state = this.state;\n\t\tif (state.code !== NetworkingStatusCode.Ready) return false;\n\t\tif (state.preparedPacket !== undefined) {\n\t\t\tthis.playAudioPacket(state.preparedPacket);\n\t\t\tstate.preparedPacket = undefined;\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Plays an audio packet, updating timing metadata used for playback.\n\t *\n\t * @param audioPacket - The audio packet to play\n\t */\n\tprivate playAudioPacket(audioPacket: Buffer) {\n\t\tconst state = this.state;\n\t\tif (state.code !== NetworkingStatusCode.Ready) return;\n\t\tconst { connectionData } = state;\n\t\tconnectionData.packetsPlayed++;\n\t\tconnectionData.sequence++;\n\t\tconnectionData.timestamp += TIMESTAMP_INC;\n\t\tif (connectionData.sequence >= 2 ** 16) connectionData.sequence = 0;\n\t\tif (connectionData.timestamp >= 2 ** 32) connectionData.timestamp = 0;\n\t\tthis.setSpeaking(true);\n\t\tstate.udp.send(audioPacket);\n\t}\n\n\t/**\n\t * Sends a packet to the voice gateway indicating that the client has start/stopped sending\n\t * audio.\n\t *\n\t * @param speaking - Whether or not the client should be shown as speaking\n\t */\n\tpublic setSpeaking(speaking: boolean) {\n\t\tconst state = this.state;\n\t\tif (state.code !== NetworkingStatusCode.Ready) return;\n\t\tif (state.connectionData.speaking === speaking) return;\n\t\tstate.connectionData.speaking = speaking;\n\t\tstate.ws.sendPacket({\n\t\t\top: VoiceOpcodes.Speaking,\n\t\t\td: {\n\t\t\t\tspeaking: (speaking ? 1 : 0) as VoiceSpeakingFlags,\n\t\t\t\tdelay: 0,\n\t\t\t\tssrc: state.connectionData.ssrc,\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Creates a new audio packet from an Opus packet. This involves encrypting the packet,\n\t * then prepending a header that includes metadata.\n\t *\n\t * @param opusPacket - The Opus packet to prepare\n\t * @param connectionData - The current connection data of the instance\n\t * @param daveSession - The DAVE session to use for encryption\n\t */\n\tprivate createAudioPacket(opusPacket: Buffer, connectionData: ConnectionData, daveSession?: DAVESession) {\n\t\tconst rtpHeader = Buffer.alloc(12);\n\t\trtpHeader[0] = 0x80;\n\t\trtpHeader[1] = RTP_OPUS_PAYLOAD_TYPE;\n\n\t\tconst { sequence, timestamp, ssrc } = connectionData;\n\n\t\trtpHeader.writeUIntBE(sequence, 2, 2);\n\t\trtpHeader.writeUIntBE(timestamp, 4, 4);\n\t\trtpHeader.writeUIntBE(ssrc, 8, 4);\n\n\t\trtpHeader.copy(nonce, 0, 0, 12);\n\t\treturn Buffer.concat([rtpHeader, ...this.encryptOpusPacket(opusPacket, connectionData, rtpHeader, daveSession)]);\n\t}\n\n\t/**\n\t * Encrypts an Opus packet using the format agreed upon by the instance and Discord.\n\t *\n\t * @param opusPacket - The Opus packet to encrypt\n\t * @param connectionData - The current connection data of the instance\n\t * @param daveSession - The DAVE session to use for encryption\n\t */\n\tprivate encryptOpusPacket(\n\t\topusPacket: Buffer,\n\t\tconnectionData: ConnectionData,\n\t\tadditionalData: Buffer,\n\t\tdaveSession?: DAVESession,\n\t) {\n\t\tconst { secretKey, encryptionMode } = connectionData;\n\n\t\tconst packet = daveSession?.encrypt(opusPacket) ?? opusPacket;\n\n\t\t// Both supported encryption methods want the nonce to be an incremental integer\n\t\tconnectionData.nonce++;\n\t\tif (connectionData.nonce > MAX_NONCE_SIZE) connectionData.nonce = 0;\n\t\tconnectionData.nonceBuffer.writeUInt32BE(connectionData.nonce, 0);\n\n\t\t// 4 extra bytes of padding on the end of the encrypted packet\n\t\tconst noncePadding = connectionData.nonceBuffer.subarray(0, 4);\n\n\t\tlet encrypted;\n\t\tswitch (encryptionMode) {\n\t\t\tcase 'aead_aes256_gcm_rtpsize': {\n\t\t\t\tconst cipher = crypto.createCipheriv('aes-256-gcm', secretKey, connectionData.nonceBuffer);\n\t\t\t\tcipher.setAAD(additionalData);\n\n\t\t\t\tencrypted = Buffer.concat([cipher.update(packet), cipher.final(), cipher.getAuthTag()]);\n\n\t\t\t\treturn [encrypted, noncePadding];\n\t\t\t}\n\n\t\t\tcase 'aead_xchacha20_poly1305_rtpsize': {\n\t\t\t\tencrypted = secretbox.methods.crypto_aead_xchacha20poly1305_ietf_encrypt(\n\t\t\t\t\tpacket,\n\t\t\t\t\tadditionalData,\n\t\t\t\t\tconnectionData.nonceBuffer,\n\t\t\t\t\tsecretKey,\n\t\t\t\t);\n\n\t\t\t\treturn [encrypted, noncePadding];\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\t// This should never happen. Our encryption mode is chosen from a list given to us by the gateway and checked with the ones we support.\n\t\t\t\tthrow new RangeError(`Unsupported encryption method: ${encryptionMode}`);\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/voice/src/networking/VoiceUDPSocket.ts",
    "content": "import { Buffer } from 'node:buffer';\nimport { createSocket, type Socket } from 'node:dgram';\nimport { EventEmitter } from 'node:events';\nimport { isIPv4 } from 'node:net';\n\n/**\n * Stores an IP address and port. Used to store socket details for the local client as well as\n * for Discord.\n */\nexport interface SocketConfig {\n\tip: string;\n\tport: number;\n}\n\n/**\n * Parses the response from Discord to aid with local IP discovery.\n *\n * @param message - The received message\n */\nexport function parseLocalPacket(message: Buffer): SocketConfig {\n\tconst packet = Buffer.from(message);\n\n\tconst ip = packet.subarray(8, packet.indexOf(0, 8)).toString('utf8');\n\n\tif (!isIPv4(ip)) {\n\t\tthrow new Error('Malformed IP address');\n\t}\n\n\tconst port = packet.readUInt16BE(packet.length - 2);\n\n\treturn { ip, port };\n}\n\n/**\n * The interval in milliseconds at which keep alive datagrams are sent.\n */\nconst KEEP_ALIVE_INTERVAL = 5e3;\n\n/**\n * The maximum value of the keep alive counter.\n */\nconst MAX_COUNTER_VALUE = 2 ** 32 - 1;\n\nexport interface VoiceUDPSocket extends EventEmitter {\n\ton(event: 'error', listener: (error: Error) => void): this;\n\ton(event: 'close', listener: () => void): this;\n\ton(event: 'debug', listener: (message: string) => void): this;\n\ton(event: 'message', listener: (message: Buffer) => void): this;\n}\n\n/**\n * Manages the UDP networking for a voice connection.\n */\nexport class VoiceUDPSocket extends EventEmitter {\n\t/**\n\t * The underlying network Socket for the VoiceUDPSocket.\n\t */\n\tprivate readonly socket: Socket;\n\n\t/**\n\t * The socket details for Discord (remote)\n\t */\n\tprivate readonly remote: SocketConfig;\n\n\t/**\n\t * The counter used in the keep alive mechanism.\n\t */\n\tprivate keepAliveCounter = 0;\n\n\t/**\n\t * The buffer used to write the keep alive counter into.\n\t */\n\tprivate readonly keepAliveBuffer: Buffer;\n\n\t/**\n\t * The Node.js interval for the keep-alive mechanism.\n\t */\n\tprivate readonly keepAliveInterval: NodeJS.Timeout;\n\n\t/**\n\t * The time taken to receive a response to keep alive messages.\n\t *\n\t * @deprecated This field is no longer updated as keep alive messages are no longer tracked.\n\t */\n\tpublic ping?: number;\n\n\t/**\n\t * Creates a new VoiceUDPSocket.\n\t *\n\t * @param remote - Details of the remote socket\n\t */\n\tpublic constructor(remote: SocketConfig) {\n\t\tsuper();\n\t\tthis.socket = createSocket('udp4');\n\t\tthis.socket.on('error', (error: Error) => this.emit('error', error));\n\t\tthis.socket.on('message', (buffer: Buffer) => this.onMessage(buffer));\n\t\tthis.socket.on('close', () => this.emit('close'));\n\t\tthis.remote = remote;\n\t\tthis.keepAliveBuffer = Buffer.alloc(8);\n\t\tthis.keepAliveInterval = setInterval(() => this.keepAlive(), KEEP_ALIVE_INTERVAL);\n\t\tsetImmediate(() => this.keepAlive());\n\t}\n\n\t/**\n\t * Called when a message is received on the UDP socket.\n\t *\n\t * @param buffer - The received buffer\n\t */\n\tprivate onMessage(buffer: Buffer): void {\n\t\t// Propagate the message\n\t\tthis.emit('message', buffer);\n\t}\n\n\t/**\n\t * Called at a regular interval to check whether we are still able to send datagrams to Discord.\n\t */\n\tprivate keepAlive() {\n\t\tthis.keepAliveBuffer.writeUInt32LE(this.keepAliveCounter, 0);\n\t\tthis.send(this.keepAliveBuffer);\n\t\tthis.keepAliveCounter++;\n\t\tif (this.keepAliveCounter > MAX_COUNTER_VALUE) {\n\t\t\tthis.keepAliveCounter = 0;\n\t\t}\n\t}\n\n\t/**\n\t * Sends a buffer to Discord.\n\t *\n\t * @param buffer - The buffer to send\n\t */\n\tpublic send(buffer: Buffer) {\n\t\tthis.socket.send(buffer, this.remote.port, this.remote.ip);\n\t}\n\n\t/**\n\t * Closes the socket, the instance will not be able to be reused.\n\t */\n\tpublic destroy() {\n\t\ttry {\n\t\t\tthis.socket.close();\n\t\t} catch {}\n\n\t\tclearInterval(this.keepAliveInterval);\n\t}\n\n\t/**\n\t * Performs IP discovery to discover the local address and port to be used for the voice connection.\n\t *\n\t * @param ssrc - The SSRC received from Discord\n\t */\n\tpublic async performIPDiscovery(ssrc: number): Promise<SocketConfig> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst listener = (message: Buffer) => {\n\t\t\t\ttry {\n\t\t\t\t\tif (message.readUInt16BE(0) !== 2) return;\n\t\t\t\t\tconst packet = parseLocalPacket(message);\n\t\t\t\t\tthis.socket.off('message', listener);\n\t\t\t\t\tresolve(packet);\n\t\t\t\t} catch {}\n\t\t\t};\n\n\t\t\tthis.socket.on('message', listener);\n\t\t\tthis.socket.once('close', () => reject(new Error('Cannot perform IP discovery - socket closed')));\n\n\t\t\tconst discoveryBuffer = Buffer.alloc(74);\n\n\t\t\tdiscoveryBuffer.writeUInt16BE(1, 0);\n\t\t\tdiscoveryBuffer.writeUInt16BE(70, 2);\n\t\t\tdiscoveryBuffer.writeUInt32BE(ssrc, 4);\n\t\t\tthis.send(discoveryBuffer);\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "packages/voice/src/networking/VoiceWebSocket.ts",
    "content": "import { Buffer } from 'node:buffer';\nimport { EventEmitter } from 'node:events';\nimport type { VoiceSendPayload } from 'discord-api-types/voice/v8';\nimport { VoiceOpcodes } from 'discord-api-types/voice/v8';\nimport WebSocket, { type MessageEvent } from 'ws';\n\n/**\n * A binary WebSocket message.\n */\nexport interface BinaryWebSocketMessage {\n\top: VoiceOpcodes;\n\tpayload: Buffer;\n\tseq: number;\n}\n\nexport interface VoiceWebSocket extends EventEmitter {\n\ton(event: 'error', listener: (error: Error) => void): this;\n\ton(event: 'open', listener: (event: WebSocket.Event) => void): this;\n\ton(event: 'close', listener: (event: WebSocket.CloseEvent) => void): this;\n\t/**\n\t * Debug event for VoiceWebSocket.\n\t *\n\t * @eventProperty\n\t */\n\ton(event: 'debug', listener: (message: string) => void): this;\n\t/**\n\t * Packet event.\n\t *\n\t * @eventProperty\n\t */\n\ton(event: 'packet', listener: (packet: any) => void): this;\n\t/**\n\t * Binary message event.\n\t *\n\t * @eventProperty\n\t */\n\ton(event: 'binary', listener: (message: BinaryWebSocketMessage) => void): this;\n}\n\n/**\n * An extension of the WebSocket class to provide helper functionality when interacting\n * with the Discord Voice gateway.\n */\nexport class VoiceWebSocket extends EventEmitter {\n\t/**\n\t * The current heartbeat interval, if any.\n\t */\n\tprivate heartbeatInterval?: NodeJS.Timeout;\n\n\t/**\n\t * The time (milliseconds since UNIX epoch) that the last heartbeat acknowledgement packet was received.\n\t * This is set to 0 if an acknowledgement packet hasn't been received yet.\n\t */\n\tprivate lastHeartbeatAck: number;\n\n\t/**\n\t * The time (milliseconds since UNIX epoch) that the last heartbeat was sent. This is set to 0 if a heartbeat\n\t * hasn't been sent yet.\n\t */\n\tprivate lastHeartbeatSend: number;\n\n\t/**\n\t * The number of consecutively missed heartbeats.\n\t */\n\tprivate missedHeartbeats = 0;\n\n\t/**\n\t * The last recorded ping.\n\t */\n\tpublic ping?: number;\n\n\t/**\n\t * The last sequence number acknowledged from Discord. Will be `-1` if no sequence numbered messages have been received.\n\t */\n\tpublic sequence = -1;\n\n\t/**\n\t * The debug logger function, if debugging is enabled.\n\t */\n\tprivate readonly debug: ((message: string) => void) | null;\n\n\t/**\n\t * The underlying WebSocket of this wrapper.\n\t */\n\tprivate readonly ws: WebSocket;\n\n\t/**\n\t * Creates a new VoiceWebSocket.\n\t *\n\t * @param address - The address to connect to\n\t */\n\tpublic constructor(address: string, debug: boolean) {\n\t\tsuper();\n\t\tthis.ws = new WebSocket(address);\n\t\tthis.ws.onmessage = (err) => this.onMessage(err);\n\t\tthis.ws.onopen = (err) => this.emit('open', err);\n\t\tthis.ws.onerror = (err: Error | WebSocket.ErrorEvent) => this.emit('error', err instanceof Error ? err : err.error);\n\t\tthis.ws.onclose = (err) => this.emit('close', err);\n\n\t\tthis.lastHeartbeatAck = 0;\n\t\tthis.lastHeartbeatSend = 0;\n\n\t\tthis.debug = debug ? (message: string) => this.emit('debug', message) : null;\n\t}\n\n\t/**\n\t * Destroys the VoiceWebSocket. The heartbeat interval is cleared, and the connection is closed.\n\t */\n\tpublic destroy() {\n\t\ttry {\n\t\t\tthis.debug?.('destroyed');\n\t\t\tthis.setHeartbeatInterval(-1);\n\t\t\tthis.ws.close(1_000);\n\t\t} catch (error) {\n\t\t\tconst err = error as Error;\n\t\t\tthis.emit('error', err);\n\t\t}\n\t}\n\n\t/**\n\t * Handles message events on the WebSocket. Attempts to JSON parse the messages and emit them\n\t * as packets. Binary messages will be parsed and emitted.\n\t *\n\t * @param event - The message event\n\t */\n\tpublic onMessage(event: MessageEvent) {\n\t\tif (event.data instanceof Buffer || event.data instanceof ArrayBuffer) {\n\t\t\tconst buffer = event.data instanceof ArrayBuffer ? Buffer.from(event.data) : event.data;\n\t\t\tconst seq = buffer.readUInt16BE(0);\n\t\t\tconst op = buffer.readUInt8(2);\n\t\t\tconst payload = buffer.subarray(3);\n\n\t\t\tthis.sequence = seq;\n\t\t\tthis.debug?.(`<< [bin] opcode ${op}, seq ${seq}, ${payload.byteLength} bytes`);\n\n\t\t\tthis.emit('binary', { op, seq, payload });\n\t\t\treturn;\n\t\t} else if (typeof event.data !== 'string') {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.debug?.(`<< ${event.data}`);\n\n\t\tlet packet: any;\n\t\ttry {\n\t\t\tpacket = JSON.parse(event.data);\n\t\t} catch (error) {\n\t\t\tconst err = error as Error;\n\t\t\tthis.emit('error', err);\n\t\t\treturn;\n\t\t}\n\n\t\tif (packet.seq) {\n\t\t\tthis.sequence = packet.seq;\n\t\t}\n\n\t\tif (packet.op === VoiceOpcodes.HeartbeatAck) {\n\t\t\tthis.lastHeartbeatAck = Date.now();\n\t\t\tthis.missedHeartbeats = 0;\n\t\t\tthis.ping = this.lastHeartbeatAck - this.lastHeartbeatSend;\n\t\t}\n\n\t\tthis.emit('packet', packet);\n\t}\n\n\t/**\n\t * Sends a JSON-stringifiable packet over the WebSocket.\n\t *\n\t * @param packet - The packet to send\n\t */\n\tpublic sendPacket(packet: VoiceSendPayload) {\n\t\ttry {\n\t\t\tconst stringified = JSON.stringify(packet);\n\t\t\tthis.debug?.(`>> ${stringified}`);\n\t\t\tthis.ws.send(stringified);\n\t\t} catch (error) {\n\t\t\tconst err = error as Error;\n\t\t\tthis.emit('error', err);\n\t\t}\n\t}\n\n\t/**\n\t * Sends a binary message over the WebSocket.\n\t *\n\t * @param opcode - The opcode to use\n\t * @param payload - The payload to send\n\t */\n\tpublic sendBinaryMessage(opcode: VoiceOpcodes, payload: Buffer) {\n\t\ttry {\n\t\t\tconst message = Buffer.concat([new Uint8Array([opcode]), payload]);\n\t\t\tthis.debug?.(`>> [bin] opcode ${opcode}, ${payload.byteLength} bytes`);\n\t\t\tthis.ws.send(message);\n\t\t} catch (error) {\n\t\t\tconst err = error as Error;\n\t\t\tthis.emit('error', err);\n\t\t}\n\t}\n\n\t/**\n\t * Sends a heartbeat over the WebSocket.\n\t */\n\tprivate sendHeartbeat() {\n\t\tthis.lastHeartbeatSend = Date.now();\n\t\tthis.missedHeartbeats++;\n\t\tconst nonce = this.lastHeartbeatSend;\n\t\tthis.sendPacket({\n\t\t\top: VoiceOpcodes.Heartbeat,\n\t\t\t// eslint-disable-next-line id-length\n\t\t\td: {\n\t\t\t\t// eslint-disable-next-line id-length\n\t\t\t\tt: nonce,\n\t\t\t\tseq_ack: this.sequence,\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Sets/clears an interval to send heartbeats over the WebSocket.\n\t *\n\t * @param ms - The interval in milliseconds. If negative, the interval will be unset\n\t */\n\tpublic setHeartbeatInterval(ms: number) {\n\t\tif (this.heartbeatInterval !== undefined) clearInterval(this.heartbeatInterval);\n\t\tif (ms > 0) {\n\t\t\tthis.heartbeatInterval = setInterval(() => {\n\t\t\t\tif (this.lastHeartbeatSend !== 0 && this.missedHeartbeats >= 3) {\n\t\t\t\t\t// Missed too many heartbeats - disconnect\n\t\t\t\t\tthis.ws.close();\n\t\t\t\t\tthis.setHeartbeatInterval(-1);\n\t\t\t\t}\n\n\t\t\t\tthis.sendHeartbeat();\n\t\t\t}, ms);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/voice/src/networking/index.ts",
    "content": "export * from './Networking';\nexport * from './VoiceUDPSocket';\nexport * from './VoiceWebSocket';\nexport * from './DAVESession';\n"
  },
  {
    "path": "packages/voice/src/receive/AudioReceiveStream.ts",
    "content": "import type { Buffer } from 'node:buffer';\nimport process from 'node:process';\nimport { Readable, type ReadableOptions } from 'node:stream';\nimport { SILENCE_FRAME } from '../audio/AudioPlayer';\n\n/**\n * The different behaviors an audio receive stream can have for deciding when to end.\n */\nexport enum EndBehaviorType {\n\t/**\n\t * The stream will only end when manually destroyed.\n\t */\n\tManual,\n\n\t/**\n\t * The stream will end after a given time period of silence/no audio packets.\n\t */\n\tAfterSilence,\n\n\t/**\n\t * The stream will end after a given time period of no audio packets.\n\t */\n\tAfterInactivity,\n}\n\nexport type EndBehavior =\n\t| {\n\t\t\tbehavior: EndBehaviorType.AfterInactivity | EndBehaviorType.AfterSilence;\n\t\t\tduration: number;\n\t  }\n\t| {\n\t\t\tbehavior: EndBehaviorType.Manual;\n\t  };\n\nexport interface AudioReceiveStreamOptions extends ReadableOptions {\n\tend: EndBehavior;\n}\n\nexport function createDefaultAudioReceiveStreamOptions(): AudioReceiveStreamOptions {\n\treturn {\n\t\tend: {\n\t\t\tbehavior: EndBehaviorType.Manual,\n\t\t},\n\t};\n}\n\n/**\n * A readable stream of Opus packets received from a specific entity\n * in a Discord voice connection.\n */\nexport class AudioReceiveStream extends Readable {\n\t/**\n\t * The end behavior of the receive stream.\n\t */\n\tpublic readonly end: EndBehavior;\n\n\tprivate endTimeout?: NodeJS.Timeout;\n\n\tpublic constructor(options: AudioReceiveStreamOptions) {\n\t\tconst { end, ...rest } = options;\n\n\t\tsuper({\n\t\t\t...rest,\n\t\t\tobjectMode: true,\n\t\t});\n\n\t\tthis.end = end;\n\t}\n\n\tpublic override push(buffer: Buffer | null) {\n\t\tif (\n\t\t\tbuffer &&\n\t\t\t(this.end.behavior === EndBehaviorType.AfterInactivity ||\n\t\t\t\t(this.end.behavior === EndBehaviorType.AfterSilence &&\n\t\t\t\t\t(buffer.compare(SILENCE_FRAME) !== 0 || this.endTimeout === undefined)))\n\t\t) {\n\t\t\tthis.renewEndTimeout(this.end);\n\t\t}\n\n\t\tif (buffer === null) {\n\t\t\t// null marks EOF for stream\n\t\t\tprocess.nextTick(() => this.destroy());\n\t\t}\n\n\t\treturn super.push(buffer);\n\t}\n\n\tprivate renewEndTimeout(end: EndBehavior & { duration: number }) {\n\t\tif (this.endTimeout) {\n\t\t\tclearTimeout(this.endTimeout);\n\t\t}\n\n\t\tthis.endTimeout = setTimeout(() => this.push(null), end.duration);\n\t}\n\n\tpublic override _read() {}\n}\n"
  },
  {
    "path": "packages/voice/src/receive/SSRCMap.ts",
    "content": "import { EventEmitter } from 'node:events';\n\n/**\n * The known data for a user in a Discord voice connection.\n */\nexport interface VoiceUserData {\n\t/**\n\t * The SSRC of the user's audio stream.\n\t */\n\taudioSSRC: number;\n\n\t/**\n\t * The Discord user id of the user.\n\t */\n\tuserId: string;\n\n\t/**\n\t * The SSRC of the user's video stream (if one exists)\n\t * Cannot be 0. If undefined, the user has no video stream.\n\t */\n\tvideoSSRC?: number;\n}\n\nexport interface SSRCMap extends EventEmitter {\n\ton(event: 'create', listener: (newData: VoiceUserData) => void): this;\n\ton(event: 'update', listener: (oldData: VoiceUserData | undefined, newData: VoiceUserData) => void): this;\n\ton(event: 'delete', listener: (deletedData: VoiceUserData) => void): this;\n}\n\n/**\n * Maps audio SSRCs to data of users in voice connections.\n */\nexport class SSRCMap extends EventEmitter {\n\t/**\n\t * The underlying map.\n\t */\n\tprivate readonly map: Map<number, VoiceUserData>;\n\n\tpublic constructor() {\n\t\tsuper();\n\t\tthis.map = new Map();\n\t}\n\n\t/**\n\t * Updates the map with new user data\n\t *\n\t * @param data - The data to update with\n\t */\n\tpublic update(data: VoiceUserData) {\n\t\tconst existing = this.map.get(data.audioSSRC);\n\n\t\tconst newValue = {\n\t\t\t...this.map.get(data.audioSSRC),\n\t\t\t...data,\n\t\t};\n\n\t\tthis.map.set(data.audioSSRC, newValue);\n\t\tif (!existing) this.emit('create', newValue);\n\t\tthis.emit('update', existing, newValue);\n\t}\n\n\t/**\n\t * Gets the stored voice data of a user.\n\t *\n\t * @param target - The target, either their user id or audio SSRC\n\t */\n\tpublic get(target: number | string) {\n\t\tif (typeof target === 'number') {\n\t\t\treturn this.map.get(target);\n\t\t}\n\n\t\tfor (const data of this.map.values()) {\n\t\t\tif (data.userId === target) {\n\t\t\t\treturn data;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Deletes the stored voice data about a user.\n\t *\n\t * @param target - The target of the delete operation, either their audio SSRC or user id\n\t * @returns The data that was deleted, if any\n\t */\n\tpublic delete(target: number | string) {\n\t\tif (typeof target === 'number') {\n\t\t\tconst existing = this.map.get(target);\n\t\t\tif (existing) {\n\t\t\t\tthis.map.delete(target);\n\t\t\t\tthis.emit('delete', existing);\n\t\t\t}\n\n\t\t\treturn existing;\n\t\t}\n\n\t\tfor (const [audioSSRC, data] of this.map.entries()) {\n\t\t\tif (data.userId === target) {\n\t\t\t\tthis.map.delete(audioSSRC);\n\t\t\t\tthis.emit('delete', data);\n\t\t\t\treturn data;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n}\n"
  },
  {
    "path": "packages/voice/src/receive/SpeakingMap.ts",
    "content": "/* eslint-disable @typescript-eslint/unified-signatures */\nimport { EventEmitter } from 'node:events';\n\nexport interface SpeakingMap extends EventEmitter {\n\t/**\n\t * Emitted when a user starts speaking.\n\t *\n\t * @eventProperty\n\t */\n\ton(event: 'start', listener: (userId: string) => void): this;\n\n\t/**\n\t * Emitted when a user ends speaking.\n\t *\n\t * @eventProperty\n\t */\n\ton(event: 'end', listener: (userId: string) => void): this;\n}\n\n/**\n * Tracks the speaking states of users in a voice channel.\n */\nexport class SpeakingMap extends EventEmitter {\n\t/**\n\t * The delay after a packet is received from a user until they're marked as not speaking anymore.\n\t */\n\tpublic static readonly DELAY = 100;\n\n\t/**\n\t * The currently speaking users, mapped to the milliseconds since UNIX epoch at which they started speaking.\n\t */\n\tpublic readonly users: Map<string, number>;\n\n\tprivate readonly speakingTimeouts: Map<string, NodeJS.Timeout>;\n\n\tpublic constructor() {\n\t\tsuper();\n\t\tthis.users = new Map();\n\t\tthis.speakingTimeouts = new Map();\n\t}\n\n\tpublic onPacket(userId: string) {\n\t\tconst timeout = this.speakingTimeouts.get(userId);\n\t\tif (timeout) {\n\t\t\tclearTimeout(timeout);\n\t\t} else {\n\t\t\tthis.users.set(userId, Date.now());\n\t\t\tthis.emit('start', userId);\n\t\t}\n\n\t\tthis.startTimeout(userId);\n\t}\n\n\tprivate startTimeout(userId: string) {\n\t\tthis.speakingTimeouts.set(\n\t\t\tuserId,\n\t\t\tsetTimeout(() => {\n\t\t\t\tthis.emit('end', userId);\n\t\t\t\tthis.speakingTimeouts.delete(userId);\n\t\t\t\tthis.users.delete(userId);\n\t\t\t}, SpeakingMap.DELAY),\n\t\t);\n\t}\n}\n"
  },
  {
    "path": "packages/voice/src/receive/VoiceReceiver.ts",
    "content": "/* eslint-disable jsdoc/check-param-names */\n\nimport { Buffer } from 'node:buffer';\nimport crypto from 'node:crypto';\nimport type { VoiceReceivePayload } from 'discord-api-types/voice/v8';\nimport { VoiceOpcodes } from 'discord-api-types/voice/v8';\nimport { VoiceConnectionStatus, type VoiceConnection } from '../VoiceConnection';\nimport { NetworkingStatusCode, type ConnectionData } from '../networking/Networking';\nimport { methods } from '../util/Secretbox';\nimport { RTP_OPUS_PAYLOAD_TYPE } from '../util/constants';\nimport {\n\tAudioReceiveStream,\n\tcreateDefaultAudioReceiveStreamOptions,\n\ttype AudioReceiveStreamOptions,\n} from './AudioReceiveStream';\nimport { SSRCMap } from './SSRCMap';\nimport { SpeakingMap } from './SpeakingMap';\n\nconst HEADER_EXTENSION_BYTE = Buffer.from([0xbe, 0xde]);\nconst UNPADDED_NONCE_LENGTH = 4;\nconst AUTH_TAG_LENGTH = 16;\n\n/**\n * Attaches to a VoiceConnection, allowing you to receive audio packets from other\n * users that are speaking.\n *\n * @beta\n */\nexport class VoiceReceiver {\n\t/**\n\t * The attached connection of this receiver.\n\t */\n\tpublic readonly voiceConnection;\n\n\t/**\n\t * Maps SSRCs to Discord user ids.\n\t */\n\tpublic readonly ssrcMap: SSRCMap;\n\n\t/**\n\t * The current audio subscriptions of this receiver.\n\t */\n\tpublic readonly subscriptions: Map<string, AudioReceiveStream>;\n\n\t/**\n\t * The connection data of the receiver.\n\t *\n\t * @internal\n\t */\n\tpublic connectionData: Partial<ConnectionData>;\n\n\t/**\n\t * The speaking map of the receiver.\n\t */\n\tpublic readonly speaking: SpeakingMap;\n\n\tpublic constructor(voiceConnection: VoiceConnection) {\n\t\tthis.voiceConnection = voiceConnection;\n\t\tthis.ssrcMap = new SSRCMap();\n\t\tthis.speaking = new SpeakingMap();\n\t\tthis.subscriptions = new Map();\n\t\tthis.connectionData = {};\n\n\t\tthis.onWsPacket = this.onWsPacket.bind(this);\n\t\tthis.onUdpMessage = this.onUdpMessage.bind(this);\n\t}\n\n\t/**\n\t * Called when a packet is received on the attached connection's WebSocket.\n\t *\n\t * @param packet - The received packet\n\t * @internal\n\t */\n\tpublic onWsPacket(packet: VoiceReceivePayload) {\n\t\tif (packet.op === VoiceOpcodes.ClientDisconnect) {\n\t\t\tthis.ssrcMap.delete(packet.d.user_id);\n\t\t} else if (packet.op === VoiceOpcodes.Speaking) {\n\t\t\tthis.ssrcMap.update({ userId: packet.d.user_id, audioSSRC: packet.d.ssrc });\n\t\t}\n\t}\n\n\tprivate decrypt(buffer: Buffer, mode: string, nonce: Buffer, secretKey: Uint8Array) {\n\t\t// Copy the last 4 bytes of unpadded nonce to the padding of (12 - 4) or (24 - 4) bytes\n\t\tbuffer.copy(nonce, 0, buffer.length - UNPADDED_NONCE_LENGTH);\n\n\t\tlet headerSize = 12;\n\t\tconst first = buffer.readUint8();\n\t\tif ((first >> 4) & 0x01) headerSize += 4;\n\n\t\t// The unencrypted RTP header contains 12 bytes, HEADER_EXTENSION and the extension size\n\t\tconst header = buffer.subarray(0, headerSize);\n\n\t\t// Encrypted contains the extension, if any, the opus packet, and the auth tag\n\t\tconst encrypted = buffer.subarray(headerSize, buffer.length - AUTH_TAG_LENGTH - UNPADDED_NONCE_LENGTH);\n\t\tconst authTag = buffer.subarray(\n\t\t\tbuffer.length - AUTH_TAG_LENGTH - UNPADDED_NONCE_LENGTH,\n\t\t\tbuffer.length - UNPADDED_NONCE_LENGTH,\n\t\t);\n\n\t\tswitch (mode) {\n\t\t\tcase 'aead_aes256_gcm_rtpsize': {\n\t\t\t\tconst decipheriv = crypto.createDecipheriv('aes-256-gcm', secretKey, nonce);\n\t\t\t\tdecipheriv.setAAD(header);\n\t\t\t\tdecipheriv.setAuthTag(authTag);\n\n\t\t\t\treturn Buffer.concat([decipheriv.update(encrypted), decipheriv.final()]);\n\t\t\t}\n\n\t\t\tcase 'aead_xchacha20_poly1305_rtpsize': {\n\t\t\t\t// Combined mode expects authtag in the encrypted message\n\t\t\t\treturn Buffer.from(\n\t\t\t\t\tmethods.crypto_aead_xchacha20poly1305_ietf_decrypt(\n\t\t\t\t\t\tBuffer.concat([encrypted, authTag]),\n\t\t\t\t\t\theader,\n\t\t\t\t\t\tnonce,\n\t\t\t\t\t\tsecretKey,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tthrow new RangeError(`Unsupported decryption method: ${mode}`);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Parses an audio packet, decrypting it to yield an Opus packet.\n\t *\n\t * @param buffer - The buffer to parse\n\t * @param mode - The encryption mode\n\t * @param nonce - The nonce buffer used by the connection for encryption\n\t * @param secretKey - The secret key used by the connection for encryption\n\t * @param userId - The user id that sent the packet\n\t * @returns The parsed Opus packet\n\t */\n\tprivate parsePacket(buffer: Buffer, mode: string, nonce: Buffer, secretKey: Uint8Array, userId: string) {\n\t\tlet packet: Buffer = this.decrypt(buffer, mode, nonce, secretKey);\n\t\tif (!packet) throw new Error('Failed to parse packet');\n\n\t\t// Strip padding (RFC3550 5.1)\n\t\tconst hasPadding = buffer[0] && Boolean(buffer[0] & 0b100000);\n\t\tif (hasPadding) {\n\t\t\tconst paddingAmount = packet[packet.length - 1]!;\n\t\t\tif (paddingAmount < packet.length) {\n\t\t\t\tpacket = packet.subarray(0, packet.length - paddingAmount);\n\t\t\t}\n\t\t}\n\n\t\t// Strip decrypted RTP Header Extension if present\n\t\t// The header is only indicated in the original data, so compare with buffer first\n\t\tif (buffer.subarray(12, 14).compare(HEADER_EXTENSION_BYTE) === 0) {\n\t\t\tconst headerExtensionLength = buffer.subarray(14).readUInt16BE();\n\t\t\tpacket = packet.subarray(4 * headerExtensionLength);\n\t\t}\n\n\t\t// Decrypt packet if in a DAVE session.\n\t\tif (\n\t\t\tthis.voiceConnection.state.status === VoiceConnectionStatus.Ready &&\n\t\t\t(this.voiceConnection.state.networking.state.code === NetworkingStatusCode.Ready ||\n\t\t\t\tthis.voiceConnection.state.networking.state.code === NetworkingStatusCode.Resuming)\n\t\t) {\n\t\t\tconst daveSession = this.voiceConnection.state.networking.state.dave;\n\t\t\tif (daveSession) packet = daveSession.decrypt(packet, userId)!;\n\t\t}\n\n\t\treturn packet;\n\t}\n\n\t/**\n\t * Called when the UDP socket of the attached connection receives a message.\n\t *\n\t * @param msg - The received message\n\t * @internal\n\t */\n\tpublic onUdpMessage(msg: Buffer) {\n\t\tif (msg.length <= 8) return;\n\t\tconst ssrc = msg.readUInt32BE(8);\n\n\t\tconst userData = this.ssrcMap.get(ssrc);\n\t\tif (!userData) return;\n\n\t\tthis.speaking.onPacket(userData.userId);\n\n\t\tconst stream = this.subscriptions.get(userData.userId);\n\t\tif (!stream) return;\n\n\t\tif (this.connectionData.encryptionMode && this.connectionData.nonceBuffer && this.connectionData.secretKey) {\n\t\t\t// As a guard, we shouldn't parse packets that (1) aren't voice packets and (2) are not in the right RTP version\n\t\t\tif ((msg[1]! & 0x7f) !== RTP_OPUS_PAYLOAD_TYPE) return;\n\n\t\t\t// Ignore packets not in RTP version 2\n\t\t\tconst rtpVersion = msg[0]! >> 6;\n\t\t\tif (rtpVersion !== 2) return;\n\n\t\t\ttry {\n\t\t\t\tconst packet = this.parsePacket(\n\t\t\t\t\tmsg,\n\t\t\t\t\tthis.connectionData.encryptionMode,\n\t\t\t\t\tthis.connectionData.nonceBuffer,\n\t\t\t\t\tthis.connectionData.secretKey,\n\t\t\t\t\tuserData.userId,\n\t\t\t\t);\n\t\t\t\tif (packet) stream.push(packet);\n\t\t\t} catch (error) {\n\t\t\t\tstream.destroy(error as Error);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates a subscription for the given user id.\n\t *\n\t * @param target - The id of the user to subscribe to\n\t * @returns A readable stream of Opus packets received from the target\n\t */\n\tpublic subscribe(userId: string, options?: Partial<AudioReceiveStreamOptions>) {\n\t\tconst existing = this.subscriptions.get(userId);\n\t\tif (existing) return existing;\n\n\t\tconst stream = new AudioReceiveStream({\n\t\t\t...createDefaultAudioReceiveStreamOptions(),\n\t\t\t...options,\n\t\t});\n\n\t\tstream.once('close', () => this.subscriptions.delete(userId));\n\t\tthis.subscriptions.set(userId, stream);\n\t\treturn stream;\n\t}\n}\n"
  },
  {
    "path": "packages/voice/src/receive/index.ts",
    "content": "export * from './VoiceReceiver';\nexport * from './SSRCMap';\nexport * from './AudioReceiveStream';\nexport * from './SpeakingMap';\n"
  },
  {
    "path": "packages/voice/src/util/Secretbox.ts",
    "content": "import { Buffer } from 'node:buffer';\n\ninterface Methods {\n\tcrypto_aead_xchacha20poly1305_ietf_decrypt(\n\t\tcipherText: Buffer,\n\t\tadditionalData: Buffer,\n\t\tnonce: Buffer,\n\t\tkey: Uint8Array,\n\t): Buffer;\n\tcrypto_aead_xchacha20poly1305_ietf_encrypt(\n\t\tplaintext: Buffer,\n\t\tadditionalData: Buffer,\n\t\tnonce: Buffer,\n\t\tkey: Uint8Array,\n\t): Buffer;\n}\n\nconst libs = {\n\t'sodium-native': (sodium: any): Methods => ({\n\t\tcrypto_aead_xchacha20poly1305_ietf_decrypt: (\n\t\t\tcipherText: Buffer,\n\t\t\tadditionalData: Buffer,\n\t\t\tnonce: Buffer,\n\t\t\tkey: Uint8Array,\n\t\t) => {\n\t\t\tconst message = Buffer.alloc(cipherText.length - sodium.crypto_aead_xchacha20poly1305_ietf_ABYTES);\n\t\t\tsodium.crypto_aead_xchacha20poly1305_ietf_decrypt(message, null, cipherText, additionalData, nonce, key);\n\t\t\treturn message;\n\t\t},\n\t\tcrypto_aead_xchacha20poly1305_ietf_encrypt: (\n\t\t\tplaintext: Buffer,\n\t\t\tadditionalData: Buffer,\n\t\t\tnonce: Buffer,\n\t\t\tkey: Uint8Array,\n\t\t) => {\n\t\t\tconst cipherText = Buffer.alloc(plaintext.length + sodium.crypto_aead_xchacha20poly1305_ietf_ABYTES);\n\t\t\tsodium.crypto_aead_xchacha20poly1305_ietf_encrypt(cipherText, plaintext, additionalData, null, nonce, key);\n\t\t\treturn cipherText;\n\t\t},\n\t}),\n\tsodium: (sodium: any): Methods => ({\n\t\tcrypto_aead_xchacha20poly1305_ietf_decrypt: (\n\t\t\tcipherText: Buffer,\n\t\t\tadditionalData: Buffer,\n\t\t\tnonce: Buffer,\n\t\t\tkey: Uint8Array,\n\t\t) => sodium.api.crypto_aead_xchacha20poly1305_ietf_decrypt(cipherText, additionalData, null, nonce, key),\n\t\tcrypto_aead_xchacha20poly1305_ietf_encrypt: (\n\t\t\tplaintext: Buffer,\n\t\t\tadditionalData: Buffer,\n\t\t\tnonce: Buffer,\n\t\t\tkey: Uint8Array,\n\t\t) => sodium.api.crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, additionalData, null, nonce, key),\n\t}),\n\t'libsodium-wrappers': (sodium: any): Methods => ({\n\t\tcrypto_aead_xchacha20poly1305_ietf_decrypt: (\n\t\t\tcipherText: Buffer,\n\t\t\tadditionalData: Buffer,\n\t\t\tnonce: Buffer,\n\t\t\tkey: Uint8Array,\n\t\t) => sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(null, cipherText, additionalData, nonce, key),\n\t\tcrypto_aead_xchacha20poly1305_ietf_encrypt: (\n\t\t\tplaintext: Buffer,\n\t\t\tadditionalData: Buffer,\n\t\t\tnonce: Buffer,\n\t\t\tkey: Uint8Array,\n\t\t) => sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, additionalData, null, nonce, key),\n\t}),\n\t'@stablelib/xchacha20poly1305': (stablelib: any): Methods => ({\n\t\tcrypto_aead_xchacha20poly1305_ietf_decrypt(plaintext, additionalData, nonce, key) {\n\t\t\tconst crypto = new stablelib.XChaCha20Poly1305(key);\n\t\t\treturn crypto.open(nonce, plaintext, additionalData);\n\t\t},\n\t\tcrypto_aead_xchacha20poly1305_ietf_encrypt(cipherText, additionalData, nonce, key) {\n\t\t\tconst crypto = new stablelib.XChaCha20Poly1305(key);\n\t\t\treturn crypto.seal(nonce, cipherText, additionalData);\n\t\t},\n\t}),\n\t'@noble/ciphers/chacha.js': (noble: any): Methods => ({\n\t\tcrypto_aead_xchacha20poly1305_ietf_decrypt(cipherText, additionalData, nonce, key) {\n\t\t\tconst chacha = noble.xchacha20poly1305(key, nonce, additionalData);\n\t\t\treturn chacha.decrypt(cipherText);\n\t\t},\n\t\tcrypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, additionalData, nonce, key) {\n\t\t\tconst chacha = noble.xchacha20poly1305(key, nonce, additionalData);\n\t\t\treturn chacha.encrypt(plaintext);\n\t\t},\n\t}),\n} as const;\n\nconst fallbackError = () => {\n\tthrow new Error(\n\t\t`Cannot play audio as no valid encryption package is installed.\n- Install one of:\n  - sodium\n  - libsodium-wrappers\n  - @stablelib/xchacha20poly1305\n  - @noble/ciphers.\n- Use the generateDependencyReport() function for more information.\\n`,\n\t);\n};\n\nconst methods: Methods = {\n\tcrypto_aead_xchacha20poly1305_ietf_encrypt: fallbackError,\n\tcrypto_aead_xchacha20poly1305_ietf_decrypt: fallbackError,\n};\n\n// eslint-disable-next-line no-async-promise-executor\nexport const secretboxLoadPromise = new Promise<void>(async (resolve) => {\n\tfor (const libName of Object.keys(libs) as (keyof typeof libs)[]) {\n\t\ttry {\n\t\t\tconst lib = await import(libName);\n\n\t\t\tif (libName === 'libsodium-wrappers' && lib.ready) {\n\t\t\t\tawait lib.ready;\n\t\t\t}\n\n\t\t\tObject.assign(methods, libs[libName](lib));\n\n\t\t\tbreak;\n\t\t} catch {}\n\t}\n\n\tresolve();\n});\n\nexport { methods };\n"
  },
  {
    "path": "packages/voice/src/util/abortAfter.ts",
    "content": "/**\n * Creates an abort controller that aborts after the given time.\n *\n * @param delay - The time in milliseconds to wait before aborting\n */\nexport function abortAfter(delay: number): [AbortController, AbortSignal] {\n\tconst ac = new AbortController();\n\tconst timeout = setTimeout(() => ac.abort(), delay);\n\tac.signal.addEventListener('abort', () => clearTimeout(timeout));\n\treturn [ac, ac.signal];\n}\n"
  },
  {
    "path": "packages/voice/src/util/adapter.ts",
    "content": "import type { GatewayVoiceServerUpdateDispatchData, GatewayVoiceStateUpdateDispatchData } from 'discord-api-types/v10';\n\n/**\n * Methods that are provided by the \\@discordjs/voice library to implementations of\n * Discord gateway DiscordGatewayAdapters.\n */\nexport interface DiscordGatewayAdapterLibraryMethods {\n\t/**\n\t * Call this when the adapter can no longer be used (e.g. due to a disconnect from the main gateway)\n\t */\n\tdestroy(): void;\n\t/**\n\t * Call this when you receive a VOICE_SERVER_UPDATE payload that is relevant to the adapter.\n\t *\n\t * @param data - The inner data of the VOICE_SERVER_UPDATE payload\n\t */\n\tonVoiceServerUpdate(data: GatewayVoiceServerUpdateDispatchData): void;\n\t/**\n\t * Call this when you receive a VOICE_STATE_UPDATE payload that is relevant to the adapter.\n\t *\n\t * @param data - The inner data of the VOICE_STATE_UPDATE payload\n\t */\n\tonVoiceStateUpdate(data: GatewayVoiceStateUpdateDispatchData): void;\n}\n\n/**\n * Methods that are provided by the implementer of a Discord gateway DiscordGatewayAdapter.\n */\nexport interface DiscordGatewayAdapterImplementerMethods {\n\t/**\n\t * This will be called by \\@discordjs/voice when the adapter can safely be destroyed as it will no\n\t * longer be used.\n\t */\n\tdestroy(): void;\n\t/**\n\t * Implement this method such that the given payload is sent to the main Discord gateway connection.\n\t *\n\t * @param payload - The payload to send to the main Discord gateway connection\n\t * @returns `false` if the payload definitely failed to send - in this case, the voice connection disconnects\n\t */\n\tsendPayload(payload: any): boolean;\n}\n\n/**\n * A function used to build adapters. It accepts a methods parameter that contains functions that\n * can be called by the implementer when new data is received on its gateway connection. In return,\n * the implementer will return some methods that the library can call - e.g. to send messages on\n * the gateway, or to signal that the adapter can be removed.\n */\nexport type DiscordGatewayAdapterCreator = (\n\tmethods: DiscordGatewayAdapterLibraryMethods,\n) => DiscordGatewayAdapterImplementerMethods;\n"
  },
  {
    "path": "packages/voice/src/util/constants.ts",
    "content": "export const RTP_OPUS_PAYLOAD_TYPE = 0x78;\n"
  },
  {
    "path": "packages/voice/src/util/demuxProbe.ts",
    "content": "import { Buffer } from 'node:buffer';\nimport process from 'node:process';\nimport { Readable } from 'node:stream';\nimport prism from 'prism-media';\nimport { StreamType } from '..';\nimport { noop } from './util';\n\n/**\n * Takes an Opus Head, and verifies whether the associated Opus audio is suitable to play in a Discord voice channel.\n *\n * @param opusHead - The Opus Head to validate\n * @returns `true` if suitable to play in a Discord voice channel, otherwise `false`\n */\nexport function validateDiscordOpusHead(opusHead: Buffer): boolean {\n\tconst channels = opusHead.readUInt8(9);\n\tconst sampleRate = opusHead.readUInt32LE(12);\n\treturn channels === 2 && sampleRate === 48_000;\n}\n\n/**\n * The resulting information after probing an audio stream\n */\nexport interface ProbeInfo {\n\t/**\n\t * The readable audio stream to use. You should use this rather than the input stream, as the probing\n\t * function can sometimes read the input stream to its end and cause the stream to close.\n\t */\n\tstream: Readable;\n\n\t/**\n\t * The recommended stream type for this audio stream.\n\t */\n\ttype: StreamType;\n}\n\n/**\n * Attempt to probe a readable stream to figure out whether it can be demuxed using an Ogg or WebM Opus demuxer.\n *\n * @param stream - The readable stream to probe\n * @param probeSize - The number of bytes to attempt to read before giving up on the probe\n * @param validator - The Opus Head validator function\n * @experimental\n */\nexport async function demuxProbe(\n\tstream: Readable,\n\tprobeSize = 1_024,\n\tvalidator = validateDiscordOpusHead,\n): Promise<ProbeInfo> {\n\treturn new Promise((resolve, reject) => {\n\t\t// Preconditions\n\t\tif (stream.readableObjectMode) {\n\t\t\treject(new Error('Cannot probe a readable stream in object mode'));\n\t\t\treturn;\n\t\t}\n\n\t\tif (stream.readableEnded) {\n\t\t\treject(new Error('Cannot probe a stream that has ended'));\n\t\t\treturn;\n\t\t}\n\n\t\tlet readBuffer = Buffer.alloc(0);\n\n\t\tlet resolved: StreamType | undefined;\n\n\t\tconst finish = (type: StreamType) => {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-use-before-define\n\t\t\tstream.off('data', onData);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-use-before-define\n\t\t\tstream.off('close', onClose);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-use-before-define\n\t\t\tstream.off('end', onClose);\n\t\t\tstream.pause();\n\t\t\tresolved = type;\n\t\t\tif (stream.readableEnded) {\n\t\t\t\tresolve({\n\t\t\t\t\tstream: Readable.from(readBuffer),\n\t\t\t\t\ttype,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tif (readBuffer.length > 0) {\n\t\t\t\t\tstream.push(readBuffer);\n\t\t\t\t}\n\n\t\t\t\tresolve({\n\t\t\t\t\tstream,\n\t\t\t\t\ttype,\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\n\t\tconst foundHead = (type: StreamType) => (head: Buffer) => {\n\t\t\tif (validator(head)) {\n\t\t\t\tfinish(type);\n\t\t\t}\n\t\t};\n\n\t\tconst webm = new prism.opus.WebmDemuxer();\n\t\twebm.once('error', noop);\n\t\twebm.on('head', foundHead(StreamType.WebmOpus));\n\n\t\tconst ogg = new prism.opus.OggDemuxer();\n\t\togg.once('error', noop);\n\t\togg.on('head', foundHead(StreamType.OggOpus));\n\n\t\tconst onClose = () => {\n\t\t\tif (!resolved) {\n\t\t\t\tfinish(StreamType.Arbitrary);\n\t\t\t}\n\t\t};\n\n\t\tconst onData = (buffer: Buffer) => {\n\t\t\treadBuffer = Buffer.concat([readBuffer, buffer]);\n\n\t\t\twebm.write(buffer);\n\t\t\togg.write(buffer);\n\n\t\t\tif (readBuffer.length >= probeSize) {\n\t\t\t\tstream.off('data', onData);\n\t\t\t\tstream.pause();\n\t\t\t\tprocess.nextTick(onClose);\n\t\t\t}\n\t\t};\n\n\t\tstream.once('error', reject);\n\t\tstream.on('data', onData);\n\t\tstream.once('close', onClose);\n\t\tstream.once('end', onClose);\n\t});\n}\n"
  },
  {
    "path": "packages/voice/src/util/entersState.ts",
    "content": "import { type EventEmitter, once } from 'node:events';\nimport type { VoiceConnection, VoiceConnectionStatus } from '../VoiceConnection';\nimport type { AudioPlayer, AudioPlayerStatus } from '../audio/AudioPlayer';\nimport { abortAfter } from './abortAfter';\n\n/**\n * Allows a voice connection a specified amount of time to enter a given state, otherwise rejects with an error.\n *\n * @param target - The voice connection that we want to observe the state change for\n * @param status - The status that the voice connection should be in\n * @param timeoutOrSignal - The maximum time we are allowing for this to occur, or a signal that will abort the operation\n */\nexport function entersState(\n\ttarget: VoiceConnection,\n\tstatus: VoiceConnectionStatus,\n\ttimeoutOrSignal: AbortSignal | number,\n): Promise<VoiceConnection>;\n\n/**\n * Allows an audio player a specified amount of time to enter a given state, otherwise rejects with an error.\n *\n * @param target - The audio player that we want to observe the state change for\n * @param status - The status that the audio player should be in\n * @param timeoutOrSignal - The maximum time we are allowing for this to occur, or a signal that will abort the operation\n */\nexport function entersState(\n\ttarget: AudioPlayer,\n\tstatus: AudioPlayerStatus,\n\ttimeoutOrSignal: AbortSignal | number,\n): Promise<AudioPlayer>;\n\n/**\n * Allows a target a specified amount of time to enter a given state, otherwise rejects with an error.\n *\n * @param target - The object that we want to observe the state change for\n * @param status - The status that the target should be in\n * @param timeoutOrSignal - The maximum time we are allowing for this to occur, or a signal that will abort the operation\n */\nexport async function entersState<Target extends AudioPlayer | VoiceConnection>(\n\ttarget: Target,\n\tstatus: AudioPlayerStatus | VoiceConnectionStatus,\n\ttimeoutOrSignal: AbortSignal | number,\n) {\n\tif (target.state.status !== status) {\n\t\tconst [ac, signal] =\n\t\t\ttypeof timeoutOrSignal === 'number' ? abortAfter(timeoutOrSignal) : [undefined, timeoutOrSignal];\n\t\ttry {\n\t\t\tawait once(target as EventEmitter, status, { signal });\n\t\t} finally {\n\t\t\tac?.abort();\n\t\t}\n\t}\n\n\treturn target;\n}\n"
  },
  {
    "path": "packages/voice/src/util/generateDependencyReport.ts",
    "content": "/* eslint-disable @typescript-eslint/no-var-requires */\n/* eslint-disable @typescript-eslint/no-require-imports */\nimport { getCiphers } from 'node:crypto';\nimport { resolve, dirname } from 'node:path';\nimport prism from 'prism-media';\n\n/**\n * Tries to find the package.json file for a given module.\n *\n * @param dir - The directory to look in\n * @param packageName - The name of the package to look for\n * @param depth - The maximum recursion depth\n */\nfunction findPackageJSON(\n\tdir: string,\n\tpackageName: string,\n\tdepth: number,\n): { name: string; version: string } | undefined {\n\tif (depth === 0) return undefined;\n\tconst attemptedPath = resolve(dir, './package.json');\n\ttry {\n\t\tconst pkg = require(attemptedPath);\n\t\tif (pkg.name !== packageName) throw new Error('package.json does not match');\n\t\treturn pkg;\n\t} catch {\n\t\treturn findPackageJSON(resolve(dir, '..'), packageName, depth - 1);\n\t}\n}\n\n/**\n * Tries to find the version of a dependency.\n *\n * @param name - The package to find the version of\n */\nfunction version(name: string): string {\n\ttry {\n\t\tif (name === '@discordjs/voice') {\n\t\t\treturn '[VI]{{inject}}[/VI]';\n\t\t}\n\n\t\tconst pkg = findPackageJSON(dirname(require.resolve(name)), name, 3);\n\t\treturn pkg?.version ?? 'not found';\n\t} catch {\n\t\treturn 'not found';\n\t}\n}\n\n/**\n * Generates a report of the dependencies used by the \\@discordjs/voice module.\n * Useful for debugging.\n */\nexport function generateDependencyReport() {\n\tconst report = [];\n\tconst addVersion = (name: string) => report.push(`- ${name}: ${version(name)}`);\n\t// general\n\treport.push('Core Dependencies');\n\taddVersion('@discordjs/voice');\n\taddVersion('prism-media');\n\treport.push('');\n\n\t// opus\n\treport.push('Opus Libraries');\n\taddVersion('@discordjs/opus');\n\taddVersion('opusscript');\n\treport.push('');\n\n\t// encryption\n\treport.push('Encryption Libraries');\n\treport.push(`- native crypto support for aes-256-gcm: ${getCiphers().includes('aes-256-gcm') ? 'yes' : 'no'}`);\n\taddVersion('sodium-native');\n\taddVersion('sodium');\n\taddVersion('libsodium-wrappers');\n\taddVersion('@stablelib/xchacha20poly1305');\n\taddVersion('@noble/ciphers');\n\treport.push('');\n\n\t// dave\n\treport.push('DAVE Libraries');\n\taddVersion('@snazzah/davey');\n\treport.push('');\n\n\t// ffmpeg\n\treport.push('FFmpeg');\n\ttry {\n\t\tconst info = prism.FFmpeg.getInfo();\n\t\treport.push(`- version: ${info.version}`);\n\t\treport.push(`- libopus: ${info.output.includes('--enable-libopus') ? 'yes' : 'no'}`);\n\t} catch {\n\t\treport.push('- not found');\n\t}\n\n\treturn ['-'.repeat(50), ...report, '-'.repeat(50)].join('\\n');\n}\n"
  },
  {
    "path": "packages/voice/src/util/index.ts",
    "content": "export * from './constants';\nexport * from './generateDependencyReport';\nexport * from './entersState';\nexport type * from './adapter';\nexport * from './demuxProbe';\n"
  },
  {
    "path": "packages/voice/src/util/util.ts",
    "content": "export const noop = () => {};\n"
  },
  {
    "path": "packages/voice/tsconfig.docs.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.docs.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist-docs\"\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/voice/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/voice/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/voice/tsconfig.test.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"noEmit\": true,\n\t\t\"skipLibCheck\": true\n\t},\n\t\"include\": [\"__tests__/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/voice/tsup.config.ts",
    "content": "import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector';\nimport { createTsupConfig } from '../../tsup.config.js';\n\nexport default createTsupConfig({\n\tesbuildPlugins: [esbuildPluginVersionInjector()],\n});\n"
  },
  {
    "path": "packages/ws/.cliff-jumperrc.json",
    "content": "{\n\t\"$schema\": \"./node_modules/@favware/cliff-jumper/assets/cliff-jumper.schema.json\",\n\t\"name\": \"ws\",\n\t\"org\": \"discordjs\",\n\t\"packagePath\": \"packages/ws\",\n\t\"identifierBase\": false\n}\n"
  },
  {
    "path": "packages/ws/.gitignore",
    "content": "# Packages\nnode_modules\n\n# Log files\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Env\n.env\n\n# Dist\ndist\ndist-docs\n\n# Docs\ndocs/**/*\n!docs/README.md\n\n# Miscellaneous\n.turbo\n.tmp\ncoverage\n"
  },
  {
    "path": "packages/ws/.lintstagedrc.js",
    "content": "/** @type {import('lint-staged').Config} */\nmodule.exports = require('../../.lintstagedrc.json');\n"
  },
  {
    "path": "packages/ws/.prettierignore",
    "content": ".turbo\ncoverage\ndist\ndist-docs\ndocs/docs.api.json\nCHANGELOG.md\ntsup.config.bundled*\n"
  },
  {
    "path": "packages/ws/.prettierrc.js",
    "content": "/** @type {import('prettier').Config} */\nmodule.exports = require('../../.prettierrc.json');\n"
  },
  {
    "path": "packages/ws/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n# [@discordjs/ws@2.0.0](https://github.com/discordjs/discord.js/compare/@discordjs/ws@1.1.0...@discordjs/ws@2.0.0) - (2024-09-01)\n\n## Bug Fixes\n\n- **WebSocketShard:** Buffer native zlib decompression payload (#10416) ([defb083](https://github.com/discordjs/discord.js/commit/defb083528ef31383778187a04ced8b00d886242))\n- **WebSocketManager:** Heartbeat event had outdated types (#10417) ([5eabec1](https://github.com/discordjs/discord.js/commit/5eabec14d45ef7bdd7f610e84234eb63e726eacd))\n- Retry for EAI_AGAIN I/O error (#10383) ([be04acd](https://github.com/discordjs/discord.js/commit/be04acd534d7d0c3fb7f6bd174e4a6482aae0d73))\n- Consistent debug log spacing (#10349) ([38c699b](https://github.com/discordjs/discord.js/commit/38c699bc8a2ca40f37f70c93e08067e00f12ee81))\n\n## Features\n\n- **WebsocketManager:** Retroactive token setting (#10418) ([de94eaf](https://github.com/discordjs/discord.js/commit/de94eaf351a69fab57ec766bd9e90e8c05e8c3d1))\n- **WebSocketShard:** Explicit time out network error handling (#10375) ([093ac92](https://github.com/discordjs/discord.js/commit/093ac924aef1bf328feadb49876bfbe26052fe1a))\n\n## Refactor\n\n- **WebSocketShard:** Error event handling (#10436) ([a6de270](https://github.com/discordjs/discord.js/commit/a6de2707fc1107262b12491f73b5b6887df91c67))\n- **ws:** Event layout (#10376) ([bf6761a](https://github.com/discordjs/discord.js/commit/bf6761a44adec1fe5017f6bf5d8bc0734916961f))\n  - **BREAKING CHANGE:** All events now emit shard id as its own param\n- Native zlib support (#10316) ([94cc02a](https://github.com/discordjs/discord.js/commit/94cc02a2580496774d75673abc0caabc765d9ee0))\n\n# [@discordjs/ws@1.1.1](https://github.com/discordjs/discord.js/compare/@discordjs/ws@1.1.0...@discordjs/ws@1.1.1) - (2024-06-02)\n\n## Bug Fixes\n\n- Deno compat (#10271) ([616208b](https://github.com/discordjs/discord.js/commit/616208ba7766ac66a8969ffd2cb7b341fdc2c67b))\n\n# [@discordjs/ws@1.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/ws@1.0.2...@discordjs/ws@1.1.0) - (2024-05-04)\n\n## Bug Fixes\n\n- Anchor link for events ([0efd1be](https://github.com/discordjs/discord.js/commit/0efd1bea46fa2fc8bcd3dcfd0ac5cd608a0a7df0))\n- Minify mainlib docs json (#9963) ([4b88306](https://github.com/discordjs/discord.js/commit/4b88306dcb2b16b840ec61e9e33047af3a31c45d))\n\n## Documentation\n\n- Remove duplicate word in comment (#10244) ([96169ad](https://github.com/discordjs/discord.js/commit/96169add6d2db37706629c0172692533948a9dca))\n- Split docs.api.json into multiple json files ([597340f](https://github.com/discordjs/discord.js/commit/597340f288437c35da8c703d9b621274de60d880))\n- Remove utf-8-validate (#10059) ([7e12bee](https://github.com/discordjs/discord.js/commit/7e12bee337af169bb131d34fa29ed090ebd26c71))\n\n## Features\n\n- **ws:** Support for custom worker messaging (#10241) ([728164e](https://github.com/discordjs/discord.js/commit/728164ed868167d43dec7b7e8d11052a37694968))\n- Local and preview detection ([79fbda3](https://github.com/discordjs/discord.js/commit/79fbda3aac6d4f0f8bfb193e797d09cbe331d315))\n- Add support for `using` keyword on discord.js `Client` and `WebSocketManager` (#10063) ([543d617](https://github.com/discordjs/discord.js/commit/543d61737e0709b9d88029d01156d48cfcaf3bcc))\n- Use globally available WebSocket client in runtimes that have it (#10042) ([319ef9a](https://github.com/discordjs/discord.js/commit/319ef9a70b92dbb11726b270ab84e73ca932850f))\n\n## Refactor\n\n- Docs (#10126) ([18cce83](https://github.com/discordjs/discord.js/commit/18cce83d80598c430218775c53441b6b2ecdc776))\n- **WebSocketShard:** Payload sending (#10098) ([c878b65](https://github.com/discordjs/discord.js/commit/c878b65ef586cd9b42f765515f87f43cb6165f61))\n- Use interfaces for AsyncEventEmitter event maps (#10044) ([adfd9cd](https://github.com/discordjs/discord.js/commit/adfd9cd3b32cfabdcc45ec90f535b2852a3ca4a6))\n\n# [@discordjs/ws@1.0.2](https://github.com/discordjs/discord.js/compare/@discordjs/ws@1.0.1...@discordjs/ws@1.0.2) - (2023-11-12)\n\n## Bug Fixes\n\n- **WebSocketManager:** Available sessions check (#9823) ([e68ab16](https://github.com/discordjs/discord.js/commit/e68ab167c2c85c9fd90fc7c3798ec3bfd2d89760))\n\n## Documentation\n\n- **create-discord-bot:** Support bun in create-discord-bot (#9798) ([7157748](https://github.com/discordjs/discord.js/commit/7157748fe3a69265896adf0450cd3f37acbcf97b))\n\n# [@discordjs/ws@1.0.1](https://github.com/discordjs/discord.js/compare/@discordjs/ws@1.0.0...@discordjs/ws@1.0.1) - (2023-08-17)\n\n## Documentation\n\n- Update Node.js requirement to 16.11.0 (#9764) ([188877c](https://github.com/discordjs/discord.js/commit/188877c50af70f0d5cffb246620fa277435c6ce6))\n\n# [@discordjs/ws@1.0.0](https://github.com/discordjs/discord.js/compare/@discordjs/ws@0.8.3...@discordjs/ws@1.0.0) - (2023-07-31)\n\n## Bug Fixes\n\n- **WebSocketShard:** Close errors not being catchable (#9704) ([8c782bf](https://github.com/discordjs/discord.js/commit/8c782bfd52b1d7bbfbf1dfd39d0c45828298e285))\n- **WebSocketManager:** Always cache result of fetchGatewayInformation (#9611) ([df8b6e9](https://github.com/discordjs/discord.js/commit/df8b6e9934af5b21aa2701ce54244c38a5f133e0))\n- **WebSocketShard:** Handle initial connect being a resume (#9549) ([4dcc9c5](https://github.com/discordjs/discord.js/commit/4dcc9c50f83cd234cb2c2ede47fb505ffb75eef2))\n\n## Features\n\n- No-de-no-de, now with extra buns (#9683) ([386f206](https://github.com/discordjs/discord.js/commit/386f206caf74a04c426799af9796ca96dcb37056))\n  - **BREAKING CHANGE:** The REST and RequestManager classes now extend AsyncEventEmitter\nfrom `@vladfrangu/async_event_emitter`, which aids in cross-compatibility\nbetween Node, Deno, Bun, CF Workers, Vercel Functions, etc.\n  - **BREAKING CHANGE:** DefaultUserAgentAppendix has been adapted to support multiple\ndifferent platforms (previously mentioned Deno, Bun, CF Workers, etc)\n  - **BREAKING CHANGE:** the entry point for `@discordjs/rest` will now differ\nin non-node-like environments (CF Workers, etc.)\n  - **Co-authored-by:** Suneet Tipirneni <77477100+suneettipirneni@users.noreply.github.com>\n  - **Co-authored-by:** Jiralite <33201955+Jiralite@users.noreply.github.com>\n  - **Co-authored-by:** suneettipirneni <suneettipirneni@icloud.com>\n\n## Refactor\n\n- **WebSocketShard:** Throttling error handling (#9701) ([ceab07b](https://github.com/discordjs/discord.js/commit/ceab07bec85c8d678958b8023a9c1902136f9f83))\n- **rest:** Switch api to fetch-like and provide strategies (#9416) ([cdaa0a3](https://github.com/discordjs/discord.js/commit/cdaa0a36f586459f1e5ede868c4250c7da90455c))\n  - **BREAKING CHANGE:** NodeJS v18+ is required when using node due to the use of global `fetch`\n  - **BREAKING CHANGE:** The raw method of REST now returns a web compatible `Respone` object.\n  - **BREAKING CHANGE:** The `parseResponse` utility method has been updated to operate on a web compatible `Response` object.\n  - **BREAKING CHANGE:** Many underlying internals have changed, some of which were exported.\n  - **BREAKING CHANGE:** `DefaultRestOptions` used to contain a default `agent`, which is now set to `null` instead.\n\n# [@discordjs/ws@0.8.3](https://github.com/discordjs/discord.js/compare/@discordjs/ws@0.8.2...@discordjs/ws@0.8.3) - (2023-05-06)\n\n## Bug Fixes\n\n- **WebSocketShard:** Wait a little before reconnecting (#9517) ([00da44a](https://github.com/discordjs/discord.js/commit/00da44a120fb0eeb2bdc3a03670836a544dc5418))\n\n## Testing\n\n- **ws:** Fix tests (#9520) ([3e80f0b](https://github.com/discordjs/discord.js/commit/3e80f0b384ea2dc14c1b60b5897e90040cab9a24))\n\n# [@discordjs/ws@0.8.2](https://github.com/discordjs/discord.js/compare/@discordjs/ws@0.8.1...@discordjs/ws@0.8.2) - (2023-05-01)\n\n## Documentation\n\n- Generate static imports for types with api-extractor ([98a76db](https://github.com/discordjs/discord.js/commit/98a76db482879f79d6bb2fb2e5fc65ac2c34e2d9))\n\n# [@discordjs/ws@0.8.1](https://github.com/discordjs/discord.js/compare/@discordjs/ws@0.8.0...@discordjs/ws@0.8.1) - (2023-04-16)\n\n## Bug Fixes\n\n- Fix external links (#9313) ([a7425c2](https://github.com/discordjs/discord.js/commit/a7425c29c4f23f1b31f4c6a463107ca9eb7fd7e2))\n\n## Refactor\n\n- Abstract identify throttling and correct max_concurrency handling (#9375) ([02dfaf1](https://github.com/discordjs/discord.js/commit/02dfaf1aa2c798315d0dd7f809cc469771b36ffc))\n- **WebSocketShard:** WaitForEvent and its error handling (#9282) ([dcf58d8](https://github.com/discordjs/discord.js/commit/dcf58d81401387a5e157b20829aa56638e106e9d))\n\n# [@discordjs/ws@0.8.0](https://github.com/discordjs/discord.js/compare/@discordjs/ws@0.7.0...@discordjs/ws@0.8.0) - (2023-04-01)\n\n## Bug Fixes\n\n- **scripts:** Accessing tsComment ([d8d5f31](https://github.com/discordjs/discord.js/commit/d8d5f31d3927fd1de62f1fa3a1a6e454243ad87b))\n- **WebSocketShard:** Don't await #destroy in error bubbling logic (#9276) ([519825a](https://github.com/discordjs/discord.js/commit/519825a651fe22042a73046824d12f03f56ca9e2))\n- **WebSocketShard:** Don't close in #destroy when status is connecting (#9254) ([c76b17d](https://github.com/discordjs/discord.js/commit/c76b17d3b327fb55ef76770d4825e02ab8f26ad1))\n- **WebSocketShard:** Cancel initial heartbeat in destroy (#9244) ([9842082](https://github.com/discordjs/discord.js/commit/98420826bc2296fc392f17e8254cf4ad743ff5af))\n\n## Features\n\n- **website:** Render syntax and mdx on the server (#9086) ([ee5169e](https://github.com/discordjs/discord.js/commit/ee5169e0aadd7bbfcd752aae614ec0f69602b68b))\n\n# [@discordjs/ws@0.7.0](https://github.com/discordjs/discord.js/compare/@discordjs/ws@0.6.0...@discordjs/ws@0.7.0) - (2023-03-12)\n\n## Bug Fixes\n\n- **WebSocketShard:** #send race condition due to ready state (#9226) ([a99fc64](https://github.com/discordjs/discord.js/commit/a99fc64e3f73c3976617a7ed825fa7d6e9fb3b53))\n- **WebSocketShard:** Wait for hello rather than ready in connect (#9178) ([27e0b32](https://github.com/discordjs/discord.js/commit/27e0b32c5f0fe605f152e6ba67ce3f596137ff01))\n- **WebSocketShard:** Proper error bubbling (#9119) ([9681f34](https://github.com/discordjs/discord.js/commit/9681f348770b0e2ff9b7c96b1c30575dd950e2ed))\n- Ws typo (#9056) ([05a1cbf](https://github.com/discordjs/discord.js/commit/05a1cbfe5479195b0bc9b6f0971fe39f6af6fd77))\n\n## Documentation\n\n- Fix typos (#9127) ([1ba1f23](https://github.com/discordjs/discord.js/commit/1ba1f238f04221ec890fc921678909b5b7d92c26))\n- Fix version export (#9049) ([8b70f49](https://github.com/discordjs/discord.js/commit/8b70f497a1207e30edebdecd12b926c981c13d28))\n- Updated @discordjs/ws README.md to include optional packages (#8973) ([4ee00b6](https://github.com/discordjs/discord.js/commit/4ee00b6534fad39da1fe54fb2c1766b264a020ca))\n\n## Features\n\n- **WebSocketShard:** Heartbeat jitter (#9223) ([6ecff26](https://github.com/discordjs/discord.js/commit/6ecff26ec65ce1d559a3406b396b3190868b1961))\n- **website:** Add support for source file links (#9048) ([f6506e9](https://github.com/discordjs/discord.js/commit/f6506e99c496683ee0ab67db0726b105b929af38))\n- **ws:** Custom workers (#9004) ([828a13b](https://github.com/discordjs/discord.js/commit/828a13b526dde1334e8879e76e664584bdb5db73))\n- **ws:** Metrics (#9005) ([0ff67d8](https://github.com/discordjs/discord.js/commit/0ff67d8e7adee43ff82bbf072dac9a4c7c9fe8c2))\n\n## Refactor\n\n- **WebSocketManager:** Passing in strategy (#9122) ([5c5a583](https://github.com/discordjs/discord.js/commit/5c5a5832b94cd4d371cc99c4f9c3384523dabeeb))\n\n## Styling\n\n- Run prettier (#9041) ([2798ba1](https://github.com/discordjs/discord.js/commit/2798ba1eb3d734f0cf2eeccd2e16cfba6804873b))\n\n# [@discordjs/ws@0.6.0](https://github.com/discordjs/discord.js/compare/@discordjs/ws@0.5.0...@discordjs/ws@0.6.0) - (2022-12-16)\n\n## Bug Fixes\n\n- **WebSocketShard:** Send ratelimit handling (#8887) ([40b504a](https://github.com/discordjs/discord.js/commit/40b504a2088effc6a467f40ac3cf2a6d736ab209))\n\n## Features\n\n- **core:** Add support for role connections (#8930) ([3d6fa24](https://github.com/discordjs/discord.js/commit/3d6fa248c07b2278504bbe8bafa17a3294971fd9))\n\n## Refactor\n\n- **WebSocketShard:** Identify throttling (#8888) ([8f552a0](https://github.com/discordjs/discord.js/commit/8f552a0e17c0eca71063e7a4353b9b351bcdf9fd))\n\n# [@discordjs/ws@0.5.0](https://github.com/discordjs/discord.js/compare/@discordjs/ws@0.4.1...@discordjs/ws@0.5.0) - (2022-11-28)\n\n## Bug Fixes\n\n- Pin @types/node version ([9d8179c](https://github.com/discordjs/discord.js/commit/9d8179c6a78e1c7f9976f852804055964d5385d4))\n\n## Documentation\n\n- Remove unused imports (#8744) ([179392d](https://github.com/discordjs/discord.js/commit/179392d6d7d634c6d10f6abb20c072516c1c1d43))\n\n## Features\n\n- New select menus (#8793) ([5152abf](https://github.com/discordjs/discord.js/commit/5152abf7285581abf7689e9050fdc56c4abb1e2b))\n\n# [@discordjs/ws@0.4.1](https://github.com/discordjs/discord.js/compare/@discordjs/ws@0.4.0...@discordjs/ws@0.4.1) - (2022-10-10)\n\n## Bug Fixes\n\n- **WebSocketShard:** Dispatch race condition (#8731) ([c2b6777](https://github.com/discordjs/discord.js/commit/c2b677759b905d6eb3ebcefcec2cb04eb38436bb))\n\n# [@discordjs/ws@0.4.0](https://github.com/discordjs/discord.js/compare/@discordjs/ws@0.3.0...@discordjs/ws@0.4.0) - (2022-10-08)\n\n## Bug Fixes\n\n- Ws package.json path (#8720) ([7af3c3b](https://github.com/discordjs/discord.js/commit/7af3c3b6f1517a5d14372b5aa0ef3a2ed8633f6f))\n- **WebSocketShard:** Add ready data parameter to ready event (#8705) ([a7eab50](https://github.com/discordjs/discord.js/commit/a7eab50ee3e286ca10e37107d695385251bd044d))\n- Footer / sidebar / deprecation alert ([ba3e0ed](https://github.com/discordjs/discord.js/commit/ba3e0ed348258fe8e51eefb4aa7379a1230616a9))\n\n## Documentation\n\n- Change name (#8604) ([dd5a089](https://github.com/discordjs/discord.js/commit/dd5a08944c258a847fc4377f1d5e953264ab47d0))\n\n## Features\n\n- Web-components (#8715) ([0ac3e76](https://github.com/discordjs/discord.js/commit/0ac3e766bd9dbdeb106483fa4bb085d74de346a2))\n- Add `@discordjs/util` (#8591) ([b2ec865](https://github.com/discordjs/discord.js/commit/b2ec865765bf94181473864a627fb63ea8173fd3))\n\n## Refactor\n\n- Website components (#8600) ([c334157](https://github.com/discordjs/discord.js/commit/c3341570d983aea9ecc419979d5a01de658c9d67))\n- Use `eslint-config-neon` for packages. (#8579) ([edadb9f](https://github.com/discordjs/discord.js/commit/edadb9fe5dfd9ff51a3cfc9b25cb242d3f9f5241))\n\n# [@discordjs/ws@0.3.0](https://github.com/discordjs/discord.js/compare/@discordjs/ws@0.2.0...@discordjs/ws@0.3.0) - (2022-08-22)\n\n## Bug Fixes\n\n- **WebSocketShard#destroy:** Wait for close and cleanup listeners (#8479) ([acdafe6](https://github.com/discordjs/discord.js/commit/acdafe60c7aa1ac5a3d358934c055c297080a944))\n- **WebSocketManager#connect:** Check if we have enough sessions (#8481) ([4fd4252](https://github.com/discordjs/discord.js/commit/4fd42528fea6127e6468a651f9544913c19ade4d))\n- **WebSocketShard:** Always reconnect on disconnected with 1000 (#8405) ([359f688](https://github.com/discordjs/discord.js/commit/359f6885558fcfb3151971ab589077a89ee71a01))\n- **WebSocketShard:** Emit errors directly instead of objects (#8406) ([3161e1a](https://github.com/discordjs/discord.js/commit/3161e1a1acfbf929ecf33958fa1657553dd9bc1e))\n\n## Documentation\n\n- Fence examples in codeblocks ([193b252](https://github.com/discordjs/discord.js/commit/193b252672440a860318d3c2968aedd9cb88e0ce))\n\n## Features\n\n- **website:** Show `constructor` information (#8540) ([e42fd16](https://github.com/discordjs/discord.js/commit/e42fd1636973b10dd7ed6fb4280ee1a4a8f82007))\n- **website:** Render `@defaultValue` blocks (#8527) ([8028813](https://github.com/discordjs/discord.js/commit/8028813825e7708915ea892760c1003afd60df2f))\n- **website:** Render tsdoc examples (#8494) ([7116647](https://github.com/discordjs/discord.js/commit/7116647947e413da59fbf493ed5251ddcd710ce7))\n- **WebSocketShard:** Support new resume url (#8480) ([bc06cc6](https://github.com/discordjs/discord.js/commit/bc06cc638d2f57ab5c600e8cdb6afc8eb2180166))\n\n## Refactor\n\n- **website:** Adjust typography (#8503) ([0f83402](https://github.com/discordjs/discord.js/commit/0f834029850d2448981596cf082ff59917018d66))\n- Docs design (#8487) ([4ab1d09](https://github.com/discordjs/discord.js/commit/4ab1d09997a18879a9eb9bda39df6f15aa22557e))\n\n# [@discordjs/ws@0.2.0](https://github.com/discordjs/discord.js/tree/@discordjs/ws@0.2.0) - (2022-07-30)\n\n## Bug Fixes\n\n- **WebSocketShard:** Account code 1000 with no prior indication (#8399) ([5137bfc](https://github.com/discordjs/discord.js/commit/5137bfc17d763488083b76ee9008611df333272a))\n- **WebSocketShard:** Use correct import (#8357) ([78d4295](https://github.com/discordjs/discord.js/commit/78d4295a40b83ea4f7cc830ff81927cba2d1d3f0))\n\n## Features\n\n- @discordjs/ws (#8260) ([748d727](https://github.com/discordjs/discord.js/commit/748d7271c45796479a29d8ed3101421de09ef867))\n"
  },
  {
    "path": "packages/ws/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2022 Noel Buechler\n   Copyright 2022 Denis Cristea\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "packages/ws/README.md",
    "content": "<div align=\"center\">\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.js.org\"><img src=\"https://discord.js.org/static/logo.svg\" width=\"546\" alt=\"discord.js\" /></a>\n\t</p>\n\t<br />\n\t<p>\n\t\t<a href=\"https://discord.gg/djs\"><img src=\"https://img.shields.io/badge/join_us-on_discord-5865F2?logo=discord&logoColor=white\" alt=\"Discord server\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/ws\"><img src=\"https://img.shields.io/npm/v/@discordjs/ws.svg?maxAge=3600\" alt=\"npm version\" /></a>\n\t\t<a href=\"https://www.npmjs.com/package/@discordjs/ws\"><img src=\"https://img.shields.io/npm/dt/@discordjs/ws.svg?maxAge=3600\" alt=\"npm downloads\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/actions\"><img src=\"https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg\" alt=\"Build status\" /></a>\n\t\t<a href=\"https://github.com/discordjs/discord.js/commits/main/packages/ws\"><img alt=\"Last commit.\" src=\"https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fws\" /></a>\n\t\t<a href=\"https://codecov.io/gh/discordjs/discord.js\"><img src=\"https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=ws\" alt=\"Code coverage\" /></a>\n\t\t<a href=\"https://opencollective.com/discordjs\"><img src=\"https://img.shields.io/opencollective/backers/discordjs?maxAge=3600&logo=opencollective\" alt=\"backers\" /></a>\n\t</p>\n\t<p>\n\t\t<a href=\"https://vercel.com/?utm_source=discordjs&utm_campaign=oss\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg\" alt=\"Vercel\" /></a>\n\t\t<a href=\"https://www.cloudflare.com\"><img src=\"https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png\" alt=\"Cloudflare Workers\" height=\"44\" /></a>\n\t</p>\n</div>\n\n## About\n\n`@discordjs/ws` is a powerful wrapper around Discord's gateway.\n\n## Installation\n\n**Node.js 22.12.0 or newer is required.**\n\n```sh\nnpm install @discordjs/ws\nyarn add @discordjs/ws\npnpm add @discordjs/ws\nbun add @discordjs/ws\n```\n\n### Optional packages\n\n- [zlib-sync](https://www.npmjs.com/package/zlib-sync) for WebSocket data compression and inflation (`npm install zlib-sync`)\n- [bufferutil](https://www.npmjs.com/package/bufferutil) for a much faster WebSocket connection (`npm install bufferutil`)\n\n## Example usage\n\nThe example uses [ES modules](https://nodejs.org/api/esm.html#enabling).\n\n```ts\nimport { WebSocketManager, WebSocketShardEvents, CompressionMethod } from '@discordjs/ws';\nimport { REST } from '@discordjs/rest';\nimport type { RESTGetAPIGatewayBotResult } from 'discord-api-types/v10';\n\nconst rest = new REST().setToken(process.env.DISCORD_TOKEN);\n// This example will spawn Discord's recommended shard count, all under the current process.\nconst manager = new WebSocketManager({\n\ttoken: process.env.DISCORD_TOKEN,\n\tintents: 0, // for no intents\n\tfetchGatewayInformation() {\n\t\treturn rest.get(Routes.gatewayBot()) as Promise<RESTGetAPIGatewayBotResult>;\n\t},\n\t// uncomment if you have zlib-sync installed and want to use compression\n\t// compression: CompressionMethod.ZlibSync,\n\n\t// alternatively, we support compression using node's native `node:zlib` module:\n\t// compression: CompressionMethod.ZlibNative,\n});\n\nmanager.on(WebSocketShardEvents.Dispatch, (event) => {\n\t// Process gateway events here.\n});\n\nawait manager.connect();\n```\n\n### Specify shards\n\n```ts\n// Spawn 4 shards\nconst manager = new WebSocketManager({\n\ttoken: process.env.DISCORD_TOKEN,\n\tintents: 0,\n\tshardCount: 4,\n\tfetchGatewayInformation() {\n\t\treturn rest.get(Routes.gatewayBot()) as Promise<RESTGetAPIGatewayBotResult>;\n\t},\n});\n\n// The manager also supports being responsible for only a subset of your shards:\n\n// Your bot will run 8 shards overall\n// This manager will only take care of 0, 2, 4, and 6\nconst manager = new WebSocketManager({\n\ttoken: process.env.DISCORD_TOKEN,\n\tintents: 0,\n\tshardCount: 8,\n\tshardIds: [0, 2, 4, 6],\n\tfetchGatewayInformation() {\n\t\treturn rest.get(Routes.gatewayBot()) as Promise<RESTGetAPIGatewayBotResult>;\n\t},\n});\n\n// Alternatively, if your shards are consecutive, you can pass in a range\nconst manager = new WebSocketManager({\n\ttoken: process.env.DISCORD_TOKEN,\n\tintents: 0,\n\tshardCount: 8,\n\tshardIds: {\n\t\tstart: 0,\n\t\tend: 4,\n\t},\n\tfetchGatewayInformation() {\n\t\treturn rest.get(Routes.gatewayBot()) as Promise<RESTGetAPIGatewayBotResult>;\n\t},\n});\n```\n\n### Specify `worker_threads`\n\nYou can also have the shards spawn in worker threads:\n\n```ts\nimport { WebSocketManager, WorkerShardingStrategy } from '@discordjs/ws';\nimport { REST } from '@discordjs/rest';\n\nconst rest = new REST().setToken(process.env.DISCORD_TOKEN);\nconst manager = new WebSocketManager({\n\ttoken: process.env.DISCORD_TOKEN,\n\tintents: 0,\n\tshardCount: 6,\n\tfetchGatewayInformation() {\n\t\treturn rest.get(Routes.gatewayBot()) as Promise<RESTGetAPIGatewayBotResult>;\n\t},\n\t// This will cause 3 workers to spawn, 2 shards per each\n\tbuildStrategy: (manager) => new WorkerShardingStrategy(manager, { shardsPerWorker: 2 }),\n\t// Or maybe you want all your shards under a single worker\n\tbuildStrategy: (manager) => new WorkerShardingStrategy(manager, { shardsPerWorker: 'all' }),\n});\n```\n\n**Note**: By default, this will cause the workers to effectively only be responsible for the WebSocket connection, they simply pass up all the events back to the main process for the manager to emit. If you want to have the workers handle events as well, you can pass in a `workerPath` option to the `WorkerShardingStrategy` constructor:\n\n```ts\nimport { WebSocketManager, WorkerShardingStrategy } from '@discordjs/ws';\nimport { REST } from '@discordjs/rest';\n\nconst rest = new REST().setToken(process.env.DISCORD_TOKEN);\nconst manager = new WebSocketManager({\n\ttoken: process.env.DISCORD_TOKEN,\n\tintents: 0,\n\tfetchGatewayInformation() {\n\t\treturn rest.get(Routes.gatewayBot()) as Promise<RESTGetAPIGatewayBotResult>;\n\t},\n\tbuildStrategy: (manager) =>\n\t\tnew WorkerShardingStrategy(manager, {\n\t\t\tshardsPerWorker: 2,\n\t\t\tworkerPath: './worker.js',\n\t\t\t// Optionally, if you have custom messaging, like for analytic collection, you can use this:\n\t\t\tasync unknownPayloadHandler(data: any) {\n\t\t\t\t// handle data here :3\n\t\t\t},\n\t\t}),\n});\n```\n\nAnd your `worker.ts` file:\n\n```ts\nimport { WorkerBootstrapper, WebSocketShardEvents } from '@discordjs/ws';\nimport { parentPort } from 'node:worker_threads';\n\nconst bootstrapper = new WorkerBootstrapper();\nvoid bootstrapper.bootstrap({\n\t// Those will be sent to the main thread for the manager to emit\n\tforwardEvents: [\n\t\tWebSocketShardEvents.Closed,\n\t\tWebSocketShardEvents.Debug,\n\t\tWebSocketShardEvents.Hello,\n\t\tWebSocketShardEvents.Ready,\n\t\tWebSocketShardEvents.Resumed,\n\t],\n\tshardCallback: (shard) => {\n\t\tshard.on(WebSocketShardEvents.Dispatch, (event) => {\n\t\t\t// Process gateway events here however you want (e.g. send them through a message broker)\n\t\t\t// You also have access to shard.id if you need it\n\t\t});\n\t},\n});\n\n// This will go to `unknownPayloadHandler` in the main thread, or be ignored if not provided\nparentPort!.postMessage({ custom: 'data' });\n```\n\n## Links\n\n- [Website][website] ([source][website-source])\n- [Documentation][documentation]\n- [Guide][guide] ([source][guide-source])\n  Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.\n- [discord.js Discord server][discord]\n- [Discord Developers Discord server][discord-developers]\n- [GitHub][source]\n- [npm][npm]\n- [Related libraries][related-libs]\n\n## Contributing\n\nBefore creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the\n[documentation][documentation].  \nSee [the contribution guide][contributing] if you'd like to submit a PR.\n\n## Help\n\nIf you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].\n\n[website]: https://discord.js.org\n[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website\n[documentation]: https://discord.js.org/docs/packages/ws/stable\n[guide]: https://discordjs.guide\n[guide-source]: https://github.com/discordjs/discord.js/tree/main/apps/guide\n[guide-update]: https://discordjs.guide/legacy/additional-info/changes-in-v14\n[discord]: https://discord.gg/djs\n[discord-developers]: https://discord.gg/discord-developers\n[source]: https://github.com/discordjs/discord.js/tree/main/packages/ws\n[npm]: https://www.npmjs.com/package/@discordjs/ws\n[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries\n[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md\n"
  },
  {
    "path": "packages/ws/__tests__/gateway.mock.ts",
    "content": "import type { RESTGetAPIGatewayBotResult } from 'discord-api-types/v10';\n\nexport const mockGatewayInformation: RESTGetAPIGatewayBotResult = {\n\tshards: 1,\n\tsession_start_limit: {\n\t\tmax_concurrency: 3,\n\t\treset_after: 60,\n\t\tremaining: 3,\n\t\ttotal: 3,\n\t},\n\turl: 'wss://gateway.discord.gg',\n};\n"
  },
  {
    "path": "packages/ws/__tests__/strategy/WorkerContextFetchingStrategy.test.ts",
    "content": "import { test, vi, expect } from 'vitest';\nimport {\n\tmanagerToFetchingStrategyOptions,\n\tWorkerContextFetchingStrategy,\n\tWebSocketManager,\n\tWorkerSendPayloadOp,\n\tWorkerReceivePayloadOp,\n\ttype WorkerReceivePayload,\n\ttype WorkerSendPayload,\n\ttype SessionInfo,\n} from '../../src/index.js';\nimport { mockGatewayInformation } from '../gateway.mock.js';\n\nconst session: SessionInfo = {\n\tshardId: 0,\n\tshardCount: 1,\n\tsequence: 123,\n\tsessionId: 'abc',\n\tresumeURL: 'wss://resume.url/',\n};\n\nvi.mock('node:worker_threads', async () => {\n\t// eslint-disable-next-line @typescript-eslint/consistent-type-imports\n\tconst { EventEmitter }: typeof import('node:events') = await vi.importActual('node:events');\n\tclass MockParentPort extends EventEmitter {\n\t\tpublic postMessage(message: WorkerReceivePayload) {\n\t\t\tif (message.op === WorkerReceivePayloadOp.RetrieveSessionInfo) {\n\t\t\t\tconst response: WorkerSendPayload = {\n\t\t\t\t\top: WorkerSendPayloadOp.SessionInfoResponse,\n\t\t\t\t\tnonce: message.nonce,\n\t\t\t\t\tsession,\n\t\t\t\t};\n\t\t\t\tthis.emit('message', response);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tparentPort: new MockParentPort(),\n\t\tisMainThread: false,\n\t\tworkerData: {},\n\t};\n});\n\ntest('session info', async () => {\n\tconst manager = new WebSocketManager({\n\t\ttoken: 'A-Very-Fake-Token',\n\t\tintents: 0,\n\t\tasync fetchGatewayInformation() {\n\t\t\treturn mockGatewayInformation;\n\t\t},\n\t});\n\n\tconst strategy = new WorkerContextFetchingStrategy(await managerToFetchingStrategyOptions(manager));\n\n\tstrategy.updateSessionInfo(0, session);\n\texpect(await strategy.retrieveSessionInfo(0)).toEqual(session);\n});\n"
  },
  {
    "path": "packages/ws/__tests__/strategy/WorkerShardingStrategy.test.ts",
    "content": "/* eslint-disable id-length */\nimport type { GatewayDispatchPayload, GatewaySendPayload } from 'discord-api-types/v10';\nimport { GatewayDispatchEvents, GatewayOpcodes } from 'discord-api-types/v10';\nimport { test, vi, expect, afterEach } from 'vitest';\nimport {\n\tWebSocketManager,\n\tWorkerSendPayloadOp,\n\tWorkerReceivePayloadOp,\n\tWorkerShardingStrategy,\n\tWebSocketShardEvents,\n\ttype WorkerReceivePayload,\n\ttype WorkerSendPayload,\n\ttype SessionInfo,\n} from '../../src/index.js';\nimport { mockGatewayInformation } from '../gateway.mock.js';\n\nconst mockConstructor = vi.fn();\nconst mockSend = vi.fn();\nconst mockTerminate = vi.fn();\n\nconst memberChunkData = {\n\top: GatewayOpcodes.Dispatch,\n\ts: 123,\n\tt: GatewayDispatchEvents.GuildMembersChunk,\n\td: {\n\t\tguild_id: '123',\n\t\tmembers: [],\n\t},\n} as unknown as GatewayDispatchPayload;\n\nconst sessionInfo: SessionInfo = {\n\tshardId: 0,\n\tshardCount: 2,\n\tsequence: 123,\n\tsessionId: 'abc',\n\tresumeURL: 'wss://ehehe.gg',\n};\n\nvi.mock('node:worker_threads', async () => {\n\t// eslint-disable-next-line @typescript-eslint/consistent-type-imports\n\tconst { EventEmitter }: typeof import('node:events') = await vi.importActual('node:events');\n\tclass MockWorker extends EventEmitter {\n\t\tpublic constructor(...args: any[]) {\n\t\t\tsuper();\n\t\t\tmockConstructor(...args);\n\t\t\t// need to delay this by an event loop cycle to allow the strategy to attach a listener\n\t\t\tsetImmediate(() => {\n\t\t\t\tthis.emit('online');\n\t\t\t\t// same deal here\n\t\t\t\tsetImmediate(() => {\n\t\t\t\t\tconst message: WorkerReceivePayload = {\n\t\t\t\t\t\top: WorkerReceivePayloadOp.WorkerReady,\n\t\t\t\t\t};\n\t\t\t\t\tthis.emit('message', message);\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tpublic postMessage(message: WorkerSendPayload) {\n\t\t\tswitch (message.op) {\n\t\t\t\tcase WorkerSendPayloadOp.Connect: {\n\t\t\t\t\tconst response: WorkerReceivePayload = {\n\t\t\t\t\t\top: WorkerReceivePayloadOp.Connected,\n\t\t\t\t\t\tshardId: message.shardId,\n\t\t\t\t\t};\n\t\t\t\t\tthis.emit('message', response);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WorkerSendPayloadOp.Destroy: {\n\t\t\t\t\tconst response: WorkerReceivePayload = {\n\t\t\t\t\t\top: WorkerReceivePayloadOp.Destroyed,\n\t\t\t\t\t\tshardId: message.shardId,\n\t\t\t\t\t};\n\t\t\t\t\tthis.emit('message', response);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WorkerSendPayloadOp.Send: {\n\t\t\t\t\tif (message.payload.op === GatewayOpcodes.RequestGuildMembers) {\n\t\t\t\t\t\tconst response: WorkerReceivePayload = {\n\t\t\t\t\t\t\top: WorkerReceivePayloadOp.Event,\n\t\t\t\t\t\t\tshardId: message.shardId,\n\t\t\t\t\t\t\tevent: WebSocketShardEvents.Dispatch,\n\t\t\t\t\t\t\tdata: [memberChunkData],\n\t\t\t\t\t\t};\n\t\t\t\t\t\tthis.emit('message', response);\n\n\t\t\t\t\t\t// Fetch session info\n\t\t\t\t\t\tconst sessionFetch: WorkerReceivePayload = {\n\t\t\t\t\t\t\top: WorkerReceivePayloadOp.RetrieveSessionInfo,\n\t\t\t\t\t\t\tshardId: message.shardId,\n\t\t\t\t\t\t\tnonce: Math.random(),\n\t\t\t\t\t\t};\n\t\t\t\t\t\tthis.emit('message', sessionFetch);\n\t\t\t\t\t}\n\n\t\t\t\t\tmockSend(message.shardId, message.payload);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WorkerSendPayloadOp.SessionInfoResponse: {\n\t\t\t\t\tmessage.session ??= sessionInfo;\n\n\t\t\t\t\tconst session: WorkerReceivePayload = {\n\t\t\t\t\t\top: WorkerReceivePayloadOp.UpdateSessionInfo,\n\t\t\t\t\t\tshardId: message.session.shardId,\n\t\t\t\t\t\tsession: { ...message.session, sequence: message.session.sequence + 1 },\n\t\t\t\t\t};\n\t\t\t\t\tthis.emit('message', session);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WorkerSendPayloadOp.ShardIdentifyResponse: {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase WorkerSendPayloadOp.FetchStatus: {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic terminate = mockTerminate;\n\t}\n\n\treturn {\n\t\tWorker: MockWorker,\n\t\tworkerData: {},\n\t};\n});\n\nafterEach(() => {\n\tmockConstructor.mockClear();\n\tmockSend.mockClear();\n\tmockTerminate.mockClear();\n});\n\ntest('spawn, connect, send a message, session info, and destroy', async () => {\n\tconst mockRetrieveSessionInfo = vi.fn();\n\tconst mockUpdateSessionInfo = vi.fn();\n\tconst manager = new WebSocketManager({\n\t\ttoken: 'A-Very-Fake-Token',\n\t\tintents: 0,\n\t\tasync fetchGatewayInformation() {\n\t\t\treturn mockGatewayInformation;\n\t\t},\n\t\tshardIds: [0, 1],\n\t\tretrieveSessionInfo: mockRetrieveSessionInfo,\n\t\tupdateSessionInfo: mockUpdateSessionInfo,\n\t\tbuildStrategy: (manager) => new WorkerShardingStrategy(manager, { shardsPerWorker: 'all' }),\n\t});\n\n\tconst managerEmitSpy = vi.spyOn(manager, 'emit');\n\n\tawait manager.connect();\n\texpect(mockConstructor).toHaveBeenCalledWith(\n\t\texpect.stringContaining('defaultWorker.js'),\n\t\texpect.objectContaining({ workerData: expect.objectContaining({ shardIds: [0, 1] }) }),\n\t);\n\n\tconst payload: GatewaySendPayload = {\n\t\top: GatewayOpcodes.RequestGuildMembers,\n\t\td: { guild_id: '123', limit: 0, query: '' },\n\t};\n\tawait manager.send(0, payload);\n\texpect(mockSend).toHaveBeenCalledWith(0, payload);\n\texpect(managerEmitSpy).toHaveBeenCalledWith(\n\t\tWebSocketShardEvents.Dispatch,\n\t\t{\n\t\t\t...memberChunkData,\n\t\t},\n\t\t0,\n\t);\n\texpect(mockRetrieveSessionInfo).toHaveBeenCalledWith(0);\n\texpect(mockUpdateSessionInfo).toHaveBeenCalledWith(0, { ...sessionInfo, sequence: sessionInfo.sequence + 1 });\n\n\tawait manager.destroy({ reason: 'souji is a soft boi :3' });\n\texpect(mockTerminate).toHaveBeenCalled();\n});\n"
  },
  {
    "path": "packages/ws/__tests__/types/WebSocketManager.test-d.ts",
    "content": "import type { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';\nimport { expectTypeOf } from 'vitest';\nimport type { ManagerShardEventsMap, WebSocketShardEventsMap, WebSocketManager } from '../../src/index.js';\n\ndeclare const manager: WebSocketManager;\ndeclare const eventMap: ManagerShardEventsMap;\n\ntype AugmentedShardEventsMap = {\n\t[K in keyof WebSocketShardEventsMap]: [...WebSocketShardEventsMap[K], shardId: number];\n};\n\nexpectTypeOf(eventMap).toEqualTypeOf<AugmentedShardEventsMap>();\nexpectTypeOf(manager).toMatchTypeOf<AsyncEventEmitter<AugmentedShardEventsMap>>();\n"
  },
  {
    "path": "packages/ws/__tests__/util/SimpleIdentifyThrottler.test.ts",
    "content": "import * as timers from 'node:timers/promises';\nimport { expect, test, vi, beforeEach, afterEach } from 'vitest';\nimport { SimpleIdentifyThrottler } from '../../src/index.js';\n\nvi.mock('node:timers/promises', () => ({\n\tsetTimeout: vi.fn(),\n}));\n\nlet throttler: SimpleIdentifyThrottler;\nconst controller = new AbortController();\n\nvi.useFakeTimers();\n\nconst TIME = Date.now();\nconst NOW = vi.fn().mockReturnValue(TIME);\nglobal.Date.now = NOW;\n\nconst sleep = vi.spyOn(timers, 'setTimeout');\n\nbeforeEach(() => {\n\tthrottler = new SimpleIdentifyThrottler(2);\n});\n\nafterEach(() => {\n\tsleep.mockClear();\n});\n\ntest('basic case', async () => {\n\t// Those shouldn't wait since they're in different keys\n\tawait throttler.waitForIdentify(0, controller.signal);\n\texpect(sleep).not.toHaveBeenCalled();\n\n\tawait throttler.waitForIdentify(1, controller.signal);\n\texpect(sleep).not.toHaveBeenCalled();\n\n\t// Those should wait\n\tawait throttler.waitForIdentify(2, controller.signal);\n\texpect(sleep).toHaveBeenCalledTimes(1);\n\n\tawait throttler.waitForIdentify(3, controller.signal);\n\texpect(sleep).toHaveBeenCalledTimes(2);\n});\n\ntest('does not call sleep with a negative time', async () => {\n\tawait throttler.waitForIdentify(0, controller.signal);\n\texpect(sleep).not.toHaveBeenCalled();\n\n\tawait throttler.waitForIdentify(0, controller.signal);\n\texpect(sleep).toHaveBeenCalledTimes(1);\n\n\t// By overshooting, we're simulating a bug that existed prior to this test, where-in by enough time\n\t// passing before the shard tried to identify for a subsequent time, the passed value would end up being negative\n\t// (and this was unchecked). Node simply treats that as 1ms, so it wasn't particularly harmful, but they\n\t// recently introduced a warning for it, so we want to avoid that.\n\tNOW.mockReturnValueOnce(TIME + 10_000);\n\tawait throttler.waitForIdentify(0, controller.signal);\n\texpect(sleep).toHaveBeenCalledTimes(1);\n});\n"
  },
  {
    "path": "packages/ws/__tests__/ws/WebSocketManager.test.ts",
    "content": "import type { GatewaySendPayload } from 'discord-api-types/v10';\nimport { GatewayOpcodes } from 'discord-api-types/v10';\nimport { describe, expect, test, vi } from 'vitest';\nimport { WebSocketManager, type IShardingStrategy } from '../../src/index.js';\nimport { mockGatewayInformation } from '../gateway.mock.js';\n\nvi.useFakeTimers();\n\nconst NOW = vi.fn().mockReturnValue(Date.now());\nglobal.Date.now = NOW;\n\ntest('fetch gateway information', async () => {\n\tconst fetchGatewayInformation = vi.fn(async () => mockGatewayInformation);\n\n\tconst manager = new WebSocketManager({\n\t\ttoken: 'A-Very-Fake-Token',\n\t\tintents: 0,\n\t\tfetchGatewayInformation,\n\t});\n\n\tconst initial = await manager.fetchGatewayInformation();\n\texpect(initial).toEqual(mockGatewayInformation);\n\texpect(fetchGatewayInformation).toHaveBeenCalledOnce();\n\n\tfetchGatewayInformation.mockClear();\n\n\tconst cached = await manager.fetchGatewayInformation();\n\texpect(cached).toEqual(mockGatewayInformation);\n\texpect(fetchGatewayInformation).not.toHaveBeenCalled();\n\n\tfetchGatewayInformation.mockClear();\n\n\tconst forced = await manager.fetchGatewayInformation(true);\n\texpect(forced).toEqual(mockGatewayInformation);\n\texpect(fetchGatewayInformation).toHaveBeenCalledOnce();\n\n\tfetchGatewayInformation.mockClear();\n\n\tNOW.mockReturnValue(Number.POSITIVE_INFINITY);\n\tconst cacheExpired = await manager.fetchGatewayInformation();\n\texpect(cacheExpired).toEqual(mockGatewayInformation);\n\texpect(fetchGatewayInformation).toHaveBeenCalledOnce();\n});\n\ndescribe('get shard count', () => {\n\ttest('with shard count', async () => {\n\t\tconst manager = new WebSocketManager({\n\t\t\ttoken: 'A-Very-Fake-Token',\n\t\t\tintents: 0,\n\t\t\tshardCount: 2,\n\t\t\tasync fetchGatewayInformation() {\n\t\t\t\treturn mockGatewayInformation;\n\t\t\t},\n\t\t});\n\n\t\texpect(await manager.getShardCount()).toBe(2);\n\t});\n\n\ttest('with shard ids array', async () => {\n\t\tconst shardIds = [5, 9];\n\t\tconst manager = new WebSocketManager({\n\t\t\ttoken: 'A-Very-Fake-Token',\n\t\t\tintents: 0,\n\t\t\tshardIds,\n\t\t\tasync fetchGatewayInformation() {\n\t\t\t\treturn mockGatewayInformation;\n\t\t\t},\n\t\t});\n\n\t\texpect(await manager.getShardCount()).toBe(shardIds.at(-1)! + 1);\n\t});\n\n\ttest('with shard id range', async () => {\n\t\tconst shardIds = { start: 5, end: 9 };\n\t\tconst manager = new WebSocketManager({\n\t\t\ttoken: 'A-Very-Fake-Token',\n\t\t\tintents: 0,\n\t\t\tshardIds,\n\t\t\tasync fetchGatewayInformation() {\n\t\t\t\treturn mockGatewayInformation;\n\t\t\t},\n\t\t});\n\n\t\texpect(await manager.getShardCount()).toBe(shardIds.end + 1);\n\t});\n});\n\ntest('update shard count', async () => {\n\tconst fetchGatewayInformation = vi.fn(async () => mockGatewayInformation);\n\n\tconst manager = new WebSocketManager({\n\t\ttoken: 'A-Very-Fake-Token',\n\t\tintents: 0,\n\t\tshardCount: 2,\n\t\tfetchGatewayInformation,\n\t});\n\n\texpect(await manager.getShardCount()).toBe(2);\n\texpect(fetchGatewayInformation).not.toHaveBeenCalled();\n\n\tfetchGatewayInformation.mockClear();\n\n\tawait manager.updateShardCount(3);\n\texpect(await manager.getShardCount()).toBe(3);\n\texpect(fetchGatewayInformation).toHaveBeenCalled();\n});\n\ntest('it handles passing in both shardIds and shardCount', async () => {\n\tconst shardIds = { start: 2, end: 3 };\n\tconst manager = new WebSocketManager({\n\t\ttoken: 'A-Very-Fake-Token',\n\t\tintents: 0,\n\t\tshardIds,\n\t\tshardCount: 4,\n\t\tasync fetchGatewayInformation() {\n\t\t\treturn mockGatewayInformation;\n\t\t},\n\t});\n\n\texpect(await manager.getShardCount()).toBe(4);\n\texpect(await manager.getShardIds()).toStrictEqual([2, 3]);\n});\n\ntest('strategies', async () => {\n\tclass MockStrategy implements IShardingStrategy {\n\t\tpublic spawn = vi.fn();\n\n\t\tpublic connect = vi.fn();\n\n\t\tpublic destroy = vi.fn();\n\n\t\tpublic send = vi.fn();\n\n\t\tpublic fetchStatus = vi.fn();\n\t}\n\n\tconst strategy = new MockStrategy();\n\n\tconst shardIds = [0, 1, 2];\n\n\tconst manager = new WebSocketManager({\n\t\ttoken: 'A-Very-Fake-Token',\n\t\tintents: 0,\n\t\tshardIds,\n\t\tasync fetchGatewayInformation() {\n\t\t\treturn mockGatewayInformation;\n\t\t},\n\t\tbuildStrategy: () => strategy,\n\t});\n\n\tawait manager.connect();\n\texpect(strategy.spawn).toHaveBeenCalledWith(shardIds);\n\texpect(strategy.connect).toHaveBeenCalled();\n\n\tconst destroyOptions = { reason: ':3' };\n\tawait manager.destroy(destroyOptions);\n\texpect(strategy.destroy).toHaveBeenCalledWith(destroyOptions);\n\n\tconst send: GatewaySendPayload = {\n\t\top: GatewayOpcodes.RequestGuildMembers,\n\t\t// eslint-disable-next-line id-length\n\t\td: { guild_id: '1234', limit: 0, query: '' },\n\t};\n\tawait manager.send(0, send);\n\texpect(strategy.send).toHaveBeenCalledWith(0, send);\n});\n"
  },
  {
    "path": "packages/ws/api-extractor.json",
    "content": "{\n\t\"extends\": \"../../api-extractor.json\",\n\t\"docModel\": {\n\t\t\"projectFolderUrl\": \"https://github.com/discordjs/discord.js/tree/main/packages/ws\"\n\t}\n}\n"
  },
  {
    "path": "packages/ws/cliff.toml",
    "content": "[changelog]\nheader = \"\"\"\n# Changelog\n\nAll notable changes to this project will be documented in this file.\\n\n\"\"\"\nbody = \"\"\"\n{%- macro remote_url() -%}\n  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\n{%- endmacro -%}\n{% if version %}\\\n\t# [{{ version | trim_start_matches(pat=\"v\") }}]\\\n\t{% if previous %}\\\n\t\t{% if previous.version %}\\\n\t\t\t({{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }})\\\n\t\t{% else %}\\\n\t\t\t({{ self::remote_url() }}/tree/{{ version }})\\\n\t\t{% endif %}\\\n\t{% endif %} \\\n\t- ({{ timestamp | date(format=\"%Y-%m-%d\") }})\n{% else %}\\\n\t# [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n\t## {{ group | upper_first }}\n\t{% for commit in commits %}\n\t\t- {% if commit.scope %}\\\n\t\t\t**{{commit.scope}}:** \\\n\t\t  {% endif %}\\\n\t\t\t{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end=\"\") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\\\n\t\t\t{% if commit.github.username %} by @{{ commit.github.username }}{%- endif %}\\\n\t\t{% if commit.breaking %}\\\n\t\t\t{% for footer in commit.footers %}\\\n\t\t\t\t{% if footer.breaking %}\\\n\t\t\t\t\t\\n{% raw %}  {% endraw %}- **{{ footer.token }}{{ footer.separator }}** {{ footer.value }}\\\n\t\t\t\t{% endif %}\\\n\t\t\t{% endfor %}\\\n\t\t{% endif %}\\\n\t{% endfor %}\n{% endfor %}\\\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length %}\\\n\t\\n### New Contributors\\n\n\t{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\\\n\t\t* @{{ contributor.username }} made their first contribution in #{{ contributor.pr_number }}\n\t{% endfor %}\\\n{% endif %}\\n\n\"\"\"\ntrim = true\nfooter = \"\"\n\n[git]\nconventional_commits = true\nfilter_unconventional = true\ncommit_parsers = [\n\t{ message = \"^feat\", group = \"Features\"},\n\t{ message = \"^fix\", group = \"Bug Fixes\"},\n\t{ message = \"^docs\", group = \"Documentation\"},\n\t{ message = \"^perf\", group = \"Performance\"},\n\t{ message = \"^refactor\", group = \"Refactor\"},\n\t{ message = \"^types\", group = \"Typings\"},\n\t{ message = \".*deprecated\", body = \".*deprecated\", group = \"Deprecation\"},\n\t{ message = \"^revert\", skip = true},\n\t{ message = \"^style\", group = \"Styling\"},\n\t{ message = \"^test\", group = \"Testing\"},\n\t{ message = \"^chore\", skip = true},\n\t{ message = \"^ci\", skip = true},\n\t{ message = \"^build\", skip = true},\n\t{ body = \".*security\", group = \"Security\"},\n]\nfilter_commits = true\nprotect_breaking_commits = true\ntag_pattern = \"@discordjs/ws@[0-9]*\"\nignore_tags = \"\"\ntopo_order = false\nsort_commits = \"newest\"\n\n[remote.github]\nowner = \"discordjs\"\nrepo = \"discord.js\"\n"
  },
  {
    "path": "packages/ws/docs/README.md",
    "content": "## [View the documentation here.](https://discord.js.org/docs/packages/ws/main)\n"
  },
  {
    "path": "packages/ws/package.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/package.json\",\n\t\"name\": \"@discordjs/ws\",\n\t\"version\": \"2.0.2\",\n\t\"description\": \"Wrapper around Discord's gateway\",\n\t\"scripts\": {\n\t\t\"test\": \"vitest run --config ../../vitest.config.ts\",\n\t\t\"build\": \"tsc --noEmit && tsup\",\n\t\t\"build:docs\": \"tsc -p tsconfig.docs.json\",\n\t\t\"lint\": \"prettier --check . && cross-env TIMING=1 eslint --format=pretty src __tests__\",\n\t\t\"format\": \"prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src __tests__\",\n\t\t\"docs\": \"pnpm run build:docs && api-extractor run --local --minify && generate-split-documentation\",\n\t\t\"prepack\": \"pnpm run build && pnpm run lint\",\n\t\t\"changelog\": \"git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/ws/*'\",\n\t\t\"release\": \"cliff-jumper\"\n\t},\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/index.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/index.d.mts\",\n\t\t\t\t\"default\": \"./dist/index.mjs\"\n\t\t\t}\n\t\t},\n\t\t\"./defaultWorker\": {\n\t\t\t\"require\": {\n\t\t\t\t\"types\": null,\n\t\t\t\t\"default\": \"./dist/defaultWorker.js\"\n\t\t\t},\n\t\t\t\"import\": {\n\t\t\t\t\"types\": null,\n\t\t\t\t\"default\": \"./dist/defaultWorker.mjs\"\n\t\t\t}\n\t\t}\n\t},\n\t\"main\": \"./dist/index.js\",\n\t\"module\": \"./dist/index.mjs\",\n\t\"types\": \"./dist/index.d.ts\",\n\t\"directories\": {\n\t\t\"lib\": \"src\",\n\t\t\"test\": \"__tests__\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"contributors\": [\n\t\t\"Crawl <icrawltogo@gmail.com>\",\n\t\t\"Amish Shah <amishshah.2k@gmail.com>\",\n\t\t\"SpaceEEC <spaceeec@yahoo.com>\",\n\t\t\"Vlad Frangu <me@vladfrangu.dev>\",\n\t\t\"Aura Román <kyradiscord@gmail.com>\",\n\t\t\"DD <didinele.dev@gmail.com>\"\n\t],\n\t\"license\": \"Apache-2.0\",\n\t\"keywords\": [\n\t\t\"discord\",\n\t\t\"api\",\n\t\t\"gateway\",\n\t\t\"discordapp\",\n\t\t\"discordjs\"\n\t],\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/discordjs/discord.js.git\",\n\t\t\"directory\": \"packages/ws\"\n\t},\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/discordjs/discord.js/issues\"\n\t},\n\t\"homepage\": \"https://discord.js.org\",\n\t\"funding\": \"https://github.com/discordjs/discord.js?sponsor\",\n\t\"dependencies\": {\n\t\t\"@discordjs/collection\": \"workspace:^\",\n\t\t\"@discordjs/util\": \"workspace:^\",\n\t\t\"@sapphire/async-queue\": \"^1.5.5\",\n\t\t\"@types/ws\": \"^8.18.1\",\n\t\t\"@vladfrangu/async_event_emitter\": \"^2.4.7\",\n\t\t\"discord-api-types\": \"^0.38.41\",\n\t\t\"tslib\": \"^2.8.1\",\n\t\t\"ws\": \"^8.19.0\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@discordjs/api-extractor\": \"workspace:^\",\n\t\t\"@discordjs/scripts\": \"workspace:^\",\n\t\t\"@favware/cliff-jumper\": \"^6.0.0\",\n\t\t\"@types/node\": \"^22.19.11\",\n\t\t\"@vitest/coverage-v8\": \"^4.0.18\",\n\t\t\"cross-env\": \"^10.1.0\",\n\t\t\"esbuild-plugin-version-injector\": \"^1.2.1\",\n\t\t\"eslint\": \"^9.39.2\",\n\t\t\"eslint-config-neon\": \"^0.3.2\",\n\t\t\"eslint-formatter-compact\": \"^9.0.1\",\n\t\t\"eslint-formatter-pretty\": \"^7.0.0\",\n\t\t\"mock-socket\": \"^9.3.1\",\n\t\t\"prettier\": \"^3.8.1\",\n\t\t\"tsup\": \"^8.5.1\",\n\t\t\"turbo\": \"^2.8.10\",\n\t\t\"typescript\": \"~5.9.3\",\n\t\t\"vitest\": \"^4.0.18\",\n\t\t\"zlib-sync\": \"^0.1.10\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\",\n\t\t\"provenance\": true\n\t}\n}\n"
  },
  {
    "path": "packages/ws/src/index.ts",
    "content": "export * from './strategies/context/IContextFetchingStrategy.js';\nexport * from './strategies/context/SimpleContextFetchingStrategy.js';\nexport * from './strategies/context/WorkerContextFetchingStrategy.js';\n\nexport type * from './strategies/sharding/IShardingStrategy.js';\nexport * from './strategies/sharding/SimpleShardingStrategy.js';\nexport * from './strategies/sharding/WorkerShardingStrategy.js';\n\nexport type * from './throttling/IIdentifyThrottler.js';\nexport * from './throttling/SimpleIdentifyThrottler.js';\n\nexport * from './utils/constants.js';\nexport * from './utils/WorkerBootstrapper.js';\n\nexport * from './ws/WebSocketManager.js';\nexport * from './ws/WebSocketShard.js';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/ws#readme | @discordjs/ws} version\n * that you are currently using.\n */\n// This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild\nexport const version = '[VI]{{inject}}[/VI]' as string;\n"
  },
  {
    "path": "packages/ws/src/strategies/context/IContextFetchingStrategy.ts",
    "content": "import type { Awaitable } from '@discordjs/util';\nimport type { APIGatewayBotInfo } from 'discord-api-types/v10';\nimport type { SessionInfo, WebSocketManager, WebSocketManagerOptions } from '../../ws/WebSocketManager.js';\n\nexport interface FetchingStrategyOptions extends Pick<\n\tWebSocketManagerOptions,\n\t| 'compression'\n\t| 'encoding'\n\t| 'handshakeTimeout'\n\t| 'helloTimeout'\n\t| 'identifyProperties'\n\t| 'initialPresence'\n\t| 'intents'\n\t| 'largeThreshold'\n\t| 'readyTimeout'\n\t| 'token'\n\t| 'useIdentifyCompression'\n\t| 'version'\n> {\n\treadonly gatewayInformation: APIGatewayBotInfo;\n\treadonly shardCount: number;\n}\n\n/**\n * Strategies responsible solely for making manager information accessible\n */\nexport interface IContextFetchingStrategy {\n\treadonly options: FetchingStrategyOptions;\n\tretrieveSessionInfo(shardId: number): Awaitable<SessionInfo | null>;\n\tupdateSessionInfo(shardId: number, sessionInfo: SessionInfo | null): Awaitable<void>;\n\t/**\n\t * Resolves once the given shard should be allowed to identify\n\t * This should correctly handle the signal and reject with an abort error if the operation is aborted.\n\t * Other errors will cause the shard to reconnect.\n\t */\n\twaitForIdentify(shardId: number, signal: AbortSignal): Promise<void>;\n}\n\nexport async function managerToFetchingStrategyOptions(manager: WebSocketManager): Promise<FetchingStrategyOptions> {\n\treturn {\n\t\tcompression: manager.options.compression,\n\t\tencoding: manager.options.encoding,\n\t\thandshakeTimeout: manager.options.handshakeTimeout,\n\t\thelloTimeout: manager.options.helloTimeout,\n\t\tidentifyProperties: manager.options.identifyProperties,\n\t\tinitialPresence: manager.options.initialPresence,\n\t\tintents: manager.options.intents,\n\t\tlargeThreshold: manager.options.largeThreshold,\n\t\treadyTimeout: manager.options.readyTimeout,\n\t\ttoken: manager.token,\n\t\tuseIdentifyCompression: manager.options.useIdentifyCompression,\n\t\tversion: manager.options.version,\n\n\t\tgatewayInformation: await manager.fetchGatewayInformation(),\n\t\tshardCount: await manager.getShardCount(),\n\t};\n}\n"
  },
  {
    "path": "packages/ws/src/strategies/context/SimpleContextFetchingStrategy.ts",
    "content": "import type { Awaitable } from '@discordjs/util';\nimport type { IIdentifyThrottler } from '../../throttling/IIdentifyThrottler.js';\nimport type { SessionInfo, WebSocketManager } from '../../ws/WebSocketManager.js';\nimport type { FetchingStrategyOptions, IContextFetchingStrategy } from './IContextFetchingStrategy.js';\n\nexport class SimpleContextFetchingStrategy implements IContextFetchingStrategy {\n\t// This strategy assumes every shard is running under the same process - therefore we need a single\n\t// IdentifyThrottler per manager.\n\tprivate static throttlerCache = new WeakMap<WebSocketManager, IIdentifyThrottler>();\n\n\tprivate static async ensureThrottler(manager: WebSocketManager): Promise<IIdentifyThrottler> {\n\t\tconst throttler = SimpleContextFetchingStrategy.throttlerCache.get(manager);\n\t\tif (throttler) {\n\t\t\treturn throttler;\n\t\t}\n\n\t\tconst newThrottler = await manager.options.buildIdentifyThrottler(manager);\n\t\tSimpleContextFetchingStrategy.throttlerCache.set(manager, newThrottler);\n\n\t\treturn newThrottler;\n\t}\n\n\tpublic constructor(\n\t\tprivate readonly manager: WebSocketManager,\n\t\tpublic readonly options: FetchingStrategyOptions,\n\t) {}\n\n\tpublic async retrieveSessionInfo(shardId: number): Promise<SessionInfo | null> {\n\t\treturn this.manager.options.retrieveSessionInfo(shardId);\n\t}\n\n\tpublic updateSessionInfo(shardId: number, sessionInfo: SessionInfo | null): Awaitable<void> {\n\t\treturn this.manager.options.updateSessionInfo(shardId, sessionInfo);\n\t}\n\n\tpublic async waitForIdentify(shardId: number, signal: AbortSignal): Promise<void> {\n\t\tconst throttler = await SimpleContextFetchingStrategy.ensureThrottler(this.manager);\n\t\tawait throttler.waitForIdentify(shardId, signal);\n\t}\n}\n"
  },
  {
    "path": "packages/ws/src/strategies/context/WorkerContextFetchingStrategy.ts",
    "content": "import { isMainThread, parentPort } from 'node:worker_threads';\nimport { Collection } from '@discordjs/collection';\nimport type { SessionInfo } from '../../ws/WebSocketManager.js';\nimport {\n\tWorkerReceivePayloadOp,\n\tWorkerSendPayloadOp,\n\ttype WorkerReceivePayload,\n\ttype WorkerSendPayload,\n} from '../sharding/WorkerShardingStrategy.js';\nimport type { FetchingStrategyOptions, IContextFetchingStrategy } from './IContextFetchingStrategy.js';\n\nexport class WorkerContextFetchingStrategy implements IContextFetchingStrategy {\n\tprivate readonly sessionPromises = new Collection<number, (session: SessionInfo | null) => void>();\n\n\tprivate readonly waitForIdentifyPromises = new Collection<\n\t\tnumber,\n\t\t{ reject(error: unknown): void; resolve(): void; signal: AbortSignal }\n\t>();\n\n\tpublic constructor(public readonly options: FetchingStrategyOptions) {\n\t\tif (isMainThread) {\n\t\t\tthrow new Error('Cannot instantiate WorkerContextFetchingStrategy on the main thread');\n\t\t}\n\n\t\tparentPort!.on('message', (payload: WorkerSendPayload) => {\n\t\t\tif (payload.op === WorkerSendPayloadOp.SessionInfoResponse) {\n\t\t\t\tthis.sessionPromises.get(payload.nonce)?.(payload.session);\n\t\t\t\tthis.sessionPromises.delete(payload.nonce);\n\t\t\t}\n\n\t\t\tif (payload.op === WorkerSendPayloadOp.ShardIdentifyResponse) {\n\t\t\t\tconst promise = this.waitForIdentifyPromises.get(payload.nonce);\n\t\t\t\tif (payload.ok) {\n\t\t\t\t\tpromise?.resolve();\n\t\t\t\t} else {\n\t\t\t\t\t// We need to make sure we reject with an abort error\n\t\t\t\t\tpromise?.reject(promise.signal.reason);\n\t\t\t\t}\n\n\t\t\t\tthis.waitForIdentifyPromises.delete(payload.nonce);\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic async retrieveSessionInfo(shardId: number): Promise<SessionInfo | null> {\n\t\tconst nonce = Math.random();\n\t\tconst payload: WorkerReceivePayload = {\n\t\t\top: WorkerReceivePayloadOp.RetrieveSessionInfo,\n\t\t\tshardId,\n\t\t\tnonce,\n\t\t};\n\t\t// eslint-disable-next-line no-promise-executor-return\n\t\tconst promise = new Promise<SessionInfo | null>((resolve) => this.sessionPromises.set(nonce, resolve));\n\t\tparentPort!.postMessage(payload);\n\t\treturn promise;\n\t}\n\n\tpublic updateSessionInfo(shardId: number, sessionInfo: SessionInfo | null) {\n\t\tconst payload: WorkerReceivePayload = {\n\t\t\top: WorkerReceivePayloadOp.UpdateSessionInfo,\n\t\t\tshardId,\n\t\t\tsession: sessionInfo,\n\t\t};\n\t\tparentPort!.postMessage(payload);\n\t}\n\n\tpublic async waitForIdentify(shardId: number, signal: AbortSignal): Promise<void> {\n\t\tconst nonce = Math.random();\n\n\t\tconst payload: WorkerReceivePayload = {\n\t\t\top: WorkerReceivePayloadOp.WaitForIdentify,\n\t\t\tnonce,\n\t\t\tshardId,\n\t\t};\n\t\tconst promise = new Promise<void>((resolve, reject) =>\n\t\t\t// eslint-disable-next-line no-promise-executor-return\n\t\t\tthis.waitForIdentifyPromises.set(nonce, { signal, resolve, reject }),\n\t\t);\n\n\t\tparentPort!.postMessage(payload);\n\n\t\tconst listener = () => {\n\t\t\tconst payload: WorkerReceivePayload = {\n\t\t\t\top: WorkerReceivePayloadOp.CancelIdentify,\n\t\t\t\tnonce,\n\t\t\t};\n\n\t\t\tparentPort!.postMessage(payload);\n\t\t};\n\n\t\tsignal.addEventListener('abort', listener);\n\n\t\ttry {\n\t\t\tawait promise;\n\t\t} finally {\n\t\t\tsignal.removeEventListener('abort', listener);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/ws/src/strategies/sharding/IShardingStrategy.ts",
    "content": "import type { Collection } from '@discordjs/collection';\nimport type { Awaitable } from '@discordjs/util';\nimport type { GatewaySendPayload } from 'discord-api-types/v10';\nimport type { WebSocketShardDestroyOptions, WebSocketShardStatus } from '../../ws/WebSocketShard.js';\n\n/**\n * Strategies responsible for spawning, initializing connections, destroying shards, and relaying events\n */\nexport interface IShardingStrategy {\n\t/**\n\t * Initializes all the shards\n\t */\n\tconnect(): Awaitable<void>;\n\t/**\n\t * Destroys all the shards\n\t */\n\tdestroy(options?: Omit<WebSocketShardDestroyOptions, 'recover'>): Awaitable<void>;\n\t/**\n\t * Fetches the status of all the shards\n\t */\n\tfetchStatus(): Awaitable<Collection<number, WebSocketShardStatus>>;\n\t/**\n\t * Sends a payload to a shard\n\t */\n\tsend(shardId: number, payload: GatewaySendPayload): Awaitable<void>;\n\t/**\n\t * Spawns all the shards\n\t */\n\tspawn(shardIds: number[]): Awaitable<void>;\n}\n"
  },
  {
    "path": "packages/ws/src/strategies/sharding/SimpleShardingStrategy.ts",
    "content": "import { Collection } from '@discordjs/collection';\nimport type { GatewaySendPayload } from 'discord-api-types/v10';\nimport type { WebSocketManager } from '../../ws/WebSocketManager.js';\nimport { WebSocketShard, WebSocketShardEvents, type WebSocketShardDestroyOptions } from '../../ws/WebSocketShard.js';\nimport { managerToFetchingStrategyOptions } from '../context/IContextFetchingStrategy.js';\nimport { SimpleContextFetchingStrategy } from '../context/SimpleContextFetchingStrategy.js';\nimport type { IShardingStrategy } from './IShardingStrategy.js';\n\n/**\n * Simple strategy that just spawns shards in the current process\n */\nexport class SimpleShardingStrategy implements IShardingStrategy {\n\tprivate readonly manager: WebSocketManager;\n\n\tprivate readonly shards = new Collection<number, WebSocketShard>();\n\n\tpublic constructor(manager: WebSocketManager) {\n\t\tthis.manager = manager;\n\t}\n\n\t/**\n\t * {@inheritDoc IShardingStrategy.spawn}\n\t */\n\tpublic async spawn(shardIds: number[]) {\n\t\tconst strategyOptions = await managerToFetchingStrategyOptions(this.manager);\n\n\t\tfor (const shardId of shardIds) {\n\t\t\tconst strategy = new SimpleContextFetchingStrategy(this.manager, strategyOptions);\n\t\t\tconst shard = new WebSocketShard(strategy, shardId);\n\n\t\t\tfor (const event of Object.values(WebSocketShardEvents)) {\n\t\t\t\t// @ts-expect-error Ugly casts are needed because when we try to collect all args, TS doesn't handle that nicely due to the strictness + lack of context\n\t\t\t\tshard.on(event, (...args) => this.manager.emit(event, ...args, shardId));\n\t\t\t}\n\n\t\t\tthis.shards.set(shardId, shard);\n\t\t}\n\t}\n\n\t/**\n\t * {@inheritDoc IShardingStrategy.connect}\n\t */\n\tpublic async connect() {\n\t\tconst promises = [];\n\n\t\tfor (const shard of this.shards.values()) {\n\t\t\tpromises.push(shard.connect());\n\t\t}\n\n\t\tawait Promise.all(promises);\n\t}\n\n\t/**\n\t * {@inheritDoc IShardingStrategy.destroy}\n\t */\n\tpublic async destroy(options?: Omit<WebSocketShardDestroyOptions, 'recover'>) {\n\t\tconst promises = [];\n\n\t\tfor (const shard of this.shards.values()) {\n\t\t\tpromises.push(shard.destroy(options));\n\t\t}\n\n\t\tawait Promise.all(promises);\n\t\tthis.shards.clear();\n\t}\n\n\t/**\n\t * {@inheritDoc IShardingStrategy.send}\n\t */\n\tpublic async send(shardId: number, payload: GatewaySendPayload) {\n\t\tconst shard = this.shards.get(shardId);\n\t\tif (!shard) {\n\t\t\tthrow new RangeError(`Shard ${shardId} not found`);\n\t\t}\n\n\t\treturn shard.send(payload);\n\t}\n\n\t/**\n\t * {@inheritDoc IShardingStrategy.fetchStatus}\n\t */\n\tpublic async fetchStatus() {\n\t\treturn this.shards.mapValues((shard) => shard.status);\n\t}\n}\n"
  },
  {
    "path": "packages/ws/src/strategies/sharding/WorkerShardingStrategy.ts",
    "content": "import { once } from 'node:events';\nimport { join, isAbsolute, resolve } from 'node:path';\nimport { Worker } from 'node:worker_threads';\nimport { Collection } from '@discordjs/collection';\nimport type { GatewaySendPayload } from 'discord-api-types/v10';\nimport type { IIdentifyThrottler } from '../../throttling/IIdentifyThrottler.js';\nimport type { SessionInfo, WebSocketManager } from '../../ws/WebSocketManager.js';\nimport type {\n\tWebSocketShardDestroyOptions,\n\tWebSocketShardEvents,\n\tWebSocketShardStatus,\n} from '../../ws/WebSocketShard.js';\nimport { managerToFetchingStrategyOptions, type FetchingStrategyOptions } from '../context/IContextFetchingStrategy.js';\nimport type { IShardingStrategy } from './IShardingStrategy.js';\n\nexport interface WorkerData extends FetchingStrategyOptions {\n\tshardIds: number[];\n}\n\nexport enum WorkerSendPayloadOp {\n\tConnect,\n\tDestroy,\n\tSend,\n\tSessionInfoResponse,\n\tShardIdentifyResponse,\n\tFetchStatus,\n}\n\nexport type WorkerSendPayload =\n\t| { nonce: number; ok: boolean; op: WorkerSendPayloadOp.ShardIdentifyResponse }\n\t| { nonce: number; op: WorkerSendPayloadOp.FetchStatus; shardId: number }\n\t| { nonce: number; op: WorkerSendPayloadOp.SessionInfoResponse; session: SessionInfo | null }\n\t| { op: WorkerSendPayloadOp.Connect; shardId: number }\n\t| { op: WorkerSendPayloadOp.Destroy; options?: WebSocketShardDestroyOptions; shardId: number }\n\t| { op: WorkerSendPayloadOp.Send; payload: GatewaySendPayload; shardId: number };\n\nexport enum WorkerReceivePayloadOp {\n\tConnected,\n\tDestroyed,\n\tEvent,\n\tRetrieveSessionInfo,\n\tUpdateSessionInfo,\n\tWaitForIdentify,\n\tFetchStatusResponse,\n\tWorkerReady,\n\tCancelIdentify,\n}\n\nexport type WorkerReceivePayload =\n\t// Can't seem to get a type-safe union based off of the event, so I'm sadly leaving data as any for now\n\t| { data: any[]; event: WebSocketShardEvents; op: WorkerReceivePayloadOp.Event; shardId: number }\n\t| { nonce: number; op: WorkerReceivePayloadOp.CancelIdentify }\n\t| { nonce: number; op: WorkerReceivePayloadOp.FetchStatusResponse; status: WebSocketShardStatus }\n\t| { nonce: number; op: WorkerReceivePayloadOp.RetrieveSessionInfo; shardId: number }\n\t| { nonce: number; op: WorkerReceivePayloadOp.WaitForIdentify; shardId: number }\n\t| { op: WorkerReceivePayloadOp.Connected; shardId: number }\n\t| { op: WorkerReceivePayloadOp.Destroyed; shardId: number }\n\t| { op: WorkerReceivePayloadOp.UpdateSessionInfo; session: SessionInfo | null; shardId: number }\n\t| { op: WorkerReceivePayloadOp.WorkerReady };\n\n/**\n * Options for a {@link WorkerShardingStrategy}\n */\nexport interface WorkerShardingStrategyOptions {\n\t/**\n\t * Dictates how many shards should be spawned per worker thread.\n\t */\n\tshardsPerWorker: number | 'all';\n\t/**\n\t * Handles a payload not recognized by the handler.\n\t */\n\tunknownPayloadHandler?(payload: any): unknown;\n\t/**\n\t * Path to the worker file to use. The worker requires quite a bit of setup, it is recommended you leverage the {@link WorkerBootstrapper} class.\n\t */\n\tworkerPath?: string;\n}\n\n/**\n * Strategy used to spawn threads in worker_threads\n */\nexport class WorkerShardingStrategy implements IShardingStrategy {\n\tprivate readonly manager: WebSocketManager;\n\n\tprivate readonly options: WorkerShardingStrategyOptions;\n\n\t#workers: Worker[] = [];\n\n\treadonly #workerByShardId = new Collection<number, Worker>();\n\n\tprivate readonly connectPromises = new Collection<number, () => void>();\n\n\tprivate readonly destroyPromises = new Collection<number, () => void>();\n\n\tprivate readonly fetchStatusPromises = new Collection<number, (status: WebSocketShardStatus) => void>();\n\n\tprivate readonly waitForIdentifyControllers = new Collection<number, AbortController>();\n\n\tprivate throttler?: IIdentifyThrottler;\n\n\tpublic constructor(manager: WebSocketManager, options: WorkerShardingStrategyOptions) {\n\t\tthis.manager = manager;\n\t\tthis.options = options;\n\t}\n\n\t/**\n\t * {@inheritDoc IShardingStrategy.spawn}\n\t */\n\tpublic async spawn(shardIds: number[]) {\n\t\tconst shardsPerWorker = this.options.shardsPerWorker === 'all' ? shardIds.length : this.options.shardsPerWorker;\n\t\tconst strategyOptions = await managerToFetchingStrategyOptions(this.manager);\n\n\t\tconst loops = Math.ceil(shardIds.length / shardsPerWorker);\n\t\tconst promises: Promise<void>[] = [];\n\n\t\tfor (let idx = 0; idx < loops; idx++) {\n\t\t\tconst slice = shardIds.slice(idx * shardsPerWorker, (idx + 1) * shardsPerWorker);\n\t\t\tconst workerData: WorkerData = {\n\t\t\t\t...strategyOptions,\n\t\t\t\tshardIds: slice,\n\t\t\t};\n\n\t\t\tpromises.push(this.setupWorker(workerData));\n\t\t}\n\n\t\tawait Promise.all(promises);\n\t}\n\n\t/**\n\t * {@inheritDoc IShardingStrategy.connect}\n\t */\n\tpublic async connect() {\n\t\tconst promises = [];\n\n\t\tfor (const [shardId, worker] of this.#workerByShardId.entries()) {\n\t\t\tconst payload: WorkerSendPayload = {\n\t\t\t\top: WorkerSendPayloadOp.Connect,\n\t\t\t\tshardId,\n\t\t\t};\n\n\t\t\t// eslint-disable-next-line no-promise-executor-return\n\t\t\tconst promise = new Promise<void>((resolve) => this.connectPromises.set(shardId, resolve));\n\t\t\tworker.postMessage(payload);\n\t\t\tpromises.push(promise);\n\t\t}\n\n\t\tawait Promise.all(promises);\n\t}\n\n\t/**\n\t * {@inheritDoc IShardingStrategy.destroy}\n\t */\n\tpublic async destroy(options: Omit<WebSocketShardDestroyOptions, 'recover'> = {}) {\n\t\tconst promises = [];\n\n\t\tfor (const [shardId, worker] of this.#workerByShardId.entries()) {\n\t\t\tconst payload: WorkerSendPayload = {\n\t\t\t\top: WorkerSendPayloadOp.Destroy,\n\t\t\t\tshardId,\n\t\t\t\toptions,\n\t\t\t};\n\n\t\t\tpromises.push(\n\t\t\t\t// eslint-disable-next-line no-promise-executor-return, promise/prefer-await-to-then\n\t\t\t\tnew Promise<void>((resolve) => this.destroyPromises.set(shardId, resolve)).then(async () => worker.terminate()),\n\t\t\t);\n\t\t\tworker.postMessage(payload);\n\t\t}\n\n\t\tthis.#workers = [];\n\t\tthis.#workerByShardId.clear();\n\n\t\tawait Promise.all(promises);\n\t}\n\n\t/**\n\t * {@inheritDoc IShardingStrategy.send}\n\t */\n\tpublic send(shardId: number, data: GatewaySendPayload) {\n\t\tconst worker = this.#workerByShardId.get(shardId);\n\t\tif (!worker) {\n\t\t\tthrow new Error(`No worker found for shard ${shardId}`);\n\t\t}\n\n\t\tconst payload: WorkerSendPayload = {\n\t\t\top: WorkerSendPayloadOp.Send,\n\t\t\tshardId,\n\t\t\tpayload: data,\n\t\t};\n\t\tworker.postMessage(payload);\n\t}\n\n\t/**\n\t * {@inheritDoc IShardingStrategy.fetchStatus}\n\t */\n\tpublic async fetchStatus() {\n\t\tconst statuses = new Collection<number, WebSocketShardStatus>();\n\n\t\tfor (const [shardId, worker] of this.#workerByShardId.entries()) {\n\t\t\tconst nonce = Math.random();\n\t\t\tconst payload: WorkerSendPayload = {\n\t\t\t\top: WorkerSendPayloadOp.FetchStatus,\n\t\t\t\tshardId,\n\t\t\t\tnonce,\n\t\t\t};\n\n\t\t\t// eslint-disable-next-line no-promise-executor-return\n\t\t\tconst promise = new Promise<WebSocketShardStatus>((resolve) => this.fetchStatusPromises.set(nonce, resolve));\n\t\t\tworker.postMessage(payload);\n\n\t\t\tconst status = await promise;\n\t\t\tstatuses.set(shardId, status);\n\t\t}\n\n\t\treturn statuses;\n\t}\n\n\tprivate async setupWorker(workerData: WorkerData) {\n\t\tconst worker = new Worker(this.resolveWorkerPath(), { workerData });\n\n\t\tawait once(worker, 'online');\n\t\t// We do this in case the user has any potentially long running code in their worker\n\t\tawait this.waitForWorkerReady(worker);\n\n\t\tworker\n\t\t\t.on('error', (err) => {\n\t\t\t\tthrow err;\n\t\t\t})\n\t\t\t.on('messageerror', (err) => {\n\t\t\t\tthrow err;\n\t\t\t})\n\t\t\t.on('message', async (payload: any) => {\n\t\t\t\tif ('op' in payload) {\n\t\t\t\t\tawait this.onMessage(worker, payload);\n\t\t\t\t} else {\n\t\t\t\t\tawait this.options.unknownPayloadHandler?.(payload);\n\t\t\t\t}\n\t\t\t});\n\n\t\tthis.#workers.push(worker);\n\t\tfor (const shardId of workerData.shardIds) {\n\t\t\tthis.#workerByShardId.set(shardId, worker);\n\t\t}\n\t}\n\n\tprivate resolveWorkerPath(): string {\n\t\tconst path = this.options.workerPath;\n\n\t\tif (!path) {\n\t\t\treturn join(__dirname, 'defaultWorker.js');\n\t\t}\n\n\t\tif (isAbsolute(path)) {\n\t\t\treturn path;\n\t\t}\n\n\t\tif (/^\\.\\.?[/\\\\]/.test(path)) {\n\t\t\treturn resolve(path);\n\t\t}\n\n\t\ttry {\n\t\t\treturn require.resolve(path);\n\t\t} catch {\n\t\t\treturn resolve(path);\n\t\t}\n\t}\n\n\tprivate async waitForWorkerReady(worker: Worker): Promise<void> {\n\t\treturn new Promise((resolve) => {\n\t\t\tconst handler = (payload: WorkerReceivePayload) => {\n\t\t\t\tif (payload.op === WorkerReceivePayloadOp.WorkerReady) {\n\t\t\t\t\tresolve();\n\t\t\t\t\tworker.off('message', handler);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tworker.on('message', handler);\n\t\t});\n\t}\n\n\tprivate async onMessage(worker: Worker, payload: WorkerReceivePayload) {\n\t\tswitch (payload.op) {\n\t\t\tcase WorkerReceivePayloadOp.Connected: {\n\t\t\t\tthis.connectPromises.get(payload.shardId)?.();\n\t\t\t\tthis.connectPromises.delete(payload.shardId);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase WorkerReceivePayloadOp.Destroyed: {\n\t\t\t\tthis.destroyPromises.get(payload.shardId)?.();\n\t\t\t\tthis.destroyPromises.delete(payload.shardId);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase WorkerReceivePayloadOp.Event: {\n\t\t\t\t// @ts-expect-error Event props can't be resolved properly, but they are correct\n\t\t\t\tthis.manager.emit(payload.event, ...payload.data, payload.shardId);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase WorkerReceivePayloadOp.RetrieveSessionInfo: {\n\t\t\t\tconst session = await this.manager.options.retrieveSessionInfo(payload.shardId);\n\t\t\t\tconst response: WorkerSendPayload = {\n\t\t\t\t\top: WorkerSendPayloadOp.SessionInfoResponse,\n\t\t\t\t\tnonce: payload.nonce,\n\t\t\t\t\tsession,\n\t\t\t\t};\n\t\t\t\tworker.postMessage(response);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase WorkerReceivePayloadOp.UpdateSessionInfo: {\n\t\t\t\tawait this.manager.options.updateSessionInfo(payload.shardId, payload.session);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase WorkerReceivePayloadOp.WaitForIdentify: {\n\t\t\t\tconst throttler = await this.ensureThrottler();\n\n\t\t\t\t// If this rejects it means we aborted, in which case we reply elsewhere.\n\t\t\t\ttry {\n\t\t\t\t\tconst controller = new AbortController();\n\t\t\t\t\tthis.waitForIdentifyControllers.set(payload.nonce, controller);\n\t\t\t\t\tawait throttler.waitForIdentify(payload.shardId, controller.signal);\n\t\t\t\t} catch {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst response: WorkerSendPayload = {\n\t\t\t\t\top: WorkerSendPayloadOp.ShardIdentifyResponse,\n\t\t\t\t\tnonce: payload.nonce,\n\t\t\t\t\tok: true,\n\t\t\t\t};\n\t\t\t\tworker.postMessage(response);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase WorkerReceivePayloadOp.FetchStatusResponse: {\n\t\t\t\tthis.fetchStatusPromises.get(payload.nonce)?.(payload.status);\n\t\t\t\tthis.fetchStatusPromises.delete(payload.nonce);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase WorkerReceivePayloadOp.WorkerReady: {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase WorkerReceivePayloadOp.CancelIdentify: {\n\t\t\t\tthis.waitForIdentifyControllers.get(payload.nonce)?.abort();\n\t\t\t\tthis.waitForIdentifyControllers.delete(payload.nonce);\n\n\t\t\t\tconst response: WorkerSendPayload = {\n\t\t\t\t\top: WorkerSendPayloadOp.ShardIdentifyResponse,\n\t\t\t\t\tnonce: payload.nonce,\n\t\t\t\t\tok: false,\n\t\t\t\t};\n\t\t\t\tworker.postMessage(response);\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tawait this.options.unknownPayloadHandler?.(payload);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async ensureThrottler(): Promise<IIdentifyThrottler> {\n\t\tthis.throttler ??= await this.manager.options.buildIdentifyThrottler(this.manager);\n\t\treturn this.throttler;\n\t}\n}\n"
  },
  {
    "path": "packages/ws/src/strategies/sharding/defaultWorker.ts",
    "content": "import { WorkerBootstrapper } from '../../utils/WorkerBootstrapper.js';\n\nconst bootstrapper = new WorkerBootstrapper();\nvoid bootstrapper.bootstrap();\n"
  },
  {
    "path": "packages/ws/src/throttling/IIdentifyThrottler.ts",
    "content": "/**\n * IdentifyThrottlers are responsible for dictating when a shard is allowed to identify.\n *\n * @see {@link https://discord.com/developers/docs/topics/gateway#sharding-max-concurrency}\n */\nexport interface IIdentifyThrottler {\n\t/**\n\t * Resolves once the given shard should be allowed to identify, or rejects if the operation was aborted.\n\t */\n\twaitForIdentify(shardId: number, signal: AbortSignal): Promise<void>;\n}\n"
  },
  {
    "path": "packages/ws/src/throttling/SimpleIdentifyThrottler.ts",
    "content": "import { setTimeout as sleep } from 'node:timers/promises';\nimport { Collection } from '@discordjs/collection';\nimport { AsyncQueue } from '@sapphire/async-queue';\nimport type { IIdentifyThrottler } from './IIdentifyThrottler.js';\n\n/**\n * The state of a rate limit key's identify queue.\n */\nexport interface IdentifyState {\n\tqueue: AsyncQueue;\n\tresetsAt: number;\n}\n\n/**\n * Local, in-memory identify throttler.\n */\nexport class SimpleIdentifyThrottler implements IIdentifyThrottler {\n\tprivate readonly states = new Collection<number, IdentifyState>();\n\n\tpublic constructor(private readonly maxConcurrency: number) {}\n\n\t/**\n\t * {@inheritDoc IIdentifyThrottler.waitForIdentify}\n\t */\n\tpublic async waitForIdentify(shardId: number, signal: AbortSignal): Promise<void> {\n\t\tconst key = shardId % this.maxConcurrency;\n\n\t\tconst state = this.states.ensure(key, () => ({\n\t\t\tqueue: new AsyncQueue(),\n\t\t\tresetsAt: Number.POSITIVE_INFINITY,\n\t\t}));\n\n\t\tawait state.queue.wait({ signal });\n\n\t\ttry {\n\t\t\tconst diff = state.resetsAt - Date.now();\n\t\t\tif (diff > 0 && diff <= 5_000) {\n\t\t\t\t// To account for the latency the IDENTIFY payload goes through, we add a bit more wait time\n\t\t\t\tconst time = diff + Math.random() * 1_500;\n\t\t\t\tawait sleep(time);\n\t\t\t}\n\n\t\t\tstate.resetsAt = Date.now() + 5_000;\n\t\t} finally {\n\t\t\tstate.queue.shift();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/ws/src/utils/WorkerBootstrapper.ts",
    "content": "import { isMainThread, parentPort, workerData } from 'node:worker_threads';\nimport { Collection } from '@discordjs/collection';\nimport type { Awaitable } from '@discordjs/util';\nimport { WorkerContextFetchingStrategy } from '../strategies/context/WorkerContextFetchingStrategy.js';\nimport {\n\tWorkerReceivePayloadOp,\n\tWorkerSendPayloadOp,\n\ttype WorkerData,\n\ttype WorkerReceivePayload,\n\ttype WorkerSendPayload,\n} from '../strategies/sharding/WorkerShardingStrategy.js';\nimport type { WebSocketShardDestroyOptions } from '../ws/WebSocketShard.js';\nimport { WebSocketShardEvents, WebSocketShard } from '../ws/WebSocketShard.js';\n\n/**\n * Options for bootstrapping the worker\n */\nexport interface BootstrapOptions {\n\t/**\n\t * Shard events to just arbitrarily forward to the parent thread for the manager to emit\n\t * Note: By default, this will include ALL events\n\t * you most likely want to handle dispatch within the worker itself\n\t */\n\tforwardEvents?: WebSocketShardEvents[];\n\t/**\n\t * Function to call when a shard is created for additional setup\n\t */\n\tshardCallback?(shard: WebSocketShard): Awaitable<void>;\n}\n\n/**\n * Utility class for bootstrapping a worker thread to be used for sharding\n */\nexport class WorkerBootstrapper {\n\t/**\n\t * The data passed to the worker thread\n\t */\n\tprotected readonly data = workerData as WorkerData;\n\n\t/**\n\t * The shards that are managed by this worker\n\t */\n\tprotected readonly shards = new Collection<number, WebSocketShard>();\n\n\tpublic constructor() {\n\t\tif (isMainThread) {\n\t\t\tthrow new Error('Expected WorkerBootstrap to not be used within the main thread');\n\t\t}\n\t}\n\n\t/**\n\t * Helper method to initiate a shard's connection process\n\t */\n\tprotected async connect(shardId: number): Promise<void> {\n\t\tconst shard = this.shards.get(shardId);\n\t\tif (!shard) {\n\t\t\tthrow new RangeError(`Shard ${shardId} does not exist`);\n\t\t}\n\n\t\tawait shard.connect();\n\t}\n\n\t/**\n\t * Helper method to destroy a shard\n\t */\n\tprotected async destroy(shardId: number, options?: WebSocketShardDestroyOptions): Promise<void> {\n\t\tconst shard = this.shards.get(shardId);\n\t\tif (!shard) {\n\t\t\tthrow new RangeError(`Shard ${shardId} does not exist`);\n\t\t}\n\n\t\tawait shard.destroy(options);\n\t}\n\n\t/**\n\t * Helper method to attach event listeners to the parentPort\n\t */\n\tprotected setupThreadEvents(): void {\n\t\tparentPort!\n\t\t\t.on('messageerror', (err) => {\n\t\t\t\tthrow err;\n\t\t\t})\n\t\t\t.on('message', async (payload: WorkerSendPayload) => {\n\t\t\t\tswitch (payload.op) {\n\t\t\t\t\tcase WorkerSendPayloadOp.Connect: {\n\t\t\t\t\t\tawait this.connect(payload.shardId);\n\t\t\t\t\t\tconst response: WorkerReceivePayload = {\n\t\t\t\t\t\t\top: WorkerReceivePayloadOp.Connected,\n\t\t\t\t\t\t\tshardId: payload.shardId,\n\t\t\t\t\t\t};\n\t\t\t\t\t\tparentPort!.postMessage(response);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase WorkerSendPayloadOp.Destroy: {\n\t\t\t\t\t\tawait this.destroy(payload.shardId, payload.options);\n\t\t\t\t\t\tconst response: WorkerReceivePayload = {\n\t\t\t\t\t\t\top: WorkerReceivePayloadOp.Destroyed,\n\t\t\t\t\t\t\tshardId: payload.shardId,\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tparentPort!.postMessage(response);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase WorkerSendPayloadOp.Send: {\n\t\t\t\t\t\tconst shard = this.shards.get(payload.shardId);\n\t\t\t\t\t\tif (!shard) {\n\t\t\t\t\t\t\tthrow new RangeError(`Shard ${payload.shardId} does not exist`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tawait shard.send(payload.payload);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase WorkerSendPayloadOp.SessionInfoResponse: {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase WorkerSendPayloadOp.ShardIdentifyResponse: {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase WorkerSendPayloadOp.FetchStatus: {\n\t\t\t\t\t\tconst shard = this.shards.get(payload.shardId);\n\t\t\t\t\t\tif (!shard) {\n\t\t\t\t\t\t\tthrow new Error(`Shard ${payload.shardId} does not exist`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst response: WorkerReceivePayload = {\n\t\t\t\t\t\t\top: WorkerReceivePayloadOp.FetchStatusResponse,\n\t\t\t\t\t\t\tstatus: shard.status,\n\t\t\t\t\t\t\tnonce: payload.nonce,\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tparentPort!.postMessage(response);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\t/**\n\t * Bootstraps the worker thread with the provided options\n\t */\n\tpublic async bootstrap(options: Readonly<BootstrapOptions> = {}): Promise<void> {\n\t\t// Start by initializing the shards\n\t\tfor (const shardId of this.data.shardIds) {\n\t\t\tconst shard = new WebSocketShard(new WorkerContextFetchingStrategy(this.data), shardId);\n\t\t\tfor (const event of options.forwardEvents ?? Object.values(WebSocketShardEvents)) {\n\t\t\t\tshard.on(event, (...args: unknown[]) => {\n\t\t\t\t\tconst payload: WorkerReceivePayload = {\n\t\t\t\t\t\top: WorkerReceivePayloadOp.Event,\n\t\t\t\t\t\tevent,\n\t\t\t\t\t\tdata: args,\n\t\t\t\t\t\tshardId,\n\t\t\t\t\t};\n\n\t\t\t\t\tparentPort!.postMessage(payload);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Any additional setup the user might want to do\n\t\t\tawait options.shardCallback?.(shard);\n\t\t\tthis.shards.set(shardId, shard);\n\t\t}\n\n\t\t// Lastly, start listening to messages from the parent thread\n\t\tthis.setupThreadEvents();\n\n\t\tconst message: WorkerReceivePayload = {\n\t\t\top: WorkerReceivePayloadOp.WorkerReady,\n\t\t};\n\t\tparentPort!.postMessage(message);\n\t}\n}\n"
  },
  {
    "path": "packages/ws/src/utils/constants.ts",
    "content": "import process from 'node:process';\nimport { Collection } from '@discordjs/collection';\nimport { lazy } from '@discordjs/util';\nimport { APIVersion, GatewayOpcodes } from 'discord-api-types/v10';\nimport { SimpleShardingStrategy } from '../strategies/sharding/SimpleShardingStrategy.js';\nimport { SimpleIdentifyThrottler } from '../throttling/SimpleIdentifyThrottler.js';\nimport type { SessionInfo, OptionalWebSocketManagerOptions, WebSocketManager } from '../ws/WebSocketManager.js';\nimport type { SendRateLimitState } from '../ws/WebSocketShard.js';\n\n/**\n * Valid encoding types\n */\nexport enum Encoding {\n\tJSON = 'json',\n}\n\n/**\n * Valid compression methods\n */\nexport enum CompressionMethod {\n\tZlibNative,\n\tZlibSync,\n\tZstdNative,\n}\n\nexport const DefaultDeviceProperty = `@discordjs/ws [VI]{{inject}}[/VI]` as `@discordjs/ws ${string}`;\n\nconst getDefaultSessionStore = lazy(() => new Collection<number, SessionInfo | null>());\n\nexport const CompressionParameterMap = {\n\t[CompressionMethod.ZlibNative]: 'zlib-stream',\n\t[CompressionMethod.ZlibSync]: 'zlib-stream',\n\t[CompressionMethod.ZstdNative]: 'zstd-stream',\n} as const satisfies Record<CompressionMethod, string>;\n\n/**\n * Default options used by the manager\n */\nexport const DefaultWebSocketManagerOptions = {\n\tasync buildIdentifyThrottler(manager: WebSocketManager) {\n\t\tconst info = await manager.fetchGatewayInformation();\n\t\treturn new SimpleIdentifyThrottler(info.session_start_limit.max_concurrency);\n\t},\n\tbuildStrategy: (manager) => new SimpleShardingStrategy(manager),\n\tshardCount: null,\n\tshardIds: null,\n\tlargeThreshold: null,\n\tinitialPresence: null,\n\tidentifyProperties: {\n\t\tbrowser: DefaultDeviceProperty,\n\t\tdevice: DefaultDeviceProperty,\n\t\tos: process.platform,\n\t},\n\tversion: APIVersion,\n\tencoding: Encoding.JSON,\n\tcompression: null,\n\tuseIdentifyCompression: false,\n\tretrieveSessionInfo(shardId) {\n\t\tconst store = getDefaultSessionStore();\n\t\treturn store.get(shardId) ?? null;\n\t},\n\tupdateSessionInfo(shardId: number, info: SessionInfo | null) {\n\t\tconst store = getDefaultSessionStore();\n\t\tif (info) {\n\t\t\tstore.set(shardId, info);\n\t\t} else {\n\t\t\tstore.delete(shardId);\n\t\t}\n\t},\n\thandshakeTimeout: 30_000,\n\thelloTimeout: 60_000,\n\treadyTimeout: 15_000,\n} as const satisfies Omit<OptionalWebSocketManagerOptions, 'fetchGatewayInformation' | 'token'>;\n\nexport const ImportantGatewayOpcodes = new Set([\n\tGatewayOpcodes.Heartbeat,\n\tGatewayOpcodes.Identify,\n\tGatewayOpcodes.Resume,\n]);\n\nexport function getInitialSendRateLimitState(): SendRateLimitState {\n\treturn {\n\t\tsent: 0,\n\t\tresetAt: Date.now() + 60_000,\n\t};\n}\n"
  },
  {
    "path": "packages/ws/src/ws/WebSocketManager.ts",
    "content": "import type { Collection } from '@discordjs/collection';\nimport { range, type Awaitable } from '@discordjs/util';\nimport { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';\nimport type {\n\tAPIGatewayBotInfo,\n\tGatewayIdentifyProperties,\n\tGatewayPresenceUpdateData,\n\tRESTGetAPIGatewayBotResult,\n\tGatewayIntentBits,\n\tGatewaySendPayload,\n\tGatewayDispatchPayload,\n\tGatewayReadyDispatchData,\n} from 'discord-api-types/v10';\nimport type { IShardingStrategy } from '../strategies/sharding/IShardingStrategy.js';\nimport type { IIdentifyThrottler } from '../throttling/IIdentifyThrottler.js';\nimport { DefaultWebSocketManagerOptions, type CompressionMethod, type Encoding } from '../utils/constants.js';\nimport type { WebSocketShardDestroyOptions, WebSocketShardEvents, WebSocketShardStatus } from './WebSocketShard.js';\n\n/**\n * Represents a range of shard ids\n */\nexport interface ShardRange {\n\tend: number;\n\tstart: number;\n}\n\n/**\n * Session information for a given shard, used to resume a session\n */\nexport interface SessionInfo {\n\t/**\n\t * URL to use when resuming\n\t */\n\tresumeURL: string;\n\t/**\n\t * The sequence number of the last message sent by the shard\n\t */\n\tsequence: number;\n\t/**\n\t * Session id for this shard\n\t */\n\tsessionId: string;\n\t/**\n\t * The total number of shards at the time of this shard identifying\n\t */\n\tshardCount: number;\n\t/**\n\t * The id of the shard\n\t */\n\tshardId: number;\n}\n\n/**\n * Required options for the WebSocketManager\n */\nexport interface RequiredWebSocketManagerOptions {\n\t/**\n\t * Function for retrieving the information returned by the `/gateway/bot` endpoint.\n\t * We recommend using a REST client that respects Discord's rate limits, such as `@discordjs/rest`.\n\t *\n\t * @example\n\t * ```ts\n\t * const rest = new REST().setToken(process.env.DISCORD_TOKEN);\n\t * const manager = new WebSocketManager({\n\t *  token: process.env.DISCORD_TOKEN,\n\t *  fetchGatewayInformation() {\n\t *    return rest.get(Routes.gatewayBot()) as Promise<RESTGetAPIGatewayBotResult>;\n\t *  },\n\t * });\n\t * ```\n\t */\n\tfetchGatewayInformation(): Awaitable<RESTGetAPIGatewayBotResult>;\n\t/**\n\t * The intents to request\n\t */\n\tintents: GatewayIntentBits | 0;\n}\n\n/**\n * Optional additional configuration for the WebSocketManager\n */\nexport interface OptionalWebSocketManagerOptions {\n\t/**\n\t * Builds an identify throttler to use for this manager's shards\n\t */\n\tbuildIdentifyThrottler(manager: WebSocketManager): Awaitable<IIdentifyThrottler>;\n\t/**\n\t * Builds the strategy to use for sharding\n\t *\n\t * @example\n\t * ```ts\n\t * const rest = new REST().setToken(process.env.DISCORD_TOKEN);\n\t * const manager = new WebSocketManager({\n\t *  token: process.env.DISCORD_TOKEN,\n\t *  intents: 0, // for no intents\n\t *  fetchGatewayInformation() {\n\t *    return rest.get(Routes.gatewayBot()) as Promise<RESTGetAPIGatewayBotResult>;\n\t *  },\n\t *  buildStrategy: (manager) => new WorkerShardingStrategy(manager, { shardsPerWorker: 2 }),\n\t * });\n\t * ```\n\t */\n\tbuildStrategy(manager: WebSocketManager): IShardingStrategy;\n\t/**\n\t * The transport compression method to use - mutually exclusive with `useIdentifyCompression`\n\t *\n\t * @defaultValue `null` (no transport compression)\n\t */\n\tcompression: CompressionMethod | null;\n\t/**\n\t * The encoding to use\n\t *\n\t * @defaultValue `'json'`\n\t */\n\tencoding: Encoding;\n\t/**\n\t * How long to wait for a shard to connect before giving up\n\t */\n\thandshakeTimeout: number | null;\n\t/**\n\t * How long to wait for a shard's HELLO packet before giving up\n\t */\n\thelloTimeout: number | null;\n\t/**\n\t * Properties to send to the gateway when identifying\n\t */\n\tidentifyProperties: GatewayIdentifyProperties;\n\t/**\n\t * Initial presence data to send to the gateway when identifying\n\t */\n\tinitialPresence: GatewayPresenceUpdateData | null;\n\t/**\n\t * Value between 50 and 250, total number of members where the gateway will stop sending offline members in the guild member list\n\t */\n\tlargeThreshold: number | null;\n\t/**\n\t * How long to wait for a shard's READY packet before giving up\n\t */\n\treadyTimeout: number | null;\n\t/**\n\t * Function used to retrieve session information (and attempt to resume) for a given shard\n\t *\n\t * @example\n\t * ```ts\n\t * const manager = new WebSocketManager({\n\t *   async retrieveSessionInfo(shardId): Awaitable<SessionInfo | null> {\n\t *     // Fetch this info from redis or similar\n\t *     return { sessionId: string, sequence: number };\n\t *     // Return null if no information is found\n\t *   },\n\t * });\n\t * ```\n\t */\n\tretrieveSessionInfo(shardId: number): Awaitable<SessionInfo | null>;\n\t/**\n\t * The total number of shards across all WebsocketManagers you intend to instantiate.\n\t * Use `null` to use Discord's recommended shard count\n\t */\n\tshardCount: number | null;\n\t/**\n\t * The ids of the shards this WebSocketManager should manage.\n\t * Use `null` to simply spawn 0 through `shardCount - 1`\n\t *\n\t * @example\n\t * ```ts\n\t * const manager = new WebSocketManager({\n\t *   shardIds: [1, 3, 7], // spawns shard 1, 3, and 7, nothing else\n\t * });\n\t * ```\n\t * @example\n\t * ```ts\n\t * const manager = new WebSocketManager({\n\t *   shardIds: {\n\t *     start: 3,\n\t *     end: 6,\n\t *   }, // spawns shards 3, 4, 5, and 6\n\t * });\n\t * ```\n\t */\n\tshardIds: number[] | ShardRange | null;\n\t/**\n\t * The token to use for identifying with the gateway\n\t *\n\t * If not provided, the token must be set using {@link WebSocketManager.setToken}\n\t */\n\ttoken: string;\n\t/**\n\t * Function used to store session information for a given shard\n\t */\n\tupdateSessionInfo(shardId: number, sessionInfo: SessionInfo | null): Awaitable<void>;\n\t/**\n\t * Whether to use the `compress` option when identifying\n\t *\n\t * @defaultValue `false`\n\t */\n\tuseIdentifyCompression: boolean;\n\t/**\n\t * The gateway version to use\n\t *\n\t * @defaultValue `'10'`\n\t */\n\tversion: string;\n}\n\nexport interface WebSocketManagerOptions extends OptionalWebSocketManagerOptions, RequiredWebSocketManagerOptions {}\n\nexport interface CreateWebSocketManagerOptions\n\textends Partial<OptionalWebSocketManagerOptions>, RequiredWebSocketManagerOptions {}\n\nexport interface ManagerShardEventsMap {\n\t[WebSocketShardEvents.Closed]: [code: number, shardId: number];\n\t[WebSocketShardEvents.Debug]: [message: string, shardId: number];\n\t[WebSocketShardEvents.Dispatch]: [payload: GatewayDispatchPayload, shardId: number];\n\t[WebSocketShardEvents.Error]: [error: Error, shardId: number];\n\t[WebSocketShardEvents.Hello]: [shardId: number];\n\t[WebSocketShardEvents.Ready]: [data: GatewayReadyDispatchData, shardId: number];\n\t[WebSocketShardEvents.Resumed]: [shardId: number];\n\t[WebSocketShardEvents.HeartbeatComplete]: [\n\t\tstats: { ackAt: number; heartbeatAt: number; latency: number },\n\t\tshardId: number,\n\t];\n\t[WebSocketShardEvents.SocketError]: [error: Error, shardId: number];\n}\n\nexport class WebSocketManager extends AsyncEventEmitter<ManagerShardEventsMap> implements AsyncDisposable {\n\t#token: string | null = null;\n\n\t/**\n\t * The options being used by this manager\n\t */\n\tpublic readonly options: Omit<WebSocketManagerOptions, 'token'>;\n\n\t/**\n\t * Internal cache for a GET /gateway/bot result\n\t */\n\tprivate gatewayInformation: {\n\t\tdata: APIGatewayBotInfo;\n\t\texpiresAt: number;\n\t} | null = null;\n\n\t/**\n\t * Internal cache for the shard ids\n\t */\n\tprivate shardIds: number[] | null = null;\n\n\t/**\n\t * Strategy used to manage shards\n\t *\n\t * @defaultValue `SimpleShardingStrategy`\n\t */\n\tprivate readonly strategy: IShardingStrategy;\n\n\t/**\n\t * Gets the token set for this manager. If no token is set, an error is thrown.\n\t * To set the token, use {@link WebSocketManager.setToken} or pass it in the options.\n\t *\n\t * @remarks\n\t * This getter is mostly used to pass the token to the sharding strategy internally, there's not much reason to use it.\n\t */\n\tpublic get token(): string {\n\t\tif (!this.#token) {\n\t\t\tthrow new Error('Token has not been set');\n\t\t}\n\n\t\treturn this.#token;\n\t}\n\n\tpublic constructor(options: CreateWebSocketManagerOptions) {\n\t\tif (typeof options.fetchGatewayInformation !== 'function') {\n\t\t\tthrow new TypeError('fetchGatewayInformation is required');\n\t\t}\n\n\t\tsuper();\n\t\tthis.options = {\n\t\t\t...DefaultWebSocketManagerOptions,\n\t\t\t...options,\n\t\t};\n\t\tthis.strategy = this.options.buildStrategy(this);\n\t\tthis.#token = options.token ?? null;\n\t}\n\n\t/**\n\t * Fetches the gateway information from Discord - or returns it from cache if available\n\t *\n\t * @param force - Whether to ignore the cache and force a fresh fetch\n\t */\n\tpublic async fetchGatewayInformation(force = false) {\n\t\tif (this.gatewayInformation) {\n\t\t\tif (this.gatewayInformation.expiresAt <= Date.now()) {\n\t\t\t\tthis.gatewayInformation = null;\n\t\t\t} else if (!force) {\n\t\t\t\treturn this.gatewayInformation.data;\n\t\t\t}\n\t\t}\n\n\t\tconst data = await this.options.fetchGatewayInformation();\n\n\t\t// For single sharded bots session_start_limit.reset_after will be 0, use 5 seconds as a minimum expiration time\n\t\tthis.gatewayInformation = { data, expiresAt: Date.now() + (data.session_start_limit.reset_after || 5_000) };\n\t\treturn this.gatewayInformation.data;\n\t}\n\n\t/**\n\t * Updates your total shard count on-the-fly, spawning shards as needed\n\t *\n\t * @param shardCount - The new shard count to use\n\t */\n\tpublic async updateShardCount(shardCount: number | null) {\n\t\tawait this.strategy.destroy({ reason: 'User is adjusting their shards' });\n\t\tthis.options.shardCount = shardCount;\n\n\t\tconst shardIds = await this.getShardIds(true);\n\t\tawait this.strategy.spawn(shardIds);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Yields the total number of shards across for your bot, accounting for Discord recommendations\n\t */\n\tpublic async getShardCount(): Promise<number> {\n\t\tif (this.options.shardCount) {\n\t\t\treturn this.options.shardCount;\n\t\t}\n\n\t\tconst shardIds = await this.getShardIds();\n\t\treturn Math.max(...shardIds) + 1;\n\t}\n\n\t/**\n\t * Yields the ids of the shards this manager should manage\n\t */\n\tpublic async getShardIds(force = false): Promise<number[]> {\n\t\tif (this.shardIds && !force) {\n\t\t\treturn this.shardIds;\n\t\t}\n\n\t\tlet shardIds: number[];\n\t\tif (this.options.shardIds) {\n\t\t\tif (Array.isArray(this.options.shardIds)) {\n\t\t\t\tshardIds = this.options.shardIds;\n\t\t\t} else {\n\t\t\t\tconst { start, end } = this.options.shardIds;\n\t\t\t\tshardIds = [...range({ start, end: end + 1 })];\n\t\t\t}\n\t\t} else {\n\t\t\tconst data = await this.fetchGatewayInformation();\n\t\t\tshardIds = [...range(this.options.shardCount ?? data.shards)];\n\t\t}\n\n\t\tthis.shardIds = shardIds;\n\t\treturn shardIds;\n\t}\n\n\tpublic async connect() {\n\t\tconst shardCount = await this.getShardCount();\n\t\t// Spawn shards and adjust internal state\n\t\tawait this.updateShardCount(shardCount);\n\n\t\tconst shardIds = await this.getShardIds();\n\t\tconst data = await this.fetchGatewayInformation();\n\n\t\tif (data.session_start_limit.remaining < shardIds.length) {\n\t\t\tthrow new Error(\n\t\t\t\t`Not enough sessions remaining to spawn ${shardIds.length} shards; only ${\n\t\t\t\t\tdata.session_start_limit.remaining\n\t\t\t\t} remaining; resets at ${new Date(Date.now() + data.session_start_limit.reset_after).toISOString()}`,\n\t\t\t);\n\t\t}\n\n\t\tawait this.strategy.connect();\n\t}\n\n\tpublic setToken(token: string): void {\n\t\tif (this.#token) {\n\t\t\tthrow new Error('Token has already been set');\n\t\t}\n\n\t\tthis.#token = token;\n\t}\n\n\tpublic destroy(options?: Omit<WebSocketShardDestroyOptions, 'recover'>) {\n\t\treturn this.strategy.destroy(options);\n\t}\n\n\tpublic send(shardId: number, payload: GatewaySendPayload) {\n\t\treturn this.strategy.send(shardId, payload);\n\t}\n\n\tpublic fetchStatus(): Awaitable<Collection<number, WebSocketShardStatus>> {\n\t\treturn this.strategy.fetchStatus();\n\t}\n\n\tpublic async [Symbol.asyncDispose]() {\n\t\tawait this.destroy();\n\t}\n}\n"
  },
  {
    "path": "packages/ws/src/ws/WebSocketShard.ts",
    "content": "import { Buffer } from 'node:buffer';\nimport { once } from 'node:events';\nimport { setTimeout as sleep } from 'node:timers/promises';\nimport type * as nativeZlib from 'node:zlib';\nimport { Collection } from '@discordjs/collection';\nimport { lazy, shouldUseGlobalFetchAndWebSocket } from '@discordjs/util';\nimport { AsyncQueue } from '@sapphire/async-queue';\nimport { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';\nimport {\n\tGatewayCloseCodes,\n\tGatewayDispatchEvents,\n\tGatewayOpcodes,\n\ttype GatewayDispatchPayload,\n\ttype GatewayIdentifyData,\n\ttype GatewayReadyDispatchData,\n\ttype GatewayReceivePayload,\n\ttype GatewaySendPayload,\n} from 'discord-api-types/v10';\nimport { WebSocket, type Data } from 'ws';\nimport type * as ZlibSync from 'zlib-sync';\nimport type { IContextFetchingStrategy } from '../strategies/context/IContextFetchingStrategy';\nimport {\n\tCompressionMethod,\n\tCompressionParameterMap,\n\tImportantGatewayOpcodes,\n\tgetInitialSendRateLimitState,\n} from '../utils/constants.js';\nimport type { SessionInfo } from './WebSocketManager.js';\n\n/* eslint-disable promise/prefer-await-to-then */\nconst getZlibSync = lazy(async () => import('zlib-sync').then((mod) => mod.default).catch(() => null));\nconst getNativeZlib = lazy(async () => import('node:zlib').then((mod) => mod).catch(() => null));\n/* eslint-enable promise/prefer-await-to-then */\n\nexport enum WebSocketShardEvents {\n\tClosed = 'closed',\n\tDebug = 'debug',\n\tDispatch = 'dispatch',\n\tError = 'error',\n\tHeartbeatComplete = 'heartbeat',\n\tHello = 'hello',\n\tReady = 'ready',\n\tResumed = 'resumed',\n\tSocketError = 'socketError',\n}\n\nexport enum WebSocketShardStatus {\n\tIdle,\n\tConnecting,\n\tResuming,\n\tReady,\n}\n\nexport enum WebSocketShardDestroyRecovery {\n\tReconnect,\n\tResume,\n}\n\nexport interface WebSocketShardEventsMap {\n\t[WebSocketShardEvents.Closed]: [code: number];\n\t[WebSocketShardEvents.Debug]: [message: string];\n\t[WebSocketShardEvents.Dispatch]: [payload: GatewayDispatchPayload];\n\t[WebSocketShardEvents.Error]: [error: Error];\n\t[WebSocketShardEvents.Hello]: [];\n\t[WebSocketShardEvents.Ready]: [payload: GatewayReadyDispatchData];\n\t[WebSocketShardEvents.Resumed]: [];\n\t[WebSocketShardEvents.HeartbeatComplete]: [stats: { ackAt: number; heartbeatAt: number; latency: number }];\n\t[WebSocketShardEvents.SocketError]: [error: Error];\n}\n\nexport interface WebSocketShardDestroyOptions {\n\tcode?: number;\n\treason?: string;\n\trecover?: WebSocketShardDestroyRecovery;\n}\n\nexport enum CloseCodes {\n\tNormal = 1_000,\n\tResuming = 4_200,\n}\n\nexport interface SendRateLimitState {\n\tresetAt: number;\n\tsent: number;\n}\n\nconst WebSocketConstructor: typeof WebSocket = shouldUseGlobalFetchAndWebSocket()\n\t? (globalThis as any).WebSocket\n\t: WebSocket;\n\nexport class WebSocketShard extends AsyncEventEmitter<WebSocketShardEventsMap> {\n\tprivate connection: WebSocket | null = null;\n\n\tprivate nativeInflate: nativeZlib.Inflate | null = null;\n\n\tprivate zLibSyncInflate: ZlibSync.Inflate | null = null;\n\n\t/**\n\t * @privateRemarks\n\t *\n\t * Used only for native zlib inflate, zlib-sync buffering is handled by the library itself.\n\t */\n\tprivate inflateBuffer: Buffer[] = [];\n\n\tprivate readonly textDecoder = new TextDecoder();\n\n\tprivate replayedEvents = 0;\n\n\tprivate isAck = true;\n\n\tprivate sendRateLimitState: SendRateLimitState = getInitialSendRateLimitState();\n\n\tprivate initialHeartbeatTimeoutController: AbortController | null = null;\n\n\tprivate heartbeatInterval: NodeJS.Timeout | null = null;\n\n\tprivate lastHeartbeatAt = -1;\n\n\t// Indicates whether the shard has already resolved its original connect() call\n\tprivate initialConnectResolved = false;\n\n\t// Indicates if we failed to connect to the ws url\n\tprivate failedToConnectDueToNetworkError = false;\n\n\tprivate readonly sendQueue = new AsyncQueue();\n\n\tprivate readonly timeoutAbortControllers = new Collection<WebSocketShardEvents, AbortController>();\n\n\tprivate readonly strategy: IContextFetchingStrategy;\n\n\tpublic readonly id: number;\n\n\t#status: WebSocketShardStatus = WebSocketShardStatus.Idle;\n\n\tprivate identifyCompressionEnabled = false;\n\n\t/**\n\t * @privateRemarks\n\t *\n\t * This is needed because `this.strategy.options.compression` is not an actual reflection of the compression method\n\t * used, but rather the compression method that the user wants to use. This is because the libraries could just be missing.\n\t */\n\tprivate get transportCompressionEnabled() {\n\t\treturn this.strategy.options.compression !== null && (this.nativeInflate ?? this.zLibSyncInflate) !== null;\n\t}\n\n\tpublic get status(): WebSocketShardStatus {\n\t\treturn this.#status;\n\t}\n\n\tpublic constructor(strategy: IContextFetchingStrategy, id: number) {\n\t\tsuper();\n\t\tthis.strategy = strategy;\n\t\tthis.id = id;\n\t}\n\n\tpublic async connect() {\n\t\tconst controller = new AbortController();\n\t\tlet promise;\n\n\t\tif (!this.initialConnectResolved) {\n\t\t\t// Sleep for the remaining time, but if the connection closes in the meantime, we shouldn't wait the remainder to avoid blocking the new conn\n\t\t\tpromise = Promise.race([\n\t\t\t\tonce(this, WebSocketShardEvents.Ready, { signal: controller.signal }),\n\t\t\t\tonce(this, WebSocketShardEvents.Resumed, { signal: controller.signal }),\n\t\t\t]);\n\t\t}\n\n\t\tvoid this.internalConnect();\n\n\t\ttry {\n\t\t\tawait promise;\n\t\t} finally {\n\t\t\t// cleanup hanging listeners\n\t\t\tcontroller.abort();\n\t\t}\n\n\t\tthis.initialConnectResolved = true;\n\t}\n\n\tprivate async internalConnect() {\n\t\tif (this.#status !== WebSocketShardStatus.Idle) {\n\t\t\tthrow new Error(\"Tried to connect a shard that wasn't idle\");\n\t\t}\n\n\t\tconst { version, encoding, compression, useIdentifyCompression } = this.strategy.options;\n\t\tthis.identifyCompressionEnabled = useIdentifyCompression;\n\n\t\tconst params = new URLSearchParams({ v: version, encoding });\n\t\tif (compression !== null) {\n\t\t\tif (useIdentifyCompression) {\n\t\t\t\tconsole.warn('WebSocketShard: transport compression is enabled, disabling identify compression');\n\t\t\t\tthis.identifyCompressionEnabled = false;\n\t\t\t}\n\n\t\t\tparams.append('compress', CompressionParameterMap[compression]);\n\n\t\t\tswitch (compression) {\n\t\t\t\tcase CompressionMethod.ZlibNative: {\n\t\t\t\t\tconst zlib = await getNativeZlib();\n\t\t\t\t\tif (zlib) {\n\t\t\t\t\t\tthis.inflateBuffer = [];\n\n\t\t\t\t\t\tconst inflate = zlib.createInflate({\n\t\t\t\t\t\t\tchunkSize: 65_535,\n\t\t\t\t\t\t\tflush: zlib.constants.Z_SYNC_FLUSH,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tinflate.on('data', (chunk) => {\n\t\t\t\t\t\t\tthis.inflateBuffer.push(chunk);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tinflate.on('error', (error) => {\n\t\t\t\t\t\t\tthis.emit(WebSocketShardEvents.Error, error);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tthis.nativeInflate = inflate;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconsole.warn('WebSocketShard: Compression is set to native zlib but node:zlib is not available.');\n\t\t\t\t\t\tparams.delete('compress');\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase CompressionMethod.ZlibSync: {\n\t\t\t\t\tconst zlib = await getZlibSync();\n\t\t\t\t\tif (zlib) {\n\t\t\t\t\t\tthis.zLibSyncInflate = new zlib.Inflate({\n\t\t\t\t\t\t\tchunkSize: 65_535,\n\t\t\t\t\t\t\tto: 'string',\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconsole.warn('WebSocketShard: Compression is set to zlib-sync, but it is not installed.');\n\t\t\t\t\t\tparams.delete('compress');\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase CompressionMethod.ZstdNative: {\n\t\t\t\t\tconst zlib = await getNativeZlib();\n\t\t\t\t\tif (zlib && 'createZstdDecompress' in zlib) {\n\t\t\t\t\t\tthis.inflateBuffer = [];\n\n\t\t\t\t\t\tconst inflate = zlib.createZstdDecompress({\n\t\t\t\t\t\t\tchunkSize: 65_535,\n\t\t\t\t\t\t}) as nativeZlib.Inflate;\n\n\t\t\t\t\t\tinflate.on('data', (chunk) => {\n\t\t\t\t\t\t\tthis.inflateBuffer.push(chunk);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tinflate.on('error', (error) => {\n\t\t\t\t\t\t\tthis.emit(WebSocketShardEvents.Error, error);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tthis.nativeInflate = inflate;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t'WebSocketShard: Compression is set to native zstd but node:zlib is not available or your node version does not support zstd decompression.',\n\t\t\t\t\t\t);\n\t\t\t\t\t\tparams.delete('compress');\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.identifyCompressionEnabled) {\n\t\t\tconst zlib = await getNativeZlib();\n\t\t\tif (!zlib) {\n\t\t\t\tconsole.warn('WebSocketShard: Identify compression is enabled, but node:zlib is not available.');\n\t\t\t\tthis.identifyCompressionEnabled = false;\n\t\t\t}\n\t\t}\n\n\t\tconst session = await this.strategy.retrieveSessionInfo(this.id);\n\n\t\tconst url = `${session?.resumeURL ?? this.strategy.options.gatewayInformation.url}?${params.toString()}`;\n\n\t\tthis.debug([`Connecting to ${url}`]);\n\n\t\tconst connection = new WebSocketConstructor(url, [], {\n\t\t\thandshakeTimeout: this.strategy.options.handshakeTimeout ?? undefined,\n\t\t});\n\n\t\tconnection.binaryType = 'arraybuffer';\n\n\t\tconnection.onmessage = (event) => {\n\t\t\tvoid this.onMessage(event.data, event.data instanceof ArrayBuffer);\n\t\t};\n\n\t\tconnection.onerror = (event) => {\n\t\t\tthis.onError(event.error);\n\t\t};\n\n\t\tconnection.onclose = (event) => {\n\t\t\tvoid this.onClose(event.code);\n\t\t};\n\n\t\tconnection.onopen = () => {\n\t\t\tthis.sendRateLimitState = getInitialSendRateLimitState();\n\t\t};\n\n\t\tthis.connection = connection;\n\n\t\tthis.#status = WebSocketShardStatus.Connecting;\n\n\t\tconst { ok } = await this.waitForEvent(WebSocketShardEvents.Hello, this.strategy.options.helloTimeout);\n\t\tif (!ok) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (session?.shardCount === this.strategy.options.shardCount) {\n\t\t\tawait this.resume(session);\n\t\t} else {\n\t\t\tawait this.identify();\n\t\t}\n\t}\n\n\tpublic async destroy(options: WebSocketShardDestroyOptions = {}) {\n\t\tif (this.#status === WebSocketShardStatus.Idle) {\n\t\t\tthis.debug(['Tried to destroy a shard that was idle']);\n\t\t\treturn;\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n\t\tif (!options.code) {\n\t\t\toptions.code = options.recover === WebSocketShardDestroyRecovery.Resume ? CloseCodes.Resuming : CloseCodes.Normal;\n\t\t}\n\n\t\tthis.debug([\n\t\t\t'Destroying shard',\n\t\t\t`Reason: ${options.reason ?? 'none'}`,\n\t\t\t`Code: ${options.code}`,\n\t\t\t`Recover: ${options.recover === undefined ? 'none' : WebSocketShardDestroyRecovery[options.recover]!}`,\n\t\t]);\n\n\t\t// Reset state\n\t\tthis.isAck = true;\n\t\tif (this.heartbeatInterval) {\n\t\t\tclearInterval(this.heartbeatInterval);\n\t\t}\n\n\t\tif (this.initialHeartbeatTimeoutController) {\n\t\t\tthis.initialHeartbeatTimeoutController.abort();\n\t\t\tthis.initialHeartbeatTimeoutController = null;\n\t\t}\n\n\t\tthis.lastHeartbeatAt = -1;\n\n\t\tfor (const controller of this.timeoutAbortControllers.values()) {\n\t\t\tcontroller.abort();\n\t\t}\n\n\t\tthis.timeoutAbortControllers.clear();\n\n\t\tthis.failedToConnectDueToNetworkError = false;\n\n\t\t// Clear session state if applicable\n\t\tif (options.recover !== WebSocketShardDestroyRecovery.Resume) {\n\t\t\tawait this.strategy.updateSessionInfo(this.id, null);\n\t\t}\n\n\t\tif (this.connection) {\n\t\t\t// No longer need to listen to messages\n\t\t\tthis.connection.onmessage = null;\n\t\t\t// Prevent a reconnection loop by unbinding the main close event\n\t\t\tthis.connection.onclose = null;\n\n\t\t\tconst shouldClose = this.connection.readyState === WebSocket.OPEN;\n\n\t\t\tthis.debug([\n\t\t\t\t'Connection status during destroy',\n\t\t\t\t`Needs closing: ${shouldClose}`,\n\t\t\t\t`Ready state: ${this.connection.readyState}`,\n\t\t\t]);\n\n\t\t\tif (shouldClose) {\n\t\t\t\tlet outerResolve: () => void;\n\t\t\t\tconst promise = new Promise<void>((resolve) => {\n\t\t\t\t\touterResolve = resolve;\n\t\t\t\t});\n\n\t\t\t\tthis.connection.onclose = outerResolve!;\n\n\t\t\t\tthis.connection.close(options.code, options.reason);\n\n\t\t\t\tawait promise;\n\t\t\t\tthis.emit(WebSocketShardEvents.Closed, options.code);\n\t\t\t}\n\n\t\t\t// Lastly, remove the error event.\n\t\t\t// Doing this earlier would cause a hard crash in case an error event fired on our `close` call\n\t\t\tthis.connection.onerror = null;\n\t\t} else {\n\t\t\tthis.debug(['Destroying a shard that has no connection; please open an issue on GitHub']);\n\t\t}\n\n\t\tthis.#status = WebSocketShardStatus.Idle;\n\n\t\tif (options.recover !== undefined) {\n\t\t\t// There's cases (like no internet connection) where we immediately fail to connect,\n\t\t\t// causing a very fast and draining reconnection loop.\n\t\t\tawait sleep(500);\n\t\t\treturn this.internalConnect();\n\t\t}\n\t}\n\n\tprivate async waitForEvent(event: WebSocketShardEvents, timeoutDuration?: number | null): Promise<{ ok: boolean }> {\n\t\tthis.debug([`Waiting for event ${event} ${timeoutDuration ? `for ${timeoutDuration}ms` : 'indefinitely'}`]);\n\t\tconst timeoutController = new AbortController();\n\t\tconst timeout = timeoutDuration ? setTimeout(() => timeoutController.abort(), timeoutDuration).unref() : null;\n\n\t\tthis.timeoutAbortControllers.set(event, timeoutController);\n\n\t\tconst closeController = new AbortController();\n\n\t\ttry {\n\t\t\t// If the first promise resolves, all is well. If the 2nd promise resolves,\n\t\t\t// the shard has meanwhile closed. In that case, a destroy is already ongoing, so we just need to\n\t\t\t// return false. Meanwhile, if something rejects (error event) or the first controller is aborted,\n\t\t\t// we enter the catch block and trigger a destroy there.\n\t\t\tconst closed = await Promise.race<boolean>([\n\t\t\t\tonce(this, event, { signal: timeoutController.signal }).then(() => false),\n\t\t\t\tonce(this, WebSocketShardEvents.Closed, { signal: closeController.signal }).then(() => true),\n\t\t\t]);\n\n\t\t\treturn { ok: !closed };\n\t\t} catch {\n\t\t\t// If we're here because of other reasons, we need to destroy the shard\n\t\t\tvoid this.destroy({\n\t\t\t\tcode: CloseCodes.Normal,\n\t\t\t\treason: 'Something timed out or went wrong while waiting for an event',\n\t\t\t\trecover: WebSocketShardDestroyRecovery.Reconnect,\n\t\t\t});\n\n\t\t\treturn { ok: false };\n\t\t} finally {\n\t\t\tif (timeout) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t}\n\n\t\t\tthis.timeoutAbortControllers.delete(event);\n\n\t\t\t// Clean up the close listener to not leak memory\n\t\t\tif (!closeController.signal.aborted) {\n\t\t\t\tcloseController.abort();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic async send(payload: GatewaySendPayload): Promise<void> {\n\t\tif (!this.connection) {\n\t\t\tthrow new Error(\"WebSocketShard wasn't connected\");\n\t\t}\n\n\t\t// Generally, the way we treat payloads is 115/60 seconds. The actual limit is 120/60, so we have a bit of leeway.\n\t\t// We use that leeway for those special payloads that we just fire with no checking, since there's no shot we ever\n\t\t// send more than 5 of those in a 60 second interval. This way we can avoid more complex queueing logic.\n\n\t\tif (ImportantGatewayOpcodes.has(payload.op)) {\n\t\t\tthis.connection.send(JSON.stringify(payload));\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.#status !== WebSocketShardStatus.Ready && !ImportantGatewayOpcodes.has(payload.op)) {\n\t\t\tthis.debug(['Tried to send a non-crucial payload before the shard was ready, waiting']);\n\t\t\t// This will throw if the shard throws an error event in the meantime, just requeue the payload\n\t\t\ttry {\n\t\t\t\tawait once(this, WebSocketShardEvents.Ready);\n\t\t\t} catch {\n\t\t\t\treturn this.send(payload);\n\t\t\t}\n\t\t}\n\n\t\tawait this.sendQueue.wait();\n\n\t\tconst now = Date.now();\n\t\tif (now >= this.sendRateLimitState.resetAt) {\n\t\t\tthis.sendRateLimitState = getInitialSendRateLimitState();\n\t\t}\n\n\t\tif (this.sendRateLimitState.sent + 1 >= 115) {\n\t\t\t// Sprinkle in a little randomness just in case.\n\t\t\tconst sleepFor = this.sendRateLimitState.resetAt - now + Math.random() * 1_500;\n\n\t\t\tthis.debug([`Was about to hit the send rate limit, sleeping for ${sleepFor}ms`]);\n\t\t\tconst controller = new AbortController();\n\n\t\t\t// Sleep for the remaining time, but if the connection closes in the meantime, we shouldn't wait the remainder to avoid blocking the new conn\n\t\t\tconst interrupted = await Promise.race([\n\t\t\t\tsleep(sleepFor).then(() => false),\n\t\t\t\tonce(this, WebSocketShardEvents.Closed, { signal: controller.signal }).then(() => true),\n\t\t\t]);\n\n\t\t\tif (interrupted) {\n\t\t\t\tthis.debug(['Connection closed while waiting for the send rate limit to reset, re-queueing payload']);\n\t\t\t\tthis.sendQueue.shift();\n\t\t\t\treturn this.send(payload);\n\t\t\t}\n\n\t\t\t// This is so the listener from the `once` call is removed\n\t\t\tcontroller.abort();\n\t\t}\n\n\t\tthis.sendRateLimitState.sent++;\n\n\t\tthis.sendQueue.shift();\n\t\tthis.connection.send(JSON.stringify(payload));\n\t}\n\n\tprivate async identify() {\n\t\tthis.debug(['Waiting for identify throttle']);\n\n\t\tconst controller = new AbortController();\n\t\tconst closeHandler = () => {\n\t\t\tcontroller.abort();\n\t\t};\n\n\t\tthis.on(WebSocketShardEvents.Closed, closeHandler);\n\n\t\ttry {\n\t\t\tawait this.strategy.waitForIdentify(this.id, controller.signal);\n\t\t} catch {\n\t\t\tif (controller.signal.aborted) {\n\t\t\t\tthis.debug(['Was waiting for an identify, but the shard closed in the meantime']);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.debug([\n\t\t\t\t'IContextFetchingStrategy#waitForIdentify threw an unknown error.',\n\t\t\t\t\"If you're using a custom strategy, this is probably nothing to worry about.\",\n\t\t\t\t\"If you're not, please open an issue on GitHub.\",\n\t\t\t]);\n\n\t\t\tawait this.destroy({\n\t\t\t\treason: 'Identify throttling logic failed',\n\t\t\t\trecover: WebSocketShardDestroyRecovery.Resume,\n\t\t\t});\n\t\t} finally {\n\t\t\tthis.off(WebSocketShardEvents.Closed, closeHandler);\n\t\t}\n\n\t\tthis.debug([\n\t\t\t'Identifying',\n\t\t\t`shard id: ${this.id.toString()}`,\n\t\t\t`shard count: ${this.strategy.options.shardCount}`,\n\t\t\t`intents: ${this.strategy.options.intents}`,\n\t\t\t`compression: ${this.transportCompressionEnabled ? CompressionParameterMap[this.strategy.options.compression!] : this.identifyCompressionEnabled ? 'identify' : 'none'}`,\n\t\t]);\n\n\t\tconst data: GatewayIdentifyData = {\n\t\t\ttoken: this.strategy.options.token,\n\t\t\tproperties: this.strategy.options.identifyProperties,\n\t\t\tintents: this.strategy.options.intents,\n\t\t\tcompress: this.identifyCompressionEnabled,\n\t\t\tshard: [this.id, this.strategy.options.shardCount],\n\t\t};\n\n\t\tif (this.strategy.options.largeThreshold) {\n\t\t\tdata.large_threshold = this.strategy.options.largeThreshold;\n\t\t}\n\n\t\tif (this.strategy.options.initialPresence) {\n\t\t\tdata.presence = this.strategy.options.initialPresence;\n\t\t}\n\n\t\tawait this.send({\n\t\t\top: GatewayOpcodes.Identify,\n\t\t\t// eslint-disable-next-line id-length\n\t\t\td: data,\n\t\t});\n\n\t\tawait this.waitForEvent(WebSocketShardEvents.Ready, this.strategy.options.readyTimeout);\n\t}\n\n\tprivate async resume(session: SessionInfo) {\n\t\tthis.debug([\n\t\t\t'Resuming session',\n\t\t\t`resume url: ${session.resumeURL}`,\n\t\t\t`sequence: ${session.sequence}`,\n\t\t\t`shard id: ${this.id.toString()}`,\n\t\t]);\n\n\t\tthis.#status = WebSocketShardStatus.Resuming;\n\t\tthis.replayedEvents = 0;\n\t\treturn this.send({\n\t\t\top: GatewayOpcodes.Resume,\n\t\t\t// eslint-disable-next-line id-length\n\t\t\td: {\n\t\t\t\ttoken: this.strategy.options.token,\n\t\t\t\tseq: session.sequence,\n\t\t\t\tsession_id: session.sessionId,\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate async heartbeat(requested = false) {\n\t\tif (!this.isAck && !requested) {\n\t\t\treturn this.destroy({ reason: 'Zombie connection', recover: WebSocketShardDestroyRecovery.Resume });\n\t\t}\n\n\t\tconst session = await this.strategy.retrieveSessionInfo(this.id);\n\n\t\tawait this.send({\n\t\t\top: GatewayOpcodes.Heartbeat,\n\t\t\t// eslint-disable-next-line id-length\n\t\t\td: session?.sequence ?? null,\n\t\t});\n\n\t\tthis.lastHeartbeatAt = Date.now();\n\t\tthis.isAck = false;\n\t}\n\n\tprivate parseInflateResult(result: any): GatewayReceivePayload | null {\n\t\tif (!result) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn JSON.parse(typeof result === 'string' ? result : this.textDecoder.decode(result)) as GatewayReceivePayload;\n\t}\n\n\tprivate async unpackMessage(data: Data, isBinary: boolean): Promise<GatewayReceivePayload | null> {\n\t\t// Deal with no compression\n\t\tif (!isBinary) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(data as string) as GatewayReceivePayload;\n\t\t\t} catch {\n\t\t\t\t// This is a non-JSON payload / (at the time of writing this comment) emitted by bun wrongly interpreting custom close codes https://github.com/oven-sh/bun/issues/3392\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\tconst decompressable = new Uint8Array(data as ArrayBuffer);\n\n\t\t// Deal with identify compress\n\t\tif (this.identifyCompressionEnabled) {\n\t\t\t// eslint-disable-next-line no-async-promise-executor\n\t\t\treturn new Promise(async (resolve, reject) => {\n\t\t\t\tconst zlib = (await getNativeZlib())!;\n\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-callbacks\n\t\t\t\tzlib.inflate(decompressable, { chunkSize: 65_535 }, (err, result) => {\n\t\t\t\t\tif (err) {\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve(JSON.parse(this.textDecoder.decode(result)) as GatewayReceivePayload);\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// Deal with transport compression\n\t\tif (this.transportCompressionEnabled) {\n\t\t\t// Each WS message received is a full gateway message for zstd streaming, but for zlib it's chunked\n\t\t\tconst flush =\n\t\t\t\tthis.strategy.options.compression === CompressionMethod.ZstdNative ||\n\t\t\t\t(decompressable.length >= 4 &&\n\t\t\t\t\tdecompressable.at(-4) === 0x00 &&\n\t\t\t\t\tdecompressable.at(-3) === 0x00 &&\n\t\t\t\t\tdecompressable.at(-2) === 0xff &&\n\t\t\t\t\tdecompressable.at(-1) === 0xff);\n\n\t\t\tif (this.nativeInflate) {\n\t\t\t\tconst doneWriting = new Promise<void>((resolve) => {\n\t\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-callbacks\n\t\t\t\t\tthis.nativeInflate!.write(decompressable, 'binary', (error) => {\n\t\t\t\t\t\tif (error) {\n\t\t\t\t\t\t\tthis.emit(WebSocketShardEvents.Error, error);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tif (!flush) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\t// This way we're ensuring the latest write has flushed and our buffer is ready\n\t\t\t\tawait doneWriting;\n\n\t\t\t\tconst result = this.parseInflateResult(Buffer.concat(this.inflateBuffer));\n\t\t\t\tthis.inflateBuffer = [];\n\n\t\t\t\treturn result;\n\t\t\t} else if (this.zLibSyncInflate) {\n\t\t\t\tconst zLibSync = (await getZlibSync())!;\n\t\t\t\tthis.zLibSyncInflate.push(Buffer.from(decompressable), flush ? zLibSync.Z_SYNC_FLUSH : zLibSync.Z_NO_FLUSH);\n\n\t\t\t\tif (this.zLibSyncInflate.err) {\n\t\t\t\t\t// Must be here because zlib-sync is lazily loaded\n\t\t\t\t\tconst ZlibErrorCodes = {\n\t\t\t\t\t\t[zLibSync.Z_NEED_DICT]: 'Z_NEED_DICT',\n\t\t\t\t\t\t[zLibSync.Z_STREAM_END]: 'Z_STREAM_END',\n\t\t\t\t\t\t[zLibSync.Z_ERRNO]: 'Z_ERRNO',\n\t\t\t\t\t\t[zLibSync.Z_STREAM_ERROR]: 'Z_STREAM_ERROR',\n\t\t\t\t\t\t[zLibSync.Z_DATA_ERROR]: 'Z_DATA_ERROR',\n\t\t\t\t\t\t[zLibSync.Z_MEM_ERROR]: 'Z_MEM_ERROR',\n\t\t\t\t\t\t[zLibSync.Z_BUF_ERROR]: 'Z_BUF_ERROR',\n\t\t\t\t\t\t[zLibSync.Z_VERSION_ERROR]: 'Z_VERSION_ERROR',\n\t\t\t\t\t} as const satisfies Record<number, string>;\n\n\t\t\t\t\t// Try to match nodejs zlib errors as much as possible\n\t\t\t\t\tconst error: NodeJS.ErrnoException = new Error(this.zLibSyncInflate.msg ?? undefined);\n\t\t\t\t\terror.errno = this.zLibSyncInflate.err;\n\t\t\t\t\terror.code = ZlibErrorCodes[this.zLibSyncInflate.err];\n\t\t\t\t\tthis.emit(WebSocketShardEvents.Error, error);\n\t\t\t\t}\n\n\t\t\t\tif (!flush) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst { result } = this.zLibSyncInflate;\n\t\t\t\treturn this.parseInflateResult(result);\n\t\t\t}\n\t\t}\n\n\t\tthis.debug([\n\t\t\t'Received a message we were unable to decompress',\n\t\t\t`isBinary: ${isBinary.toString()}`,\n\t\t\t`identifyCompressionEnabled: ${this.identifyCompressionEnabled.toString()}`,\n\t\t\t`inflate: ${this.transportCompressionEnabled ? CompressionMethod[this.strategy.options.compression!] : 'none'}`,\n\t\t]);\n\n\t\treturn null;\n\t}\n\n\tprivate async onMessage(data: Data, isBinary: boolean) {\n\t\tconst payload = await this.unpackMessage(data, isBinary);\n\t\tif (!payload) {\n\t\t\treturn;\n\t\t}\n\n\t\tswitch (payload.op) {\n\t\t\tcase GatewayOpcodes.Dispatch: {\n\t\t\t\tif (this.#status === WebSocketShardStatus.Resuming) {\n\t\t\t\t\tthis.replayedEvents++;\n\t\t\t\t}\n\n\t\t\t\t// eslint-disable-next-line sonarjs/no-nested-switch, @typescript-eslint/switch-exhaustiveness-check\n\t\t\t\tswitch (payload.t) {\n\t\t\t\t\tcase GatewayDispatchEvents.Ready: {\n\t\t\t\t\t\tthis.#status = WebSocketShardStatus.Ready;\n\n\t\t\t\t\t\tconst session = {\n\t\t\t\t\t\t\tsequence: payload.s,\n\t\t\t\t\t\t\tsessionId: payload.d.session_id,\n\t\t\t\t\t\t\tshardId: this.id,\n\t\t\t\t\t\t\tshardCount: this.strategy.options.shardCount,\n\t\t\t\t\t\t\tresumeURL: payload.d.resume_gateway_url,\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tawait this.strategy.updateSessionInfo(this.id, session);\n\n\t\t\t\t\t\tthis.emit(WebSocketShardEvents.Ready, payload.d);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase GatewayDispatchEvents.Resumed: {\n\t\t\t\t\t\tthis.#status = WebSocketShardStatus.Ready;\n\t\t\t\t\t\tthis.debug([`Resumed and replayed ${this.replayedEvents} events`]);\n\t\t\t\t\t\tthis.emit(WebSocketShardEvents.Resumed);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst session = await this.strategy.retrieveSessionInfo(this.id);\n\t\t\t\tif (session) {\n\t\t\t\t\tif (payload.s > session.sequence) {\n\t\t\t\t\t\tawait this.strategy.updateSessionInfo(this.id, { ...session, sequence: payload.s });\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis.debug([\n\t\t\t\t\t\t`Received a ${payload.t} event but no session is available. Session information cannot be re-constructed in this state without a full reconnect`,\n\t\t\t\t\t]);\n\t\t\t\t}\n\n\t\t\t\tthis.emit(WebSocketShardEvents.Dispatch, payload);\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase GatewayOpcodes.Heartbeat: {\n\t\t\t\tawait this.heartbeat(true);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase GatewayOpcodes.Reconnect: {\n\t\t\t\tawait this.destroy({\n\t\t\t\t\treason: 'Told to reconnect by Discord',\n\t\t\t\t\trecover: WebSocketShardDestroyRecovery.Resume,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase GatewayOpcodes.InvalidSession: {\n\t\t\t\tthis.debug([`Invalid session; will attempt to resume: ${payload.d.toString()}`]);\n\t\t\t\tconst session = await this.strategy.retrieveSessionInfo(this.id);\n\t\t\t\tif (payload.d && session) {\n\t\t\t\t\tawait this.resume(session);\n\t\t\t\t} else {\n\t\t\t\t\tawait this.destroy({\n\t\t\t\t\t\treason: 'Invalid session',\n\t\t\t\t\t\trecover: WebSocketShardDestroyRecovery.Reconnect,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase GatewayOpcodes.Hello: {\n\t\t\t\tthis.emit(WebSocketShardEvents.Hello);\n\t\t\t\tconst jitter = Math.random();\n\t\t\t\tconst firstWait = Math.floor(payload.d.heartbeat_interval * jitter);\n\t\t\t\tthis.debug([`Preparing first heartbeat of the connection with a jitter of ${jitter}; waiting ${firstWait}ms`]);\n\n\t\t\t\ttry {\n\t\t\t\t\tconst controller = new AbortController();\n\t\t\t\t\tthis.initialHeartbeatTimeoutController = controller;\n\t\t\t\t\tawait sleep(firstWait, undefined, { signal: controller.signal });\n\t\t\t\t} catch {\n\t\t\t\t\tthis.debug(['Cancelled initial heartbeat due to #destroy being called']);\n\t\t\t\t\treturn;\n\t\t\t\t} finally {\n\t\t\t\t\tthis.initialHeartbeatTimeoutController = null;\n\t\t\t\t}\n\n\t\t\t\tawait this.heartbeat();\n\n\t\t\t\tthis.debug([`First heartbeat sent, starting to beat every ${payload.d.heartbeat_interval}ms`]);\n\t\t\t\tthis.heartbeatInterval = setInterval(() => void this.heartbeat(), payload.d.heartbeat_interval);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase GatewayOpcodes.HeartbeatAck: {\n\t\t\t\tthis.isAck = true;\n\n\t\t\t\tconst ackAt = Date.now();\n\t\t\t\tthis.emit(WebSocketShardEvents.HeartbeatComplete, {\n\t\t\t\t\tackAt,\n\t\t\t\t\theartbeatAt: this.lastHeartbeatAt,\n\t\t\t\t\tlatency: ackAt - this.lastHeartbeatAt,\n\t\t\t\t});\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate onError(error: Error) {\n\t\tthis.emit(WebSocketShardEvents.SocketError, error);\n\t\tthis.failedToConnectDueToNetworkError = true;\n\t}\n\n\tprivate async onClose(code: number) {\n\t\tthis.emit(WebSocketShardEvents.Closed, code);\n\n\t\tswitch (code) {\n\t\t\tcase CloseCodes.Normal: {\n\t\t\t\treturn this.destroy({\n\t\t\t\t\tcode,\n\t\t\t\t\treason: 'Got disconnected by Discord',\n\t\t\t\t\trecover: WebSocketShardDestroyRecovery.Reconnect,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase CloseCodes.Resuming: {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase GatewayCloseCodes.UnknownError: {\n\t\t\t\tthis.debug([`An unknown error occurred: ${code}`]);\n\t\t\t\treturn this.destroy({ code, recover: WebSocketShardDestroyRecovery.Resume });\n\t\t\t}\n\n\t\t\tcase GatewayCloseCodes.UnknownOpcode: {\n\t\t\t\tthis.debug(['An invalid opcode was sent to Discord.']);\n\t\t\t\treturn this.destroy({ code, recover: WebSocketShardDestroyRecovery.Resume });\n\t\t\t}\n\n\t\t\tcase GatewayCloseCodes.DecodeError: {\n\t\t\t\tthis.debug(['An invalid payload was sent to Discord.']);\n\t\t\t\treturn this.destroy({ code, recover: WebSocketShardDestroyRecovery.Resume });\n\t\t\t}\n\n\t\t\tcase GatewayCloseCodes.NotAuthenticated: {\n\t\t\t\tthis.debug(['A request was somehow sent before the identify/resume payload.']);\n\t\t\t\treturn this.destroy({ code, recover: WebSocketShardDestroyRecovery.Reconnect });\n\t\t\t}\n\n\t\t\tcase GatewayCloseCodes.AuthenticationFailed: {\n\t\t\t\tthis.emit(\n\t\t\t\t\tWebSocketShardEvents.Error,\n\n\t\t\t\t\tnew Error('Authentication failed'),\n\t\t\t\t);\n\t\t\t\treturn this.destroy({ code });\n\t\t\t}\n\n\t\t\tcase GatewayCloseCodes.AlreadyAuthenticated: {\n\t\t\t\tthis.debug(['More than one auth payload was sent.']);\n\t\t\t\treturn this.destroy({ code, recover: WebSocketShardDestroyRecovery.Reconnect });\n\t\t\t}\n\n\t\t\tcase GatewayCloseCodes.InvalidSeq: {\n\t\t\t\tthis.debug(['An invalid sequence was sent.']);\n\t\t\t\treturn this.destroy({ code, recover: WebSocketShardDestroyRecovery.Reconnect });\n\t\t\t}\n\n\t\t\tcase GatewayCloseCodes.RateLimited: {\n\t\t\t\tthis.debug(['The WebSocket rate limit has been hit, this should never happen']);\n\t\t\t\treturn this.destroy({ code, recover: WebSocketShardDestroyRecovery.Reconnect });\n\t\t\t}\n\n\t\t\tcase GatewayCloseCodes.SessionTimedOut: {\n\t\t\t\tthis.debug(['Session timed out.']);\n\t\t\t\treturn this.destroy({ code, recover: WebSocketShardDestroyRecovery.Resume });\n\t\t\t}\n\n\t\t\tcase GatewayCloseCodes.InvalidShard: {\n\t\t\t\tthis.emit(WebSocketShardEvents.Error, new Error('Invalid shard'));\n\t\t\t\treturn this.destroy({ code });\n\t\t\t}\n\n\t\t\tcase GatewayCloseCodes.ShardingRequired: {\n\t\t\t\tthis.emit(\n\t\t\t\t\tWebSocketShardEvents.Error,\n\n\t\t\t\t\tnew Error('Sharding is required'),\n\t\t\t\t);\n\t\t\t\treturn this.destroy({ code });\n\t\t\t}\n\n\t\t\tcase GatewayCloseCodes.InvalidAPIVersion: {\n\t\t\t\tthis.emit(\n\t\t\t\t\tWebSocketShardEvents.Error,\n\n\t\t\t\t\tnew Error('Used an invalid API version'),\n\t\t\t\t);\n\t\t\t\treturn this.destroy({ code });\n\t\t\t}\n\n\t\t\tcase GatewayCloseCodes.InvalidIntents: {\n\t\t\t\tthis.emit(\n\t\t\t\t\tWebSocketShardEvents.Error,\n\n\t\t\t\t\tnew Error('Used invalid intents'),\n\t\t\t\t);\n\t\t\t\treturn this.destroy({ code });\n\t\t\t}\n\n\t\t\tcase GatewayCloseCodes.DisallowedIntents: {\n\t\t\t\tthis.emit(\n\t\t\t\t\tWebSocketShardEvents.Error,\n\n\t\t\t\t\tnew Error('Used disallowed intents'),\n\t\t\t\t);\n\t\t\t\treturn this.destroy({ code });\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tthis.debug([\n\t\t\t\t\t`The gateway closed with an unexpected code ${code}, attempting to ${\n\t\t\t\t\t\tthis.failedToConnectDueToNetworkError ? 'reconnect' : 'resume'\n\t\t\t\t\t}.`,\n\t\t\t\t]);\n\t\t\t\treturn this.destroy({\n\t\t\t\t\tcode,\n\t\t\t\t\trecover: this.failedToConnectDueToNetworkError\n\t\t\t\t\t\t? WebSocketShardDestroyRecovery.Reconnect\n\t\t\t\t\t\t: WebSocketShardDestroyRecovery.Resume,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate debug(messages: [string, ...string[]]) {\n\t\tthis.emit(WebSocketShardEvents.Debug, messages.join('\\n\\t'));\n\t}\n}\n"
  },
  {
    "path": "packages/ws/tsconfig.docs.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.docs.json\",\n\t\"compilerOptions\": {\n\t\t\"outDir\": \"dist-docs\"\n\t},\n\t\"include\": [\"src/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/ws/tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\n\t\t\"*.ts\",\n\t\t\"*.js\",\n\t\t\"*.cjs\",\n\t\t\"*.mjs\",\n\t\t\"src/**/*.ts\",\n\t\t\"src/**/*.js\",\n\t\t\"src/**/*.cjs\",\n\t\t\"src/**/*.mjs\",\n\t\t\"bin\",\n\t\t\"scripts\",\n\t\t\"__tests__\",\n\t\t\"__mocks__\"\n\t],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/ws/tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"../../tsconfig.json\",\n\t\"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.cjs\", \"src/**/*.mjs\", \"bin\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/ws/tsconfig.test.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"noEmit\": true,\n\t\t\"skipLibCheck\": true\n\t},\n\t\"include\": [\"__tests__/**/*.ts\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/ws/tsup.config.ts",
    "content": "import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector';\nimport { createTsupConfig } from '../../tsup.config.js';\n\nexport default [\n\tcreateTsupConfig({\n\t\texternal: ['zlib-sync'],\n\t\tesbuildPlugins: [esbuildPluginVersionInjector()],\n\t}),\n\tcreateTsupConfig({\n\t\tentry: {\n\t\t\tdefaultWorker: 'src/strategies/sharding/defaultWorker.ts',\n\t\t},\n\t}),\n];\n"
  },
  {
    "path": "patches/@microsoft__tsdoc-config@0.17.1.patch",
    "content": "diff --git a/lib/TSDocConfigFile.js b/lib/TSDocConfigFile.js\nindex caf3515d60fd386c5909db5a0aa8b4180b10d602..5f7cfed7611e3fe660b5265ff99c5da0beb7caec 100644\n--- a/lib/TSDocConfigFile.js\n+++ b/lib/TSDocConfigFile.js\n@@ -37,10 +37,7 @@ const ajv_1 = __importDefault(require(\"ajv\"));\n const jju = __importStar(require(\"jju\"));\n const ajv = new ajv_1.default({ verbose: true });\n function initializeSchemaValidator() {\n-    const jsonSchemaPath = resolve.sync('@microsoft/tsdoc/schemas/tsdoc.schema.json', {\n-        basedir: __dirname\n-    });\n-    const jsonSchemaContent = fs.readFileSync(jsonSchemaPath).toString();\n+    const jsonSchemaContent = '{\\\"title\\\":\\\"TSDoc Configuration\\\",\\\"description\\\":\\\"Describes the TSDoc configuration for a TypeScript project\\\",\\\"type\\\":\\\"object\\\",\\\"properties\\\":{\\\"$schema\\\":{\\\"description\\\":\\\"Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.\\\",\\\"type\\\":\\\"string\\\"},\\\"extends\\\":{\\\"description\\\":\\\"Optionally specifies one or more JSON config files that will be combined with this file.  This provides a way for standard settings to be shared across multiple projects.  Important: The \\\\\\\"extends\\\\\\\" paths are resolved using NodeJS module resolution, so a path to a local file MUST be prefixed with \\\\\\\".\\/\\\\\\\".\\\",\\\"type\\\":\\\"array\\\",\\\"items\\\":{\\\"type\\\":\\\"string\\\"}},\\\"noStandardTags\\\":{\\\"description\\\":\\\"By default, the config file loader will predefine all of the standardized TSDoc tags.  To disable this and start with a completely empty configuration, set \\\\\\\"noStandardTags\\\\\\\"=true.\\\",\\\"type\\\":\\\"boolean\\\"},\\\"tagDefinitions\\\":{\\\"description\\\":\\\"Additional tags to support when parsing documentation comments with TSDoc.\\\",\\\"type\\\":\\\"array\\\",\\\"items\\\":{\\\"$ref\\\":\\\"#\\/definitions\\/tsdocTagDefinition\\\"}},\\\"supportedHtmlElements\\\":{\\\"description\\\":\\\"The HTML element names that are supported in this configuration. Used in conjunction with the \\\\\\\"reportUnsupportedHtmlElements\\\\\\\" setting.\\\",\\\"type\\\":\\\"array\\\",\\\"items\\\":{\\\"type\\\":\\\"string\\\",\\\"pattern\\\":\\\"^[a-zA-Z0-9-]+$\\\"}},\\\"reportUnsupportedHtmlElements\\\":{\\\"description\\\":\\\"Whether an error should be reported when an unsupported HTML element is encountered in a doc comment. Defaults to \\\\\\\"true\\\\\\\" if the \\\\\\\"supportedHtmlElements\\\\\\\" field is present in this file, \\\\\\\"false\\\\\\\" if not.\\\",\\\"type\\\":\\\"boolean\\\"},\\\"supportForTags\\\":{\\\"description\\\":\\\"A collection of key\\/value pairs.  The key is a TSDoc tag name (e.g. \\\\\\\"@myTag\\\\\\\") that must be defined in this configuration.  The value is a boolean indicating whether the tag is supported.  The TSDoc parser may report warnings when unsupported tags are encountered.  If \\\\\\\"supportForTags\\\\\\\" is specified for at least one tag, then the \\\\\\\"reportUnsupportedTags\\\\\\\" validation check is enabled by default.\\\",\\\"type\\\":\\\"object\\\",\\\"patternProperties\\\":{\\\"@[a-zA-Z][a-zA-Z0-9]*$\\\":{\\\"type\\\":\\\"boolean\\\"}}}},\\\"required\\\":[\\\"$schema\\\"],\\\"additionalProperties\\\":false,\\\"definitions\\\":{\\\"tsdocTagDefinition\\\":{\\\"description\\\":\\\"Configuration for a custom supported TSDoc tag.\\\",\\\"type\\\":\\\"object\\\",\\\"properties\\\":{\\\"tagName\\\":{\\\"description\\\":\\\"Name of the custom tag. TSDoc tag names start with an at-sign (@) followed by ASCII letters using camelCase capitalization.\\\",\\\"type\\\":\\\"string\\\"},\\\"syntaxKind\\\":{\\\"description\\\":\\\"Syntax kind of the custom tag. \\\\\\\"inline\\\\\\\" means that this tag can appear inside other documentation sections (example: {@link}). \\\\\\\"block\\\\\\\" means that this tag starts a new documentation section (example: @remarks). \\\\\\\"modifier\\\\\\\" means that this tag\\'s presence indicates an aspect of the associated API item (example: @internal).\\\",\\\"type\\\":\\\"string\\\",\\\"enum\\\":[\\\"inline\\\",\\\"block\\\",\\\"modifier\\\"]},\\\"allowMultiple\\\":{\\\"description\\\":\\\"If true, then this tag may appear multiple times in a doc comment. By default, a tag may only appear once.\\\",\\\"type\\\":\\\"boolean\\\"}},\\\"required\\\":[\\\"tagName\\\",\\\"syntaxKind\\\"],\\\"additionalProperties\\\":false}}}';\n     const jsonSchema = jju.parse(jsonSchemaContent, { mode: 'cjson' });\n     return ajv.compile(jsonSchema);\n }\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - apps/*\n  - packages/*\n  - packages/create-discord-bot/template/**/*\n\nautoInstallPeers: false\n\nignoredBuiltDependencies:\n  - core-js-pure\n  - unrs-resolver\n\nonlyBuiltDependencies:\n  - '@discordjs/opus'\n  - '@tailwindcss/oxide'\n  - bufferutil\n  - esbuild\n  - protobufjs\n  - rclone.js\n  - sharp\n  - utf-8-validate\n  - workerd\n  - zlib-sync\n\npatchedDependencies:\n  '@microsoft/tsdoc-config@0.17.1': patches/@microsoft__tsdoc-config@0.17.1.patch\n\npeerDependencyRules:\n  allowAny:\n    - '*'\n  ignoreMissing:\n    - '*'\n\npublicHoistPattern:\n  - '*eslint*'\n  - '*prettier*'\n  - '*@rushstack/node-core-library*'\n  - '*jju*'\n\nupdateConfig:\n  ignoreDependencies:\n    - jsdoc-to-markdown\n    - typedoc\n"
  },
  {
    "path": "tsconfig.docs.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"emitDeclarationOnly\": true,\n\t\t\"declarationMap\": true\n\t},\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "tsconfig.eslint.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true\n\t},\n\t\"include\": [\"*.ts\", \"*.tsx\", \"*.js\", \".jsx\", \".cjs\", \"*.mjs\"],\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n\t\"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n\t// Mapped from https://www.typescriptlang.org/tsconfig\n\t\"compilerOptions\": {\n\t\t// Type Checking\n\t\t\"allowUnreachableCode\": false,\n\t\t\"allowUnusedLabels\": false,\n\t\t\"exactOptionalPropertyTypes\": true,\n\t\t\"noFallthroughCasesInSwitch\": true,\n\t\t\"noImplicitOverride\": true,\n\t\t\"noImplicitReturns\": true,\n\t\t\"noPropertyAccessFromIndexSignature\": false,\n\t\t\"noUncheckedIndexedAccess\": true,\n\t\t\"noUnusedLocals\": true,\n\t\t\"noUnusedParameters\": true,\n\t\t\"strict\": true,\n\n\t\t// Modules\n\t\t\"allowArbitraryExtensions\": false,\n\t\t\"allowImportingTsExtensions\": false,\n\t\t\"module\": \"ESNext\",\n\t\t\"moduleResolution\": \"Bundler\",\n\t\t\"resolveJsonModule\": true,\n\t\t\"resolvePackageJsonExports\": true,\n\t\t\"resolvePackageJsonImports\": true,\n\n\t\t// Emit\n\t\t\"declaration\": true,\n\t\t\"declarationMap\": true,\n\t\t\"importHelpers\": false,\n\t\t\"newLine\": \"lf\",\n\t\t\"noEmitHelpers\": true,\n\t\t\"outDir\": \"dist\",\n\t\t\"removeComments\": false,\n\t\t\"sourceMap\": true,\n\n\t\t// Interop Constraints\n\t\t\"allowSyntheticDefaultImports\": true,\n\t\t\"esModuleInterop\": false,\n\t\t\"forceConsistentCasingInFileNames\": true,\n\t\t\"isolatedModules\": true,\n\n\t\t// Language and Environment\n\t\t\"experimentalDecorators\": true,\n\t\t\"lib\": [\"ESNext\", \"esnext.disposable\"],\n\t\t\"target\": \"ESNext\",\n\t\t\"useDefineForClassFields\": true\n\t},\n\t\"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "tsup.config.ts",
    "content": "import type { Options } from 'tsup';\nimport { defineConfig } from 'tsup';\n\nexport function createTsupConfig({\n\tentry = ['src/index.ts'],\n\texternal = [],\n\tnoExternal = [],\n\tplatform = 'node',\n\tformat = ['esm', 'cjs'],\n\ttarget = 'es2022',\n\tskipNodeModulesBundle = true,\n\tclean = true,\n\tshims = format.includes('cjs'),\n\tcjsInterop = format.includes('cjs'),\n\tminify = false,\n\tterserOptions = {\n\t\tmangle: false,\n\t\tkeep_classnames: true,\n\t\tkeep_fnames: true,\n\t},\n\tsplitting = false,\n\tkeepNames = true,\n\tdts = true,\n\tsourcemap = true,\n\tesbuildPlugins = [],\n\ttreeshake = false,\n\toutDir = 'dist',\n}: Options = {}) {\n\treturn defineConfig({\n\t\tentry,\n\t\texternal,\n\t\tnoExternal,\n\t\tplatform,\n\t\tformat,\n\t\tskipNodeModulesBundle,\n\t\ttarget,\n\t\tclean,\n\t\tshims,\n\t\tcjsInterop,\n\t\tminify,\n\t\tterserOptions,\n\t\tsplitting,\n\t\tkeepNames,\n\t\tdts,\n\t\tsourcemap,\n\t\tesbuildPlugins,\n\t\ttreeshake,\n\t\toutDir,\n\t});\n}\n"
  },
  {
    "path": "turbo.json",
    "content": "{\n\t\"$schema\": \"https://turbo.build/schema.json\",\n\t\"remoteCache\": {\n\t\t\"enabled\": true\n\t},\n\t\"globalDependencies\": [\"tsconfig.json\"],\n\t\"tasks\": {\n\t\t\"build\": {\n\t\t\t\"dependsOn\": [\"^build\"],\n\t\t\t\"inputs\": [\"bin/**\", \"src/**\", \"scripts/**\", \"package.json\", \"tsconfig.json\", \"tsup.config.ts\", \"vite.config.ts\"],\n\t\t\t\"outputs\": [\"dist/**\"],\n\t\t\t\"outputLogs\": \"errors-only\"\n\t\t},\n\t\t\"@discordjs/ui#build-storybook\": {\n\t\t\t\"dependsOn\": [\"build\"],\n\t\t\t\"inputs\": [\".storybook/**/*\", \"src/**\", \"package.json\", \"tsconfig.json\", \"vite.config.ts\"],\n\t\t\t\"outputs\": [\"dist/**\", \"storybook-static/**\"],\n\t\t\t\"outputLogs\": \"errors-only\"\n\t\t},\n\t\t\"@discordjs/guide#build:local\": {\n\t\t\t\"dependsOn\": [\"^build\"],\n\t\t\t\"inputs\": [\"public/**\", \"src/**\", \"next.config.ts\", \"package.json\", \"tsconfig.json\"],\n\t\t\t\"outputs\": [\".next/**\", \".next/cache/**\", \".source/**\"],\n\t\t\t\"outputLogs\": \"full\"\n\t\t},\n\t\t\"@discordjs/guide#build:prod\": {\n\t\t\t\"dependsOn\": [\"^build\"],\n\t\t\t\"inputs\": [\"public/**\", \"src/**\", \"next.config.ts\", \"package.json\", \"tsconfig.json\"],\n\t\t\t\"outputs\": [\".next/**\", \".next/cache/**\", \".source/**\"],\n\t\t\t\"outputLogs\": \"full\"\n\t\t},\n\t\t\"@discordjs/website#build:local\": {\n\t\t\t\"env\": [\n\t\t\t\t\"VERCEL_ENV\",\n\t\t\t\t\"NEXT_PUBLIC_LOCAL_DEV\",\n\t\t\t\t\"EDGE_CONFIG\",\n\t\t\t\t\"MAX_FETCH_SIZE\",\n\t\t\t\t\"CF_ACCOUNT_ID\",\n\t\t\t\t\"CF_R2_DOCS_URL\",\n\t\t\t\t\"CF_R2_DOCS_ACCESS_KEY_ID\",\n\t\t\t\t\"CF_R2_DOCS_SECRET_ACCESS_KEY\",\n\t\t\t\t\"CF_R2_DOCS_TOKEN\",\n\t\t\t\t\"CF_R2_DOCS_BUCKET\",\n\t\t\t\t\"CF_R2_DOCS_BUCKET_URL\",\n\t\t\t\t\"CF_D1_DOCS_ID\",\n\t\t\t\t\"CF_D1_DOCS_API_KEY\"\n\t\t\t],\n\t\t\t\"dependsOn\": [\"^build\", \"^docs\"],\n\t\t\t\"inputs\": [\n\t\t\t\t\"../../packages/*/README.md\",\n\t\t\t\t\"public/**\",\n\t\t\t\t\"src/**\",\n\t\t\t\t\"scripts/**\",\n\t\t\t\t\"!src/assets/readme/**\",\n\t\t\t\t\"scripts/**\",\n\t\t\t\t\"next.config.ts\",\n\t\t\t\t\"package.json\",\n\t\t\t\t\"tsconfig.json\"\n\t\t\t],\n\t\t\t\"outputs\": [\".next/**\", \".next/cache/**\", \"src/assets/readme/**\"],\n\t\t\t\"outputLogs\": \"full\"\n\t\t},\n\t\t\"@discordjs/website#build:prod\": {\n\t\t\t\"env\": [\n\t\t\t\t\"VERCEL_ENV\",\n\t\t\t\t\"NEXT_PUBLIC_LOCAL_DEV\",\n\t\t\t\t\"EDGE_CONFIG\",\n\t\t\t\t\"MAX_FETCH_SIZE\",\n\t\t\t\t\"CF_ACCOUNT_ID\",\n\t\t\t\t\"CF_R2_DOCS_URL\",\n\t\t\t\t\"CF_R2_DOCS_ACCESS_KEY_ID\",\n\t\t\t\t\"CF_R2_DOCS_SECRET_ACCESS_KEY\",\n\t\t\t\t\"CF_R2_DOCS_TOKEN\",\n\t\t\t\t\"CF_R2_DOCS_BUCKET\",\n\t\t\t\t\"CF_R2_DOCS_BUCKET_URL\",\n\t\t\t\t\"CF_D1_DOCS_ID\",\n\t\t\t\t\"CF_D1_DOCS_API_KEY\"\n\t\t\t],\n\t\t\t\"dependsOn\": [\"^build\"],\n\t\t\t\"inputs\": [\n\t\t\t\t\"../../packages/*/README.md\",\n\t\t\t\t\"public/**\",\n\t\t\t\t\"src/**\",\n\t\t\t\t\"scripts/**\",\n\t\t\t\t\"!src/assets/readme/**\",\n\t\t\t\t\"scripts/**\",\n\t\t\t\t\"next.config.ts\",\n\t\t\t\t\"package.json\",\n\t\t\t\t\"tsconfig.json\"\n\t\t\t],\n\t\t\t\"outputs\": [\".next/**\", \".next/cache/**\", \"src/assets/readme/**\"],\n\t\t\t\"outputLogs\": \"full\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"dependsOn\": [\"^build\"],\n\t\t\t\"inputs\": [\n\t\t\t\t\"../../vitest.config.ts\",\n\t\t\t\t\"__mocks__/**\",\n\t\t\t\t\"__tests__/**\",\n\t\t\t\t\"src/**\",\n\t\t\t\t\"package.json\",\n\t\t\t\t\"tsconfig.json\",\n\t\t\t\t\"vitest.config.ts\"\n\t\t\t],\n\t\t\t\"outputs\": [\"coverage/**\"],\n\t\t\t\"outputLogs\": \"new-only\"\n\t\t},\n\t\t\"lint\": {\n\t\t\t\"dependsOn\": [\"^build\"],\n\t\t\t\"inputs\": [\n\t\t\t\t\"../../eslint.config.js\",\n\t\t\t\t\"../../.prettierrc.json\",\n\t\t\t\t\"../../tsconfig.eslint.json\",\n\t\t\t\t\".prettierrc.js\",\n\t\t\t\t\"bin/**\",\n\t\t\t\t\"src/**\",\n\t\t\t\t\"scripts/**\",\n\t\t\t\t\"package.json\",\n\t\t\t\t\"tsconfig.eslint.json\"\n\t\t\t],\n\t\t\t\"outputs\": [],\n\t\t\t\"outputLogs\": \"errors-only\"\n\t\t},\n\t\t\"@discordjs/guide#lint\": {\n\t\t\t\"dependsOn\": [\"^build\", \"build:local\"],\n\t\t\t\"inputs\": [\n\t\t\t\t\"../../eslint.config.js\",\n\t\t\t\t\"../../.prettierrc.json\",\n\t\t\t\t\"../../tsconfig.eslint.json\",\n\t\t\t\t\".prettierrc.js\",\n\t\t\t\t\"src/**\",\n\t\t\t\t\"!src/styles/unocss.css\",\n\t\t\t\t\"tsconfig.eslint.json\"\n\t\t\t],\n\t\t\t\"outputs\": [],\n\t\t\t\"outputLogs\": \"errors-only\"\n\t\t},\n\t\t\"@discordjs/website#lint\": {\n\t\t\t\"dependsOn\": [\"^build\", \"build:local\"],\n\t\t\t\"inputs\": [\n\t\t\t\t\"../../eslint.config.js\",\n\t\t\t\t\"../../.prettierrc.json\",\n\t\t\t\t\"../../tsconfig.eslint.json\",\n\t\t\t\t\".prettierrc.js\",\n\t\t\t\t\"src/**\",\n\t\t\t\t\"!src/styles/unocss.css\",\n\t\t\t\t\"tsconfig.eslint.json\"\n\t\t\t],\n\t\t\t\"outputs\": [],\n\t\t\t\"outputLogs\": \"errors-only\"\n\t\t},\n\t\t\"format\": {\n\t\t\t\"dependsOn\": [\"^build\"],\n\t\t\t\"inputs\": [\n\t\t\t\t\"../../eslint.config.js\",\n\t\t\t\t\"../../.prettierrc.json\",\n\t\t\t\t\"../../tsconfig.eslint.json\",\n\t\t\t\t\".prettierrc.js\",\n\t\t\t\t\"bin/**\",\n\t\t\t\t\"src/**\",\n\t\t\t\t\"scripts/**\",\n\t\t\t\t\"package.json\",\n\t\t\t\t\"tsconfig.eslint.json\"\n\t\t\t],\n\t\t\t\"outputs\": [],\n\t\t\t\"outputLogs\": \"errors-only\"\n\t\t},\n\t\t\"@discordjs/guide#format\": {\n\t\t\t\"dependsOn\": [\"^build\"],\n\t\t\t\"inputs\": [\n\t\t\t\t\"../../eslint.config.js\",\n\t\t\t\t\"../../.prettierrc.json\",\n\t\t\t\t\"../../tsconfig.eslint.json\",\n\t\t\t\t\".prettierrc.js\",\n\t\t\t\t\"src/**\",\n\t\t\t\t\"!src/styles/unocss.css\",\n\t\t\t\t\"package.json\",\n\t\t\t\t\"tsconfig.eslint.json\"\n\t\t\t],\n\t\t\t\"outputs\": [],\n\t\t\t\"outputLogs\": \"errors-only\"\n\t\t},\n\t\t\"docs\": {\n\t\t\t\"dependsOn\": [\"build\"],\n\t\t\t\"inputs\": [\n\t\t\t\t\"../api-extractor/src/**\",\n\t\t\t\t\"../api-extractor-model/src/**\",\n\t\t\t\t\"../api-extractor-utils/src/**\",\n\t\t\t\t\"../../api-extractor.json\",\n\t\t\t\t\"../../tsconfig.docs.json\",\n\t\t\t\t\"api-extractor.json\",\n\t\t\t\t\"docs/**\",\n\t\t\t\t\"!docs/docs.json\",\n\t\t\t\t\"!docs/docs.api.json\",\n\t\t\t\t\"!docs/*/split/**\",\n\t\t\t\t\"tsconfig.docs.json\"\n\t\t\t],\n\t\t\t\"outputs\": [\"dist-docs/**\", \"docs/docs.json\", \"docs/docs.api.json\", \"docs/*/split/**\"],\n\t\t\t\"cache\": false,\n\t\t\t\"outputLogs\": \"errors-only\"\n\t\t},\n\t\t\"changelog\": {\n\t\t\t\"inputs\": [\"cliff.toml\"],\n\t\t\t\"outputs\": [\"CHANGELOG.md\"],\n\t\t\t\"outputLogs\": \"full\"\n\t\t},\n\t\t\"release\": {\n\t\t\t\"dependsOn\": [\"^build\"],\n\t\t\t\"inputs\": [\"CHANGELOG.md\", \"package.json\"],\n\t\t\t\"outputs\": [],\n\t\t\t\"outputLogs\": \"full\"\n\t\t},\n\t\t\"dev\": {\n\t\t\t\"dependsOn\": [\"^build\"],\n\t\t\t\"cache\": false,\n\t\t\t\"persistent\": true,\n\t\t\t\"outputLogs\": \"full\"\n\t\t},\n\t\t\"@discordjs/guide#dev\": {\n\t\t\t\"dependsOn\": [\"^build\"],\n\t\t\t\"cache\": false,\n\t\t\t\"persistent\": true,\n\t\t\t\"outputLogs\": \"full\"\n\t\t},\n\t\t\"@discordjs/website#dev\": {\n\t\t\t\"env\": [\"VERCEL_ENV\", \"NEXT_PUBLIC_LOCAL_DEV\"],\n\t\t\t\"dependsOn\": [\"^build\", \"^docs\"],\n\t\t\t\"cache\": false,\n\t\t\t\"persistent\": true,\n\t\t\t\"outputLogs\": \"full\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "unocss.config.ts",
    "content": "import type { UserConfig } from 'unocss';\nimport { defineConfig, presetTypography, presetUno } from 'unocss';\n\nexport default defineConfig({\n\tcontent: {\n\t\tfilesystem: ['src/**/*.tsx', '../../packages/ui/src/lib/components/**/*.tsx'],\n\t},\n\ttheme: {\n\t\tcolors: {\n\t\t\tblurple: {\n\t\t\t\t50: '#e0e3ff',\n\t\t\t\t100: '#cdd2ff',\n\t\t\t\t200: '#9ea7ff',\n\t\t\t\t300: '#7782fa',\n\t\t\t\tDEFAULT: '#5865F2',\n\t\t\t\t500: '#3d48c3',\n\t\t\t\t600: '#293294',\n\t\t\t\t700: '#1a2165',\n\t\t\t\t800: '#0e1137',\n\t\t\t\t900: '#020208',\n\t\t\t},\n\t\t},\n\t\tfontFamily: {\n\t\t\tsans: 'var(--font-geist-sans)',\n\t\t\tmono: 'var(--font-geist-mono)',\n\t\t},\n\t},\n\tpresets: [\n\t\tpresetUno({ dark: 'class' }),\n\t\tpresetTypography({\n\t\t\tcssExtend: {\n\t\t\t\tpre: {\n\t\t\t\t\tpadding: '1em',\n\t\t\t\t\t'line-height': '1.5',\n\t\t\t\t\t'border-radius': '4px',\n\t\t\t\t},\n\t\t\t\tcode: {\n\t\t\t\t\t'font-size': '1em',\n\t\t\t\t\t'font-weight': 'unset',\n\t\t\t\t},\n\t\t\t\t':where(:not(pre) > code)::before': {\n\t\t\t\t\tcontent: '\"\"',\n\t\t\t\t},\n\t\t\t\t':where(:not(pre) > code)::after': {\n\t\t\t\t\tcontent: '\"\"',\n\t\t\t\t},\n\t\t\t\ta: {\n\t\t\t\t\tcolor: '#5865F2',\n\t\t\t\t\t'text-decoration': 'none',\n\t\t\t\t},\n\t\t\t\t'a > img': {\n\t\t\t\t\tdisplay: 'inline-block',\n\t\t\t\t},\n\t\t\t\t'a > img[height=\"44\"]': {\n\t\t\t\t\theight: '44px',\n\t\t\t\t},\n\t\t\t\t'div[align=\"center\"] > p > a + a': {\n\t\t\t\t\t'margin-left': '0.5em',\n\t\t\t\t},\n\t\t\t\th1: {\n\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t'place-items': 'center',\n\t\t\t\t\t'scroll-margin-top': '6.5rem',\n\t\t\t\t},\n\t\t\t\th2: {\n\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t'place-items': 'center',\n\t\t\t\t\t'margin-top': '1.25em',\n\t\t\t\t\t'scroll-margin-top': '6.5rem',\n\t\t\t\t},\n\t\t\t\th3: {\n\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t'place-items': 'center',\n\t\t\t\t\t'margin-top': '1.25em',\n\t\t\t\t\t'scroll-margin-top': '6.5rem',\n\t\t\t\t},\n\t\t\t\th4: {\n\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t'place-items': 'center',\n\t\t\t\t\t'margin-top': '1.25em',\n\t\t\t\t\t'scroll-margin-top': '6.5rem',\n\t\t\t\t},\n\t\t\t\t// eslint-disable-next-line id-length\n\t\t\t\tp: {\n\t\t\t\t\tmargin: '.5em 0',\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t],\n}) as UserConfig;\n"
  },
  {
    "path": "vitest.config.ts",
    "content": "import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n\ttest: {\n\t\texclude: ['**/node_modules', '**/dist', '.idea', '.git', '.cache'],\n\t\tpassWithNoTests: true,\n\t\ttypecheck: {\n\t\t\tenabled: true,\n\t\t\ttsconfig: './tsconfig.test.json',\n\t\t},\n\t\tcoverage: {\n\t\t\tenabled: true,\n\t\t\treporter: ['text', 'lcov', 'cobertura'],\n\t\t\tprovider: 'v8',\n\t\t\tinclude: ['src'],\n\t\t\texclude: [\n\t\t\t\t// All ts files that only contain types, due to ALL\n\t\t\t\t'**/*.{interface,type,d}.ts',\n\t\t\t\t'**/{interfaces,types}/*.ts',\n\t\t\t\t// All index files that *should* only contain exports from other files\n\t\t\t\t'**/index.{js,ts}',\n\t\t\t\t// All exports files that make subpackages available as submodules\n\t\t\t\t'**/exports/*.{js,ts}',\n\t\t\t],\n\t\t},\n\t},\n});\n"
  }
]