Skip to content

Command authorizations and scopes#15

Merged
Ntalcme merged 10 commits into
developfrom
command-authorizations-and-scopes
Jun 6, 2026
Merged

Command authorizations and scopes#15
Ntalcme merged 10 commits into
developfrom
command-authorizations-and-scopes

Conversation

@Ntalcme

@Ntalcme Ntalcme commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@Ntalcme Ntalcme added this to the v0.2.0 milestone Jun 6, 2026
@Ntalcme Ntalcme self-assigned this Jun 6, 2026
@Ntalcme Ntalcme added feature New feature or request priority: medium Should do soon labels Jun 6, 2026
@Ntalcme Ntalcme linked an issue Jun 6, 2026 that may be closed by this pull request
@Ntalcme Ntalcme marked this pull request as ready for review June 6, 2026 18:07
Copilot AI review requested due to automatic review settings June 6, 2026 18:07
@Ntalcme Ntalcme merged commit bd7cde0 into develop Jun 6, 2026
1 check passed
@Ntalcme Ntalcme deleted the command-authorizations-and-scopes branch June 6, 2026 18:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a command requirements system (scope + authorization) for both prefix and slash commands, along with shared validation/error rendering utilities, so commands can be blocked early with a consistent error response.

Changes:

  • Added requirements metadata to command types plus helpers to validate scope/authorization based on environment configuration.
  • Added a reusable “missing permissions” error container + localized error message builder.
  • Updated container rendering to support ephemeral responses (via message flags) and updated env variables used for command deployment.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/types/command.ts Adds requirement/permission types and attaches requirements to command interfaces.
src/lib/command-requirements.ts Implements scope + authorization validation helpers.
src/lib/errors.ts Adds shared builder for a permissions error container.
src/lang/errors.ts Adds localized error message for missing permissions.
src/lib/components/container.ts Adds ephemeral option to Container.build() by setting flags.
src/events/message-create.ts Enforces command.requirements for prefix commands and replies on failure.
src/events/interaction-create.ts Enforces command.requirements for slash commands and replies ephemerally on failure.
src/deploy-commands.ts Renames dev guild env var usage to TEST_GUILD_ID for guild deploys.
.env.example Updates documented environment variables for deployment + authorization.
src/client/crownutils-client.ts Marks event execution promises as intentionally not awaited (lint compliance).
src/handlers/slash-handler.ts Removes unused path/url helpers now that module loading is centralized.
src/handlers/event-handler.ts Removes unused fs/path/url helpers now that module loading is centralized.
src/commands/prefix/ping.ts Converts PrefixCommand import to type-only.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/deploy-commands.ts

if (!isProduction && !guildId) {
if (!isProduction && !testGuildId) {
throw new Error('Missing DISCORD_GUILD_ID for development deployment');
const currentAuthorization: CommandAuthorization =
userId === process.env.OWNER_ID
? 'owner'
: process.env.PRIVILEGED_IDS?.split(',').filter(Boolean).includes(userId)
Comment thread src/types/command.ts
Comment on lines +24 to +27
export interface CommandRequirements {
scope?: CommandScope;
authorizations?: CommandAuthorization;
}
Comment thread src/types/command.ts
Comment on lines +29 to +32
export interface CommandValidation {
canBeExecuted: boolean;
missing_permissions: CommandPermission[];
}
Comment thread src/lang/errors.ts
Comment on lines +3 to +6
export function buildCommandPermissionsErrorReply(
missing_permissions: CommandPermission[],
): string {
return `La commande n'a pas pu être exécutée. (\`${missing_permissions.length > 1 ? 'erreurs' : 'erreur'}: ${missing_permissions.join(', ')}\`)`;
Ntalcme added a commit that referenced this pull request Jun 6, 2026
* feat(prefix): add prefix command support with !ping (#9)

* Wrap dynamic import in try/catch to skip broken files  (#10)

* fix(handlers): wrap dynamic import in try/catch to skip broken files #5

* Fix cacth error #5

* feat(commands): add description field to prefix commands #11 (#13)

* Command authorizations and scopes (#15)

* feat(types): Add CommandAuthorization & CommandScope #12

* feat(types): add CommandRequirements, CommandValidation and permission types #12

* feat(lib): add command requirements checker #12

* feat(lib): add error container builder and permission error messages #12

* feat(components): add ephemeral option to Container.build() #12

* fix(client): wrap event listeners to handle async execute #12

* fix(handlers): remove unused imports #12

* feat(events): check command requirements before execution #12

* chore(config): add MAIN_GUILD_ID, OWNER_ID and PRIVILEGED_IDS to env.example #12

* Fix name #12

* Add scope deployment for slash commands #16 (#18)

* Update package.json version to v0.2.0
Ntalcme added a commit that referenced this pull request Jun 9, 2026
* V0.2.0 (#14)

* feat(prefix): add prefix command support with !ping (#9)

* Wrap dynamic import in try/catch to skip broken files  (#10)

* fix(handlers): wrap dynamic import in try/catch to skip broken files #5

* Fix cacth error #5

* feat(commands): add description field to prefix commands #11 (#13)

* Command authorizations and scopes (#15)

* feat(types): Add CommandAuthorization & CommandScope #12

* feat(types): add CommandRequirements, CommandValidation and permission types #12

* feat(lib): add command requirements checker #12

* feat(lib): add error container builder and permission error messages #12

* feat(components): add ephemeral option to Container.build() #12

* fix(client): wrap event listeners to handle async execute #12

* fix(handlers): remove unused imports #12

* feat(events): check command requirements before execution #12

* chore(config): add MAIN_GUILD_ID, OWNER_ID and PRIVILEGED_IDS to env.example #12

* Fix name #12

* Add scope deployment for slash commands #16 (#18)

* Update package.json version to v0.2.0

* build: resolve path aliases with tsc-alias for production build

* feat(lib): add parseDuration function #3

* feat(db): set up Prisma with SQLite and Reminder model

* Add sqlite support #3

* feat(lib): add branded time types and msToUnixSeconds #3

* feat(lib): add prisma client with better-sqlite3 adapter #3

* chore(config): ignore prisma.config.ts in eslint #3

* feat(reminders): add reminder service and messages #3

* refactor(lib): centralize environment access with fail-fast requireEnv

* refactor(components): add barrel and remove unused Footer, RawComponent and render

* refactor(lib): replace branded time types with plain millisecond helpers

* refactor(lang): unify user-facing text under a single lang namespace

* refactor(permissions): separate execution context from required scope

* refactor(commands): consume lang and component barrels in ping

* feat(events): report unexpected command errors to the user

* chore: remove redundant file comments

* feat(reminders): create, schedule, present and rehydrate reminders #3

* feat(reminders): add /remind and !remind commands #3

* refactor(permissions): modularize command types and permission engine

* refactor: adopt satisfies and command type-module import paths

* feat(components): add Section, Button, ActionRow and Title sizes

* feat(reminders): limit to 5 per user and add list and cancel buttons #3

* feat(reminder): Reminder limit for priviliged user #3
Ntalcme added a commit that referenced this pull request Jun 9, 2026
* feat(prefix): add prefix command support with !ping (#9)

* Wrap dynamic import in try/catch to skip broken files  (#10)

* fix(handlers): wrap dynamic import in try/catch to skip broken files #5

* Fix cacth error #5

* feat(commands): add description field to prefix commands #11 (#13)

* Command authorizations and scopes (#15)

* feat(types): Add CommandAuthorization & CommandScope #12

* feat(types): add CommandRequirements, CommandValidation and permission types #12

* feat(lib): add command requirements checker #12

* feat(lib): add error container builder and permission error messages #12

* feat(components): add ephemeral option to Container.build() #12

* fix(client): wrap event listeners to handle async execute #12

* fix(handlers): remove unused imports #12

* feat(events): check command requirements before execution #12

* chore(config): add MAIN_GUILD_ID, OWNER_ID and PRIVILEGED_IDS to env.example #12

* Fix name #12

* Add scope deployment for slash commands #16 (#18)

* Update package.json version to v0.2.0

* Reminders System (#20)

* V0.2.0 (#14)

* feat(prefix): add prefix command support with !ping (#9)

* Wrap dynamic import in try/catch to skip broken files  (#10)

* fix(handlers): wrap dynamic import in try/catch to skip broken files #5

* Fix cacth error #5

* feat(commands): add description field to prefix commands #11 (#13)

* Command authorizations and scopes (#15)

* feat(types): Add CommandAuthorization & CommandScope #12

* feat(types): add CommandRequirements, CommandValidation and permission types #12

* feat(lib): add command requirements checker #12

* feat(lib): add error container builder and permission error messages #12

* feat(components): add ephemeral option to Container.build() #12

* fix(client): wrap event listeners to handle async execute #12

* fix(handlers): remove unused imports #12

* feat(events): check command requirements before execution #12

* chore(config): add MAIN_GUILD_ID, OWNER_ID and PRIVILEGED_IDS to env.example #12

* Fix name #12

* Add scope deployment for slash commands #16 (#18)

* Update package.json version to v0.2.0

* build: resolve path aliases with tsc-alias for production build

* feat(lib): add parseDuration function #3

* feat(db): set up Prisma with SQLite and Reminder model

* Add sqlite support #3

* feat(lib): add branded time types and msToUnixSeconds #3

* feat(lib): add prisma client with better-sqlite3 adapter #3

* chore(config): ignore prisma.config.ts in eslint #3

* feat(reminders): add reminder service and messages #3

* refactor(lib): centralize environment access with fail-fast requireEnv

* refactor(components): add barrel and remove unused Footer, RawComponent and render

* refactor(lib): replace branded time types with plain millisecond helpers

* refactor(lang): unify user-facing text under a single lang namespace

* refactor(permissions): separate execution context from required scope

* refactor(commands): consume lang and component barrels in ping

* feat(events): report unexpected command errors to the user

* chore: remove redundant file comments

* feat(reminders): create, schedule, present and rehydrate reminders #3

* feat(reminders): add /remind and !remind commands #3

* refactor(permissions): modularize command types and permission engine

* refactor: adopt satisfies and command type-module import paths

* feat(components): add Section, Button, ActionRow and Title sizes

* feat(reminders): limit to 5 per user and add list and cancel buttons #3

* feat(reminder): Reminder limit for priviliged user #3

* Update package.json
Ntalcme added a commit that referenced this pull request Jun 13, 2026
* feat(prefix): add prefix command support with !ping (#9)

* Wrap dynamic import in try/catch to skip broken files  (#10)

* fix(handlers): wrap dynamic import in try/catch to skip broken files #5

* Fix cacth error #5

* feat(commands): add description field to prefix commands #11 (#13)

* Command authorizations and scopes (#15)

* feat(types): Add CommandAuthorization & CommandScope #12

* feat(types): add CommandRequirements, CommandValidation and permission types #12

* feat(lib): add command requirements checker #12

* feat(lib): add error container builder and permission error messages #12

* feat(components): add ephemeral option to Container.build() #12

* fix(client): wrap event listeners to handle async execute #12

* fix(handlers): remove unused imports #12

* feat(events): check command requirements before execution #12

* chore(config): add MAIN_GUILD_ID, OWNER_ID and PRIVILEGED_IDS to env.example #12

* Fix name #12

* Add scope deployment for slash commands #16 (#18)

* Update package.json version to v0.2.0

* Reminders System (#20)

* V0.2.0 (#14)

* feat(prefix): add prefix command support with !ping (#9)

* Wrap dynamic import in try/catch to skip broken files  (#10)

* fix(handlers): wrap dynamic import in try/catch to skip broken files #5

* Fix cacth error #5

* feat(commands): add description field to prefix commands #11 (#13)

* Command authorizations and scopes (#15)

* feat(types): Add CommandAuthorization & CommandScope #12

* feat(types): add CommandRequirements, CommandValidation and permission types #12

* feat(lib): add command requirements checker #12

* feat(lib): add error container builder and permission error messages #12

* feat(components): add ephemeral option to Container.build() #12

* fix(client): wrap event listeners to handle async execute #12

* fix(handlers): remove unused imports #12

* feat(events): check command requirements before execution #12

* chore(config): add MAIN_GUILD_ID, OWNER_ID and PRIVILEGED_IDS to env.example #12

* Fix name #12

* Add scope deployment for slash commands #16 (#18)

* Update package.json version to v0.2.0

* build: resolve path aliases with tsc-alias for production build

* feat(lib): add parseDuration function #3

* feat(db): set up Prisma with SQLite and Reminder model

* Add sqlite support #3

* feat(lib): add branded time types and msToUnixSeconds #3

* feat(lib): add prisma client with better-sqlite3 adapter #3

* chore(config): ignore prisma.config.ts in eslint #3

* feat(reminders): add reminder service and messages #3

* refactor(lib): centralize environment access with fail-fast requireEnv

* refactor(components): add barrel and remove unused Footer, RawComponent and render

* refactor(lib): replace branded time types with plain millisecond helpers

* refactor(lang): unify user-facing text under a single lang namespace

* refactor(permissions): separate execution context from required scope

* refactor(commands): consume lang and component barrels in ping

* feat(events): report unexpected command errors to the user

* chore: remove redundant file comments

* feat(reminders): create, schedule, present and rehydrate reminders #3

* feat(reminders): add /remind and !remind commands #3

* refactor(permissions): modularize command types and permission engine

* refactor: adopt satisfies and command type-module import paths

* feat(components): add Section, Button, ActionRow and Title sizes

* feat(reminders): limit to 5 per user and add list and cancel buttons #3

* feat(reminder): Reminder limit for priviliged user #3

* Update package.json

* Botinfo command (#25)

* Add NOTICE #24

* feat(about): expose bot version, license and source URL via env #23

* feat(about): add /about command #23

* feat(components): update component lib to support more md syntax

* feat(commands): Update label description for a more descriptive name

* feat(lang): add command about texts and update texts using md syntax to delete hardcoded md syntax

* feat(lib): add md support for texts

* feat(presentations): move reminder-presentation to the new src/services/presentation which builds the reply to user + add about-presentation

* feat(reminder): (not relative to this branch but was done) change reminder limit

* chore(pnpm-lock.yaml): apply format

* feat(about): add /about and finish about-presentation service #23

* Grade command (#30)

* refacto(lang): refacto commands texts to be englobed into lang.commands

* Add grade prefix command #28

* feat(commands): end of grade command #28

* feat(commands): grade slash command #28

* refacto: apply format and refacto lang const

* refactp: lang + format

* apply prettier

* Collector and interaction upgrade (#31)

* refactor: migrate reminder collectors to InteractiveMessage and extract core/

Replace the manual collector boilerplate in reminder-cancel/reminder-list
with the generic Collector/InteractiveMessage primitives, simplify the
delete/cancel button ids now that authorization is handled by
allowedIds, and extract a discord.js-free core/ layer (config, time,
permissions, persistence) per the architecture refactor plan.

* refactor: split reminder-service into core/reminders and discord bridge

Extract pure reminder logic (repository, validation, scheduler) into
core/reminders/, which has no discord.js dependency. The scheduler now
triggers via a generic onTrigger callback instead of holding a Client.

Add discord/reminders/reminder-bridge.ts as the Client-aware layer that
wires the scheduler to message delivery and exposes the same API
previously provided by services/reminder-service.ts.

* refactor: move Discord-facing code under discord/

Relocate components, lang, presentations, commands, events, client,
handlers, registries, interactions, and Discord-only types (SlashCommand,
PrefixCommand, Event) under src/discord/, completing the core/discord
split apart from the shared logger (next step).

* refactor: move logger to shared/

Complete the core/discord split by relocating the cross-layer logger
to src/shared/, the only module used by both core/ and discord/.

* Collector must always precise their alloweds users

* feat: add Select component and CustomId helper

Add Select to the Components V2 DSL, wrapping itself in its own
ActionRow as required by Discord (a select occupies a full row).

Add CustomId<C>, a small build/parse helper that encodes a context and
an id into a single customId string, and migrate the reminder
delete/cancel button ids onto it to remove duplicated prefix logic.

* Help command & refactor lang + add selectMenu component (#32)

* refactor(lang): rename reminder lang module to remind/reminders

Splits the reminder lang content into separate remind and reminders
modules, following the one-module-per-command convention, and aligns
about/grade lang modules to use the messages namespace consistently.

Also centralizes the command prefix into a shared discord/constants.ts
constant and switches it from `!` to `c!`, and makes interaction
collectors reply ephemerally with an error when a non-allowed user
interacts instead of silently failing.

* feat(help): add /help command (#27)

Adds a /help and !help command that shows a select menu listing every
registered command and, once one is picked, its description, usage
and aliases.

Introduces a mandatory CommandHelp field (usageSlash/usagePrefix) on
every command and a CommandLang type to enforce the lang module shape
required to power the help display.

* feat(help): add main menu #27

* Fix error display + up the limit for classic user # 29 (#33)

* Add JSdoc (thanks to A.I for this one) #22 (#34)

* Maintenance command (#36)

* feat(maintenance): add maintenance mode & maintenance command #35

* Command help display only authorized commands for the user

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

Labels

feature New feature or request priority: medium Should do soon

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add scopes and authorizations for commands

2 participants