@openclaw/slack 2026.7.1-beta.6 → 2026.7.2-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accounts.runtime-KvftRRek.js +2 -0
- package/dist/{action-runtime-DoQGk_8D.js → action-runtime-p6M2ULpv.js} +205 -29
- package/dist/action-runtime.runtime-DQstDkHG.js +2 -0
- package/dist/{actions-DMpDmKEA.js → actions-DkTcWmpT.js} +87 -138
- package/dist/{actions.runtime-C103_BPW.js → actions.runtime-BSxpwgUc.js} +1 -1
- package/dist/api.js +14 -13
- package/dist/{approval-handler.runtime-CIUbOt5T.js → approval-handler.runtime-UGbnz9OC.js} +3 -3
- package/dist/{channel-BjlsaGHn.js → channel-B0_j6C6z.js} +116 -140
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/channel-type-BpeTezY4.js +109 -0
- package/dist/{channel.setup-Dq6syTNU.js → channel.setup-BQFut21T.js} +2 -2
- package/dist/{client-DGxwSL7f.js → client-D2F6m8CP.js} +38 -2
- package/dist/config-api-Df9a1B8C.js +3 -0
- package/dist/{config-schema-BzqzFW__.js → config-schema-DYI01PV2.js} +20 -37
- package/dist/cursor-pages-DSmTg0su.js +13 -0
- package/dist/{directory-config-BZuS8141.js → directory-config-DRkFujwG.js} +2 -2
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-BNsxCgqP.js → directory-live-DX7yFsM-.js} +2 -2
- package/dist/{doctor-contract-XL6HeNCb.js → doctor-contract-DddfkMlF.js} +25 -38
- package/dist/doctor-contract-api.js +1 -1
- package/dist/group-policy-C-b2ZnSl.js +2332 -0
- package/dist/{interactive-replies-CXpT-vA_.js → interactive-replies-BilWUdcI.js} +5 -1
- package/dist/interactive-replies-api.js +1 -1
- package/dist/{message-tool-api-BgWKyu2r.js → message-tool-api-CA9jZrCY.js} +1 -1
- package/dist/message-tool-api.js +1 -1
- package/dist/{monitor-Ux-wzUWI.js → monitor-BN_uuvrQ.js} +3 -3
- package/dist/outbound-adapter-ECl0go7d.js +228 -0
- package/dist/{pipeline.runtime-rpVpay59.js → pipeline.runtime-f0eJJoJL.js} +492 -178
- package/dist/{policy-Dj-puVPb.js → policy-f8b0edSi.js} +1 -1
- package/dist/preflight-audio.runtime-D5Bgags0.js +3 -0
- package/dist/{probe-CuwRDE5j.js → probe-CfALk0l4.js} +2 -2
- package/dist/{provider-C1-DFSpw.js → provider-Ds-y-imP.js} +658 -192
- package/dist/{relay-source-D2jv1iGg.js → relay-source-B-6LFUdz.js} +6 -17
- package/dist/replies-BMvf3ihj.js +420 -0
- package/dist/{resolve-channels-CstkChBE.js → resolve-channels-DOMgNCWb.js} +17 -6
- package/dist/{resolve-users-C3NP2c-Q.js → resolve-users-aL6-Ssee.js} +11 -6
- package/dist/{runtime-BOk7xkOl.js → runtime-CauEvswP.js} +1 -1
- package/dist/{runtime-api-CEmqYxR-.js → runtime-api-CVb6CQjX.js} +3 -3
- package/dist/runtime-api.js +11 -11
- package/dist/runtime-setter-api.js +1 -1
- package/dist/{scopes-DCWVD5-8.js → scopes-Dw8wbU0j.js} +2 -2
- package/dist/{secret-contract-C3ChHo5A.js → secret-contract-CMohXFWS.js} +18 -113
- package/dist/secret-contract-api.js +1 -1
- package/dist/{send-DKDXoeoV.js → send-NEfJ0GvM.js} +662 -325
- package/dist/{send.runtime-GPRa63l1.js → send.runtime-BkKpitPu.js} +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-Dv2fIJNB.js → setup-surface-BN2WeG5c.js} +3 -3
- package/dist/{shared-CosfcFri.js → shared-BLnB9R1T.js} +7 -5
- package/dist/{slash-dispatch.runtime-CcMbbT3_.js → slash-dispatch.runtime-C0Otuf_T.js} +1 -1
- package/dist/{streaming-compat-DjlgH-Be.js → streaming-compat-3_X-21wW.js} +1 -0
- package/dist/{target-parsing-3jYH8LfB.js → target-parsing-N6lHogYZ.js} +16 -3
- package/dist/{targets-Dll4NJgs.js → targets-KmjP2E8s.js} +1 -1
- package/node_modules/p-map/index.d.ts +155 -0
- package/node_modules/p-map/index.js +284 -0
- package/node_modules/p-map/license +9 -0
- package/node_modules/p-map/package.json +57 -0
- package/node_modules/p-map/readme.md +190 -0
- package/npm-shrinkwrap.json +16 -3
- package/openclaw.plugin.json +16 -0
- package/package.json +6 -4
- package/dist/accounts.runtime-DWvaCb-X.js +0 -2
- package/dist/action-runtime.runtime-BABj3aM-.js +0 -2
- package/dist/config-api-DnT9ohtE.js +0 -2
- package/dist/format-YCNoNkM2.js +0 -107
- package/dist/outbound-adapter-DVoBfBW5.js +0 -272
- package/dist/replies-DpF38e1y.js +0 -287
- package/dist/reply-blocks-BGQ6zSqM.js +0 -877
- package/dist/resolve-allowlist-common-CP8SH0Zf.js +0 -43
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as slackContextTargetsMatch } from "./targets-
|
|
3
|
-
import {
|
|
4
|
-
import { a as readPositiveIntegerParam, c as withNormalizedTimestamp, n as imageResultFromFile, o as readReactionParams, r as jsonResult, s as readStringParam, t as createActionGate } from "./runtime-api-
|
|
5
|
-
import { n as resolveSlackChannelConfig, t as isSlackChannelAllowedByPolicy } from "./policy-
|
|
1
|
+
import { a as resolveSlackChannelId, i as parseSlackTarget } from "./target-parsing-N6lHogYZ.js";
|
|
2
|
+
import { t as slackContextTargetsMatch } from "./targets-KmjP2E8s.js";
|
|
3
|
+
import { C as hasSlackNativeDataBlock, X as parseSlackBlocksInput } from "./group-policy-C-b2ZnSl.js";
|
|
4
|
+
import { a as readPositiveIntegerParam, c as withNormalizedTimestamp, n as imageResultFromFile, o as readReactionParams, r as jsonResult, s as readStringParam, t as createActionGate } from "./runtime-api-CVb6CQjX.js";
|
|
5
|
+
import { n as resolveSlackChannelConfig, t as isSlackChannelAllowedByPolicy } from "./policy-f8b0edSi.js";
|
|
6
|
+
import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
|
|
7
|
+
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
6
8
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
7
9
|
import { isSingleUseReplyToMode } from "openclaw/plugin-sdk/reply-reference";
|
|
8
10
|
import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param";
|
|
@@ -22,8 +24,9 @@ const pinActions = /* @__PURE__ */ new Set([
|
|
|
22
24
|
"unpinMessage",
|
|
23
25
|
"listPins"
|
|
24
26
|
]);
|
|
25
|
-
const loadSlackActionsRuntime = createLazyRuntimeModule(() => import("./actions.runtime-
|
|
26
|
-
const loadSlackAccountsRuntime = createLazyRuntimeModule(() => import("./accounts.runtime-
|
|
27
|
+
const loadSlackActionsRuntime = createLazyRuntimeModule(() => import("./actions.runtime-BSxpwgUc.js"));
|
|
28
|
+
const loadSlackAccountsRuntime = createLazyRuntimeModule(() => import("./accounts.runtime-KvftRRek.js"));
|
|
29
|
+
const loadSlackChannelTypeRuntime = createLazyRuntimeModule(() => import("./channel-type-BpeTezY4.js").then((n) => n.t));
|
|
27
30
|
function createLazySlackAction(key) {
|
|
28
31
|
return (async (...args) => {
|
|
29
32
|
const action = (await loadSlackActionsRuntime())[key];
|
|
@@ -45,6 +48,8 @@ const slackActionRuntime = {
|
|
|
45
48
|
removeOwnSlackReactions: createLazySlackAction("removeOwnSlackReactions"),
|
|
46
49
|
removeSlackReaction: createLazySlackAction("removeSlackReaction"),
|
|
47
50
|
resolveSlackConversationName: createLazySlackAction("resolveSlackConversationName"),
|
|
51
|
+
resolveSlackConversationInfo: async (params) => (await loadSlackChannelTypeRuntime()).resolveSlackConversationInfo(params),
|
|
52
|
+
resolveSlackChannelType: async (params) => (await loadSlackChannelTypeRuntime()).resolveSlackChannelType(params),
|
|
48
53
|
sendSlackMessage: createLazySlackAction("sendSlackMessage"),
|
|
49
54
|
unpinSlackMessage: createLazySlackAction("unpinSlackMessage")
|
|
50
55
|
};
|
|
@@ -75,7 +80,51 @@ function readSlackBlocksParam(params) {
|
|
|
75
80
|
function isImageContentType(value) {
|
|
76
81
|
return value?.trim().toLowerCase().startsWith("image/") === true;
|
|
77
82
|
}
|
|
78
|
-
function
|
|
83
|
+
function hasPotentialSlackNamedPolicy(params) {
|
|
84
|
+
if (params.allowNameMatching !== true) return false;
|
|
85
|
+
return Object.entries(params.channels ?? {}).some(([key, entry]) => {
|
|
86
|
+
if (entry == null || key === "*") return false;
|
|
87
|
+
const named = !/^(?:channel:)?[CDG][A-Z0-9]+$/i.test(key);
|
|
88
|
+
const entryAllows = entry.enabled !== false;
|
|
89
|
+
return named && (params.decision === "allow" ? entryAllows : !entryAllows);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function resolveSlackDmReadAllowed(account) {
|
|
93
|
+
const dmPolicy = account.config.dmPolicy ?? account.config.dm?.policy ?? "pairing";
|
|
94
|
+
return account.config.dm?.enabled !== false && dmPolicy !== "disabled";
|
|
95
|
+
}
|
|
96
|
+
function normalizeConfiguredSlackDmUserId(value) {
|
|
97
|
+
const target = parseSlackTarget(String(value), { defaultKind: "user" });
|
|
98
|
+
if (target?.kind !== "user") return;
|
|
99
|
+
const userId = target.id.trim().toLowerCase();
|
|
100
|
+
return /^[uw][a-z0-9]+$/i.test(userId) ? userId : void 0;
|
|
101
|
+
}
|
|
102
|
+
async function isSlackDmTargetConfigured(params) {
|
|
103
|
+
const defaultTo = params.account.config.defaultTo?.trim();
|
|
104
|
+
if (defaultTo && slackContextTargetsMatch(params.channelId, { currentChannelId: defaultTo })) return true;
|
|
105
|
+
const userId = normalizeConfiguredSlackDmUserId(params.userId);
|
|
106
|
+
if (!userId) return false;
|
|
107
|
+
const { resolveSlackAccountAllowFrom } = await loadSlackAccountsRuntime();
|
|
108
|
+
return [
|
|
109
|
+
...resolveSlackAccountAllowFrom({
|
|
110
|
+
cfg: params.cfg,
|
|
111
|
+
accountId: params.account.accountId
|
|
112
|
+
}) ?? [],
|
|
113
|
+
...Object.keys(params.account.config.dms ?? {}),
|
|
114
|
+
...defaultTo ? [defaultTo] : []
|
|
115
|
+
].some((entry) => normalizeConfiguredSlackDmUserId(entry) === userId);
|
|
116
|
+
}
|
|
117
|
+
function isCurrentSlackReadTarget(params) {
|
|
118
|
+
const requesterAccountId = params.context?.requesterAccountId?.trim();
|
|
119
|
+
return Boolean(normalizeOptionalLowercaseString(params.context?.currentChannelProvider) === "slack" && requesterAccountId && normalizeAccountId(requesterAccountId) === normalizeAccountId(params.account.accountId) && params.context && slackContextTargetsMatch(params.channelId, params.context));
|
|
120
|
+
}
|
|
121
|
+
function assertSlackMemberInfoAllowed(params) {
|
|
122
|
+
if (params.context?.conversationReadOrigin === "direct-operator") return;
|
|
123
|
+
const requesterAccountId = params.context?.requesterAccountId?.trim();
|
|
124
|
+
const requesterSenderId = normalizeOptionalLowercaseString(params.context?.requesterSenderId);
|
|
125
|
+
if (normalizeOptionalLowercaseString(params.context?.currentChannelProvider) !== "slack" || !requesterAccountId || normalizeAccountId(requesterAccountId) !== normalizeAccountId(params.account.accountId) || !requesterSenderId || requesterSenderId !== normalizeOptionalLowercaseString(params.userId)) throw new Error("Delegated Slack member info is limited to the current requester.");
|
|
126
|
+
}
|
|
127
|
+
function resolveSlackChannelReadPolicy(params) {
|
|
79
128
|
const channels = params.account.config.channels;
|
|
80
129
|
const channelKeys = Object.keys(channels ?? {});
|
|
81
130
|
const channelConfig = resolveSlackChannelConfig({
|
|
@@ -87,29 +136,103 @@ function resolveSlackReadTargetDecision(params) {
|
|
|
87
136
|
defaultRequireMention: params.account.config.requireMention
|
|
88
137
|
});
|
|
89
138
|
const channelAllowed = channelConfig?.allowed !== false;
|
|
139
|
+
const channelExplicitlyDisabled = !channelAllowed && channelConfig?.matchSource === "direct";
|
|
140
|
+
const channelWildcardDisabled = !channelAllowed && channelConfig?.matchSource === "wildcard";
|
|
90
141
|
const { groupPolicy } = resolveOpenProviderRuntimeGroupPolicy({
|
|
91
142
|
providerConfigPresent: params.cfg.channels?.slack !== void 0,
|
|
92
143
|
groupPolicy: params.account.config.groupPolicy,
|
|
93
144
|
defaultGroupPolicy: params.cfg.channels?.defaults?.groupPolicy
|
|
94
145
|
});
|
|
95
|
-
|
|
146
|
+
const delegatedChannelAllowed = isSlackChannelAllowedByPolicy({
|
|
96
147
|
groupPolicy,
|
|
97
148
|
channelAllowlistConfigured: channelKeys.length > 0,
|
|
98
149
|
channelAllowed
|
|
99
|
-
})
|
|
100
|
-
|
|
150
|
+
}) && !(!channelAllowed && (groupPolicy !== "open" || channelConfig?.matchSource));
|
|
151
|
+
const directChannelAllowed = groupPolicy !== "disabled" && !channelExplicitlyDisabled && !channelWildcardDisabled;
|
|
152
|
+
const baseChannelAllowed = params.conversationReadOrigin === "direct-operator" || params.currentConversation ? directChannelAllowed : delegatedChannelAllowed;
|
|
153
|
+
const allowNameMatching = params.account.config.dangerouslyAllowNameMatching;
|
|
154
|
+
const shouldResolveName = !params.metadataResolved && !params.channelName && (baseChannelAllowed && channelConfig?.matchSource !== "direct" && hasPotentialSlackNamedPolicy({
|
|
155
|
+
channels,
|
|
156
|
+
allowNameMatching,
|
|
157
|
+
decision: "deny"
|
|
158
|
+
}) || !baseChannelAllowed && groupPolicy !== "disabled" && !channelExplicitlyDisabled && hasPotentialSlackNamedPolicy({
|
|
159
|
+
channels,
|
|
160
|
+
allowNameMatching,
|
|
161
|
+
decision: "allow"
|
|
162
|
+
}));
|
|
163
|
+
return {
|
|
164
|
+
channelAllowed: baseChannelAllowed,
|
|
165
|
+
channelExplicitlyDisabled,
|
|
166
|
+
groupDmAllowed: params.account.config.dm?.enabled !== false && params.account.config.dm?.groupEnabled === true && (params.currentConversation || isSlackGroupDmTargetConfigured(params.account, params.channelId)),
|
|
167
|
+
shouldResolveName
|
|
168
|
+
};
|
|
101
169
|
}
|
|
102
170
|
async function assertSlackReadTargetAllowed(params) {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
171
|
+
const deny = () => {
|
|
172
|
+
throw new Error("Slack read target channel is not allowed.");
|
|
173
|
+
};
|
|
174
|
+
const currentConversation = isCurrentSlackReadTarget({
|
|
175
|
+
account: params.account,
|
|
176
|
+
channelId: params.channelId,
|
|
177
|
+
context: params.context
|
|
178
|
+
});
|
|
179
|
+
const directOperator = params.conversationReadOrigin === "direct-operator";
|
|
180
|
+
if (/^D/i.test(params.channelId)) {
|
|
181
|
+
if (!resolveSlackDmReadAllowed(params.account)) deny();
|
|
182
|
+
if (directOperator || currentConversation) return;
|
|
183
|
+
const info = await slackActionRuntime.resolveSlackConversationInfo({
|
|
184
|
+
cfg: params.cfg,
|
|
185
|
+
accountId: params.account.accountId,
|
|
186
|
+
channelId: params.channelId,
|
|
187
|
+
operation: "read"
|
|
188
|
+
});
|
|
189
|
+
if (info.type !== "dm" || !await isSlackDmTargetConfigured({
|
|
190
|
+
...params,
|
|
191
|
+
userId: info.user
|
|
192
|
+
})) deny();
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const preliminary = resolveSlackChannelReadPolicy({
|
|
196
|
+
...params,
|
|
197
|
+
currentConversation
|
|
198
|
+
});
|
|
199
|
+
if (preliminary.channelExplicitlyDisabled) deny();
|
|
200
|
+
if (!(preliminary.shouldResolveName || preliminary.channelAllowed !== preliminary.groupDmAllowed)) {
|
|
201
|
+
if (!preliminary.channelAllowed) deny();
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const info = await slackActionRuntime.resolveSlackConversationInfo({
|
|
205
|
+
cfg: params.cfg,
|
|
206
|
+
accountId: params.account.accountId,
|
|
207
|
+
channelId: params.channelId,
|
|
208
|
+
operation: "read",
|
|
209
|
+
...preliminary.shouldResolveName ? { requireFreshName: true } : {}
|
|
210
|
+
});
|
|
211
|
+
if (preliminary.shouldResolveName && (info.type === "channel" || info.type === "unknown") && !info.name) deny();
|
|
212
|
+
const resolved = resolveSlackChannelReadPolicy({
|
|
213
|
+
...params,
|
|
214
|
+
channelName: info.name,
|
|
215
|
+
metadataResolved: true,
|
|
216
|
+
currentConversation
|
|
217
|
+
});
|
|
218
|
+
if (resolved.channelExplicitlyDisabled) deny();
|
|
219
|
+
if (info.type === "dm") {
|
|
220
|
+
if (!resolveSlackDmReadAllowed(params.account) || !directOperator && !currentConversation && !await isSlackDmTargetConfigured({
|
|
108
221
|
...params,
|
|
109
|
-
|
|
110
|
-
})
|
|
222
|
+
userId: info.user
|
|
223
|
+
})) deny();
|
|
224
|
+
return;
|
|
111
225
|
}
|
|
112
|
-
|
|
226
|
+
if (!(info.type === "channel" ? resolved.channelAllowed : info.type === "group" ? resolved.groupDmAllowed : resolved.channelAllowed && resolved.groupDmAllowed)) deny();
|
|
227
|
+
}
|
|
228
|
+
function isSlackGroupDmTargetConfigured(account, channelId) {
|
|
229
|
+
const entries = account.config.dm?.groupChannels ?? [];
|
|
230
|
+
if (entries.length === 0) return true;
|
|
231
|
+
const target = channelId.trim().toLowerCase();
|
|
232
|
+
return entries.some((entry) => {
|
|
233
|
+
const candidate = String(entry).trim().toLowerCase();
|
|
234
|
+
return candidate === "*" || candidate === target || candidate === `slack:${target}` || candidate === `channel:${target}` || candidate === `group:${target}` || candidate === `mpim:${target}`;
|
|
235
|
+
});
|
|
113
236
|
}
|
|
114
237
|
async function handleSlackAction(params, cfg, context) {
|
|
115
238
|
const resolveChannelId = () => resolveSlackChannelId(readStringParam(params, "channelId", { required: true }));
|
|
@@ -120,6 +243,7 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
120
243
|
cfg,
|
|
121
244
|
accountId
|
|
122
245
|
});
|
|
246
|
+
if (account.config.enterpriseOrgInstall === true) throw new Error("Slack action tools are unavailable for Enterprise Grid org installs.");
|
|
123
247
|
const isActionEnabled = createActionGate(account.actions ?? cfg.channels?.slack?.actions);
|
|
124
248
|
const userToken = account.userToken;
|
|
125
249
|
const botToken = account.botToken?.trim();
|
|
@@ -144,7 +268,8 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
144
268
|
account,
|
|
145
269
|
cfg,
|
|
146
270
|
channelId,
|
|
147
|
-
|
|
271
|
+
conversationReadOrigin: context?.conversationReadOrigin,
|
|
272
|
+
context
|
|
148
273
|
});
|
|
149
274
|
if (reactionsActions.has(action)) {
|
|
150
275
|
if (!isActionEnabled("reactions")) throw new Error("Slack reactions are disabled.");
|
|
@@ -152,6 +277,7 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
152
277
|
const messageId = readStringParam(params, "messageId", { required: true });
|
|
153
278
|
if (action === "react") {
|
|
154
279
|
const { emoji, remove, isEmpty } = readReactionParams(params, { removeErrorMessage: "Emoji is required to remove a Slack reaction." });
|
|
280
|
+
await assertReadTargetAllowed(channelId);
|
|
155
281
|
if (remove) {
|
|
156
282
|
if (writeOpts) await slackActionRuntime.removeSlackReaction(channelId, messageId, emoji, writeOpts);
|
|
157
283
|
else await slackActionRuntime.removeSlackReaction(channelId, messageId, emoji);
|
|
@@ -186,25 +312,66 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
186
312
|
const mediaUrl = readStringParam(params, "mediaUrl");
|
|
187
313
|
const blocks = readSlackBlocksParam(params);
|
|
188
314
|
const replyBroadcast = readBooleanParam(params, "replyBroadcast");
|
|
189
|
-
|
|
315
|
+
const textIsSlackMrkdwn = readBooleanParam(params, "textIsSlackMrkdwn");
|
|
316
|
+
const textIsSlackPlainText = readBooleanParam(params, "textIsSlackPlainText");
|
|
317
|
+
const preparedMessages = context?.preparedMessages;
|
|
318
|
+
const authoredTextPlacement = readStringParam(params, "authoredTextPlacement");
|
|
319
|
+
if (authoredTextPlacement && authoredTextPlacement !== "none" && authoredTextPlacement !== "blocks" && authoredTextPlacement !== "outside-blocks") throw new Error("Slack authoredTextPlacement is invalid.");
|
|
320
|
+
const nativeDataFallbackBaseText = readStringParam(params, "nativeDataFallbackBaseText", { allowEmpty: true });
|
|
321
|
+
if (!content && !mediaUrl && !blocks && !preparedMessages?.length) throw new Error("Slack sendMessage requires content, blocks, or mediaUrl.");
|
|
190
322
|
if (replyBroadcast && mediaUrl) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
|
|
191
323
|
const threadTs = resolveThreadTsFromContext(readStringParam(params, "threadTs"), to, context, { suppressImplicitThread: params.topLevel === true || params.threadTs === null });
|
|
192
|
-
const
|
|
324
|
+
const baseSendOpts = {
|
|
193
325
|
...writeOpts,
|
|
194
326
|
mediaLocalRoots: context?.mediaLocalRoots,
|
|
195
327
|
mediaReadFile: context?.mediaReadFile,
|
|
196
|
-
threadTs: threadTs ?? void 0
|
|
197
|
-
|
|
328
|
+
threadTs: threadTs ?? void 0
|
|
329
|
+
};
|
|
330
|
+
const sendOpts = {
|
|
331
|
+
...baseSendOpts,
|
|
332
|
+
...replyBroadcast ? { replyBroadcast } : {},
|
|
333
|
+
...textIsSlackMrkdwn ? { textIsSlackMrkdwn: true } : {},
|
|
334
|
+
...textIsSlackPlainText ? { textIsSlackPlainText: true } : {},
|
|
335
|
+
...authoredTextPlacement ? { authoredTextPlacement } : {},
|
|
336
|
+
...nativeDataFallbackBaseText !== void 0 ? { nativeDataFallbackBaseText } : {}
|
|
198
337
|
};
|
|
199
|
-
const
|
|
200
|
-
|
|
338
|
+
const sendContentAndBlocks = async () => {
|
|
339
|
+
const shouldSplitLongContent = content && content.length > 8e3 && !hasSlackNativeDataBlock(blocks);
|
|
340
|
+
if (content && shouldSplitLongContent) {
|
|
341
|
+
const { replyBroadcast: _replyBroadcast, ...blockSendOpts } = sendOpts;
|
|
342
|
+
await slackActionRuntime.sendSlackMessage(to, "", {
|
|
343
|
+
...blockSendOpts,
|
|
344
|
+
blocks
|
|
345
|
+
});
|
|
346
|
+
return await slackActionRuntime.sendSlackMessage(to, content, sendOpts);
|
|
347
|
+
}
|
|
348
|
+
return await slackActionRuntime.sendSlackMessage(to, content ?? "", {
|
|
201
349
|
...sendOpts,
|
|
350
|
+
blocks
|
|
351
|
+
});
|
|
352
|
+
};
|
|
353
|
+
const result = preparedMessages?.length ? await (async () => {
|
|
354
|
+
let lastResult;
|
|
355
|
+
if (mediaUrl) lastResult = await slackActionRuntime.sendSlackMessage(to, "", {
|
|
356
|
+
...baseSendOpts,
|
|
202
357
|
mediaUrl
|
|
203
358
|
});
|
|
204
|
-
|
|
359
|
+
for (const [index, message] of preparedMessages.entries()) lastResult = await slackActionRuntime.sendSlackMessage(to, message.text, {
|
|
360
|
+
...baseSendOpts,
|
|
361
|
+
...index === 0 && replyBroadcast ? { replyBroadcast: true } : {},
|
|
362
|
+
...message.blocks ? { blocks: message.blocks } : {},
|
|
363
|
+
...message.authoredTextPlacement ? { authoredTextPlacement: message.authoredTextPlacement } : {},
|
|
364
|
+
...Object.hasOwn(message, "nativeDataFallbackBaseText") ? { nativeDataFallbackBaseText: message.nativeDataFallbackBaseText } : {},
|
|
365
|
+
...message.textIsSlackPlainText ? { textIsSlackPlainText: true } : {}
|
|
366
|
+
});
|
|
367
|
+
if (!lastResult) throw new Error("Slack prepared message plan produced no delivery.");
|
|
368
|
+
return lastResult;
|
|
369
|
+
})() : blocks ? await (async () => {
|
|
370
|
+
if (mediaUrl) await slackActionRuntime.sendSlackMessage(to, "", {
|
|
205
371
|
...sendOpts,
|
|
206
|
-
|
|
372
|
+
mediaUrl
|
|
207
373
|
});
|
|
374
|
+
return await sendContentAndBlocks();
|
|
208
375
|
})() : await slackActionRuntime.sendSlackMessage(to, content ?? "", {
|
|
209
376
|
...sendOpts,
|
|
210
377
|
mediaUrl: mediaUrl ?? void 0,
|
|
@@ -248,6 +415,7 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
248
415
|
const content = readStringParam(params, "content", { allowEmpty: true });
|
|
249
416
|
const blocks = readSlackBlocksParam(params);
|
|
250
417
|
if (!content && !blocks) throw new Error("Slack editMessage requires content or blocks.");
|
|
418
|
+
await assertReadTargetAllowed(channelId);
|
|
251
419
|
if (writeOpts) await slackActionRuntime.editSlackMessage(channelId, messageId, content ?? "", {
|
|
252
420
|
...writeOpts,
|
|
253
421
|
blocks
|
|
@@ -258,6 +426,7 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
258
426
|
case "deleteMessage": {
|
|
259
427
|
const channelId = resolveChannelId();
|
|
260
428
|
const messageId = readStringParam(params, "messageId", { required: true });
|
|
429
|
+
await assertReadTargetAllowed(channelId);
|
|
261
430
|
if (writeOpts) await slackActionRuntime.deleteSlackMessage(channelId, messageId, writeOpts);
|
|
262
431
|
else await slackActionRuntime.deleteSlackMessage(channelId, messageId);
|
|
263
432
|
return jsonResult({ ok: true });
|
|
@@ -336,12 +505,14 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
336
505
|
const channelId = resolveChannelId();
|
|
337
506
|
if (action === "pinMessage") {
|
|
338
507
|
const messageId = readStringParam(params, "messageId", { required: true });
|
|
508
|
+
await assertReadTargetAllowed(channelId);
|
|
339
509
|
if (writeOpts) await slackActionRuntime.pinSlackMessage(channelId, messageId, writeOpts);
|
|
340
510
|
else await slackActionRuntime.pinSlackMessage(channelId, messageId);
|
|
341
511
|
return jsonResult({ ok: true });
|
|
342
512
|
}
|
|
343
513
|
if (action === "unpinMessage") {
|
|
344
514
|
const messageId = readStringParam(params, "messageId", { required: true });
|
|
515
|
+
await assertReadTargetAllowed(channelId);
|
|
345
516
|
if (writeOpts) await slackActionRuntime.unpinSlackMessage(channelId, messageId, writeOpts);
|
|
346
517
|
else await slackActionRuntime.unpinSlackMessage(channelId, messageId);
|
|
347
518
|
return jsonResult({ ok: true });
|
|
@@ -358,9 +529,14 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
358
529
|
if (action === "memberInfo") {
|
|
359
530
|
if (!isActionEnabled("memberInfo")) throw new Error("Slack member info is disabled.");
|
|
360
531
|
const userId = readStringParam(params, "userId", { required: true });
|
|
532
|
+
assertSlackMemberInfoAllowed({
|
|
533
|
+
account,
|
|
534
|
+
context,
|
|
535
|
+
userId
|
|
536
|
+
});
|
|
361
537
|
return jsonResult({
|
|
362
538
|
ok: true,
|
|
363
|
-
info:
|
|
539
|
+
info: readOpts ? await slackActionRuntime.getSlackMemberInfo(userId, readOpts) : await slackActionRuntime.getSlackMemberInfo(userId)
|
|
364
540
|
});
|
|
365
541
|
}
|
|
366
542
|
if (action === "emojiList") {
|