Skip to content

Commit c7347a4

Browse files
committed
refactor: dedupe discord trimmed readers
1 parent 96fe85f commit c7347a4

28 files changed

Lines changed: 144 additions & 106 deletions

extensions/discord/src/actions/handle-action.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param";
88
import { resolveReactionMessageId } from "openclaw/plugin-sdk/channel-actions";
99
import type { ChannelMessageActionContext } from "openclaw/plugin-sdk/channel-contract";
1010
import { normalizeInteractiveReply } from "openclaw/plugin-sdk/interactive-runtime";
11+
import { normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/text-runtime";
1112
import { handleDiscordAction } from "../../action-runtime-api.js";
1213
import { buildDiscordInteractiveComponents } from "../shared-interactive.js";
1314
import { resolveDiscordChannelId } from "../targets.js";
@@ -119,7 +120,7 @@ export async function handleDiscordMessageAction(
119120

120121
if (action === "react") {
121122
const messageIdRaw = resolveReactionMessageId({ args: params, toolContext: ctx.toolContext });
122-
const messageId = messageIdRaw != null ? String(messageIdRaw).trim() : "";
123+
const messageId = normalizeOptionalStringifiedId(messageIdRaw) ?? "";
123124
if (!messageId) {
124125
throw new Error(
125126
"messageId required. Provide messageId explicitly or react to the current inbound message.",

extensions/discord/src/approval-handler.runtime.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import type {
2424
ExecApprovalActionDescriptor,
2525
ExecApprovalDecision,
2626
} from "openclaw/plugin-sdk/infra-runtime";
27-
import { logDebug, logError } from "openclaw/plugin-sdk/text-runtime";
27+
import { logDebug, logError, normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
2828
import { shouldHandleDiscordApprovalRequest } from "./approval-native.js";
2929
import { isDiscordExecApprovalClientEnabled } from "./exec-approvals.js";
3030
import { createDiscordClient, stripUndefinedFields } from "./send.shared.js";
@@ -52,7 +52,7 @@ function resolveHandlerContext(params: ChannelApprovalCapabilityHandlerContext):
5252
context: DiscordApprovalHandlerContext;
5353
} | null {
5454
const context = params.context as DiscordApprovalHandlerContext | undefined;
55-
const accountId = params.accountId?.trim() || "";
55+
const accountId = normalizeOptionalString(params.accountId) ?? "";
5656
if (!context?.token || !accountId) {
5757
return null;
5858
}

extensions/discord/src/approval-native.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import type { ChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/ap
33
import { resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime";
44
import type { DiscordExecApprovalConfig, OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
55
import type { ExecApprovalRequest, PluginApprovalRequest } from "openclaw/plugin-sdk/infra-runtime";
6-
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
6+
import {
7+
normalizeLowercaseStringOrEmpty,
8+
normalizeOptionalString,
9+
} from "openclaw/plugin-sdk/text-runtime";
710
import { listDiscordAccountIds, resolveDiscordAccount } from "./accounts.js";
811
import {
912
createChannelApproverDmTargetResolver,
@@ -131,9 +134,11 @@ function createDiscordOriginTargetResolver(configOverride?: DiscordExecApprovalC
131134
request,
132135
channel: "discord",
133136
});
134-
const sessionKind = extractDiscordSessionKind(request.request.sessionKey?.trim() || null);
137+
const sessionKind = extractDiscordSessionKind(
138+
normalizeOptionalString(request.request.sessionKey) ?? null,
139+
);
135140
const turnSourceChannel = normalizeLowercaseStringOrEmpty(request.request.turnSourceChannel);
136-
const rawTurnSourceTo = request.request.turnSourceTo?.trim() || "";
141+
const rawTurnSourceTo = normalizeOptionalString(request.request.turnSourceTo) ?? "";
137142
const turnSourceTo = normalizeDiscordOriginChannelId(rawTurnSourceTo);
138143
const threadId =
139144
normalizeDiscordThreadId(request.request.turnSourceThreadId) ??

extensions/discord/src/audit-core.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type {
33
DiscordGuildEntry,
44
} from "openclaw/plugin-sdk/config-runtime";
55
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
6-
import { isRecord } from "openclaw/plugin-sdk/text-runtime";
6+
import { isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
77

88
export type DiscordChannelPermissionsAuditEntry = {
99
channelId: string;
@@ -50,7 +50,7 @@ export function listConfiguredGuildChannelKeys(
5050
continue;
5151
}
5252
for (const [key, value] of Object.entries(channelsRaw)) {
53-
const channelId = String(key).trim();
53+
const channelId = normalizeOptionalString(String(key)) ?? "";
5454
if (!channelId) {
5555
continue;
5656
}
@@ -88,7 +88,7 @@ export async function auditDiscordChannelPermissionsWithFetcher(params: {
8888
}>;
8989
}): Promise<DiscordChannelPermissionsAudit> {
9090
const started = Date.now();
91-
const token = params.token?.trim() ?? "";
91+
const token = normalizeOptionalString(params.token) ?? "";
9292
if (!token || params.channelIds.length === 0) {
9393
return {
9494
ok: true,

extensions/discord/src/channel-actions.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type {
99
ChannelMessageToolDiscovery,
1010
} from "openclaw/plugin-sdk/channel-contract";
1111
import type { DiscordActionConfig } from "openclaw/plugin-sdk/config-runtime";
12+
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
1213
import { extractToolSend } from "openclaw/plugin-sdk/tool-send";
1314
import {
1415
createDiscordActionGate,
@@ -168,12 +169,12 @@ function describeDiscordMessageTool({
168169
export const discordMessageActions: ChannelMessageActionAdapter = {
169170
describeMessageTool: describeDiscordMessageTool,
170171
extractToolSend: ({ args }) => {
171-
const action = typeof args.action === "string" ? args.action.trim() : "";
172+
const action = normalizeOptionalString(args.action) ?? "";
172173
if (action === "sendMessage") {
173174
return extractToolSend(args, "sendMessage");
174175
}
175176
if (action === "threadReply") {
176-
const channelId = typeof args.channelId === "string" ? args.channelId.trim() : "";
177+
const channelId = normalizeOptionalString(args.channelId) ?? "";
177178
return channelId ? { to: `channel:${channelId}` } : null;
178179
}
179180
return null;

extensions/discord/src/channel.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ import {
2525
createDefaultChannelRuntimeState,
2626
} from "openclaw/plugin-sdk/status-helpers";
2727
import { resolveTargetsWithOptionalToken } from "openclaw/plugin-sdk/target-resolver-runtime";
28-
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
28+
import {
29+
normalizeLowercaseStringOrEmpty,
30+
normalizeOptionalString,
31+
normalizeOptionalStringifiedId,
32+
} from "openclaw/plugin-sdk/text-runtime";
2933
import {
3034
listDiscordAccountIds,
3135
resolveDiscordAccount,
@@ -137,7 +141,7 @@ function resolveDiscordAttachedOutboundTarget(params: {
137141
if (params.threadId == null) {
138142
return params.to;
139143
}
140-
const threadId = String(params.threadId).trim();
144+
const threadId = normalizeOptionalStringifiedId(params.threadId) ?? "";
141145
return threadId ? `channel:${threadId}` : params.to;
142146
}
143147

@@ -206,7 +210,8 @@ function resolveDiscordStartupDelayMs(cfg: OpenClawConfig, accountId: string): n
206210
const candidate = resolveDiscordAccount({ cfg, accountId: candidateId });
207211
return (
208212
candidate.enabled &&
209-
(resolveConfiguredFromCredentialStatuses(candidate) ?? Boolean(candidate.token.trim()))
213+
(resolveConfiguredFromCredentialStatuses(candidate) ??
214+
Boolean(normalizeOptionalString(candidate.token)))
210215
);
211216
});
212217
const startupIndex = startupAccountIds.findIndex((candidateId) => candidateId === accountId);
@@ -367,7 +372,7 @@ function resolveDiscordCommandConversation(params: {
367372
const targets = [params.originatingTo, params.commandTo, params.fallbackTo];
368373
if (params.threadId) {
369374
const parentConversationId =
370-
normalizeDiscordMessagingTarget(params.threadParentId?.trim() ?? "") ||
375+
normalizeDiscordMessagingTarget(normalizeOptionalString(params.threadParentId) ?? "") ||
371376
parseDiscordParentChannelFromSessionKey(params.parentSessionKey) ||
372377
resolveDiscordConversationIdFromTargets(targets);
373378
return {

extensions/discord/src/directory-cache.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/routing";
2-
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
2+
import {
3+
normalizeLowercaseStringOrEmpty,
4+
normalizeOptionalString,
5+
normalizeOptionalStringifiedId,
6+
} from "openclaw/plugin-sdk/text-runtime";
37

48
const DISCORD_DIRECTORY_CACHE_MAX_ENTRIES = 4000;
59
const DISCORD_DISCRIMINATOR_SUFFIX = /#\d{4}$/;
@@ -12,20 +16,20 @@ function normalizeAccountCacheKey(accountId?: string | null): string {
1216
}
1317

1418
function normalizeSnowflake(value: string | number | bigint): string | null {
15-
const text = String(value ?? "").trim();
19+
const text = normalizeOptionalStringifiedId(value) ?? "";
1620
if (!/^\d+$/.test(text)) {
1721
return null;
1822
}
1923
return text;
2024
}
2125

2226
function normalizeHandleKey(raw: string): string | null {
23-
let handle = raw.trim();
27+
let handle = normalizeOptionalString(raw) ?? "";
2428
if (!handle) {
2529
return null;
2630
}
2731
if (handle.startsWith("@")) {
28-
handle = handle.slice(1).trim();
32+
handle = normalizeOptionalString(handle.slice(1)) ?? "";
2933
}
3034
if (!handle || /\s/.test(handle)) {
3135
return null;

extensions/discord/src/doctor-contract.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type {
33
ChannelDoctorLegacyConfigRule,
44
} from "openclaw/plugin-sdk/channel-contract";
55
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
6+
import { normalizeStringEntries } from "openclaw/plugin-sdk/text-runtime";
67
import { resolveDiscordPreviewStreamMode } from "./preview-streaming.js";
78

89
function asObjectRecord(value: unknown): Record<string, unknown> | null {
@@ -23,8 +24,8 @@ function allowFromListsMatch(left: unknown, right: unknown): boolean {
2324
if (!Array.isArray(left) || !Array.isArray(right)) {
2425
return false;
2526
}
26-
const normalizedLeft = left.map((value) => String(value).trim()).filter(Boolean);
27-
const normalizedRight = right.map((value) => String(value).trim()).filter(Boolean);
27+
const normalizedLeft = normalizeStringEntries(left);
28+
const normalizedRight = normalizeStringEntries(right);
2829
if (normalizedLeft.length !== normalizedRight.length) {
2930
return false;
3031
}

extensions/discord/src/doctor.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { type ChannelDoctorAdapter } from "openclaw/plugin-sdk/channel-contract";
22
import { type OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
33
import { collectProviderDangerousNameMatchingScopes } from "openclaw/plugin-sdk/runtime-doctor";
4+
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
45
import { normalizeCompatibilityConfig as normalizeDiscordCompatibilityConfig } from "./doctor-contract.js";
56
import { DISCORD_LEGACY_CONFIG_RULES } from "./doctor-shared.js";
67
import { isDiscordMutableAllowEntry } from "./security-doctor.js";
@@ -241,7 +242,7 @@ function collectDiscordMutableAllowlistWarnings(cfg: OpenClawConfig): string[] {
241242
return;
242243
}
243244
for (const entry of list) {
244-
const text = String(entry).trim();
245+
const text = normalizeOptionalString(String(entry)) ?? "";
245246
if (!text || text === "*" || !isDiscordMutableAllowEntry(text)) {
246247
continue;
247248
}

extensions/discord/src/group-policy.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
type GroupToolPolicyConfig,
66
} from "openclaw/plugin-sdk/channel-policy";
77
import { normalizeAtHashSlug } from "openclaw/plugin-sdk/string-normalization-runtime";
8+
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
89
import type { DiscordConfig } from "./runtime-api.js";
910

1011
function normalizeDiscordSlug(value?: string | null) {
@@ -21,7 +22,7 @@ function resolveDiscordGuildEntry(guilds: DiscordConfig["guilds"], groupSpace?:
2122
if (!guilds || Object.keys(guilds).length === 0) {
2223
return null;
2324
}
24-
const space = groupSpace?.trim() ?? "";
25+
const space = normalizeOptionalString(groupSpace) ?? "";
2526
if (space && guilds[space]) {
2627
return guilds[space];
2728
}

0 commit comments

Comments
 (0)