openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
275 lines (274 loc) • 10.4 kB
JavaScript
import { a as isSubagentSessionKey, c as parseAgentSessionKey, n as isAcpSessionKey } from "./session-key-utils-Bx3apsJ3.js";
import { f as resolveAgentIdFromSessionKey } from "./session-key-B_NoIfpX.js";
import { r as logVerbose } from "./globals-GTrXU4s9.js";
import { i as resolveAgentRoute, n as deriveLastRoutePolicy } from "./resolve-route-xcIS8NFL.js";
import "./runtime-env-D_2q8-VK.js";
import "./routing-CQ63ICPX.js";
import { d as upsertChannelPairingRequest } from "./pairing-store-CxANz_ON.js";
import "./conversation-runtime-VjM1-D7a.js";
import { n as createChannelIngressResolver, o as defineStableChannelIngressIdentity } from "./message-access-mwxdTUGC.js";
import "./channel-ingress-runtime-rGltVkKC.js";
import { t as createChannelPairingChallengeIssuer } from "./channel-pairing-Bk6_JhTm.js";
import { D as canViewDiscordGuildChannel } from "./send.shared-SdWkx4sF.js";
import { r as normalizeDiscordAllowList } from "./allow-list-CBhA2l4a.js";
//#region extensions/discord/src/monitor/dm-command-auth.ts
const DISCORD_ALLOW_LIST_PREFIXES = [
"discord:",
"user:",
"pk:"
];
const DISCORD_CHANNEL_ID = "discord";
const DISCORD_USER_ID_KIND = "stable-id";
const DISCORD_USER_NAME_KIND = "username";
function normalizeDiscordIdEntry(entry) {
const text = entry.trim();
if (!text) return null;
const maybeId = text.replace(/^<@!?/, "").replace(/>$/, "");
if (/^\d+$/.test(maybeId)) return maybeId;
const prefix = DISCORD_ALLOW_LIST_PREFIXES.find((entryPrefix) => text.startsWith(entryPrefix));
if (prefix) return text.slice(prefix.length).trim() || null;
return null;
}
function normalizeDiscordNameEntry(entry) {
const text = entry.trim();
if (!text || text === "*" || normalizeDiscordIdEntry(text)) return null;
const nameSlug = normalizeDiscordAllowList([text], DISCORD_ALLOW_LIST_PREFIXES)?.names.values().next().value;
return typeof nameSlug === "string" && nameSlug ? nameSlug : null;
}
function normalizeDiscordNameSubject(value) {
const nameSlug = normalizeDiscordAllowList([value], DISCORD_ALLOW_LIST_PREFIXES)?.names.values().next().value;
return typeof nameSlug === "string" && nameSlug ? nameSlug : null;
}
const discordIngressIdentity = defineStableChannelIngressIdentity({
key: "discordUserId",
kind: DISCORD_USER_ID_KIND,
normalizeEntry: normalizeDiscordIdEntry,
normalizeSubject: (value) => value.trim() || null,
sensitivity: "pii",
aliases: [["discordUserName", normalizeDiscordNameEntry], ["discordUserTag", () => null]].map(([key, normalizeEntry]) => ({
key,
kind: DISCORD_USER_NAME_KIND,
normalizeEntry,
normalizeSubject: normalizeDiscordNameSubject,
dangerous: true,
sensitivity: "pii"
}))
});
function createDiscordDmIngressSubject(sender) {
return {
stableId: sender.id,
aliases: {
discordUserName: sender.name,
discordUserTag: sender.tag
}
};
}
function createDiscordDynamicAccessGroupResolver(params) {
if (!params.cfg) return;
const cfg = params.cfg;
return async ({ name, group, accountId, subject }) => {
if (group.type !== "discord.channelAudience") return false;
const senderId = String(subject.stableId ?? "").trim();
if (!senderId) return false;
if ((group.membership ?? "canViewChannel") !== "canViewChannel") return false;
try {
return await canViewDiscordGuildChannel(group.guildId, group.channelId, senderId, {
cfg,
accountId,
token: params.token,
rest: params.rest
});
} catch (err) {
logVerbose(`discord: accessGroup:${name} lookup failed for user ${senderId}: ${String(err)}`);
throw err;
}
};
}
function createDiscordIngressResolver(params) {
return createChannelIngressResolver({
channelId: DISCORD_CHANNEL_ID,
accountId: params.accountId,
identity: discordIngressIdentity,
cfg: params.cfg,
resolveAccessGroupMembership: createDiscordDynamicAccessGroupResolver({
cfg: params.cfg,
token: params.token,
rest: params.rest
}),
...params.readStoreAllowFrom ? { readStoreAllowFrom: params.readStoreAllowFrom } : {},
...params.useDefaultPairingStore !== void 0 ? { useDefaultPairingStore: params.useDefaultPairingStore } : {}
});
}
function syntheticAccessGroupMembership(groupName, allowed) {
return allowed ? {
kind: "matched",
groupName,
source: "dynamic",
matchedEntryIds: [groupName]
} : {
kind: "not-matched",
groupName,
source: "dynamic"
};
}
async function resolveDiscordDmCommandAccess(params) {
return await createDiscordIngressResolver({
accountId: params.accountId,
cfg: params.cfg,
token: params.token,
rest: params.rest,
readStoreAllowFrom: params.readStoreAllowFrom,
useDefaultPairingStore: params.readStoreAllowFrom == null
}).message({
subject: createDiscordDmIngressSubject(params.sender),
conversation: {
kind: "direct",
id: params.sender.id
},
event: {
kind: params.eventKind ?? "native-command",
authMode: "inbound",
mayPair: true
},
dmPolicy: params.dmPolicy,
groupPolicy: "disabled",
policy: { mutableIdentifierMatching: params.allowNameMatching ? "enabled" : "disabled" },
allowFrom: params.configuredAllowFrom,
command: {
hasControlCommand: false,
modeWhenAccessGroupsOff: "configured"
}
});
}
async function resolveDiscordTextCommandAccess(params) {
const ownerAllowFrom = (params.ownerAllowFrom ?? []).filter((entry) => entry.trim() !== "*");
const memberAccessGroup = "discord-member-access";
const commandGroup = params.memberAccessConfigured ? [`accessGroup:${memberAccessGroup}`] : [];
const accessGroupMembership = params.memberAccessConfigured ? [syntheticAccessGroupMembership(memberAccessGroup, params.memberAllowed)] : [];
return (await createDiscordIngressResolver({
accountId: params.accountId,
cfg: params.cfg,
token: params.token,
rest: params.rest
}).command({
subject: createDiscordDmIngressSubject(params.sender),
conversation: {
kind: "group",
id: "discord-command"
},
accessGroupMembership,
dmPolicy: "allowlist",
groupPolicy: "allowlist",
policy: { mutableIdentifierMatching: params.allowNameMatching ? "enabled" : "disabled" },
allowFrom: ownerAllowFrom,
groupAllowFrom: commandGroup,
command: {
allowTextCommands: params.allowTextCommands,
hasControlCommand: params.hasControlCommand,
modeWhenAccessGroupsOff: "configured"
}
})).commandAccess;
}
//#endregion
//#region extensions/discord/src/monitor/dm-command-decision.ts
async function handleDiscordDmCommandDecision(params) {
if (params.senderAccess.decision === "allow") return true;
if (params.senderAccess.decision === "pairing") {
const upsertPairingRequest = params.upsertPairingRequest ?? upsertChannelPairingRequest;
const result = await createChannelPairingChallengeIssuer({
channel: "discord",
upsertPairingRequest: async ({ id, meta }) => await upsertPairingRequest({
channel: "discord",
id,
accountId: params.accountId,
meta
})
})({
senderId: params.sender.id,
senderIdLine: `Your Discord user id: ${params.sender.id}`,
meta: {
tag: params.sender.tag,
name: params.sender.name
},
sendPairingReply: async () => {}
});
if (result.created && result.code) await params.onPairingCreated(result.code);
return false;
}
await params.onUnauthorized();
return false;
}
//#endregion
//#region extensions/discord/src/monitor/route-resolution.ts
function buildDiscordRoutePeer(params) {
return {
kind: params.isDirectMessage ? "direct" : params.isGroupDm ? "group" : "channel",
id: params.isDirectMessage ? params.directUserId?.trim() || params.conversationId : params.conversationId
};
}
function resolveDiscordConversationRoute(params) {
return resolveAgentRoute({
cfg: params.cfg,
channel: "discord",
accountId: params.accountId,
guildId: params.guildId ?? void 0,
memberRoleIds: params.memberRoleIds,
peer: params.peer,
parentPeer: params.parentConversationId ? {
kind: "channel",
id: params.parentConversationId
} : void 0
});
}
function resolveDiscordBoundConversationRoute(params) {
return resolveDiscordEffectiveRoute({
route: resolveDiscordConversationRoute({
cfg: params.cfg,
accountId: params.accountId,
guildId: params.guildId,
memberRoleIds: params.memberRoleIds,
peer: buildDiscordRoutePeer({
isDirectMessage: params.isDirectMessage,
isGroupDm: params.isGroupDm,
directUserId: params.directUserId,
conversationId: params.conversationId
}),
parentConversationId: params.parentConversationId
}),
boundSessionKey: params.boundSessionKey,
configuredRoute: params.configuredRoute,
matchedBy: params.matchedBy
});
}
function resolveDiscordEffectiveRoute(params) {
const boundSessionKey = params.boundSessionKey?.trim();
if (!boundSessionKey) return params.configuredRoute?.route ?? params.route;
return {
...params.route,
sessionKey: boundSessionKey,
agentId: resolveAgentIdFromSessionKey(boundSessionKey),
lastRoutePolicy: deriveLastRoutePolicy({
sessionKey: boundSessionKey,
mainSessionKey: params.route.mainSessionKey
}),
...params.matchedBy ? { matchedBy: params.matchedBy } : {}
};
}
function hasExplicitRuntimeBindingIntent(record) {
if (record.targetKind === "subagent") return true;
if (isAcpSessionKey(record.targetSessionKey) || isSubagentSessionKey(record.targetSessionKey)) return true;
const metadata = record.metadata;
if (!metadata || typeof metadata !== "object") return false;
return typeof metadata.boundBy === "string" || typeof metadata.label === "string" || typeof metadata.threadName === "string" || metadata.pluginBindingOwner === "plugin";
}
function shouldIgnoreStaleDiscordRouteBinding(params) {
const bindingRecord = params.bindingRecord;
const boundSessionKey = bindingRecord?.targetSessionKey?.trim();
if (!bindingRecord || !boundSessionKey || hasExplicitRuntimeBindingIntent(bindingRecord)) return false;
const bound = parseAgentSessionKey(boundSessionKey);
const routed = parseAgentSessionKey(params.route.sessionKey);
if (!bound || !routed || bound.rest !== routed.rest) return false;
return bound.agentId !== params.route.agentId;
}
//#endregion
export { shouldIgnoreStaleDiscordRouteBinding as a, resolveDiscordTextCommandAccess as c, resolveDiscordEffectiveRoute as i, resolveDiscordBoundConversationRoute as n, handleDiscordDmCommandDecision as o, resolveDiscordConversationRoute as r, resolveDiscordDmCommandAccess as s, buildDiscordRoutePeer as t };