discord: support forum post creation via thread-create

Allow thread-create to create Discord forum posts by accepting initial content and appliedTagIds, and using POST /channels/{id}/threads.
This commit is contained in:
Solvely-Colin 2026-01-27 23:08:59 +00:00
parent 0b1c8db0ca
commit 37ffd3463b
4 changed files with 49 additions and 3 deletions

View File

@ -279,18 +279,31 @@ export async function handleDiscordMessagingAction(
const channelId = resolveChannelId(); const channelId = resolveChannelId();
const name = readStringParam(params, "name", { required: true }); const name = readStringParam(params, "name", { required: true });
const messageId = readStringParam(params, "messageId"); const messageId = readStringParam(params, "messageId");
// Optional initial content (required for forum posts).
const content = readStringParam(params, "content") ?? undefined;
// Optional applied tag ids (forum posts).
const appliedTagIds = Array.isArray(params.appliedTagIds)
? params.appliedTagIds.filter((x) => typeof x === "string" && x.trim())
: undefined;
const autoArchiveMinutesRaw = params.autoArchiveMinutes; const autoArchiveMinutesRaw = params.autoArchiveMinutes;
const autoArchiveMinutes = const autoArchiveMinutes =
typeof autoArchiveMinutesRaw === "number" && Number.isFinite(autoArchiveMinutesRaw) typeof autoArchiveMinutesRaw === "number" && Number.isFinite(autoArchiveMinutesRaw)
? autoArchiveMinutesRaw ? autoArchiveMinutesRaw
: undefined; : undefined;
const thread = accountId const thread = accountId
? await createThreadDiscord( ? await createThreadDiscord(
channelId, channelId,
{ name, messageId, autoArchiveMinutes }, { name, messageId, autoArchiveMinutes, content, appliedTagIds },
{ accountId }, { accountId },
) )
: await createThreadDiscord(channelId, { name, messageId, autoArchiveMinutes }); : await createThreadDiscord(channelId, {
name,
messageId,
autoArchiveMinutes,
content,
appliedTagIds,
});
return jsonResult({ ok: true, thread }); return jsonResult({ ok: true, thread });
} }
case "threadList": { case "threadList": {

View File

@ -180,6 +180,10 @@ export async function handleDiscordMessageAction(
if (action === "thread-create") { if (action === "thread-create") {
const name = readStringParam(params, "threadName", { required: true }); const name = readStringParam(params, "threadName", { required: true });
const messageId = readStringParam(params, "messageId"); const messageId = readStringParam(params, "messageId");
// Optional initial post content (required for forum post creation).
const content = readStringParam(params, "message");
// Optional forum tag ids.
const appliedTagIds = readStringArrayParam(params, "appliedTagIds");
const autoArchiveMinutes = readNumberParam(params, "autoArchiveMin", { const autoArchiveMinutes = readNumberParam(params, "autoArchiveMin", {
integer: true, integer: true,
}); });
@ -190,6 +194,8 @@ export async function handleDiscordMessageAction(
channelId: resolveChannelId(), channelId: resolveChannelId(),
name, name,
messageId, messageId,
content,
appliedTagIds,
autoArchiveMinutes, autoArchiveMinutes,
}, },
cfg, cfg,

View File

@ -94,10 +94,30 @@ export async function createThreadDiscord(
) { ) {
const rest = resolveDiscordRest(opts); const rest = resolveDiscordRest(opts);
const body: Record<string, unknown> = { name: payload.name }; const body: Record<string, unknown> = { name: payload.name };
if (payload.autoArchiveMinutes) { if (payload.autoArchiveMinutes) {
body.auto_archive_duration = payload.autoArchiveMinutes; body.auto_archive_duration = payload.autoArchiveMinutes;
} }
const route = Routes.threads(channelId, payload.messageId);
// Forum posts (channel type 15) require an initial message payload.
// If content is provided, create the thread with an initial post.
if (payload.content) {
body.message = { content: payload.content };
if (Array.isArray(payload.appliedTagIds) && payload.appliedTagIds.length) {
body.applied_tags = payload.appliedTagIds;
}
// NOTE: discord-api-types Routes doesn't currently expose a helper for
// POST /channels/{channel.id}/threads (it only exposes listing archived threads),
// so use the raw route string.
const route = `/channels/${channelId}/threads`;
return await rest.post(route, { body });
}
// Regular threads: create from an existing message when messageId is provided,
// otherwise create a standard thread in the channel.
const route = payload.messageId
? Routes.threads(channelId, payload.messageId)
: `/channels/${channelId}/threads`;
return await rest.post(route, { body }); return await rest.post(route, { body });
} }

View File

@ -67,9 +67,16 @@ export type DiscordMessageEdit = {
}; };
export type DiscordThreadCreate = { export type DiscordThreadCreate = {
/** Optional message id to start a thread from (for classic threads). */
messageId?: string; messageId?: string;
/** Thread / forum post title. */
name: string; name: string;
/** Auto-archive duration in minutes. */
autoArchiveMinutes?: number; autoArchiveMinutes?: number;
/** Optional initial post content (required for forum post creation). */
content?: string;
/** Optional forum tag ids (applied tags). */
appliedTagIds?: string[];
}; };
export type DiscordThreadList = { export type DiscordThreadList = {