Skip to content

Follow-up: tighten modal helper + Set-as-Default in typeList #2

@NindroidA

Description

@NindroidA

Two findings from the manual review on PR #1 that were intentionally deferred (option B scope) — neither is currently triggered, but both are real footguns worth closing.

1. extractCustomId returns '' for unknown modal shapes

src/utils/interactions/modalHelper.ts:80-86 probes .data.custom_id (ModalBuilder) and .custom_id (rawModal). If a future caller ever passes anything else, the helper returns '' and the awaitModalSubmit filter becomes i.customId === '' — never matches — so the call silently times out for the full TIMEOUTS.MODAL (5 minutes), notifies the user with a misleading timeout message, and blocks for that whole window.

No current caller triggers this (audited at review time) but the silent-fail mode is dangerous when the next modal helper lands. Fix: throw or warn-log when extractCustomId can't find a customId on either shape.

2. `Set as Default` does N sequential saves with shared-mutation race

src/commands/handlers/ticket/typeList.ts:179-186 iterates the in-memory types array and await typeRepo.save(t) per row in sequence. With 25 ticket types this is up to 25 sequential round-trips during which:

  • The components are still rendered, so the user can click any other button on the same row.
  • A concurrent collect handler reads from the same `types` array reference, sees the partially-mutated state mid-loop.

In practice both handlers converge because they both end up calling `save()` on the same object, but the in-place mutation while another handler holds a reference is brittle.

Fix: replace the loop with two typeRepo.update() calls — clear all (`{guildId}, {isDefault: false}`), then set one (`{guildId, typeId}, {isDefault: true}`). 2 round-trips instead of N, no shared-mutation window.

Priority

Low. Both are theoretical with current usage. Bundle into a future maintenance commit.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions