diff --git a/.eslintrc.json b/.eslintrc.json index 5c4b78f3bc..72754cc7d0 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,10 +1,13 @@ { - "extends": "marine/prettier/node", - "ignorePatterns": ["dist/*", "**/*.js"], - "parserOptions": { - "project": "./tsconfig.eslint.json" - }, - "rules": { - "no-eq-null": "off" - } + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint", "prettier"], + "rules": { + "prettier/prettier": "error" + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended" + ] } diff --git a/.github/ISSUE_TEMPLATE/app-subscriptions-bug-report.yml b/.github/ISSUE_TEMPLATE/app-subscriptions-bug-report.yml new file mode 100644 index 0000000000..8af1faa61c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/app-subscriptions-bug-report.yml @@ -0,0 +1,49 @@ +name: App Subscriptions Bug Report +description: A bug has been found in Discord's App Subscriptions. +labels: ["bug", "premium-apps"] +body: + - type: markdown + attributes: + value: "Before opening a new issue, please search existing issues: https://github.com/discord/discord-api-docs/issues?q=is%3Aissue+label%3A%22premium-apps%22" + - type: textarea + id: description + attributes: + label: Description + description: Provide a clear and concise description of what the problem is. + validations: + required: true + - type: textarea + id: steps + attributes: + label: Steps to Reproduce + description: Provide clear and concise steps for us to reliably reproduce this issue. + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected Behavior + description: What is the behavior you expect to occur that is not? + validations: + required: true + - type: textarea + id: current + attributes: + label: Current Behavior + description: What is the behavior you are currently seeing instead? + validations: + required: true + - type: textarea + id: screenshots + attributes: + label: Screenshots/Videos + description: Provide a screenshot and/or video demonstrating the issue being experienced. + validations: + required: false + - type: textarea + id: information + attributes: + label: Client and System Information + description: What is the browser/library/client you are using? What operating system and version? + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/developer-site-bug-report.yml b/.github/ISSUE_TEMPLATE/developer-site-bug-report.yml index 043a1d4c94..604576d393 100644 --- a/.github/ISSUE_TEMPLATE/developer-site-bug-report.yml +++ b/.github/ISSUE_TEMPLATE/developer-site-bug-report.yml @@ -1,10 +1,10 @@ name: Developer Site Bug Report description: A bug has been found with Discord's Developer site or documentation. -labels: ["bug"] +labels: ["bug", "developer portal"] body: - type: markdown attributes: - value: "Before opening a new issue, please search existing issues: https://github.com/discord/discord-api-docs/issues" + value: "Before opening a new issue, please search existing issues: https://github.com/discord/discord-api-docs/issues?q=is%3Aissue+label%3A%22developer+portal%22" - type: textarea id: description attributes: diff --git a/.github/ISSUE_TEMPLATE/message-components-bug-report.yml b/.github/ISSUE_TEMPLATE/message-components-bug-report.yml index d430cc53cd..d914ec9033 100644 --- a/.github/ISSUE_TEMPLATE/message-components-bug-report.yml +++ b/.github/ISSUE_TEMPLATE/message-components-bug-report.yml @@ -1,10 +1,10 @@ name: Message Components Bug Report description: A bug has been found in Discord's Message Components. -labels: ["message components"] +labels: ["bug", "message components"] body: - type: markdown attributes: - value: "Before opening a new issue, please search existing issues: https://github.com/discord/discord-api-docs/issues?q=is%3Aissue+label%3A%22message+components%22+" + value: "Before opening a new issue, please search existing issues: https://github.com/discord/discord-api-docs/issues?q=is%3Aissue+label%3A%22message+components%22" - type: textarea id: description attributes: diff --git a/.github/ISSUE_TEMPLATE/slash-command-bug-report.yml b/.github/ISSUE_TEMPLATE/slash-command-bug-report.yml index 555a7c22b8..5927d3acf7 100644 --- a/.github/ISSUE_TEMPLATE/slash-command-bug-report.yml +++ b/.github/ISSUE_TEMPLATE/slash-command-bug-report.yml @@ -1,10 +1,10 @@ name: Slash Commands Bug Report description: A bug has been found in Discord's Slash Commands and Interactions. -labels: ["slash commands"] +labels: ["bug", "slash commands"] body: - type: markdown attributes: - value: "Before opening a new issue, please search existing issues: https://github.com/discord/discord-api-docs/issues?q=is%3Aissue+label%3A%22slash+commands%22+" + value: "Before opening a new issue, please search existing issues: https://github.com/discord/discord-api-docs/issues?q=is%3Aissue+label%3A%22slash+commands%22" - type: textarea id: description attributes: diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5ace4600a1..56baa6b7d4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,3 +4,11 @@ updates: directory: "/" schedule: interval: "weekly" + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + ignore: + - dependency-name: "*" + update-types: + ["version-update:semver-patch", "version-update:semver-minor"] diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml new file mode 100644 index 0000000000..8ae77235f7 --- /dev/null +++ b/.github/workflows/docs.yaml @@ -0,0 +1,29 @@ +name: Verify Docs Formatting + +on: [push, pull_request] + +permissions: + contents: read + +jobs: + markdown_tables: + name: Check Markdown Tables + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Node v16 + uses: actions/setup-node@v3 + with: + node-version: 16 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Check Markdown Tables + run: | + shopt -s globstar + npx markdown-table-formatter docs/**/*.{md,mdx} --check + shell: bash \ No newline at end of file diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 3532280c1f..eaf4d9d4d1 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Node v16 uses: actions/setup-node@v3 @@ -30,7 +30,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Node v16 uses: actions/setup-node@v3 @@ -45,4 +45,4 @@ jobs: run: npm run build - name: Run Link Checks - run: npm run test:links + run: npm run test:links \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json index 246fdf0468..ebd6551687 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,15 +1,3 @@ { - "quoteProps": "consistent", - "endOfLine": "lf", - "printWidth": 120, - "useTabs": true, - "overrides": [ - { - "files": "*.md", - "options": { - "useTabs": false, - "tabWidth": 4 - } - } - ] + "printWidth": 120 } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6e03f498a5..5595d34a24 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,5 +12,6 @@ 1. Modifications to the overall structure and format of the API docs. 1. Additions that replicate or needlessly restructure current documentation. 1. Additions that document unreleased product functionality. +1. Changes that modify [Community Resources](https://discord.com/developers/docs/topics/community-resources#community-resources) (see [guidelines](https://github.com/discord/discord-api-docs/discussions/4456) for more detail). See the [README](https://github.com/discord/discord-api-docs/blob/main/README.md) for licensing and legal information. diff --git a/ci/checkLinks.ts b/ci/checkLinks.ts index 1f9a5fc74e..46b4a5357f 100644 --- a/ci/checkLinks.ts +++ b/ci/checkLinks.ts @@ -5,172 +5,172 @@ import * as github from "@actions/core"; const cwd = process.env.GITHUB_ACTIONS ? process.env.GITHUB_WORKSPACE! : process.cwd(); function importDirectory(directory: string, extensions: string[], subdirectories = true) { - try { - const output = new Map(); - const files = readdirSync(directory); - for (const fileOrPath of files) { - const currentPath = path.join(directory, fileOrPath); - if (statSync(currentPath).isDirectory()) { - if (!subdirectories) continue; - const subdir = importDirectory(currentPath, extensions, subdirectories); - if (!subdir) continue; - for (const [name, read] of subdir) { - output.set(`/${fileOrPath}${name}`, read); - } - continue; - } - const currentPathParts = path.parse(currentPath); - if (!extensions.some((ex) => ex === currentPathParts.ext)) continue; - const read = readFileSync(currentPath, "utf8"); - output.set(`/${currentPathParts.name}`, read); - } - return output; - } catch { - // Directory likely does not exist, we should be able to safely discard this error - return null; - } + try { + const output = new Map(); + const files = readdirSync(directory); + for (const fileOrPath of files) { + const currentPath = path.join(directory, fileOrPath); + if (statSync(currentPath).isDirectory()) { + if (!subdirectories) continue; + const subdir = importDirectory(currentPath, extensions, subdirectories); + if (!subdir) continue; + for (const [name, read] of subdir) { + output.set(`/${fileOrPath}${name}`, read); + } + continue; + } + const currentPathParts = path.parse(currentPath); + if (!extensions.some((ex) => ex === currentPathParts.ext)) continue; + const read = readFileSync(currentPath, "utf8"); + output.set(`/${currentPathParts.name}`, read); + } + return output; + } catch { + // Directory likely does not exist, we should be able to safely discard this error + return null; + } } function printResults(resultMap: Map): void { - let output = "\n"; - let total = 0; - for (const [resultFile, resultArr] of resultMap) { - if (resultArr.length <= 0) continue; - const filePath = path.join(cwd, resultFile); - output += `${chalk.underline(filePath)}\n`; - output += resultArr.reduce((result, props) => { - total += 1; - return `${result} ${props.startLine ?? ""}:${props.startColumn ?? ""}-${props.endColumn ?? ""} ${chalk.yellow( - "warning" - )} ${props.title ?? ""}\n`; - }, ""); - output += "\n"; - } - output += "\n"; - if (total > 0) { - output += chalk.red.bold(`\u2716 ${total} problem${total === 1 ? "" : "s"}\n`); - } - console.log(output); + let output = "\n"; + let total = 0; + for (const [resultFile, resultArr] of resultMap) { + if (resultArr.length <= 0) continue; + const filePath = path.join(cwd, resultFile); + output += `${chalk.underline(filePath)}\n`; + output += resultArr.reduce((result, props) => { + total += 1; + return `${result} ${props.startLine ?? ""}:${props.startColumn ?? ""}-${props.endColumn ?? ""} ${chalk.yellow( + "warning", + )} ${props.title ?? ""}\n`; + }, ""); + output += "\n"; + } + output += "\n"; + if (total > 0) { + output += chalk.red.bold(`\u2716 ${total} problem${total === 1 ? "" : "s"}\n`); + } + console.log(output); } function annotateResults(resultMap: Map): void { - let total = 0; - for (const [resultFile, resultArr] of resultMap) { - if (resultArr.length <= 0) continue; - github.startGroup(resultFile); - for (const result of resultArr) { - total += 1; - console.log( - `::warning file=${resultFile},title=Invalid Link,line=${result.startLine ?? 0},endLine=${ - result.startLine ?? 0 - },col=${result.startColumn ?? 0},endColumn=${result.endColumn ?? result.startColumn ?? 0}::${ - result.title ?? "Invalid Link" - }` - ); - } - github.endGroup(); - } - if (total > 0) { - github.setFailed("One or more links are invalid!"); - } + let total = 0; + for (const [resultFile, resultArr] of resultMap) { + if (resultArr.length <= 0) continue; + github.startGroup(resultFile); + for (const result of resultArr) { + total += 1; + console.log( + `::warning file=${resultFile},title=Invalid Link,line=${result.startLine ?? 0},endLine=${ + result.startLine ?? 0 + },col=${result.startColumn ?? 0},endColumn=${result.endColumn ?? result.startColumn ?? 0}::${ + result.title ?? "Invalid Link" + }`, + ); + } + github.endGroup(); + } + if (total > 0) { + github.setFailed("One or more links are invalid!"); + } } const docFiles = importDirectory(path.join(cwd, "docs"), [".md", ".mdx"]); if (!docFiles) { - console.error("No doc files found!"); - process.exit(1); + console.error("No doc files found!"); + process.exit(1); } const validLinks = new Map([ - ["APPLICATIONS", []], - ["SERVERS", []], - ["TEAMS", []], + ["APPLICATIONS", []], + ["SERVERS", []], + ["TEAMS", []], ]); // Gather valid links for (const [name, raw] of docFiles) { - const keyName = `DOCS${name.replaceAll("/", "_").toUpperCase()}`; - if (!validLinks.has(keyName)) { - validLinks.set(keyName, []); - } - const validAnchors = validLinks.get(keyName)!; + const keyName = `DOCS${name.replaceAll("/", "_").toUpperCase()}`; + if (!validLinks.has(keyName)) { + validLinks.set(keyName, []); + } + const validAnchors = validLinks.get(keyName)!; - let parentAnchor = ""; - let multilineCode = false; - for (const line of raw.split("\n")) { - if (line.trim().startsWith("```")) { - multilineCode = !multilineCode; - if (line.trim().length > 3 && line.trim().endsWith("```")) multilineCode = !multilineCode; - } - if (multilineCode || !line.startsWith("#")) continue; - const anchor = line - .split("%")[0] - .replace(/[^ A-Z0-9]/gi, "") - .trim() - .replace(/ +/g, "-") - .toLowerCase(); - if (/^#{1,5}(?!#)/.test(line.trim())) { - parentAnchor = `${anchor}-`; - validAnchors.push(anchor); - continue; - } - validAnchors.push(`${parentAnchor}${anchor}`); - } + let parentAnchor = ""; + let multilineCode = false; + for (const line of raw.split("\n")) { + if (line.trim().startsWith("```")) { + multilineCode = !multilineCode; + if (line.trim().length > 3 && line.trim().endsWith("```")) multilineCode = !multilineCode; + } + if (multilineCode || !line.startsWith("#")) continue; + const anchor = line + .split("%")[0] + .replace(/[^ A-Z0-9]/gi, "") + .trim() + .replace(/ +/g, "-") + .toLowerCase(); + if (/^#{1,5}(?!#)/.test(line.trim())) { + parentAnchor = `${anchor}-`; + validAnchors.push(anchor); + continue; + } + validAnchors.push(`${parentAnchor}${anchor}`); + } } const results = new Map(); // Check Links for (const [name, raw] of docFiles) { - const fileName = `docs${name}`; - const file = raw.split("\n"); - if (!results.has(fileName)) { - results.set(fileName, []); - } - const ownResults = results.get(fileName)!; - let multilineCode = false; - file.forEach((line, lineNum) => { - if (line.trim().startsWith("```")) { - multilineCode = !multilineCode; - if (line.trim().length > 3 && line.trim().endsWith("```")) multilineCode = !multilineCode; - } - if (multilineCode) return; - const matches = line.matchAll(/(? { + if (line.trim().startsWith("```")) { + multilineCode = !multilineCode; + if (line.trim().length > 3 && line.trim().endsWith("```")) multilineCode = !multilineCode; + } + if (multilineCode) return; + const matches = line.matchAll(/(? a.includes(anchor)); - const suggestionText = suggestions.length > 0 ? ` Did you mean one of (${suggestions.join(", ")})?` : ""; - ownResults.push({ - title: `Anchor ${chalk.cyan(anchor)} does not exist on ${chalk.blueBright(page)}${suggestionText}`, - startLine: lineNum + 1, - startColumn: match.index, - endColumn: (match.index ?? 0) + match[0].length, - }); - } - } - }); + if (!anchor) continue; + if (!validLinks.get(page)!.includes(anchor)) { + const suggestions = validLinks.get(page)!.filter((a) => a.includes(anchor)); + const suggestionText = suggestions.length > 0 ? ` Did you mean one of (${suggestions.join(", ")})?` : ""; + ownResults.push({ + title: `Anchor ${chalk.cyan(anchor)} does not exist on ${chalk.blueBright(page)}${suggestionText}`, + startLine: lineNum + 1, + startColumn: match.index, + endColumn: (match.index ?? 0) + match[0].length, + }); + } + } + }); } if (results.size > 0) { - if (process.env.GITHUB_ACTIONS) { - annotateResults(results); - } else { - printResults(results); - } + if (process.env.GITHUB_ACTIONS) { + annotateResults(results); + } else { + printResults(results); + } } diff --git a/docs/Change_Log.md b/docs/Change_Log.md index 44763856e6..9452ee8f69 100644 --- a/docs/Change_Log.md +++ b/docs/Change_Log.md @@ -1,5 +1,69 @@ # Change Log +## Premium App Subscriptions Available in the US +#### Sep 26, 2023 + +Starting today, eligible US-based developers can monetize their verified apps with App Subscriptions. [App Subscriptions](#DOCS_MONETIZATION_OVERVIEW) let you to charge your users for premium functionality with a recurring, monthly subscription. + +- Manage subscription SKUs in the Developer Portal +- View monetization analytics in the Developer Portal +- Team owners can setup and manage payouts in Developer Portal +- New endpoints for working with [SKUs](#DOCS_MONETIZATION_SKUS) and [Entitlements](#DOCS_MONETIZATION_ENTITLEMENTS): + - [List SKUs](#DOCS_MONETIZATION_SKUS/list-skus) `GET /applications//skus` + - [List Entitlements](#DOCS_MONETIZATION_ENTITLEMENTS/list-entitlements) `GET /applications//entitlements` + - [Create Test Entitlement](#DOCS_MONETIZATION_ENTITLEMENTS/create-test-entitlement) `POST /applications//entitlements` + - [Delete Test Entitlement](#DOCS_MONETIZATION_ENTITLEMENTS/delete-test-entitlement) `DELETE /applications//entitlements/` +- [Gateway Events](#DOCS_MONETIZATION_ENTITLEMENTS/gateway-events) for working with entitlements: `ENTITLEMENT_CREATE`, `ENTITLEMENT_UPDATE`, `ENTITLEMENT_DELETE` +- New [`PREMIUM_REQUIRED (10)` interaction response type](#DOCS_MONETIZATION_ENTITLEMENTS/premiumrequired-interaction-response) is available to prompt users to upgrade +- New `entitlements` field, which is an array of [entitlement](#DOCS_MONETIZATION_ENTITLEMENTS/) objects, available in interaction data payloads when [receiving and responding to interactions](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-structure) + +To learn more about eligibility details and how to enable monetization for your app, check out the [Monetization Overview](#DOCS_MONETIZATION_OVERVIEW). + +## Default Value in Auto-populated Select Menus + +#### Sep 22, 2023 + +A new `default_values` field was added for user (`5`), role (`6`), mentionable (`7`), and channel (`8`) [select menu components](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menus). `default_values` is a list of [default value objects](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-default-value-structure), which each include an `id` (the snowflake value for the resource), as well as a corresponding `type` (either `"user"`, `"role"`, or `"channel"`). + +## Team Member Roles + +#### Aug 23, 2023 + +You can now select roles other than admin when inviting users or configuring members of a team. There are four [role types](#DOCS_TOPICS_TEAMS/team-member-roles-team-member-role-types) that a team member can be assigned: owner, admin, developer, or read-only. The team member object now has an additional [`role` field](#DOCS_TOPICS_TEAMS/data-models-team-member-object), which is a string representing the member's current role. + +Details about team member roles are in the updated [Teams documentation](#DOCS_TOPICS_TEAMS/team-member-roles). + +## Embed Debugger + +#### Aug 10, 2023 + +We've released a new [Embed Debugger tool](https://discord.com/developers/embeds) that shows you how a URL's metadata will be parsed and rendered as a link embed within the Discord client. Use it to preview your site's embed, or debug why your site's link embed isn't working as expected. + +## Activity State for Bot Users + +#### Aug 8, 2023 + +The `state` field in [activity objects](#DOCS_TOPICS_GATEWAY_EVENTS/activity-object) can now be set when [updating presence](#DOCS_TOPICS_GATEWAY_EVENTS/update-presence) for a bot user. The value of `state` will appear as a custom status for the bot user when an [activity's `type`](#DOCS_TOPICS_GATEWAY_EVENTS/activity-object-activity-types) is set to `4`, or as additional data under an activity's name for other activity types. + +## Public Preview of OpenAPI 3.1 Specification + +#### Aug 2, 2023 + +We're introducing an [OpenAPI 3.1 spec](https://github.com/discord/discord-api-spec) in public preview to make it easier and more reliable to develop with the HTTP API. While our current developer documentation requires manual reviews and updates, the OpenAPI spec is generated from the source code which means it better reflects the nooks, crannies, and nuances of the Discord API. + +> warn +> The public preview of the OpenAPI spec is subject to breaking changes without advance notice, and should not be used within production environments. If you see something that looks incorrect or can be improved, you can [open an issue](https://github.com/discord/discord-api-spec/issues). + +The public spec can be found in the new [`discord-api-spec` repository on GitHub](https://github.com/discord/discord-api-spec). + +## New GUILD_MEDIA channel type + +#### Aug 1, 2023 + +- Add the [`GUILD_MEDIA` (16) channel type](#DOCS_RESOURCES_CHANNEL/channel-object-channel-types). `GUILD_MEDIA` channels only support threads, similar to `GUILD_FORUM` channels. + +Read the [media channel topic](#DOCS_TOPICS_THREADS/media-channels) for more information on the relevant APIs and technical details, or the [media channel Help Center Article](https://creator-support.discord.com/hc/en-us/articles/14346342766743) for more about the feature. + ## Add Join Raid and Mention Raid fields #### May 05, 2023 @@ -19,7 +83,7 @@ Discord’s username system is changing. Discriminators are being removed and ne This changelog focuses only on the technical changes to be aware of to update your app's code. ### Identifying migrated users - + The new username system will rollout to users over time rather than all at once. The value of a single zero (`"0"`) in the [`discriminator` field](#DOCS_RESOURCES_USER/user-object-user-structure) on a user will indicate that the user has been migrated to the new username system. Note that the discriminator for migrated users will *not* be 4-digits like a standard discriminator (it is `"0"`, not `"0000"`). The value of the `username` field will become the migrated user's unique username. After migration of all users is complete, the `discriminator` field may be removed. @@ -132,7 +196,7 @@ Introducing [linked roles](https://discord.com/blog/connected-accounts-functiona - [Application metadata](#DOCS_RESOURCES_APPLICATION_ROLE_CONNECTION_METADATA/application-role-connection-metadata-object) to specify more detailed linked role requirements. - New endpoints to [retrieve](#DOCS_RESOURCES_APPLICATION_ROLE_CONNECTION_METADATA/get-application-role-connection-metadata-records) (`GET /applications//role-connections/metadata`) and [update](#DOCS_RESOURCES_APPLICATION_ROLE_CONNECTION_METADATA/update-application-role-connection-metadata-records) (`PUT /applications//role-connections/metadata`) application connection metadata. - New [`role_connections.write`](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) OAuth2 scope required to authenticate the below requests. -- Endpoints to [retrieve](#DOCS_RESOURCES_USER/get-user-application-role-connection) (`GET /users/@me/applications/{application.id}/role-connection`) and [update](#DOCS_RESOURCES_USER/update-user-application-role-connection) (`PUT /users/@me/applications/{application.id}/role-connection`) a user's role connections, both of which return an [application role connection](#DOCS_RESOURCES_USER/application-role-connection-object) object. +- Endpoints to [retrieve](#DOCS_RESOURCES_USER/get-current-user-application-role-connection) (`GET /users/@me/applications/{application.id}/role-connection`) and [update](#DOCS_RESOURCES_USER/update-current-user-application-role-connection) (`PUT /users/@me/applications/{application.id}/role-connection`) a user's role connections, both of which return an [application role connection](#DOCS_RESOURCES_USER/application-role-connection-object) object. > info > For a quick rundown on how to get started using linked roles, refer to the [tutorial](#DOCS_TUTORIALS_CONFIGURING_APP_METADATA_FOR_LINKED_ROLES). @@ -152,7 +216,7 @@ Introducing [linked roles](https://discord.com/blog/connected-accounts-functiona > danger > This entry includes breaking changes -Based on feedback, we’re updating permissions for [application commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS) to simplify permission management and to make command permissions more closely resemble other permissions systems in Discord. +Based on feedback, we’re updating permissions for [application commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS) to simplify permission management and to make command permissions more closely resemble other permissions systems in Discord. Server admins can begin to opt-in to the command permission changes outlined here on a per-server basis **starting on December 16, 2022**. However, changes will not be applied to all servers **until late January or early February**. @@ -492,7 +556,7 @@ In API v10, the `MESSAGE_CONTENT` (`1 << 15`) intent is now required to receive #### Jun 17, 2022 -The `$` prefix in [identify connection properties](#DOCS_TOPICS_GATEWAY_EVENTS/identify-identify-connection-properties) are deprecated. The new field names are `os`, `browser`, and `device`. When passed, the `$`-prefixed names will resolve to the new ones. +The `$` prefix in [identify connection properties](#DOCS_TOPICS_GATEWAY_EVENTS/identify-identify-connection-properties) are deprecated. The new field names are `os`, `browser`, and `device`. When passed, the `$`-prefixed names will resolve to the new ones. In API v11, support for the previous field names (`$os`, `$browser`, and `$device`) will be removed. @@ -873,7 +937,7 @@ Get the latest at the top of the [Getting Started](#DOCS_GAME_SDK_SDK_STARTER_GU #### August 22, 2019 -News Channels are now changed to [Announcement Channels](#DOCS_GAME_AND_SERVER_MANAGEMENT_SPECIAL_CHANNELS/announcement-channels). Developer License owners will continue to get access to them (both existing and new). Underlying channel type (GUILD_NEWS = 5) remains the same. +News Channels are now changed to Announcement Channels. Developer License owners will continue to get access to them (both existing and new). Underlying channel type (GUILD_NEWS = 5) remains the same. ## More Precise Rate Limits diff --git a/docs/Getting_Started.mdx b/docs/Getting_Started.mdx index 18425b34b0..f08ff61f58 100644 --- a/docs/Getting_Started.mdx +++ b/docs/Getting_Started.mdx @@ -1,3 +1,5 @@ + + # Building your first Discord app Discord apps let you customize and extend your servers using a collection of APIs and interactive features. This guide will walk you through building your first Discord app using JavaScript, and by the end you'll have an app that uses slash commands, sends messages, and responds to component interactions. @@ -78,9 +80,9 @@ Click on **OAuth2** in the left sidebar, then select **URL generator**. > info > The URL generator creates an installation link based on the scopes and permissions you select for your app. You can use the link to install the app onto your own server, or share it with others so they can install it. -For now, add two scopes: -- `applications.commands` which allows your app to create [commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS). -- `bot` adds your bot user. After you select `bot`, you can also select different permissions for your bot. For now, just check **Send Messages**. +For now, just add the **`bot` scope**, which adds your bot user. + +After you select `bot`, you can also select different permissions for your bot. For now, just check **Send Messages**. See a list of all [OAuth2 scopes](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes), or read more on [permissions](#DOCS_TOPICS_PERMISSIONS) in the documentation. @@ -394,7 +396,6 @@ const componentId = data.custom_id; await res.send({ type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, data: { - // Fetches a random emoji to send from a helper function content: 'What is your object of choice?', // Indicates it'll be an ephemeral message flags: InteractionResponseFlags.EPHEMERAL, diff --git a/docs/Reference.md b/docs/Reference.md index e65d27dd5c..120a08900f 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -17,16 +17,16 @@ Discord exposes different versions of our API[.](https://c.tenor.com/BuZl66Eegkg ###### API Versions -| Version | Status | Default | -| ------- | -------------------------------- | ------- | -| 10 | Available | | -| 9 | Available | | -| 8 | Deprecated | | -| 7 | Deprecated | | -| 6 | Deprecated | ✓ | -| 5 | Discontinued | | -| 4 | Discontinued | | -| 3 | Discontinued | | +| Version | Status | Default | +|---------|--------------|---------| +| 10 | Available | | +| 9 | Available | | +| 8 | Deprecated | | +| 7 | Deprecated | | +| 6 | Deprecated | ✓ | +| 5 | Discontinued | | +| 4 | Discontinued | | +| 3 | Discontinued | | ## Error Messages @@ -138,7 +138,7 @@ Discord utilizes Twitter's [snowflake](https://github.com/twitter-archive/snowfl ###### Snowflake ID Format Structure (Left to Right) | Field | Bits | Number of bits | Description | Retrieval | -| ------------------- | -------- | -------------- | ---------------------------------------------------------------------------- | ----------------------------------- | +|---------------------|----------|----------------|------------------------------------------------------------------------------|-------------------------------------| | Timestamp | 63 to 22 | 42 bits | Milliseconds since Discord Epoch, the first second of 2015 or 1420070400000. | `(snowflake >> 22) + 1420070400000` | | Internal worker ID | 21 to 17 | 5 bits | | `(snowflake & 0x3E0000) >> 17` | | Internal process ID | 16 to 12 | 5 bits | | `(snowflake & 0x1F000) >> 12` | @@ -203,7 +203,7 @@ Resource fields that are optional have names that are suffixed with a question m ###### Example Nullable and Optional Fields | Field | Type | -| ---------------------------- | ------- | +|------------------------------|---------| | optional_field? | string | | nullable_field | ?string | | optional_and_nullable_field? | ?string | @@ -253,18 +253,19 @@ Discord utilizes a subset of markdown for rendering message content on its clien ###### Formats -| Type | Structure | Example | -| ------------------------ | ------------------- | ----------------------------- | -| User | <@USER_ID> | <@80351110224678912> | -| User \* | <@!USER_ID> | <@!80351110224678912> | -| Channel | <#CHANNEL_ID> | <#103735883630395392> | -| Role | <@&ROLE_ID> | <@&165511591545143296> | -| Slash Command \*\* | | | -| Standard Emoji | Unicode Characters | 💯 | -| Custom Emoji | <:NAME:ID> | <:mmLol:216154654256398347> | -| Custom Emoji (Animated) | | | -| Unix Timestamp | | | -| Unix Timestamp (Styled) | | | +| Type | Structure | Example | +|-------------------------|---------------------|-------------------------------| +| User | <@USER_ID> | <@80351110224678912> | +| User \* | <@!USER_ID> | <@!80351110224678912> | +| Channel | <#CHANNEL_ID> | <#103735883630395392> | +| Role | <@&ROLE_ID> | <@&165511591545143296> | +| Slash Command \*\* | | | +| Standard Emoji | Unicode Characters | 💯 | +| Custom Emoji | <:NAME:ID> | <:mmLol:216154654256398347> | +| Custom Emoji (Animated) | | | +| Unix Timestamp | | | +| Unix Timestamp (Styled) | | | +| Guild Navigation | \ | \ | Using the markdown for either users, roles, or channels will usually mention the target(s) accordingly, but this can be suppressed using the `allowed_mentions` parameter when creating a message. Standard emoji are currently rendered using [Twemoji](https://twemoji.twitter.com/) for Desktop/Android and Apple's native emoji on iOS. @@ -277,7 +278,7 @@ Timestamps are expressed in seconds and display the given timestamp in the user' ###### Timestamp Styles | Style | Example Output | Description | -| ----- | ---------------------------- | --------------- | +|-------|------------------------------|-----------------| | t | 16:20 | Short Time | | T | 16:20:30 | Long Time | | d | 20/04/2021 | Short Date | @@ -288,6 +289,16 @@ Timestamps are expressed in seconds and display the given timestamp in the user' \*default +###### Guild Navigation Types + +Guild navigation types link to the corresponding resource in the current server. + +| Type | Description | +|-----------|-------------------------------------------------------------------------------------------------------| +| customize | _Customize_ tab with the server's [onboarding prompts](#DOCS_RESOURCES_GUILD/guild-onboarding-object) | +| browse | _Browse Channels_ tab | +| guide | [Server Guide](https://support.discord.com/hc/en-us/articles/13497665141655) | + ## Image Formatting ###### Image Base Url @@ -301,7 +312,7 @@ Discord uses ids and hashes to render images in the client. These hashes can be ###### Image Formats | Name | Extension | -| ------ | ----------- | +|--------|-------------| | JPEG | .jpg, .jpeg | | PNG | .png | | WebP | .webp | @@ -311,14 +322,14 @@ Discord uses ids and hashes to render images in the client. These hashes can be ###### CDN Endpoints | Type | Path | Supports | -| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | +|-----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------| | Custom Emoji | emojis/[emoji_id](#DOCS_RESOURCES_EMOJI/emoji-object).png | PNG, JPEG, WebP, GIF | | Guild Icon | icons/[guild_id](#DOCS_RESOURCES_GUILD/guild-object)/[guild_icon](#DOCS_RESOURCES_GUILD/guild-object).png \* | PNG, JPEG, WebP, GIF | | Guild Splash | splashes/[guild_id](#DOCS_RESOURCES_GUILD/guild-object)/[guild_splash](#DOCS_RESOURCES_GUILD/guild-object).png | PNG, JPEG, WebP | | Guild Discovery Splash | discovery-splashes/[guild_id](#DOCS_RESOURCES_GUILD/guild-object)/[guild_discovery_splash](#DOCS_RESOURCES_GUILD/guild-object).png | PNG, JPEG, WebP | | Guild Banner | banners/[guild_id](#DOCS_RESOURCES_GUILD/guild-object)/[guild_banner](#DOCS_RESOURCES_GUILD/guild-object).png \* | PNG, JPEG, WebP, GIF | | User Banner | banners/[user_id](#DOCS_RESOURCES_USER/user-object)/[user_banner](#DOCS_RESOURCES_USER/user-object).png \* | PNG, JPEG, WebP, GIF | -| Default User Avatar | embed/avatars/[index](#DOCS_RESOURCES_USER/user-object).png \*\* \*\*\* | PNG | +| Default User Avatar | embed/avatars/[index](#DOCS_RESOURCES_USER/user-object).png \*\* \*\*\* | PNG | | User Avatar | avatars/[user_id](#DOCS_RESOURCES_USER/user-object)/[user_avatar](#DOCS_RESOURCES_USER/user-object).png \* | PNG, JPEG, WebP, GIF | | Guild Member Avatar | guilds/[guild_id](#DOCS_RESOURCES_GUILD/guild-object)/users/[user_id](#DOCS_RESOURCES_USER/user-object)/avatars/[member_avatar](#DOCS_RESOURCES_GUILD/guild-member-object).png \* | PNG, JPEG, WebP, GIF | | User Avatar Decoration | avatar-decorations/[user_id](#DOCS_RESOURCES_USER/user-object)/[user_avatar_decoration](#DOCS_RESOURCES_USER/user-object).png | PNG | @@ -326,7 +337,7 @@ Discord uses ids and hashes to render images in the client. These hashes can be | Application Cover | app-icons/[application_id](#DOCS_RESOURCES_APPLICATION/application-object)/[cover_image](#DOCS_RESOURCES_APPLICATION/application-object).png | PNG, JPEG, WebP | | Application Asset | app-assets/[application_id](#DOCS_RESOURCES_APPLICATION/application-object)/[asset_id](#DOCS_TOPICS_GATEWAY_EVENTS/activity-object-activity-assets).png | PNG, JPEG, WebP | | Achievement Icon | app-assets/[application_id](#DOCS_RESOURCES_APPLICATION/application-object)/achievements/[achievement_id](#DOCS_GAME_SDK_ACHIEVEMENTS/data-models-user-achievement-struct)/icons/[icon_hash](#DOCS_GAME_SDK_ACHIEVEMENTS/data-models-user-achievement-struct).png | PNG, JPEG, WebP | -| Store Page Asset | app-assets/[application_id](#DOCS_RESOURCES_APPLICATION/application-object)/store/asset_id | PNG, JPEG, WebP | +| Store Page Asset | app-assets/[application_id](#DOCS_RESOURCES_APPLICATION/application-object)/store/asset_id | PNG, JPEG, WebP | | Sticker Pack Banner | app-assets/710982414301790216/store/[sticker_pack_banner_asset_id](#DOCS_RESOURCES_STICKER/sticker-pack-object).png | PNG, JPEG, WebP | | Team Icon | team-icons/[team_id](#DOCS_TOPICS_TEAMS/data-models-team-object)/[team_icon](#DOCS_TOPICS_TEAMS/data-models-team-object).png | PNG, JPEG, WebP | | Sticker | stickers/[sticker_id](#DOCS_RESOURCES_STICKER/sticker-object).png \*\*\* \*\*\*\* | PNG, Lottie, GIF | @@ -454,7 +465,7 @@ For example: ## Locales | Locale | Language Name | Native Name | -| ------ | --------------------- | ------------------- | +|--------|-----------------------|---------------------| | id | Indonesian | Bahasa Indonesia | | da | Danish | Dansk | | de | German | Deutsch | @@ -480,9 +491,9 @@ For example: | bg | Bulgarian | български | | ru | Russian | Pусский | | uk | Ukrainian | Українська | -| hi | Hindi | हिन्दी | +| hi | Hindi | हिन्दी | | th | Thai | ไทย | | zh-CN | Chinese, China | 中文 | | ja | Japanese | 日本語 | | zh-TW | Chinese, Taiwan | 繁體中文 | -| ko | Korean | 한국어 | +| ko | Korean | 한국어 | diff --git a/docs/da/Getting_Started.mdx b/docs/da/Getting_Started.mdx new file mode 100644 index 0000000000..e947b6f4ab --- /dev/null +++ b/docs/da/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# Sådan udvikler du din første Discord-app + +Discord-apps lader dig tilpasse og udvide dine servere med en samling af APIs og interaktive funktioner. Denne vejledning tager dig gennem processen at udvikle din første Discord-app i JavaScript. Når du er færdig, vil du have en app, der bruger slash-kommandoer, sender beskeder og reagerer på interaktion med komponenterne. + +Vi vil udvikle en Discord-app, der lader servermedlemmerne spille sten-saks-papir (med syv valgmuligheder i stedet for de sædvanlige tre). Denne vejledning er målrettet nybegyndere, men den antager et basalt kendskab til [JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics). + + +Her kan du se, hvordan den færdige app vil se ud: + +![Demo af app-eksempel](getting-started-demo.gif) + +Lad os gøre brugerrejsen lidt mere tydelig: + +1. Bruger 1 starter et nyt spil og vælger deres genstand med appens `/challenge` slash-kommando +2. En besked bliver sendt til kanalen med en knap, så andre kan acceptere udfordringen +3. Bruger 2 trykker på knappen **Acceptér** +4. Bruger 2 modtager en kortvarig besked, hvorfra vedkommende skal vælge sin genstand +5. Resultatet af spillet bliver delt i den oprindelige kanal, hvor alle kan se det + + + +- **[GitHub repository](https://github.com/discord/discord-example-app)**, hvor koden fra denne vejledning bor sammen med nogle ekstra funktionsspecifikke kodeeksempler. +- **[discord-interactions](https://github.com/discord/discord-interactions-js)**, et bibliotek med typer og hjælpefunktioner til Discord-apps. +- **[Express](https://expressjs.com)**, et populært JavaScript-web framework vi bruger til at oprette en server, hvor Discord kan sende os anmodninger. +- **[Glitch](https://glitch.com/)**, et online miljø, der simplificerer udviklingen og hostingen af apps i de tidlige prototype- og udviklingsfaser. Du kan ogås udvikle lokalt med et værktøj som **[ngrok](https://ngrok.com/)**. + + +--- + +## Step 1: Skab en app + +Først skal du skabe en app i udviklerportalen, hvis du ikke allerede har en: + + + +Navngiv din app, og tryk på **Skab**. + +Når du har skabt din app, lander du på siden **Generel oversigt** i appens indstillinger, hvor du kan opdatere grundlæggende information om din app såsom beskrivelse og ikon. Du kan også se et **applikations-ID** og en **URL for slutpunkt for interaktioner**, som vi skal bruge lidt senere i denne vejledning. + +### Konfigurering af din bot + +Derefter konfigurerer vi [bot-brugeren](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts) for din app, så den kan se ud som og opføre sig ligesom andre medlemmer af serveren. + +I sidepanelet til venstre skal du klikke på **Bot**. På denne side kan du konfigurere indstillinger som dens [priviligerede intentioner](#DOCS_TOPICS_GATEWAY/privileged-intents), eller om den kan installeres af andre brugere. + + +Intentioner bestemmer, hvilke hændelser Discord sender din app til, når du laver en [Gateway API-forbindelse](#DOCS_TOPICS_GATEWAY). Hvis du eksempelvis vil have din app til at gøre noget, når brugere føjer en reaktion til en besked, kan du sende `GUILD_MESSAGE_REACTIONS` (`1 << 10`)-intentionen. + +Nogle intentioner er [privilegerede](#DOCS_TOPICS_GATEWAY/privileged-intents), hvilket betyder, at de lader din app tilgå data, der kan være følsomme (såsom indholdet af beskeder). Privilegerede intentioner findes og kan styres på siden **Bot** i din apps indstillinger. Standard, ikke-privilegerede intentioner kræver ingen yderligere tilladelser eller konfigurationer. + +Du finder mere information om intentioner sammen med en liste over alle intentioner, inkl. deres tilknyttede hændelser i [Gateway-dokumentationen](#DOCS_TOPICS_GATEWAY/gateway-intents). + + +![Bot-fanen i appens indstillinger](app-add-bot.png) + +Der er også en **Token**-sektion på siden **Bot**, der lader dig kopiere og nulstille din bots token. + +Bot-tokens bruges til at godkende API-anmodninger og bære din bot-brugers tilladelser, hvilket gør dem *meget følsomme*. Sørg for *ikke* at dele din token eller bruge den til nogen form for versionskontrol. + +Kopier nu din token, og gem den et sikkert sted (såsom i en administrator af adgangskoder). + +> warn +> Du vil ikke kunne se din token igen, medmindre du regenererer den, så sørg for at opbevare den et sikkert sted. + +### Tilføjelse af anvendelsesområder og bot-tilladelser + +Apps skal bruge godkendelse fra den installerende bruger for at udføre handlinger i Discord (såsom at lave en slash-kommando eller hente en liste over servermedlemmer). Lad os vælge et par anvendelsesområder og tilladelser, der skal anmodes om, inden appen bliver installeret. + + +Når du laver en app, bestemmer anvendelsesområder og tilladelser, hvad din app kan gøre og få tilgang til på Discord-servere. + +- [OAuth2-anvendelsesområder](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) bestemmer, hvilken dataadgang og hvilke handlinger din app har adgang til, tildelt på vegne af en installerende eller bekræftende bruger. +- [Tilladelser](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) er din bot-brugers detaljerede tilladelser, ligesom andre brugere på Discord også har. De kan godkendes af den installerende bruger eller senere opdateres under serverens indstillinger eller med [overskrivninger af tilladelser](#DOCS_TOPICS_PERMISSIONS/permission-overwrites). + + +Klik på **OAuth2** i venstre sidepanel, og vælg **URL-generator**. + +> info +> URL-generatoren skaber et installationslink baseret på de anvendelsesområder og tilladelser, du har valgt for din app. Du kan bruge linket til at installere appen på din egen server eller dele det med andre, så de kan installere den. + +Lige nu skal du tilføje to anvendelsesområder: +- `applications.commands`, der lader din app skabe [kommandoer](#DOCS_INTERACTIONS_APPLICATION_COMMANDS). +- `bot`, der tilføjer din bot-bruger. Når du har valgt `bot`, kan du også vælge forskellige tilladelse til din bot. Lige nu skal du bare afkrydse **Send meddelelser**. + +Se en liste med alle [OAuth2-anvendelsesområder](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes), eller læs mere om [tilladelser](#DOCS_TOPICS_PERMISSIONS) i dokumentationen. + +### Installation af din app + +Når du har tilføjet anvendelsesområder, burde du se en URL, som du kan kopiere og bruge til at installere din app. + +![Screenshot af URL-generator](url-generator.png) + +> info +> Når du udvikler apps, bør du bygge og teste dem på en server, der ikke bruges aktivt af andre. Hvis du ikke har din egen server allerede, kan du [oprette en gratis](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server-). + +Kopiér den førnævnte URL, og indsæt den i din browser. Du bliver ført gennem installationsprocessen, hvor du skal sikre, at du installerer din app på en server, hvor du kan udvikle på den og teste den. + +Når du har installeret din app, kan du gå til din server og se, at den har tilsluttet sig ✨ + +Nu da din app er konfigureret og installeret, kan vi begynde at udvikle på den. + +--- + +## Trin 2: Kør din app + +Al koden brugt i app-eksemplet kan findes i [GitHub repository](https://github.com/discord/discord-example-app). + +For at gøre det lidt nemmere at udvikle appen, bruger den [Discord-interaktioner](https://github.com/discord/discord-interactions-js), der leverer typer og hjælpefunktioner. Hvis du foretrækker at anvende andre sprog eller biblioteker, skal du se dokumentationen om [Community-ressourcer](#DOCS_TOPICS_COMMUNITY_RESOURCES). + +### Remix af projektet + +Denne vejledning bruger Glitch, der lader dig klone og udvikle inde i din browser. Hvis du foretrækker at udvikle din app lokalt, er der en vejledning i at bruge ngrok [i README](https://github.com/discord/discord-example-app#running-app-locally). + +> info +> Glitch er fantastisk til udvikling og test, men [den har nogle tekniske begrænsninger](https://help.glitch.com/kb/article/17-technical-restrictions/), så du bør overveje andre hosting-udbydere til produktions-apps. + +Begynd med at **[remixe (eller klone) Glitch-projektet 🎏](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)**. + +Når du har remixet projektet, lander du på et nyt Glitch-projekt. + + +![Glitch-projektoversigt](glitch-project.png) + +- Dit **project name** er et unikt navn på dit projekt, der kan ses i øverste venstre hjørne +- **`.env`** er filen, hvor alle legitimationsoplysninger for din app bliver gemt +- **Logs** er stedet, hvor dit projekts output kan findes – det er nyttigt for at se, om appen kører, samt information om fejl, din app støder på +- **Share**-knappen i øverste, højre hjørne er stedet, hvor du finder det live projekts URL, som du skal bruge til at opsætte interaktivitet senere i denne vejledning + + +#### Projektstruktur + +Alle projektets filer er på venstre side af dit Glitch-projekt. Herunder er der en oversigt over hovedmapperne og filerne: + +``` +├── examples -> korte, funktionsspecifikke app-prøveeksemplarer +│ ├── app.js -> færdig app.js kode +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> dine legitimationsoplysninger og ID'er +├── app.js -> primært entrypoint for app +├── commands.js -> slash-kommandonyttelaster + hjælpere +├── game.js -> logik specifik til RPS +├── utils.js -> utility-funktioner og enums +├── package.json +├── README.md +└── .gitignore +``` + +### Tilføj legitimationsoplysninger + +Der er allerede noget kode i din `app.js`-fil, men du skal bruge din apps token og ID for at lave anmodninger. Alle dine legitimationsoplysninger kan blive gemt direkte i `.env`-filen. + +Først skal du kopiere din bot-brugers token fra tidligere og indsætte den i **`DISCORD_TOKEN`**-variablen i din `.env`-fil. + +Derefter skal du gå til siden **Generel oversigt** i din app og derefter kopiere dens **App ID** og **Public Key**. Indsæt værdierne i din `.env`-fil som **`APP_ID`** og **`PUBLIC_KEY`**. + +Nu da dine legitimationsoplysninger er konfigureret, så lad os installere og håndtere slash-kommandoer. + +### Installér slash-kommandoer + +> info +> For at installere slash-kommandoer benytter appen [`node-fetch`](https://github.com/node-fetch/node-fetch). Du kan se implementeringen af installationen i `utils.js` i `DiscordRequest()`-funktionen. + +Projektet indeholder et `register`-script, du kan bruge til at installere kommandoerne i `ALL_COMMANDS`, der er defineret i bunden af `commands.js`. Det installerer kommandoerne som globale kommandoer ved at kalde HTTP API'ens [`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands) endpoint. + +Hvis du ønsker at tilpasse dine kommandoer eller tilføje ekstra kommandoer, kan du refererer kommandostrukturen i [kommandodokumentationen](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure). + +Kør `register`-scriptet ved at klikke på **Terminal** i bunden af dit Glitch-projekt og indsætte følgende kommando: + +``` +npm run registrer +``` + +Tryk på enter for at køre kommandoen. + +Hvis du går tilbage til din server, bør du nu se slash-kommandoerne. Men hvis du prøver at køre dem, sker der ikek noget, da din app ikke modtager eller håndterer nogen anmodninger fra Discord. + + +Discord har to API's som du frit kan vælge mellem og blande, når du laver apps: + +- **[HTTP API](#DOCS_REFERENCE/http-api)** er en REST-lignende API til generelle operationer som at sende og opdatere data i Discord eller hente data om en ressource. +- **[Gateway API](#DOCS_REFERENCE/gateway-websocket-api)** er en WebSocket-baseret API, der er nyttig til at beholde en tilstand eller lytte til begivenheder på en Discord-server. Vi benytter den ikke i denne vejledning, men du kan finde mere information om, hvordan du skaber en Gateway-forbindelse, samt de forskellige begivenheder, du kan lytte efter, i [Gateway-dokumentationen](#DOCS_TOPICS_GATEWAY). + + +--- + +## Trin 3: Håndtering af interaktivitet + +For at gøre din app i stand til at modtage slash-kommandoanmodninger (og andre interaktioner) skal Discord bruge en offentlig URL for at sende dem. Denne URL kan konfigureres i din apps indstillinger som **slutpunkt for interaktioner**. + +### Tilføj en URL for et slutpunkt for interaktioner + +Glitch-projekter har en offentlig URL, der som standard er synlig. Kopiér dit projekts URL ved at klikke på knappen **Del** i øverste, højre hjørne, og kopiér så "Live site"-projektlinket nær bunden af modalen. + +> info +> Hvis du udvikler lokalt, er der instrukser til at føre dine anmodninger til dit lokalmiljø [i GitHub README](https://github.com/discord/discord-example-app#running-app-locally). + +Når du har kopieret linket, skal du gå til din apps indstillinger fra [udviklingsportalen](https://discord.com/developers/applications). + +På din apps side med **Generel information** er der en instilling for **URL for slutpunkt for interaktioner**, hvor du kan indsætte din apps URL og hægte `/interactions` på den, og det er her, Express-appen konfigureres til at lytte efter anmodninger. + +![URL for slutpunkt for interaktioner i app-indstillinger](interactions-url.png) + +Klik på **Gem ændringer**, og sørg for, at dit slutpunkt er korrekt bekræftet. + +App-eksemplet håndterer bekræftelse på to måder: +- Den bruger `PUBLIC_KEY` og [discord-interaktionspakken](https://github.com/discord/discord-interactions-js#usage) med en wrapper-funktion (importeret fra `utils.js`), der gør, at den passer til [Express' `verify`-brugerflade](http://expressjs.com/en/5x/api.html#express.json). Den køres på alle indkommende anmodninger på din app. +- Den besvarer indkommende `PING`-anmodninger. + +Du kan lære mere om at forberede din app til at modtage interaktioner i [interaktionsdokumentationen](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction). + +### Håndtering af slash-kommandoanmodninger + +Når slutpunktet er bekræftet, skal du gå til dit projekts `app.js`-fil og finde kodeblokken, der håndterer `/test`-kommandoen: + +```javascript +// "test"-kommando +if (name === 'test') { + // Send en besked i kanalen, hvor kommandoen blev udløst + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Henter en tilfældig emoji, der sendes fra en hjælpefunktion + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +Koden herover reagerer på interaktionen med en besked i kanalen, hvor kommandoen kom fra. Du kan se alle tilgængelige svartyper såsom besvarelse med en modal [i dokumentationen](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type). + +> info +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE` er en konstant, der er [eksporteret fra `discord-interactions`](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33) + +Gå til din server, og sørg for, at din apps `/test` slash-kommando fungerer. Når du udløser den, burde din app sende en besked, der indeholder teksten “hello world” efterfulgt af en tilfældig emoji. + +I den følgende sektion tilføjer vi en ekstra kommando, der benytter slash-kommandoerindstillinger, knapper og valgmuligheder til at bygge sten-saks-papir-spillet. + +--- + +## Trin 4: Tilføj beskedkomponenter + +`/challenge`-kommandoen er måden, vores sten-saks-papir-spil bliver startet. Når kommandoen udløses, sender appen beskedkomponenter til kanalen, der hjælper brugerne med at fuldføre spillet. + +### Tilføj en kommando med valgmuligheder + +`/challenge`-kommandoen, kaldet `CHALLENGE_COMMAND` i `commands.js`, har en række `options`. I vores app er de forskellige options objekter, der repræsenterer forskellige ting, en bruger kan vælge mellem i et spil sten-saks-papir, genereret ved brug af nøgler for `RPSChoices` i `game.js`. + +Du kan læse mere om kommando-valgmuligheder og deres struktur [i dokumentationen](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure). + +> info +> Selvom denne vejledning ikke går i dybden med `game.js`-filen, er du velkommen til at grave lidt rundt og ændre kommandoerne eller valgmulighederne i kommandoerne. + + + +For at håndtere `/challenge`-kommandoen skal du føje følgende kode efter hvis-blokken `if name === “test”`: + +```javascript +// "challenge"-kommando +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // Brugers genstandsvalg + const objectName = req.body.data.options[0].value; + + // Skab aktivt spil med besked-ID som spil-ID + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // Tilføj spil-ID til senere brug + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> info +> Hvis du ikke er sikker på, hvor du skal indsætte koden, kan du se den fulde kode i `examples/app.js` i Glitch-projektet eller i roden `app.js` [på GitHub](https://github.com/discord/discord-example-app/blob/main/app.js). + +Koden herover gør et par forskellige ting: +1. Parser anmodningsdataen for at få ID på brugeren, der udløste slash-kommandoen (`userId`), og valget (genstandsvalg) de traf (`objectName`). +2. Tilføjer et nyt spil til `activeGames`-objektet med interaktions-ID'et. Det aktive spil noterer `userId` og `objectName`. +3. Sender en besked tilbage til kanalen med en knap med et `custom_id` på `accept_button_`. + +> warn +> Kodeeksemplet bruger et objekt som in-memory lagring, men for produktionsapps bør du bruge en database. + +Når der sendes en besked med [beskedkomponenter](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component), tilføjes den individuelle nyttelast til et `components`-sæt. Anvendelige komponenter (såsom knapper) skal være i en [handlingsrække](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows), som du kan se kodeeksemplet. + +Bemærk det unikke `custom_id`, der blev sendt med beskedkomponenterne, i dette tilfælde `accept_button_` med det aktive spils ID tilføjet. Et `custom_id` kan bruges til at håndtere anmodninger, som Discord sender dig, når nogen interagerer med komponenten, som du vil få at se om et øjeblik. + +Når du nu kører `/challenge`-kommandoen og vælger en valgmulighed, vil din app sende en besked med en **Accept**-knap. Lad os tilføje koden, der håndtere tryk på knappen. + + + + + +Når brugere interagerer med en beskedkomponent, sender Discord en anmodning med [interaktionstypen](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) `3` (eller `MESSAGE_COMPONENT`-værdien, når der anvendes `discord-interactions`). + +For at sætte en handler op for knappen tjekker vi interaktionens `type`, efterfulgt af en matching af `custom_id`. + +Indsæt følgende kode under type-handleren for `APPLICATION_COMMAND`: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id valg i nyttelast ved afsendelse af beskedkomponent +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // hent det tilhørende spil-ID + const gameId = componentId.replace('accept_button_', ''); + // Slet besked med token i anmodningskroppen + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Henter en tilfældig emoji, der sendes fra en hjælpefunktion + content: 'What is your object of choice?', + // Indikerer, at det bliver en kortvarig besked + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Tilføj spil-ID + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Slet forrige besked + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +Koden herover: +1. Tjekker efter et `custom_id`, der matcher det, vi oprindeligt sendte (i dette tilfælde starter det med `accept_button_`). Custom-ID har også det aktive spil-ID tilføjet, så vi gemmer det i `gameID`. +2. [Sletter den oprindelige besked](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response) ved at kalde en webhook med `node-fetch` og sende den unikke interaktions-`token` i anmodningens krop. Dette gøres for at rydde op i kanalen og for at forhindre, at andre brugere kan klikke på knappen. +3. Besvarer anmodningen ved at sende en besked, der indeholder en menu med valgmuligheder med genstandene i spillet. Nyttelasten bør se ud ligesom den forrige med undtagelse af `options`-sættet og `flags: 64`, [der indikerer, at beskeden er kortvarig](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message). + +`options`-sættet befolkes ved hjælp af `getShuffledOptions()`-metoden i `game.js`, der manipulerer `RPSChoices`-værdierne, så de passer til formen på [beskedkomponentvalgene](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure). + + + + + +Til slut skal vi tilføje kode, der håndterer interaktion med menuer med valgmuligheder og sender spillets resultat til kanalen. + +Da menuer med valgmuligheder blot er endnu en beskedkomponent, er koden, der håndterer deres interaktioner, næsten identisk med den for knapper. + +Modificér koden ovenfor, så den kan håndtere menuer med valgmuligheder: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id valg i nyttelast ved afsendelse af beskedkomponent +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // hent det tilhørende spil-ID + const gameId = componentId.replace('accept_button_', ''); + // Slet besked med token i anmodningskroppen + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Henter en tilfældig emoji, der sendes fra en hjælpefunktion + content: 'What is your object of choice?', + // Indikerer, at det bliver en kortvarig besked + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Tilføj spil-ID + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Slet forrige besked + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // hent det tilhørende spil-ID + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // Hent bruger-ID og valgt genstand for besvarende bruger + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // Beregn resultatet fra hjælpefunktion + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // Fjern spil fra lager + delete activeGames[gameId]; + // Opdatér besked med token i anmodningskroppen + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // Send resultater + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // Opdatér kortvarig besked + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +Ligesom med tidligere kode henter koden herover bruger-ID'et og deres valg af genstand fra interaktionsanmodningen. + +Den information, sammen med den oprindelige brugers ID og valg fra `activeGames`-objektet, sendes til `getResult()`-funktionen. `getResult()` bestemmer vinderen og bygger en læselig tekst, der sendes tilbage til kanalen. + +Vi kalder også en anden webhook, denne gang for at [opdater den opfølgende kortvarige besked](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message), siden den ikke kan slettes. + +Endelig sendes resultatet til kanalen med `CHANNEL_MESSAGE_WITH_SOURCE`-interaktionssvartypen. + + + +... og det var det 🎊 Test din app for at sikre, at alt virker. + +--- + +## Næste skridt + +Tillykke, du har skabt din første Discord-app! 🤖 + +Forhåbentlig har du lært en smule om Discord-apps, hvordan du konfigurerer dem, og hvordan du gør dem interaktive. Herfra kan du fortsætte med at udvikle din app, eller du kan udforske, hvad der ellers kan lade sig gøre: +- Læs **[dokumentationen](#DOCS_INTRO)** for dybdegående information om API-funktioner +- Kig i `examples/`-mappen i dette projekt for mindre, funktionsspecifikke kodeeksempler +- Se vores **[community-ressourcer](#DOCS_TOPICS_COMMUNITY_RESOURCES)** for sprogspecifikke redskaber, leveret af medlemmer af fællesskabet +- Læs vores vejledning om at [hoste Discord-apps på Cloudflare Workers](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS) +- Slut dig til **[Discord Developers-serveren](https://discord.gg/discord-developers)** for at stille spørgsmål om API'en, deltag i begivenheder afholdt af Discord API-teamet, og interagér med andre udviklere diff --git a/docs/de/Getting_Started.mdx b/docs/de/Getting_Started.mdx new file mode 100644 index 0000000000..c924177434 --- /dev/null +++ b/docs/de/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# Erstellen deiner ersten eigenen Discord-App + +Discord-Apps ermöglichen dir die Anpassung und Erweiterung deines Servers mithilfe einer Reihe von APIs und interaktiven Features. Diese Anleitung führt dich durch die Erstellung deiner ersten Discord-App mit JavaScript. Das Ergebnis ist eine App, die Slash-Befehle verwendet, Nachrichten sendet und auf Interaktionen mit Komponenten reagiert. + +Wir werden eine Discord-App erstellen, mit der Servermitglieder Stein-Schere-Papier spielen können (mit 7 Wahlmöglichkeiten statt der üblichen 3). Diese Anleitung richtet sich an Anfänger, setzt aber ein grundlegendes Verständnis von [JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics) voraus. + + +So wird die fertige App aussehen: + +![Demo der Beispiel-App](getting-started-demo.gif) + +Um den Spielablauf etwas besser zu erklären: + +1. Benutzer 1 startet ein neues Spiel und wählt mit dem Slash-Befehl `/challenge` ein Objekt. +2. Eine Nachricht wird an den Kanal geschickt. Sie enthält einen Button, der andere zum Annehmen der Herausforderung einlädt. +3. Benutzer 2 klickt auf den Button **Accept**. +4. Benutzer 2 erhält eine ephemerale (temporär verfügbare) Nachricht und kann dort selbst ein Objekt wählen. +5. Der Ausgang des Spiels wird im ursprünglichen Kanal für alle sichtbar gepostet. + + + +- **[Github-Repository](https://github.com/discord/discord-example-app)** mit dem Code für diese Anleitung sowie einigen weiteren Code-Beispielen für spezifische Features. +- **[discord-interactions](https://github.com/discord/discord-interactions-js)**, eine Bibliothek mit Types und Helper-Funktionen für Discord-Apps +- **[Express](https://expressjs.com)**, ein beliebtes JavaScript-Web-Framework, mit dem wir einen Server erstellen werden, über den uns Discord Anfragen schicken kann. +- **[Glitch](https://glitch.com/)**, eine Online-Umgebung, die das Erstellen und Hosten von Apps während des Prototypings und der Entwicklung vereinfacht. Mit Tools wie **[ngrok](https://ngrok.com/)** kannst du auch lokal entwickeln. + + +--- + +## Schritt 1: Erstellung einer App + +Zuerst musst du im Entwicklerportal eine App erstellen, wenn du noch keine hast: + + + +Gib deiner App einen Namen und klick dann auf **Create**. + +Nachdem du deine App erstellt hast, landest du auf der Seite **General Overview** der Einstellungen für deine App, wo du grundlegende Informationen deiner App wie Beschreibung und Icon eingeben kannst. Außerdem siehst du eine **Application ID** und **Interactions Endpoint URL**, die wir später in diesem Guide benutzen werden. + +### Konfiguration deines Bots + +Als Nächstes konfigurieren wir den [Botbenutzer](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts) für deine App, damit er wie andere Servermitglieder aussieht und handelt. + +Klick in der linken Seitenleiste auf **Bot**. Auf dieser Seite kannst du Einstellungen wie seine [Privileged Intents](#DOCS_TOPICS_GATEWAY/privileged-intents) festlegen, oder ob er von anderen Benutzern installiert werden kann. + + +Mit Intents wird festgelegt, welche Events Discord an deine App sendet, wenn du eine [Gateway-API-Verbindung](#DOCS_TOPICS_GATEWAY) erstellst. Wenn deine App zum Beispiel etwas tun soll, wenn Benutzer einer Nachricht eine Reaktion hinzufügen, kannst du den Intent `GUILD_MESSAGE_REACTIONS` (`1 << 10`) vergeben. + +Manche Intents sind [Privileged](#DOCS_TOPICS_GATEWAY/privileged-intents), weil sie deiner App Zugriff auf Daten gewähren, die vertraulich sein können (wie der Inhalt von Nachrichten). Privileged Intents werden auf der **Bot**-Seite deiner App-Einstellungen angezeigt und können dort aktiviert oder deaktiviert werden. Alle anderen Intents, die nicht dazu zählen, werden Standard Intents genannt und benötigen keine zusätzlichen Berechtigungen oder Konfigurationen. + +Mehr Informationen zu Intents und eine Liste aller verfügbaren Intents mit ihren zugehörigen Events findest du in der [Dokumentation zu Gateways](#DOCS_TOPICS_GATEWAY/gateway-intents). + + +![Bot-Tab in den App-Einstellungen](app-add-bot.png) + +Auf der **Bot**-Seite gibt es außerdem den Abschnitt **Token**, wo du das Token deines Bots kopieren und zurücksetzen kannst. + +Bot-Tokens werden benutzt, um API-Anfragen zu autorisieren und transportieren die Permissions (Berechtigungen) deines Botbenutzers, weshalb sie *streng vertraulich* sind. Du solltest dein Token *niemals* teilen oder in einer Versionskontrolle überprüfen. + +Kopiere es und speichere es an einem sicheren Ort (zum Beispiel einem Passwortmanager). + +> warn +> Stell sicher, dass du dein Token gut aufbewahrst. Du kannst es sonst nur sehen, indem du es erneut generierst. + +### Scopes und Bot Permissions hinzufügen + +Apps benötigen die Genehmigung von installierenden Benutzern, um Aktionen in Discord auszuführen (wie die Erstellung eines Slash-Befehls oder die Abfrage einer Liste von Servermitgliedern). Wählen wir ein paar Scopes und Permissions aus, bevor wir die App installieren. + + +Wenn du eine App erstellst, bestimmst du mit Scopes und Permissions, was deine App auf Discord-Servern tun und worauf sie zugreifen kann. + +- [OAuth2 Scopes](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) legen den Datenzugriff und die möglichen Aktionen deiner App fest. Sie werden so von installierenden oder authentifizierenden Benutzern übernommen. +- [Permissions](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) sind die granularen Berechtigungen für deinen Botbenutzer, wie sie auch andere Discord-Benutzer haben. Sie können vom installierenden Benutzer gewährt oder später in den Servereinstellungen oder mit [Permission Overwrites](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) aktualisiert werden. + + +Klick auf **Oauth2** in der linken Seitenleiste und wähle dann **URL Generator**. + +> info +> Der URL Generator erstellt einen Installationslink basierend auf den Scopes und Permissions, die du für deine App auswählst. Du kannst den Link verwenden, um die App auf deinem eigenen Server zu installieren, oder ihn mit anderen teilen, damit sie die App installieren können. + +Füge vorerst zwei Scopes hinzu: +- `applications.commands` ermöglicht es deiner App, [Commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS) (Befehle) zu erstellen. +- `bot` fügt deinen Botbenutzer hinzu. Nachdem du `bot` ausgewählt hast, kannst du auch verschiedene Permissions für deinen Bot festlegen. Wähle vorerst nur **Send Messages**. + +Es gibt eine Liste der [Oauth2 Scopes](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) und du kannst in der Dokumentation mehr zu [Permissions](#DOCS_TOPICS_PERMISSIONS) lesen. + +### Installation deiner App + +Sobald du Scopes hinzugefügt hast, solltest du eine URL sehen, die du kopieren kannst, um deine App zu installieren. + +![Screenshot des URL Generators](url-generator.png) + +> info +> Wenn du Apps entwickelst, solltest du sie auf einem Server erstellen und testen, der nicht aktiv von anderen verwendet wird. Wenn du noch keinen eigenen Server hast, kannst du [kostenlos einen erstellen](https://support.discord.com/hc/de/articles/204849977-Wie-erstelle-ich-einen-Server-). + +Kopiere die oben erwähnte URL in deinen Browser. Du wirst durch den Installationsprozess geführt. Stell sicher, dass du die App auf einem Server installierst, wo du sie entwickeln und testen kannst. + +Nachdem du deine App installiert hast, kannst du auf deinen Server gehen und sehen, dass er beigetreten ist ✨ + +Deine App ist jetzt konfiguriert und installiert. Jetzt können wir sie entwickeln! + +--- + +## Schritt 2: Ausführen deiner App + +Der gesamte Code in der Beispiel-App ist im [Github-Repository](https://github.com/discord/discord-example-app) zu finden. + +Um die Entwicklung etwas zu vereinfachen, verwendet die App [discord-interactions](https://github.com/discord/discord-interactions-js) für Types und Helper-Funktionen. Wenn du andere Sprachen oder Bibliotheken bevorzugst, wirf einen Blick in die Dokumentation zu [Community Resources](#DOCS_TOPICS_COMMUNITY_RESOURCES). + +### Remixen des Projekts + +Diese Anleitung verwendet Glitch, das das Klonen und die Entwicklung im Browser ermöglicht. Wenn du deine App lieber lokal entwickeln willst, findest du [in der README](https://github.com/discord/discord-example-app#running-app-locally) eine Anleitung zur Verwendung von ngrok. + +> info +> Glitch eignet sich bestens zum Entwickeln und Testen, hat aber [technische Beschränkungen](https://help.glitch.com/kb/article/17-technical-restrictions/). Deshalb sollten für Apps in Anwendung andere Hosting-Anbieter gewählt werden. + +Beginne mit dem **[Remix (oder Klonen) des Glitch-Projekts 🎏](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)**. + +Nach dem Remix des Projekts landest du in einem neuen Glitch-Projekt. + + +![Projektübersicht von Glitch](glitch-project.png) + +- Dein **Project Name** ist ein einzigartiger Name für dein Projekt, der in der oberen linken Ecke steht. +- **`.env`** ist die Datei, in der all deine Anmeldeinformationen für die App gespeichert werden. +- In den **Logs** findest du die Ausgabe deines Projekts – so kannst du sehen, ob die App funktioniert, und findest Informationen zu auftretenden Fehlern. +- Über den Button **Share** in der oberen rechten Ecke erhältst du die Live-URL des Projekts. Du benötigst sie später in dieser Anleitung, um die Interaktivität einzurichten. + + +#### Projektstruktur + +Alle Dateien für das Glitch-Projekt sind auf der linken Seite aufgeführt. Unten ist ein Überblick der Hauptordner und -dateien: + +``` +├── examples -> kurze Beispiel-Apps für spezifische Features +│ ├── app.js -> fertiger app.js-Code +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> deine Anmeldeinformationen und IDs +├── app.js -> Einsprungpunkt der App +├── commands.js -> Payloads + Helper für Slash-Befehle +├── game.js -> RPS-spezifische Logik +├── utils.js -> Dienstfunktionen und Enums +├── package.json +├── README.md +└── .gitignore +``` + +### Anmeldeinformationen hinzufügen + +Deine `app.js`-Datei enthält schon etwas Code, aber du benötigst Token und ID deiner App, um Anfragen zu stellen. Alle deine Anmeldeinformationen können direkt in der `.env`-Datei gespeichert werden. + +Kopier zuerst das Token deines Botbenutzers von vorhin und füg es in die Variable **`DISCORD_TOKEN`** deiner `.env`-Datei ein. + +Ruf dann die Seite **General Overview** deiner App auf und kopiere **App ID** und **Public Key**. Füg die Werte in deine `.env`-Datei als **`APP_ID`** und **`PUBLIC_KEY`** ein. + +Damit sind deine Anmeldeinformationen konfiguriert! Jetzt können wir Slash-Befehle installieren und einrichten. + +### Slash-Befehle installieren + +> info +> Um Slash-Befehle zu installieren, verwendet die App [`node-fetch`](https://github.com/node-fetch/node-fetch). Du kannst die Implementierung für die Installation in `utils.js` in der Funktion `DiscordRequest()` sehen. + +Das Projekt enthält ein `register`-Skript, das du benutzen kannst, um die Befehle in `ALL_COMMANDS` (am Ende von `commands.js`) zu installieren. Sie werden als globale Befehle installiert, indem der Endpunkt [`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands) der HTTP-API angefragt wird. + +Wenn du deine Befehle anpassen oder welche hinzufügen willst, kannst du den Abschnitt Command Structure in der [Dokumentation zu Befehlen](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure) zu Rate ziehen. + +Führ das `register`-Skript aus, indem du am unteren Rand deines Glitch-Projekts auf **Terminal** klickst und den folgenden Befehl einfügst: + +``` +npm run register +``` + +Drück Enter, um den Befehl auszuführen. + +Wenn du jetzt wieder auf deinen Server gehst, solltest du die Slash-Befehle sehen. Aber wenn du sie ausführst, wird nichts passieren, denn deine App erhält noch keine Anfragen von Discord. + + +Discord hat zwei APIs, die du kombinieren kannst, um Apps zu erstellen: + +- **[HTTP API](#DOCS_REFERENCE/http-api)** ist eine REST-API für allgemeine Operationen wie das Senden und Aktualisieren von Daten in Discord oder die Abfrage von Daten zu einer Ressource. +- **[Gateway API](#DOCS_REFERENCE/gateway-websocket-api)** ist eine WebSocket-basierte API, mit deren Hilfe der Zustand beibehalten oder Events eines Discord-Servers „gehört“ werden können. Wir werden sie nicht in diesem Guide benutzen. Mehr Informationen zur Erstellung einer Gateway-Verbindung und zu den verschiedenen Events, die gehört werden können, findest du in der [Dokumentation zu Gateway](#DOCS_TOPICS_GATEWAY). + + +--- + +## Schritt 3: Bearbeiten der Interaktivität + +Damit deine App Anfragen über Slash-Befehle (und andere Interaktionen) erhalten kann, benötigt Discord eine öffentliche URL, um sie zu senden. Diese URL kann in deinen App-Einstellungen als **Interaction Endpoint URL** konfiguriert werden. + +### Hinzufügen einer Interaction Endpoint URL + +Glitch-Projekte haben standardmäßig eine öffentliche URL. Kopier die URL deines Projekts mit dem Button **Share** in der oberen rechten Ecke und kopiere dann den „Live Site“-Projektlink fast ganz unten im Modal. + +> info +> Wenn du lokal entwickelst, findest du [in der Github-README](https://github.com/discord/discord-example-app#running-app-locally) Anweisungen, wie du Anfragen in deine lokale Umgebung tunnelst. + +Begib dich mit dem kopierten Link in deine App-Einstellungen im [Entwicklerportal](https://discord.com/developers/applications). + +Auf der Seite **General Information** deiner App findest du die Option **Interactive Endpoint URL**, wo du die URL deiner App einfügen und `/interactions` (enthält die Konfiguration der Express-App, um Anfragen zu hören) anhängen kannst. + +![Interactions Endpoint URL in den App-Einstellungen](interactions-url.png) + +Klick auf **Save Changes** und überprüfe, ob dein Endpunkt erfolgreich verifiziert wurde. + +Die Beispiel-App geht auf zwei Arten mit Verifizierungen um: +- Sie verwendet den `PUBLIC_KEY` und [discord-interactions](https://github.com/discord/discord-interactions-js#usage) mit einer Wrapper-Funktion (aus `utils.js` importiert), um dem [`verify`-Interface von Express](http://expressjs.com/en/5x/api.html#express.json) zu entsprechen. Das wird bei jeder Anfrage ausgeführt, die bei der App eingeht. +- Sie reagiert auf eingehende `PING`-Anfragen. + +In der [Dokumentation zu Interactions](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction) kannst du mehr darüber erfahren, wie du deine App auf eingehende Interaktionen vorbereiten kannst. + +### Anfragen für Slash-Befehle bearbeiten + +Jetzt ist unser Endpunkt verifiziert. Öffne die Datei `app.js` deines Projekts und finde den Code-Block für den Befehl `/test`: + +```javascript +// "test"-Befehl +if (name === 'test') { + // sendet eine Nachricht an den Kanal, in dem der Befehl ausgelöst wurde + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // ruft ein zufälliges Emoji von einer Helper-Funktion ab, das mitgesendet werden soll + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +Der Code oben reagiert auf die Interaktion mit einer Nachricht in dem Kanal, wo sie ausgelöst wurde. [In der Dokumentation](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type) findest du alle verfügbaren Antworttypen, zum Beispiel mit einem Modal. + +> info +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE` ist eine [aus `discord-interactions` exportierte](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33) Konstante. + +Geh auf deinen Server und überprüfe, ob dein Slash-Befehl `/test` funktioniert. Wenn du ihn auslöst, sollte deine App eine Nachricht mit „hello world“ und einem zufälligen Emoji senden. + +Im folgenden Abschnitt fügen wir für unser Stein-Schere-Papier-Spiel einen weiteren Befehl hinzu, der Slash-Befehle, Buttons und Auswahlmenüs benutzt. + +--- + +## Schritt 4: Hinzufügen von Nachrichtenkomponenten + +Der Befehl `/challenge` wird unser Stein-Schere-Papier-Spiel beginnen. Wenn er ausgelöst wird, sendet die App Nachrichtenkomponenten an den Kanal, die den Benutzer zum Abschluss des Spiels führen. + +### Hinzufügen eines Befehls mit Optionen + +Der Befehl `/challenge` (zu finden in `commands.js` als `CHALLENGE_COMMAND`) hat eine Reihe von `options`. In unserer App sind das Objekte, die ein Benutzer auswählen kann, wenn er Stein-Schere-Papier spielt. Sie werden mit Keys von `RPSChoices` in `game.js` generiert. + +[In der Dokumentation](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure) kannst du mehr über Befehlsoptionen und ihre Struktur lesen. + +> info +> Diese Anleitung geht nicht weiter auf die Datei `game.js` ein, aber sieh sie dir ruhig an und ändere Befehle oder Optionen der Befehle. + + + +Füge den folgenden Code nach dem If-Block `if name === “test”` ein, um den Befehl `/challenge` zu bearbeiten: + +```javascript +// "challenge"-Befehl +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // gewähltes Objekt des Benutzers + const objectName = req.body.data.options[0].value; + + // erstellt aktives Spiel mit der ID der Nachricht als Spiel-ID + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // hängt die Spiel-ID für spätere Verwendung an + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> info +> Wenn du nicht sicher bist, wohin der Code kopiert werden muss, findest du den vollständigen Code auch in `examples/app.js` im Glitch-Projekt oder in der vollständigen `app.js` auf [Github](https://github.com/discord/discord-example-app/blob/main/app.js). + +Der obige Code erfüllt eine Reihe von Funktionen: +1. Er parst die Anfrage, um die ID des Benutzers, der den Slash-Befehl ausgelöst hat (`userId`), und seine gewählte Option (das gewählte `objectName`-Objekt) zu erhalten. +2. Er fügt dem Objekt `activeGames` ein neues Spiel mit der Interaktions-ID hinzu. Dort werden `userId` und `objectName` festgehalten. +3. Er sendet eine Nachricht zurück an den Kanal, die einen Button mit einer `custom_id` von `accept_button_` enthält. + +> warn +> Der Beispielcode verwendet In-Memory-Speicherung für das Objekt, aber für Apps in Anwendung solltest du eine Datenbank benutzen. + +Wenn eine Nachricht mit [Message Components](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component) (Nachrichtenkomponenten) gesendet wird, werden die individuellen Payloads an ein `components`-Array angehängt. Ausführbare Komponenten (wie Buttons) müssen wie im Beispielcode in einer [Action Row](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows) sein. + +Wie du siehst, wird die einzigartige `custom_id` mit Nachrichtenkomponenten geschickt, in diesem Fall `accept_button_`, mit der angehängten ID des aktiven Spiels. Eine `custom_id` kann verwendet werden, um Anfragen von Discord zu bearbeiten, wenn jemand mit der Nachrichtenkomponente interagiert. Damit beschäftigen wir uns gleich. + +Wenn du jetzt den `/challenge`-Befehl ausführst und eine Option wählst, wird deine App eine Nachricht mit dem Button **Accept** senden. Also fügen wir jetzt den Code für das Betätigen dieses Buttons hinzu. + + + + + +Wenn Benutzer mit einer Message Component interagieren, sendet Discord eine Anfrage mit dem [Interaction Type](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) `3` (oder dem Wert von `MESSAGE_COMPONENT`, wenn `discord-interactions` verwendet wird). + +Für die Bearbeitung des Buttons prüfen wir den `type` der Interaktion, gefolgt vom Abgleich der `custom_id`. + +Kopier den folgenden Code unter die Type-Bearbeitung für `APPLICATION_COMMAND`: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id, die in der Payload beim Senden der Nachrichtenkomponente festgelegt wird +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // fragt die zugehörige Spiel-ID ab + const gameId = componentId.replace('accept_button_', ''); + // löscht Nachricht mit Token in der Anfrage + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // ruft ein zufälliges Emoji von einer Helper-Funktion ab, das mitgesendet werden soll + content: 'What is your object of choice?', + // zeigt an, dass es eine ephemerale Nachricht sein wird + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // hängt Spiel-ID an + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // löscht vorherige Nachricht + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +Der obige Code: +1. Sucht nach einer `custom_id`, die mit unserer ursprünglich gesendeten übereinstimmt (in diesem Fall beginnt sie mit `accept_button_`). Diese ID hat auch die ID des aktiven Spiels angehängt, also speichern wir diese in `gameID`. +2. [Löscht die ursprüngliche Nachricht](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response), indem mit `node-fetch` ein WebHook aufgerufen und das einzigartige Interaktions-`token` in der Anfrage weitergegeben wird. Damit wird der Kanal aufgeräumt und andere Benutzer können den Button nicht anklicken. +3. Reagiert auf die Anfrage mit dem Senden einer Nachricht, die ein Auswahlmenü mit den Objekten für das Spiel enthält. Die Payload sollte der vorherigen sehr ähnlich sein, mit Ausnahme des `options`-Arrays und `flags: 64` ([zeigt an, dass die Nachricht ephemeral ist](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message)). + +Das `options`-Array wird mit der `getShuffledOptions()`-Methode in `game.js` befüllt, die die `RPSChoices`-Werte manipuliert, um sie an die Form von [Message Component Options](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure) anzupassen. + + + + + +Als Letztes müssen wir den Code hinzufügen, der die Interaktionen im Auswahlmenü bearbeitet und das Ergebnis des Spiels an den Kanal sendet. + +Da Auswahlmenüs nur eine weitere Nachrichtenkomponente sind, ist der Code für ihre Interaktionen beinahe identisch mit dem für Buttons. + +Modifiziere den obigen Code, um das Auswahlmenü zu bearbeiten: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id, die in der Payload beim Senden der Nachrichtenkomponente festgelegt wird +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // fragt die zugehörige Spiel-ID ab + const gameId = componentId.replace('accept_button_', ''); + // löscht Nachricht mit Token in der Anfrage + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // ruft ein zufälliges Emoji von einer Helper-Funktion ab, das mitgesendet werden soll + content: 'What is your object of choice?', + // zeigt an, dass es eine ephemerale Nachricht sein wird + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // hängt Spiel-ID an + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // löscht vorherige Nachricht + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // fragt die zugehörige Spiel-ID ab + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // fragt Benutzer-ID und gewähltes Objekt für antwortenden Benutzer ab + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // kalkuliert Ergebnis aus Helper-Funktion + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // entfernt Spiel aus Speicher + delete activeGames[gameId]; + // aktualisiert Nachricht mit Token in der Anfrage + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // sendet Ergebnis + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // aktualisiert ephemerale Nachricht + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +Ähnlich wie der vorherige Code fragt dieser Code die Benutzer-ID und dessen ausgewähltes Objekt aus der Interaktionsanfrage ab. + +Diese Informationen sowie die ID des ursprünglichen Benutzers und seine Auswahl aus dem `activeGames`-Objekt werden an die `getResult()`-Funktion weitergegeben. Die `getResult()`-Funktion bestimmt den Sieger und erstellt einen lesbaren String, der zurück an den Kanal gesendet wird. + +Wir rufen außerdem einen weiteren WebHook auf, der dieses Mal [die ephemerale Nachricht aktualisiert](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message), da sie nicht gelöscht werden kann. + +Am Ende wird das Ergebnis mit dem Interaction Response Type `CHANNEL_MESSAGE_WITH_SOURCE` an den Kanal gesendet. + + + +… und das war‘s 🎊 Jetzt kannst du deine App testen und prüfen, ob alles funktioniert. + +--- + +## Nächste Schritte + +Glückwunsch, du hast deine erste Discord-App erstellt! 🤖 + +Hoffentlich konntest du ein paar Dinge über die Erstellung, Konfiguration und Interaktivität von Discord-Apps lernen. Jetzt ist es an dir, deine App weiter zu gestalten oder zu entdecken, was noch möglich ist: +- Lies **[die Dokumentation](#DOCS_INTRO)** für detaillierte Informationen zu API-Features. +- Schau dir im `examples/`-Ordner dieses Projekts weitere kleinere Code-Beispiele für spezifische Features an. +- Entdecke die **[Community-Ressourcen](#DOCS_TOPICS_COMMUNITY_RESOURCES)** für sprachspezifische Tools von Community-Mitgliedern. +- Lies unser Tutorial zum [Hosten von Discord-Apps auf Cloudflare Workers](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS). +- Tritt dem **[Server Discord Developers](https://discord.gg/discord-developers)** bei, um Fragen zur API zu stellen, an Events des API-Teams von Discord teilzunehmen und dich mit anderen Entwicklern auszutauschen. diff --git a/docs/dispatch/Error_Codes.md b/docs/dispatch/Error_Codes.md index a0aa444df7..5577f5cd63 100644 --- a/docs/dispatch/Error_Codes.md +++ b/docs/dispatch/Error_Codes.md @@ -5,22 +5,22 @@ This page outlines some of the common errors codes that may be encountered when using Dispatch. -| Code | Name | Possible Solution | -| ---- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| 2020 | Request Signing Failed | Check user entitlement | -| 2022 | Disk Space Low | Free up disk space | -| 2023 | Disk Permission Denied | Choose a new location, or change write permissions on desired location | -| 2024 | Uninstall Failed | Attempt to manually remove game files from disk | -| 2025 | Install Script Failed | Restart Discord, attempt to uninstall/reinstall the game, ensure script is correct | -| 2029 | Build Not Found | Completely close and re-open Discord | -| 2051 | Panic! | Escalate in the #dispatch channel of the [Discord Developers Server](https://discord.gg/discord-developers) | -| 2058 | Too Many API Retries | Escalate in the #dispatch channel of the [Discord Developers Server](https://discord.gg/discord-developers) | -| 2059 | Failed to set Registry Key | User most likely denied Windows administrator permissions prompt. Try again, and accept the prompt | -| 2064 | Failed to Patch File | Attempted to patch the game while running: ensure the game process is entirely ended, try restarting Discord, try disabling antivirus | -| 2065 | No Manifests | Ensure that your manifests are properly selected in the Developer Portal for your SKU | -| 2069 | API Error | Intermittent API issues. Wait, escalate in the #dispatch channel of the [Discord Developers Server](https://discord.gg/discord-developers) | -| 2070 | Bad Response | Intermittent API issues. Wait, escalate in the #dispatch channel of the [Discord Developers Server](https://discord.gg/discord-developers) | -| 2073 | Not Entitled | Check that your manifests are properly configured in the Developer Portal. Have the user install the game from the Library, not the store page | -| 2076 | Two Clients Patching | User has multiple Discords open trying to patch the same game; only use one | -| 9001 | Unknown | Catch-all error code. Escalate in the #dispatch channel of the [Discord Developers Server](https://discord.gg/discord-developers) with repro steps/as much info as possible | +| Code | Name | Possible Solution | +|------|----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 2020 | Request Signing Failed | Check user entitlement | +| 2022 | Disk Space Low | Free up disk space | +| 2023 | Disk Permission Denied | Choose a new location, or change write permissions on desired location | +| 2024 | Uninstall Failed | Attempt to manually remove game files from disk | +| 2025 | Install Script Failed | Restart Discord, attempt to uninstall/reinstall the game, ensure script is correct | +| 2029 | Build Not Found | Completely close and re-open Discord | +| 2051 | Panic! | Escalate in the #dispatch channel of the [Discord Developers Server](https://discord.gg/discord-developers) | +| 2058 | Too Many API Retries | Escalate in the #dispatch channel of the [Discord Developers Server](https://discord.gg/discord-developers) | +| 2059 | Failed to set Registry Key | User most likely denied Windows administrator permissions prompt. Try again, and accept the prompt | +| 2064 | Failed to Patch File | Attempted to patch the game while running: ensure the game process is entirely ended, try restarting Discord, try disabling antivirus | +| 2065 | No Manifests | Ensure that your manifests are properly selected in the Developer Portal for your SKU | +| 2069 | API Error | Intermittent API issues. Wait, escalate in the #dispatch channel of the [Discord Developers Server](https://discord.gg/discord-developers) | +| 2070 | Bad Response | Intermittent API issues. Wait, escalate in the #dispatch channel of the [Discord Developers Server](https://discord.gg/discord-developers) | +| 2073 | Not Entitled | Check that your manifests are properly configured in the Developer Portal. Have the user install the game from the Library, not the store page | +| 2076 | Two Clients Patching | User has multiple Discords open trying to patch the same game; only use one | +| 9001 | Unknown | Catch-all error code. Escalate in the #dispatch channel of the [Discord Developers Server](https://discord.gg/discord-developers) with repro steps/as much info as possible | diff --git a/docs/dispatch/Field_Values.md b/docs/dispatch/Field_Values.md index 7594488aaa..8c98c003c8 100644 --- a/docs/dispatch/Field_Values.md +++ b/docs/dispatch/Field_Values.md @@ -8,7 +8,7 @@ ###### Platform Values | Platform | -| -------- | +|----------| | macos | | win32 | | win64 | @@ -17,7 +17,7 @@ ###### Redistributable values | Redistributable | -| -------------------------- | +|----------------------------| | directx_june_2010 | | vcredist_2005_x86 | | vcredist_2008_sp1_x86 | @@ -36,7 +36,7 @@ ###### Cloud Save Path Replacements | value | Windows path | macOS path | linux path | -| ---------------- | ----------------------------------------------------------------------------------- | ----------------------------- | ------------------- | +|------------------|-------------------------------------------------------------------------------------|-------------------------------|---------------------| | \${HOME} | %USERPROFILE% | ~/ | ~/ | | \${DOCUMENTS} | %USERPROFILE%\Documents | ~/Documents | \$XDG_DOCUMENTS_DIR | | \${DATA} | %USERPROFILE%\AppData\Roaming | ~/Library/Application Support | \$XDG_DATA_HOME | diff --git a/docs/dispatch/List_of_Commands.md b/docs/dispatch/List_of_Commands.md index 4856f351ce..1f0de425fd 100644 --- a/docs/dispatch/List_of_Commands.md +++ b/docs/dispatch/List_of_Commands.md @@ -27,7 +27,7 @@ Creates a new branch. If you have not yet made a master branch, this command wil ###### Arguments | name | values | description | -| -------------- | ------ | ----------------------------- | +|----------------|--------|-------------------------------| | application_id | int | your application ID/client ID | | branch_name | string | the name for your new branch | @@ -45,7 +45,7 @@ Deletes a branch. ###### Arguments | name | values | description | -| -------------- | ------ | ------------------------------ | +|----------------|--------|--------------------------------| | application_id | int | your application ID/client ID | | branch_id | int | the id of the branch to delete | @@ -62,16 +62,16 @@ Lists all branches for an application. ###### Arguments | name | values | description | -| -------------- | ------ | ----------------------------- | +|----------------|--------|-------------------------------| | application_id | int | your application ID/client ID | ###### Example ``` -> dispatch branch list 290926444748734465 -| APPLICATION ID | BRANCH ID | NAME | LIVE_BUILD_ID | CREATED AT | -| -------------------- | -------------------- | -------------------- | -------------------- | ------------------------------ | -| 290926444748734465 | 471164707759996234 | master | | 2018-07-24 04:00:20.146588Z | +| APPLICATION ID | BRANCH ID | NAME | LIVE_BUILD_ID | CREATED AT | +|--------------------|--------------------|--------|---------------|-----------------------------| +| 290926444748734465 | 471164707759996234 | master | | 2018-07-24 04:00:20.146588Z | ``` ## branch promote @@ -81,7 +81,7 @@ Promotes the live build of one branch to another. ###### Arguments | name | values | description | -| ---------------- | ------ | --------------------------------- | +|------------------|--------|-----------------------------------| | application_id | int | your application ID/client ID | | branch_id | int | the id of the branch to promote | | target_branch_id | int | the id of the branch to overwrite | @@ -99,7 +99,7 @@ Deletes a build from a branch. ###### Arguments | name | values | description | -| -------------- | ------ | ----------------------------- | +|----------------|--------|-------------------------------| | application_id | int | your application ID/client ID | | build_id | int | the id of the build to delete | @@ -119,7 +119,7 @@ Wraps your executable in Discord's DRM. This only works for Windows executables. ###### Arguments | name | values | description | -| ------------------ | --------- | ---------------------------------------------------------------------------------- | +|--------------------|-----------|------------------------------------------------------------------------------------| | application_id | int | your application ID/client ID | | path_to_executable | file path | the path to the executable, either explicit or relative to the dispatch executable | @@ -136,7 +136,7 @@ Lists the builds available on the given branch. ###### Arguments | name | values | description | -| -------------- | ------ | ----------------------------- | +|----------------|--------|-------------------------------| | application_id | int | your application ID/client ID | | branch_id | int | the id of the branch to check | @@ -144,10 +144,10 @@ Lists the builds available on the given branch. ``` -> dispatch build list 290926444748734465 491362538965958686 -| APPLICATION ID | BUILD ID | STATUS | CREATION BRANCH | CREATED AT | -| -------------------- | -------------------- | -------------------- | -------------------- | ------------------------------ | -| 290926444748734465 | 489230031839821824 | READY | master | 2018-09-12 00:25:29.045554Z | -| 290926444748734465 | 479469321974841354 | READY | master | 2018-08-16 01:59:54.481336Z | +| APPLICATION ID | BUILD ID | STATUS | CREATION BRANCH | CREATED AT | +|--------------------|--------------------|--------|-----------------|-----------------------------| +| 290926444748734465 | 489230031839821824 | READY | master | 2018-09-12 00:25:29.045554Z | +| 290926444748734465 | 479469321974841354 | READY | master | 2018-08-16 01:59:54.481336Z | ``` ## build publish @@ -157,7 +157,7 @@ Marks a given build as the live build for a given branch. ###### Arguments | name | values | description | -| -------------- | ------ | ------------------------------ | +|----------------|--------|--------------------------------| | application_id | int | your application ID/client ID | | branch_id | int | the id of the branch to check | | build_id | int | the id of the build to publish | @@ -175,7 +175,7 @@ Pushes a new build to the given branch. The JSON config file tells Dispatch how ###### Arguments | name | values | description | -| ---------------- | --------- | ----------------------------------------------------------------------------------------------------- | +|------------------|-----------|-------------------------------------------------------------------------------------------------------| | branch_id | int | the id of the branch to check | | config_file | filename | the [JSON config file](#DOCS_DISPATCH_BRANCHES_AND_BUILDS/setting-up-our-first-build) for the build | | application_root | file path | the directory that dispatch will treat as the local root for operations—`.` for the current directory | @@ -197,7 +197,7 @@ Downloads the build for the given application id and branch id to the given inst ###### Arguments | name | values | description | -| -------------- | ----------------------------------------------------------------- | ------------------------------ | +|----------------|-------------------------------------------------------------------|--------------------------------| | application_id | int | your application ID/client ID | | branch_id | int | the id of the branch to check | | install_path | file path | the path to install to | @@ -217,7 +217,7 @@ Mark a build as corrupted. ###### Arguments | name | values | description | -| -------------- | ------ | ------------------------------ | +|----------------|--------|--------------------------------| | application_id | int | your application ID/client ID | | build_id | int | the id of the build to corrupt | @@ -235,7 +235,7 @@ Displays a preview of the install paths that a build will put files in, for a gi ###### Arguments | name | values | description | -| ---------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | +|------------------|-------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------| | config_file | filename | the [JSON config file](#DOCS_DISPATCH_BRANCHES_AND_BUILDS/setting-up-our-first-build) for the build | | application_root | file path | the directory that dispatch will treat as the local root for operations—`.` for the current directory | | --locale | [locale](#DOCS_REFERENCE/locales) | the build locale to preview | @@ -253,12 +253,12 @@ Repairs an application build. ###### Arguments -| name | values | description | -| ---------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| application_id | int | your application ID/client ID | -| branch_id | int | the id of the branch to check | -| build_id | int | the id of the build to repair | -| application_root | file path | the directory that dispatch will treat as the local root for operations—`.` for the current directory | +| name | values | description | +|------------------|-------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------| +| application_id | int | your application ID/client ID | +| branch_id | int | the id of the branch to check | +| build_id | int | the id of the build to repair | +| application_root | file path | the directory that dispatch will treat as the local root for operations—`.` for the current directory | | --platform | [platform](#DOCS_DISPATCH_FIELD_VALUES/manifests-platform-values) | the build platform to repair | ###### Example @@ -273,9 +273,9 @@ Runs the launch setup for an application. ###### Arguments -| name | values | description | -| ---------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| application_root | file path | the directory that dispatch will treat as the local root for operations—`.` for the current directory | +| name | values | description | +|------------------|-------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------| +| application_root | file path | the directory that dispatch will treat as the local root for operations—`.` for the current directory | | --platform | [platform](#DOCS_DISPATCH_FIELD_VALUES/manifests-platform-values) | the build platform to do the launch setup | ###### Example @@ -301,15 +301,15 @@ Lists created manifest labels. These labels are created from the JSON config fil ###### Arguments | name | values | description | -| -------------- | ------ | ----------------------------- | +|----------------|--------|-------------------------------| | application_id | int | your application ID/client ID | ###### Example ``` -> dispatch manifest-label list 290926444748734465 -| APPLICATION ID | ID | NAME | -| -------------------- | -------------------- | -------------------- | -| 290926444748734465 | 471165178650999608 | my-game | -| 290926444748734465 | 471169990397324288 | my-game-dlc | +| APPLICATION ID | ID | NAME | +|--------------------|--------------------|-------------| +| 290926444748734465 | 471165178650999608 | my-game | +| 290926444748734465 | 471169990397324288 | my-game-dlc | ``` diff --git a/docs/fr/Getting_Started.mdx b/docs/fr/Getting_Started.mdx new file mode 100644 index 0000000000..24e6283ddd --- /dev/null +++ b/docs/fr/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# Création de ta première application Discord + +Les applications Discord te permettent de personnaliser et d'étendre tes serveurs grâce à un ensemble d'API et de fonctions interactives. Ce guide t'aidera à créer ta première application Discord en employant JavaScript, et à la fin, tu disposeras d'une application qui utilise des commandes slash, envoie des messages et répond aux interactions avec des éléments. + +Nous allons créer une application Discord qui permet aux membres du serveur de jouer à pierre-feuille-ciseaux (avec 7 choix au lieu des 3 habituels). Ce guide s'adresse aux débutants, mais il nécessite une connaissance des bases de [JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics). + + +Voici à quoi ressemblera l'application : + +![Démo de l'exemple d'application](getting-started-demo.gif) + +Voici le flux utilisateur présenté de manière un peu plus explicite : + +1. L'utilisateur 1 lance une nouvelle partie et choisit son objet à l'aide de la commande slash `/defi` de l'application. +2. Un message est envoyé dans le salon avec un bouton invitant d'autres utilisateurs à relever le défi. +3. L'utilisateur 2 appuie sur le bouton **Accepter**. +4. L'utilisateur 2 reçoit un message éphémère qui lui permet de sélectionner l'objet de son choix. +5. Le résultat de la partie est posté dans le salon d'origine pour que tout le monde puisse le voir. + + + +- **[Dépôt GitHub](https://github.com/discord/discord-example-app)** où est stocké le code de ce guide ainsi que d'autres exemples de code aux fonctionnalités spécifiques. +- **[discord-interactions](https://github.com/discord/discord-interactions-js)**, une bibliothèque qui fournit des types et des fonctions d'assistance pour les applications Discord. +- **[Express](https://expressjs.com)**, une infrastructure Web JavaScript populaire que nous allons utiliser pour créer un serveur où Discord peut nous envoyer les requêtes. +- **[Glitch](https://glitch.com/)**, un environnement en ligne qui simplifie la création et l'hébergement d'applications pendant les phases initiales de prototypage et de développement. Tu peux aussi développer en local avec un outil tel que **[ngrok](https://ngrok.com/)**. + + +--- + +## Étape 1 : création d'une application + +Pour commencer, tu dois créer une application sur le portail des développeurs si tu ne l'as pas déjà fait : + + + +Saisis un nom pour ton application, puis appuie sur **Créer**. + +Une fois ton application créée, tu arrives sur la page **Vue d'ensemble** de ses paramètres, où tu peux mettre à jour des informations de base relatives à ton application, telles que sa description et son icône. Tu y trouves également l'**identifiant de l'application** et l'**URL du point de terminaison des interactions**, qui nous serviront un peu plus loin dans le guide. + +### Configuration de ton bot + +Maintenant, nous allons configurer l'[utilisateur bot](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts) pour ton application, ce qui lui permet d'apparaître et de se comporter de façon semblable aux autres membres du serveur. + +Dans l'encadré de gauche, clique sur **Bot**. Depuis cette page, tu peux configurer des paramètres tels que ses [privileged intents](#DOCS_TOPICS_GATEWAY/privileged-intents) ou déterminer si d'autres utilisateurs peuvent l'installer. + + +Les intents déterminent les événements que Discord envoie à ton application lorsque tu crées une [connexion d'API Gateway](#DOCS_TOPICS_GATEWAY). Par exemple, si tu souhaites que ton application fasse quelque chose lorsque des utilisateurs ajoutent une réaction à un message, tu peux utiliser l'intent `GUILD_MESSAGE_REACTIONS` (`1 << 10`). + +Certains intents sont [privileged](#DOCS_TOPICS_GATEWAY/privileged-intents), ce qui signifie qu'ils permettent à ton application d'accéder à des données qui peuvent être considérées comme sensibles (comme le contenu des messages). Les privileged intent sont listés et peuvent être activés ou désactivés sur la page **Bot** dans les paramètres de ton application. Les standards intents, quant à eux, ne nécessitent aucune permission ou configuration supplémentaire. + +Tu peux obtenir plus d'informations sur les intents ainsi qu'une liste complète des intents disponibles, avec leurs événements associés, en consultant la [documentation de Gateway](#DOCS_TOPICS_GATEWAY/gateway-intents). + + +![Onglet Bot dans les paramètres de l'application](app-add-bot.png) + +Il existe également une section **Token** sur la page **Bot**, qui permet de copier le token de ton bot et de le réinitialiser si besoin. + +Les tokens de bot servent à autoriser les requêtes d'API et portent les permissions de ton utilisateur bot, ce qui les rend *hautement sensibles*. Tu ne dois *jamais* partager ton token ou l'inclure dans un système de contrôle de version. + +Copie le token et garde-le dans un endroit sûr (par exemple, dans un gestionnaire de mots de passe). + +> warn +> Tu ne pourras plus voir ton token à moins d'en générer un nouveau, alors conserve-le dans un endroit sûr. + +### Ajout de champs d'application et de permissions de bot + +Les applications doivent être approuvées par les utilisateurs qui les installent afin d'effectuer des actions dans Discord (comme la création d'une commande slash ou la récupération d'une liste des membres du serveur). Sélectionnons quelques champs d'application et permissions à demander avant l'installation de l'application. + + +Lors de la création d'une application, les champs d'application et permissions déterminent ce que ton application peut faire et ce à quoi elle peut accéder sur les serveurs Discord. + +- Les [champs d'application OAuth2](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) déterminent les accès aux données et actions que ton application peut effectuer. Elles sont accordées au nom de l'utilisateur qui procède à l'installation ou qui s'authentifie. +- Les [permissions](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) sont les permissions granulaires pour ton utilisateur bot, les mêmes que celles accordées aux autres utilisateurs dans Discord. Elles peuvent être approuvées par l'utilisateur qui procède à l'installation ou mises à jour ultérieurement dans les paramètres du serveur ou à l'aide d'[écrasements de permissions](#DOCS_TOPICS_PERMISSIONS/permission-overwrites). + + +Clique sur **OAuth2** dans l'encadré de gauche, puis sélectionne **générateur d'URL**. + +> info +> Le générateur d'URL crée un lien d'installation en fonction des champs d'application et permissions que tu as sélectionnées pour ton application. Tu peux utiliser ce lien pour installer l'application sur ton propre serveur, ou le partager avec d'autres personnes pour leur permettre de l'installer. + +Pour l'instant, ajoute deux champs d'application : +- `applications.commands` qui permet à ton application de générer des [commandes](#DOCS_INTERACTIONS_APPLICATION_COMMANDS). +- `bot` ajoute ton utilisateur bot. Une fois que tu as sélectionné `bot`, tu peux également sélectionner différentes permissions pour ton bot. Pour l'instant, coche uniquement **Envoyer des messages**. + +Tu peux consulter une liste de tous les [champs d'application OAuth2](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) ou en apprendre davantage sur les [permissions](#DOCS_TOPICS_PERMISSIONS) dans la documentation. + +### Installation de ton application + +Après avoir ajouté des champs d'application, tu devrais voir apparaître une URL que tu peux copier afin d'installer ton application. + +![Capture d'écran du générateur d'URL](url-generator.png) + +> info +> Pendant le développement d'une application, il est conseillé de la développer et de la tester sur un serveur qui n'est pas utilisé par d'autres personnes. Si tu ne disposes pas déjà de ton propre serveur, tu peux en [créer un gratuitement](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server-). + +Copie l'URL générée précédemment, puis colle-la dans ton navigateur. Tu recevras des explications pour chaque étape du processus d'installation, au cours duquel tu devras vérifier que tu installes ton application sur un serveur qui te permettra de la développer et de la tester. + +Une fois ton application installée, tu peux te rendre sur ton serveur pour vérifier qu'elle a bien été intégrée ✨ + +Maintenant que ton application est configurée et installée, commençons son développement. + +--- + +## Étape 2 : exécution de ton application + +L'intégralité du code utilisé dans cet exemple d'application est disponible dans [le dépôt GitHub](https://github.com/discord/discord-example-app). + +Pour simplifier un peu le développement, l'application utilise [discord-interactions](https://github.com/discord/discord-interactions-js), qui fournit des types et des fonctions d'assistance. Si tu préfères utiliser d'autres langages ou bibliothèques, tu peux consulter la documentation des [ressources de la communauté](#DOCS_TOPICS_COMMUNITY_RESOURCES). + +### Remixage du projet + +Ce guide utilise Glitch, qui permet de cloner et de développer depuis ton navigateur. Si tu préfères développer ton application en local, des instructions relatives à l'utilisation de ngrok sont disponibles [dans le LISEZMOI](https://github.com/discord/discord-example-app#running-app-locally). + +> info +> Glitch est un excellent outil de développement et de test, mais [il présente certaines contraintes techniques](https://help.glitch.com/kb/article/17-technical-restrictions/) et il convient donc d'envisager d'autres fournisseurs d'hébergement pour les applications déjà en production. + +Pour commencer, **[remixe (ou clone) le projet Glitch 🎏](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)**. + +Une fois ceci fait, Glitch te redirigera vers un nouveau projet. + + +![Vue d'ensemble de projet Glitch](glitch-project.png) + +- Le **nom de projet** est un nom spécifique à ton projet, et se trouve dans le coin supérieur gauche de l'interface. +- **`.env`** est le fichier dans lequel est stocké l'ensemble de tes informations d'identification pour ton application. +- Les **Logs** présentent les données de sortie de ton projet, ce qui est utile pour savoir si l'application est en cours d'exécution ou pour obtenir des informations sur les erreurs détectées. +- Le bouton **Share** dans le coin supérieur droit de l'interface permet d'accéder à l'URL active du projet, dont tu auras besoin pour mettre en place l'interactivité dans la suite de ce guide. + + +#### Structure du projet + +Tous les fichiers du projet se trouvent dans l'encadré de gauche de ton projet Glitch. Voici une vue d'ensemble des principaux dossiers et fichiers : + +``` +├── examples -> exemples d'applications courtes aux fonctionnalités spécifiques +│ ├── app.js -> code app.js terminé +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> tes informations d'identification et identifiants +├── app.js -> point d'entrée principal de l'application +├── commands.js -> payloads des commandes slash + fonctions d'assistance +├── game.js -> logique spécifique à pierre-feuille-ciseaux +├── utils.js -> fonctions utilitaires et énumérations +├── package.json +├── README.md +└── .gitignore +``` + +### Ajout d'informations d'identification + +Ton fichier `app.js` contient déjà du code, mais tu auras besoin de ton identifiant et de ton token d'application pour effectuer des requêtes. Toutes tes informations d'identification peuvent être stockées directement dans le fichier `.env`. + +Tout d'abord, copie le token de l'utilisateur bot que tu as précédemment configuré, et copie-le dans la variable **`DISCORD_TOKEN`** de ton fichier `.env`. + +Ensuite, rends-toi sur la page **Vue d'ensemble** de ton application, et copie l'**identifiant de l'application « APP_ID »** ainsi que sa **clé publique « PUBLIC_KEY »**. Colle-les dans les variables **`APP_ID`** et **`PUBLIC_KEY`** de ton fichier `.env`. + +Maintenant que tes informations d'identification sont configurées, installons et gérons des commandes slash. + +### Installation de commandes slash + +> info +> Pour installer des commandes slash, l'application utilise [`node-fetch`](https://github.com/node-fetch/node-fetch). Tu peux voir l'implémentation pour l'installation dans le fichier `utils.js` à l'intérieur de la fonction `DiscordRequest()`. + +Le projet contient un script `register` que tu peux utiliser pour installer les commandes dans la section `ALL_COMMANDS`, qui est définie à la fin du fichier `commands.js`. Il installe les commandes en tant que commandes globales en appelant le point de terminaison [`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands) de l'API HTTP. + +Si tu souhaites personnaliser les commandes ou en ajouter d'autres, tu peux consulter la structure des commandes dans la [documentation des commandes](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure). + +Pour exécuter le script `register`, clique sur le bouton **Terminal** en bas de l'interface du projet Glitch et colle la commande suivante : + +``` +npm run register +``` + +Appuie sur la touche Entrée pour exécuter la commande. + +Si tu retournes sur ton serveur, tu devrais voir apparaître les commandes slash. Mais il ne se passera rien si tu essaies de les exécuter, car ton application ne reçoit et ne traite aucune requête de Discord. + + +Discord propose deux API que tu peux combiner pour créer des applications : + +- L'**[API HTTP](#DOCS_REFERENCE/http-api)** est une API similaire à une API REST qui permet d'effectuer des opérations générales telles que l'envoi et la mise à jour de données dans Discord, ou la récupération de données relatives à une ressource. +- L'**[API Gateway](#DOCS_REFERENCE/gateway-websocket-api)** est une API basée sur WebSocket qui est utile pour maintenir l'état ou suivre les événements qui se produisent sur un serveur Discord. Nous n'utiliserons pas cette API dans ce guide, mais si tu veux en savoir plus sur la création d'une connexion Gateway et sur les différents événements que tu peux suivre, consulte la [documentation de Gateway](#DOCS_TOPICS_GATEWAY). + + +--- + +## Étape 3 : gestion de l'interactivité + +Pour permettre à ton application de recevoir des requêtes de commande slash (et d'autres interactions), Discord a besoin d'une URL publique pour les envoyer. Cette URL peut être configurée dans les paramètres de ton application en tant qu'**URL de point de terminaison des interactions**. + +### Ajout d'une URL de point de terminaison des interactions + +Les projets Glitch disposent d'une URL publique exposée par défaut. Pour copier l'URL de ton projet, clique sur le bouton **Share** dans le coin supérieur droit de l'interface, puis copie le lien du projet « Live site » en bas de la fenêtre qui vient de s'ouvrir. + +> info +> Si tu développes en local, tu trouveras des instructions expliquant comment établir un protocole de tunnellisation des requêtes vers ton environnement local [dans le LISEZMOI de GitHub](https://github.com/discord/discord-example-app#running-app-locally). + +Une fois le lien copié, va dans les paramètres de ton application depuis [le portail des développeurs](https://discord.com/developers/applications). + +Sur la page **Informations générales** de ton application, tu trouveras une option **URL de point de terminaison interactive**. Tu peux y coller l'URL de ton application suivie de `/interactions`, ce qui correspond à l'endroit où l'application Express écoute les requêtes. + +![URL de point de terminaison des interactions dans les paramètres de l'application](interactions-url.png) + +Clique sur **Sauvegarder les modifications** et assure-toi que la vérification de ton point de terminaison a réussi. + +L'exemple d'application gère la vérification de deux façons : +- Elle utilise la `PUBLIC_KEY` et le [package discord-interactions](https://github.com/discord/discord-interactions-js#usage) avec une fonction wrapper (importée de `utils.js`) qui la rend conforme à l'interface `verify` d'[Express](http://expressjs.com/en/5x/api.html#express.json). Ceci est exécuté pour chaque requête entrante de votre application. +- Elle répond aux requêtes de `PING` entrantes. + +Pour en savoir plus sur la préparation de ton application à la réception d'interactions, consulte [la documentation sur les interactions](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction). + +### Gestion des requêtes de commandes slash + +Après la vérification de ton point de terminaison, ouvre le fichier `app.js` de ton projet et trouve le bloc de code qui gère la commande `/test` : + +```javascript +// commande « test » +if (name === 'test') { + // Envoi d'un message dans le salon à partir duquel la commande a été déclenchée + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Sélectionne un émoji aléatoire à envoyer à partir d'une fonction d'assistance + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +Le code ci-dessus répond à l'interaction en envoyant un message dans le salon duquel il est issu. La liste de tous les types de réponses disponibles, comme une réponse dans une fenêtre, est détaillée [dans la documentation](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type). + +> info +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE` est une constante [exportée depuis le package `discord-interactions`](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33). + +Va sur ton serveur et vérifie le bon fonctionnement de la commande slash `/test` de ton application. Lorsque tu déclenches la commande, ton application doit t'envoyer un message contenant « hello world » accompagné d'un émoji aléatoire. + +Dans la section suivante, nous allons ajouter une commande supplémentaire qui utilise des options de commande slash, des boutons et des menus de sélection pour créer le jeu pierre-feuille-ciseaux. + +--- + +## Étape 4 : ajout d'éléments de message + +La commande `/defi` permet de lancer notre jeu pierre-feuille-ciseaux. Quand cette commande est déclenchée, l'application envoie des éléments de message dans le salon, et ceux-ci guident les utilisateurs qui veulent jouer. + +### Ajout d'une commande avec des options + +La commande `/defi`, appelée `CHALLENGE_COMMAND` dans `commands.js`, dispose d'un ensemble d'`options`. Dans notre application, les options sont des objets qui représentent différentes choses qu'un utilisateur peut sélectionner lors d'une partie de pierre-feuille-ciseaux, et sont générées en utilisant les clés `RPSChoices` dans `game.js`. + +Tu peux en apprendre davantage sur les options de commande et leur structure [en consultant la documentation](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure). + +> info +> Ce guide ne traite pas en profondeur du fichier `game.js`, mais n'hésite pas à y jeter un coup d'œil et à modifier les commandes ou leurs options. + + + +Pour gérer la commande `/defi`, ajoute le code suivant après le bloc if `if name === “test”` : + +```javascript +// commande « defi » +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // Choix d'objet de l'utilisateur + const objectName = req.body.data.options[0].value; + + // Création d'une partie active en utilisant l'identifiant de message comme identifiant de partie + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // Ajout de l'identifiant de partie à utiliser ultérieurement + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> info +> Si tu ne vois pas où coller ce code, tu peux consulter le code complet dans `examples/app.js` dans le projet Glitch ou dans le fichier `app.js` à la racine [sur GitHub](https://github.com/discord/discord-example-app/blob/main/app.js). + +Le code ci-dessus fait plusieurs choses : +1. Il analyse le corps de la requête pour extraire l'identifiant de l'utilisateur qui a déclenché la commande slash (`userId`) ainsi que l'option (choix d'objet) sélectionnée (`objectName`). +2. Il ajoute un nouveau nom de partie à l'objet `activeGames` en utilisant l'identifiant d'interaction. La partie active enregistre le `userId` et le `objectName`. +3. Il renvoie un message dans le salon avec un bouton doté d'un `custom_id` de type `accept_button_`. + +> warn +> L'exemple de code utilise un objet comme stockage en mémoire, mais pour les applications en production, il est préférable d'utiliser une base de données. + +Lors de l'envoi d'un message avec des [éléments de message](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component), les payloads individuels sont annexés à un tableau `components`. Les éléments actionnables (tels que les boutons) doivent être inclus dans une [ligne d'action](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows), que tu peux voir dans l'exemple de code. + +Observe le `custom_id` unique envoyé avec les éléments de message, ici `accept_button_` avec l'identifiant de partie active en annexe. Un `custom_id` peut être utilisé pour gérer les requêtes que Discord t'envoie lorsque quelqu'un interagit avec l'élément, ce que tu verras dans un moment. + +Désormais, lorsque tu exécutes la commande `/defi` et sélectionnes une option, ton application envoie un message avec un bouton **Accepter**. Ajoutons du code pour gérer le clic sur le bouton. + + + + + +Lorsque des utilisateurs interagissent avec un élément de message, Discord envoie une requête avec un [type d'interaction](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) égal à `3` (ou la valeur `MESSAGE_COMPONENT` lors de l'utilisation de `discord-interactions`). + +Pour mettre en place un gestionnaire pour le bouton, nous allons vérifier le `type` d'interaction, puis le `custom_id`. + +Colle le code suivant sous le gestionnaire de type pour `APPLICATION_COMMAND` : + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id défini dans le payload lors de l'envoi de l'élément de message +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // récupération de l'identifiant de partie associé + const gameId = componentId.replace('accept_button_', ''); + // Suppression du message avec le token dans le corps de la requête + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Sélectionne un émoji aléatoire à envoyer à partir d'une fonction d'assistance + content: 'What is your object of choice?', + // Indique qu'il s'agit d'un message éphémère + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Annexe l'identifiant de partie + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Suppression du message précédent + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +Le code ci-dessus : +1. Vérifie qu'il existe un identifiant personnalisé `custom_id` correspondant à ce que nous avons envoyé précédemment (ici, il commence par `accept_button_`). L'identifiant personnalisé comprend également l'identifiant de partie active en annexe, donc nous le stockons dans `gameID`. +2. [Supprime le message d'origine](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response) en appelant un webhook avec `node-fetch` et en passant le `token` d'interaction unique dans le corps de la requête. Cette opération permet de nettoyer le salon pour éviter que d'autres utilisateurs ne cliquent sur le bouton. +3. Répond à la requête en envoyant un message contenant un menu de sélection avec les choix d'objets pour le jeu. Le payload devrait être assez similaire au précédent, à l'exception du tableau `options` et du `flags: 64`, [qui indique que le message est éphémère](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message). + +Le tableau `options` est peuplé en utilisant la méthode `getShuffledOptions()` dans `game.js`, qui manipule les valeurs `RPSChoices` pour être conforme au format des [options des éléments de message](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure). + + + + + +La dernière chose à ajouter est le code permettant de gérer les interactions avec le menu de sélection et d'envoyer le résultat de la partie dans le salon. + +Comme les menus de sélection sont également des éléments de message, le code qui gère leurs interactions est presque identique au code des boutons. + +Modifie le code ci-dessus pour gérer le menu de sélection : + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id défini dans le payload lors de l'envoi de l'élément de message +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // récupération de l'identifiant de partie associé + const gameId = componentId.replace('accept_button_', ''); + // Suppression du message avec le token dans le corps de la requête + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Sélectionne un émoji aléatoire à envoyer à partir d'une fonction d'assistance + content: 'What is your object of choice?', + // Indique qu'il s'agit d'un message éphémère + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Annexe l'identifiant de partie + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Suppression du message précédent + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // récupération de l'identifiant de partie associé + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // Obtention de l'identifiant d'utilisateur et du choix d'objet de l'utilisateur qui répond + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // Calcul du résultat à l'aide d'une fonction d'assistance + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // Suppression de la partie du stockage + delete activeGames[gameId]; + // Mise à jour du message avec le token dans le corps de la requête + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // Envoi des résultats + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // Mise à jour du message éphémère + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +Comme le code précédent, le code ci-dessus obtient l'identifiant de l'utilisateur et sa sélection d'objet à partir de la demande d'interaction. + +Ces informations, ainsi que l'identifiant et la sélection de l'utilisateur d'origine stockés dans l'objet `activeGames`, sont transmises à la fonction `getResult()`. `getResult()` détermine le vainqueur, puis crée une chaîne lisible à renvoyer dans le salon. + +Nous appelons également un autre webhook, cette fois-ci pour [mettre à jour le message éphémère de suivi](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message) puisqu'il ne peut pas être supprimé. + +Enfin, les résultats sont envoyés dans le salon en utilisant le type de réponse d'interaction `CHANNEL_MESSAGE_WITH_SOURCE`. + + + +… et voilà 🎊 Il ne te reste plus qu'à tester ton application pour vérifier que tout fonctionne. + +--- + +## Étapes suivantes + +Félicitations, tu viens de créer ta première application Discord ! 🤖 + +Nous espérons que tu en sais maintenant un peu plus sur les applications Discord, leur configuration et la manière de les rendre interactives. Tu peux désormais poursuivre le développement de ton application ou explorer les autres possibilités qui s'offrent à toi : +- Lire **[la documentation](#DOCS_INTRO)** pour en savoir plus sur les fonctionnalités des API +- Parcourir le dossier `examples/` de ce projet pour y trouver des exemples de code courts aux fonctionnalités spécifiques +- Explorer les **[ressources de la communauté](#DOCS_TOPICS_COMMUNITY_RESOURCES)** pour découvrir des outils spécifiques à un langage maintenus par les membres de la communauté +- Lire notre tutoriel sur [l'hébergement d'applications Discord sur Cloudflare Workers](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS) +- Rejoindre le **[serveur Discord Developers](https://discord.gg/discord-developers)** pour poser des questions sur les API, participer à des événements organisés par l'équipe API de Discord, et interagir avec d'autres développeurs diff --git a/docs/game_and_server_management/Alpha_and_Beta_Testing.md b/docs/game_and_server_management/Alpha_and_Beta_Testing.md deleted file mode 100644 index ef18f08679..0000000000 --- a/docs/game_and_server_management/Alpha_and_Beta_Testing.md +++ /dev/null @@ -1,52 +0,0 @@ -# Alpha and Beta Testing - -Alphas and betas are a critical part of a game's development lifecycle. We understand the value of getting feedback early and often and involving your community early on. That's why we've built some awesome alpha and beta testing functionality for you! - -## Beta Entitlements - -As you develop your game, you'll constantly be making improvements. You want real-time feedback from players, and there's no better place for that than Discord. In the past, players would need to dig through menus to find out how to unlock test branches, as well as remembering secret passwords _and_ typing them in correctly. Was that an `I` or an `l`? `O` or `0`? - -One of the cool features of [Store Channels](#DOCS_GAME_AND_SERVER_MANAGEMENT_SPECIAL_CHANNELS/) is their ability to grant a Beta Entitlement for your game. That means that while you keep your master branch safe and sound, users can test on `beta-branch-please-ignore-bugs` in an isolated test environment. - -> info -> To learn more about creating branches, start with [Dispatch and You](#DOCS_DISPATCH_DISPATCH_AND_YOU/). - -When you create a store channel in your server, you'll be prompted with a choice to make it a Beta channel. That will allow you to grant users entitlement to the non-master branch of your game when visiting the store page. When your beta period is over and your game is ready for release and purchase, you can brick/delete these branches if you choose, and prompt users to get the full game by putting up a new store channel that's not Beta. - -> warn -> Beta branches cannot be sold. If a user has access to a store channel for a beta entitlement, they will be able to claim it for free. - -## Role-Based Entitlement - -So, you've started getting a bunch of fans into your server. Hundreds, thousands, millions! Uh, if you hit millions, let us know. Within your hordes of adoring fans lies your Trusted Testing Group (tm), the best of the best when it comes to feedback. Maybe you want to give them access to a special `insider-only-private-beta` branch of your game. You can, with role-based entitlement! - -Store channels in Discord are just like any other channel in that they can have a set of permissions applied to them. What is special about them is that if they are set as a Beta branch, entitlement to that branch is tied to having permissions to view the channel. So, all your testers with a `Beta Tester` role, for example, will be able to get entitlement to the `insider-only-private-beta` branch. And, if they are later removed from that role, entitlement from that branch will be removed. - -A scenario might look like this: you create a Beta store channel. Only users with role `Awesome Tester` can view it. Player A is an `Awesome Tester`. They can view the channel and get entitlement to the beta branch. Player A becomes inactive; you remove them from the `Awesome Tester` role. Player A loses entitlement to `insider-only-private-beta` - -> danger -> Role-based entitlement will only work if you use Discord's DRM, which is a simple entitlement check. You can do that with the Dispatch command [`dispatch build drm-wrap`](#DOCS_DISPATCH_LIST_OF_COMMANDS/build-drmwrap) or by calling [`ApplicationManager.ValidateOrExit()`](#DOCS_GAME_SDK_APPLICATIONS/validateorexit). Otherwise, Discord will not check the user's entitlement when the game starts. - -Role-based entitlements help keep your beta community active and interactive, while also providing a way to reward your biggest fans with secret access to special things. - -## Gift Codes - -> warn -> Note that only Approved Games can generate gift codes. - -If you want to push out access to your game at scale, rather than inviting people into your server and giving them a role, you can create gift codes in the Developer Portal! Gift codes are like game keys on other platforms that you might be familiar with, with an added bonus: the ability to specify the entitlement time window. That means that you can create codes for your game to give to everyone, but they won't be able to play until the `VALID FROM` date. Similarly, you can set a `VALID UNTIL` date on all your gift codes if you want the entitlements to expire after a certain time, removing access from players. - -Note that the `VALID UNTIL` date will not remove the game from the user's library, but they will no longer be able to launch it. - -Up to 25,000 gift codes can be created at a time. When you go to create gift codes, you'll notice there are a few fields for you to fill out. Here's what they mean: - -![Screenshot of the modal to create gift codes with on the developer dashboard](gift-code-creation.png) - -- SKU: the SKU that you want the user to get -- Branch: the branch of your game you want the user to get -- Valid From: the start date at which the entitlement is valid -- Valid Until: the date at which the entitlement is no longer valid -- Amount: the number of codes you want to create (up to 25,000 per batch) -- Description: a short description of why you made the codes, so you remember! - -Once you've made your codes, you can download the `.csv` that has them all in it, and distribute them however you'd like! diff --git a/docs/game_and_server_management/How_to_Get_Your_Game_on_Discord.md b/docs/game_and_server_management/How_to_Get_Your_Game_on_Discord.md deleted file mode 100644 index 0e709c0a80..0000000000 --- a/docs/game_and_server_management/How_to_Get_Your_Game_on_Discord.md +++ /dev/null @@ -1,110 +0,0 @@ -# How to Get Your Game on Discord - -> danger -> Selling SKUs on Discord has been discontinued as of March 1, 2022. [Read here for more info.](https://support-dev.discord.com/hc/en-us/articles/6309018858647-Self-serve-Game-Selling-Deprecation) - -Welcome, adventurer! If you're here, you want to find out how to get your game up and running on Discord and learn about our awesome Server Commerce features. You've come to the right place, so let's get started. - -## Get the Band Back Together - -First things first: it's time to make a Team. Your dream team of artists, writers, engineers, designers, all working on the beautiful creation of Your Game. Build your dream team with these steps: - -1. Create a new Team at [https://discord.com/developers/teams](https://discord.com/developers/teams) -2. Invite people! - -You've now passed the first test with flying colors! - -## Apps and Games - -Throughout this process, we'll reference your "app". An app, or application, is an entity on Discord that represents something you've built: a bot, an OAuth2 app, or in this case your game. We need to make an app for your game: - -1. Create a new app at [https://discord.com/developers/applications](https://discord.com/developers/applications) -2. When doing so, make sure you select your team from the `Team` dropdown - -> info -> All apps on Discord for games must be owned by a team. If you accidentally made a personal app, you can transfer it to a team at any time by hitting the `Transfer App to Team` button within the app. - -You're now looking at a blank slate of creativity. Give your game a pretty icon and exciting description here. Next, click on `Server Commerce Checklist` in the sidebar, and we'll get to the good stuff. - -## Join the Club - -From here on forward, we'll be managing settings that tie directly to your game and its presence on Discord. We want to make sure that we're laser-focused on making the best experience possible for game developers, so we ask that you pay our Application License Fee in order to get access to our store tools, which let you: - -- make store pages for your game directly in your server -- run alpha and beta tests for your game, using the magic of channel permissions to create role-based page access -- apply for approval, letting you start making money (if you want to) - -Now that we've weeded out the trolls, let's get your server up and running with some fancy new features! - -## Your Server - Your Kingdom - -You're now looking at a checklist with a bunch of items and a prompt to select a server. Your Application License Fee entitles you to the following features in your server: - -- store channel creation -- alpha and beta testing - -Select the server that you wish to grant these features, confirm to be double-extra-super-sure, and poof! You can now create channels for both news and store pages in your server. To learn more about store page channels, read [Store Channels](#DOCS_GAME_AND_SERVER_MANAGEMENT_SPECIAL_CHANNELS/store-channels). To learn more about Announcement Channels, read [Announcement Channels](#DOCS_GAME_AND_SERVER_MANAGEMENT_SPECIAL_CHANNELS/announcement-channels). To learn about alpha and beta testing, read [Alpha and Beta Testing](#DOCS_GAME_AND_SERVER_MANAGEMENT_ALPHA_AND_BETA_TESTING/) -(you get the gist). - -Now, what do you do next? You start building! Build your community, make your game, invite testers into your server to get hype! Now is a great time to get familiar with all the tools at your disposal like: - -- [Discord's Developer Portal](https://discord.com/developers/applications), your one-stop-game-management-shop -- [The Discord Game SDK](#DOCS_GAME_SDK_SDK_STARTER_GUIDE/), a spellbook full of useful game dev incantations including Discord's crystal-clear voice chat -- [Dispatch](#DOCS_DISPATCH_DISPATCH_AND_YOU/), Discord's game patcher and downloader that's so fast, you'll swear it's magic - -To guide you through this process to success, you can follow that handy checklist. It'll tell you the steps you need to complete, show you where and how to do them, and give you a blissful sense of satisfaction as the green check marks pile up. - -The next and final step in your on-boarding journey is getting approved. Once approved, you'll be able to start making money (or karma), and you'll unlock a ton of cool server customization features to make your kingdom cozy for your players. - -## Testing Your Game - -As you go through the process of building your game and getting it ready for release on Discord, you'll want to be able to test it! One way to do so is to utilize Beta Store channels, which you can learn more about here: [Alpha and Beta Testing](#DOCS_GAME_AND_SERVER_MANAGEMENT_ALPHA_AND_BETA_TESTING/). - -If you are on the Team that owns the game, you can also use another special system for testing that we call Application Test Mode. Test Mode allows you to purchase unavailable, unlisted SKUs for free, making it helpful for testing IAP flows. It also automatically makes every branch of your game show up in your Library when Test Mode is turned on. You can read more here: [Application Test Mode](#DOCS_GAME_SDK_STORE/application-test-mode). - -## Getting Approved - -Your game looks wonderful. You've got a beautiful store page, and awesome game, and an eager community. It's time to get approved and plant your flag. Note that if your game is in an alpha or beta state, or you're interesting in Early Access, you are welcome to apply for approval whenever you are ready. Your game doesn't need to be the finished 1.0 version; give us something you'd feel comfortable giving to your players. - -Once you've completed all the items on your checklist, the `Get Approved` button will unlock. Once you submit for approval, Discord will take a look at the following things: - -- your game, to ensure that it runs properly and follows our [Game Submission Guidelines](https://support-dev.discord.com/hc/en-us/articles/360025028592-Game-Submission-Guidelines) -- your store pages, to provide helpful guidance in putting your best foot forward -- your server, to make sure you're abiding by our [Community Guidelines](https://discord.com/guidelines) - -If we need to see some changes, you'll receive an email directing you on your steps to success. Otherwise, you'll get **APPROVED!!!!!!!!!!** What's that mean? It means you can start charging for your game and making money! Don't spend it all in one place. Or do. Treat yourself. Or maybe you want your game to be **free!** Live your best life. We support you! - -## Available vs Store Page Published - -Now that you've been approved, there's a couple new toggles to flip in the Developer Portal: `Available`, and `Store Page Published`. - -![Screenshot of the SKU information page with the "available" and "store page published" switches highlighted](available-published.png) - -`Available` means that your game is now available for normal purchase/distribution; your non-beta store channel will no longer say `Coming soon!` when this is toggled, and users will be able to get your game. - -> danger -> Toggling your SKU as `Available` will make it available for purchase; make sure your price is set properly! - -If you no longer wish to make your SKU available for sale, you can again mark it unavailable. This will not remove it from users' libraries; it just stops new users from purchasing it. - -`Store Page Published` will do...well, what it says! Though your store page is always visible from within the channel in your server, there are other things that require you to explicitly mark your page viewable from outside that context, like gift code embeds for your game, or from in-game store fronts! - -TL;DR - When you're ready to distribute your game after getting approved, turn those two toggles on. - -## Getting Verified and Discovered - -Apart from being approved, you can also get your server Verified. Getting verified means your server will get that oh-so-exclusive checkmark, to let people know you're the legit home for your game. - -To get verified, head on over to our [Verification page](https://discord.com/verification) and fill out the form at the bottom. - -## Make Good Decisions - -Your game is off and running, and we couldn't be more proud. As it flourishes and your playerbase grows, keep an eye on your analytics, which you can find within your app. They'll give you important insight like revenue data, acquisitions funnels, and player retention to help you make informed decision about your game's lifecycle. Check out our [Analytics Help Article](https://support-dev.discord.com/hc/en-us/articles/360024852152) to learn more about how to read all those charts, and how to do things like [Conversion Tracking with UTM Links](https://support-dev.discord.com/hc/en-us/articles/360025153051-How-to-track-conversions-with-UTM-links). - -## What Comes Next - -Your game's success is in your own hands now. Continue to build your community and keep them informed with updates. Consider integrating more deeply with Discord to deliver cool features to your players; we recommend [Rich Presence Game Invites](#DOCS_GAME_SDK_ACTIVITIES/). They feel like magic. Drop new content by creating DLC and IAP for your game, run fun tournaments based on [HypeSquad Membership](#DOCS_GAME_SDK_USERS/currentuserhasflag), give something cool to [Discord Nitro Subscribers](#DOCS_GAME_SDK_USERS/getcurrentuserpremiumtype) because they're awesome. Or maybe, just maybe, think about your next upcoming game? - -We'd love to help you with that one, too. - --- Discord <3 diff --git a/docs/game_and_server_management/Special_Channels.md b/docs/game_and_server_management/Special_Channels.md deleted file mode 100644 index b61a2ca5cf..0000000000 --- a/docs/game_and_server_management/Special_Channels.md +++ /dev/null @@ -1,38 +0,0 @@ -# Store Channels - -> danger -> Selling SKUs on Discord has been discontinued as of March 1, 2022. [Read here for more info.](https://support-dev.discord.com/hc/en-us/articles/6309018858647-Self-serve-Game-Selling-Deprecation) - - -One of the new flagship features of Verified Servers and Game Servers are the ability to host your store pages directly in your server. We know that community is everything for games, and that your server is already the place where your community lives. Rather than the friction and impersonality of traditional storefronts, you can let your fans find your game in the cozy comfort of their home (your server!). - -In order to create a store channel for your game, you'll need to make sure you've followed [the Walkthrough](#DOCS_GAME_AND_SERVER_MANAGEMENT_HOW_TO_GET_YOUR_GAME_ON_DISCORD/) up to `Getting Approved`. If you've done that, you'll see in your server that you can create a new channel type: `Store`. - -![Screenshot of the modal to create a new Store Channel](create-store-channel.png) - -Along with entering a name for your new channel, you'll be prompted to select an application. This should be the app you created when you started; it's the one linked to your server. After selecting your app, you'll be prompted to select a SKU. What's a SKU? A SKU is simply a thing that a user can buy. This is most likely your game (a SKU of type `Game`), but could also be `IAP`, `DLC`, or a `Bundle`. - -You can create SKUs to put up for sale by going to your app and selecting `SKU Management`. - -![Screenshot of the SKU Management dashboard](sku-management.png) - -Once you select your SKU and create your channel...it's there! You now have a store channel in your server! If you want, you can set permissions on this channel like any channel in a server to restrict who can see it. Learn more about that by reading [Alpha and Beta Testing](#DOCS_GAME_AND_SERVER_MANAGEMENT_ALPHA_AND_BETA_TESTING/). - -## Lurker Mode - -Store channels also have a special property that we call `lurkability`. "Lurker Mode" is a feature that we've been experimenting with throughout Discord; it allows users to read public channels in a server without _actually_ joining the server. It also allows users to look at these channels without being logged in to Discord. - -> info -> Users viewing channels in Lurker Mode will not be able to send messages in those channels. They'll be prompted to log in and join the server if they want to chat. - -Lurker Mode is automatically enabled for store channels in your server. When someone accepts a server invite that links to a store channel, they'll be viewing in "Lurker Mode". - -We know that your server and community are at the heart of your game's success on Discord. Having Discord users see your store pages in the context of your server will help drive more members to your community and help you grow that awesome fanbase for your game. - -# Announcement Channels - -As part of our ongoing effort to help you build your game community, all [Community servers](https://dis.gd/communityservers) have the ability to create Announcement Channels! - -Unlike a regular text channel, Announcement Channels comes with a “Follow” button that allows your superfans to hook and connect your channel into their own personal servers. Now, select messages in your Announcement Channels can be "published" in your players' friend servers as regular messages, allowing them to get the latest updates of their favorite game in the places they hang out most. Because these posts appear and function as messages, it means that everyone in your superfan’s server can find them, discuss them live, and receive them as mobile notifications, if they have this setting enabled. - -[Learn more here](https://support.discord.com/hc/en-us/articles/360032008192). diff --git a/docs/game_sdk/Achievements.md b/docs/game_sdk/Achievements.md index f444b0fd8e..fa59edd449 100644 --- a/docs/game_sdk/Achievements.md +++ b/docs/game_sdk/Achievements.md @@ -22,7 +22,7 @@ You can also mark achievements as `secret` and `secure`. "Secret" achievements w ###### Achievement Struct | name | type | description | -| ------------------------- | --------------------------------------------------------------------- | ---------------------------------------------------- | +|---------------------------|-----------------------------------------------------------------------|------------------------------------------------------| | application_id | Int64 | Unique ID of the application | | name | string | Name of the achievement | | name_localizations | ?dictionary with keys as [available locales](#DOCS_REFERENCE/locales) | Localization dictionary for the `name` field | @@ -36,7 +36,7 @@ You can also mark achievements as `secret` and `secure`. "Secret" achievements w ###### User Achievement Struct | name | type | description | -| --------------- | ------ | ------------------------------------------------------------------------------------------ | +|-----------------|--------|--------------------------------------------------------------------------------------------| | UserId | Int64 | the unique ID of the user working on the achievement | | AchievementId | Int64 | the unique ID of the achievement | | PercentComplete | UInt8 | how far along the user is to completing the achievement (0-100) | @@ -51,7 +51,7 @@ Returns `Discord.Result` via callback. ###### Parameters | name | type | description | -| --------------- | ----- | -------------------------------------- | +|-----------------|-------|----------------------------------------| | achievementId | Int64 | the ID of the achievement to update | | percentComplete | UInt8 | the user's updated percentage progress | @@ -124,7 +124,7 @@ Returns `Discord.UserAchievement` ###### Parameters | name | type | description | -| ----- | ----- | ----------------------------------------- | +|-------|-------|-------------------------------------------| | index | Int32 | the index at which to get the achievement | ###### Example @@ -153,7 +153,7 @@ Gets the user achievement for the given achievement id. If you keep a hardcoded ###### Parameters | name | type | description | -| ------------- | ----- | -------------------------------- | +|---------------|-------|----------------------------------| | achievementId | Int64 | the ID of the achievement to get | ###### Example @@ -179,7 +179,7 @@ Fires when an achievement is updated for the currently connected user ###### Parameters | name | type | description | -| ----------- | ------------------- | -------------------------------- | +|-------------|---------------------|----------------------------------| | achievement | ref UserAchievement | the achievement that was updated | ## The API Way @@ -246,7 +246,7 @@ Creates a new achievement for your application. Applications can have a maximum ###### Parameters | name | type | description | -| ----------- | --------- | --------------------------------------- | +|-------------|-----------|-----------------------------------------| | name | string | the name of the achievement | | description | string | the user-facing achievement description | | secret | bool | if the achievement is secret | @@ -294,7 +294,7 @@ Updates the achievement for **\_\_ALL USERS\_\_**. This is **NOT** to update a s ###### Parameters | name | type | description | -| ----------- | --------- | --------------------------------------- | +|-------------|-----------|-----------------------------------------| | name | string | the name of the achievement | | description | string | the user-facing achievement description | | secret | bool | if the achievement is secret | @@ -352,7 +352,7 @@ Updates the UserAchievement record for a given user. Use this endpoint to update ###### Parameters | name | type | description | -| ---------------- | ---- | ------------------------------------------------------ | +|------------------|------|--------------------------------------------------------| | percent_complete | int | the user's progress towards completing the achievement | ###### Return Object diff --git a/docs/game_sdk/Activities.md b/docs/game_sdk/Activities.md index ba72cab4bc..91ddbba46e 100644 --- a/docs/game_sdk/Activities.md +++ b/docs/game_sdk/Activities.md @@ -12,7 +12,7 @@ For more detailed information and documentation around the Rich Presence feature ###### User Struct | name | type | description | -| ------------- | ------ | ----------------------------- | +|---------------|--------|-------------------------------| | Id | Int64 | the user's id | | Username | string | their name | | Discriminator | string | the user's unique discrim | @@ -22,7 +22,7 @@ For more detailed information and documentation around the Rich Presence feature ###### Activity Struct | name | type | description | -| ------------- | ------------------ | --------------------------------------------------------------- | +|---------------|--------------------|-----------------------------------------------------------------| | ApplicationId | Int64 | your application id - this is a read-only field | | Name | string | name of the application - this is a read-only field | | State | string | the player's current party status | @@ -36,37 +36,37 @@ For more detailed information and documentation around the Rich Presence feature ###### ActivityTimestamps Struct | name | type | description | -| ----- | ----- | ------------------------------------------------------ | +|-------|-------|--------------------------------------------------------| | Start | Int64 | unix timestamp - send this to have an "elapsed" timer | | End | Int64 | unix timestamp - send this to have a "remaining" timer | ###### ActivityAssets Struct -| name | type | description | -| ---------- | ------ | ------------------------------------------------------------------------------------- | +| name | type | description | +|------------|--------|----------------------------------------------------------------------------------------------| | LargeImage | string | see [Activity Asset Image](#DOCS_TOPICS_GATEWAY_EVENTS/activity-object-activity-asset-image) | -| LargeText | string | hover text for the large image | +| LargeText | string | hover text for the large image | | SmallImage | string | see [Activity Asset Image](#DOCS_TOPICS_GATEWAY_EVENTS/activity-object-activity-asset-image) | -| SmallText | string | hover text for the small image | +| SmallText | string | hover text for the small image | ###### ActivityParty Struct | name | type | description | -| ---- | --------- | ---------------------------------- | +|------|-----------|------------------------------------| | Id | string | a unique identifier for this party | | Size | PartySize | info about the size of the party | ###### PartySize Struct | name | type | description | -| ----------- | ----- | ---------------------------------- | +|-------------|-------|------------------------------------| | CurrentSize | Int32 | the current size of the party | | MaxSize | Int32 | the max possible size of the party | ###### ActivitySecrets Struct | name | type | description | -| -------- | ------ | -------------------------------------------- | +|----------|--------|----------------------------------------------| | Match | string | unique hash for the given match context | | Join | string | unique hash for chat invites and Ask to Join | | Spectate | string | unique hash for Spectate button | @@ -74,7 +74,7 @@ For more detailed information and documentation around the Rich Presence feature ###### ActivityType Enum | name | Value | -| --------- | ----- | +|-----------|-------| | Playing | 0 | | Streaming | 1 | | Listening | 2 | @@ -89,7 +89,7 @@ For more details about the activity types, [see Gateway documentation](#DOCS_TOP ###### ActivityJoinRequestReply Enum | name | value | -| ------ | ----- | +|--------|-------| | No | 0 | | Yes | 1 | | Ignore | 2 | @@ -97,7 +97,7 @@ For more details about the activity types, [see Gateway documentation](#DOCS_TOP ###### ActivityActionType Enum | name | value | -| -------- | ----- | +|----------|-------| | Join | 1 | | Spectate | 2 | @@ -108,7 +108,7 @@ If you want to hook up joining and spectating for your games, there are certain ###### Requirements | Field | Custom Artwork | Spectate | Join | Ask to Join | -| ------------------------------ | :------------: | :------: | :--: | :---------: | +|--------------------------------|:--------------:|:--------:|:----:|:-----------:| | State | | | | | | Details | | | | | | ActivityTimestamps.Start | | | | | @@ -134,7 +134,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ------- | ------ | ----------------------- | +|---------|--------|-------------------------| | command | string | the command to register | ###### Example @@ -152,7 +152,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ------- | ------ | ------------------------ | +|---------|--------|--------------------------| | steamId | UInt32 | your game's Steam app id | ###### Example @@ -173,7 +173,7 @@ Returns a `Discord.Result` via callback. ###### Parameters | name | type | description | -| -------- | -------- | ----------------------------- | +|----------|----------|-------------------------------| | activity | Activity | the new activity for the user | ###### Example @@ -259,7 +259,7 @@ Returns a `Discord.Result` via callback. ###### Parameters | name | type | description | -| ------ | ------------------------ | ------------------------------------------- | +|--------|--------------------------|---------------------------------------------| | userId | Int64 | the user id of the person who asked to join | | reply | ActivityJoinRequestReply | No, Yes, or Ignore | @@ -288,7 +288,7 @@ Returns a `Discord.Result` via callback. ###### Parameters | name | type | description | -| ------- | ------------------ | ----------------------------------------------------- | +|---------|--------------------|-------------------------------------------------------| | userId | Int64 | the id of the user to invite | | type | ActivityActionType | marks the invite as an invitation to join or spectate | | content | string | a message to send along with the invite | @@ -319,7 +319,7 @@ Returns a `Discord.Result` via callback. ###### Parameters | name | type | description | -| ------ | ----- | ---------------------------------- | +|--------|-------|------------------------------------| | userId | Int64 | the id of the user who invited you | ###### Example @@ -345,7 +345,7 @@ Fires when a user accepts a game chat invite or receives confirmation from Askin ###### Parameters | name | type | description | -| ---------- | ------ | ---------------------------------- | +|------------|--------|------------------------------------| | joinSecret | string | the secret to join the user's game | ###### Example @@ -444,7 +444,7 @@ Fires when a user accepts a spectate chat invite or clicks the Spectate button o ###### Parameters | name | type | description | -| -------------- | ------ | ------------------------------------------------- | +|----------------|--------|---------------------------------------------------| | spectateSecret | string | the secret to join the user's game as a spectator | ###### Example @@ -464,7 +464,7 @@ Fires when a user asks to join the current user's game. ###### Parameters | name | type | description | -| ---- | ---- | ----------------------- | +|------|------|-------------------------| | user | User | the user asking to join | ###### Example @@ -484,7 +484,7 @@ Fires when the user receives a join or spectate invite. ###### Parameters | name | type | description | -| -------- | ------------------ | ------------------------------------------ | +|----------|--------------------|--------------------------------------------| | type | ActivityActiontype | whether this invite is to join or spectate | | user | User | the user sending the invite | | activity | Activity | the inviting user's current activity | diff --git a/docs/game_sdk/Applications.md b/docs/game_sdk/Applications.md index 320e85dc04..b827b25a1a 100644 --- a/docs/game_sdk/Applications.md +++ b/docs/game_sdk/Applications.md @@ -22,7 +22,7 @@ This manager also includes a couple useful helper functions, like getting the lo ###### OAuth2Token Struct | name | type | description | -| ----------- | ------ | ----------------------------------------------------------------------------------------------- | +|-------------|--------|-------------------------------------------------------------------------------------------------| | AccessToken | string | a bearer token for the current user | | Scopes | string | a list of oauth2 scopes as a single string, delineated by spaces like `"identify rpc gdm.join"` | | Expires | Int64 | the timestamp at which the token expires | @@ -30,9 +30,9 @@ This manager also includes a couple useful helper functions, like getting the lo ###### SignedAppTicket Struct | name | type | description | -| -------------- | ------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------- | +|----------------|--------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------| | application_id | Int64 | the application id for the ticket | -| user | [User](#DOCS_GAME_SDK_USERS/data-models-user-struct) | the user for the ticket | +| user | [User](#DOCS_GAME_SDK_USERS/data-models-user-struct) | the user for the ticket | | entitlements | list of partial [Entitlements](#DOCS_GAME_SDK_STORE/data-models-entitlement-struct) structs that contain just the SKU id | the list of the user's entitlements for this application | | timestamp | string | the ISO 8601 timestamp for the ticket | @@ -137,7 +137,7 @@ applicationManager.ValidateOrExit((result) => ###### Current Version | version | status | -| ------- | ------- | +|---------|---------| | 2 | current | Get the signed app ticket for the current user. The structure of the ticket is: `version.signature.base64encodedjson`, so you should split the string by the `.` character. Ensure that the `version` matches the current version. The `signature` is used to verify the ticket using the libsodium library of your choice, and the `base64encodedjson` is what you can transform after verification. It contains: diff --git a/docs/game_sdk/Discord_Voice.md b/docs/game_sdk/Discord_Voice.md index 99a51aba87..be6a5c7d21 100644 --- a/docs/game_sdk/Discord_Voice.md +++ b/docs/game_sdk/Discord_Voice.md @@ -15,14 +15,14 @@ If you want people playing your game to be able to talk with each other, this Vo ###### InputModeType Enum | name | value | -| ------------- | ----- | +|---------------|-------| | VoiceActivity | 0 | | PushToTalk | 1 | ###### InputMode Struct | name | type | description | -| -------- | ------------- | --------------------------------------------- | +|----------|---------------|-----------------------------------------------| | Type | InputModeType | set either VAD or PTT as the voice input mode | | Shortcut | string | the PTT hotkey for the user | @@ -31,7 +31,7 @@ If you want people playing your game to be able to talk with each other, this Vo Keys can be mapped as a combination by adding a "+" between values, such as `"shift + 4"` or `"ctrl + v"`. | key type | value | -| ------------- | --------------------------------------------------------- | +|---------------|-----------------------------------------------------------| | Alphabetical | "a", "b", "c", etc. | | Numerical | "1", "2", "3", etc. | | Symbols | "-", "+", ".", "/", etc. | @@ -95,7 +95,7 @@ Returns a `Discord.Result` via callback. ###### Parameters | name | type | description | -| --------- | --------- | ------------------------------- | +|-----------|-----------|---------------------------------| | inputMode | InputMode | the new input mode for the user | ###### Example @@ -145,7 +145,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ---- | ---- | ------------------------------- | +|------|------|---------------------------------| | mute | bool | true for mute, false for unmute | ###### Example @@ -188,7 +188,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ---- | ---- | ------------------------------- | +|------|------|---------------------------------| | deaf | bool | true for mute, false for unmute | ###### Example @@ -211,7 +211,7 @@ Returns `bool`. ###### Parameters | name | type | description | -| ------ | ----- | --------------------------- | +|--------|-------|-----------------------------| | userId | Int64 | the id of the user to check | ###### Example @@ -233,7 +233,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ------ | ----- | ------------------------------- | +|--------|-------|---------------------------------| | userId | Int64 | the id of the user to mute | | mute | bool | true for mute, false for unmute | @@ -257,7 +257,7 @@ Returns `byte`. ###### Parameters | name | type | description | -| ------ | ----- | --------------------------- | +|--------|-------|-----------------------------| | userId | Int64 | the id of the user to check | ###### Example @@ -277,7 +277,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ------ | ----- | ------------------------------------------------- | +|--------|-------|---------------------------------------------------| | userId | Int64 | the id of the user to change | | volume | byte | the volume at which to set the user, `0` to `200` | diff --git a/docs/game_sdk/Images.md b/docs/game_sdk/Images.md index 7ddaa99b84..7632956e1c 100644 --- a/docs/game_sdk/Images.md +++ b/docs/game_sdk/Images.md @@ -13,20 +13,20 @@ Discord is like a book; it's better with pictures. The image manager helps you f ###### ImageDimensions Struct | name | type | description | -| ------ | ------ | ----------------------- | +|--------|--------|-------------------------| | Width | UInt32 | the width of the image | | Height | UInt32 | the height of the image | ###### ImageType Enum | value | description | -| ----- | ------------------------ | +|-------|--------------------------| | User | image is a user's avatar | ###### ImageHandle Struct | name | type | description | -| ---- | --------- | ----------------------------------------------- | +|------|-----------|-------------------------------------------------| | Type | ImageType | the source of the image | | Id | Int64 | the id of the user whose avatar you want to get | | Size | UInt32 | the resolution at which you want the image | @@ -40,7 +40,7 @@ Returns a `Discord.Result` and `Discord.ImageHandle` via callback. ###### Parameters | name | type | description | -| ------- | ----------- | ----------------------------------------------------------- | +|---------|-------------|-------------------------------------------------------------| | handle | ImageHandle | contains the desired userId and size for the returned image | | refresh | bool | whether to use cached data for fetch anew | @@ -72,7 +72,7 @@ Returns `Discord.ImageDimensions`. ###### Parameters | name | type | description | -| ------ | ----------- | ----------------------------------------------------------- | +|--------|-------------|-------------------------------------------------------------| | handle | ImageHandle | contains the desired userId and size for the returned image | ###### Example @@ -93,7 +93,7 @@ Gets the image data for a given user's avatar. In C#, this is overloaded by a he ###### Parameters | name | type | description | -| ------ | ----------- | --------------------------------------------- | +|--------|-------------|-----------------------------------------------| | handle | ImageHandle | the image handle from the `Fetch()` callback | | data | uint8_t\* | a buffer to read image data into (C++/C only) | | size | uint | the size of the buffer (C++/C only) | @@ -149,7 +149,7 @@ Returns a `Texture2D`. ###### Parameters | name | type | description | -| ------ | ----------- | -------------------------------------------- | +|--------|-------------|----------------------------------------------| | handle | ImageHandle | the image handle from the `Fetch()` callback | ###### Example diff --git a/docs/game_sdk/Lobbies.md b/docs/game_sdk/Lobbies.md index 887ec4db37..0ba230fd8b 100644 --- a/docs/game_sdk/Lobbies.md +++ b/docs/game_sdk/Lobbies.md @@ -57,14 +57,14 @@ lobbyManager.CreateLobby(txn, (Discord.Result result, ref Discord.Lobby lobby) = ###### LobbyType Enum | name | value | -| ------- | ----- | +|---------|-------| | Private | 1 | | Public | 2 | ###### Lobby Struct | name | type | description | -| -------- | --------- | -------------------------------------- | +|----------|-----------|----------------------------------------| | Id | Int64 | the unique id of the lobby | | Type | LobbyType | if the lobby is public or private | | OwnerId | Int64 | the userId of the lobby owner | @@ -75,7 +75,7 @@ lobbyManager.CreateLobby(txn, (Discord.Result result, ref Discord.Lobby lobby) = ###### LobbySearchComparison Enum | name | value | -| ------------------ | ----- | +|--------------------|-------| | LessThanOrEqual | -2 | | LessThan | -1 | | Equal | 0 | @@ -86,14 +86,14 @@ lobbyManager.CreateLobby(txn, (Discord.Result result, ref Discord.Lobby lobby) = ###### LobbySearchCast Enum | name | value | -| ------ | ----- | +|--------|-------| | String | 1 | | Number | 2 | ###### LobbySearchDistance Enum | name | value | description | -| -------- | ----- | ------------------------------------ | +|----------|-------|--------------------------------------| | Local | 0 | within the same region | | Default | 1 | within the same and adjacent regions | | Extended | 2 | far distances, like US to EU | @@ -120,7 +120,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ---- | --------- | ----------------- | +|------|-----------|-------------------| | type | LobbyType | private or public | ###### Example @@ -149,7 +149,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ------ | ----- | ----------------------- | +|--------|-------|-------------------------| | userId | Int64 | the new owner's user id | ###### Example @@ -175,7 +175,7 @@ Returns `void`. ###### Parameters | name | type | description | -| -------- | ------ | ---------------------- | +|----------|--------|------------------------| | capacity | UInt32 | the new max lobby size | ###### Example @@ -201,7 +201,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ----- | ------ | ---------------- | +|-------|--------|------------------| | key | string | key for the data | | value | string | data value | @@ -228,7 +228,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ---- | ------ | ---------------- | +|------|--------|------------------| | key | string | key for the data | ###### Example @@ -254,7 +254,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ------ | ---- | ----------------------------------- | +|--------|------|-------------------------------------| | locked | bool | whether to lock or unlock the lobby | ###### Example @@ -280,7 +280,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ----- | ------ | ---------------- | +|-------|--------|------------------| | key | string | key for the data | | value | string | data value | @@ -307,7 +307,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ---- | ------ | ---------------- | +|------|--------|------------------| | key | string | key for the data | ###### Example @@ -333,7 +333,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ----- | --------------------- | -------------------------------------------------------------------------- | +|-------|-----------------------|----------------------------------------------------------------------------| | key | string | key to search for filter data | | comp | LobbySearchComparison | how the value on the lobby metadata should be compared to the search value | | cast | LobbySearchCast | should the search value be cast as a string or a number | @@ -355,7 +355,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ----- | --------------- | ------------------------------------------------------- | +|-------|-----------------|---------------------------------------------------------| | key | string | key for the data | | cast | LobbySearchCast | should the search value be cast as a string or a number | | value | string | the value to sort by | @@ -376,7 +376,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ----- | ------ | -------------------------------------- | +|-------|--------|----------------------------------------| | limit | UInt32 | the number of lobbies to return at max | ###### Example @@ -395,7 +395,7 @@ Returns `void`. ###### Parameters | name | type | description | -| -------- | --------------------------- | ----------------------------------------------- | +|----------|-----------------------------|-------------------------------------------------| | distance | Discord.LobbySearchDistance | the distance within which to search for lobbies | ###### Example @@ -430,7 +430,7 @@ Returns a `Discord.LobbyTransaction`. ###### Parameters | name | type | description | -| ------- | ----- | ---------------------------- | +|---------|-------|------------------------------| | lobbyId | Int64 | the lobby you want to change | ###### Example @@ -448,7 +448,7 @@ Returns a `Discord.LobbyMemberTransaction`. ###### Parameters | name | type | description | -| ------- | ----- | ---------------------------- | +|---------|-------|------------------------------| | lobbyId | Int64 | the lobby you want to change | | userId | Int64 | the user you wish to change | @@ -467,7 +467,7 @@ Returns `Discord.Result` and `ref Discord.Lobby` via callback. ###### Parameters | name | type | description | -| ----------- | ---------------- | ----------------------------------------------------- | +|-------------|------------------|-------------------------------------------------------| | transaction | LobbyTransaction | a lobby transaction with set properties like capacity | ###### Example @@ -494,7 +494,7 @@ Returns `Discord.Result` via callback. ###### Parameters | name | type | description | -| ----------- | ---------------- | ----------------------------------- | +|-------------|------------------|-------------------------------------| | lobbyId | Int64 | the lobby you want to change | | transaction | LobbyTransaction | the transaction with wanted changes | @@ -519,7 +519,7 @@ Returns `Discord.Result` via callback. ###### Parameters | name | type | description | -| ------- | ----- | ---------------------------- | +|---------|-------|------------------------------| | lobbyId | Int64 | the lobby you want to delete | ###### Example @@ -543,7 +543,7 @@ Returns `Discord.Result` and `ref Discord.Lobby` via callback. ###### Parameters | name | type | description | -| ----------- | ------ | -------------------------------- | +|-------------|--------|----------------------------------| | lobbyId | Int64 | the lobby you want to connect to | | lobbySecret | string | the password for the lobby | @@ -568,7 +568,7 @@ Returns `Discord.Result` and `ref Discord.Lobby` via callback. ###### Parameters | name | type | description | -| -------------- | ------ | ----------------------------------------- | +|----------------|--------|-------------------------------------------| | activitySecret | string | the special activity secret for the lobby | ###### Example @@ -592,7 +592,7 @@ Returns `string`. ###### Parameters | name | type | description | -| ------- | ----- | ---------------------------------------- | +|---------|-------|------------------------------------------| | lobbyId | Int64 | the lobby you want to get the secret for | ###### Example @@ -631,7 +631,7 @@ Returns `Discord.Result` via callback. ###### Parameters | name | type | description | -| ------- | ----- | --------------------------- | +|---------|-------|-----------------------------| | lobbyId | Int64 | the lobby you want to leave | ###### Example @@ -655,7 +655,7 @@ Returns a `Discord.Lobby`. ###### Parameters | name | type | description | -| ------- | ----- | ------------------------- | +|---------|-------|---------------------------| | lobbyId | Int64 | the lobby you want to get | ###### Example @@ -686,7 +686,7 @@ Returns `Int32`. ###### Parameters | name | type | description | -| ------- | ----- | -------------------------------------- | +|---------|-------|----------------------------------------| | lobbyId | Int64 | the lobby you want to get metadata for | ###### Example @@ -708,7 +708,7 @@ Returns `string`. ###### Parameters | name | type | description | -| ------- | ----- | -------------------------------------- | +|---------|-------|----------------------------------------| | lobbyId | Int64 | the lobby you want to get metadata for | | index | Int32 | the index of lobby metadata to access | @@ -729,7 +729,7 @@ Returns lobby metadata value for a given key and id. Can be used with iteration, ###### Parameters | name | type | description | -| ------- | ------ | -------------------------------------- | +|---------|--------|----------------------------------------| | lobbyId | Int64 | the lobby you want to get metadata for | | key | string | the key name to access | @@ -748,7 +748,7 @@ Returns `Int32`. ###### Parameters | name | type | description | -| ------- | ----- | ------------------------------------- | +|---------|-------|---------------------------------------| | lobbyId | Int64 | the lobby you want to get members for | ###### Example @@ -770,7 +770,7 @@ Returns `Int64`. ###### Parameters | name | type | description | -| ------- | ----- | ------------------------------------- | +|---------|-------|---------------------------------------| | lobbyId | Int64 | the lobby you want to get members for | | index | Int32 | the index of lobby member to access | @@ -793,7 +793,7 @@ Returns `Discord.User`. ###### Parameters | name | type | description | -| ------- | ----- | ------------------------------------- | +|---------|-------|---------------------------------------| | lobbyId | Int64 | the lobby you want to get members for | | userId | Int64 | the user's userId | @@ -818,7 +818,7 @@ Returns `Int32`. ###### Parameters | name | type | description | -| ------- | ----- | -------------------------------------- | +|---------|-------|----------------------------------------| | lobbyId | Int64 | the lobby the member belongs to | | userId | Int64 | the id of the user to get metadata for | @@ -841,7 +841,7 @@ Returns `string`. ###### Parameters | name | type | description | -| ------- | ----- | -------------------------------------- | +|---------|-------|----------------------------------------| | lobbyId | Int64 | the lobby the member belongs to | | userId | Int64 | the id of the user to get metadata for | | index | Int32 | the index of metadata to access | @@ -865,7 +865,7 @@ Returns `string`. ###### Parameters | name | type | description | -| ------- | ------ | -------------------------------------- | +|---------|--------|----------------------------------------| | lobbyId | Int64 | the lobby the member belongs to | | userId | Int64 | the id of the user to get metadata for | | key | string | the metadata key to access | @@ -891,7 +891,7 @@ Returns `Discord.Result` via callback. ###### Parameters | name | type | description | -| ----------- | ---------------------- | --------------------------------- | +|-------------|------------------------|-----------------------------------| | lobbyId | Int64 | lobby the member belongs to | | userId | Int64 | id of the user | | transaction | LobbyMemberTransaction | transaction with the changed data | @@ -921,7 +921,7 @@ Returns a `Discord.Result` via callback. ###### Parameters | name | type | description | -| ------- | ------ | --------------------------- | +|---------|--------|-----------------------------| | lobbyId | Int64 | lobby the member belongs to | | data | byte[] | the data to send | @@ -964,7 +964,7 @@ Returns `Discord.Result` via callback. ###### Parameters | name | type | description | -| ------ | ----------- | ------------------- | +|--------|-------------|---------------------| | search | LobbySearch | the search criteria | ###### Example @@ -1013,7 +1013,7 @@ Returns `Int64`. ###### Parameters | name | type | description | -| ----- | ----- | ------------------------------------------------ | +|-------|-------|--------------------------------------------------| | index | Int32 | the index at which to access the list of lobbies | ###### Example @@ -1043,7 +1043,7 @@ Returns `Discord.Result` via callback. ###### Parameters | name | type | description | -| ------- | ----- | ------------------------- | +|---------|-------|---------------------------| | lobbyId | Int64 | lobby to voice connect to | ###### Example @@ -1067,7 +1067,7 @@ Returns `Discord.Result` via callback. ###### Parameters | name | type | description | -| ------- | ----- | ------------------------------ | +|---------|-------|--------------------------------| | lobbyId | Int64 | lobby to voice disconnect from | ###### Example @@ -1089,7 +1089,7 @@ Fires when a lobby is updated. ###### Parameters | name | type | description | -| ------- | ----- | ------------------ | +|---------|-------|--------------------| | lobbyId | Int64 | lobby that updated | ###### Example @@ -1108,7 +1108,7 @@ Fired when a lobby is deleted. ###### Parameters | name | type | description | -| ------- | ------ | ---------------------------------------------- | +|---------|--------|------------------------------------------------| | lobbyId | Int64 | lobby that was deleted | | reason | string | reason for deletion - this is a system message | @@ -1128,7 +1128,7 @@ Fires when a new member joins the lobby. ###### Parameters | name | type | description | -| ------- | ----- | --------------------- | +|---------|-------|-----------------------| | lobbyId | Int64 | lobby the user joined | | userId | Int64 | user that joined | @@ -1148,7 +1148,7 @@ Fires when data for a lobby member is updated. ###### Parameters | name | type | description | -| ------- | ----- | ----------------------------- | +|---------|-------|-------------------------------| | lobbyId | Int64 | lobby the user is a member of | | userId | Int64 | user that was updated | @@ -1168,7 +1168,7 @@ Fires when a member leaves the lobby. ###### Parameters | name | type | description | -| ------- | ----- | ------------------------------ | +|---------|-------|--------------------------------| | lobbyId | Int64 | lobby the user was a member of | | userId | Int64 | user that left | @@ -1188,7 +1188,7 @@ Fires when a message is sent to the lobby. ###### Parameters | name | type | description | -| ------- | ------ | ---------------------------- | +|---------|--------|------------------------------| | lobbyId | Int64 | lobby the message is sent to | | userId | Int64 | user that sent the message | | data | byte[] | the message contents | @@ -1209,7 +1209,7 @@ Fires when a user connected to voice starts or stops speaking. ###### Parameters | name | type | description | -| -------- | ----- | ------------------------------------------------------- | +|----------|-------|---------------------------------------------------------| | lobbyId | Int64 | lobby the user is connected to | | userId | Int64 | user in voice | | speaking | bool | `true` == started speaking, `false` == stopped speaking | @@ -1342,7 +1342,7 @@ To get a list of valid regions, call the [List Voice Regions](https://discord.co ###### Parameters | name | type | description | -| -------------- | --------- | ---------------------------------------------------------------------------------------------------- | +|----------------|-----------|------------------------------------------------------------------------------------------------------| | application_id | string | your application id | | type | LobbyType | the type of lobby | | metadata | dict | metadata for the lobby - key/value pairs with types `string` | @@ -1374,7 +1374,7 @@ Updates a lobby. ###### Parameters | name | type | description | -| -------- | --------- | ------------------------------------------------------------ | +|----------|-----------|--------------------------------------------------------------| | type | LobbyType | the type of lobby | | metadata | dict | metadata for the lobby - key/value pairs with types `string` | | capacity | int | max lobby capacity with a default of 16 | @@ -1390,7 +1390,7 @@ Updates the metadata for a lobby member. ###### Parameters | name | type | description | -| -------- | ---- | ------------------------------------------------------------------- | +|----------|------|---------------------------------------------------------------------| | metadata | dict | metadata for the lobby member - key/value pairs with types `string` | ## Create Lobby Search % POST /lobbies/search @@ -1400,7 +1400,7 @@ Creates a lobby search for matchmaking around given criteria. ###### Parameters | name | type | description | -| -------------- | ----------------------------- | ---------------------------------------- | +|----------------|-------------------------------|------------------------------------------| | application_id | string | your application id | | filter | array of SearchFilter objects | the filter to check against | | sort | array of SearchSort objects | how to sort the results | @@ -1409,7 +1409,7 @@ Creates a lobby search for matchmaking around given criteria. ###### SearchFilter Object | name | type | description | -| ---------- | ---------------- | ------------------------------------------------- | +|------------|------------------|---------------------------------------------------| | key | string | the metadata key to search | | value | string | the value of the metadata key to validate against | | cast | SearchCast | the type to cast `value` as | @@ -1418,7 +1418,7 @@ Creates a lobby search for matchmaking around given criteria. ###### SearchComparison Types | name | value | -| ------------------------ | ----- | +|--------------------------|-------| | EQUAL_TO_OR_LESS_THAN | -2 | | LESS_THAN | -1 | | EQUAL | 0 | @@ -1429,7 +1429,7 @@ Creates a lobby search for matchmaking around given criteria. ###### SearchSort Object | name | type | description | -| ---------- | ---------- | ----------------------------------------------------------------------- | +|------------|------------|-------------------------------------------------------------------------| | key | string | the metadata key on which to sort lobbies that meet the search criteria | | cast | SearchCast | the type to cast `value` as | | near_value | string | the value around which to sort the key | @@ -1437,7 +1437,7 @@ Creates a lobby search for matchmaking around given criteria. ###### SearchCast Types | name | value | -| ------ | ----- | +|--------|-------| | STRING | 1 | | NUMBER | 2 | @@ -1450,7 +1450,7 @@ This endpoints accepts a UTF8 string. If your message is already a string, you'r ###### Parameters | name | type | description | -| ---- | ------ | ------------------------------------------- | +|------|--------|---------------------------------------------| | data | string | a message to be sent to other lobby members | ## Integrated Networking @@ -1470,7 +1470,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ------- | ----- | ------------------------------ | +|---------|-------|--------------------------------| | lobbyId | Int64 | the ID of the lobby you are in | ###### Example @@ -1491,7 +1491,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ------- | ----- | ------------------------------ | +|---------|-------|--------------------------------| | lobbyId | Int64 | the ID of the lobby you are in | ###### Example @@ -1529,7 +1529,7 @@ Returns `void`. ###### Parameters | name | type | description | -| --------- | ----- | ---------------------------------------------------- | +|-----------|-------|------------------------------------------------------| | lobbyId | Int64 | the ID of the lobby you are in | | channelId | byte | the channel on which to connect | | reliable | bool | whether the channel should be unreliable or reliable | @@ -1554,7 +1554,7 @@ Returns `void`. ###### Parameters | name | type | description | -| --------- | ------ | --------------------------------------- | +|-----------|--------|-----------------------------------------| | lobbyId | Int64 | the ID of the lobby you are in | | userId | Int64 | the ID of the user to send a message to | | channelId | byte | the channel on which to connect | @@ -1583,7 +1583,7 @@ Fires when the user receives a message from the lobby's networking layer. ###### Parameters | name | type | description | -| --------- | ------ | --------------------------------------- | +|-----------|--------|-----------------------------------------| | lobbyId | Int64 | the ID of the lobby you are in | | userId | Int64 | the ID of the user who sent the message | | channelId | byte | the channel the message was sent on | diff --git a/docs/game_sdk/Networking.md b/docs/game_sdk/Networking.md index 9e5f6a9e9e..d2c8b2ae26 100644 --- a/docs/game_sdk/Networking.md +++ b/docs/game_sdk/Networking.md @@ -65,7 +65,7 @@ Returns `void`. ###### Parameters | name | type | description | -| --------- | ------ | ---------------------------------------------------- | +|-----------|--------|------------------------------------------------------| | peerId | UInt64 | the peerId of the user to connect to | | channelId | byte | the channel on which to connect | | reliable | bool | whether the channel should be unreliable or reliable | @@ -91,7 +91,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ------ | ------ | -------------------------------------------- | +|--------|--------|----------------------------------------------| | peerId | UInt64 | the peerId of the user to connect to | | route | string | the route the user is currently broadcasting | @@ -117,7 +117,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ------ | ------ | -------------------------- | +|--------|--------|----------------------------| | peerId | UInt64 | the user's peerId | | route | string | the new route for the user | @@ -143,7 +143,7 @@ Returns `void`. ###### Parameters | name | type | description | -| --------- | ------ | ------------------------------- | +|-----------|--------|---------------------------------| | peerId | UInt64 | the peer id to connect to | | channelId | byte | the channel on which to connect | | data | byte[] | the data to send | @@ -170,7 +170,7 @@ Returns `void`. ###### Parameters | name | type | description | -| --------- | ------ | ----------------------------------------- | +|-----------|--------|-------------------------------------------| | peerId | UInt64 | the peerId of the user to disconnect from | | channelId | byte | the route to close | @@ -196,7 +196,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ------ | ------ | ----------------- | +|--------|--------|-------------------| | peerId | UInt64 | the user's peerId | ###### Example @@ -219,7 +219,7 @@ Fires when you receive data from another user. This callback will only fire if y ###### Parameters | name | type | description | -| --------- | ------ | -------------------------- | +|-----------|--------|----------------------------| | peerId | UInt64 | the peer id of the sender | | channelId | byte | the channel it was sent on | | data | byte[] | the data sent | @@ -241,7 +241,7 @@ Fires when your networking route has changed. You should broadcast to other user ###### Parameters | name | type | description | -| ----- | ------ | ------------------------- | +|-------|--------|---------------------------| | route | string | the new route to the user | ###### Example diff --git a/docs/game_sdk/Overlay.md b/docs/game_sdk/Overlay.md index e99b4a27bc..996025c8aa 100644 --- a/docs/game_sdk/Overlay.md +++ b/docs/game_sdk/Overlay.md @@ -17,7 +17,7 @@ Discord comes with an awesome built-in overlay, and you may want to make use of ###### ActivityActionType Enum | name | value | -| -------- | ----- | +|----------|-------| | Join | 1 | | Spectate | 2 | @@ -69,7 +69,7 @@ Returns `Discord.Result` via callback. ###### Parameters | name | type | description | -| ------ | ---- | -------------------------- | +|--------|------|----------------------------| | locked | bool | lock or unlock the overlay | ###### Example @@ -90,7 +90,7 @@ Returns a `Discord.Result` via callback. ###### Parameters | name | type | description | -| ---- | ------------------ | --------------------------- | +|------|--------------------|-----------------------------| | type | ActivityActionType | what type of invite to send | ###### Example @@ -114,7 +114,7 @@ Returns a `Discord.Result` via callback. Note that a successful `Discord.Result` ###### Parameters | name | type | description | -| ---- | ------ | -------------------------- | +|------|--------|----------------------------| | code | string | an invite code for a guild | ###### Example @@ -164,7 +164,7 @@ Fires when the overlay is locked or unlocked (a.k.a. opened or closed) ###### Parameters | name | type | description | -| ------ | ---- | ------------------------------------- | +|--------|------|---------------------------------------| | locked | bool | is the overlay now locked or unlocked | ###### Example diff --git a/docs/game_sdk/Relationships.md b/docs/game_sdk/Relationships.md index d1a038a3e7..c950f0f9a4 100644 --- a/docs/game_sdk/Relationships.md +++ b/docs/game_sdk/Relationships.md @@ -22,7 +22,7 @@ An example of how to do this properly is at the end of this documentation page. ###### Relationship Struct | name | type | description | -| -------- | ---------------- | -------------------------------- | +|----------|------------------|----------------------------------| | Type | RelationshipType | what kind of relationship it is | | User | User | the user the relationship is for | | Presence | Presence | that user's current presence | @@ -30,7 +30,7 @@ An example of how to do this properly is at the end of this documentation page. ###### RelationshipType Enum | value | description | -| --------------- | -------------------------------------------------------------------------------- | +|-----------------|----------------------------------------------------------------------------------| | None | user has no intrinsic relationship | | Friend | user is a friend | | Blocked | user is blocked | @@ -41,14 +41,14 @@ An example of how to do this properly is at the end of this documentation page. ###### Presence Struct | name | type | description | -| -------- | -------- | -------------------------------- | +|----------|----------|----------------------------------| | Status | Status | the user's current online status | | Activity | Activity | the user's current activity | ###### Status Enum | name | value | -| ------------ | ----- | +|--------------|-------| | Offline | 0 | | Online | 1 | | Idle | 2 | @@ -82,7 +82,7 @@ Returns a `Relationship`. ###### Parameters | name | type | description | -| ------ | ----- | --------------------------- | +|--------|-------|-----------------------------| | userId | Int64 | the id of the user to fetch | ###### Example @@ -101,7 +101,7 @@ Returns a `Relationship`. ###### Parameters | name | type | description | -| ----- | ------ | ----------------- | +|-------|--------|-------------------| | index | UInt32 | index in the list | ###### Example @@ -149,7 +149,7 @@ Fires when a relationship in the filtered list changes, like an updated presence ###### Parameters | name | type | description | -| ------------ | ---------------- | ----------------------------- | +|--------------|------------------|-------------------------------| | relationship | ref Relationship | the relationship that changed | ###### Example diff --git a/docs/game_sdk/Storage.md b/docs/game_sdk/Storage.md index ddf0d57344..8821b19926 100644 --- a/docs/game_sdk/Storage.md +++ b/docs/game_sdk/Storage.md @@ -36,7 +36,7 @@ Yup, that's it! Don't know what this file is? Go read [Branches and Builds](#DOC ###### FileStat Struct | name | type | description | -| ------------ | ------ | -------------------------------------------- | +|--------------|--------|----------------------------------------------| | Filename | string | the name of the file | | Size | UInt64 | the size of the file | | LastModified | UInt64 | timestamp of when the file was last modified | @@ -70,7 +70,7 @@ Returns a `UInt32`. ###### Parameters | name | type | description | -| ---- | ------ | ---------------------------------- | +|------|--------|------------------------------------| | name | string | the key name to read from the file | | data | byte[] | the buffer to read into | @@ -83,7 +83,7 @@ Returns a `Discord.Result` and a `byte[]` containing the data via callback. ###### Parameters | name | type | description | -| ---- | ------ | ---------------------------------- | +|------|--------|------------------------------------| | name | string | the key name to read from the file | ###### Example @@ -106,7 +106,7 @@ Returns a `Discord.Result` and `byte[]` containing the data via callback. ###### Parameters | name | type | description | -| ------ | ------ | ------------------------------------ | +|--------|--------|--------------------------------------| | name | string | the key name to read from the file | | offset | UInt64 | the offset at which to start reading | | length | UInt64 | the length to read | @@ -131,7 +131,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ---- | ------ | --------------------------- | +|------|--------|-----------------------------| | name | string | the key name to write under | | data | byte[] | the data to write | @@ -150,7 +150,7 @@ Returns a `Discord.Result` via callback. ###### Parameters | name | type | description | -| ---- | ------ | --------------------------- | +|------|--------|-----------------------------| | name | string | the key name to write under | | data | byte[] | the data to write | @@ -175,7 +175,7 @@ Returns `void`. ###### Parameters | name | type | description | -| ---- | ------ | ---------------------- | +|------|--------|------------------------| | name | string | the key name to delete | ###### Example @@ -194,7 +194,7 @@ Returns `bool`. ###### Parameters | name | type | description | -| ---- | ------ | --------------------- | +|------|--------|-----------------------| | name | string | the key name to check | ###### Example @@ -216,7 +216,7 @@ Returns a `FileStat`. ###### Parameters | name | type | description | -| ---- | ------ | ------------------------------ | +|------|--------|--------------------------------| | name | string | the key name get file data for | ###### Example @@ -255,7 +255,7 @@ Returns a `FileStat`. ###### Parameters | name | type | description | -| ----- | ----- | ------------------------------ | +|-------|-------|--------------------------------| | index | Int32 | the index to get file data for | ###### Example diff --git a/docs/game_sdk/Store.md b/docs/game_sdk/Store.md index 9d7654b452..c6ab53d6f9 100644 --- a/docs/game_sdk/Store.md +++ b/docs/game_sdk/Store.md @@ -56,7 +56,7 @@ Non-consumable SKUs can only be purchased once. ###### SKU Struct | name | type | description | -| ----- | -------- | ------------------------ | +|-------|----------|--------------------------| | Id | Int64 | the unique ID of the SKU | | Type | SkuType | what sort of SKU it is | | Name | string | the name of the SKU | @@ -65,7 +65,7 @@ Non-consumable SKUs can only be purchased once. ###### SkuType Enum | name | value | description | -| ----------- | ----- | ---------------------------------------------- | +|-------------|-------|------------------------------------------------| | Application | 1 | SKU is a game | | DLC | 2 | SKU is a DLC | | Consumable | 3 | SKU is a consumable (in-app purchase) | @@ -74,14 +74,14 @@ Non-consumable SKUs can only be purchased once. ###### SkuPrice Struct | name | type | description | -| -------- | ------ | --------------------------------- | +|----------|--------|-----------------------------------| | Amount | UInt32 | the amount of money the SKU costs | | Currency | string | the currency the amount is in | ###### Entitlement Struct | name | type | description | -| ----- | --------------- | ----------------------------------------------- | +|-------|-----------------|-------------------------------------------------| | Id | Int64 | the unique ID of the entitlement | | Type | EntitlementType | the kind of entitlement it is | | SkuId | Int64 | the ID of the SKU to which the user is entitled | @@ -89,7 +89,7 @@ Non-consumable SKUs can only be purchased once. ###### EntitlementType Enum | name | value | description | -| ------------------- | ----- | -------------------------------------------------------------- | +|---------------------|-------|----------------------------------------------------------------| | Purchase | 1 | entitlement was purchased | | PremiumSubscription | 2 | entitlement for a Discord Nitro subscription | | DeveloperGift | 3 | entitlement was gifted by a developer | @@ -152,7 +152,7 @@ Returns `Discord.Sku`. ###### Parameters | name | type | description | -| ----- | ----- | ------------------------ | +|-------|-------|--------------------------| | skuId | Int64 | the ID of the SKU to get | ###### Example @@ -172,7 +172,7 @@ Returns `Discord.Sku`. ###### Parameters | name | type | description | -| ----- | ----- | ------------------------- | +|-------|-------|---------------------------| | index | Int32 | the index at which to get | ###### Example @@ -242,7 +242,7 @@ Returns `Discord.Entitlement`. ###### Parameters | name | type | description | -| ------------- | ----- | -------------------------------- | +|---------------|-------|----------------------------------| | entitlementId | Int64 | the ID of the entitlement to get | ###### Example @@ -264,7 +264,7 @@ Returns `Discord.Entitlement`. ###### Parameters | name | type | description | -| ----- | ----- | ------------------------- | +|-------|-------|---------------------------| | index | Int32 | the index at which to get | ###### Example @@ -289,7 +289,7 @@ Returns `bool`. ###### Parameters | name | type | description | -| ----- | ----- | -------------------------- | +|-------|-------|----------------------------| | skuId | Int64 | the ID of the SKU to check | ###### Example @@ -317,7 +317,7 @@ Returns `Discord.Result` via callback. ###### Parameters | name | type | description | -| ----- | ----- | ------------------------------------- | +|-------|-------|---------------------------------------| | skuId | Int64 | the ID of the SKU to begin purchasing | ###### Example @@ -342,7 +342,7 @@ Fires when the connected user receives a new entitlement, either through purchas ###### Parameters | name | type | description | -| ----------- | ------------------- | ----------------------------------------- | +|-------------|---------------------|-------------------------------------------| | entitlement | Discord.Entitlement | the entitlement the user has been granted | ## OnEntitlementDelete @@ -352,7 +352,7 @@ Fires when the connected user loses an entitlement, either by expiration, revoca ###### Parameters | name | type | description | -| ----------- | ------------------- | --------------------------------- | +|-------------|---------------------|-----------------------------------| | entitlement | Discord.Entitlement | the entitlement the user has lost | ## HTTP APIs @@ -368,7 +368,7 @@ Note that parameters with a `?` after the name denote optional fields. Parameter ###### Limited Payment Data Object | name | type | description | -| ------------- | ------ | ------------------------------------ | +|---------------|--------|--------------------------------------| | id | string | unique ID of the payment | | currency | string | the currency the payment was made in | | amount | int | the amount paid | @@ -382,7 +382,7 @@ Gets entitlements for a given user. You can use this on your game backend to che ###### Query Parameters | name | type | description | -| -------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | +|----------------|-----------------------------------|--------------------------------------------------------------------------------------------------------------------------------| | user_id? | snowflake | the user id to look up entitlements for | | sku_ids? | comma-delimited set of snowflakes | (optional) the list SKU ids to check entitlements for | | with_payments? | bool | returns [limited payment data](#DOCS_GAME_SDK_STORE/httpspecific-data-models-limited-payment-data-object) for each entitlement | @@ -428,7 +428,7 @@ Fetch an entitlement by its ID. This may be useful in confirming that a user has ###### Query Parameters | name | type | description | -| ------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------ | +|---------------|------|--------------------------------------------------------------------------------------------------------------------------------| | with_payment? | bool | returns [limited payment data](#DOCS_GAME_SDK_STORE/httpspecific-data-models-limited-payment-data-object) for each entitlement | ###### Example @@ -529,7 +529,7 @@ Creates a discount for the given user on their next purchase of the given SKU. Y ###### Parameters | name | type | description | -| ----------- | ---- | -------------------------------------------------------------------------------------- | +|-------------|------|----------------------------------------------------------------------------------------| | percent_off | int | the percentage to discount - max of 100, min of 1 | | ttl? | int | the time to live for the discount, in seconds - max of 3600, min of 60, default of 600 | diff --git a/docs/game_sdk/Users.md b/docs/game_sdk/Users.md index 7131bf2dbf..0a7a28165c 100644 --- a/docs/game_sdk/Users.md +++ b/docs/game_sdk/Users.md @@ -10,7 +10,7 @@ This manager helps retrieve basic user information for any user on Discord. ###### User Struct | name | type | description | -| ------------- | ------ | ----------------------------- | +|---------------|--------|-------------------------------| | Id | Int64 | the user's id | | Username | string | their name | | Discriminator | string | the user's unique discrim | @@ -20,7 +20,7 @@ This manager helps retrieve basic user information for any user on Discord. ###### UserFlag Enum | name | value | description | -| --------------- | ----- | ---------------------------- | +|-----------------|-------|------------------------------| | Partner | 2 | Discord Partner | | HypeSquadEvents | 4 | HypeSquad Events participant | | HypeSquadHouse1 | 64 | House Bravery | @@ -30,7 +30,7 @@ This manager helps retrieve basic user information for any user on Discord. ###### PremiumType Enum | name | value | description | -| ----- | ----- | ------------------------ | +|-------|-------|--------------------------| | None | 0 | Not a Nitro subscriber | | Tier1 | 1 | Nitro Classic subscriber | | Tier2 | 2 | Nitro subscriber | @@ -65,7 +65,7 @@ Returns a `Discord.Result` and `ref Discord.User` via callback. ###### Parameters | name | type | description | -| ------ | ----- | --------------------------- | +|--------|-------|-----------------------------| | userId | Int64 | the id of the user to fetch | ###### Example @@ -120,7 +120,7 @@ Returns `bool`. ###### Parameters | name | type | description | -| ---- | ---------------------------------------------------------- | --------------------------------------- | +|------|------------------------------------------------------------|-----------------------------------------| | flag | [UserFlag](#DOCS_GAME_SDK_USERS/data-models-userflag-enum) | the flag to check on the user's account | ###### Example diff --git a/docs/interactions/Application_Commands.md b/docs/interactions/Application_Commands.md index e136d4ab12..a12e437986 100644 --- a/docs/interactions/Application_Commands.md +++ b/docs/interactions/Application_Commands.md @@ -13,7 +13,7 @@ Application commands are native ways to interact with apps in the Discord client ###### Application Command Structure | Field | Type | Description | Valid Types | -| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------- | +|----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| | id | snowflake | Unique ID of command | all | | type? | one of [application command type](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-types) | [Type of command](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-types), defaults to `1` | all | | application_id | snowflake | ID of the parent application | all | @@ -35,7 +35,7 @@ Application commands are native ways to interact with apps in the Discord client ###### Application Command Types | Name | Type | Description | -| ---------- | ---- | ------------------------------------------------------------------------- | +|------------|------|---------------------------------------------------------------------------| | CHAT_INPUT | 1 | Slash commands; a text-based command that shows up when a user types `/` | | USER | 2 | A UI-based command that shows up when you right click or tap on a user | | MESSAGE | 3 | A UI-based command that shows up when you right click or tap on a message | @@ -47,7 +47,7 @@ Application commands are native ways to interact with apps in the Discord client > Required `options` must be listed before optional options | Field | Type | Description | -| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- | +|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------| | type | one of [application command option type](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-type) | Type of option | | name | string | [1-32 character name](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-naming) | | name_localizations? | ?dictionary with keys in [available locales](#DOCS_REFERENCE/locales) | Localization dictionary for the `name` field. Values follow the same restrictions as `name` | @@ -71,7 +71,7 @@ Application commands are native ways to interact with apps in the Discord client ###### Application Command Option Type | Name | Value | Note | -| ----------------- | ----- | -------------------------------------------------------------- | +|-------------------|-------|----------------------------------------------------------------| | SUB_COMMAND | 1 | | | SUB_COMMAND_GROUP | 2 | | | STRING | 3 | | @@ -89,7 +89,7 @@ Application commands are native ways to interact with apps in the Discord client If you specify `choices` for an option, they are the **only** valid values for a user to pick | Field | Type | Description | -| ------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | +|---------------------|-----------------------------------------------------------------------|---------------------------------------------------------------------------------------------| | name | string | 1-100 character choice name | | name_localizations? | ?dictionary with keys in [available locales](#DOCS_REFERENCE/locales) | Localization dictionary for the `name` field. Values follow the same restrictions as `name` | | value | string, integer, or double \* | Value for the choice, up to 100 characters if string | @@ -268,7 +268,7 @@ When the permissions for a specific command are unsynced, meaning it doesn't ali Returned when fetching the permissions for an app's command(s) in a guild. | Field | Type | Description | -| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | +|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------| | id | snowflake | ID of the command or the application ID | | application_id | snowflake | ID of the application the command belongs to | | guild_id | snowflake | ID of the guild | @@ -281,7 +281,7 @@ When the `id` field is the application ID instead of a command ID, the permissio Application command permissions allow you to enable or disable commands for specific users, roles, or channels within a guild. | Field | Type | Description | -| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | id | snowflake | ID of the role, user, or channel. It can also be a [permission constant](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-permissions-object-application-command-permissions-constants) | | type | [application command permission type](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-permissions-object-application-command-permission-type) | role (`1`), user (`2`), or channel (`3`) | | permission | boolean | `true` to allow, `false`, to disallow | @@ -291,14 +291,14 @@ Application command permissions allow you to enable or disable commands for spec The following constants can be used in the `id` field for command permissions payloads. | Permission | Value | Type | Description | -| ------------ | -------------- | --------- | ----------------------- | +|--------------|----------------|-----------|-------------------------| | `@everyone` | `guild_id` | snowflake | All members in a guild | | All Channels | `guild_id - 1` | snowflake | All channels in a guild | ###### Application Command Permission Type | Name | Value | -| ------- | ----- | +|---------|-------| | ROLE | 1 | | USER | 2 | | CHANNEL | 3 | @@ -1046,7 +1046,7 @@ Fetch all of the global commands for your application. Returns an array of [appl ###### Query String Params | Field | Type | Description | -| ------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|---------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | with_localizations? | boolean | Whether to include full localization dictionaries (`name_localizations` and `description_localizations`) in the returned objects, instead of the `name_localized` and `description_localized` fields. Default `false`. | ## Create Global Application Command % POST /applications/{application.id#DOCS_RESOURCES_APPLICATION/application-object}/commands @@ -1059,7 +1059,7 @@ Create a new global command. Returns `201` if a command with the same name does ###### JSON Params | Field | Type | Description | -| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | name | string | [Name of command](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-naming), 1-32 characters | | name_localizations? | ?dictionary with keys in [available locales](#DOCS_REFERENCE/locales) | Localization dictionary for the `name` field. Values follow the same restrictions as `name` | | description? | string | 1-100 character description for `CHAT_INPUT` commands | @@ -1085,7 +1085,7 @@ Edit a global command. Returns `200` and an [application command](#DOCS_INTERACT ###### JSON Params | Field | Type | Description | -| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | name? | string | [Name of command](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-naming), 1-32 characters | | name_localizations? | ?dictionary with keys in [available locales](#DOCS_REFERENCE/locales) | Localization dictionary for the `name` field. Values follow the same restrictions as `name` | | description? | string | 1-100 character description | @@ -1117,7 +1117,7 @@ Fetch all of the guild commands for your application for a specific guild. Retur ###### Query String Params | Field | Type | Description | -| ------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|---------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | with_localizations? | boolean | Whether to include full localization dictionaries (`name_localizations` and `description_localizations`) in the returned objects, instead of the `name_localized` and `description_localized` fields. Default `false`. | ## Create Guild Application Command % POST /applications/{application.id#DOCS_RESOURCES_APPLICATION/application-object}/guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/commands @@ -1130,7 +1130,7 @@ Create a new guild command. New guild commands will be available in the guild im ###### JSON Params | Field | Type | Description | -| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | name | string | [Name of command](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-naming), 1-32 characters | | name_localizations? | ?dictionary with keys in [available locales](#DOCS_REFERENCE/locales) | Localization dictionary for the `name` field. Values follow the same restrictions as `name` | | description? | string | 1-100 character description for `CHAT_INPUT` commands | @@ -1155,7 +1155,7 @@ Edit a guild command. Updates for guild commands will be available immediately. ###### JSON Params | Field | Type | Description | -| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | name? | string | [Name of command](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-naming), 1-32 characters | | name_localizations? | ?dictionary with keys in [available locales](#DOCS_REFERENCE/locales) | Localization dictionary for the `name` field. Values follow the same restrictions as `name` | | description? | string | 1-100 character description | @@ -1179,7 +1179,7 @@ Takes a list of application commands, overwriting the existing command list for ###### Bulk Application Command JSON Params | Field | Type | Description | -| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | id? | snowflake | ID of the command, if known | | name | string | [Name of command](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-naming), 1-32 characters | | name_localizations? | ?dictionary with keys in [available locales](#DOCS_REFERENCE/locales) | Localization dictionary for the `name` field. Values follow the same restrictions as `name` | @@ -1221,7 +1221,7 @@ You can add up to 100 permission overwrites for a command. ###### JSON Params | Field | Type | Description | -| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | +|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------| | permissions | array of [application command permissions](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-permissions-object-application-command-permissions-structure) | Permissions for the command in the guild | ## Batch Edit Application Command Permissions % PUT /applications/{application.id#DOCS_RESOURCES_APPLICATION/application-object}/guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/commands/permissions diff --git a/docs/interactions/Message_Components.md b/docs/interactions/Message_Components.md index 18a3fdaa3b..a213562288 100644 --- a/docs/interactions/Message_Components.md +++ b/docs/interactions/Message_Components.md @@ -15,7 +15,7 @@ The top-level `components` field is an array of [Action Row](#DOCS_INTERACTIONS_ ###### Component Types | Type | Name | Description | -| ---- | ------------------ | ------------------------------------------------- | +|------|--------------------|---------------------------------------------------| | 1 | Action Row | Container for other components | | 2 | Button | Button object | | 3 | String Select | Select menu for picking from defined text options | @@ -91,7 +91,7 @@ Buttons are interactive components that render in messages. They can be clicked ###### Button Structure | Field | Type | Description | -| ---------- | --------------------------------------------------- | ----------------------------------------------------------------------------------- | +|------------|-----------------------------------------------------|-------------------------------------------------------------------------------------| | type | integer | `2` for a button | | style | integer | A [button style](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/button-object-button-styles) | | label? | string | Text that appears on the button; max 80 characters | @@ -109,7 +109,7 @@ Buttons come in a variety of styles to convey different types of actions. These ###### Button Styles | Name | Value | Color | Required Field | -| --------- | ----- | ------------------------ | -------------- | +|-----------|-------|--------------------------|----------------| | Primary | 1 | blurple | `custom_id` | | Secondary | 2 | grey | `custom_id` | | Success | 3 | green | `custom_id` | @@ -215,7 +215,7 @@ There are 5 different [select menu components](#DOCS_INTERACTIONS_MESSAGE_COMPON The string select menu (type `3`) is the *only* select type that allows (and *requires*) apps to define the `options` that appear in the dropdown list. The other 4 select menu components (users, roles, mentionables, and channels) are auto-populated with options corresponding to the resource type—similar to [command option types](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-type). -In addition to the `values` array in all [select menu interaction payloads](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-menu-interaction), auto-populated select menu components (users, roles, mentionables, and channels) also include an additional [`resolved` object](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-menu-resolved-object) that provides additional details about the user's selected resource. +In addition to the `values` array in all [select menu interaction payloads](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-menu-interaction), auto-populated select menu components (user, role, mentionable, and channel) also include an additional [`resolved` object](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-menu-resolved-object) that provides additional details about the user's selected resource. The payloads for the select menu components are detailed in the [select menu structure](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-menu-structure). @@ -275,31 +275,41 @@ The payloads for the select menu components are detailed in the [select menu str ###### Select Menu Structure -| Field | Type | Description | -| ------------------ | ----------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| type | integer | [Type](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/component-object-component-types) of select menu component (text: `3`, user: `5`, role: `6`, mentionable: `7`, channels: `8`) | -| custom_id | string | ID for the select menu; max 100 characters | -| options?\* | array of [select options](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure) | Specified choices in a select menu (only required and available for string selects (type `3`); max 25 | -| channel_types?\*\* | array of [channel types](#DOCS_RESOURCES_CHANNEL/channel-object-channel-types) | List of channel types to include in the channel select component (type `8`) | -| placeholder? | string | Placeholder text if nothing is selected; max 150 characters | -| min_values? | integer | Minimum number of items that must be chosen (defaults to 1); min 0, max 25 | -| max_values? | integer | Maximum number of items that can be chosen (defaults to 1); max 25 | -| disabled? | boolean | Whether select menu is disabled (defaults to `false`) | +| Field | Type | Description | +|-----------------------|---------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| type | integer | [Type](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/component-object-component-types) of select menu component (text: `3`, user: `5`, role: `6`, mentionable: `7`, channels: `8`) | +| custom_id | string | ID for the select menu; max 100 characters | +| options?\* | array of [select options](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure) | Specified choices in a select menu (only required and available for string selects (type `3`); max 25 | +| channel_types?\*\* | array of [channel types](#DOCS_RESOURCES_CHANNEL/channel-object-channel-types) | List of channel types to include in the channel select component (type `8`) | +| placeholder? | string | Placeholder text if nothing is selected; max 150 characters | +| default_values?\*\*\* | array of [default value objects](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-default-value-structure) | List of default values for auto-populated select menu components; number of default values must be in the range defined by `min_values` and `max_values` | +| min_values? | integer | Minimum number of items that must be chosen (defaults to 1); min 0, max 25 | +| max_values? | integer | Maximum number of items that can be chosen (defaults to 1); max 25 | +| disabled? | boolean | Whether select menu is disabled (defaults to `false`) | \* `options` is required for string select menus (component type `3`), and unavailable for all other select menu components. \*\* `channel_types` can only be used for channel select menu components. +\*\*\* `default_values` is only available for auto-populated select menu components, which include user (`5`), role (`6`), mentionable (`7`), and channel (`8`) [components](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/component-object-component-types). + ###### Select Option Structure | Field | Type | Description | -| ------------ | ---------------------------------------------------------- | -------------------------------------------------------- | +|--------------|------------------------------------------------------------|----------------------------------------------------------| | label | string | User-facing name of the option; max 100 characters | | value | string | Dev-defined value of the option; max 100 characters | | description? | string | Additional description of the option; max 100 characters | | emoji? | partial [emoji](#DOCS_RESOURCES_EMOJI/emoji-object) object | `id`, `name`, and `animated` | | default? | boolean | Will show this option as selected by default | +###### Select Default Value Structure + +| Field | Type | Description | +|-------|-----------|-------------------------------------------------------------------------------| +| id | snowflake | ID of a user, role, or channel | +| type | string | Type of value that `id` represents. Either `"user"`, `"role"`, or `"channel"` | + ###### Select Menu Interaction ```json @@ -457,7 +467,9 @@ A sample `data` object (a subset of the interaction payload) for a channel selec ## Text Inputs -Text inputs are an interactive component that render on modals. They can be used to collect short-form or long-form text. +Text inputs are an interactive component that render in modals. They can be used to collect short-form or long-form text. + +When defining a text input component, you can set attributes to customize the behavior and appearance of it. However, not all attributes will be returned in the [text input interaction payload](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/text-input-object-text-input-interaction). ![A text input in a modal on desktop client](modal-desktop.png) @@ -484,23 +496,89 @@ Text inputs are an interactive component that render on modals. They can be used } ``` +### Text Input Object + ###### Text Input Structure -| Field | Type | Description | -| ------------ | ------- | ------------------------------------------------------------------------------------------- | -| type | integer | `4` for a text input | -| custom_id | string | Developer-defined identifier for the input; max 100 characters | -| style | integer | The [Text Input Style](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/text-inputs-text-input-styles) | -| label | string | Label for this component; max 45 characters | -| min_length? | integer | Minimum input length for a text input; min 0, max 4000 | -| max_length? | integer | Maximum input length for a text input; min 1, max 4000 | -| required? | boolean | Whether this component is required to be filled (defaults to `true`) | -| value? | string | Pre-filled value for this component; max 4000 characters | -| placeholder? | string | Custom placeholder text if the input is empty; max 100 characters | +| Field | Type | Description | +|--------------|---------|---------------------------------------------------------------------------------------------------| +| type | integer | `4` for a text input | +| custom_id | string | Developer-defined identifier for the input; max 100 characters | +| style | integer | The [Text Input Style](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/text-input-object-text-input-styles) | +| label | string | Label for this component; max 45 characters | +| min_length? | integer | Minimum input length for a text input; min 0, max 4000 | +| max_length? | integer | Maximum input length for a text input; min 1, max 4000 | +| required? | boolean | Whether this component is required to be filled (defaults to `true`) | +| value? | string | Pre-filled value for this component; max 4000 characters | +| placeholder? | string | Custom placeholder text if the input is empty; max 100 characters | ###### Text Input Styles | Name | Value | Description | -| --------- | ----- | ----------------- | +|-----------|-------|-------------------| | Short | 1 | Single-line input | | Paragraph | 2 | Multi-line input | + + +###### Text Input Interaction + +```json +{ + "application_id": "845027738276462632", + "channel": { + "flags": 0, + "guild_id": "772904309264089089", + "id": "772908445358620702", + "last_message_id": "113817814796417433", + "name": "general", + "nsfw": false, + "parent_id": "1113560261366927532", + "permissions": "281474976710655", + "position": 0, + "rate_limit_per_user": 0, + "topic": null, + "type": 0 + }, + "channel_id": "772908445358620702", + "data": { + "components": [ + { + "type": 1, + "components": [ + { + "custom_id": "name", + "type": 4, + "value": "John" + } + ] + } + ], + "custom_id": "cool_modal" + }, + "guild_id": "772904309264089089", + "id": "847587388497854464", + "member": { + "avatar": null, + "deaf": false, + "is_pending": false, + "joined_at": "2020-11-02T19:25:47.248000+00:00", + "mute": false, + "nick": null, + "pending": false, + "permissions": "17179869183", + "premium_since": null, + "roles": ["785609923542777878"], + "user": { + "avatar": "a_d5efa99b3eeaa7dd43acca82f5692432", + "global_name": "Mason", + "discriminator": "0", + "id": "53908232506183680", + "public_flags": 131141, + "username": "Mason" + } + }, + "token": "UNIQUE_TOKEN", + "type": 5, + "version": 1 +} +``` diff --git a/docs/interactions/Receiving_and_Responding.md b/docs/interactions/Receiving_and_Responding.md index dfa40dd1dd..b1425aa504 100644 --- a/docs/interactions/Receiving_and_Responding.md +++ b/docs/interactions/Receiving_and_Responding.md @@ -12,23 +12,24 @@ For [Message Components](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/) it includes ide ###### Interaction Structure -| Field | Type | Description | -| ---------------- | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | -| id | snowflake | ID of the interaction | -| application_id | snowflake | ID of the application this interaction is for | -| type | [interaction type](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) | Type of interaction | -| data?\* | [interaction data](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-data) | Interaction data payload | -| guild_id? | snowflake | Guild that the interaction was sent from | -| channel? | [partial channel](#DOCS_RESOURCES_CHANNEL/channel-object) object | Channel that the interaction was sent from | -| channel_id? | snowflake | Channel that the interaction was sent from | -| member?\*\* | [guild member](#DOCS_RESOURCES_GUILD/guild-member-object) object | Guild member data for the invoking user, including permissions | -| user? | [user](#DOCS_RESOURCES_USER/user-object) object | User object for the invoking user, if invoked in a DM | -| token | string | Continuation token for responding to the interaction | -| version | integer | Read-only property, always `1` | -| message? | [message](#DOCS_RESOURCES_CHANNEL/message-object) object | For components, the message they were attached to | -| app_permissions? | string | Bitwise set of permissions the app or bot has within the channel the interaction was sent from | -| locale?\*\*\* | string | Selected [language](#DOCS_REFERENCE/locales) of the invoking user | -| guild_locale? | string | [Guild's preferred locale](#DOCS_RESOURCES_GUILD/guild-object), if invoked in a guild | +| Field | Type | Description | +|------------------|-----------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------| +| id | snowflake | ID of the interaction | +| application_id | snowflake | ID of the application this interaction is for | +| type | [interaction type](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) | Type of interaction | +| data?\* | [interaction data](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-data) | Interaction data payload | +| guild_id? | snowflake | Guild that the interaction was sent from | +| channel? | [partial channel](#DOCS_RESOURCES_CHANNEL/channel-object) object | Channel that the interaction was sent from | +| channel_id? | snowflake | Channel that the interaction was sent from | +| member?\*\* | [guild member](#DOCS_RESOURCES_GUILD/guild-member-object) object | Guild member data for the invoking user, including permissions | +| user? | [user](#DOCS_RESOURCES_USER/user-object) object | User object for the invoking user, if invoked in a DM | +| token | string | Continuation token for responding to the interaction | +| version | integer | Read-only property, always `1` | +| message? | [message](#DOCS_RESOURCES_CHANNEL/message-object) object | For components, the message they were attached to | +| app_permissions? | string | Bitwise set of permissions the app or bot has within the channel the interaction was sent from | +| locale?\*\*\* | string | Selected [language](#DOCS_REFERENCE/locales) of the invoking user | +| guild_locale? | string | [Guild's preferred locale](#DOCS_RESOURCES_GUILD/guild-object), if invoked in a guild | +| entitlements | array of [entitlement](#DOCS_MONETIZATION_ENTITLEMENTS/entitlement-object) objects | For [monetized apps](#DOCS_MONETIZATION_OVERVIEW), any entitlements for the invoking user, representing access to premium [SKUs](#DOCS_MONETIZATION_SKUS) | \* This is always present on application command, message component, and modal submit interaction types. It is optional for future-proofing against new interaction types @@ -39,7 +40,7 @@ For [Message Components](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/) it includes ide ###### Interaction Type | Name | Value | -| -------------------------------- | ----- | +|----------------------------------|-------| | PING | 1 | | APPLICATION_COMMAND | 2 | | MESSAGE_COMPONENT | 3 | @@ -53,34 +54,35 @@ While the `data` field is guaranteed to be present for all [interaction types](# ###### Application Command Data Structure > info -> Sent in `APPLICATION_COMMAND` and `APPLICATION_COMMAND_AUTOCOMPLETE` interactions. - -| Field | Type | Description | -| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| id | snowflake | the [`ID`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure) of the invoked command | -| name | string | the [`name`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure) of the invoked command | -| type | integer | the [`type`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure) of the invoked command | -| resolved? | [resolved data](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-resolved-data-structure) | converted users + roles + channels + attachments | +> Sent in `APPLICATION_COMMAND` and `APPLICATION_COMMAND_AUTOCOMPLETE` interactions. + +| Field | Type | Description | +|------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| id | snowflake | the [`ID`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure) of the invoked command | +| name | string | the [`name`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure) of the invoked command | +| type | integer | the [`type`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure) of the invoked command | +| resolved? | [resolved data](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-resolved-data-structure) | converted users + roles + channels + attachments | | options?\* | array of [application command interaction data option](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-application-command-interaction-data-option-structure) | the params + values from the user | -| guild_id? | snowflake | the id of the guild the command is registered to | -| target_id? | snowflake | id of the user or message targeted by a [user](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/user-commands) or [message](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/message-commands) command | +| guild_id? | snowflake | the id of the guild the command is registered to | +| target_id? | snowflake | id of the user or message targeted by a [user](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/user-commands) or [message](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/message-commands) command | \* This [can be partial](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/autocomplete) when in response to `APPLICATION_COMMAND_AUTOCOMPLETE` ###### Message Component Data Structure | Field | Type | Description | -| -------------- | ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | +|----------------|-------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------| | custom_id | string | the [`custom_id`](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/custom-id) of the component | | component_type | integer | the [type](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/component-object-component-types) of the component | | values?\* | array of [select option values](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure) | values the user selected in a [select menu](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object) component | +| resolved? | [resolved data](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-resolved-data-structure) | resolved entities from selected options | \* This is always present for select menu components ###### Modal Submit Data Structure | Field | Type | Description | -| ---------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | +|------------|-----------------------------------------------------------------------------------------|---------------------------------------------------------------------------------| | custom_id | string | the [`custom_id`](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/custom-id) of the modal | | components | array of [message components](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/message-components) | the values submitted by the user | @@ -90,7 +92,7 @@ While the `data` field is guaranteed to be present for all [interaction types](# > If data for a Member is included, data for its corresponding User will also be included. | Field | Type | Description | -| ------------- | ---------------------------------------------------------------------------------------- | ----------------------------------- | +|---------------|------------------------------------------------------------------------------------------|-------------------------------------| | users? | Map of Snowflakes to [user](#DOCS_RESOURCES_USER/user-object) objects | the ids and User objects | | members?\* | Map of Snowflakes to [partial member](#DOCS_RESOURCES_GUILD/guild-member-object) objects | the ids and partial Member objects | | roles? | Map of Snowflakes to [role](#DOCS_TOPICS_PERMISSIONS/role-object) objects | the ids and Role objects | @@ -108,13 +110,13 @@ All options have names, and an option can either be a parameter and input value- `value` and `options` are mutually exclusive. -| Field | Type | Description | -| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| name | string | Name of the parameter | -| type | integer | Value of [application command option type](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-type) | -| value? | string, integer, double, or boolean | Value of the option resulting from user input | +| Field | Type | Description | +|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------| +| name | string | Name of the parameter | +| type | integer | Value of [application command option type](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-type) | +| value? | string, integer, double, or boolean | Value of the option resulting from user input | | options? | array of [application command interaction data option](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-application-command-interaction-data-option-structure) | Present if this option is a group or subcommand | -| focused? | boolean | `true` if this option is the currently focused option for autocomplete | +| focused? | boolean | `true` if this option is the currently focused option for autocomplete | ### Message Interaction Object @@ -126,14 +128,13 @@ This is sent on the [message object](#DOCS_RESOURCES_CHANNEL/message-object) whe ###### Message Interaction Structure | Field | Type | Description | -| ------- | --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|---------|-----------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | id | snowflake | ID of the interaction | | type | [interaction type](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) | Type of interaction | | name | string | Name of the [application command](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure), including subcommands and subcommand groups | | user | [user object](#DOCS_RESOURCES_USER/user-object) | User who invoked the interaction | | member? | [partial member](#DOCS_RESOURCES_GUILD/guild-member-object) object | Member who invoked the interaction in the guild | - ## Interactions and Bot Users We're all used to the way that Discord bots have worked for a long time. You make an application in the developer portal with a bot user, then use that bot's token to connect to the Gateway and make requests to Discord's API. @@ -148,8 +149,8 @@ Welcome to the new world. When a user interacts with your app, your app will receive an **[Interaction](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object)**. Your app can receive an interaction in one of two ways: -- Via [Interaction Create](#DOCS_TOPICS_GATEWAY_EVENTS/interaction-create) gateway event -- Via outgoing webhook +- Via [Interaction Create](#DOCS_TOPICS_GATEWAY_EVENTS/interaction-create) gateway event +- Via outgoing webhook These two methods are **mutually exclusive**; you can _only_ receive Interactions one of the two ways. The `INTERACTION_CREATE` [Gateway Event](#DOCS_TOPICS_GATEWAY_EVENTS/interaction-create) may be handled by connected clients, while the webhook method detailed below does not require a connected client. @@ -178,11 +179,11 @@ You'll also need to properly set up [Security and Authorization](#DOCS_INTERACTI An [Interaction](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object) includes metadata to aid your application in handling it as well as `data` specific to the interaction type. You can find samples for each interaction type on their respective pages: -- [Slash Commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/slash-commands-example-interaction) -- [User Commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/user-commands-example-interaction) -- [Message Commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/message-commands-example-interaction) -- [Message Components](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/component-interaction-object-sample-component-interaction) -- [Select Menu Message Components](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-menu-interaction) +- [Slash Commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/slash-commands-example-interaction) +- [User Commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/user-commands-example-interaction) +- [Message Commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/message-commands-example-interaction) +- [Message Components](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/component-interaction-object-sample-component-interaction) +- [Select Menu Message Components](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-menu-interaction) An explanation of all the fields can be found in our [data models](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object). @@ -199,14 +200,14 @@ There are a number of ways you can respond to an interaction: ###### Interaction Response Structure | Field | Type | Description | -| ----- | ---------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | +|-------|------------------------------------------------------------------------------------------------------------------------------------------|------------------------------| | type | [interaction callback type](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type) | the type of response | | data? | [interaction callback data](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-data-structure) | an optional response message | ###### Interaction Callback Type | Name | Value | Description | -| --------------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------- | +|-----------------------------------------|-------|---------------------------------------------------------------------------------------------------------------| | PONG | 1 | ACK a `Ping` | | CHANNEL_MESSAGE_WITH_SOURCE | 4 | respond to an interaction with a message | | DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE | 5 | ACK an interaction and edit a response later, the user sees a loading state | @@ -214,10 +215,13 @@ There are a number of ways you can respond to an interaction: | UPDATE_MESSAGE\* | 7 | for components, edit the message the component was attached to | | APPLICATION_COMMAND_AUTOCOMPLETE_RESULT | 8 | respond to an autocomplete interaction with suggested choices | | MODAL\*\* | 9 | respond to an interaction with a popup modal | +| PREMIUM_REQUIRED\*\*\* | 10 | respond to an interaction with an upgrade button, only available for apps with monetization enabled | \* Only valid for [component-based](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/) interactions -\*\* Not available for MODAL_SUBMIT and PING interactions. +\*\* Not available for `MODAL_SUBMIT` and `PING` interactions. + +\*\*\* Not available for `APPLICATION_COMMAND_AUTOCOMPLETE` and `PING` interactions. ###### Interaction Callback Data Structure @@ -225,9 +229,8 @@ There are a number of ways you can respond to an interaction: Not all message fields are currently supported. - -| Field | Type | Description | -| ----------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Field | Type | Description | +|-------------------|----------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | tts? | boolean | is the response TTS | | content? | string | message content | | embeds? | array of [embeds](#DOCS_RESOURCES_CHANNEL/embed-object) | supports up to 10 embeds | @@ -240,8 +243,8 @@ Not all message fields are currently supported. ###### Autocomplete -| Field | Type | Description | -| ------- | ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | +| Field | Type | Description | +|---------|------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------| | choices | array of [choices](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-choice-structure) | autocomplete choices (max of 25 choices) | ###### Modal @@ -249,11 +252,11 @@ Not all message fields are currently supported. > warn > Support for components in modals is currently limited to type 4 (Text Input). -| Field | Type | Description | -| ---------- | ------------------------------------------------------------- | -------------------------------------------------------------------- | -| custom_id | string | a developer-defined identifier for the modal, max 100 characters | -| title | string | the title of the popup modal, max 45 characters | -| components | array of [components](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/) | between 1 and 5 (inclusive) components that make up the modal | +| Field | Type | Description | +|------------|---------------------------------------------------------------|------------------------------------------------------------------| +| custom_id | string | a developer-defined identifier for the modal, max 100 characters | +| title | string | the title of the popup modal, max 45 characters | +| components | array of [components](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/) | between 1 and 5 (inclusive) components that make up the modal | > warn > While interaction responses and followups are webhooks, they respect @everyone's ability to ping @everyone / @here . Nonetheless if your application responds with user data, you should still use [`allowed_mentions`](#DOCS_RESOURCES_CHANNEL/allowed-mentions-object) to filter which mentions in the content actually ping. Other differences include the ability to send named links in the message content (`[text](url)`). @@ -299,16 +302,16 @@ r = requests.post(url, json=json) ``` > info -> Interaction `tokens` are valid for **15 minutes** and can be used to send followup messages but you **must send an initial response within 3 seconds of receiving the event**. If the 3 second deadline is exceeded, the token will be invalidated. +> Interaction `tokens` are valid for **15 minutes** and can be used to send followup messages but you **must send an initial response within 3 seconds of receiving the event**. If the 3 second deadline is exceeded, the token will be invalidated. ## Followup Messages Sometimes, your bot will want to send followup messages to a user after responding to an interaction. Or, you may want to edit your original response. Whether you receive Interactions over the gateway or by outgoing webhook, you can use the following endpoints to edit your initial response or send followup messages: -- [`PATCH /webhooks///messages/@original`](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-original-interaction-response) to edit your initial response to an Interaction -- [`DELETE /webhooks///messages/@original`](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response) to delete your initial response to an Interaction -- [`POST /webhooks//`](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message) to send a new followup message -- [`PATCH /webhooks///messages/`](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message) to edit a message sent with that `token` +- [`PATCH /webhooks///messages/@original`](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-original-interaction-response) to edit your initial response to an Interaction +- [`DELETE /webhooks///messages/@original`](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response) to delete your initial response to an Interaction +- [`POST /webhooks//`](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message) to send a new followup message +- [`PATCH /webhooks///messages/`](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message) to edit a message sent with that `token` > info > Interactions webhooks share the same rate limit properties as normal webhooks. @@ -324,29 +327,29 @@ The internet is a scary place, especially for people hosting open, unauthenticat Every Interaction is sent with the following headers: -- `X-Signature-Ed25519` as a signature -- `X-Signature-Timestamp` as a timestamp +- `X-Signature-Ed25519` as a signature +- `X-Signature-Timestamp` as a timestamp Using your favorite security library, you **must validate the request each time you receive an [interaction](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object)**. If the signature fails validation, respond with a `401` error code. Here's a couple code examples: ```js -const nacl = require('tweetnacl'); +const nacl = require("tweetnacl"); // Your public key can be found on your application in the Developer Portal -const PUBLIC_KEY = 'APPLICATION_PUBLIC_KEY'; +const PUBLIC_KEY = "APPLICATION_PUBLIC_KEY"; -const signature = req.get('X-Signature-Ed25519'); -const timestamp = req.get('X-Signature-Timestamp'); +const signature = req.get("X-Signature-Ed25519"); +const timestamp = req.get("X-Signature-Timestamp"); const body = req.rawBody; // rawBody is expected to be a string, not raw bytes const isVerified = nacl.sign.detached.verify( - Buffer.from(timestamp + body), - Buffer.from(signature, 'hex'), - Buffer.from(PUBLIC_KEY, 'hex') + Buffer.from(timestamp + body), + Buffer.from(signature, "hex"), + Buffer.from(PUBLIC_KEY, "hex") ); if (!isVerified) { - return res.status(401).end('invalid request signature'); + return res.status(401).end("invalid request signature"); } ``` diff --git a/docs/ja/Getting_Started.mdx b/docs/ja/Getting_Started.mdx new file mode 100644 index 0000000000..fc2ba16ebd --- /dev/null +++ b/docs/ja/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# 初めてのDiscordアプリ作成 + +Discordアプリは、様々なAPIやインタラクティブ機能により、あなたのサーバーのカスタマイズや拡張を助けてくれる存在です。このガイドでは、JavaScriptを使って初めてのDiscordアプリを作るお手伝いをします。ガイドを最後までたどれば、スラッシュコマンドの使用、メッセージの使用、コンポーネント・インタラクションへの応答に対応したアプリが完成します。 + +サーバーメンバーがじゃんけん(ただし通常の3つではなく7つの手が選べる)をできるDiscordアプリを作ります。このガイドは初心者向けですが、[JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics)の基本を知っていることが前提となります。 + + +これが完成したアプリのお手本です: + +![アプリ実例のデモ](getting-started-demo.gif) + +このユーザーフローをもう少し明確にしてみましょう: + +1. ユーザー1が新しいゲームを開始し、アプリの`/challenge`スラッシュコマンドを使ってオブジェクトを選ぶ +2. 他のメンバーに挑戦を促すボタンを添えたメッセージがチャンネルに送られる +3. ユーザー2が**Accept(承諾)**ボタンを押す +4. ユーザー2に、オブジェクトを選ぶよう促す一時メッセージが送られる +5. ゲームの結果が、元のチャンネルに公開で投稿される + + + +- **[Githubレポジトリ](https://github.com/discord/discord-example-app)**:このガイドのコードと、追加の機能固有のコード例がいくつか掲載されています。 +- **[discord-interactions](https://github.com/discord/discord-interactions-js)**:Discordアプリのタイプおよびヘルパー関数を提供するライブラリです。 +- **[Express](https://expressjs.com)**:人気のJavaScriptウェブフレームワーク。Discordがリクエストを送信できるサーバーの作成に使います。 +- **[Glitch](https://glitch.com/)**:初期のプロトタイピングおよび開発段階でのアプリの構築およびホストをシンプル化してくれるオンライン環境です。**[ngrok](https://ngrok.com/)**のようなツールを用いてローカルで開発することもできます。 + + +--- + +## ステップ1:アプリを作成する + +アプリが既にない場合はまず、開発者ポータルでアプリを作成する必要があります: + + + +アプリの名前を入力し、**Create(作成)**を押してください。 + +アプリを作成すると、アプリの設定の**概要**ページが開きます。ここではアプリの説明やアイコンなど、基本情報を更新できます。Yまた**アプリケーションID**と**インタラクション・エンドポイントURL**も確認できます。これらはガイドで後ほど使用します。 + +### Botを設定する + +次にアプリの[Botユーザー](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts)を設定します。これにより、Botがサーバー内で他のメンバーと同様に表示・動作するようになります。 + +左側のサイドバーで**Bot**をクリックします。このページでは、Botの[特権インテント(privileged intents)](#DOCS_TOPICS_GATEWAY/privileged-intents)や、Botが他のユーザーによってインストールできるかどうかなどの設定を行えます。 + + +インテントとは、[ゲートウェイAPI接続](#DOCS_TOPICS_GATEWAY)を作成する際に、Discordがあなたのアプリにどのイベントを送信するかを決定するものです。たとえば、ユーザーがメッセージにリアクションを追加したときに動作するアプリを作りたいなら、`GUILD_MESSAGE_REACTIONS` (`1 << 10`) インテントを渡します。 + +一部のインテントは[特権](#DOCS_TOPICS_GATEWAY/privileged-intents)インテントであり、センシティブと判断される可能性のあるデータ(メッセージの内容など)にアプリがアクセスできるようにします。特権インテントはアプリの設定の**Bot**ページに表示され、ここで切り替えできます。標準の非特権インテントは、追加の権限や設定を必要としません。 + +インテントについての詳細情報、利用可能な全インテント一覧とそれらに関連付けられたイベントについては、[ゲートウェイ・ドキュメント](#DOCS_TOPICS_GATEWAY/gateway-intents)をご覧ください。 + + +![アプリ設定のBotタブ](app-add-bot.png) + +**Bot**ページには、Botのトークンをコピーしたりリセットしたりできる**トークン**セクションもあります。 + +BotトークンはAPIリクエストの認証に使われ、Botユーザーの権限を含んでいるため、*きわめて機密性が高い*ものです。トークンを共有したり、何らかのバージョン管理にチェックインしたりすることは*絶対に*しないでください。 + +トークンをコピーし、安全な場所(パスワードマネージャーなど)に保管しておきましょう。 + +> 警告 +> トークンは再生成しない限り2度と見ることはできませんので、必ず安全な場所に保管してください。 + +### スコープとBot権限を追加する + +アプリは、ダウンロードするユーザーから、Discordでアクション(スラッシュコマンドを作成する、サーバーメンバーのリストを取得するなど)を行う許可を得る必要があります。アプリをインストールする前に、スコープと権限をいくつか選択しましょう。 + + +アプリの作成にあたって、あなたのアプリがDiscordサーバーでできること、アクセスできるものを定めるのがスコープと権限です。 + +- [OAuth2スコープ](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes)は、インストールまたは認証を行うユーザーに代わってあなたのアプリが行えるデータアクセスやアクションを定めます。 +- [権限](#DOCS_TOPICS_PERMISSIONS/permission-overwrites)は、Botユーザーに与える粒度の細かい権限であり、Discordにおける他のユーザーが有しているのと同様のものです。インストールするユーザーが承認することもできますし、後から[権限の上書き](#DOCS_TOPICS_PERMISSIONS/permission-overwrites)を用いてサーバー設定で更新することもできます。 + + +左側のサイドバーで**OAuth2**をクリックし、続いて**URLジェネレータ(URL generator)**を選択します。 + +> 情報 +> URLジェネレータは、あなたがアプリ用に選択したスコープと権限に基づいてインストール用リンクを生成します。このリンクで自分のサーバーにアプリをインストールできるほか、他の人と共有してインストールしてもらうこともできます。 + +今のところは2つのスコープを追加してみましょう: +- `applications.commands`:アプリが[コマンド](#DOCS_INTERACTIONS_APPLICATION_COMMANDS)を生成できるようにします。 +- `bot`:Botユーザーを追加します。`bot`を選択したら、Bot用に他の各種権限を追加できます。今のところは、**メッセージを送信**だけチェックしておきましょう。 + +[OAuth2スコープ](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes)の一覧をご確認いただくか、ドキュメントで[権限](#DOCS_TOPICS_PERMISSIONS)についての詳細をご覧ください。 + +### アプリをインストールする + +スコープを追加したら、URLが表示されます。これをコピーしてアプリをインストールすることができます。 + +![URLジェネレータのスクリーンショット](url-generator.png) + +> 情報 +> アプリ開発にあたっては、他の人がアクティブに利用していないサーバーでビルドおよびテストを行ってください。自分のサーバーがまだない方は、[無料で作成できます](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server-)。 + +上記よりURLをコピーし、ブラウザにペーストしてください。インストールのステップを踏む際は、アプリの開発とテストをできるサーバーに間違いなくインストールしていることを確かめてください。 + +アプリをインストールしたら、サーバーに移動して、アプリが参加したことを確かめましょう✨ + +アプリの設定とインストールが完了したら、開発を始めましょう。 + +--- + +## ステップ2:アプリを実行する + +アプリ実例で使われたコードはすべて[Githubレポジトリ](https://github.com/discord/discord-example-app)に掲載されています。 + +開発がしやすくなるよう、このアプリでは、タイプおよびヘルパー関数を提供する[discord-interactions](https://github.com/discord/discord-interactions-js)を使用しています。他の言語やライブラリを使用したい場合は、[コミュニティ・リソース](#DOCS_TOPICS_COMMUNITY_RESOURCES)ドキュメントをご確認ください。 + +### プロジェクトをリミックスする + +このガイドでは、ブラウザでクローンと開発ができるGlitchを使用しています。ローカルでアプリの開発をしたい場合は、[README](https://github.com/discord/discord-example-app#running-app-locally)にngrokの使い方が掲載されています。 + +> 情報 +> Glitchは開発とテストには最適ですが、[技術的な制限があるため](https://help.glitch.com/hc/en-us/articles/16287495313293-Technical-Restrictions)、プロダクションアプリについては他のホスティング・プロバイダをご検討ください。 + +まず**[Glitchプロジェクトをリミックス(またはクローン)しましょう🎏](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)** + +プロジェクトをリミックスすると、新しいGlitchプロジェクトが開きます。 + + +![Glitchプロジェクトの概要](glitch-project.png) + +- あなたの**プロジェクト名**は、プロジェクト固有の名前であり、左上隅に表示されます +- **`.env`**はあなたのアプリのクレデンシャルがすべて保存されるファイルです +- **ログ**は、あなたのプロジェクトのアウトプットがある場所です。アプリがきちんと実行されているかを確かめたり、アプリに生じたエラーをチェックしたりするのに役立ちます +- 右上隅の**共有(Share)**ボタンを押すと、ライブプロジェクトURLが表示されます。このURLは、このガイドで後ほどインタラクティビティを設定するのに必要です + + +#### プロジェクトの構造 + +プロジェクト用のファイルはすべて、Glitchプロジェクトの左側に表示されます。下記は主なフォルダーとファイルを概観したものです: + +``` +├── examples -> 特定機能向けの短いサンプルアプリ +│ ├── app.js -> 書き終えたapp.jsコード +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> あなたのクレデンシャルとID +├── app.js -> アプリのメインエントリポイント +├── commands.js -> スラッシュコマンドのペイロードとヘルパー +├── game.js -> RPS固有のロジック +├── utils.js -> ユーティリティ関数と列挙型 +├── package.json +├── README.md +└── .gitignore +``` + +### クレデンシャルを追加する + +`app.js`ファイルには既にコードが入っていますが、リクエストを行うにはアプリのトークンとIDが必要です。あなたのクレデンシャルはすべて直接`.env`ファイルに保存できます。 + +まず、先ほどのBotユーザーのトークンをコピーし、`.env`ファイルの**`DISCORD_TOKEN`**変数にペーストします。 + +次に、アプリの**概要**ページに移動し、**アプリID**と**パブリックキー**をコピーします。`.env`ファイルに、**`APP_ID`**および**`PUBLIC_KEY`**として値をペーストします。 + +クレデンシャルの設定が終わったら、スラッシュコマンドをインストールしてハンドルしてみましょう。 + +### スラッシュコマンドをインストールする + +> 情報 +> アプリはスラッシュコマンドをインストールするにあたり、[`node-fetch`](https://github.com/node-fetch/node-fetch)を利用しています。インストールの実装は、`DiscordRequest()`関数内の`utils.js`で確認できます。 + +プロジェクトには`register`スクリプトが含まれています。これを用いて、`commands.js`の最下部で定義されている`ALL_COMMANDS`のコマンドをインストールできます。これはHTTP APIの[`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands)エンドポイントを呼び出すことで、コマンドをグローバルコマンドとしてインストールします。 + +コマンドをカスタマイズしたい、または新しいものを追加したい場合は、[コマンド・ドキュメント](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure)にてコマンドの構造をご確認ください。 + +Glitchプロジェクトの最下部にある**ターミナル(Terminal)**をクリックして`register`スクリプトを実行し、下記のコマンドをペーストします: + +``` +npm run register +``` + +Enterキーを押してコマンドを実行します。 + +サーバーに戻ると、スラッシュコマンドが表示されるようになっているはずです。ただし、アプリはまだDiscordからのリクエストを受け取ったりハンドルしたりできないため、実行しても何も起きません。 + + +Discordには2種類のAPIがあり、これらを組み合わせてアプリを作成できます: + +- **[HTTP API](#DOCS_REFERENCE/http-api)**:RESTに似たAPIであり、Discord上でのデータ送信やアップデート、リソースに関するデータの取得などの全般的操作に使用します。 +- **[Gateway API](#DOCS_REFERENCE/gateway-websocket-api)**:WebSocketベースのAPIであり、ステートを維持したり、Discordサーバーで起こっているイベントをリッスンしたりするのに便利です。このガイドでは使いませんが、ゲートウェイ接続の作成方法や、リッスンできる各種イベントについては、[ゲートウェイ・ドキュメント](#DOCS_TOPICS_GATEWAY)をご覧ください。 + + +--- + +## ステップ3:インタラクティビティをハンドルする + +Discordでは、アプリがスラッシュコマンド・リクエスト(およびその他のインタラクション)を受け取れるようにするには、それらを送信するための公開URLが必要となります。このURLは、アプリの設定で**インタラクション・エンドポイントURL**として設定できます。 + +### インタラクション・エンドポイントURLを追加する + +Glitchプロジェクトでは、デフォルトで公開URLが見られるようになっています。右上隅の**共有(Share)**ボタンをクリックしてプロジェクトのURLをコピーし、続いてモーダルの下部近くにある「ライブ中のサイト(Live Site)」プロジェクトリンクをコピーしてください。 + +> 情報 +> ローカルで開発をしている場合は、ローカルの環境にリクエストをトンネリングする手順を[Github README](https://github.com/discord/discord-example-app#running-app-locally)で確認できます。 + +リンクがコピーできたら、[開発者ポータル](https://discord.com/developers/applications)からアプリの設定を開きます。 + +アプリの**概要**ページに**インタラクティブ・エンドポイントURL**オプションがあります。ここでアプリのURLをペーストし、Expressアプリがリクエストをリッスンするよう設定される`/interactions`をアペンドできます。 + +![アプリ設定におけるインタラクション・エンドポイントURL](interactions-url.png) + +**変更を保存(Save Changes)**をクリックし、エンドポイントが認証されたことを確かめましょう。 + +サンプルアプリは2つの方法で認証をハンドリングします: +- `PUBLIC_KEY`およびラッパー関数(`utils.js`よりインポート)を伴った[discord-interactionsパッケージ](https://github.com/discord/discord-interactions-js#usage)を利用する。これにより、[Expressの`verify`インターフェース](http://expressjs.com/en/5x/api.html#express.json)に適合します。これはあなたのアプリにリクエストが入ってくるたびに実行されます。 +- 入ってくる`PING`リクエストに応答する。 + +アプリがインタラクションを受け取れるようにする方法について、詳しくは[インタラクション・ドキュメント](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction)をご覧ください。 + +### スラッシュコマンド・リクエストをハンドリングする + +エンドポイントの認証が完了したら、プロジェクトの`app.js`ファイルに移動し、`/test`コマンドをハンドリングするコードブロックを見つけてください: + +```javascript +// 「test」コマンド +if (name === 'test') { + // コマンドがトリガーされた起点のチャンネルにメッセージを送る + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // ヘルパー関数から送る絵文字をランダムに取得する + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +上記のコードは、起点となったチャンネルにおけるメッセージとのインタラクションに応答しています。可能な応答タイプ(モーダルで応答するなど)は[ドキュメント](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type)でご確認いただけます。 + +> 情報 +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE`は[`discord-interactions`からエクスポートされた](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33)定数です + +サーバーに移動し、アプリの`/test`スラッシュコマンドが機能することを確かめましょう。トリガーすると、アプリは「hello world」という言葉のあとにランダムな絵文字を含むメッセージを送信するはずです。 + +次のセクションでは、じゃんけんゲームを構築するため、スラッシュコマンド・オプションを利用する別のコマンド、ボタン、選択メニューを追加していきます。 + +--- + +## ステップ4:メッセージ・コンポーネントを追加する + +このじゃんけん式ゲームは、`/challenge`コマンドで開始されます。コマンドがトリガーされると、アプリはチャンネルにメッセージ・コンポーネントを送信し、これによってユーザーはゲームを完了するよう誘導されます。 + +### オプションのあるコマンドを追加する + +`/challenge`コマンドは、`commands.js`では`CHALLENGE_COMMAND`と呼ばれており、一連の`options`を有します。今回のアプリでは、オプションはユーザーがじゃんけんをする際に選択できる様々なものを表しており、`game.js`における`RPSChoices`のキーを利用して生成されます。 + +コマンドオプションとその構造については[ドキュメント](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure)をご覧ください。 + +> 情報 +> このガイドでは`game.js`にはあまり深入りしませんが、コマンドやコマンド内のオプションを変えるなど、いろいろといじってみましょう。 + + + +`/challenge`コマンドをハンドリングするには、ifブロック`if name === “test”`のあとに次のコードを追加してください: + +```javascript +// 「challenge」コマンド +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // ユーザーの選択したオブジェクト + const objectName = req.body.data.options[0].value; + + // メッセージIDをゲームIDとして用い、アクティブなゲームを作成する + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // 後ほど使用するため、ゲームIDをアペンドする + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> 情報 +> コードをペーストする場所が分からない場合は、Glitchプロジェクトの`examples/app.js`でコード全体を見るか、[Github](https://github.com/discord/discord-example-app/blob/main/app.js)でルート`app.js`を見てみましょう。 + +上記のコードは、次のような動きをしています: +1. リクエストボディをパースし、スラッシュコマンドをトリガーしたユーザーのID(`userId`)とそのユーザーが選択したオプション(選んだオブジェクト)(`objectName`)を取得します。 +2. インタラクションIDを使用して、`activeGames`オブジェクトに新しいゲームを追加します。アクティブなゲームは`userId`と`objectName`を記録します。 +3. チャンネルに、`accept_button_`の`custom_id`を伴う、ボタンのついたメッセージを送り返します。 + +> 警告 +> サンプルコードではオブジェクトをメモリ内ストレージとして使用していますが、プロダクションアプリではデータベースを使用してください。 + +[メッセージ・コンポーネント](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component)を伴うメッセージを送るとき、個々のペイロードは`components`アレイにアペンドされます。実行可能なコンポーネント(ボタンなど)は、コードサンプルで確認できる[アクション行](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows)の中にある必要があります。 + +メッセージ・コンポーネントと共に送られる一意の`custom_id`にお気づきでしょうか。この場合は、アクティブなゲームのIDがアペンドされた`accept_button_`になります。誰かがコンポーネントとインタラクトした際にDiscordがあなたに送るリクエストをハンドリングするには、`custom_id`が使用できます。これについては後ほどご説明します。 + +これで、`/challenge`コマンドを実行してオプションを選ぶと、アプリが**挑戦受諾(Accept)**ボタンを伴うメッセージを送信します。ボタンを押す動作をハンドリングできるよう、コードを追加しましょう。 + + + + + +ユーザーがメッセージ・コンポーネントとインタラクトすると、Discordは[インタラクション・タイプ](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type)が`3`(または`discord-interactions`を使用している場合は`MESSAGE_COMPONENT`の値)のリクエストを送信します。 + +ボタンのハンドラを設定するため、インタラクションの`type`を確認し、続いて`custom_id`のマッチングを行います。 + +`APPLICATION_COMMAND`のタイプハンドラの下に、下記のコードをペーストしてください: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// メッセージ・コンポーネントを送信する際、custom_idをペイロード内に設定する +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // 関連付けられたゲームIDを取得する + const gameId = componentId.replace('accept_button_', ''); + // リクエストボディのトークンを含むメッセージを削除する + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // ヘルパー関数から送る絵文字をランダムに取得する + content: 'What is your object of choice?', + // 一時メッセージであることを示す + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // ゲームIDをアペンドする + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // 以前のメッセージを削除する + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +上記のコードは以下のように動作します: +1. 元々送ったものとマッチする`custom_id`をチェックします(この場合は`accept_button_`で始まるものです)。カスタムIDにはアクティブなゲームIDもアペンドされていますので、これを`gameID`に保存します。 +2. `node-fetch`を使用してウェブフックを呼び出し、リクエストボディ内の一意のインタラクション`token`を渡すことで、[元のメッセージを削除](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response)します。これは他のユーザーがボタンをクリックしてしまわないよう、チャンネルをクリーンアップするための動作です。 +3. ゲームのオブジェクトの選択肢を示す選択メニューを含んだメッセージを送ることで、リクエストに応答します。ペイロードは前のものとよく似ていますが、`options`アレイと[一時メッセージであることを示す](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message)`flags: 64`がある点で異なります。 + +`options`アレイは`game.js`の`getShuffledOptions()`メソッドを利用して入力されます。これは`RPSChoices`の値を操作して[メッセージ・コンポーネント・オプション](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure)の形に合わせてゆくものです。 + + + + + +最後に追加するのは、選択メニューとのインタラクションをハンドリングし、ゲームの結果をチャンネルに送信するコードです。 + +選択メニューもメッセージ・コンポーネントに他ならないため、メニューとのインタラクションをハンドリングするコードも、ボタンのそれとほぼ同じになります。 + +上記のコードを編集して、選択メニューをハンドリングしましょう: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// メッセージ・コンポーネントを送信する際、custom_idをペイロード内に設定する +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // 関連付けられたゲームIDを取得する + const gameId = componentId.replace('accept_button_', ''); + // リクエストボディのトークンを含むメッセージを削除する + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // ヘルパー関数から送る絵文字をランダムに取得する + content: 'What is your object of choice?', + // 一時メッセージであることを示す + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // ゲームIDをアペンドする + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // 以前のメッセージを削除する + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // 関連付けられたゲームIDを取得する + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // ユーザー応答のためユーザーIDと選択されたオブジェクトを取得する + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // ヘルパー関数から結果を計算する + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // ゲームをストレージから削除する + delete activeGames[gameId]; + // リクエストボディのトークンを含むメッセージを更新する + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // 結果を送信する + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // 一時メッセージを更新する + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +以前のコードと同様、上記のコードは、インタラクション・リクエストからユーザーIDとそのユーザーの選択したオブジェクトを取得しています。 + +この情報、ならびに元のユーザーのIDと`activeGames`オブジェクトからの選択が、`getResult()`関数に渡されます。`getResult()`が勝者を決定し、チャンネルに送り返すための読み取り可能な文字列をビルドします。 + +また、別のウェブフックも呼び出して、[フォローアップの一時メッセージを削除できない代わりに更新します](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message)。 + +最後に、`CHANNEL_MESSAGE_WITH_SOURCE`インタラクション応答タイプを使用して、結果がチャンネルに送られます。 + + + +……以上です 🎊 アプリをテストしてみて、すべてが想定通りに動くかどうか確かめましょう。 + +--- + +## 今後のステップ + +初めてのDiscordアプリの完成、おめでとうございます!🤖 + +Discordアプリのこと、設定する方法、そしてインタラクティブなアプリを作る方法について、学んでいただけていれば幸いです。ここからは、アプリを開発をさらに進めてもよいですし、他にできることを調べてみてもよいでしょう: +- API機能についてさらに詳しく知るため、**[ドキュメント](#DOCS_INTRO)**を読んでみる +- より小規模な、機能固有のコード例を見るため、このプロジェクトの`examples/`フォルダーを見てみる +- **[コミュニティリソース](#DOCS_TOPICS_COMMUNITY_RESOURCES)**で、コミュニティメンバーが管理している言語ごとのツールを見てみる +- [Cloudflare WorkersでDiscordアプリをホストする](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS)チュートリアルを読む +- **[Discord開発者サーバー](https://discord.gg/discord-developers)**に加入して、APIについて質問したり、Discord APIチームの主催するイベントに参加したり、他の開発者と交流したりする diff --git a/docs/monetization/App_Subscriptions.md b/docs/monetization/App_Subscriptions.md new file mode 100644 index 0000000000..ae781a7869 --- /dev/null +++ b/docs/monetization/App_Subscriptions.md @@ -0,0 +1,86 @@ +# App Subscriptions + +App Subscriptions enable you to charge your users for premium app functionality with a recurring subscription. Before you can add an app subscription to your app, you must complete the [Monetization Eligibility Checklist](#DOCS_MONETIZATION_OVERVIEW/eligibility-checklist). + +Once you've confirmed eligibility for your app and team, you will be able to set up a [SKU](#DOCS_MONETIZATION_SKUS) (stock-keeping unit) to represent your app's premium offering. + +## Types of Subscriptions + +When creating subscriptions, you will need to choose between user or guild subscriptions: + +- **User Subscriptions**: Offers premium features to an individual user across any server where your app installed. +- **Guild Subscriptions**: Provides premium benefits to all members within a specific server. + +Currently, you can only have one published subscription SKU for your app, so you cannot offer both types of subscriptions. + +## Configuring App Subscriptions + +Once you have an idea what type of subscription you want to offer for your app, you can create and [customize your SKU](#DOCS_MONETIZATION_SKUS/customizing-your-skus) to reflect the premium features that you are adding to your app. This is a good place to outline the benefits your users will receive from having an app subscription. + +Once an app has a published SKU, there are 4 ways users will be able to subscribe: + +- Server admins can use the **Integrations** tab within a server's settings menu +- Bot user profiles include an Upgrade button +- App Directory profiles offer a Premium tab containing subscription details and an Upgrade option +- Attempting to run a premium command will display the Upgrade button in the response + +If you don't have any premium commands, your users will still be able to upgrade to your premium app via the Integrations settings menu, bot user profiles and App Directory profiles. + +## Implementing App Subscriptions + +When a user subscribes to your app, there are a few things you will need to implement in your code to check for subscription status and access. + +- Gating your App with Premium Interactions +- Working with Entitlements +- Handling Gateway Events for Entitlements + +### Gating Premium Interactions + +Interactions like [commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS) commonly respond to users with a message or modal response. If you'd like to make a command only available to users with a subscription, you can reply with a `PREMIUM_REQUIRED` interaction response `type: 10`. Users without a subscription will be prompted to upgrade when they attempt to use these commands. + +```javascript +return new JsonResponse({ + type: 10, // PREMIUM_REQUIRED interaction response type + data: {}, +}); +``` + +![Interaction Response](monetization-interaction-response.png) + +If someone is already subscribed, this command will show the upgrade prompt with a disabled upgrade button. In order to avoid this, your interaction handler should check to see if the user or guild has an active entitlement for your SKU. + +Each interaction payload includes an `entitlements` field containing an array of full entitlement objects that the guild or user currently has entitlement to. + +You can use this field to determine if the user or guild is subscribed to your app. + +### Keeping Track of Entitlements + +When a user purchases a subscription, an entitlement is created. [Entitlements](#DOCS_MONETIZATION_ENTITLEMENTS) represent the user's access to your premium offering. You can keep track of entitlements using Gateway Events and the HTTP API. + +#### Entitlement Gateway Events + +When users subscribe or renew a subscription with your app, Discord will emit [entitlement gateway events](#DOCS_MONETIZATION_ENTITLEMENTS/gateway-events). + +Upon a user's purchase of a SKU, you'll receive an [`ENTITLEMENT_CREATE`](#DOCS_MONETIZATION_ENTITLEMENTS/new-entitlement) event. A successful renewal triggers an [`ENTITLEMENT_UPDATE`](#DOCS_MONETIZATION_ENTITLEMENTS/updated-entitlement) event. + +> info +> An [`ENTITLEMENT_DELETE`](#DOCS_MONETIZATION_ENTITLEMENTS/deleted-entitlement) event only occurs when Discord refunds a subscription or removes an entitlement, not when an entitlement expires or is canceled. + +#### Entitlement HTTP Endpoints + +For apps requiring background processing or not solely reliant on interactions, keeping track of entitlements is essential. You can utilize the [List Entitlements](#DOCS_MONETIZATION_ENTITLEMENTS/list-entitlements) endpoint to list active and expired entitlements. Your app can filter entitlements by a specific user or guild by using the `?user_id=XYZ` or `?guild_Id=XYZ` query params. + +For example, you might keep track of our entitlements in a database and check a user's subscription status before performing a cron job or other task. + +## Testing Your Implementation + +You can test your implementation by [creating](#DOCS_MONETIZATION_ENTITLEMENTS/create-test-entitlement) and [deleting](#DOCS_MONETIZATION_ENTITLEMENTS/delete-test-entitlement) test entitlements. These entitlements will allow you to test your premium offering in both a subscribed and unsubscribed state as a user or guild. + +> info +> Test Entitlements do not have a `starts_at` or `ends_at` field as they are valid until they are deleted. + +## Receiving Payouts + +Once an app has made its first $100 it will become eligible for payout. A review will be conducted and if everything looks good, your team will begin to receive payouts. + +For more information, read the [Premium Apps Payouts](https://support-dev.discord.com/hc/articles/17299902720919) Help Center article. \ No newline at end of file diff --git a/docs/monetization/Entitlements.md b/docs/monetization/Entitlements.md new file mode 100644 index 0000000000..2b4a6a4326 --- /dev/null +++ b/docs/monetization/Entitlements.md @@ -0,0 +1,184 @@ +## Entitlement Resource + +Entitlements in Discord represent that a user or guild has access to a premium offering in your application. + +### Entitlement Object + +###### Entitlement Structure + +| Field | Type | Description | +|----------------|-------------------|---------------------------------------------------------------------------------------------| +| id | snowflake | ID of the entitlement | +| sku_id | snowflake | ID of the SKU | +| user_id? | snowflake | ID of the user that is granted access to the entitlement's sku | +| guild_id? | snowflake | ID of the guild that is granted access to the entitlement's sku | +| application_id | snowflake | ID of the parent application | +| type | integer | [Type of entitlement](#DOCS_MONETIZATION_ENTITLEMENTS/entitlement-object-entitlement-types) | +| consumed | boolean | Not applicable for App Subscriptions. Subscriptions are not consumed and will be `false` | +| starts_at? | ISO8601 timestamp | Start date at which the entitlement is valid. Not present when using test entitlements. | +| ends_at? | ISO8601 timestamp | Date at which the entitlement is no longer valid. Not present when using test entitlements. | + +###### Entitlement Example + +```json +{ + "id": "1019653849998299136", + "sku_id": "1019475255913222144", + "application_id": "1019370614521200640", + "user_id": "771129655544643584", + "promotion_id": null, + "type": 8, + "deleted": false, + "gift_code_flags": 0, + "consumed": false, + "starts_at": "2022-09-14T17:00:18.704163+00:00", + "ends_at": "2022-10-14T17:00:18.704163+00:00", + "guild_id": "1015034326372454400", + "subscription_id": "1019653835926409216" +} +``` + +###### Entitlement Types + +| Type | ID | Description | +|--------------------------|----|--------------------------------------------------| +| APPLICATION_SUBSCRIPTION | 8 | Entitlement was purchased as an app subscription | + +## List Entitlements % GET /applications/{application.id#DOCS_RESOURCES_APPLICATION/application-object}/entitlements + +Returns all entitlements for a given app, active and expired. + +###### Query Params + +| param | type | description | +|----------------|-----------------------------------|------------------------------------------------------| +| user_id? | snowflake | User ID to look up entitlements for | +| sku_ids? | comma-delimited set of snowflakes | Optional list of SKU IDs to check entitlements for | +| before? | snowflake | Retrieve entitlements before this time | +| after? | snowflake | Retrieve entitlements after this time | +| limit? | integer | Number of entitlements to return, 1-100, default 100 | +| guild_id? | snowflake | Guild ID to look up entitlements for | +| exclude_ended? | boolean | Whether entitlements should be omitted | + +```json +[ + { + "id": "1019653849998299136", + "sku_id": "1019475255913222144", + "application_id": "1019370614521200640", + "user_id": "771129655544643584", + "promotion_id": null, + "type": 8, + "deleted": false, + "gift_code_flags": 0, + "consumed": false, + "starts_at": "2022-09-14T17:00:18.704163+00:00", + "ends_at": "2022-10-14T17:00:18.704163+00:00", + "guild_id": "1015034326372454400", + "subscription_id": "1019653835926409216" + } +] +``` + +## Create Test Entitlement % POST /applications/{application.id#DOCS_RESOURCES_APPLICATION/application-object}/entitlements + +Creates a test entitlement to a given SKU for a given guild or user. Discord will act as though that user or guild has entitlement to your premium offering. + +This endpoint returns a partial entitlement object. It will **not** contain `subscription_id`, `starts_at`, or `ends_at`, as it's valid in perpetuity. + +After creating a test entitlement, you'll need to reload your Discord client. After doing so, you'll see that your server or user now has premium access. + +###### JSON Params + +| param | type | description | +|------------|---------|-----------------------------------------------------------| +| sku_id | string | ID of the SKU to grant the entitlement to | +| owner_id | string | ID of the guild or user to grant the entitlement to | +| owner_type | integer | `1` for a guild subscription, `2` for a user subscription | + +```json +{ + "sku_id": "999184799365857331", + "owner_id": "847184799365857999", + "owner_type": 1 +} +``` + +## Delete Test Entitlement % DELETE /applications/{application.id#DOCS_RESOURCES_APPLICATION/application-object}/entitlements/{entitlement.id#DOCS_MONETIZATION_ENTITLEMENTS/entitlement-object} + +Deletes a currently-active test entitlement. Discord will act as though that user or guild _no longer has_ entitlement to your premium offering. + +Returns `204 No Content` on success. + +--- + +## Gateway Events + +### New Entitlement + +`ENTITLEMENT_CREATE` + +Fires when a user subscribes to a SKU. Contains an entitlement object. + +```json +{ + "id": "1083167266843000832", + "sku_id": "1083142056391606272", + "application_id": "1083108937882013696", + "user_id": "1072239583707664384", + "promotion_id": null, + "type": 8, + "deleted": false, + "gift_code_flags": 0, + "consumed": false, + "starts_at": "2023-03-08T23:19:58.010876+00:00", + "ends_at": "2023-04-08T23:19:58.010876+00:00", + "subscription_id": "1083167255652597760" +} +``` + +### Updated Entitlement + +`ENTITLEMENT_UPDATE` + +Fires when a user's subscription renews for the next billing period. The `ends_at` field will have an updated value with the new expiration date. + +If a user's subscription is cancelled, you will _not_ receive an `ENTITLEMENT_DELETE` event. Instead, you will simply not receive an `UPDATE` event with a new `ends_at` date at the end of the billing period. + +### Deleted Entitlement + +`ENTITLEMENT_DELETE` + +Fires when a user's entitlement is deleted. Entitlement deletions are infrequent, and occur when: + +- Discord issues a refund for a subscription +- Discord removes an entitlement from a user via internal tooling + +Entitlements are _not_ deleted when they expire. + +--- + +## Using Entitlements in Interactions + +### PREMIUM_REQUIRED Interaction Response + +If your app has monetization enabled, it will have access to a new [`PREMIUM_REQUIRED` interaction response (`type: 10`)](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type). This can be sent in response to any kind of interaction. It does not allow a `content` field. + +This response will create an ephemeral message shown to the user that ran the interaction, instructing them that whatever they tried to do requires the premium benefits of your app. It also contains an "Upgrade" button to subscribe. The response message is static, but will be automatically updated with the name of your premium SKU. + +![Interaction Response](monetization-interaction-response.png) + +```js +return res.send({ + type: InteractionResponseType.PREMIUM_REQUIRED, // This has a value of 10 + data: {}, +}); +``` + +--- + +### Checking Entitlements in Interactions + +To check what the current guild or user has entitlements to, your app can inspect the `entitlements` field. `entitlements` is an array of [entitlement objects](#DOCS_MONETIZATION_ENTITLEMENTS/entitlement-object) for the current guild and user. + +You can reference `entitlements` during interactions to handle subscription status, rather than fetching entitlements from the API or your database. diff --git a/docs/monetization/Overview.md b/docs/monetization/Overview.md new file mode 100644 index 0000000000..66dbeda051 --- /dev/null +++ b/docs/monetization/Overview.md @@ -0,0 +1,64 @@ +# Monetizing Your Discord App + +Premium Apps is a set of monetization features for apps on Discord that allows developers to: + +- Sell monthly recurring [subscriptions](#DOCS_MONETIZATION_APP_SUBSCRIPTIONS) for your app's premium functionality within Discord +- Highlight your app's premium benefits on the App Directory +- Offer native product tie-ins and upsells on the App Directory, app profiles, and in chat + +![Premium App screenshot](premium-example.png) + +## Eligibility Checklist + +Before you can start creating SKUs and offering subscriptions for your app, your app and team must be eligible for monetization. + +Only team owners can enable monetization for an app. When a team owner enables monetization, they'll be taken through a series of steps and checks to ensure the following criteria are met: + +- App must be verified +- App belongs to a developer team +- Team owner must be at least 18 years old +- Team must have verified emails and 2FA set up +- App uses slash commands, or has been approved for the privileged `Message Content` intent +- App has a link to your Terms of Service + - This document is an agreement between you and users governing the use of your app. +- App has a link to your Privacy Policy + - This document should clearly and accurately describe to users of your app the user data you collect and how you use and share such data with us and third parties, consistent with our Developer Terms of Service and Developer Policy. +- App must not contain any harmful or bad language in the name, description, commands, or role connection metadata. +- Payouts must be setup with a valid payment method +- Agreement to the [Monetization Terms](https://support.discord.com/hc/articles/5330075836311) and [Discord App Subscriptions Policy](https://support-dev.discord.com/hc/articles/17442400631959). + +## Setting Up Monetization + +Adding monetization to your app is a three-step process: + +1. Set up your app and developer team to offer subscriptions +2. Create and customize a SKU for your app subscription +3. Adding support for SKUs and Entitlements to your app + +### Configuring Your App + +Before monetization can be enabled, you will need: + +- A [team](#DOCS_TOPICS_TEAMS) in the developer portal. If you don't have one, you can [create one on the Teams page](https://discord.com/developers/teams) +- A [verified app](https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Allowlisting#h_46b3869c-6d50-43fc-b07c-9ed7569a1160) that is _owned by that team_ +- A test app _owned by that team_ +### Setting Up Team Payouts + +In the meantime, you can begin setting up your payout information so you can get paid! Discord does all payout processing through Stripe, so part of setting up payouts will be going through Stripe's onboarding flow. + +Only the owner of the team can enable payout settings for the team. + +#### If You are Based in the United States + +- Click on [your team](https://discord.com/developers/teams) on the Teams page. +- Select "Payout Settings" + - If you do not see "Payout Settings", you are not the owner of the team. Only the owner of the team can enable payout settings for the team. +- Complete the onboarding flow through Stripe + +#### If You are Based Outside of the United States + +Premium Apps is not currently available outside of the United States. These features will be made available to more regions soon. + +### Implementing Your Premium Features + +Once your team and app are all set up for monetization, you are ready to [customize your subscription](#DOCS_MONETIZATION_SKUS/customizing-your-skus) and [implement your premium features](#DOCS_MONETIZATION_APP_SUBSCRIPTIONS) in your app! \ No newline at end of file diff --git a/docs/monetization/SKUs.md b/docs/monetization/SKUs.md new file mode 100644 index 0000000000..a923cc0499 --- /dev/null +++ b/docs/monetization/SKUs.md @@ -0,0 +1,147 @@ +## SKU Resource + +SKUs (stock-keeping units) in Discord represent premium offerings that can be made available to your application's users or guilds. + +### SKU Object + +###### SKU Structure + +| Field | Type | Description | +|----------------|-----------|-----------------------------------------------------------------------------------------------------------------------------| +| id | snowflake | ID of SKU | +| type | integer | [Type of SKU](#DOCS_MONETIZATION_SKUS/sku-object-sku-types) | +| application_id | snowflake | ID of the parent application | +| name | string | Customer-facing name of your premium offering | +| slug | string | System-generated URL slug based on the SKU's name | +| flags | integer | [SKU flags](#DOCS_MONETIZATION_SKUS/sku-object-sku-flags) combined as a [bitfield](https://en.wikipedia.org/wiki/Bit_field) | + +###### SKU Example + +```json +{ + "id": "1088510058284990888", + "type": 5, + "dependent_sku_id": null, + "application_id": "788708323867885999", + "manifest_labels": null, + "access_type": 1, + "name": "Test Premium", + "features": [], + "release_date": null, + "premium": false, + "slug": "test-premium", + "flags": 128, + "show_age_gate": false +} +``` + +###### SKU Types + +For subscriptions, SKUs will have a type of either `SUBSCRIPTION` represented by `type: 5` or `SUBSCRIPTION_GROUP` represented by `type:6`. For any current implementations, you will want to use the SKU defined by `type: 5`. A `SUBSCRIPTION_GROUP` is automatically created for each `SUBSCRIPTION` SKU and are not used at this time. + +| Type | ID | Description | +|--------------------|----|----------------------------------------------------------| +| SUBSCRIPTION | 5 | Represents a recurring subscription | +| SUBSCRIPTION_GROUP | 6 | System-generated group for each SUBSCRIPTION SKU created | + +###### SKU Flags + +For subscriptions, there are two types of access levels you can offer to users: + +- **Guild Subscriptions**: A subscription purchased by a user and applied to a single server. Everyone in that server gets your premium benefits. +- **User Subscriptions**: A subscription purchased by a user for themselves. They get access to your premium benefits in every server. + +The `flags` field can be used to differentiate user and server subscriptions with a bitwise `&&` operator. + +| Value | Type | +|--------|--------------------| +| 1 << 7 | GUILD_SUBSCRIPTION | +| 1 << 8 | USER_SUBSCRIPTION | + +## Customizing Your SKUs + +Within your app's settings, you're able to customize details about your premium offering: + +- A name for your premium SKU, max 80 characters. +- A description for your premium SKU, max 160 characters +- An icon for your premium SKU + +![Example SKU customization](sku-customization.png) + +### Adding Benefits to Your SKU + +You're able to customize a list of up to 6 benefits to explain your premium offering to users. Benefits are displayed on the App Directory and during the purchase and cancellation flows, and each can have: + +- A name, max 80 characters +- A description, max 160 characters +- An emoji, standard or custom + +![Example of SKU benefits](sku-benefits.png) + +#### Using a Unicode Emoji +To set an icon using a standard Unicode emoji, enter the emoji in the `Unicode Emoji or Custom Emoji Name` field. + +> info +> Using an emoji keyboard can make it easier to pick an icon to display alongside your SKU benefit. +> MacOS: `control + command + space bar` +> Windows: `Windows + .` + +![Set a unicode emoji](sku-unicode.png) + +#### Using a Custom Emoji +To use a custom emoji, set a value for both fields: + +- Name of your custom emoji +- ID of the custom emoji + +> info +> You can find the ID of the emoji in the Discord app by escaping the emoji in a message with a backslash character `\`. For example, `\:uwu:` will render with the name and ID of the emoji. + +![Set a custom emoji](sku-custom.png) + +## Publishing Your SKUs + +When you're ready to launch, you can go to your [app's settings](https://discord.com/developers/applications) and change your SKU to "Published", and your premium offering will be live and available for purchase by users. + +From then on, we'll send you daily dashboard emails containing information about purchases, cancellations, and other premium information. + +Congratulations on going live! 🥳 + +## List SKUs % GET /applications/{application.id#DOCS_RESOURCES_APPLICATION/application-object}/skus + +Returns all SKUs for a given application. Because of how our SKU and subscription systems work, you will see two SKUs for your premium offering. For integration and testing entitlements, you should use the SKU with `type: 5`. + +```json +[ + { + "id": "1088510053843210999", + "type": 6, + "dependent_sku_id": null, + "application_id": "788708323867885999", + "manifest_labels": null, + "access_type": 1, + "name": "Test Premium", + "features": [], + "release_date": null, + "premium": false, + "slug": "test-premium", + "flags": 128, + "show_age_gate": false + }, + { + "id": "1088510058284990888", + "type": 5, + "dependent_sku_id": null, + "application_id": "788708323867885999", + "manifest_labels": null, + "access_type": 1, + "name": "Test Premium", + "features": [], + "release_date": null, + "premium": false, + "slug": "test-premium", + "flags": 128, + "show_age_gate": false + } +] +``` diff --git a/docs/nl/Getting_Started.mdx b/docs/nl/Getting_Started.mdx new file mode 100644 index 0000000000..da9e784a90 --- /dev/null +++ b/docs/nl/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# Het bouwen van je eerste Discord-app + +Met Discord-apps kun je je servers aanpassen en uitbreiden via een aantal API's en interactieve functies. Deze gids helpt je stap voor stap bij het bouwen van je eerste Discord-app met behulp van JavaScript, waardoor je app uiteindelijk gebruikmaakt van slashopdrachten, berichten verstuurt en reageert op interacties tussen componenten. + +We gaan een app bouwen waarmee serverleden steen-papier-schaar kunnen spelen (met 7 keuzes in plaats van 3). Deze gids richt zich op beginners, maar gaat uit van basiskennis van [JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics). + + +Zo komt de voltooide app eruit te zien: + +![Demo van de voorbeeld-app](getting-started-demo.gif) + +Ter verduidelijking van de gebruikersflow: + +1. Gebruiker 1 begint aan een nieuw spel en kiest een object via de slashopdracht `/challenge` in de app +2. Er wordt een bericht naar een kanaal gestuurd met een knop waarmee anderen de uitdaging kunnen accepteren +3. Gebruiker 2 klikt op de knop **Accepteren** +4. Gebruiker 2 ontvangt een kortstondig bericht waarin een object naar keuze kan worden geselecteerd +5. Het resultaat van het spel wordt in het oorspronkelijke kanaal gepost, zodat iedereen het kan zien + + + +- **[GitHub-register](https://github.com/discord/discord-example-app)** waar de code uit deze gids zich bevindt, samen met wat extra codevoorbeelden voor speciale functies. +- **[discord-interacties](https://github.com/discord/discord-interactions-js)**, een bibliotheek met soort- en hulpfuncties voor Discord-apps. +- **[Express](https://expressjs.com)**, een populair JavaScript-webframewerk dat we gebruiken om een server te creëren waarvandaan Discord ons verzoeken kan sturen. +- **[Glitch](https://glitch.com/)**, een online omgeving die het bouwen en hosten van apps vereenvoudigt in de vroege prototype- en ontwikkelingsfase. Je kunt ook lokaal ontwikkelen met een tool als **[ngrok](https://ngrok.com/)**. + + +--- + +## Stap 1: Een app creëren + +Eerst moet je een app creëren in het ontwikkelaarsportaal, als je dat nog niet hebt gedaan: + + + +Voer een naam in voor je app en klik dan op **Creëren**. + +Na het creëren van je app, kom je terecht op de pagina **Algemeen overzicht** van de app-instellingen, waar je basisinformatie over je app kunt updaten, zoals de beschrijving en het pictogram. Je ziet daar ook een **applicatie-ID** en **eindpunt-URL voor interacties**, waar we later in de gids mee te maken krijgen. + +### Je bot configureren + +Nu gaan we de [botgebruiker](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts) voor je app configureren, waardoor hij kan verschijnen en zich kan gedragen als andere serverleden. + +Klik in de linker zijbalk op **Bot**. Op deze pagina kun je instellingen configureren zoals de [privileged intents](#DOCS_TOPICS_GATEWAY/privileged-intents) van je bot en of je wilt dat andere gebruikers hem kunnen installeren. + + +Intents bepalen welke evenementen Discord naar je app stuurt als je een [Gateway API-verbinding](#DOCS_TOPICS_GATEWAY) creëert. Als je bijvoorbeeld wilt dat je app iets doet als gebruikers reageren op een bericht, kun je de intent `GUILD_MESSAGE_REACTIONS` (`1 << 10`) doorgeven. + +Sommige intents zijn [privileged intents](#DOCS_TOPICS_GATEWAY/privileged-intents), wat betekent dat ze je app toegang geven tot data die als gevoelig beschouwd kunnen worden (zoals de inhoud van berichten). Privileged intents verschijnen op de **Bot**-pagina in je app-instellingen, waar je ze ook aan en uit kunt zetten. Voor gewone intents heb je geen extra machtigingen of configuraties nodig. + +Meer informatie over intents en een volledige lijst van beschikbare intents en de bijbehorende evenementen is te vinden in de [Gateway-documentatie](#DOCS_TOPICS_GATEWAY/gateway-intents). + + +![Bot-tab in app-instellingen](app-add-bot.png) + +Er is ook een **Token**-sectie op de **Bot**-pagina, waarmee je het token van je bot kunt kopiëren en resetten. + +Met bottokens worden API-verzoeken geautoriseerd. Ze bevatten de machtigingen van je botgebruiker, waardoor ze *zeer kwetsbaar* zijn. Deel *nooit* je token en gebruik hem nooit bij versiecontrole. + +Maar je kunt je token gerust kopiëren en hem dan veilig opbergen (bijvoorbeeld in een wachtwoordbeheerprogramma). + +> waarschuwing +> Je kunt je token niet zien tenzij je hem regenereert, dus berg hem ergens veilig op. + +### Scopes en botmachtigingen toevoegen + +Apps hebben toestemming nodig van gebruikers die ze installeren om acties uit te voeren in Discord (zoals het creëren van slahopdrachten of het ophalen van een lijst met serverleden). Laten we een paar scopes en machtigingen kiezen om aan te vragen voordat de app wordt geïnstalleerd. + + +Bij het creëren van een app bepaal je met scopes en botmachtigingen wat je app kan doen en waartoe de app toegang krijgt op Discord-servers. + +- [OAuth2-scopes](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) bepalen de datatoegang en acties waarvan je app gebruik mag maken, toegekend uit naam van een gebruiker die de app installeert of authentiseert. +- [Machtigingen](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) zijn de gespecialiseerde toestemmingen voor je botgebruiker, zoals andere gebruikers op Discord ook hebben. Ze kunnen toestemming krijgen van de installerende gebruiker, of later worden bijgewerkt in de serverinstellingen of met [machtigingsoverschrijvingen](#DOCS_TOPICS_PERMISSIONS/permission-overwrites). + + +Klik in de zijbalk links op **OAuth2** en selecteer vervolgens **URL-generator**. + +> info +> De URL-generator creëert een installatielink gebaseerd op de scopes en machtigingen die je selecteert voor je app. Je kunt de link gebruiken om de app op je eigen server te installeren of om hem te delen met anderen, zodat zij hem kunnen installeren. + +Voeg voorlopig twee scopes toe: +- `applications.commands`, waarmee je app [opdrachten](#DOCS_INTERACTIONS_APPLICATION_COMMANDS) kan creëren. +- `bot` voegt je botgebruiker toe. Nadat je `bot` hebt geselecteerd, kun je ook andere machtigingen selecteren voor je bot. Vink voorlopig alleen **Berichten verzenden** aan. + +Bekijk een lijst met alle [OAuth2-scopes](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) of lees meer over [machtigingen](#DOCS_TOPICS_PERMISSIONS) in de documentatie. + +### Je app installeren + +Als je eenmaal scopes hebt toegevoegd, verschijnt er een URL die je kunt kopiëren om je app te installeren. + +![Screenshot van URL-generator](url-generator.png) + +> info +> Als je apps ontwikkelt, kun je ze het beste bouwen en testen op een server die niet actief wordt gebruikt door anderen. Als je nog geen eigen server hebt, kun je [er gratis eentje creëren](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server-). + +Kopieer de bovenstaande URL en plak hem in je browser. Je wordt vervolgens door het installatieproces geleid, waarbij je ervoor moet zorgen dat je je app installeert op een server waarop hij ontwikkeld en getest kan worden. + +Na het installeren van je app kun je naar je server gaan om te zien of alles werkt ✨ + +Nu je app is geconfigureerd en geïnstalleerd, kun je hem gaan ontwikkelen. + +--- + +## Stap 2: Je app laten draaien + +Alle code uit de voorbeeld-app vind je in [het GitHub-register](https://github.com/discord/discord-example-app). + +Om het ontwikkelen wat makkelijker te maken, maakt de app gebruik van [discord-interactions](https://github.com/discord/discord-interactions-js), die soort- en hulpfuncties verschaffen. Als je liever andere talen of bibliotheken gebruikt, raadpleeg dan de documentatie van de [communityhulpbronnen.](#DOCS_TOPICS_COMMUNITY_RESOURCES) + +### Het project remixen + +Deze gids maakt gebruik van Glitch, waarmee je in je browser kunt klonen en ontwikkelen. Als je je app liever lokaal ontwikkelt, vind je [in de README](https://github.com/discord/discord-example-app#running-app-locally) instructies over het gebruik van ngrok. + +> info +> Glitch is geweldig voor ontwikkeling en testen, maar [het heeft ook zijn technische beperkingen](https://help.glitch.com/hc/en-us/articles/16287495313293-Technical-Restrictions). Daarom is het goed om voor productie-apps ook naar andere hostingproviders te kijken. + +**[Remix (of kloon) om te beginnen het Glitch-project 🎏](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)**. + +Als je het project remixt, kom je in een nieuw Glitch-project terecht. + + +![Projectoverzicht Glitch](glitch-project.png) + +- Je **projectnaam** is een unieke naam voor je project, die je vindt in de linker bovenhoek +- **`.env`** is het bestand waar alle verificatiegegevens voor je app in worden opgeslagen +- In **logs** kun je de output van je project vinden. Hier kun je zien of de app wel draait, en info bekijken over problemen waar je app tegenaan loopt +- De knop **Delen**, rechts boven in het scherm, is de plaats waar de live project-URL te vinden is. Verderop in deze gids gebruiken we die om interactiviteit in te stellen + + +#### Projectstructuur + +Alle bestanden voor het project staan aan de linkerkant van je Glitch-project. Hieronder zie je een overzicht van de hoofdmappen en -bestanden: + +``` +├── examples -> korte, functie-specifieke voorbeeld-apps +│ ├── app.js -> voltooide app.js-code +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> je verificatiegegevens en ID's +├── app.js -> belangrijkste ingang voor app +├── commands.js -> payloads van slashopdrachten + hulpfuncties +├── game.js -> specifieke SPS-logica +├── utils.js -> hulpprogrammafuncties en enums +├── package.json +├── README.md +└── .gitignore +``` + +### Verificatiegegevens toevoegen + +Er staat al wat code in je `app.js`-bestand, maar om verzoeken in te dienen, heb je de token en ID van je app nodig. Al je verificatiegegevens kun je opslaan in het `.env`-bestand. + +Eerst kopieer je het eerder genoemde token van je botgebruiker en plak je die in de **`DISCORD_TOKEN`**-variabele van je `.env`-bestand. + +Ga daarna naar de pagina **Algemeen overzicht** en kopieer de **app-ID** en **openbare code**. Plak de waarden in je `.env`-bestand als **`APP_ID`** en **`PUBLIC_KEY`**. + +Nu je verificatiegegevens zijn geconfigureerd, gaan we slashopdrachten installeren en er verder mee werken. + +### Slashopdrachten installeren + +> info +> Om slashopdrachten te installeren, maakt de app gebruik van [`node-fetch`](https://github.com/node-fetch/node-fetch). Je kunt de implementatie voor de installatie zien in `utils.js`, binnen de `DiscordRequest()`-functie. + +Het project bevat een `register`-script waarmee je de opdrachten kunt installeren in `ALL_COMMANDS`, wat je onderaan `commands.js` vindt. Dit installeert de opdrachten als algemene opdrachten door het [`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands)-eindpunt van de HTTP API op te roepen. + +Als je je opdrachten wilt aanpassen of extra opdrachten wilt toevoegen, kun je verwijzen naar de opdrachtstructuur in de [opdrachtdocumentatie](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure). + +Run het `register`-script door onderaan het Glitch-project op **Terminal** te klikken en de volgende opdracht te plakken: + +``` +npm run register +``` + +Druk op Enter om de opdracht te activeren. + +Als je teruggaat naar je server, moet je nu de slashopdrachten zien verschijnen. Maar als je ze probeert uit te voeren, gebeurt er niets, omdat je app geen verzoeken ontvangt of verwerkt van Discord. + + +Discord heeft twee API's die je kunt combineren om apps te bouwen: + +- **[HTTP API](#DOCS_REFERENCE/http-api)** is een REST-achtige API voor algemene handelingen zoals het versturen en updaten van data in Discord, of het ophalen van data over een hulpbron. +- **[Gateway API](#DOCS_REFERENCE/gateway-websocket-api)** is een op WebSocket gebaseerde API die nuttig is voor het behouden van een status en om te luisteren naar evenementen die plaatsvinden op een Discord-server. We gebruiken deze API niet in deze gids, maar als je meer wilt weten over het creëren van een Gateway-verbinding en de verschillende evenementen waarnaar je kunt luisteren, raadpleeg dan de [Gateway-documentatie](#DOCS_TOPICS_GATEWAY). + + +--- + +## Step 3: Werken met interactiviteit + +Om ervoor te zorgen dat je app slashopdrachtverzoeken (en andere interacties) kan ontvangen, heeft Discord een openbare URL nodig om ze te versturen. Je kunt deze URL configureren in de instellingen van je app als **eindpunt-URL voor interacties**. + +### Een eindpunt-URL voor interacties toevoegen + +In Glitch-projecten is standaard een openbare URL te zien. Kopieer de URL van je project door op de knop **Delen** te klikken rechtsboven in de hoek. Kopieer vervolgens de projectlink 'Live site' onderaan de modal. + +> info +> Als je lokaal ontwikkelt, kun je [in de README van GitHub](https://github.com/discord/discord-example-app#running-app-locally) instructies vinden om verzoeken naar je lokale omgeving te leiden. + +Nu de link gekopieerd is, ga je naar de instellingen van je app vanuit [het ontwikkelaarsportaal](https://discord.com/developers/applications). + +Op de pagina **Algemene informatie** van je app staat de optie **Interactieve eindpunt-URL**. Hier kun je de URL van de app in plakken en er `/interactions` aanhangen. Dat is waar de Express-app geconfigureerd kan worden om verzoeken op te vangen. + +![Eindpunt-URL voor interacties in app-instellingen](interactions-url.png) + +Klik op **Wijzigingen opslaan** en controleer of het is gelukt om je eindpunt te verifiëren. + +In de voorbeeld-app wordt verificatie op twee manieren aangepakt: +- Het gebruikt de `PUBLIC_KEY` en het [pakket discord-interactions](https://github.com/discord/discord-interactions-js#usage) met een wrapper-functie (geïmporteerd uit `utils.js`) waardoor het geschikt wordt voor de [`verify`-interface van Express](http://expressjs.com/en/5x/api.html#express.json). Dit wordt toegepast op elk binnenkomend verzoek op je app. +- Het reageert op binnenkomende `PING`-verzoeken. + +Raadpleeg voor meer informatie over het voorbereiden van je app op het ontvangen van interacties [de interactiedocumentatie](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction). + +### Werken met slashopdracht-verzoeken + +Nu het eindpunt geverifieerd is, ga je naar het `app.js`-bestand van je project en zoek je het codeblok voor de `/test`-opdracht: + +```javascript +// "test" opdracht +if (name === 'test') { + // Stuur een bericht naar het kanaal waarin de opdracht is geactiveerd + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Haalt een willekeurige emoji op om te versturen vanaf een hulpfunctie + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +Bovenstaande code reageert op de interactie door een bericht naar het kanaal te sturen waar de interactie is ontstaan. Je kunt alle beschikbare reactiesoorten bekijken, zoals reageren met een modal, [in de documentatie](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type). + +> info +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE` is een constante [die wordt geëxporteerd uit `discord-interactions`](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33) + +Ga naar je server en zorg ervoor dat de `/test`-slashopdracht van je app werkt. Als je hem activeert, moet je app een bericht versturen met de woorden 'hello world' erin, gevolgd door een willekeurige emoji. + +In de volgende sectie voegen we een extra opdracht toe met slashopdracht-opties, knoppen en keuzemenu's om het spelletje steen-papier-schaar op te bouwen. + +--- + +## Stap 4: Berichtonderdelen toevoegen + +Met de opdracht `/challenge` wordt ons steen-papier-schaar-achtige spelletje gestart. Als de opdracht wordt geactiveerd, stuurt de app een berichtonderdeel naar het kanaal, dat gebruikers tot het eind van het spel zal begeleiden. + +### Een opdracht met opties toevoegen + +De opdracht `/challenge`, `CHALLENGE_COMMAND` genaamd in `commands.js`, heeft verschillende `options`. In onze app zijn de opties verschillende objecten die een gebruiker kan kiezen bij het spelen van steen-papier-schaar, die worden gegenereerd met behulp van `RPSChoices`-codes in `game.js`. + +Je kunt meer lezen over opdrachtopties en hun structuur [in de documentatie](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure). + +> info +> In deze gids staat niet veel over het `game.js`-bestand, maar verken het bestand gerust en wees niet bang opdrachten of opties in de opdrachten te wijzigen. + + + +Om met de opdracht `/challenge` te werken, moet je de volgende code toevoegen na het 'if block'`if name === “test”`: + +```javascript +// "challenge" opdracht +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // Objectkeuze van gebruiker + const objectName = req.body.data.options[0].value; + + // Creëer een actief spel met bericht-ID als game-ID + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // Voeg de game-ID bij om later te gebruiken + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> info +> Als je niet zeker weet waar je de code moet plakken, kun je de volledige code bekijken in `examples/app.js` in het Glitch-project of de root van `app.js` [op GitHub](https://github.com/discord/discord-example-app/blob/main/app.js). + +De bovenstaande code doet een aantal dingen: +1. Hij analyseert de inhoud van het verzoek om de ID van de gebruiker op te halen die de slashopdracht heeft geactiveerd (`userId`) en de optie (objectkeuze) die de gebruiker heeft geselecteerd (`objectName`). +2. Hij voegt een nieuw spel toe aan het object `activeGames` met behulp van de interactie-ID. Het actieve spel registreert de `userId` en `objectName`. +3. Hij stuurt een bericht met daarin een knop met een `custom_id` van `accept_button_` naar het kanaal terug. + +> waarschuwing +> De voorbeeldcode gebruikt een object als opslag in het geheugen, maar voor productie-apps moet je een database gebruiken. + +Bij het sturen van een bericht met [berichtonderdelen](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component) worden de individuele payloads aan een `components`-lijst toegevoegd. Onderdelen waar acties mee worden uitgevoerd (zoals knoppen) moeten deel uitmaken van een [actierij](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows), die je in het codevoorbeeld ziet staan. + +Let op de unieke `custom_id` die meegestuurd wordt met berichtonderdelen. In dit geval is dat `accept_button_` waaraan de ID van het actieve spel is bijgevoegd. Een `custom_id` kan worden gebruikt om verzoeken af te handelen die Discord je stuurt als iemand interactie aangaat met het onderdeel, waarvan je straks een voorbeeld ziet. + +Als je nu de opdracht `/challenge` activeert en een optie kiest, zal je app een bericht sturen met de knop **Accepteren** erin. Laten we code toevoegen om de druk op de knop te verwerken. + + + + + +Als gebruikers interactie aangaan met een berichtonderdeel, verstuurt Discord een verzoek met één [interactietype](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) uit `3` opties (of de waarde van het `MESSAGE_COMPONENT` als `discord-interactions` wordt gebruikt). + +Om een verwerker in te stellen voor de knop, controleren we het `type` interactie en matchen we de `custom_id`. + +Plak de volgende code onder de typeverwerker voor `APPLICATION_COMMAND`: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id wordt ingesteld in payload bij versturen berichtonderdeel +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // Haal de bijbehorende game-ID op + const gameId = componentId.replace('accept_button_', ''); + // Verwijder bericht met token in verzoekinhoud + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Haalt een willekeurige emoji op om te versturen vanaf een hulpfunctie + content: 'What is your object of choice?', + // Geeft aan dat het een kortstondig bericht wordt + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Voeg game-ID bij + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Verwijder eerder bericht + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +De bovenstaande code: +1. Zoekt naar een `custom_id` die overeenkomt met wat we oorspronkelijk hebben verstuurd (in dit geval begint dat met `accept_button_`). Bij de aangepaste ID is de game-ID gevoegd, zodat we die kunnen opslaan in `gameID`. +2. [Verwijdert het oorspronkelijke bericht](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response) door een webhook aan te roepen met behulp van `node-fetch` en door de unieke interactie-`token` door te geven in de inhoud van het verzoek. +3. Reageert op het verzoek door een bericht te sturen met een keuzemenu dat de objectkeuzes voor de game bevat. De payload is vergelijkbaar met de vorige, met uitzondering van de `options`-lijst en `flags: 64`, [die aangeeft dat het bericht kortstondig is](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message). + +De `options`-lijst wordt gevuld met behulp van de `getShuffledOptions()`-methode in `game.js`, die de `RPSChoices`-waarden manipuleert om te passen bij de vorm van de [berichtcomponentopties](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure). + + + + + +Het laatste wat je moet toevoegen is een code om keuzemenu-interacties te verwerken en het resultaat van het spel naar een kanaal te sturen. + +Aangezien keuzemenu's gewoon een berichtonderdeel zijn, is de code om de bijbehorende interacties te verwerken vergelijkbaar met knoppen. + +Pas de bovenstaande code aan voor het keuzemenu: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id wordt ingesteld in payload bij versturen berichtonderdeel +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // Haal de bijbehorende game-ID op + const gameId = componentId.replace('accept_button_', ''); + // Verwijder bericht met token in verzoekinhoud + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Haalt een willekeurige emoji op om te versturen vanaf een hulpfunctie + content: 'What is your object of choice?', + // Geeft aan dat het een kortstondig bericht wordt + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Voeg game-ID bij + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Verwijder eerder bericht + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // Haal de bijbehorende game-ID op + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // Haal de gebruikers-ID en objectkeuze voor de reagerende gebruiker op + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // Bereken resultaat met hulpfunctie + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // Verwijder game uit opslag + delete activeGames[gameId]; + // Update bericht met token in verzoekinhoud + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // Verstuur resultaten + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // Update kortstondig bericht + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +Net zoals de eerdere code, haalt de bovenstaande code de gebruikers-ID en de objectkeuze op uit het interactieverzoek. + +Die informatie wordt samen met de ID van de oorspronkelijke gebruiker en de keuze van het `activeGames`-object doorgegeven aan de functie `getResult()`. `getResult()` bepaalt de winnaar en bouwt een leesbare string om naar het kanaal terug te sturen. + +We roepen ook nog een andere webhook aan, dit keer om [het kortstondige opvolgbericht te updaten](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message), aangezien dat niet kan worden verwijderd. + +Als laatste worden de resultaten verstuurd naar het kanaal met behulp van het interactiereactietype `CHANNEL_MESSAGE_WITH_SOURCE`. + + + +En dat was het! 🎊 Nu kun je je app testen en ervoor zorgen dat alles werkt. + +--- + +## Volgende stappen + +Gefeliciteerd met het bouwen van je eerste Discord-app! 🎊 + +Hopelijk heb je iets opgestoken over Discord-apps, hoe je ze kunt configureren en hoe je ze interactief kunt maken. Je kunt nu je app verder uitbouwen of ontdekken wat er nog meer mogelijk is: +- Lees **[de documentatie](#DOCS_INTRO)** voor meer informatie over API-functies +- Kijk de `examples/`-map van dit project door voor kleinere codevoorbeelden, speciaal voor bepaalde functies +- Check de **[communityhulpbronnen](#DOCS_TOPICS_COMMUNITY_RESOURCES)** voor tools in verschillende coderingstalen die door communityleden worden beheerd +- Lees onze tutorial over het [hosten van Discord-apps op Cloudflare Workers](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS) +- Word lid van de **[Discord-ontwikkelaarsserver](https://discord.gg/discord-developers)** om vragen te stellen over de API, deel te nemen aan door het Discord API-team gehoste evenementen en met andere ontwikkelaars te praten diff --git a/docs/pl/Getting_Started.mdx b/docs/pl/Getting_Started.mdx new file mode 100644 index 0000000000..c49e2fdb9e --- /dev/null +++ b/docs/pl/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# Tworzenie pierwszej aplikacji Discorda + +Aplikacje Discorda pozwalają spersonalizować i wzbogacić serwery przy pomocy API i interaktywnych funkcji. W tym przewodniku dowiesz się, jak stworzyć pierwszą aplikację Discorda w języku JavaScript, która wykorzystuje polecenia z ukośnikiem, wysyła wiadomości i reaguje na interakcje z elementami. + +Zaczniemy od stworzenia aplikacji Discorda, która pozwala członkom serwera grać w papier, kamień, nożyce (z 7 wyborami zamiast 3 wyborów, jak w tradycyjnej wersji gry). Ten przewodnik jest przeznaczony dla początkujących, ale zakłada, że znasz podstawy języka [JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics). + + +Oto, jak będzie wyglądała gotowa aplikacja: + +![Demonstracja przykładowej aplikacji](getting-started-demo.gif) + +Poniżej przedstawiono szczegółowy zarys przepływu użytkowników: + +1. Użytkownik 1 rozpoczyna nową grę i wybiera obiekt przy pomocy polecenia z ukośnikiem `/challenge` +2. Na kanał zostaje wysłana wiadomość z przyciskiem zachęcającym innych do przyjęcia wyzwania +3. Użytkownik 2 naciska przycisk **Accept** (Przyjmij) +4. Użytkownik 2 otrzymuje znikającą wiadomość, w której wybiera obiekt +5. Wynik gry jest publikowany dla wszystkich na pierwotnym kanale + + + +- **[Repozytorium GitHuba](https://github.com/discord/discord-example-app)**, gdzie znajdziesz kod z tego przewodnika wraz z dodatkowymi przykładami kodu przedstawiającymi określone funkcje. +- **[discord-interactions](https://github.com/discord/discord-interactions-js)**, biblioteka zawierająca typy i pomocnicze funkcje do aplikacji Discorda. +- **[Express](https://expressjs.com)**, popularny framework sieciowy JavaScript, którego użyjemy do utworzenia serwera, na który Discord może wysyłać żądania. +- **[Glitch](https://glitch.com/)**, internetowe środowisko, które upraszcza projektowanie i hostowanie aplikacji na wczesnym etapie prototypu i rozwoju. Możesz też projektować aplikację lokalnie przy pomocy narzędzia takiego jak **[ngrok](https://ngrok.com/)**. + + +--- + +## Krok 1: Tworzenie aplikacji + +Najpierw musisz stworzyć aplikację w portalu deweloperów, jeśli jeszcze jej nie masz: + + + +Wprowadź nazwę aplikacji i naciśnij **Stwórz**. + +Po utworzeniu aplikacji zostanie wyświetlona strona **Przegląd** ustawień aplikacji, gdzie możesz zaktualizować podstawowe dane swojej aplikacji takie jak jej opis i ikona. Znajdziesz tutaj również **ID aplikacji** i **końcowy adres URL interakcji**, które wykorzystamy w późniejszej części przewodnika. + +### Konfigurowanie bota + +W następnej kolejności skonfigurujemy [użytkownika bota](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts) Twojej aplikacji, dzięki któremu będzie ona wyglądać i zachowywać się podobnie do innych członków serwera. + +Na lewym pasku bocznym kliknij **Bot**. Na tej stronie możesz skonfigurować ustawienia takie jak [uprawnienia intent typu „privileged”](#DOCS_TOPICS_GATEWAY/privileged-intents) lub określić, czy bot może być instalowany przez innych użytkowników. + + +Uprawnienia intent określają, które zdarzenia Discord będzie wysyłać do Twojej aplikacji, gdy tworzysz [połączenie API bramki](#DOCS_TOPICS_GATEWAY). Przykładowo jeśli chcesz, aby aplikacja wykonała jakąś czynność, gdy użytkownicy dodadzą reakcję do wiadomości, możesz przekazać uprawnienie intent `GUILD_MESSAGE_REACTIONS` (`1 << 10`). + +Niektóre uprawnienia intent są „[privileged](#DOCS_TOPICS_GATEWAY/privileged-intents)”, co znaczy, że zezwalają aplikacji na dostęp do danych, które można uznać za wrażliwe (takich jak zawartość wiadomości). Uprawnienia intent typu „privileged” są wyświetlane i mogą zostać włączone/wyłączone na stronie **Bot** ustawień aplikacji. Standardowe uprawnienia intent („non-privileged”) nie wymagają dodatkowych uprawnień ani konfiguracji. + +Więcej informacji na temat uprawnień intent i pełną ich listę, wraz z powiązanymi zdarzeniami, znajdziesz w [dokumentacji bramki](#DOCS_TOPICS_GATEWAY/gateway-intents). + + +![Karta Bot w ustawieniach aplikacji](app-add-bot.png) + +Na stronie **Bot** znajduje się sekcja **Token**, gdzie możesz skopiować i zresetować token bota. + +Tokeny bota służą do uwierzytelniania żądań API i zawierają uprawnienia użytkownika bota, co czyni je *bardzo wrażliwymi*. *Nigdy* nie udostępniaj swojego tokena ani nie umieszczaj go w systemie kontroli wersji. + +Skopiuj token i zapisz go w bezpiecznym miejscu (np. menedżerze haseł). + +> ostrzeżenie +> Nie będzie można wyświetlić tokena ponownie, chyba że wygenerujesz go od nowa, więc przechowaj token w bezpiecznym miejscu. + +### Dodawanie zakresów i uprawnień bota + +Aplikacje potrzebują zgody instalujących je użytkowników, aby wykonywać czynności na Discordzie (takie jak tworzenie polecenia z ukośnikiem lub pobieranie listy członków serwera). Wybierzmy kilka zakresów i uprawnień, o których przyznanie będziemy prosić przed instalacją aplikacji. + + +Podczas tworzenia aplikacji zakresy i uprawnienia określają, co Twoja aplikacja może robić i do czego ma dostęp na serwerach Discorda. + +- [Zakresy OAuth2](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) określają, do których danych aplikacja może uzyskiwać dostęp i jakie czynności może wykonywać w imieniu instalującego lub uwierzytelniającego użytkownika. +- [Uprawnienia](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) są szczegółowymi uprawnieniami dla użytkownika bota – takimi samymi jak te, które posiadają inni użytkownicy na Discordzie. Uprawnienia te mogą zostać przyznane przez instalującego użytkownika lub zaktualizowane później w ustawieniach serwera bądź przy pomocy [nadpisań uprawnień](#DOCS_TOPICS_PERMISSIONS/permission-overwrites). + + +Kliknij **OAuth2** na lewym pasku bocznym, a następnie wybierz **Generator adresu URL**. + +> informacje +> Generator adresu URL tworzy łącze instalacyjne na podstawie zakresów i uprawnień wybranych dla aplikacji. Możesz użyć łącza do instalacji aplikacji na swoim serwerze lub udostępnić je innym, aby mogli zainstalować aplikację. + +Na razie dodaj dwa zakresy: +- `applications.commands`, który umożliwia aplikacji tworzenie [poleceń](#DOCS_INTERACTIONS_APPLICATION_COMMANDS). +- `bot` dodaje Twojego użytkownika bota. Po wybraniu `bot` możesz również wybrać różne uprawnienia bota. Na razie zaznacz tylko **Wysyłanie wiadomości**. + +Zobacz listę wszystkich [zakresów OAuth2](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) lub przeczytaj więcej na temat [uprawnień](#DOCS_TOPICS_PERMISSIONS) w dokumentacji. + +### Instalacja aplikacji + +Po dodaniu zakresów powinien zostać wyświetlony adres URL, który możesz skopiować w celu instalacji aplikacji. + +![Zrzut ekranu generatora adresu URL](url-generator.png) + +> informacje +> Podczas pracy nad aplikacjami należy budować i testować je na serwerze, który nie jest aktywnie używany przez innych. Jeśli nie masz jeszcze własnego serwera, możesz [utworzyć go za darmo](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server-). + +Skopiuj powyższy adres URL i wklej go w swojej przeglądarce. Zostanie wyświetlony interfejs instalacji, w którym należy upewnić się, że instalujesz aplikację na serwerze, na którym możesz rozwijać ją i testować. + +Po zainstalowaniu aplikacji przejdź do serwera, aby zobaczyć, czy została do niego dodana ✨ + +Po skonfigurowaniu i zainstalowaniu aplikacji możemy zacząć pracę nad nią. + +--- + +## Krok 2: Uruchomienie aplikacji + +Cały kod przykładowej aplikacji można znaleźć w [repozytorium GitHuba](https://github.com/discord/discord-example-app). + +Aby uprościć nieco pracę, aplikacja wykorzystuje bibliotekę [discord-interactions](https://github.com/discord/discord-interactions-js), która zawiera typy i funkcje pomocnicze. Jeśli wolisz użyć innych języków lub bibliotek, zobacz dokumentację [Zasoby społeczności](#DOCS_TOPICS_COMMUNITY_RESOURCES). + +### Edycja projektu + +W tym przewodniku używamy narzędzia Glitch, które pozwala sklonować aplikację i pracować nad nią w przeglądarce. Jeśli wolisz pracować nad aplikacją lokalnie, zobacz instrukcje dotyczące używania narzędzia ngrok [w README](https://github.com/discord/discord-example-app#running-app-locally). + +> informacje +> Choć rozwiązanie Glitch znakomicie nadaje się do pracy nad aplikacją i jej testowania, [ma ograniczenia techniczne,](https://help.glitch.com/kb/article/17-technical-restrictions/) więc należy rozważyć użycie innych dostawców usług hostingowych do publicznej wersji aplikacji. + +Aby zacząć, **[edytuj (lub sklonuj) projekt Glitch 🎏](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)**. + +Po edytowaniu projektu zostanie otwarty nowy projekt Glitch. + + +![Przegląd projektu Glitch](glitch-project.png) + +- **Nazwa projektu** to unikalna nazwa produktu widoczna w lewym górnym rogu +- **`.env`** to plik, w którym są przechowywane wszystkie Twoje dane uwierzytelniające do aplikacji +- **Dzienniki** zawierają dane wyjściowe projektu – pomagają one w ustaleniu, czy aplikacja działa; znajdziesz tu również informacje o wszelkich błędach występujących w aplikacji +- Przycisk **Udostępnij** w prawym górnym rogu pozwala uzyskać aktywny adres URL projektu, który będzie potrzebny do skonfigurowania interaktywności w dalszej części przewodnika + + +#### Struktura projektu + +Wszystkie pliki projektu są widoczne po lewej stronie projektu Glitch. Poniżej przedstawiono przegląd głównych folderów i plików: + +``` +├── examples -> krótkie, skupione na określonych funkcjach aplikacje przykładowe, +│ ├── app.js -> gotowy kod app.js, +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> Twoje dane uwierzytelniające i ID, +├── app.js -> główny punkt wejścia aplikacji, +├── commands.js -> payloady poleceń z ukośnikiem + elementy pomocnicze, +├── game.js -> logika gry w papier, kamień, nożyce, +├── utils.js -> funkcje narzędzi i wyliczenia. +├── package.json +├── README.md +└── .gitignore +``` + +### Dodawanie danych uwierzytelniających + +Plik `app.js` zawiera już kod, ale potrzebujesz tokena i ID aplikacji, aby przesyłać żądania. Wszystkie dane uwierzytelniające mogą być przechowywane bezpośrednio w pliku `.env`. + +Najpierw skopiuj token użytkownika bota, o którym była mowa wcześniej, i wklej go w parametrze **`DISCORD_TOKEN`** w pliku `.env`. + +Następnie przejdź do strony **Przegląd** aplikacji i skopiuj **ID aplikacji** oraz **publiczny klucz**. Wklej te wartości w pliku `.env` jako parametry **`APP_ID`** i **`PUBLIC_KEY`**. + +Po skonfigurowaniu danych uwierzytelniających czas zainstalować i wdrożyć polecenia z ukośnikiem. + +### Instalacja poleceń z ukośnikiem + +> informacje +> Aplikacja wykorzystuje moduł [`node-fetch`](https://github.com/node-fetch/node-fetch) do instalacji poleceń z ukośnikiem. Kod odpowiedzialny za instalację znajduje się w pliku `utils.js`, w funkcji `DiscordRequest()`. + +Projekt zawiera skrypt `register`, którego możesz użyć do instalacji poleceń w elemencie `ALL_COMMANDS`, który jest zdefiniowany na końcu pliku `commands.js`. Instaluje on polecenia jako globalne polecenia, wywołując punkt końcowy [`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands) API HTTP. + +Jeśli chcesz spersonalizować polecenia lub dodać ich więcej, możesz odnieść się do struktury poleceń przedstawionej w [ich dokumentacji](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure). + +Uruchom skrypt `register`, klikając **Terminal** na dole projektu Glitch i wklejając następujące polecenie: + +``` +npm run register +``` + +Naciśnij Enter, aby uruchomić polecenie. + +Jeśli wrócisz do swojego serwera, zobaczysz polecenia z ukośnikiem. Ale jeśli spróbujesz je uruchomić, nic się nie stanie, ponieważ Twoja aplikacja nie otrzymuje ani nie obsługuje żądań od Discorda. + + +Discord ma dwa API, które można łączyć w tworzonych aplikacjach: + +- **[API HTTP](#DOCS_REFERENCE/http-api)** jest API w stylu REST przeznaczonym do ogólnych operacji takich jak wysyłanie i aktualizowanie danych na Discordzie lub pobieranie informacji o zasobie. +- **[API bramki](#DOCS_REFERENCE/gateway-websocket-api)** to oparte na protokole WebSocket API przydatne do utrzymywania stanu lub nasłuchiwania zdarzeń na serwerze Discorda. Nie będziemy używać go w tym przewodniku, ale więcej informacji na temat tworzenia połączenia z bramką i różnych zdarzeń, które możesz nasłuchiwać, znajdziesz w [dokumentacji bramki](#DOCS_TOPICS_GATEWAY). + + +--- + +## Krok 3: Obsługa interaktywności + +Aby umożliwić aplikacji otrzymywanie żądań w postaci poleceń z ukośnikiem (i innych interakcji), Discord potrzebuje adresu URL, na który będzie je wysyłać. Można go skonfigurować w ustawieniach aplikacji, w polu **Końcowy adres URL interakcji**. + +### Dodawanie końcowego adresu URL interakcji + +Projekty Glitch mają publiczny adres URL, który jest domyślnie ujawniony. Skopuj go, klikając przycisk **Udostępnij** w prawym górnym rogu, a następnie skopiuj łącze projektu „Aktywna witryna” blisko dolnej części okna. + +> informacje +> Jeśli pracujesz nad aplikacją lokalnie, zobacz instrukcje dotyczące przekazywania żądań do lokalnego środowiska [w README na GitHubie](https://github.com/discord/discord-example-app#running-app-locally). + +Po skopiowaniu łącza przejdź do ustawień aplikacji z poziomu [portalu deweloperów](https://discord.com/developers/applications). + +Na stronie **Informacje ogólne** aplikacji znajduje się opcja **Końcowy adres URL interakcji**, gdzie możesz wkleić adres URL swojej aplikacji i dodać do niego ciąg `/interactions`, który wskazuje lokalizację, gdzie aplikacja Express będzie nasłuchiwać żądań. + +![Końcowy adres URL interakcji w ustawieniach aplikacji](interactions-url.png) + +Kliknij **Zapisz zmiany** i upewnij się, że końcowy adres został pomyślnie zweryfikowany. + +Przykładowa aplikacja obsługuje weryfikację na dwa sposoby: +- Wykorzystuje `PUBLIC_KEY` i [pakiet discord-interactions](https://github.com/discord/discord-interactions-js#usage) z funkcją wrapper (zaimportowaną z pliku `utils.js`), która zapewnia zgodność z interfejsem [Express`verify`](http://expressjs.com/en/5x/api.html#express.json). Jest ona uruchamiana za każdym razem, gdy Twoja aplikacja otrzyma żądanie. +- Funkcja reaguje na przychodzące żądania `PING`. + +Więcej informacji na temat przygotowywania aplikacji na przyjmowanie interakcji znajdziesz w [dokumentacji interakcji](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction). + +### Obsługa poleceń z ukośnikiem + +Po zweryfikowaniu końcowego adresu URL przejdź do pliku `app.js` w projekcie i znajdź blok kodu odpowiadający za obsługę polecenia `/test`: + +```javascript +// polecenie „test” +if (name === 'test') { + // Wysyła wiadomość na kanał, na którym aktywowano polecenie + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Pobiera losowe emoji do wysłania z funkcji pomocniczej + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +Powyższy kod reaguje na interakcję z wiadomością na kanale, z którego pochodzi. Możesz zobaczyć wszystkie dostępne typy reakcji, takie jak reagowanie oknem, [w dokumentacji](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type). + +> informacje +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE` jest stałą [eksportowaną z pliku pakietu `discord-interactions`](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33) + +Przejdź do swojego serwera i upewnij się, że polecenie z ukośnikiem `/test` działa. Gdy je aktywujesz, aplikacja powinna wysłać wiadomość z tekstem „hello world” i losowym emoji. + +W następnym punkcie dodamy polecenie wykorzystujące opcje polecenia z ukośnikiem, przyciski i menu wyboru, aby stworzyć grę w papier, kamień, nożyce. + +--- + +## Krok 4: Dodanie elementów wiadomości + +Polecenie `/challenge` będzie uruchamiać grę w stylu gry w papier, kamień, nożyce. Po aktywowaniu polecenia aplikacja wyśle na kanał wiadomości instruujące użytkowników, jak ukończyć grę. + +### Dodawanie polecenia z opcjami + +Polecenie `/challenge`, zwane `CHALLENGE_COMMAND` w pliku `commands.js`, ma szereg opcji (`options`). W naszej aplikacji opcje są obiektami oznaczającymi różne elementy, które użytkownik może wybrać podczas gry w papier, kamień, nożyce, generowane przy pomocy kluczy `RPSChoices` w pliku `game.js`. + +Więcej o opcjach poleceń i ich strukturze przeczytasz [w dokumentacji](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure). + +> informacje +> Choć w tym przewodniku nie zagłębimy się w plik `game.js`, możesz poeksperymentować z nim, zmieniając polecenia lub ich opcje. + + + +Aby dodać obsługę polecenia `/challenge`, dodaj następujący kod po bloku „if” `if name === “test”`: + +```javascript +// Polecenie „challenge” +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // Wybór obiektu użytkownika + const objectName = req.body.data.options[0].value; + + // Tworzy aktywną grę, używając ID wiadomości jako ID gry + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // Dołącza ID gry do późniejszego użytku + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> informacje +> Jeśli nie wiesz, gdzie wkleić kod, możesz zobaczyć pełen kod w pliku `examples/app.js` w projekcie Glitch lub w nadrzędnym pliku `app.js` [na GitFHubie](https://github.com/discord/discord-example-app/blob/main/app.js). + +Powyższy kod wykonuje szereg czynności: +1. Przetwarza treść żądania w celu uzyskania ID użytkownika, który aktywował polecenie z ukośnikiem (`userId`), i wybraną przez niego opcję (wybrany obiekt) (`objectName`). +2. Dodaje nową grę do obiektu `activeGames` przy pomocy ID interakcji. Aktywna gra zapisuje elementy `userId` i `objectName`. +3. Wysyła na kanał wiadomość z przyciskiem z wartością `accept_button_` w polu `custom_id`. + +> ostrzeżenie +> Przykładowy kod wykorzystuje obiekt przechowywany w pamięci, ale na potrzeby publicznej wersji aplikacji zaleca się użycie bazy danych. + +Przy wysyłaniu [elementów wiadomości](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component) indywidualne payloady są dodawane do tablicy `components`. Interaktywne elementy (takie jak przyciski) muszą znajdować się w [rzędzie czynności](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows), który jest widoczny w przykładowym kodzie. + +Zwróć uwagę na unikalny `custom_id` wysyłany z elementami wiadomości, w tym przypadku `accept_button_` z dodanym ID gry. `custom_id` pozwala obsłużyć żądania przesyłane przez Discorda, gdy ktoś wejdzie w interakcję z elementem – zobaczysz za chwilę, jak to wygląda. + +Teraz gdy użyjesz polecenia `/challenge` i wybierzesz opcję, Twoja aplikacja wyśle wiadomość z przyciskiem **Accept** (Akceptuj). Dodajmy kod odpowiadający za obsługę naciśnięcia przycisku. + + + + + +Gdy użytkownicy wejdą w interakcję z elementem wiadomości, Discord wyśle żądanie z [typem interakcji](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) `3` (lub wartością `MESSAGE_COMPONENT` przy używaniu `discord-interactions`). + +W celu skonfigurowania procedury obsługi przycisku sprawdzimy typ (`type`) interakcji, a następnie `custom_id`. + +Wklej następujący kod pod procedurą obsługi typu dla `APPLICATION_COMMAND`: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id konfigurowany w payloadzie przy wysyłaniu elementu wiadomości +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // Uzyskuje powiązany ID gry + const gameId = componentId.replace('accept_button_', ''); + // Usuwa wiadomość z tokenem w treści żądania + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Pobiera losowe emoji do wysłania z funkcji pomocniczej + content: 'What is your object of choice?', + // Określa, że wiadomość będzie znikająca + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Dodaje ID gry + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Usuwa poprzednią wiadomość + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +Powyższy kod: +1. Sprawdza, czy parametr `custom_id` jest zgodny z pierwotnie wysłanym parametrem (w tym przypadku zaczyna się od `accept_button_`). Zawiera on również ID aktywnej gry, więc przechowujemy go w parametrze `gameID`. +2. [Usuwa pierwotną wiadomość](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response), wywołując webhook przy pomocy `node-fetch` i przekazując `token` unikalnej interakcji w treści żądania. Jest to konieczne, aby zachować porządek na kanale i zapobiec klikaniu przycisku przez innych użytkowników. +3. Wysyła w odpowiedzi na żądanie wiadomość zawierającą menu wyboru obiektu do gry. Payload powinien wyglądać podobnie do poprzedniego, z wyjątkiem tabeli `options` i parametru `flags: 64`, [który oznacza, że wiadomość jest znikająca](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message). + +Tabela `options` jest wypełniana przy pomocy metody `getShuffledOptions()` w pliku `game.js`, która dostosowuje wartości `RPSChoices` do formatu [opcji elementu wiadomości](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure). + + + + + +Na koniec należy dodać kod odpowiedzialny za obsługę interakcji z menu wyboru i wysyłanie wyniku gry na kanał. + +Ponieważ menu wyboru to tylko kolejny element wiadomości, kod odpowiedzialny za interakcję z nim będzie praktycznie taki sam jak w przypadku przycisków. + +Zmodyfikuj powyższy kod pod kątem obsługi menu wyboru: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id konfigurowany w payloadzie przy wysyłaniu elementu wiadomości +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // Uzyskuje powiązany ID gry + const gameId = componentId.replace('accept_button_', ''); + // Usuwa wiadomość z tokenem w treści żądania + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Pobiera losowe emoji do wysłania z funkcji pomocniczej + content: 'What is your object of choice?', + // Określa, że wiadomość będzie znikająca + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Dodaje ID gry + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Usuwa poprzednią wiadomość + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // Uzyskuje powiązany ID gry + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // Pobiera ID i obiekt wybrany przez odpowiadającego użytkownika + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // Oblicza wynik funkcji pomocniczej + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // Usuwa grę z dysku + delete activeGames[gameId]; + // Aktualizuje wiadomość z tokenem w treści żądania + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // Wysyła wynik + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // Aktualizuje znikającą wiadomość + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +Podobnie jak w przypadku poprzedniego kodu, powyższy kod pobiera ID użytkownika i wybrany przez niego obiekt z żądania interakcji. + +Te informacje, wraz z ID i wyborem pierwotnego użytkownika z obiektu `activeGames`, są przekazywane do funkcji `getResult()`. `getResult()` określa zwycięzcę, a następnie tworzy czytelny ciąg, który zostanie wysłany na kanał. + +Wywołujemy również kolejny webhook, tym razem w celu [aktualizacji następczej znikającej wiadomości,](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message) ponieważ nie można jej usunąć. + +Na koniec wyniki są wysyłane na kanał przy pomocy typu reakcji na interakcję `CHANNEL_MESSAGE_WITH_SOURCE`. + + + +To już wszystko 🎊 Możesz teraz przetestować swoją aplikację i upewnić się, że wszystko działa. + +--- + +## Kolejne kroki + +Gratulujemy utworzenia pierwszej aplikacji Discorda! 🤖 + +Mamy nadzieję, że ten artykuł przybliżył Ci nieco aplikacje Discorda i to, jak można konfigurować je i dodawać do nich interaktywne elementy. Teraz możesz kontynuować pracę nad swoją aplikacją lub zobaczyć inne możliwości: +- Przeczytaj **[dokumentację](#DOCS_INTRO)**, w której znajdziesz szczegółowe informacje o funkcjach API +- Zobacz folder `examples/` tego projektu, który zawiera mniejsze, skupione na określonych funkcjach przykłady kodu +- Zapoznaj się z **[zasobami społeczności](#DOCS_TOPICS_COMMUNITY_RESOURCES)** dotyczącymi przeznaczonych do określonych języków narzędzi tworzonych przez użytkowników Discorda +- Przeczytaj nasz samouczek dotyczący [hostowania aplikacji Discorda w serwisie Cloudflare Workers](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS) +- Dołącz do **[serwera Discord Developers](https://discord.gg/discord-developers)**, gdzie możesz zadawać pytania na temat API, uczestniczyć w wydarzeniach organizowanych przez zespół API Discorda i rozmawiać z innymi deweloperami diff --git a/docs/policies_and_agreements/Premium_Apps_Policy.md b/docs/policies_and_agreements/Premium_Apps_Policy.md new file mode 100644 index 0000000000..5840918de9 --- /dev/null +++ b/docs/policies_and_agreements/Premium_Apps_Policy.md @@ -0,0 +1,77 @@ +# Discord Premium Apps Policy + +## Effective date: September 26, 2023 + +## Last updated: September 26, 2023 + +## Summary +Discord believes in giving developers the ability to support themselves and their apps through monetization. To monetize apps on Discord via our Premium Apps products, developers and their apps must abide by the requirements and restrictions outlined below: + +This Discord Premium Apps Policy is incorporated into the Discord [Monetization Terms](https://support.discord.com/hc/en-us/articles/5330075836311) and you agree that it applies to your use of Premium Apps products and services. Capitalized terms not otherwise defined herein have the meaning assigned to them in the Monetization Terms. For clarity, the term “including” as used herein means “including without limitation”. Additionally, examples provided herein are for convenience, and should not be construed to limit the applicability of this Policy. + +Please check back here regularly as we may update these policies from time to time and your continued use of Premium Apps products and services after such updates go into effect means you accept and agree to those updates. Additional terms and policies apply to your use of Premium Apps products and services, including our [Terms of Service](https://discord.com/terms), [Community Guidelines](https://discord.com/guidelines) and Developer [Terms](https://discord.com/developers/docs/policies-and-agreements/developer-terms-of-service) & [Policy](https://discord.com/developers/docs/policies-and-agreements/developer-policy). + + +## Your Account Must Meet The Following Requirements +We look at a number of safety and security signals to determine eligibility for the app owner and members of the developer team. This is not an exhaustive list, but examples that we offer for transparency and ease of understanding: +1. You must be 18 years or older. +2. Your account must be in good standing. Good standing includes but is not limited to: + - You are not actively violating any of Discord’s [Terms](https://discord.com/terms), [Guidelines](https://discord.com/guidelines), or [Developer terms](https://discord.com/developers/docs/policies-and-agreements/developer-terms-of-service) or [policies](https://discord.com/developers/docs/policies-and-agreements/developer-policy). + - Your account has not received a safety violation in the past 30 days. + - Your account has not been flagged for suspicious activity usually reserved for safety, abuse, and fraud cases. + - No outstanding dues or unpaid charges owed to Discord. +3. You must have your email verified. +4. You must have [Two Factor Authentication](https://support.discord.com/hc/en-us/articles/219576828) enabled. Please note, you cannot remove 2FA when you have published an app on our service. + +## Your App Must Meet the Following Requirements +1. Your app must be verified. +2. Your app must not have had an ownership transfer in the last 30 days, all app ownership transfers must be reviewed and approved by Discord. +3. Your app may not be bought or sold without Discord’s approval. +4. Your app must be in good standing. Good standing includes but is not limited to: + - Your app has not received a safety violation in the past 30 days. + - Your app has not been flagged for suspicious activity usually reserved for safety, abuse, and fraud cases. + - Your app is not actively violating Discord’s Developer [Terms](https://discord.com/terms) of Service and [Policy](https://discord.com/developers/docs/policies-and-agreements/developer-policy). + +## You May Not Monetize Content or Apps Associated With Any Of The Following +1. Intellectual property of other rights holders without written permission. +2. Impersonation, unless it is clearly labeled as parody or satire. + - Labels of parody or satire must be clearly visible to users and to Discord at all times. +3. Sexually explicit content, whether hosted on Discord or linked from other services. + - Content may not contain nudity, explicit sexual acts, or content created for the purpose of sexual gratification or arousal. + - Exceptions for non-sexual nudity may be made for context that is educational, artistic, or newsworthy at Discord’s sole discretion. +4. Facilitation, solicitation of, or participation in online dating. +5. Political candidates, campaign teams, political parties, elected or appointed government officials, and/or partisan political activity. +6. Exploitation of tragedy, hardship, or turmoil. + - This includes, for example, participating in financially manipulative behavior such as price gouging and inducing artificial scarcity of necessities. +7. Monetization where the stated purpose of monetization is to support a charitable endeavor. +8. Promotion of pharmaceutical goods, drugs, and unsafe health practices. + - This includes claims of medicinal benefit from supplements that have not been approved by the FDA or similar regulatory body. +9. Promotion or solicitation of endangering behaviors or activities to yourself, others, or animals. +10. Primary purpose of marketing, advertising, or promotional benefit of the app or of a third party, such as: + - Third party servers, + - Applications, + - Businesses, or services. +11. Facilitation of gambling or gambling-adjacent activities such as: + - Simulated casinos and their games. +12. Distribution, manufacturing, sale, or promotion of sales of lethal weapons or explosives and their regulated accessories. +13. Promotion or encouragement of alcohol, tobacco, and other drugs such as: + - Drug paraphernalia, + - Displaying characters that are under the influence, + - Depicting under age drinking, + - Simulated alcohol games, + - Alcohol branding, + - Depictions of hard drug use. +14. Deceptive, misleading, or manipulative financial practices such as: + - Multi-level marketing schemes, + - Financial scams, + - Fraudulent behavior. +15. Facilitation of financial asset transfers or securities ownership. +16. Inappropriate or distasteful content. + - Content that is inflammatory, demeaning, dangerous, misleading, or excessively violent such as: + - Misrepresentative or manipulated content, + - Graphic imagery and realistic displays of crime, violence, physical trauma, execution, + - Content meant to shock or scare, + - Disgusting imagery of guts, gore, sexual fluids, human or animal waste. +17. Profanity or vulgarity, + - Including obscene uses of symbols, emojis, or gestures, + - Emojis or gestures which contain implicit or explicit vulgarity. diff --git a/docs/pt-br/Getting_Started.mdx b/docs/pt-br/Getting_Started.mdx new file mode 100644 index 0000000000..752271a59e --- /dev/null +++ b/docs/pt-br/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# Criando seu primeiro app Discord + +Apps Discord permitem que você personalize e estenda seus servidores usando uma coleção de APIs e recursos interativos. Esse guia orientará você a criar seu primeiro app Discord usando JavaScript e, até o final, você terá um app que usa comandos de barra, envia mensagens e responde a interações de componentes. + +Vamos criar um app Discord que permite que os membros do servidor joguem pedra-papel-tesoura (com 7 opções em vez das 3 de sempre). Esse guia é voltado para iniciantes, mas presume um entendimento básico de [JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics). + + +O app pronto ficará mais ou menos assim: + +![Demo do app de exemplo](getting-started-demo.gif) + +Só para deixar o fluxo de interações mais claro: + +1. O Usuário 1 inicia um novo jogo e escolhe o objeto usando o comando de barra `/challenge` do app. +2. Uma mensagem é publicada no canal com um botão convidando outros usuários a aceitarem o desafio. +3. O Usuário 2 aperta o botão **Aceitar** +4. O Usuário 2 recebe uma mensagem efêmera onde escolhe qual objeto quer usar. +5. O resultado do jogo é postado no canal original para que todos vejam. + + + +- **[Repositório do GitHub](https://github.com/discord/discord-example-app)** onde está hospedado o código deste guia, junto com alguns exemplos adicionais dos códigos de cada recurso. +- **[discord-interactions](https://github.com/discord/discord-interactions-js)**, uma biblioteca que fornece tipos e funções auxiliares para apps Discord. +- **[Express](https://expressjs.com)**, um framework web popular para JavaScript, que usaremos para criar um servidor onde o Discord possa mandar solicitações. +- **[Glitch](https://glitch.com/)**, um ambiente online que simplifica a construção e hospedagem de apps nos estágios iniciais de prototipagem e desenvolvimento. Você também pode desenvolver localmente nele com uma ferramenta como a **[ngrok](https://ngrok.com/)**. + + +--- + +## Passo 1: Criando um app + +Primeiro, você precisa criar o app no portal do desenvolvedor, caso ainda não tenha um: + + + +Insira um nome para seu app, depois aperte **Criar**. + +Após criar seu app, você chegará na página de **Visão Geral** das configurações, onde você pode atualizar informações básicas do seu app, como a descrição e o ícone. Você também verá uma **ID de Aplicativo** e **URL de Endpoint de Interações**, que usaremos daqui a pouco no guia. + +### Configurando seu bot + +Agora, vamos configurar o [usuário-bot](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts) para o seu app, de modo que ele se pareça e se comporte de forma similar a outros membros do servidor. + +Na barra lateral esquerda, clique em **Bot**. Nesta página, você pode definir configurações como as [intenções privilegiadas](#DOCS_TOPICS_GATEWAY/privileged-intents) ou se ele pode ser instalado por outros usuários. + + +Intenções determinam quais eventos o Discord enviará para o seu app quando você criar uma [conexão ao API de Gateway](#DOCS_TOPICS_GATEWAY). Por exemplo, se você quiser que seu app faça alguma coisa quando usuários adicionam uma reação a uma mensagem, você pode passar a intenção `GUILD_MESSAGE_REACTIONS` (`1 << 10`). + +Algumas intenções são [privilegiadas](#DOCS_TOPICS_GATEWAY/privileged-intents), ou seja, elas permitem que seu app acesse dados que podem ser considerados sigilosos (como conteúdo de mensagens). Intenções privilegiadas aparecem e podem ser ligadas ou desligadas na página de **Bots** das configurações do seu app. Intenções padrão (não-privilegiadas) não requerem permissões ou configurações adicionais. + +Para mais informações sobre as intenções e uma lista completa das intenções disponíveis e dos eventos associados a elas, leia a [documentação do Gateway](#DOCS_TOPICS_GATEWAY/gateway-intents). + + +![Aba de Bots nas configurações do app](app-add-bot.png) + +Também há uma seção **Token** na página **Bot**, que permite que você copie e redefina o token do seu bot. + +Tokens de bots são usados para autorizar solicitações de API e contêm as permissões do seu usuário-bot, ou seja, são *extremamente confidenciais*. Certifique-se de *nunca* compartilhar seu token ou incluí-lo em qualquer tipo de controle de versão. + +Pode copiar o token, e guarde-o em um lugar seguro (como um gerenciador de senhas). + +> aviso +> Você não conseguirá mais ver seu token a menos que gere um novo, então trate de guardá-lo em um lugar seguro. + +### Adicionando escopos e permissões de bot + +Apps precisam da permissão do usuário que o está instalando para realizar ações no Discord (como criar um comando de barra ou acessar uma lista de membros do servidor). Vamos selecionar alguns escopos e permissões para solicitar antes de instalar o app. + + +Ao criar um app, escopos e permissões determinam o que seu app pode fazer e acessar nos servidores do Discord. + +- [Escopos OAuth2](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) determinam quais dados e quais ações seu app pode acessar e realizar, concedidos em nome de um usuário que esteja instalando ou autenticando o app. +- [Permissões](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) são as permissões granulares para seu usuário-bot, iguais às que outros usuários do Discord têm. Elas podem ser aprovadas pelo usuário que está instalando ou, mais tarde, atualizando o bot com configurações de servidor ou [redefinições de permissão](#DOCS_TOPICS_PERMISSIONS/permission-overwrites). + + +Clique em **OAuth2** na barra lateral, depois selecione o **gerador de URL**. + +> info +> O gerador de URL cria um link de instalação baseado nos escopos e permissões que você selecionou para o seu app. Você pode usar o link para instalar o app no seu próprio servidor, ou compartilhá-lo com outras pessoas para que elas as instalem. + +Por ora, adicione dois escopos: +- `applications.commands`, que permite que seu app crie [comandos](#DOCS_INTERACTIONS_APPLICATION_COMMANDS). +- `bot` adiciona seu usuário-bot. Após selecionar `bot`, também dá para selecionar várias permissões para o seu bot. Por ora, pode escolher só **Enviar Mensagens**. + +Leia a documentação para ver uma lista de todos os [escopos OAuth2](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) ou saber mais sobre [permissões](#DOCS_TOPICS_PERMISSIONS). + +### Instalando seu app + +Ao adicionar escopos, você deve ver um URL que pode copiar para instalar seu app. + +![Captura de tela do gerador de URL](url-generator.png) + +> info +> Ao desenvolver apps, é melhor criá-los e instalá-los em um servidor que ninguém usa. Se já não tiver seu próprio servidor, pode [criar um de graça](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server-). + +Copie o URL acima e cole-o no seu navegador. A página vai te guiar pelo fluxo da instalação, onde você deve se certificar que está instalando seu app num servidor onde possa desenvolvê-lo e testá-lo. + +Após instalar seu app, você pode entrar no servidor e ver que ele entrou ✨ + +Com seu app configurado e instalado, vamos começar o desenvolvimento. + +--- + +## Passo 2: Executando seu app + +Todo o código usado no app de exemplo está disponível no [repositório do GitHub](https://github.com/discord/discord-example-app). + +Para simplificar o desenvolvimento, o app usa o [discord-interactions](https://github.com/discord/discord-interactions-js), que fornece tipos e funções auxiliares. Se você preferir usar outros idiomas ou bibliotecas, acesse a documentação dos [Recursos de Comunidade](#DOCS_TOPICS_COMMUNITY_RESOURCES). + +### Remixando o projeto + +Este guia usa o Glitch, que permite que você clone e desenvolva o app no seu navegador. Se você preferir desenvolver seu app localmente, o [LEIAME](https://github.com/discord/discord-example-app#running-app-locally) contém instruções sobre como usar o ngrok. + +> info +> Apesar do Glitch ser ótimo para desenvolvimento e testagem, ele tem restrições técnicas (ver https://help.glitch.com/hc/en-us/articles/16287495313293-Technical-Restrictions), então considere outras hospedagens quando for desenvolver para produção. + +Para começar, **[remixe (ou clone) o projeto do Glitch 🎏](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)**. + +Após remixar o projeto, você abrirá um projeto novo do Glitch. + + +![Visão geral do projeto do Glitch](glitch-project.png) + +- Seu **nome de projeto** é um nome único para seu projeto, que aparece no canto superior-esquerdo. +- **`.env`** é o arquivo onde todas as suas credenciais do seu app são armazenadas. +- **Registros** são onde aparecem os resultados do seu projeto. Eles são úteis para verificar se o app está sendo executado ou ler informações sobre erros que o app encontrar. +- O botão **Compartilhar** no canto superior direito é onde aparece a URL do seu projeto, que você usará mais tarde neste guia para montar a interatividade. + + +#### Estrutura do projeto + +Todos os arquivos do projeto ficam do lado esquerdo do seu projeto do Glitch. Abaixo, uma visão geral das pastas e arquivos principais: + +``` +├── examples -> amostras de apps curtos de cada recurso +│ ├── app.js -> código app.js finalizado +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> suas credenciais e IDs +├── app.js -> entrypoint principal do app +├── commands.js -> payloads e auxiliares dos comandos de barra +├── game.js -> lógica específica do pedra-papel-tesoura +├── utils.js -> funções utilitárias e enums +├── package.json +├── README.md +└── .gitignore +``` + +### Adicionando credenciais + +Já existem alguns códigos no seu arquivo `app.js`, mas você precisará do token e ID do seu app para fazer solicitações. Todas as suas credenciais podem ser armazenadas diretamente no arquivo `.env`. + +Primeiro, copie o token do seu bot obtido anteriormente e cole-o na variável **`DISCORD_TOKEN`** do seu arquivo `.env`. + +Em seguida, navegue até a página **Visão Geral** do seu app, copie a **ID do app** e a **Chave Pública**. Cole os valores no seu arquivo `.env` como **`APP_ID`** e **`PUBLIC_KEY`**. + +Com suas credenciais configuradas, vamos instalar e direcionar os comandos de barra. + +### Instalando comandos de barra + +> info +> Para instalar comandos de barra, o app usa [`node-fetch`](https://github.com/node-fetch/node-fetch). Você pode ver a implementação da instalação em `utils.js` dentro da função `DiscordRequest()`. + +O projeto contém um script `register` que você pode usar para instalar os comandos em `ALL_COMMANDS`, que são definidos no fim de `commands.js`. Ele instala os comandos como globais chamando o endpoint [`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands) das APIs HTTP. + +Se quiser personalizar seus comandos ou adicionar novos, você pode consultar a estrutura de comando na [documentação de comandos](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure). + +Execute o script `register` clicando em **Terminal** na parte de baixo do seu projeto do Glitch e colando o seguinte comando: + +``` +npm run register +``` + +Aperte enter para executar o comando. + +Quando voltar lá para seu servidor, você deve ver os comandos de barra aparecendo. Mas, se tentar executá-los, nada vai acontecer, pois seu app não está recebendo ou processando solicitações do Discord. + + +O Discord tem duas APIs que você pode combinar como quiser para criar apps: + +- A **[API HTTP](#DOCS_REFERENCE/http-api)** é uma API tipo REST para operações gerais como o envio e atualização de dados no Discord, ou solicitações de dados sobre recursos. +- A **[API de Gateway](#DOCS_REFERENCE/gateway-websocket-api)** é uma API baseada em WebSocket que ajuda a manter o estado ou ouvir eventos que estão ocorrendo em um servidor Discord. Não vamos usá-la neste guia, mas você pode ler mais sobre como criar uma conexão de Gateway e os diferentes eventos que ela pode ouvir na [documentação de Gateway](#DOCS_TOPICS_GATEWAY). + + +--- + +## Passo 3: Lidando com a interatividade + +Para permitir que seu app receba solicitações de comando de barra (e outras interações), o Discord precisa de um URL público para onde mandá-las. Este URL pode ser configurado nas configurações do seu app, como o **URL de Endpoint de Interações**. + +### Adicionando um URL de Endpoint de Interações + +Projetos do Glitch têm um URL público exposto por padrão. Copie o URL do seu projeto clicando no botão **Compartilhar** no canto superior direito, depois copie o link do projeto "Live site" perto do final do modal. + +> info +> Se você estiver desenvolvendo localmente, há instruções sobre como direcionar solicitações ao seu ambiente local no [LEIAME do GitHub](https://github.com/discord/discord-example-app#running-app-locally). + +Com o link copiado, vá até as configurações do seu app no [portal do desenvolvedor](https://discord.com/developers/applications). + +Na página de **Informações Gerais** do seu app, há uma opção de **URL de Endpoint de Interação**, onde você deve colar o URL do seu app e colocar `/interactions` no fim dele, pois é daí que o app Express está configurado para esperar solicitações. + +![URL de Endpoint de Interações nas configurações do app](interactions-url.png) + +Clique em **Salvar Mudanças** e certifique-se que seu endpoint seja verificado corretamente. + +O app de exemplo faz a verificação de duas formas: +- Usando a `PUBLIC_KEY` e o [pacote discord-interactions](https://github.com/discord/discord-interactions-js#usage) com uma função wrapper (importada do `utils.js`) que faz ele se conformar à [interface `verify` do Express](http://expressjs.com/en/5x/api.html#express.json). Esse processo é realizado em cada solicitação que seu app recebe. +- Ele responde a solicitações `PING` recebidas. + +Você pode ler mais sobre como preparar seu app para receber interações na [documentação de interações](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction). + +### Processando solicitações de comando de barra + +Com o endpoint verificado, vá até o arquivo `app.js` do seu projeto e procure o bloco de código que cuida do comando `/test`: + +```javascript +// comando "test" +if (name === 'test') { + // Envia uma mensagem para o canal de onde o comando foi ativado + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Escolhe um emoji aleatório para enviar de uma função auxiliar + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +O código acima respondeu à interação com uma mensagem no canal na qual ela se originou. Você pode ver todos os tipos de respostas disponíveis (por exemplo, responder com um modal) [na documentação](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type). + +> info +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE` é uma constante [exportada do `discord-interactions`](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33) + +Vá até seu servidor e certifique-se que o comando de barra `/test` do seu app esteja funcionando. Ao ativá-lo, o app deve mandar uma mensagem que contém "hello world" seguido de um emoji aleatório. + +Na seção a seguir, adicionaremos um comando adicional que usa opções de comando de barra, botões e menus de seleção para construir o jogo de pedra-papel-tesoura. + +--- + +## Passo 4: Adicionando componentes de mensagens + +Usaremos o comando `/challenge` para iniciar nosso jogo estilo pedra-papel-tesoura. Quando o comando é ativado, o app enviará componentes de mensagem ao canal, que guiarão os usuários para completar o jogo. + +### Adicionando um comando com opções + +O comando `/challenge`, chamado `CHALLENGE_COMMAND` no `commands.js`, tem um array de `options`. No nosso app, as opções são objetos representando coisas diferentes que usuários podem escolher enquanto jogam pedra-papel-tesoura, gerados usando chaves de `RPSChoices` em `game.js`. + +Você pode ler mais sobre opções de comando e a estrutura delas [na documentação](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure). + +> info +> Este guia não vai falar muito do arquivo `game.js`, mas fique à vontade para mexer nele, mudando os comandos ou as opções deles. + + + +Para lidar com o comando `/challenge`, adicione o seguinte código após o bloco "se" `if name === “test”`: + +```javascript +// comando "challenge" +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // Objeto de escolha do usuário + const objectName = req.body.data.options[0].value; + + // Criar jogo ativo usando ID da mensagem como ID de jogo + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // Anexar a ID do jogo para usar mais tarde + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> info +> Se não tiver certeza onde colar o código, você pode ver o código completo em `examples/app.js` no projeto do Glitch ou no root `app.js` [no GitHub](https://github.com/discord/discord-example-app/blob/main/app.js). + +O código acima faz algumas coisas: +1. Analisa o corpo da solicitação para obter a ID do usuário que ativou o comando de barra (`userId`) e a opção (escolha de objeto) que ele(a) selecionou (`objectName`). +2. Adiciona um novo jogo ao objeto `activeGames` usando a ID de interação. O jogo ativo registra o `userId` e o `objectName`. +3. Envia uma mensagem de volta ao canal com um botão contendo uma `custom_id` de `accept_button_`. + +> aviso +> O código de exemplo usa um objeto como armazenamento na memória, mas os apps para produção devem ter bases de dados. + +Ao enviar uma mensagem com [componentes de mensagem](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component), os payloads individuais são anexados a um array `components`. Componentes acionáveis (como botões) precisam estar dentro de uma [fileira de ações](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows), como aparece na amostra do código. + +Repare na `custom_id` enviada com componentes de mensagem (neste caso `accept_button_`) com a ID do jogo ativo anexada a ela. Uma `custom_id` pode ser usada para lidar com solicitações enviadas pelo Discord quando alguém interage com o componente. Você verá isso daqui a pouco. + +Agora, quando você usar o comando `/challenge` e escolher uma opção, seu app mandará uma mensagem com o botão **Aceitar**. Vamos adicionar um código para lidar com o apertar do botão. + + + + + +Quando usuários interagem com um componente de mensagem, o Discord envia uma solicitação com um [tipo de interação](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) de `3` (ou o valor `MESSAGE_COMPONENT` ao usar `discord-interactions`). + +Para montar um handler para o botão, vamos verificar o `type` da interação e alinhando com a `custom_id`. + +Cole o seguinte código sob o handler de tipo para `APPLICATION_COMMAND`s: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id definida no payload ao enviar o componente da mensagem +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // recebe a ID de jogo associada + const gameId = componentId.replace('accept_button_', ''); + // Exclui a mudança com o token no corpo da solicitação + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Escolhe um emoji aleatório para enviar de uma função auxiliar + content: 'What is your object of choice?', + // Indica que será uma mensagem efêmera + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Anexa a ID de jogo + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Exclui a mensagem anterior + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +O código acima: +1. Procura uma `custom_id` que combine com a enviada originalmente (neste caso, ela começa com `accept_button_`). A ID personalizada também tem a ID do jogo ativo anexada, então armazenamos ela na `gameID`. +2. [Exclui a mensagem original](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response) chamando um webhook através do `node-fetch` e passando o `token` de interação única no corpo da solicitação. Isso serve para manter o canal limpo e para impedir que outros usuários cliquem no botão. +3. Responde à solicitação enviando uma mensagem que contém um menu de seleção com as escolhas de objeto do jogo. O payload deve ser bem parecido com o anterior, com exceção do array de `options` e `flags: 64`, [que indica que a mensagem é efêmera](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message). + +O array de `options` é povoado usando o método `getShuffledOptions()` do `game.js`, que manipula os valores de `RPSChoices` para se conformar ao formato das [opções de componente de mensagem](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure). + + + + + +A última coisa a adicionar é um código que lide com interações do menu de seleção e envie os resultados do jogo para o canal. + +Já que menus de seleção são só outro componente de mensagem, o código que cuida das interações deles serão quase idênticos aos dos botões. + +Modifique o código acima para lidar com o menu de seleção: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id definida no payload ao enviar o componente da mensagem +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // recebe a ID de jogo associada + const gameId = componentId.replace('accept_button_', ''); + // Exclui a mudança com o token no corpo da solicitação + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Escolhe um emoji aleatório para enviar de uma função auxiliar + content: 'What is your object of choice?', + // Indica que será uma mensagem efêmera + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Anexa a ID de jogo + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Exclui a mensagem anterior + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // recebe a ID de jogo associada + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // Recebe a ID de usuário e escolha de objeto do usuário que responde + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // Calcula o resultado na função auxiliar + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // Remove o jogo da armazenagem + delete activeGames[gameId]; + // Atualiza a mensagem com o token no corpo da solicitação + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // Envia os resultados + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // Atualiza a mensagem efêmera + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +Parecido com códigos anteriores, o código acima busca a ID de usuário e a seleção de objeto da solicitação de interação. + +Essas informações, junto com a ID do usuário original e a seleção feita no objeto `activeGames`, são passadas para a função `getResult()`. A `getResult()` determina o vencedor, depois monta uma string legível para enviar de volta ao canal. + +Também estamos chamando outro webhook, desta vez para [atualizar a mensagem efêmera complementar](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message), já que ela não pode ser excluída. + +Por fim, os resultados são enviados no canal usando o tipo de interação de resposta `CHANNEL_MESSAGE_WITH_SOURCE`. + + + +...e pronto 🎊 Pode testar seu app pra garantir que está tudo funcionando. + +--- + +## Próximos passos + +Parabéns por criar seu primeiro app Discord! 🤖 + +Esperamos que você tenha aprendido um pouco sobre apps Discord e como torná-los interativos. Daqui, você pode continuar a montar seu app ou explorar outras possibilidades: +- Ler **[a documentação](#DOCS_INTRO)** para informações mais detalhadas sobre recursos da API. +- Navegar pela pasta `examples/` neste projeto para ver exemplos de código menores e mais específicos. +- Conferir **[recursos da comunidade](#DOCS_TOPICS_COMMUNITY_RESOURCES)** para ferramentas específicas de certas linguagens de programaçãoque são mantidas por membros da comunidade. +- Ler nosso tutorial sobre [como hospedar apps Discord no Cloudflare Workers](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS) +- Entrar no **[servidor de Desenvolvedores Discord](https://discord.gg/discord-developers)** para fazer perguntas sobre a API, participar de eventos organizados pela equipe da API do Discord e interagir com outros desenvolvedores. diff --git a/docs/resources/Application.md b/docs/resources/Application.md index 7f67ab761d..d30b81bf64 100644 --- a/docs/resources/Application.md +++ b/docs/resources/Application.md @@ -4,32 +4,35 @@ ###### Application Structure -| Field | Type | Description | -| ---------------------------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| id | snowflake | the id of the app | -| name | string | the name of the app | -| icon | ?string | the [icon hash](#DOCS_REFERENCE/image-formatting) of the app | -| description | string | the description of the app | -| rpc_origins? | array of strings | an array of rpc origin urls, if rpc is enabled | -| bot_public | boolean | when false only app owner can join the app's bot to guilds | -| bot_require_code_grant | boolean | when true the app's bot will only join upon completion of the full oauth2 code grant flow | -| terms_of_service_url? | string | the url of the app's terms of service | -| privacy_policy_url? | string | the url of the app's privacy policy | -| owner? | partial [user](#DOCS_RESOURCES_USER/user-object) object | partial user object containing info on the owner of the application | -| summary *(deprecated)* | string | **deprecated and will be removed in v11.** An empty string. | -| verify_key | string | the hex encoded key for verification in interactions and the GameSDK's [GetTicket](#DOCS_GAME_SDK_APPLICATIONS/getticket) | -| team | ?[team](#DOCS_TOPICS_TEAMS/data-models-team-object) object | if the application belongs to a team, this will be a list of the members of that team | -| guild_id? | snowflake | guild associated with the app. For example, a developer support server. | -| guild? | partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object | a partial object of the associated guild | -| primary_sku_id? | snowflake | if this application is a game sold on Discord, this field will be the id of the "Game SKU" that is created, if exists | -| slug? | string | if this application is a game sold on Discord, this field will be the URL slug that links to the store page | -| cover_image? | string | the application's default rich presence invite [cover image hash](#DOCS_REFERENCE/image-formatting) | -| flags? | integer | the application's public [flags](#DOCS_RESOURCES_APPLICATION/application-object-application-flags) | -| approximate_guild_count? | integer | an approximate count of the app's guild membership. | -| tags? | array of strings | up to 5 tags describing the content and functionality of the application | -| install_params? | [install params](#DOCS_RESOURCES_APPLICATION/install-params-object) object | settings for the application's default in-app authorization link, if enabled | -| custom_install_url? | string | the application's default custom authorization link, if enabled | -| role_connections_verification_url? | string | the application's role connection verification entry point, which when configured will render the app as a verification method in the guild role verification configuration | +| Field | Type | Description | +|------------------------------------|----------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------| +| id | snowflake | ID of the app | +| name | string | Name of the app | +| icon | ?string | [Icon hash](#DOCS_REFERENCE/image-formatting) of the app | +| description | string | Description of the app | +| rpc_origins? | array of strings | List of RPC origin URLs, if RPC is enabled | +| bot_public | boolean | When `false`, only the app owner can add the app to guilds | +| bot_require_code_grant | boolean | When `true`, the app's bot will only join upon completion of the full OAuth2 code grant flow | +| bot? | partial [user](#DOCS_RESOURCES_USER/user-object) object | Partial user object for the bot user associated with the app | +| terms_of_service_url? | string | URL of the app's Terms of Service | +| privacy_policy_url? | string | URL of the app's Privacy Policy | +| owner? | partial [user](#DOCS_RESOURCES_USER/user-object) object | Partial user object for the owner of the app | +| summary *(deprecated)* | string | **deprecated and will be removed in v11.** An empty string. | +| verify_key | string | Hex encoded key for verification in interactions and the GameSDK's [GetTicket](#DOCS_GAME_SDK_APPLICATIONS/getticket) | +| team | ?[team](#DOCS_TOPICS_TEAMS/data-models-team-object) object | If the app belongs to a team, this will be a list of the members of that team | +| guild_id? | snowflake | Guild associated with the app. For example, a developer support server. | +| guild? | partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object | Partial object of the associated guild | +| primary_sku_id? | snowflake | If this app is a game sold on Discord, this field will be the id of the "Game SKU" that is created, if exists | +| slug? | string | If this app is a game sold on Discord, this field will be the URL slug that links to the store page | +| cover_image? | string | App's default rich presence invite [cover image hash](#DOCS_REFERENCE/image-formatting) | +| flags? | integer | App's public [flags](#DOCS_RESOURCES_APPLICATION/application-object-application-flags) | +| approximate_guild_count? | integer | Approximate count of guilds the app has been added to | +| redirect_uris? | array of strings | Array of redirect URIs for the app | +| interactions_endpoint_url? | string | [Interactions endpoint URL](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction) for the app | +| role_connections_verification_url? | string | Role connection verification URL for the app | +| tags? | array of strings | List of tags describing the content and functionality of the app. Max of 5 tags. | +| install_params? | [install params](#DOCS_RESOURCES_APPLICATION/install-params-object) object | Settings for the app's default in-app authorization link, if enabled | +| custom_install_url? | string | Default custom authorization URL for the app, if enabled | ###### Example Application Object @@ -77,7 +80,7 @@ ###### Application Flags | Value | Name | Description | -| ------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|---------|-----------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 << 6 | APPLICATION_AUTO_MODERATION_RULE_CREATE_BADGE | Indicates if an app uses the [Auto Moderation API](#DOCS_RESOURCES_AUTO_MODERATION) | | 1 << 12 | GATEWAY_PRESENCE | Intent required for bots in **100 or more servers** to receive [`presence_update` events](#DOCS_TOPICS_GATEWAY_EVENTS/presence-update) | | 1 << 13 | GATEWAY_PRESENCE_LIMITED | Intent required for bots in under 100 servers to receive [`presence_update` events](#DOCS_TOPICS_GATEWAY_EVENTS/presence-update), found on the **Bot** page in your app's settings | @@ -93,11 +96,36 @@ ###### Install Params Structure -| Field | Type | Description | -| ----------- | ---------------- | ---------------------------------------------------------------------------------------------------------- | -| scopes | array of strings | the [scopes](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) to add the application to the server with | -| permissions | string | the [permissions](#DOCS_TOPICS_PERMISSIONS) to request for the bot role | +| Field | Type | Description | +|-------------|------------------|--------------------------------------------------------------------------------------------------------| +| scopes | array of strings | [Scopes](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) to add the application to the server with | +| permissions | string | [Permissions](#DOCS_TOPICS_PERMISSIONS) to request for the bot role | ## Get Current Application % GET /applications/@me Returns the [application](#DOCS_RESOURCES_APPLICATION/application-object) object associated with the requesting bot user. + +## Edit Current Application % PATCH /applications/@me + +Edit properties of the app associated with the requesting bot user. Only properties that are passed will be updated. Returns the updated [application](#DOCS_RESOURCES_APPLICATION/application-object) object on success. + +> info +> All parameters to this endpoint are optional + +###### JSON Params + +| Field | Type | Description | +|-----------------------------------|----------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------| +| custom_install_url | string | Default custom authorization URL for the app, if enabled | +| description | string | Description of the app | +| role_connections_verification_url | string | Role connection verification URL for the app | +| install_params | [install params](#DOCS_RESOURCES_APPLICATION/install-params-object) object | Settings for the app's default in-app authorization link, if enabled | +| flags \* | integer | App's public [flags](#DOCS_RESOURCES_APPLICATION/application-object-application-flags) | +| icon | ?[image data](#DOCS_REFERENCE/image-data) | Icon for the app | +| cover_image | ?[image data](#DOCS_REFERENCE/image-data) | Default rich presence invite cover image for the app | +| interactions_endpoint_url \*\* | string | [Interactions endpoint URL](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction) for the app | +| tags | array of strings | List of tags describing the content and functionality of the app (max of 20 characters per tag). Max of 5 tags. | + +\* Only limited intent flags (`GATEWAY_PRESENCE_LIMITED`, `GATEWAY_GUILD_MEMBERS_LIMITED`, and `GATEWAY_MESSAGE_CONTENT_LIMITED`) can be updated via the API. + +\*\* To update an Interactions endpoint URL via the API, the URL must be valid according to the [Receiving an Interaction](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction) documentation. \ No newline at end of file diff --git a/docs/resources/Application_Role_Connection_Metadata.md b/docs/resources/Application_Role_Connection_Metadata.md index 042a67f787..6403b37877 100644 --- a/docs/resources/Application_Role_Connection_Metadata.md +++ b/docs/resources/Application_Role_Connection_Metadata.md @@ -6,25 +6,25 @@ When a guild has added a bot and that bot has configured its [`role_connections_ If an application has configured role connection metadata, its metadata will appear in the role verification configuration when the application has been added as a verification method to the role. -When a user connects their account using the bot's [`role_connections_verification_url`](#DOCS_RESOURCES_APPLICATION/application-object), the bot will [update a user's role connection with metadata](#DOCS_RESOURCES_USER/update-user-application-role-connection) using the OAuth2 `role_connections.write` scope. +When a user connects their account using the bot's [`role_connections_verification_url`](#DOCS_RESOURCES_APPLICATION/application-object), the bot will [update a user's role connection with metadata](#DOCS_RESOURCES_USER/update-current-user-application-role-connection) using the OAuth2 `role_connections.write` scope. ### Application Role Connection Metadata Object ###### Application Role Connection Metadata Structure -| Field | Type | Description | -| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | -| type | [ApplicationRoleConnectionMetadataType](#DOCS_RESOURCES_APPLICATION_ROLE_CONNECTION_METADATA/application-role-connection-metadata-object-application-role-connection-metadata-type) | type of metadata value | -| key | string | dictionary key for the metadata field (must be `a-z`, `0-9`, or `_` characters; 1-50 characters) | -| name | string | name of the metadata field (1-100 characters) | -| name_localizations? | dictionary with keys in [available locales](#DOCS_REFERENCE/locales) | translations of the name | -| description | string | description of the metadata field (1-200 characters) | -| description_localizations? | dictionary with keys in [available locales](#DOCS_REFERENCE/locales) | translations of the description | +| Field | Type | Description | +|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------| +| type | [ApplicationRoleConnectionMetadataType](#DOCS_RESOURCES_APPLICATION_ROLE_CONNECTION_METADATA/application-role-connection-metadata-object-application-role-connection-metadata-type) | type of metadata value | +| key | string | dictionary key for the metadata field (must be `a-z`, `0-9`, or `_` characters; 1-50 characters) | +| name | string | name of the metadata field (1-100 characters) | +| name_localizations? | dictionary with keys in [available locales](#DOCS_REFERENCE/locales) | translations of the name | +| description | string | description of the metadata field (1-200 characters) | +| description_localizations? | dictionary with keys in [available locales](#DOCS_REFERENCE/locales) | translations of the description | ###### Application Role Connection Metadata Type | Type | Value | Description | -| ------------------------------ | ----- | -------------------------------------------------------------------------------------------------------------------------------------- | +|--------------------------------|-------|----------------------------------------------------------------------------------------------------------------------------------------| | INTEGER_LESS_THAN_OR_EQUAL | 1 | the metadata value (`integer`) is less than or equal to the guild's configured value (`integer`) | | INTEGER_GREATER_THAN_OR_EQUAL | 2 | the metadata value (`integer`) is greater than or equal to the guild's configured value (`integer`) | | INTEGER_EQUAL | 3 | the metadata value (`integer`) is equal to the guild's configured value (`integer`) | diff --git a/docs/resources/Audit_Log.md b/docs/resources/Audit_Log.md index b89f561690..9521448bc7 100644 --- a/docs/resources/Audit_Log.md +++ b/docs/resources/Audit_Log.md @@ -11,7 +11,7 @@ When an app is performing an eligible action using the APIs, it can pass an `X-A ###### Audit Log Structure | Field | Type | Description | -| ---------------------- | ------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- | +|------------------------|--------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------| | application_commands | array of [application commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object) objects | List of application commands referenced in the audit log | | audit_log_entries | array of [audit log entry](#DOCS_RESOURCES_AUDIT_LOG/audit-log-entry-object) objects | List of audit log entries, sorted from most to least recent | | auto_moderation_rules | array of [auto moderation rule](#DOCS_RESOURCES_AUTO_MODERATION/auto-moderation-rule-object) objects | List of auto moderation rules referenced in the audit log | @@ -49,7 +49,7 @@ Apps can specify why an administrative action is being taken by passing an `X-Au ###### Audit Log Entry Structure | Field | Type | Description | -| ----------- | ------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | +|-------------|---------------------------------------------------------------------------------------------------------|-------------------------------------------------------| | target_id | ?string | ID of the affected entity (webhook, user, role, etc.) | | changes? | array of [audit log change](#DOCS_RESOURCES_AUDIT_LOG/audit-log-change-object) objects | Changes made to the target_id | | user_id | ?snowflake | User or app that made the changes | @@ -73,7 +73,7 @@ If no object is noted, there won't be a `changes` array in the entry, though oth > You should assume that your app may run into any field for the changed object, though none are guaranteed to be present. In most cases only a subset of the object's fields will be in the `changes` array. | Event | Value | Description | Object Changed | -| ------------------------------------------- | ----- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +|---------------------------------------------|-------|-----------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------| | GUILD_UPDATE | 1 | Server settings were updated | [Guild](#DOCS_RESOURCES_GUILD/guild-object) | | CHANNEL_CREATE | 10 | Channel was created | [Channel](#DOCS_RESOURCES_CHANNEL/channel-object) | | CHANNEL_UPDATE | 11 | Channel settings were updated | [Channel](#DOCS_RESOURCES_CHANNEL/channel-object) | @@ -136,7 +136,7 @@ If no object is noted, there won't be a `changes` array in the entry, though oth ###### Optional Audit Entry Info | Field | Type | Description | Event Types | -| --------------------------------- | --------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------------|-----------|------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | application_id | snowflake | ID of the app whose permissions were targeted | APPLICATION_COMMAND_PERMISSION_UPDATE | | auto_moderation_rule_name | string | Name of the Auto Moderation rule that was triggered | AUTO_MODERATION_BLOCK_MESSAGE & AUTO_MODERATION_FLAG_TO_CHANNEL & AUTO_MODERATION_USER_COMMUNICATION_DISABLED | | auto_moderation_rule_trigger_type | string | Trigger type of the Auto Moderation rule that was triggered | AUTO_MODERATION_BLOCK_MESSAGE & AUTO_MODERATION_FLAG_TO_CHANNEL & AUTO_MODERATION_USER_COMMUNICATION_DISABLED | @@ -148,6 +148,7 @@ If no object is noted, there won't be a `changes` array in the entry, though oth | message_id | snowflake | ID of the message that was targeted | MESSAGE_PIN & MESSAGE_UNPIN | | role_name | string | Name of the role if type is `"0"` (not present if type is `"1"`) | CHANNEL_OVERWRITE_CREATE & CHANNEL_OVERWRITE_UPDATE & CHANNEL_OVERWRITE_DELETE | | type | string | Type of overwritten entity - role (`"0"`) or member (`"1"`) | CHANNEL_OVERWRITE_CREATE & CHANNEL_OVERWRITE_UPDATE & CHANNEL_OVERWRITE_DELETE | +| integration_type | string | The type of integration which performed the action | MEMBER_KICK & MEMBER_ROLE_UPDATE | ### Audit Log Change Object @@ -162,17 +163,17 @@ Some events don't follow the same pattern as other audit log events. Details abo | Field | Type | Description | -| ---------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +|------------|-------------------------------------|------------------------------------------------------------------------------------------------------------------------------------| | new_value? | mixed (matches object field's type) | New value of the key | | old_value? | mixed (matches object field's type) | Old value of the key | | key | string | Name of the changed entity, with a few [exceptions](#DOCS_RESOURCES_AUDIT_LOG/audit-log-change-object-audit-log-change-exceptions) | ###### Audit Log Change Exceptions -For most objects, the change keys may be any field on the changed object. The following table details the exceptions to this pattern. +For most objects, the change keys may be any field on the changed object. The following table details the exceptions to this pattern. | Object Changed | Change Key Exceptions | Change Object Exceptions | -| ---------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [Command Permission](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-permissions-object-application-command-permissions-structure) | snowflake as key | The `changes` array contains objects with a `key` field representing the entity whose command was affected (role, channel, or user ID), a previous permissions object (with an `old_value` key), and an updated permissions object (with a `new_value` key) | | [Invite](#DOCS_RESOURCES_INVITE/invite-object) and [Invite Metadata](#DOCS_RESOURCES_INVITE/invite-metadata-object) | Additional `channel_id` key (instead of object's `channel.id`) | | | [Partial Role](#DOCS_TOPICS_PERMISSIONS/role-object) | `$add` and `$remove` as keys | `new_value` is an array of objects that contain the role `id` and `name` | @@ -189,7 +190,7 @@ The returned list of audit log entries is ordered based on whether you use `befo The following parameters can be used to filter which and how many audit log entries are returned. | Field | Type | Description | -| ------------ | --------- | ----------------------------------------------------------------------------------------------------------- | +|--------------|-----------|-------------------------------------------------------------------------------------------------------------| | user_id? | snowflake | Entries from a specific user ID | | action_type? | integer | Entries for a specific [audit log event](#DOCS_RESOURCES_AUDIT_LOG/audit-log-entry-object-audit-log-events) | | before? | snowflake | Entries with ID less than a specific audit log entry ID | diff --git a/docs/resources/Auto_Moderation.md b/docs/resources/Auto_Moderation.md index 6b797ff144..b00fe9d1a0 100644 --- a/docs/resources/Auto_Moderation.md +++ b/docs/resources/Auto_Moderation.md @@ -9,7 +9,7 @@ Rules can be configured to automatically execute actions whenever they trigger. ###### Auto Moderation Rule Structure | Field | Type | Description | -| ---------------- | ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | +|------------------|------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------| | id | snowflake | the id of this rule | | guild_id | snowflake | the id of the guild which this rule belongs to | | name | string | the rule name | @@ -100,7 +100,7 @@ value of [trigger_type](#DOCS_RESOURCES_AUTO_MODERATION/auto-moderation-rule-obj ###### Keyword Preset Types | Preset Type | Value | Description | -| -------------- | ----- | ------------------------------------------------------------ | +|----------------|-------|--------------------------------------------------------------| | PROFANITY | 1 | words that may be considered forms of swearing or cursing | | SEXUAL_CONTENT | 2 | words that refer to sexually explicit behavior or activity | | SLURS | 3 | personal insults or words that may be considered hate speech | @@ -123,7 +123,7 @@ Use the wildcard symbol (`*`) at the beginning or end of a keyword to define how **Prefix** - word must start with the keyword | Keyword | Matches | -| --------- | ------------------------------------- | +|-----------|---------------------------------------| | cat\* | **cat**ch, **Cat**apult, **CAt**tLE | | tra\* | **tra**in, **tra**de, **TRA**ditional | | the mat\* | **the mat**rix | @@ -132,7 +132,7 @@ Use the wildcard symbol (`*`) at the beginning or end of a keyword to define how **Suffix** - word must end with the keyword | Keyword | Matches | -| --------- | ----------------------------------- | +|-----------|-------------------------------------| | \*cat | wild**cat**, copy**Cat** | | \*tra | ex**tra**, ul**tra**, orches**TRA** | | \*the mat | brea**the mat** | @@ -141,7 +141,7 @@ Use the wildcard symbol (`*`) at the beginning or end of a keyword to define how **Anywhere** - keyword can appear anywhere in the content | Keyword | Matches | -| ----------- | --------------------------- | +|-------------|-----------------------------| | \*cat\* | lo**cat**ion, edu**Cat**ion | | \*tra\* | abs**tra**cted, ou**tra**ge | | \*the mat\* | brea**the mat**ter | @@ -150,7 +150,7 @@ Use the wildcard symbol (`*`) at the beginning or end of a keyword to define how **Whole Word** - keyword is a full word or phrase and must be surrounded by whitespace | Keyword | Matches | -| ------- | ----------- | +|---------|-------------| | cat | **cat** | | train | **train** | | the mat | **the mat** | @@ -163,7 +163,7 @@ An action which will execute whenever a rule is triggered. ###### Auto Moderation Action Structure | Field | Type | Description | -| ----------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- | +|-------------|--------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------| | type | [action type](#DOCS_RESOURCES_AUTO_MODERATION/auto-moderation-action-object-action-types) | the type of action | | metadata? * | [action metadata](#DOCS_RESOURCES_AUTO_MODERATION/auto-moderation-action-object-action-metadata) | additional metadata needed during execution for this specific action type | @@ -187,7 +187,7 @@ Additional data used when an action is executed. Different fields are relevant b value of [action type](#DOCS_RESOURCES_AUTO_MODERATION/auto-moderation-action-object-action-types). | Field | Type | Associated Action Types | Description | Constraints | -| ---------------- | --------- | ----------------------- | -------------------------------------------------------------------------------------- | ------------------------------------ | +|------------------|-----------|-------------------------|----------------------------------------------------------------------------------------|--------------------------------------| | channel_id | snowflake | SEND_ALERT_MESSAGE | channel to which user content should be logged | existing channel | | duration_seconds | integer | TIMEOUT | timeout duration in seconds | maximum of 2419200 seconds (4 weeks) | | custom_message? | string | BLOCK_MESSAGE | additional explanation that will be shown to members whenever their message is blocked | maximum of 150 characters | @@ -225,7 +225,7 @@ Create a new rule. Returns an [auto moderation rule](#DOCS_RESOURCES_AUTO_MODERA ###### JSON Params | Field | Type | Description | -| ------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | +|---------------------|------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------| | name | string | the rule name | | event_type | integer | the [event type](#DOCS_RESOURCES_AUTO_MODERATION/auto-moderation-rule-object-event-types) | | trigger_type | integer | the [trigger type](#DOCS_RESOURCES_AUTO_MODERATION/auto-moderation-rule-object-trigger-types) | @@ -257,7 +257,7 @@ Modify an existing rule. Returns an [auto moderation rule](#DOCS_RESOURCES_AUTO_ ###### JSON Params | Field | Type | Description | -| ------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | +|---------------------|------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------| | name | string | the rule name | | event_type | integer | the [event type](#DOCS_RESOURCES_AUTO_MODERATION/auto-moderation-rule-object-event-types) | | trigger_metadata? * | object | the [trigger metadata](#DOCS_RESOURCES_AUTO_MODERATION/auto-moderation-rule-object-trigger-metadata) | diff --git a/docs/resources/Channel.md b/docs/resources/Channel.md index 3cbe1bd62e..7869a7a554 100644 --- a/docs/resources/Channel.md +++ b/docs/resources/Channel.md @@ -6,43 +6,43 @@ Represents a guild or DM channel within Discord. ###### Channel Structure -| Field | Type | Description | -| ----------------------------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| id | snowflake | the id of this channel | -| type | integer | the [type of channel](#DOCS_RESOURCES_CHANNEL/channel-object-channel-types) | -| guild_id? | snowflake | the id of the guild (may be missing for some channel objects received over gateway guild dispatches) | -| position? | integer | sorting position of the channel | -| permission_overwrites? | array of [overwrite](#DOCS_RESOURCES_CHANNEL/overwrite-object) objects | explicit permission overwrites for members and roles | -| name? | ?string | the name of the channel (1-100 characters) | -| topic? | ?string | the channel topic (0-4096 characters for `GUILD_FORUM` channels, 0-1024 characters for all others) | -| nsfw? | boolean | whether the channel is nsfw | -| last_message_id? | ?snowflake | the id of the last message sent in this channel (or thread for `GUILD_FORUM` channels) (may not point to an existing or valid message or thread) | -| bitrate? | integer | the bitrate (in bits) of the voice channel | -| user_limit? | integer | the user limit of the voice channel | -| rate_limit_per_user?\* | integer | amount of seconds a user has to wait before sending another message (0-21600); bots, as well as users with the permission `manage_messages` or `manage_channel`, are unaffected | -| recipients? | array of [user](#DOCS_RESOURCES_USER/user-object) objects | the recipients of the DM | -| icon? | ?string | icon hash of the group DM | -| owner_id? | snowflake | id of the creator of the group DM or thread | -| application_id? | snowflake | application id of the group DM creator if it is bot-created | -| managed? | boolean | for group DM channels: whether the channel is managed by an application via the `gdm.join` OAuth2 scope | -| parent_id? | ?snowflake | for guild channels: id of the parent category for a channel (each parent category can contain up to 50 channels), for threads: id of the text channel this thread was created | -| last_pin_timestamp? | ?ISO8601 timestamp | when the last pinned message was pinned. This may be `null` in events such as `GUILD_CREATE` when a message is not pinned. | -| rtc_region? | ?string | [voice region](#DOCS_RESOURCES_VOICE/voice-region-object) id for the voice channel, automatic when set to null | -| video_quality_mode? | integer | the camera [video quality mode](#DOCS_RESOURCES_CHANNEL/channel-object-video-quality-modes) of the voice channel, 1 when not present | -| message_count?\*\* | integer | number of messages (not including the initial message or deleted messages) in a thread. | -| member_count? | integer | an approximate count of users in a thread, stops counting at 50 | -| thread_metadata? | a [thread metadata](#DOCS_RESOURCES_CHANNEL/thread-metadata-object) object | thread-specific fields not needed by other channels | -| member? | a [thread member](#DOCS_RESOURCES_CHANNEL/thread-member-object) object | thread member object for the current user, if they have joined the thread, only included on certain API endpoints | -| default_auto_archive_duration? | integer | default duration, copied onto newly created threads, in minutes, threads will stop showing in the channel list after the specified period of inactivity, can be set to: 60, 1440, 4320, 10080 | -| permissions? | string | computed permissions for the invoking user in the channel, including overwrites, only included when part of the `resolved` data received on a slash command interaction | -| flags? | integer | [channel flags](#DOCS_RESOURCES_CHANNEL/channel-object-channel-flags) combined as a [bitfield](https://en.wikipedia.org/wiki/Bit_field) | -| total_message_sent? | integer | number of messages ever sent in a thread, it's similar to `message_count` on message creation, but will not decrement the number when a message is deleted | -| available_tags? | array of [tag](#DOCS_RESOURCES_CHANNEL/forum-tag-object) objects | the set of tags that can be used in a `GUILD_FORUM` channel | -| applied_tags? | array of snowflakes | the IDs of the set of tags that have been applied to a thread in a `GUILD_FORUM` channel | -| default_reaction_emoji? | ?[default reaction](#DOCS_RESOURCES_CHANNEL/default-reaction-object) object | the emoji to show in the add reaction button on a thread in a `GUILD_FORUM` channel | -| default_thread_rate_limit_per_user? | integer | the initial `rate_limit_per_user` to set on newly created threads in a channel. this field is copied to the thread at creation time and does not live update. | -| default_sort_order? | ?integer | the [default sort order type](#DOCS_RESOURCES_CHANNEL/channel-object-sort-order-types) used to order posts in `GUILD_FORUM` channels. Defaults to `null`, which indicates a preferred sort order hasn't been set by a channel admin | -| default_forum_layout? | integer | the [default forum layout view](#DOCS_RESOURCES_CHANNEL/channel-object-forum-layout-types) used to display posts in `GUILD_FORUM` channels. Defaults to `0`, which indicates a layout view has not been set by a channel admin | +| Field | Type | Description | +|-------------------------------------|-----------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| id | snowflake | the id of this channel | +| type | integer | the [type of channel](#DOCS_RESOURCES_CHANNEL/channel-object-channel-types) | +| guild_id? | snowflake | the id of the guild (may be missing for some channel objects received over gateway guild dispatches) | +| position? | integer | sorting position of the channel | +| permission_overwrites? | array of [overwrite](#DOCS_RESOURCES_CHANNEL/overwrite-object) objects | explicit permission overwrites for members and roles | +| name? | ?string | the name of the channel (1-100 characters) | +| topic? | ?string | the channel topic (0-4096 characters for `GUILD_FORUM` and `GUILD_MEDIA` channels, 0-1024 characters for all others) | +| nsfw? | boolean | whether the channel is nsfw | +| last_message_id? | ?snowflake | the id of the last message sent in this channel (or thread for `GUILD_FORUM` or `GUILD_MEDIA` channels) (may not point to an existing or valid message or thread) | +| bitrate? | integer | the bitrate (in bits) of the voice channel | +| user_limit? | integer | the user limit of the voice channel | +| rate_limit_per_user?\* | integer | amount of seconds a user has to wait before sending another message (0-21600); bots, as well as users with the permission `manage_messages` or `manage_channel`, are unaffected | +| recipients? | array of [user](#DOCS_RESOURCES_USER/user-object) objects | the recipients of the DM | +| icon? | ?string | icon hash of the group DM | +| owner_id? | snowflake | id of the creator of the group DM or thread | +| application_id? | snowflake | application id of the group DM creator if it is bot-created | +| managed? | boolean | for group DM channels: whether the channel is managed by an application via the `gdm.join` OAuth2 scope | +| parent_id? | ?snowflake | for guild channels: id of the parent category for a channel (each parent category can contain up to 50 channels), for threads: id of the text channel this thread was created | +| last_pin_timestamp? | ?ISO8601 timestamp | when the last pinned message was pinned. This may be `null` in events such as `GUILD_CREATE` when a message is not pinned. | +| rtc_region? | ?string | [voice region](#DOCS_RESOURCES_VOICE/voice-region-object) id for the voice channel, automatic when set to null | +| video_quality_mode? | integer | the camera [video quality mode](#DOCS_RESOURCES_CHANNEL/channel-object-video-quality-modes) of the voice channel, 1 when not present | +| message_count?\*\* | integer | number of messages (not including the initial message or deleted messages) in a thread. | +| member_count? | integer | an approximate count of users in a thread, stops counting at 50 | +| thread_metadata? | a [thread metadata](#DOCS_RESOURCES_CHANNEL/thread-metadata-object) object | thread-specific fields not needed by other channels | +| member? | a [thread member](#DOCS_RESOURCES_CHANNEL/thread-member-object) object | thread member object for the current user, if they have joined the thread, only included on certain API endpoints | +| default_auto_archive_duration? | integer | default duration, copied onto newly created threads, in minutes, threads will stop showing in the channel list after the specified period of inactivity, can be set to: 60, 1440, 4320, 10080 | +| permissions? | string | computed permissions for the invoking user in the channel, including overwrites, only included when part of the `resolved` data received on a slash command interaction. This does not include [implicit permissions](#DOCS_TOPICS_PERMISSIONS/implicit-permissions), which may need to be checked separately | +| flags? | integer | [channel flags](#DOCS_RESOURCES_CHANNEL/channel-object-channel-flags) combined as a [bitfield](https://en.wikipedia.org/wiki/Bit_field) | +| total_message_sent? | integer | number of messages ever sent in a thread, it's similar to `message_count` on message creation, but will not decrement the number when a message is deleted | +| available_tags? | array of [tag](#DOCS_RESOURCES_CHANNEL/forum-tag-object) objects | the set of tags that can be used in a `GUILD_FORUM` or a `GUILD_MEDIA` channel | +| applied_tags? | array of snowflakes | the IDs of the set of tags that have been applied to a thread in a `GUILD_FORUM` or a `GUILD_MEDIA` channel | +| default_reaction_emoji? | ?[default reaction](#DOCS_RESOURCES_CHANNEL/default-reaction-object) object | the emoji to show in the add reaction button on a thread in a `GUILD_FORUM` or a `GUILD_MEDIA` channel | +| default_thread_rate_limit_per_user? | integer | the initial `rate_limit_per_user` to set on newly created threads in a channel. this field is copied to the thread at creation time and does not live update. | +| default_sort_order? | ?integer | the [default sort order type](#DOCS_RESOURCES_CHANNEL/channel-object-sort-order-types) used to order posts in `GUILD_FORUM` and `GUILD_MEDIA` channels. Defaults to `null`, which indicates a preferred sort order hasn't been set by a channel admin | +| default_forum_layout? | integer | the [default forum layout view](#DOCS_RESOURCES_CHANNEL/channel-object-forum-layout-types) used to display posts in `GUILD_FORUM` channels. Defaults to `0`, which indicates a layout view has not been set by a channel admin | \* `rate_limit_per_user` also applies to thread creation. Users can send one message and create one thread during each `rate_limit_per_user` interval. @@ -53,49 +53,53 @@ Represents a guild or DM channel within Discord. > warn > Type 10, 11 and 12 are only available in API v9 and above. -| Type | ID | Description | -| ------------------- | --- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -| GUILD_TEXT | 0 | a text channel within a server | -| DM | 1 | a direct message between users | -| GUILD_VOICE | 2 | a voice channel within a server | -| GROUP_DM | 3 | a direct message between multiple users | -| GUILD_CATEGORY | 4 | an [organizational category](https://support.discord.com/hc/en-us/articles/115001580171-Channel-Categories-101) that contains up to 50 channels | -| GUILD_ANNOUNCEMENT | 5 | a channel that [users can follow and crosspost into their own server](https://support.discord.com/hc/en-us/articles/360032008192) (formerly news channels) | -| ANNOUNCEMENT_THREAD | 10 | a temporary sub-channel within a GUILD_ANNOUNCEMENT channel | -| PUBLIC_THREAD | 11 | a temporary sub-channel within a GUILD_TEXT or GUILD_FORUM channel | -| PRIVATE_THREAD | 12 | a temporary sub-channel within a GUILD_TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission | -| GUILD_STAGE_VOICE | 13 | a voice channel for [hosting events with an audience](https://support.discord.com/hc/en-us/articles/1500005513722) | -| GUILD_DIRECTORY | 14 | the channel in a [hub](https://support.discord.com/hc/en-us/articles/4406046651927-Discord-Student-Hubs-FAQ) containing the listed servers | -| GUILD_FORUM | 15 | Channel that can only contain threads | +| Type | ID | Description | +|---------------------|----|------------------------------------------------------------------------------------------------------------------------------------------------------------| +| GUILD_TEXT | 0 | a text channel within a server | +| DM | 1 | a direct message between users | +| GUILD_VOICE | 2 | a voice channel within a server | +| GROUP_DM | 3 | a direct message between multiple users | +| GUILD_CATEGORY | 4 | an [organizational category](https://support.discord.com/hc/en-us/articles/115001580171-Channel-Categories-101) that contains up to 50 channels | +| GUILD_ANNOUNCEMENT | 5 | a channel that [users can follow and crosspost into their own server](https://support.discord.com/hc/en-us/articles/360032008192) (formerly news channels) | +| ANNOUNCEMENT_THREAD | 10 | a temporary sub-channel within a GUILD_ANNOUNCEMENT channel | +| PUBLIC_THREAD | 11 | a temporary sub-channel within a GUILD_TEXT or GUILD_FORUM channel | +| PRIVATE_THREAD | 12 | a temporary sub-channel within a GUILD_TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission | +| GUILD_STAGE_VOICE | 13 | a voice channel for [hosting events with an audience](https://support.discord.com/hc/en-us/articles/1500005513722) | +| GUILD_DIRECTORY | 14 | the channel in a [hub](https://support.discord.com/hc/en-us/articles/4406046651927-Discord-Student-Hubs-FAQ) containing the listed servers | +| GUILD_FORUM | 15 | Channel that can only contain threads | +| GUILD_MEDIA | 16 | Channel that can only contain threads, similar to `GUILD_FORUM` channels | + +\* The `GUILD_MEDIA` channel type is still in active development. Avoid implementing any features that are not documented here, since they are subject to change without notice! ###### Video Quality Modes | Mode | Value | Description | -| ---- | ----- | --------------------------------------------------- | +|------|-------|-----------------------------------------------------| | AUTO | 1 | Discord chooses the quality for optimal performance | | FULL | 2 | 720p | ###### Channel Flags -| Flag | Value | Description | -| ----------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------- | -| PINNED | 1 << 1 | this thread is pinned to the top of its parent `GUILD_FORUM` channel | -| REQUIRE_TAG | 1 << 4 | whether a tag is required to be specified when creating a thread in a `GUILD_FORUM` channel. Tags are specified in the `applied_tags` field. | +| Flag | Value | Description | +|-----------------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| PINNED | 1 << 1 | this thread is pinned to the top of its parent `GUILD_FORUM` or `GUILD_MEDIA` channel | +| REQUIRE_TAG | 1 << 4 | whether a tag is required to be specified when creating a thread in a `GUILD_FORUM` or a `GUILD_MEDIA` channel. Tags are specified in the `applied_tags` field. | +| HIDE_MEDIA_DOWNLOAD_OPTIONS | 1 << 15 | when set hides the embedded media download options. Available only for media channels | ###### Sort Order Types | Flag | Value | Description | -| --------------- | ----- | -------------------------------------------------------------- | +|-----------------|-------|----------------------------------------------------------------| | LATEST_ACTIVITY | 0 | Sort forum posts by activity | | CREATION_DATE | 1 | Sort forum posts by creation time (from most recent to oldest) | ###### Forum Layout Types -| Flag | Value | Description | -| --------------- | ----- | -------------------------------------------------------------- | -| NOT_SET | 0 | No default has been set for forum channel | -| LIST_VIEW | 1 | Display posts as a list | -| GALLERY_VIEW | 2 | Display posts as a collection of tiles | +| Flag | Value | Description | +|--------------|-------|-------------------------------------------| +| NOT_SET | 0 | No default has been set for forum channel | +| LIST_VIEW | 1 | Display posts as a list | +| GALLERY_VIEW | 2 | Display posts as a collection of tiles | ###### Example Guild Text Channel @@ -263,7 +267,7 @@ Represents a message sent in a channel within Discord. > `content`, `embeds`, `attachments`, and `components` require the [`MESSAGE_CONTENT` intent](#DOCS_TOPICS_GATEWAY/message-content-intent) to receive non-empty values. | Field | Type | Description | -| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------|------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | id | snowflake | id of the message | | channel_id | snowflake | id of the channel the message was sent in | | author\* | [user](#DOCS_RESOURCES_USER/user-object) object | the author of this message (not guaranteed to be a valid user, see below) | @@ -295,6 +299,8 @@ Represents a message sent in a channel within Discord. | stickers? | array of [sticker](#DOCS_RESOURCES_STICKER/sticker-object) objects | **Deprecated** the stickers sent with the message | | position? | integer | A generally increasing integer (there may be gaps or duplicates) that represents the approximate position of the message in a thread, it can be used to estimate the relative position of the message in a thread in company with `total_message_sent` on parent thread | | role_subscription_data? | [role subscription data](#DOCS_RESOURCES_CHANNEL/role-subscription-data-object) object | data of the role subscription purchase or renewal that prompted this ROLE_SUBSCRIPTION_PURCHASE message | +| resolved? | [resolved](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-resolved-data-structure) data | data for users, members, channels, and roles in the message's [auto-populated select menus](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menus) | + \* The author object follows the structure of the user object, but is only a valid user in the case where the message is generated by a user or bot user. If the message is generated by a webhook, the author object corresponds to the webhook's id, username, and avatar. You can tell if a message is generated by a webhook by checking for the `webhook_id` on the message object. @@ -349,14 +355,14 @@ Represents a message sent in a channel within Discord. ###### Message Activity Structure | Field | Type | Description | -| --------- | ------- | ------------------------------------------------------------------------------------------------------------------ | +|-----------|---------|--------------------------------------------------------------------------------------------------------------------| | type | integer | [type of message activity](#DOCS_RESOURCES_CHANNEL/message-object-message-activity-types) | | party_id? | string | party_id from a [Rich Presence event](#DOCS_RICH_PRESENCE_HOW_TO/updating-presence-update-presence-payload-fields) | ###### Message Activity Types | Type | Value | -| ------------ | ----- | +|--------------|-------| | JOIN | 1 | | SPECTATE | 2 | | LISTEN | 3 | @@ -365,7 +371,7 @@ Represents a message sent in a channel within Discord. ###### Message Flags | Flag | Value | Description | -| -------------------------------------- | ------ | --------------------------------------------------------------------------------- | +|----------------------------------------|---------|-----------------------------------------------------------------------------------| | CROSSPOSTED | 1 << 0 | this message has been published to subscribed channels (via Channel Following) | | IS_CROSSPOST | 1 << 1 | this message originated from a message in another channel (via Channel Following) | | SUPPRESS_EMBEDS | 1 << 2 | do not include any embeds when serializing this message | @@ -385,11 +391,16 @@ Represents a message sent in a channel within Discord. "reactions": [ { "count": 1, + "count_details": { + "burst": 0, + "normal": 1 + }, "me": false, "emoji": { - "id": null, - "name": "🔥" - } + "id": null, + "name": "🔥" + }, + "burst_colors": [] } ], "attachments": [], @@ -421,11 +432,17 @@ Represents a message sent in a channel within Discord. "reactions": [ { "count": 1, + "count_details": { + "burst": 0, + "normal": 1 + }, "me": false, + "me_burst": false, "emoji": { - "id": null, - "name": "🔥" - } + "id": null, + "name": "🔥" + }, + "burst_colors": [] } ], "attachments": [], @@ -469,7 +486,7 @@ Represents a message sent in a channel within Discord. ###### Message Reference Structure | Field | Type | Description | -| ------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------- | +|---------------------|-----------|-----------------------------------------------------------------------------------------------------------------------------------------| | message_id? | snowflake | id of the originating message | | channel_id? \* | snowflake | id of the originating message's channel | | guild_id? | snowflake | id of the originating message's guild | @@ -532,7 +549,7 @@ The encoding, and the waveform details, are an implementation detail and may cha ###### Followed Channel Structure | Field | Type | Description | -| ---------- | --------- | ------------------------- | +|------------|-----------|---------------------------| | channel_id | snowflake | source channel id | | webhook_id | snowflake | created target webhook id | @@ -540,11 +557,25 @@ The encoding, and the waveform details, are an implementation detail and may cha ###### Reaction Structure -| Field | Type | Description | -| ----- | ---------------------------------------------------------- | ------------------------------------------------- | -| count | integer | times this emoji has been used to react | -| me | boolean | whether the current user reacted using this emoji | -| emoji | partial [emoji](#DOCS_RESOURCES_EMOJI/emoji-object) object | emoji information | +| Field | Type | Description | +|---------------|------------------------------------------------------------|----------------------------------------------------------------------------------------| +| count | integer | Total number of times this emoji has been used to react (including super reacts) | +| count_details | object | [Reaction count details object](#DOCS_RESOURCES_CHANNEL/reaction-count-details-object) | +| me | boolean | Whether the current user reacted using this emoji | +| me_burst | boolean | Whether the current user super-reacted using this emoji | +| emoji | partial [emoji](#DOCS_RESOURCES_EMOJI/emoji-object) object | emoji information | +| burst_colors | array | HEX colors used for super reaction | + +### Reaction Count Details Object + +The reaction count details object contains a breakdown of normal and super reaction counts for the associated emoji. + +###### Reaction Count Details Structure + +| Field | Type | Description | +|--------|---------|---------------------------| +| burst | integer | Count of super reactions | +| normal | integer | Count of normal reactions | ### Overwrite Object @@ -553,7 +584,7 @@ See [permissions](#DOCS_TOPICS_PERMISSIONS/permissions) for more information abo ###### Overwrite Structure | Field | Type | Description | -| ----- | --------- | ----------------------------- | +|-------|-----------|-------------------------------| | id | snowflake | role or user id | | type | int | either 0 (role) or 1 (member) | | allow | string | permission bit set | @@ -569,7 +600,7 @@ The thread metadata object contains a number of thread-specific channel fields t > Starting on March 6, threads will be able to be locked and archived independently. Read details about the upcoming changes to the `locked` field in the [Change Log entry](#DOCS_CHANGE_LOG/update-to-locked-threads). | Field | Type | Description | -| --------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | +|-----------------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------| | archived | boolean | whether the thread is archived | | auto_archive_duration | integer | the thread will stop showing in the channel list after `auto_archive_duration` minutes of inactivity, can be set to: 60, 1440, 4320, 10080 | | archive_timestamp | ISO8601 timestamp | timestamp when the thread's archive status was last changed, used for calculating recent activity | @@ -584,7 +615,7 @@ A thread member object contains information about a user that has joined a threa ###### Thread Member Structure | Field | Type | Description | -| --------------- | ---------------------------------------------------------------- | --------------------------------------------------------------- | +|-----------------|------------------------------------------------------------------|-----------------------------------------------------------------| | id? \* | snowflake | ID of the thread | | user_id? \* | snowflake | ID of the user | | join_timestamp | ISO8601 timestamp | Time the user last joined the thread | @@ -602,21 +633,21 @@ An object that specifies the emoji to use as the default way to react to a forum ###### Default Reaction Structure | Field | Type | Description | -| ---------- | ---------- | ---------------------------------- | +|------------|------------|------------------------------------| | emoji_id | ?snowflake | the id of a guild's custom emoji | | emoji_name | ?string | the unicode character of the emoji | ### Forum Tag Object -An object that represents a tag that is able to be applied to a thread in a `GUILD_FORUM` channel. +An object that represents a tag that is able to be applied to a thread in a `GUILD_FORUM` or `GUILD_MEDIA` channel. ###### Forum Tag Structure > info -> When updating a `GUILD_FORUM` channel, tag objects in `available_tags` only require the `name` field. +> When updating a `GUILD_FORUM` or a `GUILD_MEDIA` channel, tag objects in `available_tags` only require the `name` field. | Field | Type | Description | -| ---------- | ---------- | -------------------------------------------------------------------------------------------------------------- | +|------------|------------|----------------------------------------------------------------------------------------------------------------| | id | snowflake | the id of the tag | | name | string | the name of the tag (0-20 characters) | | moderated | boolean | whether this tag can only be added to or removed from threads by a member with the `MANAGE_THREADS` permission | @@ -630,7 +661,7 @@ An object that represents a tag that is able to be applied to a thread in a `GUI ###### Embed Structure | Field | Type | Description | -| ------------ | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | +|--------------|--------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------| | title? | string | title of embed | | type? | string | [type of embed](#DOCS_RESOURCES_CHANNEL/embed-object-embed-types) (always "rich" for webhook embeds) | | description? | string | description of embed | @@ -650,7 +681,7 @@ An object that represents a tag that is able to be applied to a thread in a `GUI Embed types are "loosely defined" and, for the most part, are not used by our clients for rendering. Embed attributes power what is rendered. Embed types should be considered deprecated and might be removed in a future API version. | Type | Description | -| ------- | -------------------------------------------------- | +|---------|----------------------------------------------------| | rich | generic embed rendered from embed attributes | | image | image embed | | video | video embed | @@ -661,7 +692,7 @@ Embed types are "loosely defined" and, for the most part, are not used by our cl ###### Embed Thumbnail Structure | Field | Type | Description | -| ---------- | ------- | --------------------------------------------------------------- | +|------------|---------|-----------------------------------------------------------------| | url | string | source url of thumbnail (only supports http(s) and attachments) | | proxy_url? | string | a proxied url of the thumbnail | | height? | integer | height of thumbnail | @@ -670,7 +701,7 @@ Embed types are "loosely defined" and, for the most part, are not used by our cl ###### Embed Video Structure | Field | Type | Description | -| ---------- | ------- | -------------------------- | +|------------|---------|----------------------------| | url? | string | source url of video | | proxy_url? | string | a proxied url of the video | | height? | integer | height of video | @@ -679,7 +710,7 @@ Embed types are "loosely defined" and, for the most part, are not used by our cl ###### Embed Image Structure | Field | Type | Description | -| ---------- | ------- | ----------------------------------------------------------- | +|------------|---------|-------------------------------------------------------------| | url | string | source url of image (only supports http(s) and attachments) | | proxy_url? | string | a proxied url of the image | | height? | integer | height of image | @@ -688,14 +719,14 @@ Embed types are "loosely defined" and, for the most part, are not used by our cl ###### Embed Provider Structure | Field | Type | Description | -| ----- | ------ | ---------------- | +|-------|--------|------------------| | name? | string | name of provider | | url? | string | url of provider | ###### Embed Author Structure | Field | Type | Description | -| --------------- | ------ | ---------------------------------------------------------- | +|-----------------|--------|------------------------------------------------------------| | name | string | name of author | | url? | string | url of author (only supports http(s)) | | icon_url? | string | url of author icon (only supports http(s) and attachments) | @@ -704,7 +735,7 @@ Embed types are "loosely defined" and, for the most part, are not used by our cl ###### Embed Footer Structure | Field | Type | Description | -| --------------- | ------ | ---------------------------------------------------------- | +|-----------------|--------|------------------------------------------------------------| | text | string | footer text | | icon_url? | string | url of footer icon (only supports http(s) and attachments) | | proxy_icon_url? | string | a proxied url of footer icon | @@ -712,7 +743,7 @@ Embed types are "loosely defined" and, for the most part, are not used by our cl ###### Embed Field Structure | Field | Type | Description | -| ------- | ------- | ----------------------------------------------- | +|---------|---------|-------------------------------------------------| | name | string | name of the field | | value | string | value of the field | | inline? | boolean | whether or not this field should display inline | @@ -724,7 +755,7 @@ To facilitate showing rich content, rich embeds do not follow the traditional li All of the following limits are measured inclusively. Leading and trailing whitespace characters are not included (they are trimmed automatically). | Field | Limit | -| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | +|----------------------------------------------------------------------------|--------------------------------------------------------------------------------------| | title | 256 characters | | description | 4096 characters | | fields | Up to 25 [field](#DOCS_RESOURCES_CHANNEL/embed-object-embed-field-structure) objects | @@ -744,20 +775,20 @@ Embeds are deduplicated by URL. If a message contains multiple embeds with the > info > For the `attachments` array in Message Create/Edit requests, only the `id` is required. -| Field | Type | Description | -| -------------- | --------- | --------------------------------------------------------------------------------------- | -| id | snowflake | attachment id | -| filename | string | name of file attached | -| description? | string | description for the file (max 1024 characters) | -| content_type? | string | the attachment's [media type](https://en.wikipedia.org/wiki/Media_type) | -| size | integer | size of file in bytes | -| url | string | source url of file | -| proxy_url | string | a proxied url of file | -| height? | ?integer | height of file (if image) | -| width? | ?integer | width of file (if image) | -| ephemeral? \* | boolean | whether this attachment is ephemeral | -| duration_secs? | float | the duration of the audio file (currently for voice messages) | -| waveform? | string | base64 encoded bytearray representing a sampled waveform (currently for voice messages) | +| Field | Type | Description | +|----------------|-----------|--------------------------------------------------------------------------------------------------------------------------------------------------| +| id | snowflake | attachment id | +| filename | string | name of file attached | +| description? | string | description for the file (max 1024 characters) | +| content_type? | string | the attachment's [media type](https://en.wikipedia.org/wiki/Media_type) | +| size | integer | size of file in bytes | +| url | string | source url of file | +| proxy_url | string | a proxied url of file | +| height? | ?integer | height of file (if image) | +| width? | ?integer | width of file (if image) | +| ephemeral? \* | boolean | whether this attachment is ephemeral | +| duration_secs? | float | the duration of the audio file (currently for voice messages) | +| waveform? | string | base64 encoded bytearray representing a sampled waveform (currently for voice messages) | | flags? | integer | [attachment flags](#DOCS_RESOURCES_CHANNEL/attachment-object-attachment-flags) combined as a [bitfield](https://en.wikipedia.org/wiki/Bit_field) | \* Ephemeral attachments will automatically be removed after a set period of time. Ephemeral attachments on messages are guaranteed to be available as long as the message itself exists. @@ -765,7 +796,7 @@ Embeds are deduplicated by URL. If a message contains multiple embeds with the ###### Attachment Flags | Flag | Value | Description | -| -------- | ------ | ----------------------------------------------------------------- | +|----------|--------|-------------------------------------------------------------------| | IS_REMIX | 1 << 2 | this attachment has been edited using the remix feature on mobile | ### Channel Mention Object @@ -773,7 +804,7 @@ Embeds are deduplicated by URL. If a message contains multiple embeds with the ###### Channel Mention Structure | Field | Type | Description | -| -------- | --------- | --------------------------------------------------------------------------- | +|----------|-----------|-----------------------------------------------------------------------------| | id | snowflake | id of the channel | | guild_id | snowflake | id of the guild containing the channel | | type | integer | the [type of channel](#DOCS_RESOURCES_CHANNEL/channel-object-channel-types) | @@ -786,7 +817,7 @@ The allowed mention field allows for more granular control over mentions without ###### Allowed Mention Types | Type | Value | Description | -| ----------------- | ---------- | ------------------------------------- | +|-------------------|------------|---------------------------------------| | Role Mentions | "roles" | Controls role mentions | | User Mentions | "users" | Controls user mentions | | Everyone Mentions | "everyone" | Controls @everyone and @here mentions | @@ -794,7 +825,7 @@ The allowed mention field allows for more granular control over mentions without ###### Allowed Mentions Structure | Field | Type | Description | -| ------------ | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- | +|--------------|--------------------------------|---------------------------------------------------------------------------------------------------------------------------------------| | parse | array of allowed mention types | An array of [allowed mention types](#DOCS_RESOURCES_CHANNEL/allowed-mentions-object-allowed-mention-types) to parse from the content. | | roles | list of snowflakes | Array of role_ids to mention (Max size of 100) | | users | list of snowflakes | Array of user_ids to mention (Max size of 100) | @@ -885,7 +916,7 @@ user 125 in the content. ###### Role Subscription Data Object Structure | Field | Type | Description | -| ---------------------------- | --------- | --------------------------------------------------------------------- | +|------------------------------|-----------|-----------------------------------------------------------------------| | role_subscription_listing_id | snowflake | the id of the sku and listing that the user is subscribed to | | tier_name | string | the name of the tier that the user is subscribed to | | total_months_subscribed | integer | the cumulative number of months that the user has been subscribed for | @@ -907,7 +938,7 @@ Update a channel's settings. Returns a [channel](#DOCS_RESOURCES_CHANNEL/channel Fires a [Channel Update](#DOCS_TOPICS_GATEWAY_EVENTS/channel-update) Gateway event. | Field | Type | Description | -| ----- | ------ | ---------------------------- | +|-------|--------|------------------------------| | name | string | 1-100 character channel name | | icon | binary | base64 encoded icon | @@ -915,27 +946,27 @@ Fires a [Channel Update](#DOCS_TOPICS_GATEWAY_EVENTS/channel-update) Gateway eve Requires the `MANAGE_CHANNELS` permission for the guild. Fires a [Channel Update](#DOCS_TOPICS_GATEWAY_EVENTS/channel-update) Gateway event. If modifying a category, individual [Channel Update](#DOCS_TOPICS_GATEWAY_EVENTS/channel-update) events will fire for each child channel that also changes. If modifying permission overwrites, the `MANAGE_ROLES` permission is required. Only permissions your bot has in the guild or parent channel (if applicable) can be allowed/denied (unless your bot has a `MANAGE_ROLES` overwrite in the channel). -| Field | Type | Description | Channel Type | -| ----------------------------------- | ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | -| name | string | 1-100 character channel name | All | -| type | integer | the [type of channel](#DOCS_RESOURCES_CHANNEL/channel-object-channel-types); only conversion between text and announcement is supported and only in guilds with the "NEWS" feature | Text, Announcement | -| position | ?integer | the position of the channel in the left-hand listing | All | -| topic | ?string | 0-1024 character channel topic (0-4096 characters for `GUILD_FORUM` channels) | Text, Announcement, Forum | -| nsfw | ?boolean | whether the channel is nsfw | Text, Voice, Announcement, Stage, Forum | -| rate_limit_per_user | ?integer | amount of seconds a user has to wait before sending another message (0-21600); bots, as well as users with the permission `manage_messages` or `manage_channel`, are unaffected | Text, Voice, Stage, Forum | -| bitrate\* | ?integer | the bitrate (in bits) of the voice or stage channel; min 8000 | Voice, Stage | -| user_limit | ?integer | the user limit of the voice or stage channel, max 99 for voice channels and 10,000 for stage channels (0 refers to no limit) | Voice, Stage | -| permission_overwrites\*\* | ?array of partial [overwrite](#DOCS_RESOURCES_CHANNEL/overwrite-object) objects | channel or category-specific permissions | All | -| parent_id | ?snowflake | id of the new parent category for a channel | Text, Voice, Announcement, Stage, Forum | -| rtc_region | ?string | channel [voice region](#DOCS_RESOURCES_VOICE/voice-region-object) id, automatic when set to null | Voice, Stage | -| video_quality_mode | ?integer | the camera [video quality mode](#DOCS_RESOURCES_CHANNEL/channel-object-video-quality-modes) of the voice channel | Voice, Stage | -| default_auto_archive_duration | ?integer | the default duration that the clients use (not the API) for newly created threads in the channel, in minutes, to automatically archive the thread after recent activity | Text, Announcement, Forum | -| flags? | integer | [channel flags](#DOCS_RESOURCES_CHANNEL/channel-object-channel-flags) combined as a [bitfield](https://en.wikipedia.org/wiki/Bit_field). Currently only `REQUIRE_TAG` (`1 << 4`) is supported. | Forum | -| available_tags? | array of [tag](#DOCS_RESOURCES_CHANNEL/forum-tag-object) objects | the set of tags that can be used in a `GUILD_FORUM` channel; limited to 20 | Forum | -| default_reaction_emoji? | ?[default reaction](#DOCS_RESOURCES_CHANNEL/default-reaction-object) object | the emoji to show in the add reaction button on a thread in a `GUILD_FORUM` channel | Forum | -| default_thread_rate_limit_per_user? | integer | the initial `rate_limit_per_user` to set on newly created threads in a channel. this field is copied to the thread at creation time and does not live update. | Text, Forum | -| default_sort_order? | ?integer | the [default sort order type](#DOCS_RESOURCES_CHANNEL/channel-object-sort-order-types) used to order posts in `GUILD_FORUM` channels | Forum | -| default_forum_layout? | integer | the [default forum layout type](#DOCS_RESOURCES_CHANNEL/channel-object-forum-layout-types) used to display posts in `GUILD_FORUM` channels | Forum | +| Field | Type | Description | Channel Type | +|-------------------------------------|---------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------| +| name | string | 1-100 character channel name | All | +| type | integer | the [type of channel](#DOCS_RESOURCES_CHANNEL/channel-object-channel-types); only conversion between text and announcement is supported and only in guilds with the "NEWS" feature | Text, Announcement | +| position | ?integer | the position of the channel in the left-hand listing | All | +| topic | ?string | 0-1024 character channel topic (0-4096 characters for `GUILD_FORUM` and `GUILD_MEDIA` channels) | Text, Announcement, Forum, Media | +| nsfw | ?boolean | whether the channel is nsfw | Text, Voice, Announcement, Stage, Forum, Media | +| rate_limit_per_user | ?integer | amount of seconds a user has to wait before sending another message (0-21600); bots, as well as users with the permission `manage_messages` or `manage_channel`, are unaffected | Text, Voice, Stage, Forum, Media | +| bitrate\* | ?integer | the bitrate (in bits) of the voice or stage channel; min 8000 | Voice, Stage | +| user_limit | ?integer | the user limit of the voice or stage channel, max 99 for voice channels and 10,000 for stage channels (0 refers to no limit) | Voice, Stage | +| permission_overwrites\*\* | ?array of partial [overwrite](#DOCS_RESOURCES_CHANNEL/overwrite-object) objects | channel or category-specific permissions | All | +| parent_id | ?snowflake | id of the new parent category for a channel | Text, Voice, Announcement, Stage, Forum, Media | +| rtc_region | ?string | channel [voice region](#DOCS_RESOURCES_VOICE/voice-region-object) id, automatic when set to null | Voice, Stage | +| video_quality_mode | ?integer | the camera [video quality mode](#DOCS_RESOURCES_CHANNEL/channel-object-video-quality-modes) of the voice channel | Voice, Stage | +| default_auto_archive_duration | ?integer | the default duration that the clients use (not the API) for newly created threads in the channel, in minutes, to automatically archive the thread after recent activity | Text, Announcement, Forum, Media | +| flags? | integer | [channel flags](#DOCS_RESOURCES_CHANNEL/channel-object-channel-flags) combined as a [bitfield](https://en.wikipedia.org/wiki/Bit_field). Currently only `REQUIRE_TAG` (`1 << 4`) is supported by `GUILD_FORUM` and `GUILD_MEDIA` channels. `HIDE_MEDIA_DOWNLOAD_OPTIONS` (`1 << 15`) is supported only by `GUILD_MEDIA` channels | Forum, Media | +| available_tags? | array of [tag](#DOCS_RESOURCES_CHANNEL/forum-tag-object) objects | the set of tags that can be used in a `GUILD_FORUM` or a `GUILD_MEDIA` channel; limited to 20 | Forum, Media | +| default_reaction_emoji? | ?[default reaction](#DOCS_RESOURCES_CHANNEL/default-reaction-object) object | the emoji to show in the add reaction button on a thread in a `GUILD_FORUM` or a `GUILD_MEDIA` channel | Forum, Media | +| default_thread_rate_limit_per_user? | integer | the initial `rate_limit_per_user` to set on newly created threads in a channel. this field is copied to the thread at creation time and does not live update. | Text, Forum, Media | +| default_sort_order? | ?integer | the [default sort order type](#DOCS_RESOURCES_CHANNEL/channel-object-sort-order-types) used to order posts in `GUILD_FORUM` and `GUILD_MEDIA` channels | Forum, Media | +| default_forum_layout? | integer | the [default forum layout type](#DOCS_RESOURCES_CHANNEL/channel-object-forum-layout-types) used to display posts in `GUILD_FORUM` channels | Forum | \* For voice channels, normal servers can set bitrate up to 96000, servers with Boost level 1 can set up to 128000, servers with Boost level 2 can set up to 256000, and servers with Boost level 3 or the `VIP_REGIONS` [guild feature](#DOCS_RESOURCES_GUILD/guild-object-guild-features) can set up to 384000. For stage channels, bitrate can be set up to 64000. @@ -947,16 +978,16 @@ When setting `archived` to `false`, when `locked` is also `false`, only the `SEN Otherwise, requires the `MANAGE_THREADS` permission. Fires a [Thread Update](#DOCS_TOPICS_GATEWAY_EVENTS/thread-update) Gateway event. Requires the thread to have `archived` set to `false` or be set to `false` in the request. -| Field | Type | Description | -| --------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| name | string | 1-100 character channel name | -| archived | boolean | whether the thread is archived | -| auto_archive_duration | integer | the thread will stop showing in the channel list after `auto_archive_duration` minutes of inactivity, can be set to: 60, 1440, 4320, 10080 | -| locked | boolean | whether the thread is locked; when a thread is locked, only users with MANAGE_THREADS can unarchive it | -| invitable | boolean | whether non-moderators can add other non-moderators to a thread; only available on private threads | -| rate_limit_per_user | ?integer | amount of seconds a user has to wait before sending another message (0-21600); bots, as well as users with the permission `manage_messages`, `manage_thread`, or `manage_channel`, are unaffected | -| flags? | integer | [channel flags](#DOCS_RESOURCES_CHANNEL/channel-object-channel-flags) combined as a [bitfield](https://en.wikipedia.org/wiki/Bit_field); `PINNED` can only be set for threads in forum channels | -| applied_tags? | array of snowflakes | the IDs of the set of tags that have been applied to a thread in a `GUILD_FORUM` channel; limited to 5 | +| Field | Type | Description | +|-----------------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| name | string | 1-100 character channel name | +| archived | boolean | whether the thread is archived | +| auto_archive_duration | integer | the thread will stop showing in the channel list after `auto_archive_duration` minutes of inactivity, can be set to: 60, 1440, 4320, 10080 | +| locked | boolean | whether the thread is locked; when a thread is locked, only users with MANAGE_THREADS can unarchive it | +| invitable | boolean | whether non-moderators can add other non-moderators to a thread; only available on private threads | +| rate_limit_per_user | ?integer | amount of seconds a user has to wait before sending another message (0-21600); bots, as well as users with the permission `manage_messages`, `manage_thread`, or `manage_channel`, are unaffected | +| flags? | integer | [channel flags](#DOCS_RESOURCES_CHANNEL/channel-object-channel-flags) combined as a [bitfield](https://en.wikipedia.org/wiki/Bit_field); `PINNED` can only be set for threads in forum and media channels | +| applied_tags? | array of snowflakes | the IDs of the set of tags that have been applied to a thread in a `GUILD_FORUM` or a `GUILD_MEDIA` channel; limited to 5 | ## Delete/Close Channel % DELETE /channels/{channel.id#DOCS_RESOURCES_CHANNEL/channel-object} @@ -985,7 +1016,7 @@ If the current user is missing the `READ_MESSAGE_HISTORY` permission in the chan ###### Query String Params | Field | Type | Description | Default | -| ------- | --------- | ---------------------------------------- | ------- | +|---------|-----------|------------------------------------------|---------| | around? | snowflake | Get messages around this message ID | absent | | before? | snowflake | Get messages before this message ID | absent | | after? | snowflake | Get messages after this message ID | absent | @@ -1022,19 +1053,19 @@ Files must be attached using a `multipart/form-data` body as described in [Uploa > info > When creating a message, apps must provide a value for **at least one of** `content`, `embeds`, `sticker_ids`, `components`, or `files[n]`. -| Field | Type | Description | -| ------------------ | ------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| content?\* | string | Message contents (up to 2000 characters) | -| nonce? | integer or string | Can be used to verify a message was sent (up to 25 characters). Value will appear in the [Message Create event](#DOCS_TOPICS_GATEWAY_EVENTS/message-create). | -| tts? | boolean | `true` if this is a TTS message | -| embeds?\* | array of [embed](#DOCS_RESOURCES_CHANNEL/embed-object) objects | Up to 10 `rich` embeds (up to 6000 characters) | -| allowed_mentions? | [allowed mention object](#DOCS_RESOURCES_CHANNEL/allowed-mentions-object) | Allowed mentions for the message | -| message_reference? | [message reference](#DOCS_RESOURCES_CHANNEL/message-reference-object-message-reference-structure) | Include to make your message a reply | -| components?\* | array of [message component](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/component-object) objects | Components to include with the message | -| sticker_ids?\* | array of snowflakes | IDs of up to 3 [stickers](#DOCS_RESOURCES_STICKER/sticker-object) in the server to send in the message | -| files[n]?\* | file contents | Contents of the file being sent. See [Uploading Files](#DOCS_REFERENCE/uploading-files) | -| payload_json? | string | JSON-encoded body of non-file params, only for `multipart/form-data` requests. See [Uploading Files](#DOCS_REFERENCE/uploading-files) | -| attachments? | array of partial [attachment](#DOCS_RESOURCES_CHANNEL/attachment-object) objects | Attachment objects with filename and description. See [Uploading Files](#DOCS_REFERENCE/uploading-files) | +| Field | Type | Description | +|--------------------|---------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| content?\* | string | Message contents (up to 2000 characters) | +| nonce? | integer or string | Can be used to verify a message was sent (up to 25 characters). Value will appear in the [Message Create event](#DOCS_TOPICS_GATEWAY_EVENTS/message-create). | +| tts? | boolean | `true` if this is a TTS message | +| embeds?\* | array of [embed](#DOCS_RESOURCES_CHANNEL/embed-object) objects | Up to 10 `rich` embeds (up to 6000 characters) | +| allowed_mentions? | [allowed mention object](#DOCS_RESOURCES_CHANNEL/allowed-mentions-object) | Allowed mentions for the message | +| message_reference? | [message reference](#DOCS_RESOURCES_CHANNEL/message-reference-object-message-reference-structure) | Include to make your message a reply | +| components?\* | array of [message component](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/component-object) objects | Components to include with the message | +| sticker_ids?\* | array of snowflakes | IDs of up to 3 [stickers](#DOCS_RESOURCES_STICKER/sticker-object) in the server to send in the message | +| files[n]?\* | file contents | Contents of the file being sent. See [Uploading Files](#DOCS_REFERENCE/uploading-files) | +| payload_json? | string | JSON-encoded body of non-file params, only for `multipart/form-data` requests. See [Uploading Files](#DOCS_REFERENCE/uploading-files) | +| attachments? | array of partial [attachment](#DOCS_RESOURCES_CHANNEL/attachment-object) objects | Attachment objects with filename and description. See [Uploading Files](#DOCS_REFERENCE/uploading-files) | | flags? | integer | [Message flags](#DOCS_RESOURCES_CHANNEL/message-object-message-flags) combined as a [bitfield](https://en.wikipedia.org/wiki/Bit_field) (only `SUPPRESS_EMBEDS` and `SUPPRESS_NOTIFICATIONS` can be set) | \* At least one of `content`, `embeds`, `sticker_ids`, `components`, or `files[n]` is required. @@ -1083,7 +1114,7 @@ The `emoji` must be [URL Encoded](https://en.wikipedia.org/wiki/Percent-encoding ###### Query String Params | Field | Type | Description | Default | -| ------ | --------- | ------------------------------------- | ------- | +|--------|-----------|---------------------------------------|---------| | after? | snowflake | Get users after this user ID | absent | | limit? | integer | Max number of users to return (1-100) | 25 | @@ -1116,7 +1147,7 @@ Any provided files will be **appended** to the message. To remove or replace fil ###### JSON/Form Params | Field | Type | Description | -| ---------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- | +|------------------|--------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| | content | string | Message contents (up to 2000 characters) | | embeds | array of [embed](#DOCS_RESOURCES_CHANNEL/embed-object) objects | Up to 10 `rich` embeds (up to 6000 characters) | | flags | integer | Edit the [flags](#DOCS_RESOURCES_CHANNEL/message-object-message-flags) of a message (only `SUPPRESS_EMBEDS` can currently be set/unset) | @@ -1148,7 +1179,7 @@ Any message IDs given that do not exist or are invalid will count towards the mi ###### JSON Params | Field | Type | Description | -| -------- | ------------------- | ----------------------------------------- | +|----------|---------------------|-------------------------------------------| | messages | array of snowflakes | an array of message ids to delete (2-100) | ## Edit Channel Permissions % PUT /channels/{channel.id#DOCS_RESOURCES_CHANNEL/channel-object}/permissions/{overwrite.id#DOCS_RESOURCES_CHANNEL/overwrite-object} @@ -1161,7 +1192,7 @@ Edit the channel permission overwrites for a user or role in a channel. Only usa ###### JSON Params | Field | Type | Description | -| ------ | ------- | --------------------------------------------------------------- | +|--------|---------|-----------------------------------------------------------------| | allow? | string? | the bitwise value of all allowed permissions (default `"0"`) | | deny? | string? | the bitwise value of all disallowed permissions (default `"0"`) | | type | integer | 0 for a role or 1 for a member | @@ -1180,7 +1211,7 @@ Create a new [invite](#DOCS_RESOURCES_INVITE/invite-object) object for the chann ###### JSON Params | Field | Type | Description | Default | -| --------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | +|-----------------------|-----------|-------------------------------------------------------------------------------------------------------------------------------------------|------------------| | max_age | integer | duration of invite in seconds before expiry, or 0 for never. between 0 and 604800 (7 days) | 86400 (24 hours) | | max_uses | integer | max number of uses or 0 for unlimited. between 0 and 100 | 0 | | temporary | boolean | whether this invite only grants temporary membership | false | @@ -1203,12 +1234,14 @@ Follow an Announcement Channel to send messages to a target channel. Requires th ###### JSON Params | Field | Type | Description | -| ------------------ | --------- | -------------------- | +|--------------------|-----------|----------------------| | webhook_channel_id | snowflake | id of target channel | ## Trigger Typing Indicator % POST /channels/{channel.id#DOCS_RESOURCES_CHANNEL/channel-object}/typing -Post a typing indicator for the specified channel. Generally bots should **not** implement this route. However, if a bot is responding to a command and expects the computation to take a few seconds, this endpoint may be called to let the user know that the bot is processing their message. Returns a 204 empty response on success. Fires a [Typing Start](#DOCS_TOPICS_GATEWAY_EVENTS/typing-start) Gateway event. +Post a typing indicator for the specified channel, which expires after 10 seconds. Returns a 204 empty response on success. Fires a [Typing Start](#DOCS_TOPICS_GATEWAY_EVENTS/typing-start) Gateway event. + +Generally bots should **not** use this route. However, if a bot is responding to a command and expects the computation to take a few seconds, this endpoint may be called to let the user know that the bot is processing their message. ## Get Pinned Messages % GET /channels/{channel.id#DOCS_RESOURCES_CHANNEL/channel-object}/pins @@ -1238,7 +1271,7 @@ Adds a recipient to a Group DM using their access token. ###### JSON Params | Field | Type | Description | -| ------------ | ------ | --------------------------------------------------------------------- | +|--------------|--------|-----------------------------------------------------------------------| | access_token | string | access token of a user that has granted your app the `gdm.join` scope | | nick | string | nickname of the user being added | @@ -1250,7 +1283,7 @@ Removes a recipient from a Group DM. Creates a new thread from an existing message. Returns a [channel](#DOCS_RESOURCES_CHANNEL/channel-object) on success, and a 400 BAD REQUEST on invalid parameters. Fires a [Thread Create](#DOCS_TOPICS_GATEWAY_EVENTS/thread-create) and a [Message Update](#DOCS_TOPICS_GATEWAY_EVENTS/message-update) Gateway event. -When called on a `GUILD_TEXT` channel, creates a `PUBLIC_THREAD`. When called on a `GUILD_ANNOUNCEMENT` channel, creates a `ANNOUNCEMENT_THREAD`. Does not work on a [`GUILD_FORUM`](#DOCS_RESOURCES_CHANNEL/start-thread-in-forum-channel) channel. The id of the created thread will be the same as the id of the source message, and as such a message can only have a single thread created from it. +When called on a `GUILD_TEXT` channel, creates a `PUBLIC_THREAD`. When called on a `GUILD_ANNOUNCEMENT` channel, creates a `ANNOUNCEMENT_THREAD`. Does not work on a [`GUILD_FORUM`](#DOCS_RESOURCES_CHANNEL/start-thread-in-forum-or-media-channel) or a `GUILD_MEDIA` channel. The id of the created thread will be the same as the id of the source message, and as such a message can only have a single thread created from it. > info > This endpoint supports the `X-Audit-Log-Reason` header. @@ -1258,7 +1291,7 @@ When called on a `GUILD_TEXT` channel, creates a `PUBLIC_THREAD`. When called on ###### JSON Params | Field | Type | Description | -| ---------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +|------------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------| | name | string | 1-100 character channel name | | auto_archive_duration? | integer | the thread will stop showing in the channel list after `auto_archive_duration` minutes of inactivity, can be set to: 60, 1440, 4320, 10080 | | rate_limit_per_user? | ?integer | amount of seconds a user has to wait before sending another message (0-21600) | @@ -1273,7 +1306,7 @@ Creates a new thread that is not connected to an existing message. Returns a [ch ###### JSON Params | Field | Type | Description | -| ---------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +|------------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------| | name | string | 1-100 character channel name | | auto_archive_duration? | integer | the thread will stop showing in the channel list after `auto_archive_duration` minutes of inactivity, can be set to: 60, 1440, 4320, 10080 | | type?\* | integer | the [type of thread](#DOCS_RESOURCES_CHANNEL/channel-object-channel-types) to create | @@ -1282,9 +1315,9 @@ Creates a new thread that is not connected to an existing message. Returns a [ch \* `type` currently defaults to `PRIVATE_THREAD` in order to match the behavior when thread documentation was first published. In a future API version this will be changed to be a required field, with no default. -## Start Thread in Forum Channel % POST /channels/{channel.id#DOCS_RESOURCES_CHANNEL/channel-object}/threads +## Start Thread in Forum or Media Channel % POST /channels/{channel.id#DOCS_RESOURCES_CHANNEL/channel-object}/threads -Creates a new thread in a forum channel, and sends a message within the created thread. Returns a [channel](#DOCS_RESOURCES_CHANNEL/channel-object), with a nested [message](#DOCS_RESOURCES_CHANNEL/message-object) object, on success, and a 400 BAD REQUEST on invalid parameters. Fires a [Thread Create](#DOCS_TOPICS_GATEWAY_EVENTS/thread-create) and [Message Create](#DOCS_TOPICS_GATEWAY_EVENTS/message-create) Gateway event. +Creates a new thread in a forum or a media channel, and sends a message within the created thread. Returns a [channel](#DOCS_RESOURCES_CHANNEL/channel-object), with a nested [message](#DOCS_RESOURCES_CHANNEL/message-object) object, on success, and a 400 BAD REQUEST on invalid parameters. Fires a [Thread Create](#DOCS_TOPICS_GATEWAY_EVENTS/thread-create) and [Message Create](#DOCS_TOPICS_GATEWAY_EVENTS/message-create) Gateway event. - The type of the created thread is `PUBLIC_THREAD`. - See [message formatting](#DOCS_REFERENCE/message-formatting) for more information on how to properly format messages. @@ -1303,31 +1336,31 @@ Creates a new thread in a forum channel, and sends a message within the created ###### JSON/Form Params -| Field | Type | Description | -| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | -| name | string | 1-100 character channel name | -| auto_archive_duration?\* | integer | duration in minutes to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080 | -| rate_limit_per_user? | ?integer | amount of seconds a user has to wait before sending another message (0-21600) | -| message | a [forum thread message params](#DOCS_RESOURCES_CHANNEL/start-thread-in-forum-channel-forum-thread-message-params-object) object | contents of the first message in the forum thread | -| applied_tags? | array of snowflakes | the IDs of the set of tags that have been applied to a thread in a `GUILD_FORUM` channel | +| Field | Type | Description | +|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------| +| name | string | 1-100 character channel name | +| auto_archive_duration?\* | integer | duration in minutes to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080 | +| rate_limit_per_user? | ?integer | amount of seconds a user has to wait before sending another message (0-21600) | +| message | a [forum thread message params](#DOCS_RESOURCES_CHANNEL/start-thread-in-forum-or-media-channel-forum-and-media-thread-message-params-object) object | contents of the first message in the forum thread | +| applied_tags? | array of snowflakes | the IDs of the set of tags that have been applied to a thread in a `GUILD_FORUM` channel | +| files[n]?\* | file contents | Contents of the file being sent. See [Uploading Files](#DOCS_REFERENCE/uploading-files) | +| payload_json? | string | JSON-encoded body of non-file params, only for `multipart/form-data` requests. See [Uploading Files](#DOCS_REFERENCE/uploading-files) | -###### Forum Thread Message Params Object +###### Forum and Media Thread Message Params Object > info > When sending a message, apps must provide a value for **at least one of** `content`, `embeds`, `sticker_ids`, `components`, or `files[n]`. | Field | Type | Description | -| ----------------- | -------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-------------------|----------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | content?\* | string | Message contents (up to 2000 characters) | -| embeds?\* | array of [embed](#DOCS_RESOURCES_CHANNEL/embed-object) objects | Up to 10 `rich` embeds (up to 6000 characters) | +| embeds?\* | array of [embed](#DOCS_RESOURCES_CHANNEL/embed-object) objects | Embedded `rich` content (up to 6000 characters) | | allowed_mentions? | [allowed mention object](#DOCS_RESOURCES_CHANNEL/allowed-mentions-object) | Allowed mentions for the message | | components?\* | array of [message component](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/component-object) objects | Components to include with the message | | sticker_ids?\* | array of snowflakes | IDs of up to 3 [stickers](#DOCS_RESOURCES_STICKER/sticker-object) in the server to send in the message | -| files[n]\* | file contents | Contents of the file being sent. See [Uploading Files](#DOCS_REFERENCE/uploading-files) | -| payload_json? | string | JSON-encoded body of non-file params, only for `multipart/form-data` requests. See [Uploading Files](#DOCS_REFERENCE/uploading-files) | | attachments? | array of partial [attachment](#DOCS_RESOURCES_CHANNEL/attachment-object) objects | Attachment objects with `filename` and `description`. See [Uploading Files](#DOCS_REFERENCE/uploading-files) | -| flags? | integer | [Message flags](#DOCS_RESOURCES_CHANNEL/message-object-message-flags) combined as a [bitfield](https://en.wikipedia.org/wiki/Bit_field) (only `SUPPRESS_EMBEDS` and `SUPPRESS_NOTIFICATIONS` can be set) | +| flags? | integer | [Message flags](#DOCS_RESOURCES_CHANNEL/message-object-message-flags) combined as a [bitfield](https://en.wikipedia.org/wiki/Bit_field) (only `SUPPRESS_EMBEDS` can be set) | \* At least one of `content`, `embeds`, `sticker_ids`, `components`, or `files[n]` is required. @@ -1355,9 +1388,9 @@ When `with_member` is set to `true`, the thread member object will include a `me ###### Query String Params -| Field | Type | Description | -| ------------ | --------- | ----------------------------------------------------------------------------------------------------------- | -| with_member? | boolean | Whether to include a [guild member](#DOCS_RESOURCES_GUILD/guild-member-object) object for the thread member | +| Field | Type | Description | +|--------------|---------|-------------------------------------------------------------------------------------------------------------| +| with_member? | boolean | Whether to include a [guild member](#DOCS_RESOURCES_GUILD/guild-member-object) object for the thread member | ## List Thread Members % GET /channels/{channel.id#DOCS_RESOURCES_CHANNEL/channel-object}/thread-members @@ -1374,7 +1407,7 @@ When `with_member` is set to `true`, the results will be paginated and each thre ###### Query String Params | Field | Type | Description | -| ------------ | --------- | ------------------------------------------------------------------------------------------------------------ | +|--------------|-----------|--------------------------------------------------------------------------------------------------------------| | with_member? | boolean | Whether to include a [guild member](#DOCS_RESOURCES_GUILD/guild-member-object) object for each thread member | | after? | snowflake | Get thread members after this user ID | | limit? | integer | Max number of thread members to return (1-100). Defaults to 100. | @@ -1386,14 +1419,14 @@ Returns archived threads in the channel that are public. When called on a `GUILD ###### Query String Params | Field | Type | Description | -| ------- | ----------------- | ---------------------------------------------- | +|---------|-------------------|------------------------------------------------| | before? | ISO8601 timestamp | returns threads archived before this timestamp | | limit? | integer | optional maximum number of threads to return | ###### Response Body | Field | Type | Description | -| -------- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | +|----------|---------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------| | threads | array of [channel](#DOCS_RESOURCES_CHANNEL/channel-object) objects | the public, archived threads | | members | array of [thread members](#DOCS_RESOURCES_CHANNEL/thread-member-object) objects | a thread member object for each returned thread the current user has joined | | has_more | boolean | whether there are potentially additional threads that could be returned on a subsequent call | @@ -1405,14 +1438,14 @@ Returns archived threads in the channel that are of [type](#DOCS_RESOURCES_CHANN ###### Query String Params | Field | Type | Description | -| ------- | ----------------- | ---------------------------------------------- | +|---------|-------------------|------------------------------------------------| | before? | ISO8601 timestamp | returns threads archived before this timestamp | | limit? | integer | optional maximum number of threads to return | ###### Response Body | Field | Type | Description | -| -------- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | +|----------|---------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------| | threads | array of [channel](#DOCS_RESOURCES_CHANNEL/channel-object) objects | the private, archived threads | | members | array of [thread members](#DOCS_RESOURCES_CHANNEL/thread-member-object) objects | a thread member object for each returned thread the current user has joined | | has_more | boolean | whether there are potentially additional threads that could be returned on a subsequent call | @@ -1424,14 +1457,14 @@ Returns archived threads in the channel that are of [type](#DOCS_RESOURCES_CHANN ###### Query String Params | Field | Type | Description | -| ------- | --------- | -------------------------------------------- | +|---------|-----------|----------------------------------------------| | before? | snowflake | returns threads before this id | | limit? | integer | optional maximum number of threads to return | ###### Response Body | Field | Type | Description | -| -------- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | +|----------|---------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------| | threads | array of [channel](#DOCS_RESOURCES_CHANNEL/channel-object) objects | the private, archived threads the current user has joined | | members | array of [thread members](#DOCS_RESOURCES_CHANNEL/thread-member-object) objects | a thread member object for each returned thread the current user has joined | | has_more | boolean | whether there are potentially additional threads that could be returned on a subsequent call | diff --git a/docs/resources/Emoji.md b/docs/resources/Emoji.md index 218982ccce..c229453552 100644 --- a/docs/resources/Emoji.md +++ b/docs/resources/Emoji.md @@ -8,7 +8,7 @@ ###### Emoji Structure | Field | Type | Description | -| --------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------- | +|-----------------|------------------------------------------------------------------|---------------------------------------------------------------------------| | id | ?snowflake | [emoji id](#DOCS_REFERENCE/image-formatting) | | name | ?string (can be null only in reaction emoji objects) | emoji name | | roles? | array of [role](#DOCS_TOPICS_PERMISSIONS/role-object) object ids | roles allowed to use this emoji | @@ -90,18 +90,18 @@ Returns an [emoji](#DOCS_RESOURCES_EMOJI/emoji-object) object for the given guil Create a new emoji for the guild. Requires the `MANAGE_GUILD_EXPRESSIONS` permission. Returns the new [emoji](#DOCS_RESOURCES_EMOJI/emoji-object) object on success. Fires a [Guild Emojis Update](#DOCS_TOPICS_GATEWAY_EVENTS/guild-emojis-update) Gateway event. > warn -> Emojis and animated emojis have a maximum file size of 256kb. Attempting to upload an emoji larger than this limit will fail and return 400 Bad Request and an error message, but not a [JSON status code](#DOCS_TOPICS_OPCODES_AND_STATUS_CODES/json). +> Emojis and animated emojis have a maximum file size of 256 KiB. Attempting to upload an emoji larger than this limit will fail and return 400 Bad Request and an error message, but not a [JSON status code](#DOCS_TOPICS_OPCODES_AND_STATUS_CODES/json). > info > This endpoint supports the `X-Audit-Log-Reason` header. ###### JSON Params -| Field | Type | Description | -| ----- | ---------------------------------------- | ---------------------------------------------- | -| name | string | name of the emoji | -| image | [image data](#DOCS_REFERENCE/image-data) | the 128x128 emoji image | -| roles | array of snowflakes | roles allowed to use this emoji | +| Field | Type | Description | +|-------|------------------------------------------|---------------------------------| +| name | string | name of the emoji | +| image | [image data](#DOCS_REFERENCE/image-data) | the 128x128 emoji image | +| roles | array of snowflakes | roles allowed to use this emoji | ## Modify Guild Emoji % PATCH /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/emojis/{emoji.id#DOCS_RESOURCES_EMOJI/emoji-object} @@ -115,10 +115,10 @@ Modify the given emoji. Requires the `MANAGE_GUILD_EXPRESSIONS` permission. Retu ###### JSON Params -| Field | Type | Description | -| ----- | -------------------- | --------------------------------------------- | -| name | string | name of the emoji | -| roles | ?array of snowflakes | roles allowed to use this emoji | +| Field | Type | Description | +|-------|----------------------|---------------------------------| +| name | string | name of the emoji | +| roles | ?array of snowflakes | roles allowed to use this emoji | ## Delete Guild Emoji % DELETE /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/emojis/{emoji.id#DOCS_RESOURCES_EMOJI/emoji-object} diff --git a/docs/resources/Guild.md b/docs/resources/Guild.md index 3e59435074..4c424c632c 100644 --- a/docs/resources/Guild.md +++ b/docs/resources/Guild.md @@ -9,51 +9,51 @@ Guilds in Discord represent an isolated collection of users and channels, and ar > info > Fields specific to the `GUILD_CREATE` event are listed in the [Gateway Events documentation](#DOCS_TOPICS_GATEWAY_EVENTS/guild-create). -| Field | Type | Description | -| ------------------------------ | ----------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| id | snowflake | guild id | -| name | string | guild name (2-100 characters, excluding trailing and leading whitespace) | -| icon | ?string | [icon hash](#DOCS_REFERENCE/image-formatting) | -| icon_hash? | ?string | [icon hash](#DOCS_REFERENCE/image-formatting), returned when in the template object | -| splash | ?string | [splash hash](#DOCS_REFERENCE/image-formatting) | -| discovery_splash | ?string | [discovery splash hash](#DOCS_REFERENCE/image-formatting); only present for guilds with the "DISCOVERABLE" feature | -| owner? \* | boolean | true if [the user](#DOCS_RESOURCES_USER/get-current-user-guilds) is the owner of the guild | -| owner_id | snowflake | id of owner | -| permissions? \* | string | total permissions for [the user](#DOCS_RESOURCES_USER/get-current-user-guilds) in the guild (excludes overwrites) | -| region? \*\* | ?string | [voice region](#DOCS_RESOURCES_VOICE/voice-region-object) id for the guild (deprecated) | -| afk_channel_id | ?snowflake | id of afk channel | -| afk_timeout | integer | afk timeout in seconds | -| widget_enabled? | boolean | true if the server widget is enabled | -| widget_channel_id? | ?snowflake | the channel id that the widget will generate an invite to, or `null` if set to no invite | -| verification_level | integer | [verification level](#DOCS_RESOURCES_GUILD/guild-object-verification-level) required for the guild | -| default_message_notifications | integer | default [message notifications level](#DOCS_RESOURCES_GUILD/guild-object-default-message-notification-level) | -| explicit_content_filter | integer | [explicit content filter level](#DOCS_RESOURCES_GUILD/guild-object-explicit-content-filter-level) | -| roles | array of [role](#DOCS_TOPICS_PERMISSIONS/role-object) objects | roles in the guild | -| emojis | array of [emoji](#DOCS_RESOURCES_EMOJI/emoji-object) objects | custom guild emojis | -| features | array of [guild feature](#DOCS_RESOURCES_GUILD/guild-object-guild-features) strings | enabled guild features | -| mfa_level | integer | required [MFA level](#DOCS_RESOURCES_GUILD/guild-object-mfa-level) for the guild | -| application_id | ?snowflake | application id of the guild creator if it is bot-created | -| system_channel_id | ?snowflake | the id of the channel where guild notices such as welcome messages and boost events are posted | -| system_channel_flags | integer | [system channel flags](#DOCS_RESOURCES_GUILD/guild-object-system-channel-flags) | -| rules_channel_id | ?snowflake | the id of the channel where Community guilds can display rules and/or guidelines | -| max_presences? | ?integer | the maximum number of presences for the guild (`null` is always returned, apart from the largest of guilds) | -| max_members? | integer | the maximum number of members for the guild | -| vanity_url_code | ?string | the vanity url code for the guild | -| description | ?string | the description of a guild | -| banner | ?string | [banner hash](#DOCS_REFERENCE/image-formatting) | -| premium_tier | integer | [premium tier](#DOCS_RESOURCES_GUILD/guild-object-premium-tier) (Server Boost level) | -| premium_subscription_count? | integer | the number of boosts this guild currently has | -| preferred_locale | string | the preferred [locale](#DOCS_REFERENCE/locales) of a Community guild; used in server discovery and notices from Discord, and sent in interactions; defaults to "en-US" | -| public_updates_channel_id | ?snowflake | the id of the channel where admins and moderators of Community guilds receive notices from Discord | -| max_video_channel_users? | integer | the maximum amount of users in a video channel | -| max_stage_video_channel_users? | integer | the maximum amount of users in a stage video channel | -| approximate_member_count? | integer | approximate number of members in this guild, returned from the `GET /guilds/` and `/users/@me/guilds` endpoints when `with_counts` is `true` | -| approximate_presence_count? | integer | approximate number of non-offline members in this guild, returned from the `GET /guilds/` and `/users/@me/guilds` endpoints when `with_counts` is `true` | -| welcome_screen? | [welcome screen](#DOCS_RESOURCES_GUILD/welcome-screen-object) object | the welcome screen of a Community guild, shown to new members, returned in an [Invite](#DOCS_RESOURCES_INVITE/invite-object)'s guild object | -| nsfw_level | integer | [guild NSFW level](#DOCS_RESOURCES_GUILD/guild-object-guild-nsfw-level) | -| stickers? | array of [sticker](#DOCS_RESOURCES_STICKER/sticker-object) objects | custom guild stickers | -| premium_progress_bar_enabled | boolean | whether the guild has the boost progress bar enabled | -| safety_alerts_channel_id | ?snowflake | the id of the channel where admins and moderators of Community guilds receive safety alerts from Discord | +| Field | Type | Description | +|--------------------------------|-------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| id | snowflake | guild id | +| name | string | guild name (2-100 characters, excluding trailing and leading whitespace) | +| icon | ?string | [icon hash](#DOCS_REFERENCE/image-formatting) | +| icon_hash? | ?string | [icon hash](#DOCS_REFERENCE/image-formatting), returned when in the template object | +| splash | ?string | [splash hash](#DOCS_REFERENCE/image-formatting) | +| discovery_splash | ?string | [discovery splash hash](#DOCS_REFERENCE/image-formatting); only present for guilds with the "DISCOVERABLE" feature | +| owner? \* | boolean | true if [the user](#DOCS_RESOURCES_USER/get-current-user-guilds) is the owner of the guild | +| owner_id | snowflake | id of owner | +| permissions? \* | string | total permissions for [the user](#DOCS_RESOURCES_USER/get-current-user-guilds) in the guild (excludes overwrites and [implicit permissions](#DOCS_TOPICS_PERMISSIONS/implicit-permissions)) | +| region? \*\* | ?string | [voice region](#DOCS_RESOURCES_VOICE/voice-region-object) id for the guild (deprecated) | +| afk_channel_id | ?snowflake | id of afk channel | +| afk_timeout | integer | afk timeout in seconds | +| widget_enabled? | boolean | true if the server widget is enabled | +| widget_channel_id? | ?snowflake | the channel id that the widget will generate an invite to, or `null` if set to no invite | +| verification_level | integer | [verification level](#DOCS_RESOURCES_GUILD/guild-object-verification-level) required for the guild | +| default_message_notifications | integer | default [message notifications level](#DOCS_RESOURCES_GUILD/guild-object-default-message-notification-level) | +| explicit_content_filter | integer | [explicit content filter level](#DOCS_RESOURCES_GUILD/guild-object-explicit-content-filter-level) | +| roles | array of [role](#DOCS_TOPICS_PERMISSIONS/role-object) objects | roles in the guild | +| emojis | array of [emoji](#DOCS_RESOURCES_EMOJI/emoji-object) objects | custom guild emojis | +| features | array of [guild feature](#DOCS_RESOURCES_GUILD/guild-object-guild-features) strings | enabled guild features | +| mfa_level | integer | required [MFA level](#DOCS_RESOURCES_GUILD/guild-object-mfa-level) for the guild | +| application_id | ?snowflake | application id of the guild creator if it is bot-created | +| system_channel_id | ?snowflake | the id of the channel where guild notices such as welcome messages and boost events are posted | +| system_channel_flags | integer | [system channel flags](#DOCS_RESOURCES_GUILD/guild-object-system-channel-flags) | +| rules_channel_id | ?snowflake | the id of the channel where Community guilds can display rules and/or guidelines | +| max_presences? | ?integer | the maximum number of presences for the guild (`null` is always returned, apart from the largest of guilds) | +| max_members? | integer | the maximum number of members for the guild | +| vanity_url_code | ?string | the vanity url code for the guild | +| description | ?string | the description of a guild | +| banner | ?string | [banner hash](#DOCS_REFERENCE/image-formatting) | +| premium_tier | integer | [premium tier](#DOCS_RESOURCES_GUILD/guild-object-premium-tier) (Server Boost level) | +| premium_subscription_count? | integer | the number of boosts this guild currently has | +| preferred_locale | string | the preferred [locale](#DOCS_REFERENCE/locales) of a Community guild; used in server discovery and notices from Discord, and sent in interactions; defaults to "en-US" | +| public_updates_channel_id | ?snowflake | the id of the channel where admins and moderators of Community guilds receive notices from Discord | +| max_video_channel_users? | integer | the maximum amount of users in a video channel | +| max_stage_video_channel_users? | integer | the maximum amount of users in a stage video channel | +| approximate_member_count? | integer | approximate number of members in this guild, returned from the `GET /guilds/` and `/users/@me/guilds` endpoints when `with_counts` is `true` | +| approximate_presence_count? | integer | approximate number of non-offline members in this guild, returned from the `GET /guilds/` and `/users/@me/guilds` endpoints when `with_counts` is `true` | +| welcome_screen? | [welcome screen](#DOCS_RESOURCES_GUILD/welcome-screen-object) object | the welcome screen of a Community guild, shown to new members, returned in an [Invite](#DOCS_RESOURCES_INVITE/invite-object)'s guild object | +| nsfw_level | integer | [guild NSFW level](#DOCS_RESOURCES_GUILD/guild-object-guild-nsfw-level) | +| stickers? | array of [sticker](#DOCS_RESOURCES_STICKER/sticker-object) objects | custom guild stickers | +| premium_progress_bar_enabled | boolean | whether the guild has the boost progress bar enabled | +| safety_alerts_channel_id | ?snowflake | the id of the channel where admins and moderators of Community guilds receive safety alerts from Discord | \* These fields are only sent when using the [GET Current User Guilds](#DOCS_RESOURCES_USER/get-current-user-guilds) endpoint and are relative to the requested user @@ -62,14 +62,14 @@ Guilds in Discord represent an isolated collection of users and channels, and ar ###### Default Message Notification Level | Key | Value | Description | -| ------------- | ----- | ---------------------------------------------------------------------------------- | +|---------------|-------|------------------------------------------------------------------------------------| | ALL_MESSAGES | 0 | members will receive notifications for all messages by default | | ONLY_MENTIONS | 1 | members will receive notifications only for messages that @mention them by default | ###### Explicit Content Filter Level | Level | Integer | Description | -| --------------------- | ------- | ----------------------------------------------------------- | +|-----------------------|---------|-------------------------------------------------------------| | DISABLED | 0 | media content will not be scanned | | MEMBERS_WITHOUT_ROLES | 1 | media content sent by members without roles will be scanned | | ALL_MEMBERS | 2 | media content sent by all members will be scanned | @@ -77,14 +77,14 @@ Guilds in Discord represent an isolated collection of users and channels, and ar ###### MFA Level | Level | Integer | Description | -| -------- | ------- | ------------------------------------------------------- | +|----------|---------|---------------------------------------------------------| | NONE | 0 | guild has no MFA/2FA requirement for moderation actions | | ELEVATED | 1 | guild has a 2FA requirement for moderation actions | ###### Verification Level | Level | Integer | Description | -| --------- | ------- | --------------------------------------------------------- | +|-----------|---------|-----------------------------------------------------------| | NONE | 0 | unrestricted | | LOW | 1 | must have verified email on account | | MEDIUM | 2 | must be registered on Discord for longer than 5 minutes | @@ -94,7 +94,7 @@ Guilds in Discord represent an isolated collection of users and channels, and ar ###### Guild NSFW Level | Level | Value | -| -------------- | ----- | +|----------------|-------| | DEFAULT | 0 | | EXPLICIT | 1 | | SAFE | 2 | @@ -103,7 +103,7 @@ Guilds in Discord represent an isolated collection of users and channels, and ar ###### Premium Tier | Level | Integer | Description | -| ------ | ------- | --------------------------------------------- | +|--------|---------|-----------------------------------------------| | NONE | 0 | guild has not unlocked any Server Boost perks | | TIER_1 | 1 | guild has unlocked Server Boost level 1 perks | | TIER_2 | 2 | guild has unlocked Server Boost level 2 perks | @@ -112,7 +112,7 @@ Guilds in Discord represent an isolated collection of users and channels, and ar ###### System Channel Flags | Flag | Value | Description | -| -------------------------------------------------------- | ------ | ------------------------------------------------------------- | +|----------------------------------------------------------|--------|---------------------------------------------------------------| | SUPPRESS_JOIN_NOTIFICATIONS | 1 << 0 | Suppress member join notifications | | SUPPRESS_PREMIUM_SUBSCRIPTIONS | 1 << 1 | Suppress server boost notifications | | SUPPRESS_GUILD_REMINDER_NOTIFICATIONS | 1 << 2 | Suppress server setup tips | @@ -123,7 +123,7 @@ Guilds in Discord represent an isolated collection of users and channels, and ar ###### Guild Features | Feature | Description | -| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +|-------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------| | ANIMATED_BANNER | guild has access to set an animated guild banner image | | ANIMATED_ICON | guild has access to set an animated guild icon | | APPLICATION_COMMAND_PERMISSIONS_V2 | guild is using the [old permissions configuration behavior](#DOCS_CHANGE_LOG/upcoming-application-command-permission-changes) | @@ -155,7 +155,7 @@ Guilds in Discord represent an isolated collection of users and channels, and ar ###### Mutable Guild Features | Features | Required Permissions | Effects | -| -------------------- | -------------------- | --------------------------------------------------------- | +|----------------------|----------------------|-----------------------------------------------------------| | COMMUNITY | Administrator | Enables Community Features in the guild | | DISCOVERABLE | Administrator* | Enables discovery in the guild, making it publicly listed | | INVITES_DISABLED | Manage Guild | Pauses all invites/access to the server | @@ -230,7 +230,7 @@ A partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object. Represents an Offl ###### Guild Preview Structure | Field | Type | Description | -| -------------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------- | +|----------------------------|-------------------------------------------------------------------------------------|-----------------------------------------------------------| | id | snowflake | guild id | | name | string | guild name (2-100 characters) | | icon | ?string | [icon hash](#DOCS_REFERENCE/image-formatting) | @@ -276,7 +276,7 @@ A partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object. Represents an Offl ###### Guild Widget Settings Structure | Field | Type | Description | -| ---------- | ---------- | ----------------------------- | +|------------|------------|-------------------------------| | enabled | boolean | whether the widget is enabled | | channel_id | ?snowflake | the widget channel id | @@ -294,7 +294,7 @@ A partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object. Represents an Offl ###### Guild Widget Structure | Field | Type | Description | -| -------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------- | +|----------------|----------------------------------------------------------------------------|----------------------------------------------------------------------| | id | snowflake | guild id | | name | string | guild name (2-100 characters) | | instant_invite | ?string | instant invite for the guilds specified widget invite channel | @@ -343,7 +343,7 @@ A partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object. Represents an Offl ###### Guild Member Structure | Field | Type | Description | -| ----------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +|-------------------------------|-------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | user? | [user](#DOCS_RESOURCES_USER/user-object) object | the user this guild member represents | | nick? | ?string | this user's guild nickname | | avatar? | ?string | the member's [guild avatar hash](#DOCS_REFERENCE/image-formatting) | @@ -380,7 +380,7 @@ A partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object. Represents an Offl ###### Guild Member Flags | Flag | Value | Description | Editable | -| --------------------- | ------ | ----------------------------------------------------- | -------- | +|-----------------------|--------|-------------------------------------------------------|----------| | DID_REJOIN | 1 << 0 | Member has left and rejoined the guild | false | | COMPLETED_ONBOARDING | 1 << 1 | Member has completed onboarding | false | | BYPASSES_VERIFICATION | 1 << 2 | Member is exempt from guild verification requirements | true | @@ -394,7 +394,7 @@ A partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object. Represents an Offl ###### Integration Structure | Field | Type | Description | -| ----------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | +|-------------------------|------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------| | id | snowflake | integration id | | name | string | integration name | | type | string | integration type (twitch, youtube, discord, or guild_subscription) | @@ -419,7 +419,7 @@ A partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object. Represents an Offl ###### Integration Expire Behaviors | Value | Name | -| ----- | ----------- | +|-------|-------------| | 0 | Remove role | | 1 | Kick | @@ -428,7 +428,7 @@ A partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object. Represents an Offl ###### Integration Account Structure | Field | Type | Description | -| ----- | ------ | ------------------- | +|-------|--------|---------------------| | id | string | id of the account | | name | string | name of the account | @@ -437,7 +437,7 @@ A partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object. Represents an Offl ###### Integration Application Structure | Field | Type | Description | -| ----------- | ----------------------------------------------- | ------------------------------------------------------------ | +|-------------|-------------------------------------------------|--------------------------------------------------------------| | id | snowflake | the id of the app | | name | string | the name of the app | | icon | ?string | the [icon hash](#DOCS_REFERENCE/image-formatting) of the app | @@ -449,7 +449,7 @@ A partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object. Represents an Offl ###### Ban Structure | Field | Type | Description | -| ------ | ----------------------------------------------- | ---------------------- | +|--------|-------------------------------------------------|------------------------| | reason | ?string | the reason for the ban | | user | [user](#DOCS_RESOURCES_USER/user-object) object | the banned user | @@ -473,14 +473,14 @@ A partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object. Represents an Offl ###### Welcome Screen Structure | Field | Type | Description | -| ---------------- | ----------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | +|------------------|-------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------| | description | ?string | the server description shown in the welcome screen | | welcome_channels | array of [welcome screen channel](#DOCS_RESOURCES_GUILD/welcome-screen-object-welcome-screen-channel-structure) objects | the channels shown in the welcome screen, up to 5 | ###### Welcome Screen Channel Structure | Field | Type | Description | -| ----------- | ---------- | ----------------------------------------------------------------------------------------- | +|-------------|------------|-------------------------------------------------------------------------------------------| | channel_id | snowflake | the channel's id | | description | string | the description shown for the channel | | emoji_id | ?snowflake | the [emoji id](#DOCS_REFERENCE/image-formatting), if the emoji is custom | @@ -533,7 +533,7 @@ Represents the [onboarding](https://support.discord.com/hc/en-us/articles/110749 ###### Guild Onboarding Structure | Field | Type | Description | -| ------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | +|---------------------|-----------------------------------------------------------------------------------------------------------------|------------------------------------------------------------| | guild_id | snowflake | ID of the guild this onboarding is part of | | prompts | array of [onboarding prompt](#DOCS_RESOURCES_GUILD/guild-onboarding-object-onboarding-prompt-structure) objects | Prompts shown during onboarding and in customize community | | default_channel_ids | array of snowflakes | Channel IDs that members get opted into automatically | @@ -543,7 +543,7 @@ Represents the [onboarding](https://support.discord.com/hc/en-us/articles/110749 ###### Onboarding Prompt Structure | Field | Type | Description | -| ------------- | ------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +|---------------|---------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------| | id | snowflake | ID of the prompt | | type | [prompt type](#DOCS_RESOURCES_GUILD/guild-onboarding-object-prompt-types) | Type of prompt | | options | array of [prompt option](#DOCS_RESOURCES_GUILD/guild-onboarding-object-prompt-option-structure) objects | Options available within the prompt | @@ -555,7 +555,7 @@ Represents the [onboarding](https://support.discord.com/hc/en-us/articles/110749 ###### Prompt Option Structure | Field | Type | Description | -| ----------- | -------------------------------------------------- | ----------------------------------------------------------------- | +|-------------|----------------------------------------------------|-------------------------------------------------------------------| | id | snowflake | ID of the prompt option | | channel_ids | array of snowflakes | IDs for channels a member is added to when the option is selected | | role_ids | array of snowflakes | IDs for roles assigned to a member when the option is selected | @@ -568,14 +568,14 @@ Represents the [onboarding](https://support.discord.com/hc/en-us/articles/110749 Defines the criteria used to satisfy Onboarding constraints that are required for enabling. | Name | Value | Description | -| ------------------- | ----- | --------------------------------------------------------- | +|---------------------|-------|-----------------------------------------------------------| | ONBOARDING_DEFAULT | 0 | Counts only Default Channels towards constraints | | ONBOARDING_ADVANCED | 1 | Counts Default Channels and Questions towards constraints | ###### Prompt Types | Name | Value | -| --------------- | ----- | +|-----------------|-------| | MULTIPLE_CHOICE | 0 | | DROPDOWN | 1 | @@ -654,7 +654,7 @@ Create a new guild. Returns a [guild](#DOCS_RESOURCES_GUILD/guild-object) object ###### JSON Params | Field | Type | Description | -| ------------------------------ | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | +|--------------------------------|----------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------| | name | string | name of the guild (2-100 characters) | | region? | ?string | [voice region](#DOCS_RESOURCES_VOICE/voice-region-object) id (deprecated) | | icon? | [image data](#DOCS_REFERENCE/image-data) | base64 128x128 image for the guild icon | @@ -715,7 +715,7 @@ Returns the [guild](#DOCS_RESOURCES_GUILD/guild-object) object for the given id. ###### Query String Params | Field | Type | Description | Required | Default | -| ------------ | ------- | ----------------------------------------------------------------------------- | -------- | ------- | +|--------------|---------|-------------------------------------------------------------------------------|----------|---------| | with_counts? | boolean | when `true`, will return approximate member and presence counts for the guild | false | false | ###### Example Response @@ -791,7 +791,7 @@ Returns the [guild](#DOCS_RESOURCES_GUILD/guild-object) object for the given id. ## Get Guild Preview % GET /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/preview -Returns the [guild preview](#DOCS_RESOURCES_GUILD/guild-preview-object) object for the given id. +Returns the [guild preview](#DOCS_RESOURCES_GUILD/guild-preview-object) object for the given id. If the user is not in the guild, then the guild must be [discoverable](#DOCS_RESOURCES_GUILD/guild-object-guild-features). ## Modify Guild % PATCH /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object} @@ -810,7 +810,7 @@ Modify a guild's settings. Requires the `MANAGE_GUILD` permission. Returns the u ###### JSON Params | Field | Type | Description | -| ----------------------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-------------------------------|-------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------| | name | string | guild name | | region | ?string | guild [voice region](#DOCS_RESOURCES_VOICE/voice-region-object) id (deprecated) | | verification_level | ?integer | [verification level](#DOCS_RESOURCES_GUILD/guild-object-verification-level) | @@ -853,25 +853,26 @@ Create a new [channel](#DOCS_RESOURCES_CHANNEL/channel-object) object for the gu ###### JSON Params -| Field | Type | Description | Channel Type | -| ----------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | -| name | string | channel name (1-100 characters) | All | -| type | integer | the [type of channel](#DOCS_RESOURCES_CHANNEL/channel-object-channel-types) | All | -| topic | string | channel topic (0-1024 characters) | Text, Announcement, Forum | -| bitrate\* | integer | the bitrate (in bits) of the voice or stage channel; min 8000 | Voice, Stage | -| user_limit | integer | the user limit of the voice channel | Voice, Stage | -| rate_limit_per_user | integer | amount of seconds a user has to wait before sending another message (0-21600); bots, as well as users with the permission `manage_messages` or `manage_channel`, are unaffected | Text, Voice, Stage, Forum | -| position | integer | sorting position of the channel | All | -| permission_overwrites\*\* | array of partial [overwrite](#DOCS_RESOURCES_CHANNEL/overwrite-object) objects | the channel's permission overwrites | All | -| parent_id | snowflake | id of the parent category for a channel | Text, Voice, Announcement, Stage, Forum | -| nsfw | boolean | whether the channel is nsfw | Text, Voice, Announcement, Stage, Forum | -| rtc_region | string | channel [voice region](#DOCS_RESOURCES_VOICE/voice-region-object) id of the voice or stage channel, automatic when set to null | Voice, Stage | -| video_quality_mode | integer | the camera [video quality mode](#DOCS_RESOURCES_CHANNEL/channel-object-video-quality-modes) of the voice channel | Voice, Stage | -| default_auto_archive_duration | integer | the default duration that the clients use (not the API) for newly created threads in the channel, in minutes, to automatically archive the thread after recent activity | Text, Announcement, Forum | -| default_reaction_emoji | [default reaction](#DOCS_RESOURCES_CHANNEL/default-reaction-object) object | emoji to show in the add reaction button on a thread in a `GUILD_FORUM` channel | Forum | -| available_tags | array of [tag](#DOCS_RESOURCES_CHANNEL/forum-tag-object) objects | set of tags that can be used in a `GUILD_FORUM` channel | Forum | -| default_sort_order | integer | the [default sort order type](#DOCS_RESOURCES_CHANNEL/channel-object-sort-order-types) used to order posts in `GUILD_FORUM` channels | Forum | -| default_forum_layout | integer | the [default forum layout view](#DOCS_RESOURCES_CHANNEL/channel-object-forum-layout-types) used to display posts in `GUILD_FORUM` channels | Forum | +| Field | Type | Description | Channel Type | +|------------------------------------|--------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------| +| name | string | channel name (1-100 characters) | All | +| type | integer | the [type of channel](#DOCS_RESOURCES_CHANNEL/channel-object-channel-types) | All | +| topic | string | channel topic (0-1024 characters) | Text, Announcement, Forum, Media | +| bitrate\* | integer | the bitrate (in bits) of the voice or stage channel; min 8000 | Voice, Stage | +| user_limit | integer | the user limit of the voice channel | Voice, Stage | +| rate_limit_per_user | integer | amount of seconds a user has to wait before sending another message (0-21600); bots, as well as users with the permission `manage_messages` or `manage_channel`, are unaffected | Text, Voice, Stage, Forum, Media | +| position | integer | sorting position of the channel | All | +| permission_overwrites\*\* | array of partial [overwrite](#DOCS_RESOURCES_CHANNEL/overwrite-object) objects | the channel's permission overwrites | All | +| parent_id | snowflake | id of the parent category for a channel | Text, Voice, Announcement, Stage, Forum, Media | +| nsfw | boolean | whether the channel is nsfw | Text, Voice, Announcement, Stage, Forum | +| rtc_region | string | channel [voice region](#DOCS_RESOURCES_VOICE/voice-region-object) id of the voice or stage channel, automatic when set to null | Voice, Stage | +| video_quality_mode | integer | the camera [video quality mode](#DOCS_RESOURCES_CHANNEL/channel-object-video-quality-modes) of the voice channel | Voice, Stage | +| default_auto_archive_duration | integer | the default duration that the clients use (not the API) for newly created threads in the channel, in minutes, to automatically archive the thread after recent activity | Text, Announcement, Forum, Media | +| default_reaction_emoji | [default reaction](#DOCS_RESOURCES_CHANNEL/default-reaction-object) object | emoji to show in the add reaction button on a thread in a `GUILD_FORUM` or a `GUILD_MEDIA` channel | Forum, Media | +| available_tags | array of [tag](#DOCS_RESOURCES_CHANNEL/forum-tag-object) objects | set of tags that can be used in a `GUILD_FORUM` or a `GUILD_MEDIA` channel | Forum, Media | +| default_sort_order | integer | the [default sort order type](#DOCS_RESOURCES_CHANNEL/channel-object-sort-order-types) used to order posts in `GUILD_FORUM` and `GUILD_MEDIA` channels | Forum, Media | +| default_forum_layout | integer | the [default forum layout view](#DOCS_RESOURCES_CHANNEL/channel-object-forum-layout-types) used to display posts in `GUILD_FORUM` channels | Forum | +| default_thread_rate_limit_per_user | integer | the initial `rate_limit_per_user` to set on newly created threads in a channel. this field is copied to the thread at creation time and does not live update. | Text, Announcement, Forum, Media | \* For voice channels, normal servers can set bitrate up to 96000, servers with Boost level 1 can set up to 128000, servers with Boost level 2 can set up to 256000, and servers with Boost level 3 or the `VIP_REGIONS` [guild feature](#DOCS_RESOURCES_GUILD/guild-object-guild-features) can set up to 384000. For stage channels, bitrate can be set up to 64000. @@ -888,12 +889,12 @@ This endpoint takes a JSON array of parameters in the following format: ###### JSON Params -| Field | Type | Description | -| ---------------- | ---------- | -------------------------------------------------------------------------------- | -| id | snowflake | channel id | -| position | ?integer | sorting position of the channel | -| lock_permissions | ?boolean | syncs the permission overwrites with the new parent, if moving to a new category | -| parent_id | ?snowflake | the new parent ID for the channel that is moved | +| Field | Type | Description | +|-------------------|------------|----------------------------------------------------------------------------------| +| id | snowflake | channel id | +| position? | ?integer | sorting position of the channel | +| lock_permissions? | ?boolean | syncs the permission overwrites with the new parent, if moving to a new category | +| parent_id? | ?snowflake | the new parent ID for the channel that is moved | ## List Active Guild Threads % GET /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/threads/active @@ -902,7 +903,7 @@ Returns all active threads in the guild, including public and private threads. T ###### Response Body | Field | Type | Description | -| ------- | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | +|---------|---------------------------------------------------------------------------------|-----------------------------------------------------------------------------| | threads | array of [channel](#DOCS_RESOURCES_CHANNEL/channel-object) objects | the active threads | | members | array of [thread members](#DOCS_RESOURCES_CHANNEL/thread-member-object) objects | a thread member object for each returned thread the current user has joined | @@ -923,7 +924,7 @@ Returns a list of [guild member](#DOCS_RESOURCES_GUILD/guild-member-object) obje ###### Query String Params | Field | Type | Description | Default | -| ----- | --------- | ---------------------------------------- | ------- | +|-------|-----------|------------------------------------------|---------| | limit | integer | max number of members to return (1-1000) | 1 | | after | snowflake | the highest user id in the previous page | 0 | @@ -937,7 +938,7 @@ Returns a list of [guild member](#DOCS_RESOURCES_GUILD/guild-member-object) obje ###### Query String Params | Field | Type | Description | Default | -| ----- | ------- | ---------------------------------------------------------- | ------- | +|-------|---------|------------------------------------------------------------|---------| | query | string | Query string to match username(s) and nickname(s) against. | | | limit | integer | max number of members to return (1-1000) | 1 | @@ -956,7 +957,7 @@ For guilds with [Membership Screening](#DOCS_RESOURCES_GUILD/membership-screenin ###### JSON Params | Field | Type | Description | Permission | -| ------------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------ | ---------------- | +|--------------|---------------------|--------------------------------------------------------------------------------------------------------------------------|------------------| | access_token | string | an oauth2 access token granted with the `guilds.join` to the bot's application for the user you want to add to the guild | | | nick | string | value to set user's nickname to | MANAGE_NICKNAMES | | roles | array of snowflakes | array of role ids the member is assigned | MANAGE_ROLES | @@ -977,7 +978,7 @@ Modify attributes of a [guild member](#DOCS_RESOURCES_GUILD/guild-member-object) ###### JSON Params | Field | Type | Description | Permission | -| ---------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------- | +|------------------------------|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------| | nick | string | value to set user's nickname to | MANAGE_NICKNAMES | | roles | array of snowflakes | array of role ids the member is assigned | MANAGE_ROLES | | mute | boolean | whether the user is muted in voice channels. Will throw a 400 error if the user is not in a voice channel | MUTE_MEMBERS | @@ -996,7 +997,7 @@ Modifies the current member in a guild. Returns a 200 with the updated member ob ###### JSON Params | Field | Type | Description | Permission | -| ----- | ------- | ------------------------------- | --------------- | +|-------|---------|---------------------------------|-----------------| | nick? | ?string | value to set user's nickname to | CHANGE_NICKNAME | ## Modify Current User Nick % PATCH /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/members/@me/nick @@ -1012,7 +1013,7 @@ Modifies the nickname of the current user in a guild. Returns a 200 with the nic ###### JSON Params | Field | Type | Description | Permission | -| ----- | ------- | ------------------------------- | --------------- | +|-------|---------|---------------------------------|-----------------| | nick? | ?string | value to set user's nickname to | CHANGE_NICKNAME | ## Add Guild Member Role % PUT /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/members/{user.id#DOCS_RESOURCES_USER/user-object}/roles/{role.id#DOCS_TOPICS_PERMISSIONS/role-object} @@ -1043,7 +1044,7 @@ Returns a list of [ban](#DOCS_RESOURCES_GUILD/ban-object) objects for the users ###### Query String Params | Field | Type | Description | Default | -| --------- | --------- | ---------------------------------------------- | ------- | +|-----------|-----------|------------------------------------------------|---------| | limit? | number | number of users to return (up to maximum 1000) | 1000 | | before? * | snowflake | consider only users before given user id | null | | after? * | snowflake | consider only users after given user id | null | @@ -1064,7 +1065,7 @@ Create a guild ban, and optionally delete previous messages sent by the banned u ###### JSON Params | Field | Type | Description | Default | -| ----------------------- | ------- | ----------------------------------------------------------------------- | ------- | +|-------------------------|---------|-------------------------------------------------------------------------|---------| | delete_message_days? | integer | number of days to delete messages for (0-7) (deprecated) | 0 | | delete_message_seconds? | integer | number of seconds to delete messages for, between 0 and 604800 (7 days) | 0 | @@ -1089,7 +1090,7 @@ Create a new [role](#DOCS_TOPICS_PERMISSIONS/role-object) for the guild. Require ###### JSON Params | Field | Type | Description | Default | -| ------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------ | +|---------------|-------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------|--------------------------------| | name | string | name of the role, max 100 characters | "new role" | | permissions | string | bitwise value of the enabled/disabled permissions | @everyone permissions in guild | | color | integer | RGB color value | 0 | @@ -1110,7 +1111,7 @@ This endpoint takes a JSON array of parameters in the following format: ###### JSON Params | Field | Type | Description | -| --------- | --------- | ---------------------------- | +|-----------|-----------|------------------------------| | id | snowflake | role | | position? | ?integer | sorting position of the role | @@ -1127,7 +1128,7 @@ Modify a guild role. Requires the `MANAGE_ROLES` permission. Returns the updated ###### JSON Params | Field | Type | Description | -| ------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | +|---------------|------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------| | name | string | name of the role, max 100 characters | | permissions | string | bitwise value of the enabled/disabled permissions | | color | integer | RGB color value | @@ -1146,7 +1147,7 @@ Modify a guild's MFA level. Requires guild ownership. Returns the updated [level ###### JSON Params | Field | Type | Description | -| ----- | ------- | --------------------------------------------------------- | +|-------|---------|-----------------------------------------------------------| | level | integer | [MFA level](#DOCS_RESOURCES_GUILD/guild-object-mfa-level) | ## Delete Guild Role % DELETE /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/roles/{role.id#DOCS_TOPICS_PERMISSIONS/role-object} @@ -1165,7 +1166,7 @@ By default, prune will not remove users with roles. You can optionally include s ###### Query String Params | Field | Type | Description | Default | -| ------------- | ------------------------------------------- | ---------------------------------------- | ------- | +|---------------|---------------------------------------------|------------------------------------------|---------| | days | integer | number of days to count prune for (1-30) | 7 | | include_roles | string; comma-delimited array of snowflakes | role(s) to include | none | @@ -1181,7 +1182,7 @@ By default, prune will not remove users with roles. You can optionally include s ###### JSON Params | Field | Type | Description | Default | -| ------------------- | ------------------- | ---------------------------------------------------------- | ------- | +|---------------------|---------------------|------------------------------------------------------------|---------| | days | integer | number of days to prune (1-30) | 7 | | compute_prune_count | boolean | whether `pruned` is returned, discouraged for large guilds | true | | include_roles | array of snowflakes | role(s) to include | none | @@ -1215,14 +1216,14 @@ Returns a [guild widget settings](#DOCS_RESOURCES_GUILD/guild-widget-settings-ob ## Modify Guild Widget % PATCH /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/widget -Modify a [guild widget settings](#DOCS_RESOURCES_GUILD/guild-widget-settings-object) object for the guild. All attributes may be passed in with JSON and modified. Requires the `MANAGE_GUILD` permission. Returns the updated [guild widget settings](#DOCS_RESOURCES_GUILD/guild-widget-settings-object) object. +Modify a [guild widget settings](#DOCS_RESOURCES_GUILD/guild-widget-settings-object) object for the guild. All attributes may be passed in with JSON and modified. Requires the `MANAGE_GUILD` permission. Returns the updated [guild widget settings](#DOCS_RESOURCES_GUILD/guild-widget-settings-object) object. Fires a [Guild Update](#DOCS_TOPICS_GATEWAY_EVENTS/guild-update) Gateway event. > info > This endpoint supports the `X-Audit-Log-Reason` header. ## Get Guild Widget % GET /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/widget.json -Returns the [widget](#DOCS_RESOURCES_GUILD/guild-widget-object) for the guild. +Returns the [widget](#DOCS_RESOURCES_GUILD/guild-widget-object) for the guild. Fires an [Invite Create](#DOCS_TOPICS_GATEWAY_EVENTS/invite-create) Gateway event when an invite channel is defined and a new [Invite](#DOCS_RESOURCES_INVITE/invite-object) is generated. ## Get Guild Vanity URL % GET /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/vanity-url @@ -1247,13 +1248,13 @@ Returns a PNG image widget for the guild. Requires no permissions or authenticat ###### Query String Params | Field | Type | Description | Default | -| ----- | ------ | ---------------------------------------------- | ------- | +|-------|--------|------------------------------------------------|---------| | style | string | style of the widget image returned (see below) | shield | ###### Widget Style Options | Value | Description | Example | -| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | +|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------| | shield | shield style widget with Discord icon and guild members online count | [Example](https://discord.com/api/guilds/81384788765712384/widget.png?style=shield) | | banner1 | large image with guild icon, name and online count. "POWERED BY DISCORD" as the footer of the widget | [Example](https://discord.com/api/guilds/81384788765712384/widget.png?style=banner1) | | banner2 | smaller widget style with guild icon, name and online count. Split on the right with Discord logo | [Example](https://discord.com/api/guilds/81384788765712384/widget.png?style=banner2) | @@ -1277,7 +1278,7 @@ Modify the guild's [Welcome Screen](#DOCS_RESOURCES_GUILD/welcome-screen-object) ###### JSON Params | Field | Type | Description | -| ---------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | +|------------------|-------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------| | enabled | boolean | whether the welcome screen is enabled | | welcome_channels | array of [welcome screen channel](#DOCS_RESOURCES_GUILD/welcome-screen-object-welcome-screen-channel-structure) objects | channels linked in the welcome screen and their display options | | description | string | the server description to show in the welcome screen | @@ -1299,7 +1300,7 @@ Modifies the onboarding configuration of the guild. Returns a 200 with the [Onbo ###### JSON Params | Field | Type | Description | -| ------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | +|---------------------|-----------------------------------------------------------------------------------------------------------------|------------------------------------------------------------| | prompts | array of [onboarding prompt](#DOCS_RESOURCES_GUILD/guild-onboarding-object-onboarding-prompt-structure) objects | Prompts shown during onboarding and in customize community | | default_channel_ids | array of snowflakes | Channel IDs that members get opted into automatically | | enabled | boolean | Whether onboarding is enabled in the guild | @@ -1312,7 +1313,7 @@ Updates the current user's voice state. Returns `204 No Content` on success. Fir ###### JSON Params | Field | Type | Description | -| --------------------------- | ------------------ | ---------------------------------------------- | +|-----------------------------|--------------------|------------------------------------------------| | channel_id? | snowflake | the id of the channel the user is currently in | | suppress? | boolean | toggles the user's suppress state | | request_to_speak_timestamp? | ?ISO8601 timestamp | sets the user's request to speak | @@ -1334,7 +1335,7 @@ Updates another user's voice state. Fires a [Voice State Update](#DOCS_TOPICS_GA ###### JSON Params | Field | Type | Description | -| ---------- | --------- | ---------------------------------------------- | +|------------|-----------|------------------------------------------------| | channel_id | snowflake | the id of the channel the user is currently in | | suppress? | boolean | toggles the user's suppress state | diff --git a/docs/resources/Guild_Scheduled_Event.md b/docs/resources/Guild_Scheduled_Event.md index 8b89b99ff9..d52cdd45c1 100644 --- a/docs/resources/Guild_Scheduled_Event.md +++ b/docs/resources/Guild_Scheduled_Event.md @@ -7,7 +7,7 @@ A representation of a scheduled event in a [guild](#DOCS_RESOURCES_GUILD/). ###### Guild Scheduled Event Structure | Field | Type | Description | -| --------------------- | ------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------|--------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | id | snowflake | the id of the scheduled event | | guild_id | snowflake | the guild id which the scheduled event belongs to | | channel_id ** | ?snowflake | the channel id in which the scheduled event will be hosted, or `null` if [scheduled entity type](#DOCS_RESOURCES_GUILD_SCHEDULED_EVENT/guild-scheduled-event-object-guild-scheduled-event-entity-types) is `EXTERNAL` | @@ -32,14 +32,14 @@ A representation of a scheduled event in a [guild](#DOCS_RESOURCES_GUILD/). ###### Guild Scheduled Event Privacy Level -| Level | Value | Description | -| ---------- | ----- | -------------------------------------------------------- | -| GUILD_ONLY | 2 | the scheduled event is only accessible to guild members | +| Level | Value | Description | +|------------|-------|---------------------------------------------------------| +| GUILD_ONLY | 2 | the scheduled event is only accessible to guild members | ###### Guild Scheduled Event Entity Types | Type | Value | -| -------------- | ----- | +|----------------|-------| | STAGE_INSTANCE | 1 | | VOICE | 2 | | EXTERNAL | 3 | @@ -55,10 +55,10 @@ The following table shows field requirements based on current entity type. `-` : No strict requirements | Entity Type | channel_id | entity_metadata | scheduled_end_time | -| -------------- | ---------- | --------------- | ------------------ | -| STAGE_INSTANCE | value | null | - | -| VOICE | value | null | - | -| EXTERNAL | null | value * | value | +|----------------|------------|-----------------|--------------------| +| STAGE_INSTANCE | value | null | - | +| VOICE | value | null | - | +| EXTERNAL | null | value * | value | \* `entity_metadata` with a non-null `location` must be provided @@ -66,7 +66,7 @@ The following table shows field requirements based on current entity type. ###### Guild Scheduled Event Status | Type | Value | -| ----------- | ----- | +|-------------|-------| | SCHEDULED | 1 | | ACTIVE | 2 | | COMPLETED * | 3 | @@ -85,9 +85,9 @@ SCHEDULED --> CANCELED ###### Guild Scheduled Event Entity Metadata -| Field | Type | Description | -| ------------ | ------------------- | ---------------------------------------- | -| location? * | string | location of the event (1-100 characters) | +| Field | Type | Description | +|-------------|--------|------------------------------------------| +| location? * | string | location of the event (1-100 characters) | \* [required](#DOCS_RESOURCES_GUILD_SCHEDULED_EVENT/guild-scheduled-event-object-guild-scheduled-event-entity-metadata) for events with `'entity_type': EXTERNAL` @@ -95,11 +95,11 @@ SCHEDULED --> CANCELED ###### Guild Scheduled Event User Structure -| Field | Type | Description | -| -------------------- | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- | -| guild_scheduled_event_id | snowflake | the scheduled event id which the user subscribed to | -| user | [user](#DOCS_RESOURCES_USER/user-object) | user which subscribed to an event | -| member? | [guild member](#DOCS_RESOURCES_GUILD/guild-member-object) | guild member data for this user for the guild which this event belongs to, if any | +| Field | Type | Description | +|--------------------------|-----------------------------------------------------------|-----------------------------------------------------------------------------------| +| guild_scheduled_event_id | snowflake | the scheduled event id which the user subscribed to | +| user | [user](#DOCS_RESOURCES_USER/user-object) | user which subscribed to an event | +| member? | [guild member](#DOCS_RESOURCES_GUILD/guild-member-object) | guild member data for this user for the guild which this event belongs to, if any | ## List Scheduled Events for Guild % GET /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/scheduled-events @@ -109,7 +109,7 @@ Returns a list of [guild scheduled event](#DOCS_RESOURCES_GUILD_SCHEDULED_EVENT/ ###### Query String Params | Field | Type | Description | -| ---------------- | ------- | ------------------------------------------------ | +|------------------|---------|--------------------------------------------------| | with_user_count? | boolean | include number of users subscribed to each event | ## Create Guild Scheduled Event % POST /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/scheduled-events @@ -124,17 +124,17 @@ Create a guild scheduled event in the guild. Returns a [guild scheduled event](# ###### JSON Params -| Field | Type | Description | -| ---------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | -| channel_id? * | snowflake * | the channel id of the scheduled event. | -| entity_metadata? ** | [entity metadata](#DOCS_RESOURCES_GUILD_SCHEDULED_EVENT/guild-scheduled-event-object-guild-scheduled-event-entity-metadata) | the entity metadata of the scheduled event | -| name | string | the name of the scheduled event | -| privacy_level | [privacy level](#DOCS_RESOURCES_GUILD_SCHEDULED_EVENT/guild-scheduled-event-object-guild-scheduled-event-privacy-level) | the privacy level of the scheduled event | -| scheduled_start_time | ISO8601 timestamp | the time to schedule the scheduled event | -| scheduled_end_time? ** | ISO8601 timestamp | the time when the scheduled event is scheduled to end | -| description? | string | the description of the scheduled event | -| entity_type | [entity type](#DOCS_RESOURCES_GUILD_SCHEDULED_EVENT/guild-scheduled-event-object-guild-scheduled-event-entity-types) | the entity type of the scheduled event | -| image? | [image data](#DOCS_REFERENCE/image-data) | the cover image of the scheduled event | +| Field | Type | Description | +|------------------------|-----------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------| +| channel_id? * | snowflake * | the channel id of the scheduled event. | +| entity_metadata? ** | [entity metadata](#DOCS_RESOURCES_GUILD_SCHEDULED_EVENT/guild-scheduled-event-object-guild-scheduled-event-entity-metadata) | the entity metadata of the scheduled event | +| name | string | the name of the scheduled event | +| privacy_level | [privacy level](#DOCS_RESOURCES_GUILD_SCHEDULED_EVENT/guild-scheduled-event-object-guild-scheduled-event-privacy-level) | the privacy level of the scheduled event | +| scheduled_start_time | ISO8601 timestamp | the time to schedule the scheduled event | +| scheduled_end_time? ** | ISO8601 timestamp | the time when the scheduled event is scheduled to end | +| description? | string | the description of the scheduled event | +| entity_type | [entity type](#DOCS_RESOURCES_GUILD_SCHEDULED_EVENT/guild-scheduled-event-object-guild-scheduled-event-entity-types) | the entity type of the scheduled event | +| image? | [image data](#DOCS_REFERENCE/image-data) | the cover image of the scheduled event | \* Optional for events with `'entity_type': EXTERNAL` @@ -147,7 +147,7 @@ Get a guild scheduled event. Returns a [guild scheduled event](#DOCS_RESOURCES_G ###### Query String Params | Field | Type | Description | -| ---------------- | ------- | ------------------------------------------------ | +|------------------|---------|--------------------------------------------------| | with_user_count? | boolean | include number of users subscribed to this event | ## Modify Guild Scheduled Event % PATCH /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/scheduled-events/{guild_scheduled_event.id#DOCS_RESOURCES_GUILD_SCHEDULED_EVENT/guild-scheduled-event-object} @@ -166,7 +166,7 @@ Modify a guild scheduled event. Returns the modified [guild scheduled event](#DO ###### JSON Params | Field | Type | Description | -| --------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | +|-----------------------|------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| | channel_id? * | ?snowflake | the channel id of the scheduled event, set to `null` if changing entity type to `EXTERNAL` | | entity_metadata? | ?[entity metadata](#DOCS_RESOURCES_GUILD_SCHEDULED_EVENT/guild-scheduled-event-object-guild-scheduled-event-entity-metadata) | the entity metadata of the scheduled event | | name? | string | the name of the scheduled event | @@ -194,12 +194,12 @@ Get a list of guild scheduled event users subscribed to a guild scheduled event. ###### Query String Params -| Field | Type | Description | Default | -| ------------ | ------- | ------------------------------------------------------------------------------ | ------- | -| limit? | number | number of users to return (up to maximum 100) | 100 | -| with_member? | boolean | include guild member data if it exists | false | -| before? * | snowflake | consider only users before given user id | null | -| after? * | snowflake | consider only users after given user id | null | +| Field | Type | Description | Default | +|--------------|-----------|-----------------------------------------------|---------| +| limit? | number | number of users to return (up to maximum 100) | 100 | +| with_member? | boolean | include guild member data if it exists | false | +| before? * | snowflake | consider only users before given user id | null | +| after? * | snowflake | consider only users after given user id | null | \* Provide a user id to `before` and `after` for pagination. Users will always be returned in ascending order by `user_id`. If both `before` and `after` are provided, only `before` is respected. Fetching users in-between `before` and `after` is not supported. diff --git a/docs/resources/Invite.md b/docs/resources/Invite.md index fce074eb08..5f100dd235 100644 --- a/docs/resources/Invite.md +++ b/docs/resources/Invite.md @@ -7,7 +7,7 @@ Represents a code that when used, adds a user to a guild or group DM channel. ###### Invite Structure | Field | Type | Description | -| --------------------------- | -------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------|----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------| | code | string | the invite code (unique ID) | | guild? | partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object | the guild this invite is for | | channel | ?partial [channel](#DOCS_RESOURCES_CHANNEL/channel-object) object | the channel this invite is for | @@ -75,13 +75,13 @@ Extra information about an invite, will extend the [invite](#DOCS_RESOURCES_INVI ###### Invite Metadata Structure -| Field | Type | Description | -| ---------- | ----------------------------------------------- | ---------------------------------------------------- | -| uses | integer | number of times this invite has been used | -| max_uses | integer | max number of times this invite can be used | -| max_age | integer | duration (in seconds) after which the invite expires | -| temporary | boolean | whether this invite only grants temporary membership | -| created_at | ISO8601 timestamp | when this invite was created | +| Field | Type | Description | +|------------|-------------------|------------------------------------------------------| +| uses | integer | number of times this invite has been used | +| max_uses | integer | max number of times this invite can be used | +| max_age | integer | duration (in seconds) after which the invite expires | +| temporary | boolean | whether this invite only grants temporary membership | +| created_at | ISO8601 timestamp | when this invite was created | ###### Example Invite Metadata @@ -137,7 +137,7 @@ Returns an [invite](#DOCS_RESOURCES_INVITE/invite-object) object for the given c ###### Query String Params | Field | Type | Description | -| ------------------------- | --------- | ----------------------------------------------------------- | +|---------------------------|-----------|-------------------------------------------------------------| | with_counts? | boolean | whether the invite should contain approximate member counts | | with_expiration? | boolean | whether the invite should contain the expiration date | | guild_scheduled_event_id? | snowflake | the guild scheduled event to include with the invite | diff --git a/docs/resources/Stage_Instance.md b/docs/resources/Stage_Instance.md index 7c6e750ba3..dea873cbe3 100644 --- a/docs/resources/Stage_Instance.md +++ b/docs/resources/Stage_Instance.md @@ -7,7 +7,7 @@ A _Stage Instance_ holds information about a live stage. ###### Stage Instance Structure | Field | Type | Description | -| ------------------------ | ---------- | ------------------------------------------------------------------------------------------------------------- | +|--------------------------|------------|---------------------------------------------------------------------------------------------------------------| | id | snowflake | The id of this Stage instance | | guild_id | snowflake | The guild id of the associated Stage channel | | channel_id | snowflake | The id of the associated Stage channel | @@ -18,10 +18,10 @@ A _Stage Instance_ holds information about a live stage. ###### Privacy Level -| Level | Value | Description | -| ---------- | ----- | ------------------------------------------------------------------- | -| PUBLIC | 1 | The Stage instance is visible publicly. (deprecated) | -| GUILD_ONLY | 2 | The Stage instance is visible to only guild members. | +| Level | Value | Description | +|------------|-------|------------------------------------------------------| +| PUBLIC | 1 | The Stage instance is visible publicly. (deprecated) | +| GUILD_ONLY | 2 | The Stage instance is visible to only guild members. | ###### Example Stage Instance @@ -50,8 +50,6 @@ Below are some definitions related to stages. - `MOVE_MEMBERS` - **Topic**: This is the blurb that gets shown below the channel's name, among other places. - **Public**: A Stage instance is public when it has a `privacy_level` of `PUBLIC`. While a guild has a public Stage instance: - - The guild will be lurkable. - - Lurkers may join any Stage channel with a public Stage instance. - Users in the Stage can have the Stage show in their [activities](#DOCS_TOPICS_GATEWAY_EVENTS/presence). - [Invites](#DOCS_RESOURCES_INVITE/invite-object) to the Stage channel will have the `stage_instance` field. @@ -71,11 +69,12 @@ Requires the user to be a moderator of the Stage channel. ###### JSON Params | Field | Type | Description | -| --------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------|-----------|------------------------------------------------------------------------------------------------------------------------------------| | channel_id | snowflake | The id of the Stage channel | | topic | string | The topic of the Stage instance (1-120 characters) | | privacy_level? | integer | The [privacy level](#DOCS_RESOURCES_STAGE_INSTANCE/stage-instance-object-privacy-level) of the Stage instance (default GUILD_ONLY) | | send_start_notification? \* | boolean | Notify @everyone that a Stage instance has started | +| guild_scheduled_event_id? | snowflake | The guild scheduled event associated with this Stage instance | \* The stage moderator must have the `MENTION_EVERYONE` permission for this notification to be sent. @@ -95,7 +94,7 @@ Requires the user to be a moderator of the Stage channel. ###### JSON Params | Field | Type | Description | -| -------------- | ------- | ------------------------------------------------------------------------------------------------------------- | +|----------------|---------|---------------------------------------------------------------------------------------------------------------| | topic? | string | The topic of the Stage instance (1-120 characters) | | privacy_level? | integer | The [privacy level](#DOCS_RESOURCES_STAGE_INSTANCE/stage-instance-object-privacy-level) of the Stage instance | diff --git a/docs/resources/Sticker.md b/docs/resources/Sticker.md index 74c561e238..d6f8170a3b 100644 --- a/docs/resources/Sticker.md +++ b/docs/resources/Sticker.md @@ -6,35 +6,35 @@ Represents a sticker that can be sent in messages. ###### Sticker Structure -| Field | Type | Description | -| ----------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| id | snowflake | [id of the sticker](#DOCS_REFERENCE/image-formatting) | -| pack_id? | snowflake | for standard stickers, id of the pack the sticker is from | -| name | string | name of the sticker | -| description | ?string | description of the sticker | -| tags\* | string | autocomplete/suggestion tags for the sticker (max 200 characters) | -| asset? | string | **Deprecated** previously the sticker asset hash, now an empty string | -| type | integer | [type of sticker](#DOCS_RESOURCES_STICKER/sticker-object-sticker-types) | -| format_type | integer | [type of sticker format](#DOCS_RESOURCES_STICKER/sticker-object-sticker-format-types) | -| available? | boolean | whether this guild sticker can be used, may be false due to loss of Server Boosts | -| guild_id? | snowflake | id of the guild that owns this sticker | -| user? | [user](#DOCS_RESOURCES_USER/user-object) object | the user that uploaded the guild sticker | -| sort_value? | integer | the standard sticker's sort order within its pack | +| Field | Type | Description | +|-------------|-------------------------------------------------|---------------------------------------------------------------------------------------| +| id | snowflake | [id of the sticker](#DOCS_REFERENCE/image-formatting) | +| pack_id? | snowflake | for standard stickers, id of the pack the sticker is from | +| name | string | name of the sticker | +| description | ?string | description of the sticker | +| tags\* | string | autocomplete/suggestion tags for the sticker (max 200 characters) | +| asset? | string | **Deprecated** previously the sticker asset hash, now an empty string | +| type | integer | [type of sticker](#DOCS_RESOURCES_STICKER/sticker-object-sticker-types) | +| format_type | integer | [type of sticker format](#DOCS_RESOURCES_STICKER/sticker-object-sticker-format-types) | +| available? | boolean | whether this guild sticker can be used, may be false due to loss of Server Boosts | +| guild_id? | snowflake | id of the guild that owns this sticker | +| user? | [user](#DOCS_RESOURCES_USER/user-object) object | the user that uploaded the guild sticker | +| sort_value? | integer | the standard sticker's sort order within its pack | \* A comma separated list of keywords is the format used in this field by standard stickers, but this is just a convention. Incidentally the client will always use a name generated from an emoji as the value of this field when creating or modifying a guild sticker. ###### Sticker Types -| Type | Value | Description | -| -------- | ----- | ----------------------------------------------------------------------------- | -| STANDARD | 1 | an official sticker in a pack, part of Nitro or in a removed purchasable pack | -| GUILD | 2 | a sticker uploaded to a guild for the guild's members | +| Type | Value | Description | +|----------|-------|-------------------------------------------------------| +| STANDARD | 1 | an official sticker in a pack | +| GUILD | 2 | a sticker uploaded to a guild for the guild's members | ###### Sticker Format Types | Type | Value | -| ------ | ----- | +|--------|-------| | PNG | 1 | | APNG | 2 | | LOTTIE | 3 | @@ -63,7 +63,7 @@ The smallest amount of data required to render a sticker. A partial sticker obje ###### Sticker Item Structure | Field | Type | Description | -| ----------- | --------- | ------------------------------------------------------------------------------------- | +|-------------|-----------|---------------------------------------------------------------------------------------| | id | snowflake | id of the sticker | | name | string | name of the sticker | | format_type | integer | [type of sticker format](#DOCS_RESOURCES_STICKER/sticker-object-sticker-format-types) | @@ -75,7 +75,7 @@ Represents a pack of standard stickers. ###### Sticker Pack Structure | Field | Type | Description | -| ---------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------- | +|-------------------|--------------------------------------------------------------------|---------------------------------------------------------------------------| | id | snowflake | id of the sticker pack | | stickers | array of [sticker](#DOCS_RESOURCES_STICKER/sticker-object) objects | the stickers in the pack | | name | string | name of the sticker pack | @@ -102,14 +102,14 @@ Represents a pack of standard stickers. Returns a [sticker](#DOCS_RESOURCES_STICKER/sticker-object) object for the given sticker ID. -## List Nitro Sticker Packs % GET /sticker-packs +## List Sticker Packs % GET /sticker-packs -Returns the list of sticker packs available to Nitro subscribers. +Returns a list of available sticker packs. ###### Response Structure | Field | Type | -| ------------- | ---------------------------------------------------------------------------- | +|---------------|------------------------------------------------------------------------------| | sticker_packs | array of [sticker pack](#DOCS_RESOURCES_STICKER/sticker-pack-object) objects | ## List Guild Stickers % GET /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/stickers @@ -134,14 +134,15 @@ Every guilds has five free sticker slots by default, and each Boost level will g > warn > Uploaded stickers are constrained to 5 seconds in length for animated stickers, and 320 x 320 pixels. + ###### Form Params -| Field | Type | Description | -| ----------- | ------------- | -------------------------------------------------------------------------------------------- | -| name | string | name of the sticker (2-30 characters) | -| description | string | description of the sticker (empty or 2-100 characters) | -| tags | string | autocomplete/suggestion tags for the sticker (max 200 characters) | -| file | file contents | the sticker file to upload, must be a PNG, APNG, GIF, or Lottie JSON file, max 512 KB | +| Field | Type | Description | +|-------------|---------------|----------------------------------------------------------------------------------------| +| name | string | name of the sticker (2-30 characters) | +| description | string | description of the sticker (empty or 2-100 characters) | +| tags | string | autocomplete/suggestion tags for the sticker (max 200 characters) | +| file | file contents | the sticker file to upload, must be a PNG, APNG, GIF, or Lottie JSON file, max 512 KiB | ## Modify Guild Sticker % PATCH /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/stickers/{sticker.id#DOCS_RESOURCES_STICKER/sticker-object} @@ -155,11 +156,11 @@ Modify the given sticker. Requires the `MANAGE_GUILD_EXPRESSIONS` permission. Re ###### JSON Params -| Field | Type | Description | -| ----------- | ------- | -------------------------------------------------------------------------------------------- | -| name | string | name of the sticker (2-30 characters) | -| description | ?string | description of the sticker (2-100 characters) | -| tags | string | autocomplete/suggestion tags for the sticker (max 200 characters) | +| Field | Type | Description | +|-------------|---------|-------------------------------------------------------------------| +| name | string | name of the sticker (2-30 characters) | +| description | ?string | description of the sticker (2-100 characters) | +| tags | string | autocomplete/suggestion tags for the sticker (max 200 characters) | ## Delete Guild Sticker % DELETE /guilds/{guild.id#DOCS_RESOURCES_GUILD/guild-object}/stickers/{sticker.id#DOCS_RESOURCES_STICKER/sticker-object} diff --git a/docs/resources/User.md b/docs/resources/User.md index 9b981e5595..b3d61312d6 100644 --- a/docs/resources/User.md +++ b/docs/resources/User.md @@ -25,7 +25,7 @@ There are other rules and restrictions not shared here for the sake of spam and ###### User Structure | Field | Type | Description | Required OAuth2 Scope | -| ------------------ | --------- | ---------------------------------------------------------------------------------------------------- | --------------------- | +|--------------------|-----------|------------------------------------------------------------------------------------------------------|-----------------------| | id | snowflake | the user's id | identify | | username | string | the user's username, not unique across the platform | identify | | discriminator | string | the user's Discord-tag | identify | @@ -65,7 +65,7 @@ There are other rules and restrictions not shared here for the sake of spam and ###### User Flags | Value | Name | Description | -| ------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | +|---------|--------------------------|------------------------------------------------------------------------------------------------------------------------------------------------| | 1 << 0 | STAFF | Discord Employee | | 1 << 1 | PARTNER | Partnered Server Owner | | 1 << 2 | HYPESQUAD | HypeSquad Events Member | @@ -87,7 +87,7 @@ There are other rules and restrictions not shared here for the sake of spam and Premium types denote the level of premium a user has. Visit the [Nitro](https://discord.com/nitro) page to learn more about the premium plans we currently offer. | Value | Name | -| ----- | ------------- | +|-------|---------------| | 0 | None | | 1 | Nitro Classic | | 2 | Nitro | @@ -100,7 +100,7 @@ The connection object that the user has attached. ###### Connection Structure | Field | Type | Description | -| ------------- | ------- | ---------------------------------------------------------------------------------------- | +|---------------|---------|------------------------------------------------------------------------------------------| | id | string | id of the connection account | | name | string | the username of the connection account | | type | string | the [service](#DOCS_RESOURCES_USER/connection-object-services) of this connection | @@ -115,7 +115,7 @@ The connection object that the user has attached. ###### Services | Value | Name | -| --------------- | ------------------- | +|-----------------|---------------------| | battlenet | Battle.net | | ebay | eBay | | epicgames | Epic Games | @@ -132,7 +132,7 @@ The connection object that the user has attached. | steam | Steam | | tiktok | TikTok | | twitch | Twitch | -| twitter | Twitter | +| twitter | X (Twitter) | | xbox | Xbox | | youtube | YouTube | @@ -141,7 +141,7 @@ The connection object that the user has attached. ###### Visibility Types | Value | Name | Description | -| ----- | -------- | ------------------------------------------------ | +|-------|----------|--------------------------------------------------| | 0 | None | invisible to everyone except the user themselves | | 1 | Everyone | visible to everyone | @@ -152,7 +152,7 @@ The role connection object that an application has attached to a user. ###### Application Role Connection Structure | Field | Type | Description | -| ----------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | platform_name | ?string | the vanity name of the platform a bot has connected (max 50 characters) | | platform_username | ?string | the username on the platform a bot has connected (max 100 characters) | | metadata | object | object mapping [application role connection metadata](#DOCS_RESOURCES_APPLICATION_ROLE_CONNECTION_METADATA/application-role-connection-metadata-object) keys to their `string`-ified value (max 100 characters) for the user on the platform a bot has connected | @@ -175,13 +175,13 @@ Modify the requester's user account settings. Returns a [user](#DOCS_RESOURCES_U ###### JSON Params | Field | Type | Description | -| -------- | ----------------------------------------- | -------------------------------------------------------------------------------- | +|----------|-------------------------------------------|----------------------------------------------------------------------------------| | username | string | user's username, if changed may cause the user's discriminator to be randomized. | | avatar | ?[image data](#DOCS_REFERENCE/image-data) | if passed, modifies the user's avatar | ## Get Current User Guilds % GET /users/@me/guilds -Returns a list of partial [guild](#DOCS_RESOURCES_GUILD/guild-object) objects the current user is a member of. Requires the `guilds` OAuth2 scope. +Returns a list of partial [guild](#DOCS_RESOURCES_GUILD/guild-object) objects the current user is a member of. For OAuth2, requires the `guilds` scope. ###### Example Partial Guild @@ -204,7 +204,7 @@ Returns a list of partial [guild](#DOCS_RESOURCES_GUILD/guild-object) objects th ###### Query String Params | Field | Type | Description | Required | Default | -| ----------- | --------- | ---------------------------------------------------------- | -------- | ------- | +|-------------|-----------|------------------------------------------------------------|----------|---------| | before | snowflake | get guilds before this guild ID | false | absent | | after | snowflake | get guilds after this guild ID | false | absent | | limit | integer | max number of guilds to return (1-200) | false | 200 | @@ -228,7 +228,7 @@ Create a new DM channel with a user. Returns a [DM channel](#DOCS_RESOURCES_CHAN ###### JSON Params | Field | Type | Description | -| ------------ | --------- | --------------------------------------- | +|--------------|-----------|-----------------------------------------| | recipient_id | snowflake | the recipient to open a DM channel with | ## Create Group DM % POST /users/@me/channels @@ -241,26 +241,26 @@ Create a new group DM channel with multiple users. Returns a [DM channel](#DOCS_ ###### JSON Params | Field | Type | Description | -| ------------- | ---------------- | ---------------------------------------------------------------------- | +|---------------|------------------|------------------------------------------------------------------------| | access_tokens | array of strings | access tokens of users that have granted your app the `gdm.join` scope | | nicks | dict | a dictionary of user ids to their respective nicknames | -## Get User Connections % GET /users/@me/connections +## Get Current User Connections % GET /users/@me/connections Returns a list of [connection](#DOCS_RESOURCES_USER/connection-object) objects. Requires the `connections` OAuth2 scope. -## Get User Application Role Connection % GET /users/@me/applications/{application.id#DOCS_RESOURCES_APPLICATION/application-object}/role-connection +## Get Current User Application Role Connection % GET /users/@me/applications/{application.id#DOCS_RESOURCES_APPLICATION/application-object}/role-connection Returns the [application role connection](#DOCS_RESOURCES_USER/application-role-connection-object) for the user. Requires an OAuth2 access token with `role_connections.write` scope for the application specified in the path. -## Update User Application Role Connection % PUT /users/@me/applications/{application.id#DOCS_RESOURCES_APPLICATION/application-object}/role-connection +## Update Current User Application Role Connection % PUT /users/@me/applications/{application.id#DOCS_RESOURCES_APPLICATION/application-object}/role-connection Updates and returns the [application role connection](#DOCS_RESOURCES_USER/application-role-connection-object) for the user. Requires an OAuth2 access token with `role_connections.write` scope for the application specified in the path. ###### JSON Params | Field | Type | Description | -| ------------------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|--------------------|--------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | platform_name? | string | the vanity name of the platform a bot has connected (max 50 characters) | | platform_username? | string | the username on the platform a bot has connected (max 100 characters) | | metadata? | object | object mapping [application role connection metadata](#DOCS_RESOURCES_APPLICATION_ROLE_CONNECTION_METADATA/application-role-connection-metadata-object) keys to their `string`-ified value (max 100 characters) for the user on the platform a bot has connected | diff --git a/docs/resources/Voice.md b/docs/resources/Voice.md index b08b699834..5fde22e159 100644 --- a/docs/resources/Voice.md +++ b/docs/resources/Voice.md @@ -7,7 +7,7 @@ Used to represent a user's voice connection status. ###### Voice State Structure | Field | Type | Description | -| -------------------------- | ---------------------------------------------------------------- | ------------------------------------------------- | +|----------------------------|------------------------------------------------------------------|---------------------------------------------------| | guild_id? | snowflake | the guild id this voice state is for | | channel_id | ?snowflake | the channel id this user is connected to | | user_id | snowflake | the user id this voice state is for | @@ -43,7 +43,7 @@ Used to represent a user's voice connection status. ###### Voice Region Structure | Field | Type | Description | -| ---------- | ------- | --------------------------------------------------------------------- | +|------------|---------|-----------------------------------------------------------------------| | id | string | unique ID for the region | | name | string | name of the region | | optimal | boolean | true for a single server that is closest to the current user's client | diff --git a/docs/resources/Webhook.md b/docs/resources/Webhook.md index fe1ef66078..d45e7b1b8c 100644 --- a/docs/resources/Webhook.md +++ b/docs/resources/Webhook.md @@ -8,27 +8,27 @@ Used to represent a webhook. ###### Webhook Structure -| Field | Type | Description | -| ------------------ | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | -| id | snowflake | the id of the webhook | -| type | integer | the [type](#DOCS_RESOURCES_WEBHOOK/webhook-object-webhook-types) of the webhook | -| guild_id? | ?snowflake | the guild id this webhook is for, if any | -| channel_id | ?snowflake | the channel id this webhook is for, if any | -| user? | [user](#DOCS_RESOURCES_USER/user-object) object | the user this webhook was created by (not returned when getting a webhook with its token) | -| name | ?string | the default name of the webhook | -| avatar | ?string | the default user avatar [hash](#DOCS_REFERENCE/image-formatting) of the webhook | -| token? | string | the secure token of the webhook (returned for Incoming Webhooks) | -| application_id | ?snowflake | the bot/OAuth2 application that created this webhook | -| source_guild? * | partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object | the guild of the channel that this webhook is following (returned for Channel Follower Webhooks) | -| source_channel? * | partial [channel](#DOCS_RESOURCES_CHANNEL/channel-object) object | the channel that this webhook is following (returned for Channel Follower Webhooks) | -| url? | string | the url used for executing the webhook (returned by the [webhooks](#DOCS_TOPICS_OAUTH2/webhooks) OAuth2 flow) | +| Field | Type | Description | +|-------------------|------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------| +| id | snowflake | the id of the webhook | +| type | integer | the [type](#DOCS_RESOURCES_WEBHOOK/webhook-object-webhook-types) of the webhook | +| guild_id? | ?snowflake | the guild id this webhook is for, if any | +| channel_id | ?snowflake | the channel id this webhook is for, if any | +| user? | [user](#DOCS_RESOURCES_USER/user-object) object | the user this webhook was created by (not returned when getting a webhook with its token) | +| name | ?string | the default name of the webhook | +| avatar | ?string | the default user avatar [hash](#DOCS_REFERENCE/image-formatting) of the webhook | +| token? | string | the secure token of the webhook (returned for Incoming Webhooks) | +| application_id | ?snowflake | the bot/OAuth2 application that created this webhook | +| source_guild? * | partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object | the guild of the channel that this webhook is following (returned for Channel Follower Webhooks) | +| source_channel? * | partial [channel](#DOCS_RESOURCES_CHANNEL/channel-object) object | the channel that this webhook is following (returned for Channel Follower Webhooks) | +| url? | string | the url used for executing the webhook (returned by the [webhooks](#DOCS_TOPICS_OAUTH2/webhooks) OAuth2 flow) | \* These fields will be absent if the webhook creator has since lost access to the guild where the followed channel resides ###### Webhook Types | Value | Name | Description | -| ----- | ---------------- | -------------------------------------------------------------------------------------------------------------- | +|-------|------------------|----------------------------------------------------------------------------------------------------------------| | 1 | Incoming | Incoming Webhooks can post messages to channels with a generated token | | 2 | Channel Follower | Channel Follower Webhooks are internal webhooks used with Channel Following to post new messages into channels | | 3 | Application | Application webhooks are webhooks used with Interactions | @@ -113,7 +113,7 @@ An error will be returned if a webhook name (`name`) is not valid. A webhook nam ###### JSON Params | Field | Type | Description | -| ------- | ----------------------------------------- | ------------------------------------- | +|---------|-------------------------------------------|---------------------------------------| | name | string | name of the webhook (1-80 characters) | | avatar? | ?[image data](#DOCS_REFERENCE/image-data) | image for the default webhook avatar | @@ -146,7 +146,7 @@ Modify a webhook. Requires the `MANAGE_WEBHOOKS` permission. Returns the updated ###### JSON Params | Field | Type | Description | -| ---------- | ----------------------------------------- | -------------------------------------------------- | +|------------|-------------------------------------------|----------------------------------------------------| | name | string | the default name of the webhook | | avatar | ?[image data](#DOCS_REFERENCE/image-data) | image for the default webhook avatar | | channel_id | snowflake | the new channel id this webhook should be moved to | @@ -181,27 +181,27 @@ Refer to [Uploading Files](#DOCS_REFERENCE/uploading-files) for details on attac ###### Query String Params -| Field | Type | Description | Required | -| ----- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -| wait | boolean | waits for server confirmation of message send before response, and returns the created message body (defaults to `false`; when `false` a message that is not saved does not return an error) | false | -| thread_id | snowflake | Send a message to the specified thread within a webhook's channel. The thread will automatically be unarchived. | false | +| Field | Type | Description | Required | +|-----------|-----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------| +| wait | boolean | waits for server confirmation of message send before response, and returns the created message body (defaults to `false`; when `false` a message that is not saved does not return an error) | false | +| thread_id | snowflake | Send a message to the specified thread within a webhook's channel. The thread will automatically be unarchived. | false | ###### JSON/Form Params -| Field | Type | Description | Required | -| ---------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | -| content | string | the message contents (up to 2000 characters) | one of content, file, embeds | -| username | string | override the default username of the webhook | false | -| avatar_url | string | override the default avatar of the webhook | false | -| tts | boolean | true if this is a TTS message | false | -| embeds | array of up to 10 [embed](#DOCS_RESOURCES_CHANNEL/embed-object) objects | embedded `rich` content | one of content, file, embeds | -| allowed_mentions | [allowed mention object](#DOCS_RESOURCES_CHANNEL/allowed-mentions-object) | allowed mentions for the message | false | -| components \* | array of [message component](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/component-object) | the components to include with the message | false | -| files[n] \*\* | file contents | the contents of the file being sent | one of content, file, embeds | -| payload_json \*\*| string | JSON encoded body of non-file params | `multipart/form-data` only | -| attachments \*\* | array of partial [attachment](#DOCS_RESOURCES_CHANNEL/attachment-object) objects | attachment objects with filename and description | false | -| flags | integer | [message flags](#DOCS_RESOURCES_CHANNEL/message-object-message-flags) combined as a [bitfield](https://en.wikipedia.org/wiki/Bit_field) (only `SUPPRESS_EMBEDS` can be set) | false | -| thread_name | string | name of thread to create (requires the webhook channel to be a forum channel) | false | +| Field | Type | Description | Required | +|-------------------|--------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------| +| content | string | the message contents (up to 2000 characters) | one of content, file, embeds | +| username | string | override the default username of the webhook | false | +| avatar_url | string | override the default avatar of the webhook | false | +| tts | boolean | true if this is a TTS message | false | +| embeds | array of up to 10 [embed](#DOCS_RESOURCES_CHANNEL/embed-object) objects | embedded `rich` content | one of content, file, embeds | +| allowed_mentions | [allowed mention object](#DOCS_RESOURCES_CHANNEL/allowed-mentions-object) | allowed mentions for the message | false | +| components \* | array of [message component](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/component-object) | the components to include with the message | false | +| files[n] \*\* | file contents | the contents of the file being sent | one of content, file, embeds | +| payload_json \*\* | string | JSON encoded body of non-file params | `multipart/form-data` only | +| attachments \*\* | array of partial [attachment](#DOCS_RESOURCES_CHANNEL/attachment-object) objects | attachment objects with filename and description | false | +| flags | integer | [message flags](#DOCS_RESOURCES_CHANNEL/message-object-message-flags) combined as a [bitfield](https://en.wikipedia.org/wiki/Bit_field) (only `SUPPRESS_EMBEDS` can be set) | false | +| thread_name | string | name of thread to create (requires the webhook channel to be a forum channel) | false | \* Requires an application-owned webhook. @@ -217,7 +217,7 @@ Refer to [Slack's documentation](https://api.slack.com/incoming-webhooks) for mo ###### Query String Params | Field | Type | Description | Required | -| --------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | +|-----------|-----------|-------------------------------------------------------------------------------------------------------------------------------------------------------|----------| | thread_id | snowflake | id of the thread to send the message in | false | | wait | boolean | waits for server confirmation of message send before response (defaults to `true`; when `false` a message that is not saved does not return an error) | false | @@ -228,7 +228,7 @@ Add a new webhook to your GitHub repo (in the repo's settings), and use this end ###### Query String Params | Field | Type | Description | Required | -| --------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | +|-----------|-----------|-------------------------------------------------------------------------------------------------------------------------------------------------------|----------| | thread_id | snowflake | id of the thread to send the message in | false | | wait | boolean | waits for server confirmation of message send before response (defaults to `true`; when `false` a message that is not saved does not return an error) | false | @@ -239,7 +239,7 @@ Returns a previously-sent webhook message from the same token. Returns a [messag ###### Query String Params | Field | Type | Description | Required | -| --------- | --------- | ---------------------------------- | -------- | +|-----------|-----------|------------------------------------|----------| | thread_id | snowflake | id of the thread the message is in | false | ## Edit Webhook Message % PATCH /webhooks/{webhook.id#DOCS_RESOURCES_WEBHOOK/webhook-object}/{webhook.token#DOCS_RESOURCES_WEBHOOK/webhook-object}/messages/{message.id#DOCS_RESOURCES_CHANNEL/message-object} @@ -260,20 +260,20 @@ Any provided files will be **appended** to the message. To remove or replace fil ###### Query String Params | Field | Type | Description | Required | -| --------- | --------- | ---------------------------------- | -------- | +|-----------|-----------|------------------------------------|----------| | thread_id | snowflake | id of the thread the message is in | false | ###### JSON/Form Params -| Field | Type | Description | -| ---------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------------------- | -| content | string | the message contents (up to 2000 characters) | -| embeds | array of up to 10 [embed](#DOCS_RESOURCES_CHANNEL/embed-object) objects | embedded `rich` content | -| allowed_mentions | [allowed mention object](#DOCS_RESOURCES_CHANNEL/allowed-mentions-object) | allowed mentions for the message | -| components \* | array of [message component](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/component-object) | the components to include with the message | -| files[n] \*\* | file contents | the contents of the file being sent/edited | -| payload_json \*\*| string | JSON encoded body of non-file params (multipart/form-data only) | -| attachments \*\* | array of partial [attachment](#DOCS_RESOURCES_CHANNEL/attachment-object) objects | attached files to keep and possible descriptions for new files | +| Field | Type | Description | +|-------------------|--------------------------------------------------------------------------------------|-----------------------------------------------------------------| +| content | string | the message contents (up to 2000 characters) | +| embeds | array of up to 10 [embed](#DOCS_RESOURCES_CHANNEL/embed-object) objects | embedded `rich` content | +| allowed_mentions | [allowed mention object](#DOCS_RESOURCES_CHANNEL/allowed-mentions-object) | allowed mentions for the message | +| components \* | array of [message component](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/component-object) | the components to include with the message | +| files[n] \*\* | file contents | the contents of the file being sent/edited | +| payload_json \*\* | string | JSON encoded body of non-file params (multipart/form-data only) | +| attachments \*\* | array of partial [attachment](#DOCS_RESOURCES_CHANNEL/attachment-object) objects | attached files to keep and possible descriptions for new files | \* Requires an application-owned webhook. @@ -286,5 +286,5 @@ Deletes a message that was created by the webhook. Returns a `204 No Content` re ###### Query String Params | Field | Type | Description | Required | -| --------- | --------- | ---------------------------------- | -------- | +|-----------|-----------|------------------------------------|----------| | thread_id | snowflake | id of the thread the message is in | false | diff --git a/docs/rich_presence/Best_Practices.md b/docs/rich_presence/Best_Practices.md index 3d6fe12cea..6e5229fb1b 100644 --- a/docs/rich_presence/Best_Practices.md +++ b/docs/rich_presence/Best_Practices.md @@ -42,10 +42,10 @@ For a great real world example, check out [Holodrive](https://store.steampowered ###### Examples -| Bad | Good | -| :------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------: | +| Bad | Good | +|:--------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------:| | ![A rich presence string that is too long and does not fit on one line](rp-long-strings.png) | ![Screenshot of a good rich presence string that is concise and easy to read](rp-short-strings.png) | -| The data wraps onto multiple lines. It’s repetitive, slower to read, and messy. | The data all fits on one line per string. Clean! | +| The data wraps onto multiple lines. It’s repetitive, slower to read, and messy. | The data all fits on one line per string. Clean! | ### Make it Actionable! @@ -55,10 +55,10 @@ For a great real world example, check out [Holodrive](https://store.steampowered ###### Examples -| Bad | Good | -| :---------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------: | -| ![Screenshot of a rich presence string reading "Rank 9999"](rp-non-actionable.png) | ![Screenshot of a good rich presence string shows a game mode of "Ranked: Control Point" and that the user is in a queue](rp-actionable.png) | -| While Rank 9999 is impressive, it doesn’t present any actionable data for their friends. | This player is in queue for something I want to play. Let's ask to join that open spot! | +| Bad | Good | +|:----------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------:| +| ![Screenshot of a rich presence string reading "Rank 9999"](rp-non-actionable.png) | ![Screenshot of a good rich presence string shows a game mode of "Ranked: Control Point" and that the user is in a queue](rp-actionable.png) | +| While Rank 9999 is impressive, it doesn’t present any actionable data for their friends. | This player is in queue for something I want to play. Let's ask to join that open spot! | ### Use ALL of the fields (where applicable)! @@ -68,10 +68,10 @@ For a great real world example, check out [Holodrive](https://store.steampowered ###### Examples -| Bad | Good | -| :---------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: | +| Bad | Good | +|:-----------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------:| | ![Screenshot of a rich presence string that is hard to read at a glance](rp-not-all-fields.png) | ![Screenshot of a good rich presence that takes advantage of storing less important information in tooltips](rp-all-fields.png) | -| The map name takes up space and makes the player's status harder to read at a glance. | Moving the name of the map to the tooltip makes the data cleaner and frees up space for the score. | +| The map name takes up space and makes the player's status harder to read at a glance. | Moving the name of the map to the tooltip makes the data cleaner and frees up space for the score. | ### Have interesting, expressive art! @@ -82,7 +82,7 @@ For a great real world example, check out [Holodrive](https://store.steampowered ###### Examples -| Bad | Good | -| :-----------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------: | -| ![Screenshot of a rich presence icon that is too dark to see clearly](rp-bad-art.png) | ![Screenshot of a rich presence icon that is clear and detailed](rp-good-art.png) | -| The image is dark and unfocused. Highly-detailed images can be hard to see. | This image is bright and matches the details. Let's help! | +| Bad | Good | +|:-------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------:| +| ![Screenshot of a rich presence icon that is too dark to see clearly](rp-bad-art.png) | ![Screenshot of a rich presence icon that is clear and detailed](rp-good-art.png) | +| The image is dark and unfocused. Highly-detailed images can be hard to see. | This image is bright and matches the details. Let's help! | diff --git a/docs/rich_presence/How_To.md b/docs/rich_presence/How_To.md index 9215a80b1e..208471efbe 100644 --- a/docs/rich_presence/How_To.md +++ b/docs/rich_presence/How_To.md @@ -130,23 +130,23 @@ typedef struct DiscordRichPresence { ###### Update Presence Payload Fields -| parameter | type | description | example | -| -------------- | -------- | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | -| state | char\* | the user's current party status | "Looking to Play", "Playing Solo", "In a Group" | -| details | char\* | what the player is currently doing | "Competitive - Captain's Mode", "In Queue", "Unranked PvP" | -| startTimestamp | int64_t | epoch seconds for game start - including will show time as "elapsed" | 1507665886 | -| endTimestamp | int64_t | epoch seconds for game end - including will show time as "remaining" | 1507665886 | -| largeImageKey | char\* | name of the uploaded image for the large profile artwork | "default" | -| largeImageText | char\* | tooltip for the largeImageKey | "Blade's Edge Arena", "Numbani", "Danger Zone" | -| smallImageKey | char\* | name of the uploaded image for the small profile artwork | "rogue" | -| smallImageText | char\* | tooltip for the smallImageKey | "Rogue - Level 100" | -| partyId | char\* | id of the player's party, lobby, or group | "ae488379-351d-4a4f-ad32-2b9b01c91657" | -| partySize | int | current size of the player's party, lobby, or group | 1 | -| partyMax | int | maximum size of the player's party, lobby, or group | 5 | -| matchSecret | char\* | (for future use) unique hashed string for a player's match | MmhuZToxMjMxMjM6cWl3amR3MWlqZA== | -| spectateSecret | char\* | unique hashed string for Spectate button | MTIzNDV8MTIzNDV8MTMyNDU0 | -| joinSecret | char\* | unique hashed string for chat invitations and Ask to Join | MTI4NzM0OjFpMmhuZToxMjMxMjM= | -| instance | int8_t | (for future use) integer representing a boolean for if the player is in an instance (an in-progress match) | 1 | +| parameter | type | description | example | +|----------------|---------|------------------------------------------------------------------------------------------------------------|------------------------------------------------------------| +| state | char\* | the user's current party status | "Looking to Play", "Playing Solo", "In a Group" | +| details | char\* | what the player is currently doing | "Competitive - Captain's Mode", "In Queue", "Unranked PvP" | +| startTimestamp | int64_t | epoch seconds for game start - including will show time as "elapsed" | 1507665886 | +| endTimestamp | int64_t | epoch seconds for game end - including will show time as "remaining" | 1507665886 | +| largeImageKey | char\* | name of the uploaded image for the large profile artwork | "default" | +| largeImageText | char\* | tooltip for the largeImageKey | "Blade's Edge Arena", "Numbani", "Danger Zone" | +| smallImageKey | char\* | name of the uploaded image for the small profile artwork | "rogue" | +| smallImageText | char\* | tooltip for the smallImageKey | "Rogue - Level 100" | +| partyId | char\* | id of the player's party, lobby, or group | "ae488379-351d-4a4f-ad32-2b9b01c91657" | +| partySize | int | current size of the player's party, lobby, or group | 1 | +| partyMax | int | maximum size of the player's party, lobby, or group | 5 | +| matchSecret | char\* | (for future use) unique hashed string for a player's match | MmhuZToxMjMxMjM6cWl3amR3MWlqZA== | +| spectateSecret | char\* | unique hashed string for Spectate button | MTIzNDV8MTIzNDV8MTMyNDU0 | +| joinSecret | char\* | unique hashed string for chat invitations and Ask to Join | MTI4NzM0OjFpMmhuZToxMjMxMjM= | +| instance | int8_t | (for future use) integer representing a boolean for if the player is in an instance (an in-progress match) | 1 | > info > Sending `endTimestamp` will **always** have the time displayed as "remaining" until the given time. Sending `startTimestamp` will show "elapsed" as long as there is no `endTimestamp` sent. @@ -155,17 +155,17 @@ Here's a handy image to see how these fields are actually displayed on a profile ![Graphical representation of the legend for rich presence details](rp-legend.png) -| location | field name | notes | -| -------------------------------------- | ---------------------- | --------------------------------------------------------------------------- | -| First row below title | details | | -| Second row below title | state | | -| Second row below title | partySize | In parenthesis next to the `state`, first number in the format `(1 of 10)` | -| Second row below title | partyMax | In parenthesis next to the `state`, second number in the format `(1 of 10)` | -| Third row below title | startTimestamp | Converted to a format such as `01:33 elapsed` | -| First button at the bottom | joinSecret | Button has the text "Ask to join" | -| Second button at the bottom | spectateSecret | Button has the text "Spectate" | -| Large image to the left of any content | largeImageKey | Four rows high, includes the title but not the bottom buttons | -| Small image to the left of any content | smallImageKey | Small icon inset on the bottom right of the `largeImageKey` | +| location | field name | notes | +|----------------------------------------|----------------|-----------------------------------------------------------------------------| +| First row below title | details | | +| Second row below title | state | | +| Second row below title | partySize | In parenthesis next to the `state`, first number in the format `(1 of 10)` | +| Second row below title | partyMax | In parenthesis next to the `state`, second number in the format `(1 of 10)` | +| Third row below title | startTimestamp | Converted to a format such as `01:33 elapsed` | +| First button at the bottom | joinSecret | Button has the text "Ask to join" | +| Second button at the bottom | spectateSecret | Button has the text "Spectate" | +| Large image to the left of any content | largeImageKey | Four rows high, includes the title but not the bottom buttons | +| Small image to the left of any content | smallImageKey | Small icon inset on the bottom right of the `largeImageKey` | Note that this layout may be subject to change without warning. This information is only provided to help those with impaired eyesight to understand the potential layout of this information in a user interface. @@ -209,7 +209,7 @@ typedef struct DiscordJoinRequest { ###### Ask to Join Payload Fields | parameter | type | description | -| ------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------- | +|---------------|-----------|-------------------------------------------------------------------------------------------------------------------------------------| | userId | char[24] | the userId of the player asking to join | | username | char[344] | the username of the player asking to join | | discriminator | char[8] | the discriminator of the player asking to join | @@ -223,7 +223,7 @@ When it fires, your game should surface this data with a Yes or No choice for Pl ###### Ask to Join Response Codes | code | value | -| -------------------- | ----- | +|----------------------|-------| | DISCORD_REPLY_NO | 0 | | DISCORD_REPLY_YES | 1 | | DISCORD_REPLY_IGNORE | 2 | @@ -265,7 +265,7 @@ All fields in the `DiscordRichPresence` object are entirely optional. Anything y ###### Rich Presence Field Requirements | Field | Custom Artwork | Spectating | Joining | Ask to Join | -| :------------: | :------------: | :--------: | :-----: | :---------: | +|:--------------:|:--------------:|:----------:|:-------:|:-----------:| | state | | | | | | details | | | | | | startTimestamp | | | | | diff --git a/docs/topics/Certified_Devices.md b/docs/topics/Certified_Devices.md index 0856325ee2..49c661a1b2 100644 --- a/docs/topics/Certified_Devices.md +++ b/docs/topics/Certified_Devices.md @@ -19,7 +19,7 @@ Yup, that's it. You give us the real-time info about any connected devices, and ###### Query String Params | Name | Value | Required | -| --------- | -------------------- | --------- | +|-----------|----------------------|-----------| | v | `1` | All | | client_id | your app's client id | All | | encoding | `json` | WebSocket | @@ -164,7 +164,7 @@ The socket will respond with a `200 OK` status code and the following JSON. ###### Device Object | Field | Type | Description | -| ------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------- | +|---------------------------|----------------------------------------------------------------------|----------------------------------------------------------| | type | [device type](#DOCS_TOPICS_CERTIFIED_DEVICES/models-device-type) | the type of device | | id | string | the device's Windows UUID | | vendor | [vendor](#DOCS_TOPICS_CERTIFIED_DEVICES/models-vendor-object) object | the hardware vendor | @@ -180,21 +180,21 @@ The socket will respond with a `200 OK` status code and the following JSON. ###### Vendor Object | Field | Type | Description | -| ----- | ------ | ------------------ | +|-------|--------|--------------------| | name | string | name of the vendor | | url | string | url for the vendor | ###### Model Object | Field | Type | Description | -| ----- | ------ | ----------------- | +|-------|--------|-------------------| | name | string | name of the model | | url | string | url for the model | ###### Device Type | Type | Value | -| ------------ | ------------- | +|--------------|---------------| | AUDIO_INPUT | "audioinput" | | AUDIO_OUTPUT | "audiooutput" | | VIDEO_INPUT | "videoinput" | diff --git a/docs/topics/Community_Resources.md b/docs/topics/Community_Resources.md index 78efccd018..4f28c41e9f 100644 --- a/docs/topics/Community_Resources.md +++ b/docs/topics/Community_Resources.md @@ -13,15 +13,18 @@ Discord does not maintain official SDKs. The following table is an inexhaustive ###### Discord Libraries | Name | Language | -| ------------------------------------------------------------- | ---------- | +|---------------------------------------------------------------|------------| | [Discord.Net](https://github.com/discord-net/Discord.Net) | C# | | [DSharpPlus](https://github.com/DSharpPlus/DSharpPlus) | C# | +| [D++](https://github.com/brainboxdotcc/DPP) | C++ | +| [discljord](https://github.com/discljord/discljord) | Clojure | | [DiscordGo](https://github.com/bwmarrin/discordgo) | Go | | [Discord4J](https://github.com/Discord4J/Discord4J) | Java | | [Javacord](https://github.com/Javacord/Javacord) | Java | | [JDA](https://github.com/DV8FromTheWorld/JDA) | Java | | [discord.js](https://github.com/discordjs/discord.js) | JavaScript | | [Eris](https://github.com/abalabahaha/eris) | JavaScript | +| [Oceanic](https://github.com/OceanicJS/Oceanic) | JavaScript | | [Discordia](https://github.com/SinisterRectus/Discordia) | Lua | | [DiscordPHP](https://github.com/discord-php/DiscordPHP) | PHP | | [discord.py](https://github.com/Rapptz/discord.py) | Python | @@ -62,6 +65,13 @@ Discord does not maintain official SDKs. The following table is an inexhaustive - [Autocode Slash Command Builder](https://autocode.com/tools/discord/command-builder/) - [Bsati's Slash Command Builder](https://bsati.github.io/dc-app-command-builder/) +## OpenAPI Specification + +> warn +> The OpenAPI spec is currently in public preview and **is subject to breaking changes** + +The public preview of the [Discord HTTP API specification](https://github.com/discord/discord-api-spec) provides a standard [OpenAPI 3.1 spec](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md) for the HTTP API. + ## Game SDK Tools Discord Game SDK's lobby and networking layer shares similarities with other gaming platforms (i.e. Valve's Steamworks SDK). The following open source library provides developers a uniform interface for these shared features and can simplify developing for multiple platforms. Note: this library is tailored for Unity3D development. @@ -99,7 +109,7 @@ Webhooks and embeds might seem like black magic. That's because they are, but le If you're working on a project that interacts with our API, you might find an API types module useful as it provides type inspection/completion for the Discord API. -| Name | Language | -| ---------------------------------------------------------------------- | ---------- | -| [dasgo](https://github.com/switchupcb/dasgo) | Go | -| [discord-api-types](https://github.com/discordjs/discord-api-types) | JavaScript | +| Name | Language | +|---------------------------------------------------------------------|------------| +| [dasgo](https://github.com/switchupcb/dasgo) | Go | +| [discord-api-types](https://github.com/discordjs/discord-api-types) | JavaScript | diff --git a/docs/topics/Gateway.md b/docs/topics/Gateway.md index 75b8010943..7d60c8a116 100644 --- a/docs/topics/Gateway.md +++ b/docs/topics/Gateway.md @@ -81,7 +81,7 @@ At a high-level, Gateway connections consist of the following cycle: 4. App sends an [Identify (opcode `2`)](#DOCS_TOPICS_GATEWAY_EVENTS/identify) event to perform the initial handshake with the Gateway. **Read the section on [Identifying](#DOCS_TOPICS_GATEWAY/identifying)** 5. Discord sends the app a [Ready (opcode `0`)](#DOCS_TOPICS_GATEWAY_EVENTS/ready) event which indicates the handshake was successful and the connection is established. The Ready event contains a `resume_gateway_url` that the app should keep track of to determine the WebSocket URL an app should use to Resume. **Read the section on [the Ready event](#DOCS_TOPICS_GATEWAY/ready-event)** 6. The connection may be dropped for a variety of reasons. Whether the app can [Resume](#DOCS_TOPICS_GATEWAY/resuming) the connection or whether it must re-identify is determined by a variety of factors like the [opcode](#DOCS_TOPICS_OPCODES_AND_STATUS_CODES/gateway-gateway-opcodes) and [close code](#DOCS_TOPICS_OPCODES_AND_STATUS_CODES/gateway-gateway-close-event-codes) that it receives. **Read the section on [Disconnecting](#DOCS_TOPICS_GATEWAY/disconnecting)** -7. If an app **can** resume/reconnect, it should open a new connection using `resume_gateway_url`, then send a [Resume (opcode `6`)](#DOCS_TOPICS_GATEWAY_EVENTS/resume) event. If an app **cannot** resume/reconnect, it should open a new connection using the cached URL from step #1, then repeat the whole Gateway cycle. *Yipee!* **Read the section on [Resuming](#DOCS_TOPICS_GATEWAY/resuming)** +7. If an app **can** resume/reconnect, it should open a new connection using `resume_gateway_url` with the same version and encoding, then send a [Resume (opcode `6`)](#DOCS_TOPICS_GATEWAY_EVENTS/resume) event. If an app **cannot** resume/reconnect, it should open a new connection using the cached URL from step #1, then repeat the whole Gateway cycle. *Yipee!* **Read the section on [Resuming](#DOCS_TOPICS_GATEWAY/resuming)** ### Connecting @@ -100,14 +100,14 @@ When connecting to the URL, it's a good idea to explicitly pass the API version ###### Gateway URL Query String Params | Field | Type | Description | Accepted Values | -| --------- | ------- | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | +|-----------|---------|-----------------------------------------------------------------------------------------------------|------------------------------------------------------------| | v | integer | [API Version](#DOCS_REFERENCE/api-versioning) to use | [API version](#DOCS_REFERENCE/api-versioning-api-versions) | | encoding | string | The [encoding](#DOCS_TOPICS_GATEWAY/encoding-and-compression) of received gateway packets | `json` or `etf` | | compress? | string | The optional [transport compression](#DOCS_TOPICS_GATEWAY/transport-compression) of gateway packets | `zlib-stream` | #### Hello Event -Once connected to the Gateway, your app will receive a [Hello (opcode `10`)](#DOCS_TOPICS_GATEWAY/hello-event) event that contains your connection's heartbeat interval (`hearbeat_interval`). +Once connected to the Gateway, your app will receive a [Hello (opcode `10`)](#DOCS_TOPICS_GATEWAY/hello-event) event that contains your connection's heartbeat interval (`heartbeat_interval`). The heartbeat interval indicates a length of time in milliseconds that you should use to determine how often your app needs to send a Heartbeat event in order to maintain the active connection. Heartbeating is detailed in the [Sending Heartbeats](#DOCS_TOPICS_GATEWAY/sending-heartbeats) section. @@ -238,7 +238,7 @@ There are a handful of scenarios when your app should attempt to resume: Before your app can send a [Resume (opcode `6`)](#DOCS_TOPICS_GATEWAY_EVENTS/resume) event, it will need three values: the `session_id` and the `resume_gateway_url` from the [Ready](#DOCS_TOPICS_GATEWAY/ready-event) event, and the sequence number (`s`) from the last Dispatch (opcode `0`) event it received before the disconnect. -After the connection is closed, your app should open a new connection using `resume_gateway_url` rather than the URL used to initially connect. If your app doesn't use the `resume_gateway_url` when reconnecting, it will experience disconnects at a higher rate than normal. +After the connection is closed, your app should open a new connection using `resume_gateway_url` rather than the URL used to initially connect, with the same query parameters from the initial [Connection](#DOCS_TOPICS_GATEWAY/connecting). If your app doesn't use the `resume_gateway_url` when reconnecting, it will experience disconnects at a higher rate than normal. Once the new connection is opened, your app should send a [Gateway Resume](#DOCS_TOPICS_GATEWAY_EVENTS/resume) event using the `session_id` and sequence number mentioned above. When sending the event, `session_id` will have the same field name, but the last sequence number will be passed as `seq` in the data object (`d`). @@ -246,6 +246,9 @@ When Resuming, you do not need to send an Identify event after opening the conne If successful, the Gateway will send the missed events in order, finishing with a [Resumed](#DOCS_TOPICS_GATEWAY_EVENTS/resumed) event to signal event replay has finished and that all subsequent events will be new. +> info +> When resuming with the `resume_gateway_url` you need to provide the same version and encoding as the initial connection. + It's possible your app won't reconnect in time to Resume, in which case it will receive an [Invalid Session (opcode `9`)](#DOCS_TOPICS_GATEWAY_EVENTS/invalid-session) event. If the `d` field is set to `false` (which is most of the time), your app should disconnect. After disconnect, your app should create a new connection with your cached URL from the [Get Gateway](#DOCS_TOPICS_GATEWAY/get-gateway) or the [Get Gateway Bot](#DOCS_TOPICS_GATEWAY/get-gateway-bot) endpoint, then send an [Identify (opcode `2`)](#DOCS_TOPICS_GATEWAY_EVENTS/identify) event. ###### Example Gateway Resume Event @@ -675,7 +678,7 @@ Returns an object based on the information in [Get Gateway](#DOCS_TOPICS_GATEWAY ###### JSON Response | Field | Type | Description | -| ------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | +|---------------------|-------------------------------------------------------------------------------|--------------------------------------------------------------------------------------| | url | string | WSS URL that can be used for connecting to the Gateway | | shards | integer | Recommended number of [shards](#DOCS_TOPICS_GATEWAY/sharding) to use when connecting | | session_start_limit | [session_start_limit](#DOCS_TOPICS_GATEWAY/session-start-limit-object) object | Information on the current session start limit | @@ -700,7 +703,7 @@ Returns an object based on the information in [Get Gateway](#DOCS_TOPICS_GATEWAY ###### Session Start Limit Structure | Field | Type | Description | -| --------------- | ------- | -------------------------------------------------------------- | +|-----------------|---------|----------------------------------------------------------------| | total | integer | Total number of session starts the current user is allowed | | remaining | integer | Remaining number of session starts the current user is allowed | | reset_after | integer | Number of milliseconds after which the limit resets | diff --git a/docs/topics/Gateway_Events.md b/docs/topics/Gateway_Events.md index dad3173e78..3258379b17 100644 --- a/docs/topics/Gateway_Events.md +++ b/docs/topics/Gateway_Events.md @@ -23,7 +23,7 @@ For readability, event names in the following documentation are typically left i Gateway event payloads have a common structure, but the contents of the associated data (`d`) varies between the different events. | Field | Type | Description | -| ----- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +|-------|-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------| | op | integer | [Gateway opcode](#DOCS_TOPICS_OPCODES_AND_STATUS_CODES/gateway-gateway-opcodes), which indicates the payload type | | d | ?mixed (any JSON value) | Event data | | s | ?integer \* | Sequence number of event used for [resuming sessions](#DOCS_TOPICS_GATEWAY/resuming) and [heartbeating](#DOCS_TOPICS_GATEWAY/sending-heartbeats) | @@ -50,7 +50,7 @@ Send events are Gateway events encapsulated in an [event payload](#DOCS_TOPICS_G > Previously, Gateway send events were labeled as commands | Name | Description | -| -------------------------------------------------------------------------- | --------------------------------------------------------- | +|----------------------------------------------------------------------------|-----------------------------------------------------------| | [Identify](#DOCS_TOPICS_GATEWAY_EVENTS/identify) | Triggers the initial handshake with the gateway | | [Resume](#DOCS_TOPICS_GATEWAY_EVENTS/resume) | Resumes a dropped gateway connection | | [Heartbeat](#DOCS_TOPICS_GATEWAY_EVENTS/heartbeat) | Maintains an active gateway connection | @@ -67,7 +67,7 @@ Details about identifying is in the [Gateway documentation](#DOCS_TOPICS_GATEWAY ###### Identify Structure | Field | Type | Description | Default | -| ---------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------- | +|------------------|-----------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------|---------| | token | string | Authentication token | - | | properties | object | [Connection properties](#DOCS_TOPICS_GATEWAY_EVENTS/identify-identify-connection-properties) | - | | compress? | boolean | Whether this connection supports compression of packets | false | @@ -79,7 +79,7 @@ Details about identifying is in the [Gateway documentation](#DOCS_TOPICS_GATEWAY ###### Identify Connection Properties | Field | Type | Description | -| ------- | ------ | --------------------- | +|---------|--------|-----------------------| | os | string | Your operating system | | browser | string | Your library name | | device | string | Your library name | @@ -127,7 +127,7 @@ Details about resuming are in the [Gateway documentation](#DOCS_TOPICS_GATEWAY/r ###### Resume Structure | Field | Type | Description | -| ---------- | ------- | ----------------------------- | +|------------|---------|-------------------------------| | token | string | Session token | | session_id | string | Session ID | | seq | integer | Last sequence number received | @@ -175,7 +175,7 @@ Due to our privacy and infrastructural concerns with this feature, there are som ###### Request Guild Members Structure | Field | Type | Description | Required | -| ---------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | +|------------|----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|----------------------------| | guild_id | snowflake | ID of the guild to get members for | true | | query? | string | string that username starts with, or an empty string to return all members | one of query or user_ids | | limit | integer | maximum number of members to send matching the `query`; a limit of `0` can be used with an empty string `query` to return all members | true when specifying query | @@ -206,7 +206,7 @@ Sent when a client wants to join, move, or disconnect from a voice channel. ###### Gateway Voice State Update Structure | Field | Type | Description | -| ---------- | ---------- | -------------------------------------------------------------------- | +|------------|------------|----------------------------------------------------------------------| | guild_id | snowflake | ID of the guild | | channel_id | ?snowflake | ID of the voice channel client wants to join (null if disconnecting) | | self_mute | boolean | Whether the client is muted | @@ -233,7 +233,7 @@ Sent by the client to indicate a presence or status update. ###### Gateway Presence Update Structure | Field | Type | Description | -| ---------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------- | +|------------|--------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| | since | ?integer | Unix time (in milliseconds) of when the client went idle, or null if the client is not idle | | activities | array of [activity](#DOCS_TOPICS_GATEWAY_EVENTS/activity-object) objects | User's activities | | status | string | User's new [status](#DOCS_TOPICS_GATEWAY_EVENTS/update-presence-status-types) | @@ -242,7 +242,7 @@ Sent by the client to indicate a presence or status update. ###### Status Types | Status | Description | -| --------- | ------------------------------ | +|-----------|--------------------------------| | online | Online | | dnd | Do Not Disturb | | idle | AFK | @@ -271,7 +271,7 @@ Sent by the client to indicate a presence or status update. Receive events are Gateway events encapsulated in an [event payload](#DOCS_TOPICS_GATEWAY_EVENTS/payload-structure), and are sent by Discord to an app through a Gateway connection. Receive events correspond to events that happen in a Discord server where the app is installed. | Name | Description | -| ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | +|--------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------| | [Hello](#DOCS_TOPICS_GATEWAY_EVENTS/hello) | Defines the heartbeat interval | | [Ready](#DOCS_TOPICS_GATEWAY_EVENTS/ready) | Contains the initial state information | | [Resumed](#DOCS_TOPICS_GATEWAY_EVENTS/resumed) | Response to [Resume](#DOCS_TOPICS_GATEWAY_EVENTS/resume) | @@ -344,7 +344,7 @@ Sent on connection to the websocket. Defines the heartbeat interval that an app ###### Hello Structure | Field | Type | Description | -| ------------------ | ------- | ------------------------------------------------------- | +|--------------------|---------|---------------------------------------------------------| | heartbeat_interval | integer | Interval (in milliseconds) an app should heartbeat with | ###### Example Hello @@ -367,7 +367,7 @@ The ready event is dispatched when a client has completed the initial handshake ###### Ready Event Fields | Field | Type | Description | -| ------------------ | ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- | +|--------------------|--------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------| | v | integer | [API version](#DOCS_REFERENCE/api-versioning-api-versions) | | user | [user](#DOCS_RESOURCES_USER/user-object) object | Information about the user including email | | guilds | array of [Unavailable Guild](#DOCS_RESOURCES_GUILD/unavailable-guild-object) objects | Guilds the user is in | @@ -441,7 +441,7 @@ Sent when a rule is triggered and an action is executed (e.g. when a message is ###### Auto Moderation Action Execution Event Fields | Field | Type | Description | -| ------------------------ | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | +|--------------------------|------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------| | guild_id | snowflake | ID of the guild in which action was executed | | action | [auto moderation action](#DOCS_RESOURCES_AUTO_MODERATION/auto-moderation-action-object) object | Action which was executed | | rule_id | snowflake | ID of the rule which action belongs to | @@ -469,7 +469,7 @@ Sent when a new guild channel is created, relevant to the current user. The inne #### Channel Update -Sent when a channel is updated. The inner payload is a [channel](#DOCS_RESOURCES_CHANNEL/channel-object) object. This is not sent when the field `last_message_id` is altered. To keep track of the last_message_id changes, you must listen for [Message Create](#DOCS_TOPICS_GATEWAY_EVENTS/message-create) events (or [Thread Create](#DOCS_TOPICS_GATEWAY_EVENTS/thread-create) events for `GUILD_FORUM` channels). +Sent when a channel is updated. The inner payload is a [channel](#DOCS_RESOURCES_CHANNEL/channel-object) object. This is not sent when the field `last_message_id` is altered. To keep track of the last_message_id changes, you must listen for [Message Create](#DOCS_TOPICS_GATEWAY_EVENTS/message-create) events (or [Thread Create](#DOCS_TOPICS_GATEWAY_EVENTS/thread-create) events for `GUILD_FORUM` and `GUILD_MEDIA` channels). This event may reference roles or guild members that no longer exist in the guild. @@ -498,7 +498,7 @@ Sent when the current user _gains_ access to a channel. ###### Thread List Sync Event Fields | Field | Type | Description | -| ------------ | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|--------------|--------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | guild_id | snowflake | ID of the guild | | channel_ids? | array of snowflakes | Parent channel IDs whose threads are being synced. If omitted, then threads were synced for the entire guild. This array may contain channel_ids that have no active threads as well, so you know to clear that data. | | threads | array of [channel](#DOCS_RESOURCES_CHANNEL/channel-object) objects | All active threads in the given channels that the current user can access | @@ -511,7 +511,7 @@ Sent when the [thread member](#DOCS_RESOURCES_CHANNEL/thread-member-object) obje ###### Thread Member Update Event Extra Fields | Field | Type | Description | -| -------- | --------- | --------------- | +|----------|-----------|-----------------| | guild_id | snowflake | ID of the guild | @@ -522,7 +522,7 @@ Sent when anyone is added to or removed from a thread. If the current user does ###### Thread Members Update Event Fields | Field | Type | Description | -| ------------------- | ------------------------------------------------------------------------------ | --------------------------------------------------------- | +|---------------------|--------------------------------------------------------------------------------|-----------------------------------------------------------| | id | snowflake | ID of the thread | | guild_id | snowflake | ID of the guild | | member_count | integer | Approximate number of members in the thread, capped at 50 | @@ -538,7 +538,7 @@ Sent when a message is pinned or unpinned in a text channel. This is not sent wh ###### Channel Pins Update Event Fields | Field | Type | Description | -| ------------------- | ------------------ | ------------------------------------------------------- | +|---------------------|--------------------|---------------------------------------------------------| | guild_id? | snowflake | ID of the guild | | channel_id | snowflake | ID of the channel | | last_pin_timestamp? | ?ISO8601 timestamp | Time at which the most recent pinned message was pinned | @@ -563,7 +563,7 @@ The inner payload can be: ###### Guild Create Extra Fields | Field | Type | Description | -| ---------------------- | ------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- | +|------------------------|--------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------| | joined_at | ISO8601 timestamp | When this guild was joined at | | large | boolean | `true` if this is considered a large guild | | unavailable? | boolean | `true` if this guild is unavailable due to an outage | @@ -598,7 +598,7 @@ Sent when a user is banned from a guild. ###### Guild Ban Add Event Fields | Field | Type | Description | -| -------- | ------------------------------------------------- | ------------------- | +|----------|---------------------------------------------------|---------------------| | guild_id | snowflake | ID of the guild | | user | a [user](#DOCS_RESOURCES_USER/user-object) object | User who was banned | @@ -609,7 +609,7 @@ Sent when a user is unbanned from a guild. ###### Guild Ban Remove Event Fields | Field | Type | Description | -| -------- | ------------------------------------------------- | --------------------- | +|----------|---------------------------------------------------|-----------------------| | guild_id | snowflake | ID of the guild | | user | a [user](#DOCS_RESOURCES_USER/user-object) object | User who was unbanned | @@ -620,7 +620,7 @@ Sent when a guild's emojis have been updated. ###### Guild Emojis Update Event Fields | Field | Type | Description | -| -------- | --------- | ----------------------------------------------------- | +|----------|-----------|-------------------------------------------------------| | guild_id | snowflake | ID of the guild | | emojis | array | Array of [emojis](#DOCS_RESOURCES_EMOJI/emoji-object) | @@ -631,7 +631,7 @@ Sent when a guild's stickers have been updated. ###### Guild Stickers Update Event Fields | Field | Type | Description | -| -------- | --------- | ----------------------------------------------------------- | +|----------|-----------|-------------------------------------------------------------| | guild_id | snowflake | ID of the guild | | stickers | array | Array of [stickers](#DOCS_RESOURCES_STICKER/sticker-object) | @@ -642,7 +642,7 @@ Sent when a guild integration is updated. ###### Guild Integrations Update Event Fields | Field | Type | Description | -| -------- | --------- | ----------------------------------------------- | +|----------|-----------|-------------------------------------------------| | guild_id | snowflake | ID of the guild whose integrations were updated | #### Guild Member Add @@ -655,7 +655,7 @@ Sent when a new user joins a guild. The inner payload is a [guild member](#DOCS_ ###### Guild Member Add Extra Fields | Field | Type | Description | -| -------- | --------- | --------------- | +|----------|-----------|-----------------| | guild_id | snowflake | ID of the guild | #### Guild Member Remove @@ -668,7 +668,7 @@ Sent when a user is removed from a guild (leave/kick/ban). ###### Guild Member Remove Event Fields | Field | Type | Description | -| -------- | ------------------------------------------------- | -------------------- | +|----------|---------------------------------------------------|----------------------| | guild_id | snowflake | ID of the guild | | user | a [user](#DOCS_RESOURCES_USER/user-object) object | User who was removed | @@ -682,7 +682,7 @@ Sent when a guild member is updated. This will also fire when the user object of ###### Guild Member Update Event Fields | Field | Type | Description | -| ----------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +|-------------------------------|---------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | guild_id | snowflake | ID of the guild | | roles | array of snowflakes | User role ids | | user | a [user](#DOCS_RESOURCES_USER/user-object) object | User | @@ -703,7 +703,7 @@ You can use the `chunk_index` and `chunk_count` to calculate how many chunks are ###### Guild Members Chunk Event Fields | Field | Type | Description | -| ----------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | +|-------------|----------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | guild_id | snowflake | ID of the guild | | members | array of [guild member](#DOCS_RESOURCES_GUILD/guild-member-object) objects | Set of guild members | | chunk_index | integer | Chunk index in the expected chunks for this response (0 <= chunk\_index < chunk\_count) | @@ -719,7 +719,7 @@ Sent when a guild role is created. ###### Guild Role Create Event Fields | Field | Type | Description | -| -------- | ----------------------------------------------------- | --------------------- | +|----------|-------------------------------------------------------|-----------------------| | guild_id | snowflake | ID of the guild | | role | a [role](#DOCS_TOPICS_PERMISSIONS/role-object) object | Role that was created | @@ -730,7 +730,7 @@ Sent when a guild role is updated. ###### Guild Role Update Event Fields | Field | Type | Description | -| -------- | ----------------------------------------------------- | --------------------- | +|----------|-------------------------------------------------------|-----------------------| | guild_id | snowflake | ID of the guild | | role | a [role](#DOCS_TOPICS_PERMISSIONS/role-object) object | Role that was updated | @@ -741,7 +741,7 @@ Sent when a guild role is deleted. ###### Guild Role Delete Event Fields | Field | Type | Description | -| -------- | --------- | --------------- | +|----------|-----------|-----------------| | guild_id | snowflake | ID of the guild | | role_id | snowflake | ID of the role | @@ -764,7 +764,7 @@ Sent when a user has subscribed to a guild scheduled event. ###### Guild Scheduled Event User Add Event Fields | Field | Type | Description | -| ------------------------ | --------- | ------------------------------- | +|--------------------------|-----------|---------------------------------| | guild_scheduled_event_id | snowflake | ID of the guild scheduled event | | user_id | snowflake | ID of the user | | guild_id | snowflake | ID of the guild | @@ -776,7 +776,7 @@ Sent when a user has unsubscribed from a guild scheduled event. ###### Guild Scheduled Event User Remove Event Fields | Field | Type | Description | -| ------------------------ | --------- | ------------------------------- | +|--------------------------|-----------|---------------------------------| | guild_scheduled_event_id | snowflake | ID of the guild scheduled event | | user_id | snowflake | ID of the user | | guild_id | snowflake | ID of the guild | @@ -790,7 +790,7 @@ Sent when an integration is created. The inner payload is an [integration](#DOCS ###### Integration Create Event Additional Fields | Field | Type | Description | -| -------- | --------- | --------------- | +|----------|-----------|-----------------| | guild_id | snowflake | ID of the guild | #### Integration Update @@ -800,7 +800,7 @@ Sent when an integration is updated. The inner payload is an [integration](#DOCS ###### Integration Update Event Additional Fields | Field | Type | Description | -| -------- | --------- | --------------- | +|----------|-----------|-----------------| | guild_id | snowflake | ID of the guild | #### Integration Delete @@ -810,7 +810,7 @@ Sent when an integration is deleted. ###### Integration Delete Event Fields | Field | Type | Description | -| --------------- | --------- | ------------------------------------------------------------- | +|-----------------|-----------|---------------------------------------------------------------| | id | snowflake | Integration ID | | guild_id | snowflake | ID of the guild | | application_id? | snowflake | ID of the bot/OAuth2 application for this discord integration | @@ -826,7 +826,7 @@ Sent when a new invite to a channel is created. ###### Invite Create Event Fields | Field | Type | Description | -| ------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | +|---------------------|------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------| | channel_id | snowflake | Channel the invite is for | | code | string | Unique invite [code](#DOCS_RESOURCES_INVITE/invite-object) | | created_at | ISO8601 timestamp | Time at which the invite was created | @@ -847,7 +847,7 @@ Sent when an invite is deleted. ###### Invite Delete Event Fields | Field | Type | Description | -| ---------- | --------- | ---------------------------------------------------------- | +|------------|-----------|------------------------------------------------------------| | channel_id | snowflake | Channel of the invite | | guild_id? | snowflake | Guild of the invite | | code | string | Unique invite [code](#DOCS_RESOURCES_INVITE/invite-object) | @@ -864,7 +864,7 @@ Sent when a message is created. The inner payload is a [message](#DOCS_RESOURCES ###### Message Create Extra Fields | Field | Type | Description | -| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | +|-----------|-------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------| | guild_id? | snowflake | ID of the guild the message was sent in - unless it is an ephemeral message | | member? | partial [guild member](#DOCS_RESOURCES_GUILD/guild-member-object) object | Member properties for this message's author. Missing for ephemeral messages and messages from webhooks | | mentions | array of [user](#DOCS_RESOURCES_USER/user-object) objects, with an additional partial [member](#DOCS_RESOURCES_GUILD/guild-member-object) field | Users specifically mentioned in the message | @@ -883,7 +883,7 @@ Sent when a message is deleted. ###### Message Delete Event Fields | Field | Type | Description | -| ---------- | --------- | ----------------- | +|------------|-----------|-------------------| | id | snowflake | ID of the message | | channel_id | snowflake | ID of the channel | | guild_id? | snowflake | ID of the guild | @@ -895,7 +895,7 @@ Sent when multiple messages are deleted at once. ###### Message Delete Bulk Event Fields | Field | Type | Description | -| ---------- | ------------------- | ------------------- | +|------------|---------------------|---------------------| | ids | array of snowflakes | IDs of the messages | | channel_id | snowflake | ID of the channel | | guild_id? | snowflake | ID of the guild | @@ -907,7 +907,7 @@ Sent when a user adds a reaction to a message. ###### Message Reaction Add Event Fields | Field | Type | Description | -| ------------------ | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | +|--------------------|--------------------------------------------------------------|--------------------------------------------------------------------------------------------| | user_id | snowflake | ID of the user | | channel_id | snowflake | ID of the channel | | message_id | snowflake | ID of the message | @@ -923,7 +923,7 @@ Sent when a user removes a reaction from a message. ###### Message Reaction Remove Event Fields | Field | Type | Description | -| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | +|------------|--------------------------------------------------------------|--------------------------------------------------------------------------------------------| | user_id | snowflake | ID of the user | | channel_id | snowflake | ID of the channel | | message_id | snowflake | ID of the message | @@ -937,7 +937,7 @@ Sent when a user explicitly removes all reactions from a message. ###### Message Reaction Remove All Event Fields | Field | Type | Description | -| ---------- | --------- | ----------------- | +|------------|-----------|-------------------| | channel_id | snowflake | ID of the channel | | message_id | snowflake | ID of the message | | guild_id? | snowflake | ID of the guild | @@ -949,7 +949,7 @@ Sent when a bot removes all instances of a given emoji from the reactions of a m ###### Message Reaction Remove Emoji Event Fields | Field | Type | Description | -| ---------- | ---------------------------------------------------------- | ---------------------- | +|------------|------------------------------------------------------------|------------------------| | channel_id | snowflake | ID of the channel | | guild_id? | snowflake | ID of the guild | | message_id | snowflake | ID of the message | @@ -970,7 +970,7 @@ A user's presence is their current state on a guild. This event is sent when a u ###### Presence Update Event Fields | Field | Type | Description | -| ------------- | ------------------------------------------------------------------------ | -------------------------------------------- | +|---------------|--------------------------------------------------------------------------|----------------------------------------------| | user | [user](#DOCS_RESOURCES_USER/user-object) object | User whose presence is being updated | | guild_id | snowflake | ID of the guild | | status | string | Either "idle", "dnd", "online", or "offline" | @@ -982,7 +982,7 @@ A user's presence is their current state on a guild. This event is sent when a u Active sessions are indicated with an "online", "idle", or "dnd" string per platform. If a user is offline or invisible, the corresponding field is not present. | Field | Type | Description | -| -------- | ------ | --------------------------------------------------------------------------------- | +|----------|--------|-----------------------------------------------------------------------------------| | desktop? | string | User's status set for an active desktop (Windows, Linux, Mac) application session | | mobile? | string | User's status set for an active mobile (iOS, Android) application session | | web? | string | User's status set for an active web (browser, bot user) application session | @@ -992,7 +992,7 @@ Active sessions are indicated with an "online", "idle", or "dnd" string per plat ###### Activity Structure | Field | Type | Description | -| --------------- | ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- | +|-----------------|--------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------| | name | string | Activity's name | | type | integer | [Activity type](#DOCS_TOPICS_GATEWAY_EVENTS/activity-object-activity-types) | | url? | ?string | Stream URL, is validated when type is 1 | @@ -1000,7 +1000,7 @@ Active sessions are indicated with an "online", "idle", or "dnd" string per plat | timestamps? | [timestamps](#DOCS_TOPICS_GATEWAY_EVENTS/activity-object-activity-timestamps) object | Unix timestamps for start and/or end of the game | | application_id? | snowflake | Application ID for the game | | details? | ?string | What the player is currently doing | -| state? | ?string | User's current party status | +| state? | ?string | User's current party status, or text used for a custom status | | emoji? | ?[emoji](#DOCS_TOPICS_GATEWAY_EVENTS/activity-object-activity-emoji) object | Emoji used for a custom status | | party? | [party](#DOCS_TOPICS_GATEWAY_EVENTS/activity-object-activity-party) object | Information for the current party of the player | | assets? | [assets](#DOCS_TOPICS_GATEWAY_EVENTS/activity-object-activity-assets) object | Images for the presence and their hover texts | @@ -1010,18 +1010,18 @@ Active sessions are indicated with an "online", "idle", or "dnd" string per plat | buttons? | array of [buttons](#DOCS_TOPICS_GATEWAY_EVENTS/activity-object-activity-buttons) | Custom buttons shown in the Rich Presence (max 2) | > info -> Bots are only able to send `name`, `type`, and optionally `url`. +> Bot users are only able to set `name`, `state`, `type`, and `url`. ###### Activity Types -| ID | Name | Format | Example | -| --- | --------- | ------------------- | ------------------------------------ | -| 0 | Game | Playing {name} | "Playing Rocket League" | -| 1 | Streaming | Streaming {details} | "Streaming Rocket League" | -| 2 | Listening | Listening to {name} | "Listening to Spotify" | -| 3 | Watching | Watching {name} | "Watching YouTube Together" | -| 4 | Custom | {emoji} {name} | ":smiley: I am cool" | -| 5 | Competing | Competing in {name} | "Competing in Arena World Champions" | +| ID | Name | Format | Example | +|----|-----------|---------------------|--------------------------------------| +| 0 | Game | Playing {name} | "Playing Rocket League" | +| 1 | Streaming | Streaming {details} | "Streaming Rocket League" | +| 2 | Listening | Listening to {name} | "Listening to Spotify" | +| 3 | Watching | Watching {name} | "Watching YouTube Together" | +| 4 | Custom | {emoji} {state} | ":smiley: I am cool" | +| 5 | Competing | Competing in {name} | "Competing in Arena World Champions" | > info > The streaming type currently only supports Twitch and YouTube. Only `https://twitch.tv/` and `https://youtube.com/` urls will work. @@ -1029,14 +1029,14 @@ Active sessions are indicated with an "online", "idle", or "dnd" string per plat ###### Activity Timestamps | Field | Type | Description | -| ------ | ------- | -------------------------------------------------------- | +|--------|---------|----------------------------------------------------------| | start? | integer | Unix time (in milliseconds) of when the activity started | | end? | integer | Unix time (in milliseconds) of when the activity ends | ###### Activity Emoji | Field | Type | Description | -| --------- | --------- | ----------------------------- | +|-----------|-----------|-------------------------------| | name | string | Name of the emoji | | id? | snowflake | ID of the emoji | | animated? | boolean | Whether the emoji is animated | @@ -1044,14 +1044,14 @@ Active sessions are indicated with an "online", "idle", or "dnd" string per plat ###### Activity Party | Field | Type | Description | -| ----- | ---------------------------------------------- | ------------------------------------------------- | +|-------|------------------------------------------------|---------------------------------------------------| | id? | string | ID of the party | | size? | array of two integers (current_size, max_size) | Used to show the party's current and maximum size | ###### Activity Assets | Field | Type | Description | -| ------------ | ------ | -------------------------------------------------------------------------------------------- | +|--------------|--------|----------------------------------------------------------------------------------------------| | large_image? | string | See [Activity Asset Image](#DOCS_TOPICS_GATEWAY_EVENTS/activity-object-activity-asset-image) | | large_text? | string | Text displayed when hovering over the large image of the activity | | small_image? | string | See [Activity Asset Image](#DOCS_TOPICS_GATEWAY_EVENTS/activity-object-activity-asset-image) | @@ -1064,14 +1064,14 @@ Activity asset images are arbitrary strings which usually contain snowflake IDs To use an external image via media proxy, specify the URL as the field's value when sending. You will only receive the `mp:` prefix via the gateway. | Type | Format | Image URL | -| ----------------- | ------------------------ | -------------------------------------------------------------------------- | +|-------------------|--------------------------|----------------------------------------------------------------------------| | Application Asset | `{application_asset_id}` | See [Application Asset Image Formatting](#DOCS_REFERENCE/image-formatting) | | Media Proxy Image | `mp:{image_id}` | `https://media.discordapp.net/{image_id}` | ###### Activity Secrets | Field | Type | Description | -| --------- | ------ | ------------------------------------- | +|-----------|--------|---------------------------------------| | join? | string | Secret for joining a party | | spectate? | string | Secret for spectating a game | | match? | string | Secret for a specific instanced match | @@ -1079,7 +1079,7 @@ To use an external image via media proxy, specify the URL as the field's value w ###### Activity Flags | Name | Value | -| --------------------------- | ------ | +|-----------------------------|--------| | INSTANCE | 1 << 0 | | JOIN | 1 << 1 | | SPECTATE | 1 << 2 | @@ -1095,7 +1095,7 @@ To use an external image via media proxy, specify the URL as the field's value w When received over the gateway, the `buttons` field is an array of strings, which are the button labels. Bots cannot access a user's activity button URLs. When sending, the `buttons` field must be an array of the below object: | Field | Type | Description | -| ----- | ------ | ------------------------------------------------------ | +|-------|--------|--------------------------------------------------------| | label | string | Text shown on the button (1-32 characters) | | url | string | URL opened when clicking the button (1-512 characters) | @@ -1151,7 +1151,7 @@ Sent when a user starts typing in a channel. ###### Typing Start Event Fields | Field | Type | Description | -| ---------- | ---------------------------------------------------------- | ------------------------------------------------------ | +|------------|------------------------------------------------------------|--------------------------------------------------------| | channel_id | snowflake | ID of the channel | | guild_id? | snowflake | ID of the guild | | user_id | snowflake | ID of the user | @@ -1178,7 +1178,7 @@ Sent when a guild's voice server is updated. This is sent when initially connect ###### Voice Server Update Event Fields | Field | Type | Description | -| -------- | --------- | ------------------------------------- | +|----------|-----------|---------------------------------------| | token | string | Voice connection token | | guild_id | snowflake | Guild this voice server update is for | | endpoint | ?string | Voice server host | @@ -1202,7 +1202,7 @@ Sent when a guild channel's webhook is created, updated, or deleted. ###### Webhooks Update Event Fields | Field | Type | Description | -| ---------- | --------- | ----------------- | +|------------|-----------|-------------------| | guild_id | snowflake | ID of the guild | | channel_id | snowflake | ID of the channel | diff --git a/docs/topics/OAuth2.md b/docs/topics/OAuth2.md index d0233b8d52..23b8869b48 100644 --- a/docs/topics/OAuth2.md +++ b/docs/topics/OAuth2.md @@ -9,7 +9,7 @@ The first step in implementing OAuth2 is [registering a developer application](# ###### OAuth2 URLs | URL | Description | -| ------------------------------------------- | ----------------------------------------------------------- | +|---------------------------------------------|-------------------------------------------------------------| | https://discord.com/oauth2/authorize | Base authorization URL | | https://discord.com/api/oauth2/token | Token URL | | https://discord.com/api/oauth2/token/revoke | [Token Revocation](https://tools.ietf.org/html/rfc7009) URL | @@ -22,18 +22,18 @@ The first step in implementing OAuth2 is [registering a developer application](# These are a list of all the OAuth2 scopes that Discord supports. Some scopes require approval from Discord to use. Requesting them from a user without approval from Discord may cause errors or undocumented behavior in the OAuth2 flow. | Name | Description | -| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | activities.read | allows your app to fetch data from a user's "Now Playing/Recently Played" list — not currently available for apps | -| activities.write | allows your app to update a user's activity - requires Discord approval (NOT REQUIRED FOR [GAMESDK ACTIVITY MANAGER](#DOCS_GAME_SDK_ACTIVITIES/)) | +| activities.write | allows your app to update a user's activity - not currently available for apps (NOT REQUIRED FOR [GAMESDK ACTIVITY MANAGER](#DOCS_GAME_SDK_ACTIVITIES/)) | | applications.builds.read | allows your app to read build data for a user's applications | | applications.builds.upload | allows your app to upload/update builds for a user's applications - requires Discord approval | -| applications.commands | allows your app to use [commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/) in a guild | +| applications.commands | allows your app to add [commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/) to a guild - included by default with the `bot` scope | | applications.commands.update | allows your app to update its [commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/) using a Bearer token - [client credentials grant](#DOCS_TOPICS_OAUTH2/client-credentials-grant) only | | applications.commands.permissions.update | allows your app to update [permissions for its commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/permissions) in a guild a user has permissions to | | applications.entitlements | allows your app to read entitlements for a user's applications | | applications.store.update | allows your app to read and update store data (SKUs, store listings, achievements, etc.) for a user's applications | | bot | for oauth2 bots, this puts the bot in the user's selected guild by default | -| connections | allows [/users/@me/connections](#DOCS_RESOURCES_USER/get-user-connections) to return linked third-party accounts | +| connections | allows [/users/@me/connections](#DOCS_RESOURCES_USER/get-current-user-connections) to return linked third-party accounts | | dm_channels.read | allows your app to see information about the user's DMs and group DMs - requires Discord approval | | email | enables [/users/@me](#DOCS_RESOURCES_USER/get-current-user) to return an `email` | | gdm.join | allows your app to [join users to a group dm](#DOCS_RESOURCES_CHANNEL/group-dm-add-recipient) | @@ -68,6 +68,8 @@ While Discord does not require the use of the `state` parameter, we support it a The authorization code grant is what most developers will recognize as "standard OAuth2" and involves retrieving an access code and exchanging it for a user's access token. It allows the authorization server to act as an intermediary between the client and the resource owner, so the resource owner's credentials are never shared directly with the client. +All calls to the OAuth2 endpoints require either HTTP Basic authentication or `client_id` and `client_secret` supplied in the form data body. + ###### Authorization URL Example ``` @@ -88,8 +90,6 @@ https://nicememe.website/?code=NhhvTDYsFcdgNLnnLijcl7Ku7bEEeee&state=15773059ghq `code` is now exchanged for the user's access token by making a `POST` request to the [token URL](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-urls) with the following parameters: -- `client_id` - your application's client id -- `client_secret` - your application's client secret - `grant_type` - must be set to `authorization_code` - `code` - the code from the querystring - `redirect_uri` - the `redirect_uri` associated with this authorization, usually from your authorization URL @@ -106,8 +106,6 @@ REDIRECT_URI = 'https://nicememe.website' def exchange_code(code): data = { - 'client_id': CLIENT_ID, - 'client_secret': CLIENT_SECRET, 'grant_type': 'authorization_code', 'code': code, 'redirect_uri': REDIRECT_URI @@ -115,12 +113,12 @@ def exchange_code(code): headers = { 'Content-Type': 'application/x-www-form-urlencoded' } - r = requests.post('%s/oauth2/token' % API_ENDPOINT, data=data, headers=headers) + r = requests.post('%s/oauth2/token' % API_ENDPOINT, data=data, headers=headers, auth=(CLIENT_ID, CLIENT_SECRET)) r.raise_for_status() return r.json() ``` -You can also pass your `client_id` and `client_secret` as basic authentication with `client_id` as the username and `client_secret` as the password. In response, you will receive: +In response, you will receive: ###### Access Token Response @@ -136,8 +134,6 @@ You can also pass your `client_id` and `client_secret` as basic authentication w Having the user's access token allows your application to make certain requests to the API on their behalf, restricted to whatever scopes were requested. `expires_in` is how long, in seconds, until the returned access token expires, allowing you to anticipate the expiration and refresh the token. To refresh, make another `POST` request to the [token URL](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-urls) with the following parameters: -- `client_id` - your application's client id -- `client_secret` - your application's client secret - `grant_type` - must be set to `refresh_token` - `refresh_token` - the user's refresh token @@ -149,25 +145,52 @@ import requests API_ENDPOINT = 'https://discord.com/api/v10' CLIENT_ID = '332269999912132097' CLIENT_SECRET = '937it3ow87i4ery69876wqire' -REDIRECT_URI = 'https://nicememe.website' def refresh_token(refresh_token): data = { - 'client_id': CLIENT_ID, - 'client_secret': CLIENT_SECRET, 'grant_type': 'refresh_token', 'refresh_token': refresh_token } headers = { 'Content-Type': 'application/x-www-form-urlencoded' } - r = requests.post('%s/oauth2/token' % API_ENDPOINT, data=data, headers=headers) + r = requests.post('%s/oauth2/token' % API_ENDPOINT, data=data, headers=headers, auth=(CLIENT_ID, CLIENT_SECRET)) r.raise_for_status() return r.json() ``` Boom; fresh [access token response](#DOCS_TOPICS_OAUTH2/authorization-code-grant-access-token-response)! +###### Token Revocation Example + +To disable an access or refresh token, you can revoke it by making a `POST` request to the [token revocation URL](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-urls) with the following parameters: + +- `token` - the access token or refresh token to revoke +- `token_type_hint` *(optional)* - the `token` parameter's type—either `access_token` or `refresh_token` + +> warn +> When you revoke a token, any active access or refresh tokens associated with that authorization will be revoked, regardless of the `token` and `token_type_hint` values you pass in. + +```python +import requests + +API_ENDPOINT = 'https://discord.com/api/v10' +CLIENT_ID = '332269999912132097' +CLIENT_SECRET = '937it3ow87i4ery69876wqire' + +def revoke_access_token(access_token): + data = { + 'token': access_token, + 'token_type_hint': 'access_token' + } + headers = { + 'Content-Type': 'application/x-www-form-urlencoded' + } + requests.post('%s/oauth2/token/revoke' % API_ENDPOINT, data=data, headers=headers, auth=(CLIENT_ID, CLIENT_SECRET)) +``` + +Boom; the tokens are safely revoked. + ## Implicit Grant The implicit OAuth2 grant is a simplified flow optimized for in-browser clients. Instead of issuing the client an authorization code to be exchanged for an access token, the client is directly issued an access token. The URL is formatted as follows: @@ -257,7 +280,7 @@ Bot authorization is a special server-less and callback-less OAuth2 flow that ma ###### Bot Auth Parameters | name | description | -| -------------------- | --------------------------------------------------------------------- | +|----------------------|-----------------------------------------------------------------------| | client_id | your app's client id | | scope | needs to include `bot` for the bot flow | | permissions | the [permissions](#DOCS_TOPICS_PERMISSIONS/) you're requesting | @@ -272,8 +295,6 @@ https://discord.com/oauth2/authorize?client_id=157730590492196864&scope=bot&perm In the case of bots, the `scope` parameter should be set to `bot`. There's also a new parameter, `permissions`, which is an integer corresponding to the [permission calculations](#DOCS_TOPICS_PERMISSIONS/permissions-bitwise-permission-flags) for the bot. You'll also notice the absence of `response_type` and `redirect_uri`. Bot authorization does not require these parameters because there is no need to retrieve the user's access token. -Additionally, if your bot provides [Application Commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS), you can add `applications.commands` to the URL's scopes, so that commands will be available in the guild. - When the user navigates to this page, they'll be prompted to add the bot to a guild in which they have proper permissions. On acceptance, the bot will be added. Super easy! If you happen to already know the ID of the guild the user will add your bot to, you can provide this ID in the URL as a `guild_id=GUILD_ID` parameter. @@ -400,7 +421,7 @@ Returns info about the current authorization. Requires authentication with a bea ###### Response Structure | Field | Type | Description | -| ----------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | +|-------------|------------------------------------------------------------------------------|-----------------------------------------------------------------------------------| | application | partial [application](#DOCS_RESOURCES_APPLICATION/application-object) object | the current application | | scopes | array of strings | the scopes the user has authorized the application for | | expires | ISO8601 timestamp | when the access token expires | @@ -427,9 +448,10 @@ Returns info about the current authorization. Requires authentication with a bea "expires": "2021-01-23T02:33:17.017000+00:00", "user": { "id": "268473310986240001", - "username": "Discord", + "username": "discord", "avatar": "f749bb0cbeeb26ef21eca719337d20f1", - "discriminator": "0001", + "discriminator": "0", + "global_name": "Discord", "public_flags": 131072 } } diff --git a/docs/topics/Opcodes_and_Status_Codes.md b/docs/topics/Opcodes_and_Status_Codes.md index 39daccd81a..2bbc051a40 100644 --- a/docs/topics/Opcodes_and_Status_Codes.md +++ b/docs/topics/Opcodes_and_Status_Codes.md @@ -29,11 +29,11 @@ In order to prevent broken reconnect loops, you should consider some close codes |------|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------| | 4000 | Unknown error | We're not sure what went wrong. Try reconnecting? | true | | 4001 | Unknown opcode | You sent an invalid [Gateway opcode](#DOCS_TOPICS_OPCODES_AND_STATUS_CODES/gateway-gateway-opcodes) or an invalid payload for an opcode. Don't do that! | true | -| 4002 | Decode error | You sent an invalid [payload](#DOCS_TOPICS_GATEWAY/sending-events) to Discord. Don't do that! | true | -| 4003 | Not authenticated | You sent us a payload prior to [identifying](#DOCS_TOPICS_GATEWAY/identifying). | true | -| 4004 | Authentication failed | The account token sent with your [identify payload](#DOCS_TOPICS_GATEWAY_EVENTS/identify) is incorrect. | false | +| 4002 | Decode error | You sent an invalid [payload](#DOCS_TOPICS_GATEWAY/sending-events) to Discord. Don't do that! | true | +| 4003 | Not authenticated | You sent us a payload prior to [identifying](#DOCS_TOPICS_GATEWAY/identifying). | true | +| 4004 | Authentication failed | The account token sent with your [identify payload](#DOCS_TOPICS_GATEWAY_EVENTS/identify) is incorrect. | false | | 4005 | Already authenticated | You sent more than one identify payload. Don't do that! | true | -| 4007 | Invalid `seq` | The sequence sent when [resuming](#DOCS_TOPICS_GATEWAY_EVENTS/resume) the session was invalid. Reconnect and start a new session. | true | +| 4007 | Invalid `seq` | The sequence sent when [resuming](#DOCS_TOPICS_GATEWAY_EVENTS/resume) the session was invalid. Reconnect and start a new session. | true | | 4008 | Rate limited | Woah nelly! You're sending payloads to us too quickly. Slow it down! You will be disconnected on receiving this. | true | | 4009 | Session timed out | Your session timed out. Reconnect and start a new one. | true | | 4010 | Invalid shard | You sent us an invalid [shard when identifying](#DOCS_TOPICS_GATEWAY/sharding). | false | @@ -67,10 +67,10 @@ Our voice gateways have their own set of opcodes and close codes. | Code | Description | Explanation | |------|--------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------| | 4001 | Unknown opcode | You sent an invalid [opcode](#DOCS_TOPICS_OPCODES_AND_STATUS_CODES/voice-voice-opcodes). | -| 4002 | Failed to decode payload | You sent an invalid payload in your [identifying](#DOCS_TOPICS_GATEWAY_EVENTS/identify) to the Gateway. | -| 4003 | Not authenticated | You sent a payload before [identifying](#DOCS_TOPICS_GATEWAY_EVENTS/identify) with the Gateway. | -| 4004 | Authentication failed | The token you sent in your [identify](#DOCS_TOPICS_GATEWAY_EVENTS/identify) payload is incorrect. | -| 4005 | Already authenticated | You sent more than one [identify](#DOCS_TOPICS_GATEWAY_EVENTS/identify) payload. Stahp. | +| 4002 | Failed to decode payload | You sent an invalid payload in your [identifying](#DOCS_TOPICS_GATEWAY_EVENTS/identify) to the Gateway. | +| 4003 | Not authenticated | You sent a payload before [identifying](#DOCS_TOPICS_GATEWAY_EVENTS/identify) with the Gateway. | +| 4004 | Authentication failed | The token you sent in your [identify](#DOCS_TOPICS_GATEWAY_EVENTS/identify) payload is incorrect. | +| 4005 | Already authenticated | You sent more than one [identify](#DOCS_TOPICS_GATEWAY_EVENTS/identify) payload. Stahp. | | 4006 | Session no longer valid | Your session is no longer valid. | | 4009 | Session timeout | Your session has timed out. | | 4011 | Server not found | We can't find the server you're trying to connect to. | @@ -282,6 +282,7 @@ Along with the HTTP error code, our API can also return more detailed error code | 60003 | Two factor is required for this operation | | 80004 | No users with DiscordTag exist | | 90001 | Reaction was blocked | +| 90002 | User cannot use burst reactions | | 110001 | Application not yet available. Try again later | | 130000 | API resource is currently overloaded. Try again a little later | | 150006 | The Stage is already open | diff --git a/docs/topics/Permissions.md b/docs/topics/Permissions.md index 144f382363..80bacd8b55 100644 --- a/docs/topics/Permissions.md +++ b/docs/topics/Permissions.md @@ -31,7 +31,7 @@ Below is a table of all current permissions, their integer values in hexadecimal ###### Bitwise Permission Flags | Permission | Value | Description | Channel Type | -| -------------------------------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | +|----------------------------------------|----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|--------------| | CREATE_INSTANT_INVITE | `0x0000000000000001` `(1 << 0)` | Allows creation of instant invites | T, V, S | | KICK_MEMBERS \* | `0x0000000000000002` `(1 << 1)` | Allows kicking members | | | BAN_MEMBERS \* | `0x0000000000000004` `(1 << 2)` | Allows banning members | | @@ -192,7 +192,7 @@ Roles represent a set of permissions attached to a group of users. Roles have na ###### Role Structure | Field | Type | Description | -| -------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +|----------------|------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------| | id | snowflake | role id | | name | string | role name | | color | integer | integer representation of hexadecimal color code | @@ -213,7 +213,7 @@ Roles without colors (`color == 0`) do not count towards the final computed colo Tags with type `null` represent booleans. They will be present and set to `null` if they are "true", and will be not present if they are "false". | Field | Type | Description | -| ------------------------ | --------- | -------------------------------------------------- | +|--------------------------|-----------|----------------------------------------------------| | bot_id? | snowflake | the id of the bot this role belongs to | | integration_id? | snowflake | the id of the integration this role belongs to | | premium_subscriber? | null | whether this is the guild's Booster role | @@ -242,7 +242,7 @@ Tags with type `null` represent booleans. They will be present and set to `null` ###### Role Flags | Flag | Value | Description | -| --------- | ------ | -------------------------------------------------------------------------------------------------------- | +|-----------|--------|----------------------------------------------------------------------------------------------------------| | IN_PROMPT | 1 << 0 | role can be selected by members in an [onboarding](#DOCS_RESOURCES_GUILD/guild-onboarding-object) prompt | ## Permissions For Timed Out Members diff --git a/docs/topics/RPC.md b/docs/topics/RPC.md index 6425deb040..5f91f225a8 100644 --- a/docs/topics/RPC.md +++ b/docs/topics/RPC.md @@ -8,7 +8,7 @@ All Discord clients have an RPC server running on localhost that allows control ###### RPC Versions | Version | Out of Service | -| ------- | -------------- | +|---------|----------------| | 1 | no | ## Restrictions @@ -22,7 +22,7 @@ For applications/games not approved, we limit you to creating 10 guilds and 10 c ###### Payload Structure | Field | Type | Description | Present | -| ----- | ------ | --------------------------------------------------------------------- | -------------------------------------------------------- | +|-------|--------|-----------------------------------------------------------------------|----------------------------------------------------------| | cmd | enum | [payload command](#DOCS_TOPICS_RPC/commands-and-events-rpc-commands) | Always | | nonce | string | unique string used once for replies from the server | In responses to commands (not subscribed events) | | evt | enum | [subscription event](#DOCS_TOPICS_RPC/commands-and-events-rpc-events) | In subscribed events, errors, and (un)subscribing events | @@ -92,7 +92,7 @@ Commands are requests made to the RPC socket by a client. ###### RPC Commands | Name | Description | -| ---------------------------------------------------------------------- | --------------------------------------------------------------- | +|------------------------------------------------------------------------|-----------------------------------------------------------------| | [DISPATCH](#DOCS_TOPICS_RPC/commands-and-events-rpc-events) | event dispatch | | [AUTHORIZE](#DOCS_TOPICS_RPC/authorize) | used to authorize a new client with your app | | [AUTHENTICATE](#DOCS_TOPICS_RPC/authenticate) | used to authenticate an existing client with your app | @@ -117,28 +117,28 @@ Events are payloads sent over the socket to a client that correspond to events i ###### RPC Events -| Name | Description | -| --------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | -| [READY](#DOCS_TOPICS_RPC/ready) | non-subscription event sent immediately after connecting, contains server information | -| [ERROR](#DOCS_TOPICS_RPC/error) | non-subscription event sent when there is an error, including command responses | -| [GUILD_STATUS](#DOCS_TOPICS_RPC/guildstatus) | sent when a subscribed server's state changes | -| [GUILD_CREATE](#DOCS_TOPICS_RPC/guildcreate) | sent when a guild is created/joined on the client | -| [CHANNEL_CREATE](#DOCS_TOPICS_RPC/channelcreate) | sent when a channel is created/joined on the client | -| [VOICE_CHANNEL_SELECT](#DOCS_TOPICS_RPC/voicechannelselect) | sent when the client joins a voice channel | -| [VOICE_STATE_CREATE](#DOCS_TOPICS_RPC/voicestatecreatevoicestateupdatevoicestatedelete) | sent when a user joins a subscribed voice channel | -| [VOICE_STATE_UPDATE](#DOCS_TOPICS_RPC/voicestatecreatevoicestateupdatevoicestatedelete) | sent when a user's voice state changes in a subscribed voice channel (mute, volume, etc.) | -| [VOICE_STATE_DELETE](#DOCS_TOPICS_RPC/voicestatecreatevoicestateupdatevoicestatedelete) | sent when a user parts a subscribed voice channel | -| [VOICE_SETTINGS_UPDATE](#DOCS_TOPICS_RPC/voicesettingsupdate) | sent when the client's voice settings update | -| [VOICE_CONNECTION_STATUS](#DOCS_TOPICS_RPC/voiceconnectionstatus) | sent when the client's voice connection status changes | -| [SPEAKING_START](#DOCS_TOPICS_RPC/speakingstartspeakingstop) | sent when a user in a subscribed voice channel speaks | -| [SPEAKING_STOP](#DOCS_TOPICS_RPC/speakingstartspeakingstop) | sent when a user in a subscribed voice channel stops speaking | -| [MESSAGE_CREATE](#DOCS_TOPICS_RPC/messagecreatemessageupdatemessagedelete) | sent when a message is created in a subscribed text channel | -| [MESSAGE_UPDATE](#DOCS_TOPICS_RPC/messagecreatemessageupdatemessagedelete) | sent when a message is updated in a subscribed text channel | -| [MESSAGE_DELETE](#DOCS_TOPICS_RPC/messagecreatemessageupdatemessagedelete) | sent when a message is deleted in a subscribed text channel | -| [NOTIFICATION_CREATE](#DOCS_TOPICS_RPC/notificationcreate) | sent when the client receives a notification (mention or new message in eligible channels) | -| [ACTIVITY_JOIN](#DOCS_TOPICS_RPC/activityjoin) | sent when the user clicks a Rich Presence join invite in chat to join a game | -| [ACTIVITY_SPECTATE](#DOCS_TOPICS_RPC/activityspectate) | sent when the user clicks a Rich Presence spectate invite in chat to spectate a game | -| [ACTIVITY_JOIN_REQUEST](#DOCS_TOPICS_RPC/activityjoinrequest) | sent when the user receives a Rich Presence Ask to Join request | +| Name | Description | +|-----------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| +| [READY](#DOCS_TOPICS_RPC/ready) | non-subscription event sent immediately after connecting, contains server information | +| [ERROR](#DOCS_TOPICS_RPC/error) | non-subscription event sent when there is an error, including command responses | +| [GUILD_STATUS](#DOCS_TOPICS_RPC/guildstatus) | sent when a subscribed server's state changes | +| [GUILD_CREATE](#DOCS_TOPICS_RPC/guildcreate) | sent when a guild is created/joined on the client | +| [CHANNEL_CREATE](#DOCS_TOPICS_RPC/channelcreate) | sent when a channel is created/joined on the client | +| [VOICE_CHANNEL_SELECT](#DOCS_TOPICS_RPC/voicechannelselect) | sent when the client joins a voice channel | +| [VOICE_STATE_CREATE](#DOCS_TOPICS_RPC/voicestatecreatevoicestateupdatevoicestatedelete) | sent when a user joins a subscribed voice channel | +| [VOICE_STATE_UPDATE](#DOCS_TOPICS_RPC/voicestatecreatevoicestateupdatevoicestatedelete) | sent when a user's voice state changes in a subscribed voice channel (mute, volume, etc.) | +| [VOICE_STATE_DELETE](#DOCS_TOPICS_RPC/voicestatecreatevoicestateupdatevoicestatedelete) | sent when a user parts a subscribed voice channel | +| [VOICE_SETTINGS_UPDATE](#DOCS_TOPICS_RPC/voicesettingsupdate) | sent when the client's voice settings update | +| [VOICE_CONNECTION_STATUS](#DOCS_TOPICS_RPC/voiceconnectionstatus) | sent when the client's voice connection status changes | +| [SPEAKING_START](#DOCS_TOPICS_RPC/speakingstartspeakingstop) | sent when a user in a subscribed voice channel speaks | +| [SPEAKING_STOP](#DOCS_TOPICS_RPC/speakingstartspeakingstop) | sent when a user in a subscribed voice channel stops speaking | +| [MESSAGE_CREATE](#DOCS_TOPICS_RPC/messagecreatemessageupdatemessagedelete) | sent when a message is created in a subscribed text channel | +| [MESSAGE_UPDATE](#DOCS_TOPICS_RPC/messagecreatemessageupdatemessagedelete) | sent when a message is updated in a subscribed text channel | +| [MESSAGE_DELETE](#DOCS_TOPICS_RPC/messagecreatemessageupdatemessagedelete) | sent when a message is deleted in a subscribed text channel | +| [NOTIFICATION_CREATE](#DOCS_TOPICS_RPC/notificationcreate) | sent when the client receives a notification (mention or new message in eligible channels) | +| [ACTIVITY_JOIN](#DOCS_TOPICS_RPC/activityjoin) | sent when the user clicks a Rich Presence join invite in chat to join a game | +| [ACTIVITY_SPECTATE](#DOCS_TOPICS_RPC/activityspectate) | sent when the user clicks a Rich Presence spectate invite in chat to spectate a game | +| [ACTIVITY_JOIN_REQUEST](#DOCS_TOPICS_RPC/activityjoinrequest) | sent when the user receives a Rich Presence Ask to Join request | #### AUTHORIZE @@ -151,7 +151,7 @@ We also have an RPC token system to bypass the user authorization modal. This is ###### Authorize Argument Structure | Field | Type | Description | -| --------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------- | +|-----------|------------------------------------------------------------------------------|---------------------------------------------------------------------------| | scopes | array of [OAuth2 scopes](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) | scopes to authorize | | client_id | string | OAuth2 application id | | rpc_token | string | one-time use RPC token | @@ -160,7 +160,7 @@ We also have an RPC token system to bypass the user authorization modal. This is ###### Authorize Response Structure | Field | Type | Description | -| ----- | ------ | ------------------------- | +|-------|--------|---------------------------| | code | string | OAuth2 authorization code | ###### Example Authorize Command Payload @@ -195,13 +195,13 @@ Used to authenticate an existing client with your app. ###### Authenticate Argument Structure | Field | Type | Description | -| ------------ | ------ | ------------------- | +|--------------|--------|---------------------| | access_token | string | OAuth2 access token | ###### Authenticate Response Structure | Field | Type | Description | -| ----------- | --------------------------------------------------------------------------------------- | ------------------------------- | +|-------------|-----------------------------------------------------------------------------------------|---------------------------------| | user | partial [user](#DOCS_RESOURCES_USER/user-object) object | the authed user | | scopes | array of [OAuth2 scopes](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) | authorized scopes | | expires | date | expiration date of OAuth2 token | @@ -210,7 +210,7 @@ Used to authenticate an existing client with your app. ###### OAuth2 Application Structure | Field | Type | Description | -| ----------- | ---------------- | ------------------------ | +|-------------|------------------|--------------------------| | description | string | application description | | icon | string | hash of the icon | | id | snowflake | application client id | @@ -262,7 +262,7 @@ Used to get a list of guilds the client is in. ###### Get Guilds Response Structure | Field | Type | Description | -| ------ | -------------------------------------------------------------------- | ------------------------- | +|--------|----------------------------------------------------------------------|---------------------------| | guilds | array of partial [guild](#DOCS_RESOURCES_GUILD/guild-object) objects | the guilds the user is in | ###### Example Get Guilds Command Payload @@ -299,14 +299,14 @@ Used to get a guild the client is in. ###### Get Guild Argument Structure | Field | Type | Description | -| -------- | ------- | ------------------------------------------------------------ | +|----------|---------|--------------------------------------------------------------| | guild_id | string | id of the guild to get | | timeout | integer | asynchronously get guild with time to wait before timing out | ###### Get Guild Response Structure | Field | Type | Description | -| -------- | -------------------------------------------------------------------------- | ----------------------------------------------------- | +|----------|----------------------------------------------------------------------------|-------------------------------------------------------| | id | string | guild id | | name | string | guild name | | icon_url | string | guild icon url | @@ -346,13 +346,13 @@ Used to get a channel the client is in. ###### Get Channel Argument Structure | Field | Type | Description | -| ---------- | ------ | ------------------------ | +|------------|--------|--------------------------| | channel_id | string | id of the channel to get | ###### Get Channel Response Structure | Field | Type | Description | -| ------------ | ------------------------------------------------------------------------ | ---------------------------------------------------------------- | +|--------------|--------------------------------------------------------------------------|------------------------------------------------------------------| | id | string | channel id | | guild_id | string | channel's guild id | | name | string | channel name | @@ -426,13 +426,13 @@ Used to get a guild's channels the client is in. ###### Get Channels Argument Structure | Field | Type | Description | -| -------- | ------ | ----------------------------------- | +|----------|--------|-------------------------------------| | guild_id | string | id of the guild to get channels for | ###### Get Channels Response Structure | Field | Type | Description | -| -------- | -------------------------------------------------------------------------- | ----------------------------- | +|----------|----------------------------------------------------------------------------|-------------------------------| | channels | array of partial [channel](#DOCS_RESOURCES_CHANNEL/channel-object) objects | guild channels the user is in | ###### Example Get Channels Command Payload @@ -477,7 +477,7 @@ Used to change voice settings of users in voice channels ###### Set User Voice Settings Argument and Response Structure | Field | Type | Description | -| ------- | -------------------------------------------------------------- | -------------------------------------------------------- | +|---------|----------------------------------------------------------------|----------------------------------------------------------| | user_id | string | user id | | pan? | [pan](#DOCS_TOPICS_RPC/setuservoicesettings-pan-object) object | set the pan of the user | | volume? | integer | set the volume of user (defaults to 100, min 0, max 200) | @@ -494,7 +494,7 @@ Used to change voice settings of users in voice channels ###### Pan Object | Field | Type | Description | -| ----- | ----- | -------------------------------------- | +|-------|-------|----------------------------------------| | left | float | left pan of user (min: 0.0, max: 1.0) | | right | float | right pan of user (min: 0.0, max: 1.0) | @@ -541,7 +541,7 @@ Used to join and leave voice channels, group dms, or dms. Returns the [Get Chann ###### Select Voice Channel Argument Structure | Field | Type | Description | -| ---------- | ------- | --------------------------------------------------------------- | +|------------|---------|-----------------------------------------------------------------| | channel_id | string | channel id to join (or `null` to leave) | | timeout | integer | asynchronously join channel with time to wait before timing out | | force | boolean | forces a user to join a voice channel | @@ -616,7 +616,7 @@ Used to join and leave text channels, group dms, or dms. Returns the [Get Channe ###### Select Text Channel Argument Structure | Field | Type | Description | -| ---------- | ------- | --------------------------------------------------------------- | +|------------|---------|-----------------------------------------------------------------| | channel_id | string | channel id to join (or `null` to leave) | | timeout | integer | asynchronously join channel with time to wait before timing out | @@ -625,7 +625,7 @@ Used to join and leave text channels, group dms, or dms. Returns the [Get Channe ###### Get Voice Settings Response Structure | Field | Type | Description | -| ---------------------- | ---------------------------------------------------------------------------------------------- | --------------------------------- | +|------------------------|------------------------------------------------------------------------------------------------|-----------------------------------| | input | [voice settings input](#DOCS_TOPICS_RPC/getvoicesettings-voice-settings-input-object) object | input settings | | output | [voice settings output](#DOCS_TOPICS_RPC/getvoicesettings-voice-settings-output-object) object | output settings | | mode | [voice settings mode](#DOCS_TOPICS_RPC/getvoicesettings-voice-settings-mode-object) object | voice mode settings | @@ -640,7 +640,7 @@ Used to join and leave text channels, group dms, or dms. Returns the [Get Channe ###### Voice Settings Input Object | Field | Type | Description | -| ----------------- | ---------------- | -------------------------------------------------------------------------- | +|-------------------|------------------|----------------------------------------------------------------------------| | device_id | string | device id | | volume | float | input voice level (min: 0, max: 100) | | available_devices | array of objects | array of _read-only_ device objects containing `id` and `name` string keys | @@ -648,7 +648,7 @@ Used to join and leave text channels, group dms, or dms. Returns the [Get Channe ###### Voice Settings Output Object | Field | Type | Description | -| ----------------- | ---------------- | -------------------------------------------------------------------------- | +|-------------------|------------------|----------------------------------------------------------------------------| | device_id | string | device id | | volume | float | output voice level (min: 0, max: 200) | | available_devices | array of objects | array of _read-only_ device objects containing `id` and `name` string keys | @@ -656,7 +656,7 @@ Used to join and leave text channels, group dms, or dms. Returns the [Get Channe ###### Voice Settings Mode Object | Field | Type | Description | -| -------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | +|----------------|------------------------------------------------------------------------------------------|---------------------------------------------------------------------| | type | string | voice setting mode type (can be `PUSH_TO_TALK` or `VOICE_ACTIVITY`) | | auto_threshold | boolean | voice activity threshold automatically sets its threshold | | threshold | float | threshold for voice activity (in dB) (min: -100, max: 0) | @@ -666,19 +666,19 @@ Used to join and leave text channels, group dms, or dms. Returns the [Get Channe ###### Shortcut Key Combo Object | Field | Type | Description | -| ----- | ------- | ------------------------------------------------------------ | +|-------|---------|--------------------------------------------------------------| | type | integer | see [key types](#DOCS_TOPICS_RPC/getvoicesettings-key-types) | | code | integer | key code | | name | string | key name | ###### Key Types -| Type | Id | -| --------------------- | --- | -| KEYBOARD_KEY | 0 | -| MOUSE_BUTTON | 1 | -| KEYBOARD_MODIFIER_KEY | 2 | -| GAMEPAD_BUTTON | 3 | +| Type | Id | +|-----------------------|----| +| KEYBOARD_KEY | 0 | +| MOUSE_BUTTON | 1 | +| KEYBOARD_MODIFIER_KEY | 2 | +| GAMEPAD_BUTTON | 3 | ###### Example Get Voice Settings Response Payload @@ -748,7 +748,7 @@ When setting voice settings, all fields are optional. Only passed fields are upd ###### Set Voice Settings Argument and Response Structure | Field | Type | Description | -| ---------------------- | ---------------------------------------------------------------------------------------------- | --------------------------------- | +|------------------------|------------------------------------------------------------------------------------------------|-----------------------------------| | input | [voice settings input](#DOCS_TOPICS_RPC/getvoicesettings-voice-settings-input-object) object | input settings | | output | [voice settings output](#DOCS_TOPICS_RPC/getvoicesettings-voice-settings-output-object) object | output settings | | mode | [voice settings mode](#DOCS_TOPICS_RPC/getvoicesettings-voice-settings-mode-object) object | voice mode settings | @@ -834,7 +834,7 @@ Used to subscribe to events. `evt` of the payload should be set to the event bei ###### Subscribe Response Structure | Field | Type | Description | -| ----- | ------ | ---------------------------- | +|-------|--------|------------------------------| | evt | string | event name now subscribed to | ###### Example Subscribe Command Payload @@ -869,7 +869,7 @@ Used to unsubscribe from events. `evt` of the payload should be set to the event ###### Unsubscribe Response Structure | Field | Type | Description | -| ----- | ------ | -------------------------------- | +|-------|--------|----------------------------------| | evt | string | event name now unsubscribed from | ###### Example Unsubscribe Command Payload @@ -903,44 +903,44 @@ Used by hardware manufacturers to send information about the current state of th ###### Set Certified Devices Argument Structure -| Field | Type | Description | -| ------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------- | +| Field | Type | Description | +|---------|-----------------------------------------------------------------------------------------|---------------------------------------------------------------| | devices | array of [certified device](#DOCS_TOPICS_RPC/setcertifieddevices-device-object) objects | a list of devices for your manufacturer, in order of priority | ###### Device Object -| Field | Type | Description | -| ------------------------- | --------------------------------------------------------------------- | -------------------------------------------------------- | -| type | [device type](#DOCS_TOPICS_RPC/setcertifieddevices-device-type) | the type of device | -| id | string | the device's Windows UUID | -| vendor | [vendor](#DOCS_TOPICS_RPC/setcertifieddevices-vendor-object) object | the hardware vendor | -| model | [model](#DOCS_TOPICS_RPC/setcertifieddevices-model-object) object | the model of the product | -| related | array of strings | UUIDs of related devices | -| echo_cancellation?\* | boolean | if the device's native echo cancellation is enabled | -| noise_suppression?\* | boolean | if the device's native noise suppression is enabled | -| automatic_gain_control?\* | boolean | if the device's native automatic gain control is enabled | -| hardware_mute?\* | boolean | if the device is hardware muted | +| Field | Type | Description | +|---------------------------|---------------------------------------------------------------------|----------------------------------------------------------| +| type | [device type](#DOCS_TOPICS_RPC/setcertifieddevices-device-type) | the type of device | +| id | string | the device's Windows UUID | +| vendor | [vendor](#DOCS_TOPICS_RPC/setcertifieddevices-vendor-object) object | the hardware vendor | +| model | [model](#DOCS_TOPICS_RPC/setcertifieddevices-model-object) object | the model of the product | +| related | array of strings | UUIDs of related devices | +| echo_cancellation?\* | boolean | if the device's native echo cancellation is enabled | +| noise_suppression?\* | boolean | if the device's native noise suppression is enabled | +| automatic_gain_control?\* | boolean | if the device's native automatic gain control is enabled | +| hardware_mute?\* | boolean | if the device is hardware muted | \*These fields are only applicable for `AUDIO_INPUT` device types ###### Vendor Object | Field | Type | Description | -| ----- | ------ | ------------------ | +|-------|--------|--------------------| | name | string | name of the vendor | | url | string | url for the vendor | ###### Model Object | Field | Type | Description | -| ----- | ------ | ----------------- | +|-------|--------|-------------------| | name | string | name of the model | | url | string | url for the model | ###### Device Type | Type | Value | -| ------------ | ------------- | +|--------------|---------------| | AUDIO_INPUT | "audioinput" | | AUDIO_OUTPUT | "audiooutput" | | VIDEO_INPUT | "videoinput" | @@ -992,9 +992,9 @@ Used to update a user's Rich Presence. ###### Set Activity Argument Structure -| Field | Type | Description | -| -------- | ------------------------------------------------------- | --------------------------------------- | -| pid | integer | the application's process id | +| Field | Type | Description | +|----------|----------------------------------------------------------------|-----------------------------------------| +| pid | integer | the application's process id | | activity | [activity](#DOCS_TOPICS_GATEWAY_EVENTS/activity-object) object | the rich presence to assign to the user | ###### Example Set Activity Payload @@ -1040,7 +1040,7 @@ Used to accept an Ask to Join request. ###### Send Activity Join Invite Argument Structure | Field | Type | Description | -| ------- | --------- | ----------------------------- | +|---------|-----------|-------------------------------| | user_id | snowflake | the id of the requesting user | ###### Example Send Activity Join Invite Payload @@ -1062,7 +1062,7 @@ Used to reject an Ask to Join request. ###### Close Activity Request Argument Structure | Field | Type | Description | -| ------- | --------- | ----------------------------- | +|---------|-----------|-------------------------------| | user_id | snowflake | the id of the requesting user | ###### Example Close Activity Request Payload @@ -1082,7 +1082,7 @@ Used to reject an Ask to Join request. ###### Ready Dispatch Data Structure | Field | Type | Description | -| ------ | ----------------------------------------------------------------------------------------- | ---------------------------------- | +|--------|-------------------------------------------------------------------------------------------|------------------------------------| | v | integer | RPC version | | config | [rpc server configuration](#DOCS_TOPICS_RPC/ready-rpc-server-configuration-object) object | server configuration | | user | partial [user](#DOCS_RESOURCES_USER/user-object) object | the user to whom you are connected | @@ -1090,7 +1090,7 @@ Used to reject an Ask to Join request. ###### RPC Server Configuration Object | Field | Type | Description | -| ------------ | ------ | --------------------- | +|--------------|--------|-----------------------| | cdn_host | string | server's cdn | | api_endpoint | string | server's api endpoint | | environment | string | server's environment | @@ -1123,7 +1123,7 @@ Used to reject an Ask to Join request. ###### Error Data Structure | Field | Type | Description | -| ------- | ------- | ----------------- | +|---------|---------|-------------------| | code | integer | RPC Error Code | | message | string | Error description | @@ -1146,13 +1146,13 @@ Used to reject an Ask to Join request. ###### Guild Status Argument Structure | Field | Type | Description | -| -------- | ------ | ----------------------------------- | +|----------|--------|-------------------------------------| | guild_id | string | id of guild to listen to updates of | ###### Guild Status Dispatch Data Structure | Field | Type | Description | -| ------ | ---------------------------------------------------------- | ------------------------------------------------------ | +|--------|------------------------------------------------------------|--------------------------------------------------------| | guild | partial [guild](#DOCS_RESOURCES_GUILD/guild-object) object | guild with requested id | | online | integer | number of online users in guild (deprecated; always 0) | @@ -1180,7 +1180,7 @@ No arguments ###### Guild Create Dispatch Data Structure | Field | Type | Description | -| ----- | ------ | ----------------- | +|-------|--------|-------------------| | id | string | guild id | | name | string | name of the guild | @@ -1204,7 +1204,7 @@ No arguments ###### Channel Create Dispatch Data Structure | Field | Type | Description | -| ----- | ------- | ---------------------------------------------------------------- | +|-------|---------|------------------------------------------------------------------| | id | string | channel id | | name | string | name of the channel | | type | integer | channel type (guild text: 0, guild voice: 2, dm: 1, group dm: 3) | @@ -1230,7 +1230,7 @@ No arguments ###### Voice Channel Select Dispatch Data Structure | Field | Type | Description | -| ---------- | ------ | ------------------------------ | +|------------|--------|--------------------------------| | channel_id | string | id of channel (`null` if none) | | guild_id | string | id of guild (`null` if none) | @@ -1311,7 +1311,7 @@ Dispatches channel voice state objects ###### Voice State Argument Structure | Field | Type | Description | -| ---------- | ------ | ------------------------------------- | +|------------|--------|---------------------------------------| | channel_id | string | id of channel to listen to updates of | ###### Example Voice State Dispatch Payload @@ -1353,7 +1353,7 @@ No arguments ###### Voice Connection Status Dispatch Data Structure | Field | Type | Description | -| ------------ | ----------------- | ----------------------------------------------- | +|--------------|-------------------|-------------------------------------------------| | state | string | one of the voice connection states listed below | | hostname | string | hostname of the connected voice server | | pings | array of integers | last 20 pings (in ms) | @@ -1363,7 +1363,7 @@ No arguments ###### Voice Connection States | Field | Description | -| ------------------ | --------------------------------- | +|--------------------|-----------------------------------| | DISCONNECTED | TCP disconnected | | AWAITING_ENDPOINT | Waiting for voice endpoint | | AUTHENTICATING | TCP authenticating | @@ -1398,7 +1398,7 @@ Dispatches message objects, with the exception of deletions, which only contains ###### Message Argument Structure | Field | Type | Description | -| ---------- | ------ | ------------------------------------- | +|------------|--------|---------------------------------------| | channel_id | string | id of channel to listen to updates of | ###### Example Message Dispatch Payload @@ -1447,13 +1447,13 @@ Dispatches message objects, with the exception of deletions, which only contains ###### Speaking Argument Structure | Field | Type | Description | -| ---------- | ------ | ------------------------------------- | +|------------|--------|---------------------------------------| | channel_id | string | id of channel to listen to updates of | ###### Speaking Dispatch Data Structure | Field | Type | Description | -| ------- | ------ | --------------------------------------- | +|---------|--------|-----------------------------------------| | user_id | string | id of user who started/stopped speaking | ###### Example Speaking Dispatch Payload @@ -1475,7 +1475,7 @@ No arguments. This event requires the `rpc.notifications.read` [OAuth2 scope](#D ###### Notification Create Dispatch Data Structure | Field | Type | Description | -| ---------- | -------------------------------------------------------- | ----------------------------------------- | +|------------|----------------------------------------------------------|-------------------------------------------| | channel_id | string | id of channel where notification occurred | | message | [message](#DOCS_RESOURCES_CHANNEL/message-object) object | message that generated this notification | | icon_url | string | icon url of the notification | @@ -1533,7 +1533,7 @@ No arguments ###### Activity Join Dispatch Data Structure | Field | Type | Description | -| ------ | ------ | --------------------------------------------------------------------------------------------------------------------- | +|--------|--------|-----------------------------------------------------------------------------------------------------------------------| | secret | string | the [`join_secret`](#DOCS_RICH_PRESENCE_HOW_TO/updating-presence-update-presence-payload-fields) for the given invite | ###### Example Activity Join Dispatch Payload @@ -1555,7 +1555,7 @@ No arguments ###### Activity Spectate Dispatch Data Structure | Field | Type | Description | -| ------ | ------ | ------------------------------------------------------------------------------------------------------------------------- | +|--------|--------|---------------------------------------------------------------------------------------------------------------------------| | secret | string | the [`spectate_secret`](#DOCS_RICH_PRESENCE_HOW_TO/updating-presence-update-presence-payload-fields) for the given invite | ###### Example Activity Spectate Dispatch Payload @@ -1577,7 +1577,7 @@ No arguments ###### Activity Join Request Data Structure | Field | Type | Description | -| ----- | ------------------------------------------------------- | --------------------------------------------- | +|-------|---------------------------------------------------------|-----------------------------------------------| | user | partial [user](#DOCS_RESOURCES_USER/user-object) object | information about the user requesting to join | ###### Example Activity Join Request Dispatch Payload diff --git a/docs/topics/Rate_Limits.md b/docs/topics/Rate_Limits.md index 9fa2701e70..1cdf397993 100644 --- a/docs/topics/Rate_Limits.md +++ b/docs/topics/Rate_Limits.md @@ -42,12 +42,12 @@ In the case that a rate limit is exceeded, the API will return a HTTP 429 respon ###### Rate Limit Response Structure -| Field | Type | Description | -|-------------|------------------|-----------------------------------------------------------------------------| -| message | string | A message saying you are being rate limited. | -| retry_after | float | The number of seconds to wait before submitting another request. | -| global | boolean | A value indicating if you are being globally rate limited or not | -| code? | integer | An [error code](#DOCS_TOPICS_OPCODES_AND_STATUS_CODES/json) for some limits | +| Field | Type | Description | +|-------------|---------|-----------------------------------------------------------------------------| +| message | string | A message saying you are being rate limited. | +| retry_after | float | The number of seconds to wait before submitting another request. | +| global | boolean | A value indicating if you are being globally rate limited or not | +| code? | integer | An [error code](#DOCS_TOPICS_OPCODES_AND_STATUS_CODES/json) for some limits | Note that normal route rate-limiting headers will also be sent in this response. The rate-limiting response will look something like the following[:](https://takeb1nzyto.space/) diff --git a/docs/topics/Teams.md b/docs/topics/Teams.md index 0671f36026..153adc49e0 100644 --- a/docs/topics/Teams.md +++ b/docs/topics/Teams.md @@ -1,80 +1,78 @@ # Teams -Teams are groups of developers on Discord who want to collaborate on apps. On other platforms, these may be referred to as "organizations", "companies", or "teams". We went with the name Teams because it best encompassed all the awesome conglomerates of devs that work together to make awesome things on Discord. Also, we never got picked for kickball in gym class, so now we get to be on a team. +Teams are groups of developers (or other Discord users) who want to collaborate and share access to an app's configuration, management, and payout settings. Go team(s)! -## What Do They Do +## Creating a Team -Teams allow you and other Discord users to share access to apps. No more sharing login credentials in order to reset the token on a bot that your friend owns but you work on, or other such cases. +To create or be a member on a team, you must [enable 2FA for your Discord account](https://support.discord.com/hc/en-us/articles/219576828-Setting-up-Two-Factor-Authentication). After you have 2FA enabled, create a team by navigating to the [Teams page](https://discord.com/developers/teams) then clicking the "New Team" button. -For game developers, this means that you can get your engineers access to your app for credentials they may need, your marketing folks access to store page management, and your finance people access to sales and performance metrics. +![Screenshot of the Teams page](team-page.png) -> danger -> For the initial release, Teams only support one kind of user: Admin. Admins have full access to all parts of an app _except_ for deleting the app and adding/removing users. That can only be done by the owner of the Team. - -## How Do I Make One - -Making a Team is easy! Head on over to our [Team creation](https://discord.com/developers/teams) page and make your own. - -![Screenshot of the initial landing page for viewing Teams that you are a part of](team-page.png) - -Note that to use Discord Teams, you need to have 2FA enabled on your account. Security is of the utmost importance, especially when it comes to shared resources. If you're developing on your own and don't want to use Teams, you do not need 2FA. But, in order to keep other Team members safe, you'll need to add it to use Teams. +Once you create a team, you'll land on the **Team Information** page where you can fill out details and start inviting other Discord users to join your team. Since users added to a team have access to any apps that team owns, use caution when adding new team members. -![Screenshot of the 2FA requirement modal](team-2fa.png) +> info +> Currently, only the team Owner can invite or remove additional users. -Once your team is made, you can start inviting other Discord users to join. +## Adding Apps to a Team -> info -> For the initial release, only the Team owner can invite or remove additional users. +Once your team is set up, you can create or transfer apps that will be owned by the team. Teams can have a maximum of 25 apps. -## Apps on Teams +### Creating an App -Now that you've got your Team set up, you can start creating apps under it. Teams can own a maximum of 25 apps. To create a new app under a Team, select the Team in the app creation modal. If you want to keep the app under your own ownership, choose `Personal`: +To create a new app that belongs to a team, select the team from the **Team** dropdown in the app creation modal. If you want to keep the app under your own account's ownership, choose `Personal`: -![Screenshot of the Team Application creation modal](team-make-app.png) +![Screenshot of the create application modal with a Team selected](create-team-owned-app.png) -If you have an existing app that you want to transfer to a Team, you can do that, too! Just go into the app that you want to transfer, hit `Transfer App to Team`, and send the app to its new home. +### Transfering an App -![Screenshot of where to find the button to transfer an Application to a Team](transfer-app-to-team.png) +To transfer an existing app to a team, navigate to the [Application](https://discord.com/developers/applications) that you want to transfer. At the bottom of the app's **General Information** page, click "Transfer App to Team". > danger > Once an app has been transferred to a team, it _cannot_ be transferred back. -## What Next +![Screenshot of where to find the button to transfer an Application to a team](transfer-app-to-team.png) + +## Team Member Roles -What next? Go make awesome stuff! Whether you're a Game Developer, Mad Bot Scientist, or OAuth2 Enthusiast, you can now work together with other like-minded Discordians to bring your creations to life. +Team members can be one of four roles (owner, admin, developer, and read-only), and each role inherits the access of those below it. Roles for team members can be configured under **Team Members** in a team's settings. -We've got a lot of awesome features planned for teams in the future, so stay tuned for things like: +###### Team Member Role Types -- Roles and Permissions -- Audit Logs -- More cat pictures +| Role Name | Value | Description | +|-----------|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Owner\* | | Owners are the most permissiable role, and can take destructive, irreversible actions like deleting team-owned apps or the team itself. Teams are limited to 1 owner. | +| Admin | admin | Admins have similar access as owners, except they cannot take destructive actions on the team or team-owned apps. | +| Developer | developer | Developers can access information about team-owned apps, like the client secret or public key. They can also take limited actions on team-owned apps, like configuring interaction endpoints or resetting the bot token. Members with the Developer role *cannot* manage the team or its members, or take destructive actions on team-owned apps. | +| Read-only | read_only | Read-only members can access information about a team and any team-owned apps. Some examples include getting the IDs of applications and exporting payout records. | + +\* The owner role is not represented in the `role` field on the [team member object](#DOCS_TOPICS_TEAMS/data-models-team-member-object). Instead, the `owner_user_id` field on the [team object](#DOCS_TOPICS_TEAMS/data-models-team-object) should be used to identify which user has the owner role for the team. -Go team! ## Data Models ###### Team Object -| field | type | description | -| ------------- | --------------------------------------------------------------------------------- | -------------------------------------- | -| icon | ?string | a hash of the image of the team's icon | -| id | snowflake | the unique id of the team | -| members | array of [team member](#DOCS_TOPICS_TEAMS/data-models-team-member-object) objects | the members of the team | -| name | string | the name of the team | -| owner_user_id | snowflake | the user id of the current team owner | +| field | type | description | +|---------------|-----------------------------------------------------------------------------------|--------------------------------------| +| icon | ?string | Hash of the image of the team's icon | +| id | snowflake | Unique ID of the team | +| members | array of [team member](#DOCS_TOPICS_TEAMS/data-models-team-member-object) objects | Members of the team | +| name | string | Name of the team | +| owner_user_id | snowflake | User ID of the current team owner | ###### Team Member Object -| field | type | description | -| ---------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | -| membership_state | integer | the user's [membership state](#DOCS_TOPICS_TEAMS/data-models-membership-state-enum) on the team | -| permissions | array of strings | will always be `["*"]` | -| team_id | snowflake | the id of the parent team of which they are a member | -| user | partial [user](#DOCS_RESOURCES_USER/user-object) object | the avatar, discriminator, id, and username of the user | +| field | type | description | +|------------------|---------------------------------------------------------|---------------------------------------------------------------------------------------------| +| membership_state | integer | User's [membership state](#DOCS_TOPICS_TEAMS/data-models-membership-state-enum) on the team | +| team_id | snowflake | ID of the parent team of which they are a member | +| user | partial [user](#DOCS_RESOURCES_USER/user-object) object | Avatar, discriminator, ID, and username of the user | +| role | string | [Role](#DOCS_TOPICS_TEAMS/team-member-roles-team-member-role-types) of the team member | + ###### Membership State Enum | name | value | -| -------- | ----- | +|----------|-------| | INVITED | 1 | | ACCEPTED | 2 | diff --git a/docs/topics/Threads.md b/docs/topics/Threads.md index 661fd051d4..abf3124799 100644 --- a/docs/topics/Threads.md +++ b/docs/topics/Threads.md @@ -139,7 +139,7 @@ There are four `GET` routes for enumerating threads in a specific channel: Webhooks can send messages to threads by using the `thread_id` query parameter. See the [execute webhook](#DOCS_RESOURCES_WEBHOOK/execute-webhook) docs for more details. -## Details about Thread Access and Syncing +## Details about Thread Access and Syncing While the syncing of threads is similar to channels, there are two important differences that are relevant for [Thread List Sync](#DOCS_TOPICS_GATEWAY_EVENTS/thread-list-sync) and [Thread Create](#DOCS_TOPICS_GATEWAY_EVENTS/thread-create) events: @@ -189,7 +189,7 @@ Additionally, when a user or app loses access to a channel, they are not removed When a thread is unarchived, there is no guarantee that an app has the thread or its member status in memory. To account for this, the Gateway will send two events (in the listed order): 1. A [Thread Update](#DOCS_TOPICS_GATEWAY_EVENTS/thread-update) event, which contains the full channel object. -2. A [Thread Member Update](#DOCS_TOPICS_GATEWAY_EVENTS/thread-member-update) event, which is sent to all members of the unarchived thread. Discord's clients only load active threads into memory on start, so this event is sent even if it may not be relevant to most apps. +2. A [Thread Member Update](#DOCS_TOPICS_GATEWAY_EVENTS/thread-member-update) event, which is sent to all members of the unarchived thread. Discord's clients only load active threads into memory on start, so this event is sent even if it may not be relevant to most apps. ## Forums @@ -200,32 +200,40 @@ Messages cannot be sent directly in forum channels. > info > More information about forum channels and how they appear in Discord can be found in the [Forum Channels FAQ](https://support.discord.com/hc/en-us/articles/6208479917079-Forum-Channels-FAQ#h_01G69FJQWTWN88HFEHK7Z6X79N) -### Creating Threads in Forum Channels +## Media Channels -Within a forum channel, threads appear as forum posts. They can be created using the [`POST /channels//threads`](#DOCS_RESOURCES_CHANNEL/start-thread-in-forum-channel) endpoint as threads in text channels, but with [slightly different parameters](#DOCS_RESOURCES_CHANNEL/start-thread-in-forum-channel-jsonform-params). For example, when creating threads in a forum channel, a message is created that has the same ID as the thread. This requires you to pass parameters for both a thread *and* a message. +A `GUILD_MEDIA` (type `16`) channel is similar to a `GUILD_FORUM` channel in that only threads can be created in them. Unless otherwise noted, threads in media channels behave in the same way as in forum channels - meaning they use the same endpoints and receive the same Gateway events. More information about media channels and how they appear in Discord can be found in the [media channels Help Center Article](https://creator-support.discord.com/hc/en-us/articles/14346342766743). -Threads in a forum channel have the same permissions behavior as threads in a text channel, inheriting all permissions from the parent channel, with one exception: creating a thread in a forum channel only requires the `SEND_MESSAGES` permission. +> warn +> `GUILD_MEDIA` channels are in beta and still being actively developed. The API and other technical details are subject to change. + + +### Creating Threads in Forum and Media Channels + +Within thread-only channels, threads appear as posts. Threads can be created using the [`POST /channels//threads`](#DOCS_RESOURCES_CHANNEL/start-thread-in-forum-or-media-channel) endpoint with [slightly different parameters](#DOCS_RESOURCES_CHANNEL/start-thread-in-forum-or-media-channel-jsonform-params) than threads in text channels. For example, when creating threads in a threads-only channel, a message is created that has the same ID as the thread which requires you to pass parameters for both a thread *and* a message. + +Threads in thread-only channels have the same permissions behavior as threads in a text channel, inheriting all permissions from the parent channel, with one exception: creating a thread in a thread-only channel only requires the `SEND_MESSAGES` permission. -### Forum Channel Fields +### Forum and Media Channel Fields -It's worth calling out a few details about fields specific to forum channels that may be important to keep in mind: +It's worth calling out a few details about fields specific to thread-only channels that may be important to keep in mind: - The `last_message_id` field is the ID of the most recently created thread in that channel. As with messages, your app will not receive a `CHANNEL_UPDATE` event when the field is changed. Instead clients should update the value when receiving [Thread Create](#DOCS_TOPICS_GATEWAY_EVENTS/thread-create) events. - The `topic` field is what is shown in the "Guidelines" section within the Discord client. -- The `rate_limit_per_user` field limits how frequently threads can be created. There is a new `default_thread_rate_limit_per_user` field on forums as well, which limits how often messages can be sent _in a thread_. This field is copied into `rate_limit_per_user` on the thread at creation time. +- The `rate_limit_per_user` field limits how frequently threads can be created. There is a new `default_thread_rate_limit_per_user` field on thread-only channels as well, which limits how often messages can be sent _in a thread_. This field is copied into `rate_limit_per_user` on the thread at creation time. - The `available_tags` field can be set when creating or updating a channel, which determines which tags can be set on individual threads within the thread's `applied_tags` field. -- The `flags` field indicates any [channel flags](#DOCS_RESOURCES_CHANNEL/channel-object-channel-flags) set for a forum channel. Currently only `REQUIRE_TAG` can be used, which requires that a tag from `available_tags` be specified when creating a thread in that channel. +- The `flags` field indicates any [channel flags](#DOCS_RESOURCES_CHANNEL/channel-object-channel-flags) set for a thread-only channel. Currently only `REQUIRE_TAG` can be used, which requires that a tag from `available_tags` be specified when creating a thread in that channel. -All fields for channels, including forum channels, can be found in the [Channel Object](#DOCS_RESOURCES_CHANNEL/channel-object). +All fields for channels, including thread-only channels, can be found in the [Channel Object](#DOCS_RESOURCES_CHANNEL/channel-object). -### Forum Channel Thread Fields +### Forum and Media Channel Thread Fields -A thread can be pinned within a forum, which will be represented as the [`PINNED` flag](#DOCS_RESOURCES_CHANNEL/channel-object-channel-flags) in the `flags` field within a forum channel. A thread that is pinned will have the `(1 << 1)` flag set, and archiving that thread will unset the flag. A pinned thread will *not* auto-archive. +A thread can be pinned within a thread-only, which will be represented as the [`PINNED` flag](#DOCS_RESOURCES_CHANNEL/channel-object-channel-flags) in the `flags` field within a thread-only channel. A thread that is pinned will have the `(1 << 1)` flag set, and archiving that thread will unset the flag. A pinned thread will *not* auto-archive. -The `message_count` and `total_message_sent` fields on threads in forum channels will increment on `MESSAGE_CREATE` events, and decrement on `MESSAGE_DELETE` and `MESSAGE_DELETE_BULK` events. There will be no specific `CHANNEL_UPDATE` event that notifies your app of changes to those fields—instead, apps should update those values when receiving corresponding events. +The `message_count` and `total_message_sent` fields on threads in thread-only channels will increment on `MESSAGE_CREATE` events, and decrement on `MESSAGE_DELETE` and `MESSAGE_DELETE_BULK` events. There will be no specific `CHANNEL_UPDATE` event that notifies your app of changes to those fields—instead, apps should update those values when receiving corresponding events. -All fields for threads in forum channels can be found in the [channel resources documentation](#DOCS_RESOURCES_CHANNEL/start-thread-in-forum-channel-jsonform-params). +All fields for threads in thread-only channels can be found in the [channel resources documentation](#DOCS_RESOURCES_CHANNEL/start-thread-in-forum-or-media-channel-jsonform-params). -### Forum Channel Formatting +### Forum and Media Channel Formatting -In forum channels, the first message in a thread and the channel topic can both contain markdown for bulleted lists and headings (unlike text channels). +In thread-only channels, the first message in a thread and the channel topic can both contain markdown for bulleted lists and headings (unlike text channels). diff --git a/docs/topics/Voice_Connections.md b/docs/topics/Voice_Connections.md index 46600d0d55..e1625400c2 100644 --- a/docs/topics/Voice_Connections.md +++ b/docs/topics/Voice_Connections.md @@ -9,7 +9,7 @@ To ensure that you have the most up-to-date information, please use [version 4]( ###### Gateway Versions | Version | Status | WebSocket URL Append | -| ------- | ----------- | -------------------- | +|---------|-------------|----------------------| | 4 | recommended | ?v=4 | | 3 | available | ?v=3 | | 2 | available | ?v=2 | @@ -198,7 +198,7 @@ Voice data sent to discord should be encoded with [Opus](https://www.opus-codec. ###### Voice Packet Structure | Field | Type | Size | -| --------------- | ----------------------------- | ------- | +|-----------------|-------------------------------|---------| | Version + Flags | Single byte value of `0x80` | 1 byte | | Payload Type | Single byte value of `0x78` | 1 byte | | Sequence | Unsigned short (big endian) | 2 bytes | @@ -213,7 +213,7 @@ To notify clients that you are speaking or have stopped speaking, send an [Opcod The following flags can be used as a bitwise mask. For example `5` would be priority and voice. | Flag | Meaning | Value | -| ---------- | -------------------------------------------------------------- | ------ | +|------------|----------------------------------------------------------------|--------| | Microphone | Normal transmission of voice audio | 1 << 0 | | Soundshare | Transmission of context audio for video, no speaking indicator | 1 << 1 | | Priority | Priority speaker, lowering audio of other speakers | 1 << 2 | @@ -272,11 +272,11 @@ If the resume is unsuccessful—for example, due to an invalid session—the Web Generally routers on the Internet mask or obfuscate UDP ports through a process called NAT. Most users who implement voice will want to utilize IP discovery to find their external IP and port which will then be used for receiving voice communications. To retrieve your external IP and port, send the following UDP packet to your voice port (all numeric are big endian): -| Field | Description | Size | -| --------------- | -------------------------------------------------------------- | -------- | -| Type | Values 0x1 and 0x2 indicate request and response, respectively | 2 bytes | -| Length | Message length excluding Type and Length fields (value 70) | 2 bytes | -| SSRC | Unsigned integer | 4 bytes | -| Address | Null-terminated string in response | 64 bytes | -| Port | Unsigned short | 2 bytes | +| Field | Description | Size | +|---------|----------------------------------------------------------------|----------| +| Type | Values 0x1 and 0x2 indicate request and response, respectively | 2 bytes | +| Length | Message length excluding Type and Length fields (value 70) | 2 bytes | +| SSRC | Unsigned integer | 4 bytes | +| Address | Null-terminated string in response | 64 bytes | +| Port | Unsigned short | 2 bytes | diff --git a/docs/tr/Getting_Started.mdx b/docs/tr/Getting_Started.mdx new file mode 100644 index 0000000000..815a60ce85 --- /dev/null +++ b/docs/tr/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# İlk Discord uygulamanı oluşturmak + +Discord uygulamaları, bir dizi API ve etkileşimli özellik kullanarak sunucularını özelleştirmene ve genişletmene olanak tanır. Bu rehber, JavaScript kullanarak ilk Discord uygulamanı oluşturmanda sana yol gösterecek ve rehberin sonunda eğik çizgi komutlarını kullanan, mesaj gönderen ve bileşen etkileşimlerine yanıt veren bir uygulamaya sahip olacaksın. + +Sunucu üyelerinin taş, kâğıt, makas oynayabilmelerini sağlayacak bir Discord uygulaması oluşturacağız (klasik 3 seçenek yerine 7 seçenek olacak). Bu kılavuz yeni başlayanlara yöneliktir ancak temel bir [JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics) bilginin olduğunu varsayar. + + +Uygulama bittiğinde işte böyle gözükecek: + +![Uygulamanın örnek gösterimi](getting-started-demo.gif) + +Kullanıcı akışını biraz daha açık hâle getirmek adına: + +1. İlk Kullanıcı yeni bir oyun başlatır ve uygulamanın `/challenge` eğik çizgi komutunu kullanarak nesnesini seçer +2. Kanala, diğer kullanıcıların meydan okumayı kabul etmesini sağlayan bir buton içeren bir mesaj gönderilir +3. 2. kullanıcı **Kabul Et** butonuna tıklar +4. 2. kullanıcı, nesnesini seçebileceği geçici bir mesaj alır +5. Oyunun sonucu herkesin görebilmesi için orijinal kanalda paylaşılır + + + +- Bu kılavuzdaki kodun yanı sıra bazı ek özelliklere özgü kod örneklerinin bulunduğu **[GitHub deposu](https://github.com/discord/discord-example-app)**. +- Discord uygulamaları için tipler ve yardımcı fonksiyonlar sağlayan **[discord-interactions](https://github.com/discord/discord-interactions-js)** kitaplığı. +- Discord'un bize istek gönderebileceği bir sunucu oluşturmak için kullanacağımız popüler bir JavaScript web çerçevesi olan **[Express](https://expressjs.com)**. +- Erken prototip ve geliştirme aşamalarında uygulamaları oluşturma ve barındırma işlemlerini basitleştiren bir çevrim içi ortam olan **[Glitch](https://glitch.com/)**. İstersen **[ngrok](https://ngrok.com/)** gibi bir araçla yerel ortamında da geliştirebilirsin. + + +--- + +## Adım 1: Bir uygulama oluşturmak + +Öncelikle, eğer hâlihazırda bir uygulaman yoksa geliştirici portalında bir uygulama oluşturman gerekli: + + + +Uygulamanın ismini yaz ve **Oluştur** butonuna bas. + +Uygulamanı oluşturduktan sonra uygulamanla ilgili açıklama ve simge gibi temel bilgileri güncelleyebileceğin uygulama ayarlarının **Genel Bakış** sayfasına ulaşacaksın. Ayrıca rehberin ilerleyen bölümlerinde kullanacağımız bir **Uygulama Kimliği** ve **Etkileşim Bitiş Noktası URL**'si de göreceksin. + +### Botunu yapılandırmak + +Şimdiyse uygulamanın [bot kullanıcısını](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts) yapılandırarak onun da tıpkı diğer sunucu üyeleri gibi görünmesini ve hareket etmesini sağlayacağız. + +Sol taraftaki kenar çubuğunda **Bot**'a tıkla. Bu sayfada botun [ayrıcalıklı amaçlarını](#DOCS_TOPICS_GATEWAY/privileged-intents) veya diğer kullanıcılar tarafından yüklenip yüklenemeyeceği gibi ayarları yapılandırabilirsin. + + +Amaçlar, bir [Ağ Geçidi API bağlantısı](#DOCS_TOPICS_GATEWAY) oluştururken Discord'un uygulamana hangi olayları göndereceğini belirler. Örneğin, kullanıcılar bir mesaja tepki eklediğinde uygulamanın bir şey yapmasını istiyorsan `GUILD_MESSAGE_REACTIONS` (`1 << 10`) amacını gönderebilirsin. + +Bazı amaçlar [privileged'tir](#DOCS_TOPICS_GATEWAY/privileged-intents), yani uygulamanın hassas olarak kabul edilebilecek verilere (mesajların içeriği gibi) erişmesine izin verir. Privileged intent'ler uygulamanın ayarlarındaki **Bot** sayfasında görünür ve açılıp kapatılabilir. Standart, privileged intent dışındakiler herhangi bir ek izin veya yapılandırma gerektirmez. + +Amaçlar hakkında daha fazla bilgi ve mevcut amaçların tam listesi, ilişkili olaylarıyla birlikte [Ağ Geçidi dokümantasyonunda](#DOCS_TOPICS_GATEWAY/gateway-intents) bulunmaktadır. + + +![Ayarlardaki bot sekmesi](app-add-bot.png) + +**Bot** sayfasında, botunun token'ını kopyalamana ve sıfırlamana olanak tanıyan bir **Token** bölümü de vardır. + +Bot token'ları, API isteklerini yetkilendirmek için kullanılır ve bot kullanıcısının izinlerini taşır, bu da onları *son derece hassas* hâle getirir. Token'ını *asla* paylaşmadığından veya herhangi bir versiyon kontrol sisteminde kontrol etmediğinden emin ol. + +Şimdi token'ı kopyala ve onu örneğin parola yöneticisi gibi güvenli bir yerde sakla. + +> uyarı +> Token'ını yeniden oluşturmadığın sürece tekrar görüntüleyemezsin, bu nedenle güvenli bir yerde sakladığından emin ol. + +### Bot izinlerini ve kapsamlarını ekleme + +Uygulamalar, Discord'da eğik çizgi komutu oluşturmak veya sunucu üyelerinin listesini almak gibi eylemler gerçekleştirmek için yükleme yapan kullanıcıların onayına ihtiyaç duyar. Uygulamayı yüklemeden önce istek atılacak birkaç kapsam ve izin seçelim. + + +Kapsamlar ve izinler, bir uygulama oluştururken uygulamanın Discord sunucularında neler yapabileceğini ve nelere erişebileceğini belirler. + +- [OAuth2 Kapsamları](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes), uygulamanın yükleme yapan veya yetki veren bir kullanıcı adına hangi verilere erişebileceğini ve eylemleri gerçekleştirebileceğini belirler. +- [İzinler](#DOCS_TOPICS_PERMISSIONS/permission-overwrites), Discord'daki diğer kullanıcıların sahip olduğu gibi bot kullanıcıya verilmiş detaylı izinlerdir. Bunlar, yükleyen kullanıcı tarafından onaylanabilir veya daha sonra sunucu ayarlarında veya [izinlerin üzerine yazarak](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) güncellenebilir. + + +Sol kenar çubuğunda **OAuth2**'ye tıkla, ardından **URL oluşturucuyu** seç. + +> bilgi +> URL oluşturucu, uygulaman için seçtiğin kapsamlara ve izinlere göre bir yükleme bağlantısı oluşturur. Bağlantıyı, uygulamayı kendi sunucuna yüklemek için kullanabilir veya yükleyebilmeleri için başkalarıyla paylaşabilirsin. + +Şimdilik iki kapsam ekleyelim: +- `applications.commands`, uygulamanın [komutlar](#DOCS_INTERACTIONS_APPLICATION_COMMANDS) oluşturmasını sağlar. +- `bot`, bot kullanıcını ekler. `bot`'u seçtikten sonra botun için farklı izinler de seçebilirsin. Şimdilik sadece **Mesaj Gönder** seçeneğini işaretleyelim. + +Dokümantasyonda tüm [OAuth2 kapsamlarının](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) bir listesine bakabilir veya [izinler](#DOCS_TOPICS_PERMISSIONS) hakkında daha fazla bilgi edinebilirsin. + +### Uygulamanı yüklemek + +Kapsamları ekledikten sonra uygulamanı yüklemek için kopyalayabileceğin bir URL göreceksin. + +![URL oluşturucu ekran görüntüsü](url-generator.png) + +> bilgi +> Uygulama geliştirirken uygulamanı başkaları tarafından aktif olarak kullanılmayan bir sunucuda oluşturmalı ve test etmelisin. Hâlihazırda kendi sunucun yoksa [ücretsiz bir tane oluşturabilirsin](https://support.discord.com/hc/articles/204849977-How-do-I-create-a-server-). + +URL'yi yukarıdan kopyala ve tarayıcına yapıştır. Kurulum süreci sana rehberlik edecektir; bu süreçte uygulamanı geliştirebileceğin ve test edebileceğin bir sunucuya yüklediğinden emin olmalısın. + +Uygulamanı yükledikten sonra sunucuna gidebilir ve uygulamanın sunucuna katıldığını görebilirsin ✨ + +Hadi yapılandırılmış ve yüklenmiş uygulamanı geliştirelim. + +--- + +## Adım 2: Uygulamanı çalıştırmak + +Örnek uygulamada kullanılan tüm kodlar [GitHub deposunda](https://github.com/discord/discord-example-app) bulunabilir. + +Uygulama, geliştirmeyi daha basit hâle getirmek için tipler ve yardımcı fonksiyonlar sağlayan [discord-interactions](https://github.com/discord/discord-interactions-js) kullanır. Başka dilleri veya kütüphaneleri kullanmayı tercih ediyorsan [Topluluk Kaynakları](#DOCS_TOPICS_COMMUNITY_RESOURCES) dokümantasyonlarına göz atabilirsin. + +### Projeyi remikslemek + +Bu rehber, tarayıcında klonlama ve geliştirme yapmanı sağlayan Glitch'i kullanır. Uygulamanı yerel olarak geliştirmeyi tercih edersen, [README](https://github.com/discord/discord-example-app#running-app-locally) dosyasından ngrok kullanımıyla ilgili talimatlara ulaşabilirsin. + +> bilgi +> Glitch, geliştirme ve test için harika olsa da [teknik kısıtlamalara sahiptir](https://help.glitch.com/hc/en-us/articles/16287495313293-Technical-Restrictions/), bu nedenle bitmiş uygulamalar için diğer barındırma sağlayıcıları düşünmekte fayda vardır. + +Başlamak için **[Glitch projesini 🎏 remiksle (veya klonla)](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)**. + +Projeyi remikslediğinde yeni bir Glitch projesine ulaşacaksın. + + +![Glitch projesine genel bakış](glitch-project.png) + +- **Proje ismin**, projenin sol üst köşesinde görünen benzersiz ismidir +- **`.env`**, uygulaman için tüm kimlik bilgilerinin saklanacağı dosyadır +- **Loglar**, projenin çıktısının bulabileceğin dosyalardır; uygulamanın çalışıp çalışmadığını görmek veya uygulamanın karşılaştığı hatalar hakkında bilgi almak için yararlıdır +- Sağ üst köşedeki **Paylaş** butonu, bu rehberin ilerleyen bölümlerinde etkileşimi ayarlamak için ihtiyaç duyacağın canlı proje URL'sini bulacağın yerdir + + +#### Proje yapısı + +Projenin tüm dosyaları Glitch projenin sol tarafında bulunmaktadır. Aşağıdaki görselde ana klasörlere ve dosyalara genel bir bakış mevcut: + +``` +├── examples -> kısa, özelliklere has örnek uygulamalar +│ ├── app.js -> bitmiş app.js kodu +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> kimlik bilgilerin ve kimliklerin +├── app.js -> uygulaman için ana giriş noktası +├── commands.js -> eğik çizgi komutları payload'ları (yükler) ve yardımcılar +├── game.js -> Taş-kâğıt-makas için özel mantık +├── utils.js -> yardımcı fonksiyonlar ve enum'lar +├── package.json +├── README.md +└── .gitignore +``` + +### Kimlik bilgilerini eklemek + +`app.js` dosyanda zaten bazı kodlar var ancak istekte bulunmak için uygulamanın token'ına ve kimliğine ihtiyacın olacak. Tüm kimlik bilgilerin doğrudan `.env` dosyasında saklanabilir. + +İlk olarak, önceden oluşturduğumuz bot kullanıcısının token'ını kopyala ve `.env` dosyandaki **`DISCORD_TOKEN`** değişkenine yapıştır. + +Ardından uygulamanın **Genel Bakış** sayfasına git, sonrasında **Uygulama Kimliğini** ve **Ortak Anahtarı** kopyala. Değerleri `.env` dosyana **`APP_ID`** ve **`PUBLIC_KEY`** olarak yapıştır. + +Kimlik bilgilerin yapılandırıldıktan sonra eğik çizgi komutlarını yükleyelim ve işleyelim. + +### Eğik çizgi komutlarını yükleme + +> bilgi +> Eğik çizgi komutlarını yüklemek için uygulama [`node-fetch`](https://github.com/node-fetch/node-fetch) kullanır. Yükleme implementasyonunu `utils.js`'de `DiscordRequest()` fonksiyonu içinde görebilirsin. + +Proje, `commands.js` dosyasının altında tanımlanan `ALL_COMMANDS` içerisindeki komutları yüklemek için kullanabileceğin bir `register` komut dosyası içerir. HTTP API'sinin [`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands) uç noktasını çağırarak komutları global komutlar olarak yükler. + +Komutlarını özelleştirmek veya ilave komutlar eklemek istersen [komutlar dokümantasyonundaki](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure) komut yapısına başvurabilirsin. + +Glitch projenin altındaki **Terminal**'e tıklayarak ve aşağıdaki komutu yapıştırarak `register` komut dosyasını çalıştır: + +``` +npm run register +``` + +Komutu çalıştırmak için enter tuşuna bas. + +Sunucuna geri döndüğünde eğik çizgi komutlarının göründüğünü göreceksin. Ancak bunları çalıştırmayı denersen uygulaman Discord'dan herhangi bir istek almadığı veya işlemediği için hiçbir şey olmayacaktır. + + +Discord, uygulamalar oluşturmak için bir araya getirebileceğin iki API'ye sahiptir: + +- **[HTTP API](#DOCS_REFERENCE/http-api)**, Discord'da veri gönderme, veri güncelleme veya bir kaynak hakkında veri alma gibi genel işlemler için kullanılan REST benzeri bir API'dir. +- **[Ağ Geçidi API](#DOCS_REFERENCE/gateway-websocket-api)**, durumu korumak veya Discord sunucusunda gerçekleşen olayları dinlemek için yararlı, WebSocket tabanlı bir API'dir. Bu rehberde bunu kullanmayacağız ancak bir Ağ Geçidi bağlantısının nasıl oluşturulacağı hakkında ve dinleyebileceğin farklı olaylar hakkında daha fazla bilgi [Ağ Geçidi dokümantasyonunda](#DOCS_TOPICS_GATEWAY) bulunmaktadır. + + +--- + +## Adım 3: Etkileşimi işlemek + +Uygulamanın eğik çizgi komut isteklerini (ve diğer etkileşimleri) almasını sağlamak için Discord'un bunları göndermek üzere genel bir URL'ye ihtiyacı vardır. Bu URL, uygulamanın ayarlarında **Etkileşim Uç Noktası URL'si** olarak yapılandırılabilir. + +### Etkileşim uç noktası URL'si ekleme + +Glitch projeleri varsayılan olarak herkese açık bir URL'ye sahiptir. Sağ üst köşedeki **Paylaş** butonuna tıklayarak projenin URL'sini kopyala, ardından minik pencerenin alt kısmındaki "Canlı site" proje bağlantısını kopyala. + +> bilgi +> Yerel olarak geliştirme yapıyorsan, [GitHub README'de](https://github.com/discord/discord-example-app#running-app-locally) istekleri yerel ortamına tünellemek için talimatlara ulaşabilirsin. + +Bağlantı kopyalandıktan sonra [geliştirici portalından](https://discord.com/developers/applications) uygulamanın ayarlarına git. + +Uygulamanın **Genel Bilgiler** sayfasında, uygulamanın URL'sini yapıştırabileceğin ve içerisine `/interactions` ekleyebileceğin bir **Etkileşimli Uç Nokta URL'si** seçeneği vardır. Express uygulamasının istekleri dinlemek için yapılandırıldığı yer de bu Etkileşimli Uç Nokta URL'sidir. + +![Uygulama ayarlarında etkileşimler uç nokta URL'si](interactions-url.png) + +**Değişiklikleri Kaydet**'e tıkla ve uç noktanın başarıyla doğrulandığından emin ol. + +Örnek uygulama, doğrulamayı iki şekilde ele alır: +- `PUBLIC_KEY` ve [discord-interactions paketini](https://github.com/discord/discord-interactions-js#usage) [Express'in `verify` arayüzüne](http://expressjs.com/en/5x/api.html#express.json) uygun hâle getiren bir wrapper fonksiyonla (`utils.js` içerisinden içe aktarılır) birlikte kullanır. Bu, uygulamana gelen her istekte çalıştırılır. +- Gelen `PING` isteklerine yanıt verir. + +Uygulamanı etkileşim almaya hazırlama hakkında daha fazla bilgiyi [etkileşimler dokümantasyonunda](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction) bulabilirsin. + +### Eğik çizgi komut isteklerini işleme + +Uç nokta doğrulandıktan sonra projenin `app.js` dosyasına git ve `/test` komutunu işleyen kod blokunu bul: + +```javascript +// "test" komutu +if (name === 'test') { + // Komutun tetiklendiği kanala bir mesaj gönderir + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Bir yardımcı fonksiyondan göndermek için rastgele bir emoji alır + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +Yukarıdaki kod, gelen etkileşime meydana geldiği kanaldaki bir mesajla yanıt veriyor. Modal ile yanıt vermek gibi mevcut tüm yanıt türlerini [dokümantasyonda](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type) bulabilirsin. + +> bilgi +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE`, [`discord-interactions`'dan dışa aktarılmış](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33) bir sabittir. + +Sunucuna git ve uygulamanın `/test` eğik çizgi komutunun çalıştığından emin ol. Bunu tetiklediğinde, uygulaman "hello world" kelimelerini takip eden rastgele bir emoji içeren bir mesaj göndermelidir. + +Aşağıdaki bölümde, taş-kâğıt-makas oyununu oluşturmak için eğik çizgi komut seçeneklerini, butonları ve seçme menülerini kullanan ek bir komut ekleyeceğiz. + +--- + +## Adım 4: Mesaj bileşenlerini ekleme + +Taş-kâğıt-makas tarzı oyunumuz `/challenge` komutuyla başlatılacaktır. Komut tetiklendiğinde uygulama kanala mesaj bileşenleri gönderecek ve bu da kullanıcıları oyunu tamamlamaları için yönlendirecektir. + +### Seçenekli bir komut ekleme + +`commands.js`'de `CHALLENGE_COMMAND` olarak adlandırılan `/challenge` komutu bir dizi `options`'a sahiptir. Uygulamamızda seçenekler, kullanıcının taş-kâğıt-makas oynarken seçebileceği farklı şeyleri temsil eden nesnelerdir ve `game.js`'deki `RPSChoices` anahtarları kullanılarak oluşturulmuştur. + +Komut seçenekleri ve bunların yapısı hakkında daha fazla bilgiyi [dokümantasyonlardan](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure) edinebilirsin. + +> bilgi +> Bu rehber `game.js` dosyasına fazla değinmeyecek olsa da sen onu kurcalayabilir, komutları veya komutlardaki seçenekleri çekinmeden değiştirebilirsin. + + + +`/challenge` komutunu işlemek için `if name === “test”` if blokundan sonra aşağıdaki kodu ekle: + +```javascript +// "meydanoku" komutu +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // Kullanıcının nesne seçimi + const objectName = req.body.data.options[0].value; + + // Oyun kimliği olarak mesaj kimliğini kullanarak aktif oyun oluşturur + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // Daha sonra kullanmak üzere oyun kimliğini ekler + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> bilgi +> Kodu nereye yapıştıracağından emin değilsen, kodun tamamını Glitch projesindeki `examples/app.js` dosyasında veya [GitHub'daki](https://github.com/discord/discord-example-app/blob/main/app.js) kök `app.js` dosyasında bulabilirsin. + +Yukarıdaki kod birkaç şey yapıyor: +1. Eğik çizgi komutunu tetikleyen kullanıcının kimliğini (`userId`) ve seçtiği (`objectName`) seçeneği (nesne seçimi) almak için istek gövdesini ayrıştırır. +2. Etkileşim kimliğini kullanarak `activeGames` nesnesine yeni bir oyun ekler. Etkin oyun `userId` ve `objectName`'i kaydeder. +3. Kanala, `custom_id`'si `accept_button_` olan bir buton ile bir mesaj gönderir. + +> uyarı +> Örnek kod, bellek içi depolama alanı olarak bir nesne kullanır ancak bitmiş uygulamalar için bir veri tabanı kullanman gerekir. + +[Mesaj bileşenleriyle](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component) bir mesaj gönderirken, tekil payload'lar bir `components` dizisine eklenir. Eyleme geçirilebilir bileşenlerin (butonlar gibi) kod örneğinde görebileceğin bir [eylem satırının](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows) içinde olması gereklidir. + +Mesaj bileşenleriyle birlikte gönderilen benzersiz `custom_id`'ye dikkatli bakalım. Şu anki durumda `accept_button_` aktif oyunun kimliğiyle birlikte eklendi. Bir `custom_id`, birisi bileşenle etkileşime girdiğinde Discord'un sana gönderdiği istekleri işlemek için kullanılabilir, bunu birazdan göreceğiz. + +Artık `/challenge` komutunu çalıştırdığında ve bir seçenek belirlediğinde, uygulaman bir **Kabul Et** butonu içeren bir mesaj gönderecektir. Butona basmayı işlemek için kod ekleyelim. + + + + + +Kullanıcılar bir mesaj bileşeniyle etkileşime girdiğinde, Discord [etkileşim türü](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) `3` (veya `discord-interactions` kullanılırken `MESSAGE_COMPONENT`) değeri olan bir istek gönderecektir. + +Buton için bir işleyici ayarlamak üzere, etkileşimin `type`'ını kontrol edeceğiz ve ardından `custom_id` ile eşleştireceğiz. + +Aşağıdaki kodu `APPLICATION_COMMAND` için tip işleyicisinin altına yapıştır: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id mesaj bileşeni gönderilirken payload'da ayarlanır +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // ilişkili oyun kimliğini alır + const gameId = componentId.replace('accept_button_', ''); + // İstek gövdesinde token bulunan mesajı siler + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Bir yardımcı fonksiyondan göndermek için rastgele bir emoji alır + content: 'What is your object of choice?', + // Geçici bir mesaj olacağını belirtir + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Oyun kimliğini ekler + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Önceki mesajı siler + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +Yukarıdaki kod: +1. Başlangıçta gönderdiğimizle eşleşen bir `custom_id` olup olmadığını kontrol eder (bu durumda, `accept_button_` ile başlar). Özel kimliğe aktif oyun kimliği de eklenmiştir, bu yüzden bunu `gameID`'de saklarız. +2. `node-fetch` kullanarak bir webhook çağıran ve istek gövdesinde benzersiz etkileşim `token`'ı ileten [orijinal mesajı siler](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response). Bu, kanalı temizlemek için yapılır ve böylece diğer kullanıcılar butona tıklayamaz. +3. Oyun için nesne seçeneklerini içeren bir seçim menüsü içeren bir mesaj göndererek isteğe yanıt verir. Payload, `options` dizisi ve [mesajın geçici olduğunu gösteren](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message) `flags: 64` belirteci haricinde önceki payload'a epey benzer görünmelidir. + +`options` dizisi, `game.js`'deki `getShuffledOptions()` metodu kullanılarak doldurulur ve bu metot `RPSChoices` değerlerini [mesaj bileşeni seçeneklerinin](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure) şekline uyacak şekilde değiştirir. + + + + + +Eklenecek son şey, seçim menüsü etkileşimlerini işleyecek ve oyunun sonucunu kanala gönderecek koddur. + +Seçim menüleri sadece başka bir mesaj bileşeni olduğundan, etkileşimlerini işleyen kod, buton kodlarının neredeyse aynısı olacaktır. + +Seçim menüsünü işlemek için yukarıdaki kodu değiştir: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id mesaj bileşeni gönderilirken payload'da ayarlanır +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // ilişkili oyun kimliğini alır + const gameId = componentId.replace('accept_button_', ''); + // İstek gövdesinde token bulunan mesajı siler + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Bir yardımcı fonksiyondan göndermek için rastgele bir emoji alır + content: 'What is your object of choice?', + // Geçici bir mesaj olacağını belirtir + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Oyun kimliğini ekler + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Önceki mesajı siler + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // ilişkili oyun kimliğini alır + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // Yanıt veren kullanıcı için kullanıcı kimliğini ve nesne seçimini alır + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // Yardımcı fonksiyondan gelen sonucu hesaplar + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // Oyunu bellekten kaldırır + delete activeGames[gameId]; + // Mesajı istek gövdesinde token ile günceller + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // Sonuçları gönderir + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // Geçici mesajı günceller + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +Daha önceki koda benzer şekilde, yukarıdaki kod etkileşim isteğinden kullanıcı kimliğini ve nesne seçimini alır. + +Bu bilgi, orijinal kullanıcının kimliği ve `activeGames` nesnesinden yapılan seçimle birlikte `getResult()` fonksiyonuna aktarılır. `getResult()` kazananı belirler, ardından kanala geri göndermek için okunabilir bir karakter dizisi oluşturur. + +Ayrıca, bu kez silinemediği için [takip eden geçici mesajı güncellemek](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message) için başka bir webhook çağırıyoruz. + +Son olarak, sonuçlar kanalda `CHANNEL_MESSAGE_WITH_SOURCE` etkileşim yanıt tipi kullanılarak gönderilir. + + + +...işte bu kadar 🎊 Durma, uygulamanı test et ve her şeyin çalıştığından emin ol. + +--- + +## Sonraki adımlar + +Tebrikler, ilk Discord uygulamanı geliştirdin! 🤖 + +Umarız Discord uygulamaları, nasıl yapılandırılacakları ve nasıl etkileşimli hâle getirilecekleri hakkında biraz bilgi edinmişsindir. Buradan uygulamanı oluşturmaya devam edebilir veya başka nelerin mümkün olduğunu keşfedebilirsin: +- API özellikleri hakkında derinlemesine bilgi için **[dokümantasyonları](#DOCS_INTRO)** oku +- Daha küçük, özelliğe has kod örnekleri için bu projedeki `examples/` klasörüne göz at +- Topluluk üyeleri tarafından yürütülen kodlama diline özgü araçlar için **[topluluk kaynaklarına](#DOCS_TOPICS_COMMUNITY_RESOURCES)** göz at +- Discord uygulamalarını [Cloudflare Workers](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS) üzerinde barındırma hakkındaki eğitimimizi oku +- API hakkında sorular sormak, Discord API ekibi tarafından düzenlenen etkinliklere katılmak ve diğer geliştiricilerle etkileşim kurmak için **[Discord Geliştiricileri sunucusuna](https://discord.gg/discord-developers)** katıl diff --git a/images/create-team-owned-app.png b/images/create-team-owned-app.png new file mode 100644 index 0000000000..722c4e18ee Binary files /dev/null and b/images/create-team-owned-app.png differ diff --git a/images/monetization-eligibility.png b/images/monetization-eligibility.png new file mode 100644 index 0000000000..500524d9c4 Binary files /dev/null and b/images/monetization-eligibility.png differ diff --git a/images/monetization-interaction-response.png b/images/monetization-interaction-response.png new file mode 100644 index 0000000000..93d1b3a9cf Binary files /dev/null and b/images/monetization-interaction-response.png differ diff --git a/images/monetization.png b/images/monetization.png new file mode 100644 index 0000000000..e5a0034eda Binary files /dev/null and b/images/monetization.png differ diff --git a/images/premium-example.png b/images/premium-example.png new file mode 100644 index 0000000000..92eb99ddfb Binary files /dev/null and b/images/premium-example.png differ diff --git a/images/sku-benefits.png b/images/sku-benefits.png new file mode 100644 index 0000000000..d3dc2d1af6 Binary files /dev/null and b/images/sku-benefits.png differ diff --git a/images/sku-custom.png b/images/sku-custom.png new file mode 100644 index 0000000000..b097389504 Binary files /dev/null and b/images/sku-custom.png differ diff --git a/images/sku-customization.png b/images/sku-customization.png new file mode 100644 index 0000000000..ef35607787 Binary files /dev/null and b/images/sku-customization.png differ diff --git a/images/sku-unicode.png b/images/sku-unicode.png new file mode 100644 index 0000000000..41dedab409 Binary files /dev/null and b/images/sku-unicode.png differ diff --git a/images/team-2fa.png b/images/team-2fa.png deleted file mode 100644 index 81b821a4d6..0000000000 Binary files a/images/team-2fa.png and /dev/null differ diff --git a/images/team-make-app.png b/images/team-make-app.png deleted file mode 100644 index 78a297ef61..0000000000 Binary files a/images/team-make-app.png and /dev/null differ diff --git a/images/team-page.png b/images/team-page.png index a90baa8bda..4b6a6092ed 100644 Binary files a/images/team-page.png and b/images/team-page.png differ diff --git a/images/transfer-app-to-team.png b/images/transfer-app-to-team.png index 6672d1d772..1c2420a3d0 100644 Binary files a/images/transfer-app-to-team.png and b/images/transfer-app-to-team.png differ diff --git a/package-lock.json b/package-lock.json index a747139379..21d8b4e2f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,16 +10,25 @@ "license": "MIT", "devDependencies": { "@actions/core": "^1.9.1", - "@types/node": "^16.10.3", - "@typescript-eslint/eslint-plugin": "^4.33.0", - "@typescript-eslint/parser": "^4.33.0", - "chalk": "^4.1.2", - "eslint": "^7.32.0", - "eslint-config-marine": "^9.0.6", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-prettier": "^4.0.0", - "prettier": "^2.4.1", - "typescript": "^4.4.3" + "@types/node": "^20.6.2", + "@typescript-eslint/eslint-plugin": "^6.7.0", + "@typescript-eslint/parser": "^6.7.0", + "chalk": "^5.3.0", + "eslint": "^8.49.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "markdown-table-formatter": "^1.4.0", + "prettier": "^3.0.3", + "typescript": "^5.2.2" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/@actions/core": { @@ -41,156 +50,93 @@ "tunnel": "^0.0.6" } }, - "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@eslint-community/regexpp": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz", + "integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==", "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, "engines": { - "node": ">=4" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", "dev": true, "dependencies": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "node_modules/@eslint/js": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz", + "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==", "dev": true, "engines": { - "node": ">= 4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", + "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, "node_modules/@nodelib/fs.scandir": { @@ -228,43 +174,72 @@ "node": ">= 8" } }, + "node_modules/@pkgr/utils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", + "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "fast-glob": "^3.3.0", + "is-glob": "^4.0.3", + "open": "^9.1.0", + "picocolors": "^1.0.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", "dev": true }, "node_modules/@types/node": { - "version": "16.10.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.3.tgz", - "integrity": "sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ==", + "version": "20.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.2.tgz", + "integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz", - "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==", - "dev": true, - "dependencies": { - "@typescript-eslint/experimental-utils": "4.33.0", - "@typescript-eslint/scope-manager": "4.33.0", - "debug": "^4.3.1", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.1.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.0.tgz", + "integrity": "sha512-gUqtknHm0TDs1LhY12K2NA3Rmlmp88jK9Tx8vGZMfHeNMLE3GH2e9TRub+y+SOjuYgtOmok+wt1AyDPZqxbNag==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.7.0", + "@typescript-eslint/type-utils": "6.7.0", + "@typescript-eslint/utils": "6.7.0", + "@typescript-eslint/visitor-keys": "6.7.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^4.0.0", - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -272,81 +247,85 @@ } } }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz", - "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==", + "node_modules/@typescript-eslint/parser": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.0.tgz", + "integrity": "sha512-jZKYwqNpNm5kzPVP5z1JXAuxjtl2uG+5NpaMocFPTNC2EdYIgbXIPImObOkhbONxtFTTdoZstLZefbaK+wXZng==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "@typescript-eslint/scope-manager": "6.7.0", + "@typescript-eslint/types": "6.7.0", + "@typescript-eslint/typescript-estree": "6.7.0", + "@typescript-eslint/visitor-keys": "6.7.0", + "debug": "^4.3.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@typescript-eslint/parser": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz", - "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.0.tgz", + "integrity": "sha512-lAT1Uau20lQyjoLUQ5FUMSX/dS07qux9rYd5FGzKz/Kf8W8ccuvMyldb8hadHdK/qOI7aikvQWqulnEq2nCEYA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "debug": "^4.3.1" + "@typescript-eslint/types": "6.7.0", + "@typescript-eslint/visitor-keys": "6.7.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz", - "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==", + "node_modules/@typescript-eslint/type-utils": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.0.tgz", + "integrity": "sha512-f/QabJgDAlpSz3qduCyQT0Fw7hHpmhOzY/Rv6zO3yO+HVIdPfIWhrQoAyG+uZVtWAIS85zAyzgAFfyEr+MgBpg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0" + "@typescript-eslint/typescript-estree": "6.7.0", + "@typescript-eslint/utils": "6.7.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/types": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz", - "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.0.tgz", + "integrity": "sha512-ihPfvOp7pOcN/ysoj0RpBPOx3HQTJTrIN8UZK+WFd3/iDeFHHqeyYxa4hQk4rMhsz9H9mXpR61IzwlBVGXtl9Q==", "dev": true, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -354,21 +333,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz", - "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.0.tgz", + "integrity": "sha512-dPvkXj3n6e9yd/0LfojNU8VMUGHWiLuBZvbM6V6QYD+2qxqInE7J+J/ieY2iGwR9ivf/R/haWGkIj04WVUeiSQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "@typescript-eslint/types": "6.7.0", + "@typescript-eslint/visitor-keys": "6.7.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -380,17 +359,42 @@ } } }, + "node_modules/@typescript-eslint/utils": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.0.tgz", + "integrity": "sha512-MfCq3cM0vh2slSikQYqK2Gq52gvOhe57vD2RM3V4gQRZYX4rDPnKLu5p6cm89+LJiGlwEXU8hkYxhqqEC/V3qA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.7.0", + "@typescript-eslint/types": "6.7.0", + "@typescript-eslint/typescript-estree": "6.7.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz", - "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.0.tgz", + "integrity": "sha512-/C1RVgKFDmGMcVGeD8HjKv2bd72oI1KxQDeY8uc66gw9R0OK0eMq48cA+jv9/2Ag6cdrsUGySm1yzYmfz0hxwQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.33.0", - "eslint-visitor-keys": "^2.0.0" + "@typescript-eslint/types": "6.7.0", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -398,9 +402,9 @@ } }, "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -434,15 +438,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -468,13 +463,10 @@ } }, "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/array-union": { "version": "2.1.0", @@ -485,13 +477,13 @@ "node": ">=8" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, "engines": { - "node": ">=8" + "node": ">= 4.0.0" } }, "node_modules/balanced-match": { @@ -500,6 +492,27 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.44" + }, + "engines": { + "node": ">= 5.10.0" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -522,6 +535,21 @@ "node": ">=8" } }, + "node_modules/bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "dependencies": { + "run-applescript": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -532,16 +560,12 @@ } }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" @@ -586,9 +610,9 @@ } }, "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -608,6 +632,52 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "dependencies": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "dependencies": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -632,24 +702,6 @@ "node": ">=6.0.0" } }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -663,84 +715,63 @@ } }, "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz", + "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.49.0", + "@humanwhocodes/config-array": "^0.11.11", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-config-aqua": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/eslint-config-aqua/-/eslint-config-aqua-9.0.2.tgz", - "integrity": "sha512-WqV4EYX3pXoL0TkUBH9VVHoWjR3eJ0ud1p5OmSfbRoyjDbUJURs78fpeU4H8t88pO8mFB4SHTZM95DJEwKG/MQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-config-marine": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/eslint-config-marine/-/eslint-config-marine-9.0.6.tgz", - "integrity": "sha512-PPx84UDPQrLM5kyGG4kaDCQ2EAfzh3bcFjS9Sqg322z2vzERg8di3D4YSjUHWgXNqgooOUor8qjzM2NnPL0AKw==", - "dev": true, - "dependencies": { - "eslint-config-aqua": "^9.0.2" - } - }, "node_modules/eslint-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -750,160 +781,111 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", - "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz", + "integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==", "dev": true, "dependencies": { - "prettier-linter-helpers": "^1.0.0" + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.5" }, "engines": { - "node": ">=6.0.0" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/prettier" }, "peerDependencies": { - "eslint": ">=7.28.0", - "prettier": ">=2.0.0" + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "prettier": ">=3.0.0" }, "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, "eslint-config-prettier": { "optional": true } } }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/eslint/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, "engines": { - "node": ">=4" + "node": ">=0.10" } }, - "node_modules/eslint/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "dependencies": { "estraverse": "^5.2.0" @@ -912,19 +894,10 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { "node": ">=4.0" @@ -939,6 +912,29 @@ "node": ">=0.10.0" } }, + "node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -952,9 +948,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -964,7 +960,19 @@ "micromatch": "^4.0.4" }, "engines": { - "node": ">=8" + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/fast-json-stable-stringify": { @@ -980,9 +988,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -1012,6 +1020,28 @@ "node": ">=8" } }, + "node_modules/find-package-json": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/find-package-json/-/find-package-json-1.2.0.tgz", + "integrity": "sha512-+SOGcLGYDJHtyqHd87ysBhmaeQ95oWspDKnMXBrnQ9Eq4OkLNqejgoaD8xVWu6GPa0B6roa6KinCMEMcVeqONw==", + "dev": true + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -1031,17 +1061,38 @@ "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", "dev": true }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/glob": { "version": "7.2.0", @@ -1064,21 +1115,21 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, "node_modules/globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -1091,16 +1142,16 @@ } }, "node_modules/globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" }, "engines": { @@ -1110,6 +1161,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1119,10 +1182,19 @@ "node": ">=8" } }, + "node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, "node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, "engines": { "node": ">= 4" @@ -1169,22 +1241,28 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, + "bin": { + "is-docker": "cli.js" + }, "engines": { - "node": ">=0.10.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, "node_modules/is-glob": { @@ -1199,6 +1277,24 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -1208,26 +1304,67 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-wsl/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" @@ -1245,6 +1382,18 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1258,11 +1407,20 @@ "node": ">= 0.8.0" } }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -1270,12 +1428,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -1288,6 +1440,44 @@ "node": ">=10" } }, + "node_modules/markdown-table-formatter": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/markdown-table-formatter/-/markdown-table-formatter-1.4.0.tgz", + "integrity": "sha512-SxezWds03j9ouHE27qz3IXMSFyGd0KCgDlgIW3B36D09Crji2uH8KlgVn0dFOS0cq8QAT5rkv1OHkxKxRcsyrQ==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "find-package-json": "^1.2.0", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "markdown-table-prettify": "^3.6.0", + "optionator": "^0.9.1" + }, + "bin": { + "markdown-table-formatter": "lib/index.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/markdown-table-prettify": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/markdown-table-prettify/-/markdown-table-prettify-3.6.0.tgz", + "integrity": "sha512-xZg+sL5yWyPz75GwNHtCOLe85CPnssoTLqpGc19xSr6CirGu4xRW2f8wj1f7c8Kx1IItXo3hUIqlUX4qAOwAdg==", + "dev": true, + "bin": { + "markdown-table-prettify": "cli/index.js" + }, + "engines": { + "vscode": "^1.59.0" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -1298,18 +1488,30 @@ } }, "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1334,6 +1536,33 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1343,23 +1572,86 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "dependencies": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -1372,6 +1664,15 @@ "node": ">=6" } }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -1399,10 +1700,16 @@ "node": ">=8" } }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "engines": { "node": ">=8.6" @@ -1421,15 +1728,18 @@ } }, "node_modules/prettier": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", - "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", "dev": true, "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/prettier-linter-helpers": { @@ -1444,19 +1754,10 @@ "node": ">=6.0.0" } }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true, "engines": { "node": ">=6" @@ -1482,59 +1783,142 @@ } ] }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "node_modules/run-applescript/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=10.17.0" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "node_modules/run-applescript/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "node_modules/run-applescript/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "node_modules/run-applescript/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "dependencies": { - "glob": "^7.1.3" + "path-key": "^3.0.0" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">=8" + } + }, + "node_modules/run-applescript/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" } }, "node_modules/run-parallel": { @@ -1561,9 +1945,9 @@ } }, "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -1596,6 +1980,12 @@ "node": ">=8" } }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -1605,43 +1995,6 @@ "node": ">=8" } }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -1654,6 +2007,18 @@ "node": ">=8" } }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -1678,51 +2043,40 @@ "node": ">=8" } }, - "node_modules/table": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", - "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", + "node_modules/synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", "dev": true, "dependencies": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" }, "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "node": "^14.18.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://opencollective.com/unts" } }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "node_modules/titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1735,27 +2089,24 @@ "node": ">=8.0" } }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, "engines": { - "node": ">= 6" + "node": ">=16.13.0" }, "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + "typescript": ">=4.2.0" } }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -1790,16 +2141,34 @@ } }, "node_modules/typescript": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", - "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" } }, "node_modules/uri-js": { @@ -1820,12 +2189,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -1841,15 +2204,6 @@ "node": ">= 8" } }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -1861,9 +2215,27 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } }, "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, "@actions/core": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", @@ -1883,130 +2255,65 @@ "tunnel": "^0.0.6" } }, - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, "requires": { - "@babel/highlight": "^7.10.4" + "eslint-visitor-keys": "^3.3.0" } }, - "@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "@eslint-community/regexpp": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz", + "integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==", "dev": true }, - "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", "dev": true, "requires": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - } } }, + "@eslint/js": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz", + "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==", + "dev": true + }, "@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^1.2.0", + "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" } }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, "@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, "@nodelib/fs.scandir": { @@ -2035,105 +2342,142 @@ "fastq": "^1.6.0" } }, + "@pkgr/utils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", + "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "fast-glob": "^3.3.0", + "is-glob": "^4.0.3", + "open": "^9.1.0", + "picocolors": "^1.0.0", + "tslib": "^2.6.0" + } + }, "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", "dev": true }, "@types/node": { - "version": "16.10.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.3.tgz", - "integrity": "sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ==", + "version": "20.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.2.tgz", + "integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==", + "dev": true + }, + "@types/semver": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw==", "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz", - "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "4.33.0", - "@typescript-eslint/scope-manager": "4.33.0", - "debug": "^4.3.1", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.1.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.0.tgz", + "integrity": "sha512-gUqtknHm0TDs1LhY12K2NA3Rmlmp88jK9Tx8vGZMfHeNMLE3GH2e9TRub+y+SOjuYgtOmok+wt1AyDPZqxbNag==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.7.0", + "@typescript-eslint/type-utils": "6.7.0", + "@typescript-eslint/utils": "6.7.0", + "@typescript-eslint/visitor-keys": "6.7.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" } }, - "@typescript-eslint/experimental-utils": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz", - "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==", + "@typescript-eslint/parser": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.0.tgz", + "integrity": "sha512-jZKYwqNpNm5kzPVP5z1JXAuxjtl2uG+5NpaMocFPTNC2EdYIgbXIPImObOkhbONxtFTTdoZstLZefbaK+wXZng==", "dev": true, "requires": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "@typescript-eslint/scope-manager": "6.7.0", + "@typescript-eslint/types": "6.7.0", + "@typescript-eslint/typescript-estree": "6.7.0", + "@typescript-eslint/visitor-keys": "6.7.0", + "debug": "^4.3.4" } }, - "@typescript-eslint/parser": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz", - "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==", + "@typescript-eslint/scope-manager": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.0.tgz", + "integrity": "sha512-lAT1Uau20lQyjoLUQ5FUMSX/dS07qux9rYd5FGzKz/Kf8W8ccuvMyldb8hadHdK/qOI7aikvQWqulnEq2nCEYA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "debug": "^4.3.1" + "@typescript-eslint/types": "6.7.0", + "@typescript-eslint/visitor-keys": "6.7.0" } }, - "@typescript-eslint/scope-manager": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz", - "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==", + "@typescript-eslint/type-utils": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.0.tgz", + "integrity": "sha512-f/QabJgDAlpSz3qduCyQT0Fw7hHpmhOzY/Rv6zO3yO+HVIdPfIWhrQoAyG+uZVtWAIS85zAyzgAFfyEr+MgBpg==", "dev": true, "requires": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0" + "@typescript-eslint/typescript-estree": "6.7.0", + "@typescript-eslint/utils": "6.7.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" } }, "@typescript-eslint/types": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz", - "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.0.tgz", + "integrity": "sha512-ihPfvOp7pOcN/ysoj0RpBPOx3HQTJTrIN8UZK+WFd3/iDeFHHqeyYxa4hQk4rMhsz9H9mXpR61IzwlBVGXtl9Q==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz", - "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.0.tgz", + "integrity": "sha512-dPvkXj3n6e9yd/0LfojNU8VMUGHWiLuBZvbM6V6QYD+2qxqInE7J+J/ieY2iGwR9ivf/R/haWGkIj04WVUeiSQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.7.0", + "@typescript-eslint/visitor-keys": "6.7.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/utils": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.0.tgz", + "integrity": "sha512-MfCq3cM0vh2slSikQYqK2Gq52gvOhe57vD2RM3V4gQRZYX4rDPnKLu5p6cm89+LJiGlwEXU8hkYxhqqEC/V3qA==", "dev": true, "requires": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.7.0", + "@typescript-eslint/types": "6.7.0", + "@typescript-eslint/typescript-estree": "6.7.0", + "semver": "^7.5.4" } }, "@typescript-eslint/visitor-keys": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz", - "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.0.tgz", + "integrity": "sha512-/C1RVgKFDmGMcVGeD8HjKv2bd72oI1KxQDeY8uc66gw9R0OK0eMq48cA+jv9/2Ag6cdrsUGySm1yzYmfz0hxwQ==", "dev": true, "requires": { - "@typescript-eslint/types": "4.33.0", - "eslint-visitor-keys": "^2.0.0" + "@typescript-eslint/types": "6.7.0", + "eslint-visitor-keys": "^3.4.1" } }, "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true }, "acorn-jsx": { @@ -2155,12 +2499,6 @@ "uri-js": "^4.2.2" } }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2177,13 +2515,10 @@ } }, "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "array-union": { "version": "2.1.0", @@ -2191,10 +2526,10 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true }, "balanced-match": { @@ -2203,6 +2538,21 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true + }, + "bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "requires": { + "big-integer": "^1.6.44" + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2222,6 +2572,15 @@ "fill-range": "^7.0.1" } }, + "bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "requires": { + "run-applescript": "^5.0.0" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2229,14 +2588,10 @@ "dev": true }, "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true }, "color-convert": { "version": "2.0.1", @@ -2271,9 +2626,9 @@ } }, "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -2285,37 +2640,50 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", "dev": true, "requires": { - "path-type": "^4.0.0" + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" } }, - "doctrine": { + "default-browser-id": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", "dev": true, "requires": { - "esutils": "^2.0.2" + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" } }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { - "ansi-colors": "^4.1.1" + "esutils": "^2.0.2" } }, "escape-string-regexp": { @@ -2325,174 +2693,113 @@ "dev": true }, "eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz", + "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.49.0", + "@humanwhocodes/config-array": "^0.11.11", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true } } }, - "eslint-config-aqua": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/eslint-config-aqua/-/eslint-config-aqua-9.0.2.tgz", - "integrity": "sha512-WqV4EYX3pXoL0TkUBH9VVHoWjR3eJ0ud1p5OmSfbRoyjDbUJURs78fpeU4H8t88pO8mFB4SHTZM95DJEwKG/MQ==", - "dev": true - }, - "eslint-config-marine": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/eslint-config-marine/-/eslint-config-marine-9.0.6.tgz", - "integrity": "sha512-PPx84UDPQrLM5kyGG4kaDCQ2EAfzh3bcFjS9Sqg322z2vzERg8di3D4YSjUHWgXNqgooOUor8qjzM2NnPL0AKw==", - "dev": true, - "requires": { - "eslint-config-aqua": "^9.0.2" - } - }, "eslint-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", "dev": true, "requires": {} }, "eslint-plugin-prettier": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", - "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz", + "integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==", "dev": true, "requires": { - "prettier-linter-helpers": "^1.0.0" + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.5" } }, "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "requires": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" + "estraverse": "^5.2.0" } }, "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true }, "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "requires": { "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } } }, "esrecurse": { @@ -2502,20 +2809,12 @@ "dev": true, "requires": { "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } } }, "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "esutils": { @@ -2524,6 +2823,23 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + } + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2537,9 +2853,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -2547,6 +2863,17 @@ "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } } }, "fast-json-stable-stringify": { @@ -2562,9 +2889,9 @@ "dev": true }, "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -2588,6 +2915,22 @@ "to-regex-range": "^5.0.1" } }, + "find-package-json": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/find-package-json/-/find-package-json-1.2.0.tgz", + "integrity": "sha512-+SOGcLGYDJHtyqHd87ysBhmaeQ95oWspDKnMXBrnQ9Eq4OkLNqejgoaD8xVWu6GPa0B6roa6KinCMEMcVeqONw==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -2604,16 +2947,28 @@ "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", "dev": true }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, "glob": { @@ -2631,47 +2986,65 @@ } }, "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "requires": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" } }, "globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "requires": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" } }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true + }, "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true }, "import-fresh": { @@ -2706,16 +3079,16 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true }, "is-glob": { @@ -2727,32 +3100,63 @@ "is-extglob": "^2.1.1" } }, + "is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "requires": { + "is-docker": "^3.0.0" + } + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + }, + "dependencies": { + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + } + } + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" } }, "json-schema-traverse": { @@ -2767,6 +3171,16 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2777,11 +3191,14 @@ "type-check": "~0.4.0" } }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } }, "lodash.merge": { "version": "4.6.2", @@ -2789,12 +3206,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2804,6 +3215,32 @@ "yallist": "^4.0.0" } }, + "markdown-table-formatter": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/markdown-table-formatter/-/markdown-table-formatter-1.4.0.tgz", + "integrity": "sha512-SxezWds03j9ouHE27qz3IXMSFyGd0KCgDlgIW3B36D09Crji2uH8KlgVn0dFOS0cq8QAT5rkv1OHkxKxRcsyrQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "find-package-json": "^1.2.0", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "markdown-table-prettify": "^3.6.0", + "optionator": "^0.9.1" + } + }, + "markdown-table-prettify": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/markdown-table-prettify/-/markdown-table-prettify-3.6.0.tgz", + "integrity": "sha512-xZg+sL5yWyPz75GwNHtCOLe85CPnssoTLqpGc19xSr6CirGu4xRW2f8wj1f7c8Kx1IItXo3hUIqlUX4qAOwAdg==", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -2811,15 +3248,21 @@ "dev": true }, "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, + "mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2841,6 +3284,23 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "requires": { + "path-key": "^4.0.0" + }, + "dependencies": { + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true + } + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2850,18 +3310,57 @@ "wrappy": "1" } }, + "onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "requires": { + "mimic-fn": "^4.0.0" + } + }, + "open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "requires": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + } + }, "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" } }, "parent-module": { @@ -2873,6 +3372,12 @@ "callsites": "^3.0.0" } }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -2891,10 +3396,16 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, "prelude-ls": { @@ -2904,9 +3415,9 @@ "dev": true }, "prettier": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", - "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", "dev": true }, "prettier-linter-helpers": { @@ -2918,16 +3429,10 @@ "fast-diff": "^1.1.2" } }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true }, "queue-microtask": { @@ -2936,18 +3441,6 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2969,6 +3462,76 @@ "glob": "^7.1.3" } }, + "run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "requires": { + "execa": "^5.0.0" + }, + "dependencies": { + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + } + } + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -2979,9 +3542,9 @@ } }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -3002,40 +3565,18 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -3045,6 +3586,12 @@ "ansi-regex": "^5.0.1" } }, + "strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -3060,38 +3607,14 @@ "has-flag": "^4.0.0" } }, - "table": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", - "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", + "synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", "dev": true, "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" } }, "text-table": { @@ -3100,6 +3623,12 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3109,21 +3638,19 @@ "is-number": "^7.0.0" } }, + "ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "requires": {} + }, "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, "tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -3146,9 +3673,21 @@ "dev": true }, "typescript": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", - "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", "dev": true }, "uri-js": { @@ -3166,12 +3705,6 @@ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3181,12 +3714,6 @@ "isexe": "^2.0.0" } }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -3198,6 +3725,12 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true } } } diff --git a/package.json b/package.json index a6cfcb85ea..adb00007e1 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "1.1.1", "description": "Documentation for using Discord's API", "main": "index.js", + "type": "module", "directories": { "doc": "docs" }, @@ -20,19 +21,21 @@ "build": "tsc --build", "lint": "eslint ci", "lint:fix": "eslint ci --fix", - "test:links": "node dist/ci/checkLinks.js" + "test:links": "node dist/ci/checkLinks.js", + "test:tables": "npx markdown-table-formatter docs/**/*.{md,mdx} --check", + "fix:tables": "npx markdown-table-formatter docs/**/*.{md,mdx}" }, "devDependencies": { "@actions/core": "^1.9.1", - "@types/node": "^16.10.3", - "@typescript-eslint/eslint-plugin": "^4.33.0", - "@typescript-eslint/parser": "^4.33.0", - "chalk": "^4.1.2", - "eslint": "^7.32.0", - "eslint-config-marine": "^9.0.6", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-prettier": "^4.0.0", - "prettier": "^2.4.1", - "typescript": "^4.4.3" + "@types/node": "^20.6.2", + "@typescript-eslint/eslint-plugin": "^6.7.0", + "@typescript-eslint/parser": "^6.7.0", + "chalk": "^5.3.0", + "eslint": "^8.49.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "markdown-table-formatter": "^1.4.0", + "prettier": "^3.0.3", + "typescript": "^5.2.2" } } diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json deleted file mode 100644 index b13fa84b33..0000000000 --- a/tsconfig.eslint.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": ["ci"] -} diff --git a/tsconfig.json b/tsconfig.json index 1b89d9de2a..dd9517b986 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,19 +1,11 @@ { "compilerOptions": { - "target": "ES2021", - "lib": ["ESNext"], - "skipLibCheck": true, + "target": "ES2022", "strict": true, - "alwaysStrict": true, - "forceConsistentCasingInFileNames": true, "esModuleInterop": true, - "module": "commonjs", - "moduleResolution": "node", - "importsNotUsedAsValues": "error", - "isolatedModules": true, "rootDir": "./", + "module": "NodeNext", "outDir": "./dist" }, "include": ["**/*.ts"], - "exclude": ["node_modules"] }