From 05658b66093881299c2b26ce55b3673e0f9a1bc6 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 15 Jan 2026 17:08:09 +0000 Subject: [PATCH] fix: tighten command arg value types --- src/auto-reply/commands-registry.types.ts | 3 +- src/auto-reply/templating.test.ts | 34 +++++++++++++++++++++++ src/discord/monitor/native-command.ts | 2 +- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 src/auto-reply/templating.test.ts diff --git a/src/auto-reply/commands-registry.types.ts b/src/auto-reply/commands-registry.types.ts index 9abfa80c4..c19c9d9a7 100644 --- a/src/auto-reply/commands-registry.types.ts +++ b/src/auto-reply/commands-registry.types.ts @@ -28,7 +28,8 @@ export type CommandArgMenuSpec = { title?: string; }; -export type CommandArgValues = Record; +export type CommandArgValue = string | number | boolean | bigint; +export type CommandArgValues = Record; export type CommandArgs = { raw?: string; diff --git a/src/auto-reply/templating.test.ts b/src/auto-reply/templating.test.ts new file mode 100644 index 000000000..aeefdc53a --- /dev/null +++ b/src/auto-reply/templating.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from "vitest"; +import { applyTemplate, type TemplateContext } from "./templating.js"; + +describe("applyTemplate", () => { + it("renders primitive values", () => { + const ctx = { MessageSid: "sid", IsNewSession: "no" } as TemplateContext; + const overrides = ctx as Record; + overrides.MessageSid = 42; + overrides.IsNewSession = true; + + expect(applyTemplate("sid={{MessageSid}} new={{IsNewSession}}", ctx)).toBe( + "sid=42 new=true", + ); + }); + + it("renders arrays of primitives", () => { + const ctx = { MediaPaths: ["a"] } as TemplateContext; + (ctx as Record).MediaPaths = ["a", 2, true, null, { ok: false }]; + + expect(applyTemplate("paths={{MediaPaths}}", ctx)).toBe("paths=a,2,true"); + }); + + it("drops object values", () => { + const ctx: TemplateContext = { CommandArgs: { raw: "go" } }; + + expect(applyTemplate("args={{CommandArgs}}", ctx)).toBe("args="); + }); + + it("renders missing placeholders as empty", () => { + const ctx: TemplateContext = {}; + + expect(applyTemplate("missing={{Missing}}", ctx)).toBe("missing="); + }); +}); diff --git a/src/discord/monitor/native-command.ts b/src/discord/monitor/native-command.ts index cb07e216b..3dafe17c7 100644 --- a/src/discord/monitor/native-command.ts +++ b/src/discord/monitor/native-command.ts @@ -118,7 +118,7 @@ function readDiscordCommandArgs( if (!definitions || definitions.length === 0) return undefined; const values: CommandArgValues = {}; for (const definition of definitions) { - let value: unknown; + let value: string | number | boolean | null; if (definition.type === "number") { value = interaction.options.getNumber(definition.name); } else if (definition.type === "boolean") {