Skip to content

Commit 32e1dd3

Browse files
wings1029claude
andcommitted
fix(discord): inherit default_auto_archive_duration in createThreadDiscord
When createThreadForBinding hardcoded autoArchiveMinutes: 60, the parent channel's default_auto_archive_duration (configured by operators at 1440, 4320, or 10080) was silently overridden. This is the same pattern fixed in #103033 for sendMessageDiscord's implicit forum thread creation. - Move the auto_archive_duration set after the channel fetch in createThreadDiscord so channel.default_auto_archive_duration can serve as a fallback when autoArchiveMinutes is not provided. - Remove the hardcoded autoArchiveMinutes: 60 from createThreadForBinding so it inherits the channel default for forum/media channels and omits the field for text channels (preserving Discord's server-side default). - Explicit autoArchiveMinutes from callers (thread-create action, auto-thread config) still take priority via the ?? operator. Co-Authored-By: Claude <[email protected]>
1 parent cd9db5e commit 32e1dd3

4 files changed

Lines changed: 81 additions & 34 deletions

File tree

extensions/discord/src/monitor/thread-bindings.discord-api.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,6 @@ export async function createThreadForBinding(params: {
287287
params.channelId,
288288
{
289289
name: params.threadName,
290-
autoArchiveMinutes: 60,
291290
},
292291
{
293292
cfg: params.cfg,

extensions/discord/src/monitor/thread-bindings.lifecycle.test.ts

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,6 @@ describe("thread binding lifecycle", () => {
219219
params.channelId,
220220
{
221221
name: params.threadName,
222-
autoArchiveMinutes: 60,
223222
},
224223
{
225224
accountId: params.accountId,
@@ -892,13 +891,14 @@ describe("thread binding lifecycle", () => {
892891
});
893892
expect(hoisted.createThreadDiscord).toHaveBeenCalledTimes(1);
894893
expect(mockCallArg(hoisted.createThreadDiscord, 0, 0, "createThreadDiscord")).toBe("parent-1");
895-
expectFields(
896-
mockCallArg(hoisted.createThreadDiscord, 0, 1, "createThreadDiscord"),
897-
"thread options",
898-
{
899-
autoArchiveMinutes: 60,
900-
},
901-
);
894+
expect(
895+
(
896+
mockCallArg(hoisted.createThreadDiscord, 0, 1, "createThreadDiscord") as Record<
897+
string,
898+
unknown
899+
>
900+
)?.name,
901+
).toBeTypeOf("string");
902902
expectFields(
903903
mockCallArg(hoisted.createThreadDiscord, 0, 2, "createThreadDiscord"),
904904
"thread context",
@@ -942,13 +942,14 @@ describe("thread binding lifecycle", () => {
942942
expectFields(childBinding, "child binding", { channelId: "parent-1" });
943943
expect(hoisted.restGet).toHaveBeenCalledTimes(1);
944944
expect(mockCallArg(hoisted.createThreadDiscord, 0, 0, "createThreadDiscord")).toBe("parent-1");
945-
expectFields(
946-
mockCallArg(hoisted.createThreadDiscord, 0, 1, "createThreadDiscord"),
947-
"thread options",
948-
{
949-
autoArchiveMinutes: 60,
950-
},
951-
);
945+
expect(
946+
(
947+
mockCallArg(hoisted.createThreadDiscord, 0, 1, "createThreadDiscord") as Record<
948+
string,
949+
unknown
950+
>
951+
)?.name,
952+
).toBeTypeOf("string");
952953
expectFields(
953954
mockCallArg(hoisted.createThreadDiscord, 0, 2, "createThreadDiscord"),
954955
"thread context",
@@ -1114,13 +1115,14 @@ describe("thread binding lifecycle", () => {
11141115
expect(mockCallArg(hoisted.createThreadDiscord, 0, 0, "createThreadDiscord")).toBe(
11151116
"parent-runtime",
11161117
);
1117-
expectFields(
1118-
mockCallArg(hoisted.createThreadDiscord, 0, 1, "createThreadDiscord"),
1119-
"thread options",
1120-
{
1121-
autoArchiveMinutes: 60,
1122-
},
1123-
);
1118+
expect(
1119+
(
1120+
mockCallArg(hoisted.createThreadDiscord, 0, 1, "createThreadDiscord") as Record<
1121+
string,
1122+
unknown
1123+
>
1124+
)?.name,
1125+
).toBeTypeOf("string");
11241126
expectFields(
11251127
mockCallArg(hoisted.createThreadDiscord, 0, 2, "createThreadDiscord"),
11261128
"thread context",
@@ -1177,13 +1179,14 @@ describe("thread binding lifecycle", () => {
11771179
expect(mockCallArg(hoisted.createThreadDiscord, 0, 0, "createThreadDiscord")).toBe(
11781180
"1491611525914558667",
11791181
);
1180-
expectFields(
1181-
mockCallArg(hoisted.createThreadDiscord, 0, 1, "createThreadDiscord"),
1182-
"thread options",
1183-
{
1184-
autoArchiveMinutes: 60,
1185-
},
1186-
);
1182+
expect(
1183+
(
1184+
mockCallArg(hoisted.createThreadDiscord, 0, 1, "createThreadDiscord") as Record<
1185+
string,
1186+
unknown
1187+
>
1188+
)?.name,
1189+
).toBeTypeOf("string");
11871190
expectFields(
11881191
mockCallArg(hoisted.createThreadDiscord, 0, 2, "createThreadDiscord"),
11891192
"thread context",

extensions/discord/src/send.creates-thread.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,40 @@ describe("sendMessageDiscord", () => {
156156
});
157157
});
158158

159+
it("inherits default_auto_archive_duration for forum threads", async () => {
160+
const { rest, getMock, postMock } = makeDiscordRest();
161+
getMock.mockResolvedValue({
162+
type: ChannelType.GuildForum,
163+
default_auto_archive_duration: 1440,
164+
});
165+
postMock.mockResolvedValue({ id: "t1" });
166+
await createThreadDiscord("chan1", { name: "thread" }, discordClientOpts(rest));
167+
expect(requestBody(postMock as unknown as MockCallSource)).toEqual({
168+
name: "thread",
169+
auto_archive_duration: 1440,
170+
message: { content: "thread" },
171+
});
172+
});
173+
174+
it("prefers explicit autoArchiveMinutes over channel default", async () => {
175+
const { rest, getMock, postMock } = makeDiscordRest();
176+
getMock.mockResolvedValue({
177+
type: ChannelType.GuildForum,
178+
default_auto_archive_duration: 1440,
179+
});
180+
postMock.mockResolvedValue({ id: "t1" });
181+
await createThreadDiscord(
182+
"chan1",
183+
{ name: "thread", autoArchiveMinutes: 4320 },
184+
discordClientOpts(rest),
185+
);
186+
expect(requestBody(postMock as unknown as MockCallSource)).toEqual({
187+
name: "thread",
188+
auto_archive_duration: 4320,
189+
message: { content: "thread" },
190+
});
191+
});
192+
159193
it("creates media threads with provided content", async () => {
160194
const { rest, getMock, postMock } = makeDiscordRest();
161195
getMock.mockResolvedValue({ type: ChannelType.GuildMedia });

extensions/discord/src/send.messages.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,23 +158,34 @@ export async function createThreadDiscord(
158158
) {
159159
const rest = resolveDiscordRest(opts);
160160
const body: Record<string, unknown> = { name: payload.name };
161-
if (payload.autoArchiveMinutes) {
162-
body.auto_archive_duration = payload.autoArchiveMinutes;
163-
}
164161
if (!payload.messageId && payload.type !== undefined) {
165162
body.type = payload.type;
166163
}
164+
let channel: APIChannel | undefined;
167165
let channelType: ChannelType | undefined;
168166
if (!payload.messageId) {
169167
// Only detect channel kind for route-less thread creation.
170168
// If this lookup fails, keep prior behavior and let Discord validate.
171169
try {
172-
const channel = await getChannel(rest, channelId);
170+
channel = await getChannel(rest, channelId);
173171
channelType = channel?.type;
174172
} catch {
175173
channelType = undefined;
176174
}
177175
}
176+
// Inherit auto_archive_duration from the parent channel when the caller does
177+
// not provide an explicit value. Forum and media channels expose
178+
// default_auto_archive_duration; text channels omit it so the field is left
179+
// unset, preserving Discord's server-side default.
180+
// APIChannel is a union; default_auto_archive_duration only exists on guild
181+
// channels (text, news, forum, media) so narrow via an intersection cast.
182+
const archiveDuration =
183+
payload.autoArchiveMinutes ??
184+
(channel as { default_auto_archive_duration?: number } | undefined)
185+
?.default_auto_archive_duration;
186+
if (archiveDuration !== undefined) {
187+
body.auto_archive_duration = archiveDuration;
188+
}
178189
const isForumLike =
179190
channelType === ChannelType.GuildForum || channelType === ChannelType.GuildMedia;
180191
if (isForumLike) {

0 commit comments

Comments
 (0)