Skip to content

feat(plugin-gateway): add ApplicationCommand and its managers - #252

Merged
kodiakhq[bot] merged 2 commits into
mainfrom
feat/plugin-gateway-application-commands
Oct 17, 2026
Merged

kodiakhq[bot] merged 2 commits into
mainfrom
feat/plugin-gateway-application-commands

Conversation

@RedStar071

Copy link
Copy Markdown
Member

🔗 Linked issue

Closes #209
Refs #207 (the ApplicationCommand half; ApplicationEmoji is #250)

🧭 Context

@wolfstar/plugin-gateway has no counterpart of discord.js's ApplicationCommand, ApplicationCommandManager, GuildApplicationCommandManager and ApplicationCommandPermissionsManager, so a process can neither read nor manage its application commands, and ApplicationCommand#equals() could not be ported with the rest of #203. They hang off client.application (#208, merged in #238). The structure and its managers ship together because the structure's edit()/delete() go through the manager and the manager returns the structure.

📚 Description

Everything follows Pullfrog's plan on #207 and the decisions taken on it:

  • Fetch-only. Commands are never cached: Discord sends no event when they change, so a copy could not be kept in sync. No new plugin-cache entity type. The existing applicationCommandPermissions store is the only cached piece, and fetch/has of the permissions manager read it for one command (unless force), while fetches and writes keep it up to date.
  • set() is kept (bulk overwrite) and documented in the TSDoc and the README as replacing whatever @wolfstar/http-framework registered. Nothing calls it automatically.
  • Permission writes take an explicit token (the OAuth2 bearer token), passed to editGuildCommandPermissions(userToken, ...). There is no OAuth handling; without a token they throw GatewayError ApplicationCommandPermissionsTokenMissing. Roles and channels are IDs or structures only, nothing is resolved through the guild.
  • REST goes through @discordjs/core's ApplicationCommandsAPI, with one exception: fetch({ locale }) sends X-Discord-Locale, which the core API cannot carry, so that call uses client.rest directly.

Where I departed from the plan or from discord.js:

  • fetch takes no cache/force options, since there is no cache to skip.
  • GuildUncachedEntityResolve was not added: with IDs/structures only there is no code path that could throw it. InvalidType/InvalidElement already exist. The new codes are ApplicationCommandPermissionsTokenMissing and GlobalCommandPermissions.
  • null localizations are sent as null (they remove localizations). discord.js's nameLocalizations ?? name_localizations drops them.
  • defaultMemberPermissions: undefined leaves the permissions alone in an edit, where discord.js would send "0".
  • ApplicationCommand#edit() patches the structure in place (like GuildEmoji#edit) and clears the optional fields the API no longer returns. delete() of the manager resolves to void since nothing is cached.
  • equals() and optionsEqual() return false for a foreign argument instead of throwing.
  • ApplicationCommandResolvable now also accepts the ApplicationCommand structure, and ApplicationCommandDataResolvable camel-cased ApplicationCommandData (both were declared in types.ts already).
  • plugin-gateway does not emit an applicationCommandPermissionsUpdate event today (the dispatch only updates the cache); this PR does not add one.

Key changes

Where What
structures/applications/ApplicationCommand.ts ApplicationCommand with the command fields, edit(), set*(), delete(), permissions, equals(), static optionsEqual() and transformOption(), plus the option/data types
managers/ApplicationCommandManager.ts fetch, create, set, edit, delete, commandPath, static transformCommand (camel-cased data, raw payloads, builders through toJSON())
managers/GuildApplicationCommandManager.ts the same manager bound to a guild
managers/ApplicationCommandPermissionsManager.ts fetch, has, set, add, remove, permissionsPath
ClientApplication, Guild, GuildManager client.application.commands, guild.commands, client.guilds.commands(guildId) (a new instance on every access)
errors/Messages.ts, types.ts, indexes the two error codes, the widened resolvables, exports
tests/application-commands.test.ts, tests/types/application-commands.ts 47 tests on the mocked REST layer, and a type-level test
README, changeset an "Application commands" section, a minor changeset for @wolfstar/plugin-gateway

Type of Change

  • New feature (non-breaking change which adds functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation change
  • Workflow / CI change

Pre-flight Checklist

  • I have read the Contributing Guidelines (if applicable)
  • My code follows the code style of this project
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have updated the documentation accordingly
  • I added a changeset with pnpm changeset (or pnpm changeset add --empty if no release is needed). See .changeset/README.md.

Verification (run locally in this order): pnpm lint (exit 0, format check clean), pnpm build (9/9 tasks), pnpm typecheck (exit 0), pnpm test (122 files, 1759 tests passed).

🤖 AI disclosure: Claude Code was used on this PR. Code written with claude-sonnet-5-5; PR description written with claude-sonnet-5-5. AI policy.

@coldtea-pr-lens

coldtea-pr-lens Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
  • Redraw · drawn at 0b761e3, the branch has moved on

Architecture

Architecture diagram for wolfstar-project/plugins at 0b761e3

Play the walkthrough

Inside the changed components — 1 view

Component view — Application Commands

Internal managers, structures, and external REST interactions for application commands and permissions.

Architecture view of Component view — Application Commands in wolfstar-project/plugins

Data flow

Data flow diagram for wolfstar-project/plugins at 0b761e3

Follow each request

The other flows — 1 sequence

Updating command permissions

Sequence diagram of Updating command permissions in wolfstar-project/plugins

Review

✨ Nothing flagged · reviewed 0b761e3


Tip

The CLI's render reads .github/pr-lens.yml and applies your renames, exclusions and lane pins at draw time

🪧 More tips
  • Run npx skills add coldteadotai/pr-lens, then tell your coding agent: "Diagram the change you just made with PR Lens and attach it to the pull request."
  • Run npx @coldtea/pr-lens-cli analyze --base origin/main on a branch, then npx @coldtea/pr-lens-cli render .pr-lens/graph.json. Same lenses, your own model key, before the pull request exists
  • Click the link under each diagram to open it on a canvas you can zoom, pan and step through
  • The diagrams are links. Click one to open it on the canvas, then press W or click play to walk through the change
  • Open a diagram on the canvas, then press W or click play to walk through the change one step at a time
  • Set github.comment.collapsed: true in .github/pr-lens.yml to fold the comment behind one View architecture and data flow row. Drawing still runs as before
  • Set github.draw: on-demand in .github/pr-lens.yml and PR Lens stops drawing pull requests on its own. Comment @pr-lens draw on a pull request when you want that one drawn
  • Add .github/workflows/pr-lens.yml with coldteadotai/pr-lens/packages/action@v0 and your model provider's key as its api-key to run PR Lens from your own CI. Any /chat/completions endpoint works
  • After a push, tick Redraw to draw the latest commit
  • Switch GitHub to dark mode and the diagrams follow. The moving dots are this pull request's data in motion

Thanks for using PR Lens! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out on X, Bluesky, Mastodon, Reddit or LinkedIn

@wolfstarbot wolfstarbot added the packages:plugin-gateway Changes in plugin-gateway label Oct 17, 2026

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ No critical issues — two minor suggestions inline.

Reviewed changes

Reviewed the full single-commit diff of the fetch-only ApplicationCommand structure and its managers in @wolfstar/plugin-gateway.

  • ApplicationCommand structure: camel-cased getters, in-place edit()/set*(), delete(), permissions, equals(), optionsEqual() and transformOption().
  • ApplicationCommandManager / GuildApplicationCommandManager: fetch, create, set, edit, delete, commandPath and transformCommand, going through client.api.applicationCommands (with client.rest only for the localized fetch).
  • ApplicationCommandPermissionsManager: cache-aware fetch/has, and token-gated set/add/remove.
  • Wiring: client.application.commands, guild.commands, client.guilds.commands(id), the widened resolvable types, two new error codes, exports, README and changeset.
  • Tests: 47 mocked-REST tests and a type-level consumption test.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using claude-sonnet-5-5 | 𝕏

Comment thread packages/plugin-gateway/src/managers/ApplicationCommandManager.ts Outdated
Comment thread packages/plugin-gateway/src/managers/ApplicationCommandManager.ts Outdated
Adds the fetch-only ApplicationCommandManager (client.application.commands), the
GuildApplicationCommandManager (guild.commands), the ApplicationCommand structure with
equals() and optionsEqual(), and the ApplicationCommandPermissionsManager, whose writes
take an explicit bearer token and whose reads use the applicationCommandPermissions cache.
@RedStar071
RedStar071 force-pushed the feat/plugin-gateway-application-commands branch from 0b761e3 to b785711 Compare October 17, 2026 10:10
@pkg-pr-new

pkg-pr-new Bot commented Oct 17, 2026

Copy link
Copy Markdown

Open in StackBlitz

@wolfstar/plugin-api

pnpm add https://pkg.pr.new/@wolfstar/plugin-api@252

@wolfstar/plugin-broker

pnpm add https://pkg.pr.new/@wolfstar/plugin-broker@252

@wolfstar/plugin-cache

pnpm add https://pkg.pr.new/@wolfstar/plugin-cache@252

@wolfstar/plugin-gateway

pnpm add https://pkg.pr.new/@wolfstar/plugin-gateway@252

@wolfstar/plugin-i18next

pnpm add https://pkg.pr.new/@wolfstar/plugin-i18next@252

@wolfstar/plugin-logger

pnpm add https://pkg.pr.new/@wolfstar/plugin-logger@252

@wolfstar/plugin-scheduled-tasks

pnpm add https://pkg.pr.new/@wolfstar/plugin-scheduled-tasks@252

@wolfstar/plugin-sharder

pnpm add https://pkg.pr.new/@wolfstar/plugin-sharder@252

@wolfstar/plugin-subcommands-advanced

pnpm add https://pkg.pr.new/@wolfstar/plugin-subcommands-advanced@252

commit: b785711

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

Reviewed what changed since the prior pullfrog review (0b761e3): one follow-up commit that addresses both earlier suggestions, plus a rebase onto main.

  • Raw guild commands routed correctly: ApplicationCommandManager#edit() and #delete() now use a shared commandGuildId() that reads guildId ?? guild_id, so a raw APIApplicationCommand with guild_id hits the guild endpoint. A new test covers both methods.
  • Shared helpers: Loose, firstDefined and compact moved into util/applicationCommands.ts and are imported by both ApplicationCommand.ts and ApplicationCommandManager.ts.
  • Rebase onto main: ClientApplication, managers/index.ts and types.ts now sit alongside the entitlement and subscription managers from #253; the imports and exports are consistent.

Pullfrog  | View workflow run | Using claude-sonnet-5-5 | 𝕏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

packages:plugin-gateway Changes in plugin-gateway

Projects

None yet

Development

Successfully merging this pull request may close these issues.

plugin-gateway: port ApplicationCommandManager and ApplicationCommandPermissionsManager (discord.js parity)

2 participants