@openclaw/slack 2026.7.2-beta.7 → 2026.8.1-beta.2
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/{account-inspect-DEKpg9Ip.js → account-inspect-Drw2gAiN.js} +1 -1
- package/dist/account-inspect-api.js +1 -1
- package/dist/{accounts-CHAeNZOX.js → accounts-CK4AVI2_.js} +2 -2
- package/dist/{accounts.runtime-BHD4Ma2R.js → accounts.runtime-Cb7QwWBz.js} +1 -1
- package/dist/{action-runtime-DfuYoMjG.js → action-runtime-BkGe7ny_.js} +148 -76
- package/dist/action-runtime.runtime-D9I6uc0Q.js +2 -0
- package/dist/{actions-D3NuJvva.js → actions-BTDXwwE3.js} +85 -44
- package/dist/actions.runtime-DLFyUkvg.js +2 -0
- package/dist/api.js +15 -15
- package/dist/{approval-handler.runtime-BA05P0QT.js → approval-handler.runtime-CJaNzAq2.js} +51 -14
- package/dist/{block-text-DkHaoGem.js → block-text-YtiNkqmx.js} +1 -1
- package/dist/{channel-B9fVdW3s.js → channel-D_tovcUL.js} +151 -91
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel-type-DXyos1d2.js → channel-type-B9MSdoGN.js} +9 -8
- package/dist/{config-adapter-CxBQH8fq.js → channel.setup-Bch9dYmA.js} +83 -25
- package/dist/{config-schema-SgZT6nXV.js → config-schema-xto5jFIx.js} +5 -11
- package/dist/{directory-config-CnCIAktf.js → directory-config-CNBz8lJa.js} +3 -3
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-DKunWh3A.js → directory-live-CFKUtW9E.js} +13 -22
- package/dist/{doctor-contract-CsGH1Dfc.js → doctor-contract-BAy7-EUQ.js} +30 -3
- package/dist/doctor-contract-api.js +1 -1
- package/dist/{group-policy-NQZti9t-.js → group-policy-c4RP9bjc.js} +248 -163
- package/dist/index.js +4 -1
- package/dist/{message-tool-api-DkhFpMoy.js → message-tool-api-BykQB4AU.js} +14 -3
- package/dist/message-tool-api.js +1 -1
- package/dist/{monitor-CmKz0wtI.js → monitor-1nF1NtqT.js} +3 -3
- package/dist/{outbound-adapter-BkuMp2Vs.js → outbound-adapter-S81tsswN.js} +19 -17
- package/dist/{pipeline.runtime-DgtmuYCP.js → pipeline.runtime-BvYsM5JO.js} +1087 -682
- package/dist/{policy-PRysPn23.js → policy-TapwbeaT.js} +18 -14
- package/dist/{probe-CgDsSops.js → probe-HoEg_WxB.js} +38 -18
- package/dist/{provider-DmRizMZt.js → provider-CDNvBXUi.js} +3422 -2590
- package/dist/{relay-source-Blxj8xb4.js → relay-source-C9leF11u.js} +11 -21
- package/dist/{replies-4s_Vq_z9.js → replies-CeOfv82I.js} +52 -6
- package/dist/{resolve-channels-yEqmM-3I.js → resolve-channels-CNPrxaXY.js} +39 -12
- package/dist/{resolve-users-BOrt5K-5.js → resolve-users-Dzomuwnr.js} +28 -5
- package/dist/{runtime-api-QMb-Q5Ko.js → runtime-api-Cj9nxBNv.js} +3 -3
- package/dist/runtime-api.js +11 -11
- package/dist/{scopes-BJSrkAp6.js → scopes-cYXKkrRD.js} +1 -1
- package/dist/{send-DsLeZpST.js → send-Nor0iBwY.js} +211 -105
- package/dist/{send.runtime-gUdK6V3h.js → send.runtime-BmgNe6S9.js} +1 -1
- package/dist/setup-entry.js +1 -4
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-BeNzrMrJ.js → setup-surface-CbX1-Knh.js} +6 -6
- package/dist/{shared-DgIN3Dcr.js → shared-zdT5AMp-.js} +36 -42
- package/dist/{slash-dispatch.runtime-zPkyl7dB.js → slash-dispatch.runtime-Bnr9GR1S.js} +1 -1
- package/dist/{streaming-compat-3_X-21wW.js → streaming-compat-B-e0mqM0.js} +3 -8
- package/dist/{target-parsing-N6lHogYZ.js → target-parsing-BnMD2ZqZ.js} +40 -2
- package/dist/{targets-KmjP2E8s.js → targets-Cx5W_n3W.js} +1 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/crypto.d.ts +1 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
- package/node_modules/@slack/socket-mode/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/socket-mode/node_modules/@types/node/crypto.d.ts +1 -1
- package/node_modules/@slack/socket-mode/node_modules/@types/node/package.json +2 -2
- package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/crypto.d.ts +1 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
- package/node_modules/undici/lib/cache/memory-cache-store.js +54 -9
- package/node_modules/undici/lib/cache/sqlite-cache-store.js +7 -1
- package/node_modules/undici/lib/core/request.js +12 -1
- package/node_modules/undici/lib/dispatcher/client-h1.js +11 -2
- package/node_modules/undici/lib/handler/cache-handler.js +246 -64
- package/node_modules/undici/lib/handler/cache-revalidation-handler.js +3 -3
- package/node_modules/undici/lib/handler/retry-handler.js +24 -0
- package/node_modules/undici/lib/interceptor/cache.js +159 -52
- package/node_modules/undici/lib/util/cache.js +324 -62
- package/node_modules/undici/lib/util/date.js +23 -6
- package/node_modules/undici/lib/web/cookies/util.js +79 -9
- package/node_modules/undici/package.json +1 -1
- package/openclaw.plugin.json +239 -34
- package/package.json +9 -9
- package/skills/slack/SKILL.md +10 -68
- package/dist/action-runtime.runtime-DQErZYpz.js +0 -2
- package/dist/actions.runtime-BIRU_G4M.js +0 -2
- package/dist/channel.setup-CLP5oTvh.js +0 -56
- package/dist/preflight-audio.runtime-D5Bgags0.js +0 -3
- package/dist/slash-plugin-commands.runtime-Dosfcx3X.js +0 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as resolveDefaultSlackAccountId, r as mergeSlackAccountConfig } from "./accounts-
|
|
1
|
+
import { i as resolveDefaultSlackAccountId, r as mergeSlackAccountConfig } from "./accounts-CK4AVI2_.js";
|
|
2
2
|
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
|
|
3
3
|
import { hasConfiguredSecretInput, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
4
4
|
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as inspectSlackAccount } from "./account-inspect-
|
|
1
|
+
import { t as inspectSlackAccount } from "./account-inspect-Drw2gAiN.js";
|
|
2
2
|
//#region extensions/slack/account-inspect-api.ts
|
|
3
3
|
function inspectSlackReadOnlyAccount(cfg, accountId) {
|
|
4
4
|
return inspectSlackAccount({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_ACCOUNT_ID, createAccountListHelpers, hasConfiguredAccountValue, normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
|
|
2
2
|
import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
3
|
-
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
|
+
import { asOptionalRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
4
|
import { mapAllowFromEntries, normalizeChannelDmPolicy } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
5
5
|
import { resolveAccountEntry } from "openclaw/plugin-sdk/routing";
|
|
6
6
|
//#region extensions/slack/src/token.ts
|
|
@@ -60,7 +60,7 @@ function resolveSlackAccountConfig(cfg, accountId) {
|
|
|
60
60
|
return resolveAccountEntry(cfg.channels?.slack?.accounts, accountId);
|
|
61
61
|
}
|
|
62
62
|
function asStreamingConfigObject(value) {
|
|
63
|
-
return
|
|
63
|
+
return asOptionalRecord(value);
|
|
64
64
|
}
|
|
65
65
|
function asLegacyStreamingScalar(value) {
|
|
66
66
|
return typeof value === "boolean" || typeof value === "string" ? value : void 0;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as resolveSlackAccount, l as resolveSlackOperationToken, o as resolveSlackAccountAllowFrom } from "./accounts-
|
|
1
|
+
import { a as resolveSlackAccount, l as resolveSlackOperationToken, o as resolveSlackAccountAllowFrom } from "./accounts-CK4AVI2_.js";
|
|
2
2
|
export { resolveSlackAccount, resolveSlackAccountAllowFrom, resolveSlackOperationToken };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { a as
|
|
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 parseSlackTarget, n as formatSlackTarget, o as resolveSlackChannelId } from "./target-parsing-BnMD2ZqZ.js";
|
|
2
|
+
import { t as slackContextTargetsMatch } from "./targets-Cx5W_n3W.js";
|
|
3
|
+
import { St as getSlackInstallationKind, T as hasSlackNativeDataBlock, lt as parseSlackBlocksInput, p as assertSlackDetachedTargetAllowed, t as buildSlackChannelIdCandidates } from "./group-policy-c4RP9bjc.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-Cj9nxBNv.js";
|
|
5
|
+
import { n as resolveSlackChannelConfig, t as isSlackChannelAllowedByPolicy } from "./policy-TapwbeaT.js";
|
|
6
6
|
import { normalizeAccountId } from "openclaw/plugin-sdk/account-resolution";
|
|
7
7
|
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
8
8
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
@@ -24,9 +24,10 @@ const pinActions = /* @__PURE__ */ new Set([
|
|
|
24
24
|
"unpinMessage",
|
|
25
25
|
"listPins"
|
|
26
26
|
]);
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const
|
|
27
|
+
const SLACK_REACTION_USER_LIMIT = 100;
|
|
28
|
+
const loadSlackActionsRuntime = createLazyRuntimeModule(() => import("./actions.runtime-DLFyUkvg.js"));
|
|
29
|
+
const loadSlackAccountsRuntime = createLazyRuntimeModule(() => import("./accounts.runtime-Cb7QwWBz.js"));
|
|
30
|
+
const loadSlackChannelTypeRuntime = createLazyRuntimeModule(() => import("./channel-type-B9MSdoGN.js").then((n) => n.t));
|
|
30
31
|
function createLazySlackAction(key) {
|
|
31
32
|
return (async (...args) => {
|
|
32
33
|
const action = (await loadSlackActionsRuntime())[key];
|
|
@@ -116,7 +117,7 @@ async function isSlackDmTargetConfigured(params) {
|
|
|
116
117
|
}
|
|
117
118
|
function isCurrentSlackReadTarget(params) {
|
|
118
119
|
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.
|
|
120
|
+
return Boolean(normalizeOptionalLowercaseString(params.context?.currentChannelProvider) === "slack" && requesterAccountId && normalizeAccountId(requesterAccountId) === normalizeAccountId(params.account.accountId) && params.context && slackContextTargetsMatch(params.target, params.context));
|
|
120
121
|
}
|
|
121
122
|
function assertSlackMemberInfoAllowed(params) {
|
|
122
123
|
if (params.context?.conversationReadOrigin === "direct-operator") return;
|
|
@@ -128,6 +129,8 @@ function resolveSlackChannelReadPolicy(params) {
|
|
|
128
129
|
const channels = params.account.config.channels;
|
|
129
130
|
const channelKeys = Object.keys(channels ?? {});
|
|
130
131
|
const channelConfig = resolveSlackChannelConfig({
|
|
132
|
+
teamId: params.teamId,
|
|
133
|
+
allowUnscoped: getSlackInstallationKind(params.account.accountId) !== "enterprise",
|
|
131
134
|
channelId: params.channelId,
|
|
132
135
|
channelName: params.channelName,
|
|
133
136
|
channels,
|
|
@@ -163,7 +166,7 @@ function resolveSlackChannelReadPolicy(params) {
|
|
|
163
166
|
return {
|
|
164
167
|
channelAllowed: baseChannelAllowed,
|
|
165
168
|
channelExplicitlyDisabled,
|
|
166
|
-
groupDmAllowed: params.account.config.dm?.enabled !== false && params.account.config.dm?.groupEnabled === true && (params.currentConversation || isSlackGroupDmTargetConfigured(params.account, params.channelId)),
|
|
169
|
+
groupDmAllowed: params.account.config.dm?.enabled !== false && params.account.config.dm?.groupEnabled === true && (params.currentConversation || isSlackGroupDmTargetConfigured(params.account, params.channelId, params.teamId)),
|
|
167
170
|
shouldResolveName
|
|
168
171
|
};
|
|
169
172
|
}
|
|
@@ -173,7 +176,11 @@ async function assertSlackReadTargetAllowed(params) {
|
|
|
173
176
|
};
|
|
174
177
|
const currentConversation = isCurrentSlackReadTarget({
|
|
175
178
|
account: params.account,
|
|
176
|
-
|
|
179
|
+
target: formatSlackTarget({
|
|
180
|
+
teamId: params.teamId,
|
|
181
|
+
kind: "channel",
|
|
182
|
+
id: params.channelId
|
|
183
|
+
}),
|
|
177
184
|
context: params.context
|
|
178
185
|
});
|
|
179
186
|
const directOperator = params.conversationReadOrigin === "direct-operator";
|
|
@@ -184,6 +191,7 @@ async function assertSlackReadTargetAllowed(params) {
|
|
|
184
191
|
cfg: params.cfg,
|
|
185
192
|
accountId: params.account.accountId,
|
|
186
193
|
channelId: params.channelId,
|
|
194
|
+
teamId: params.teamId,
|
|
187
195
|
operation: "read"
|
|
188
196
|
});
|
|
189
197
|
if (info.type !== "dm" || !await isSlackDmTargetConfigured({
|
|
@@ -205,6 +213,7 @@ async function assertSlackReadTargetAllowed(params) {
|
|
|
205
213
|
cfg: params.cfg,
|
|
206
214
|
accountId: params.account.accountId,
|
|
207
215
|
channelId: params.channelId,
|
|
216
|
+
teamId: params.teamId,
|
|
208
217
|
operation: "read",
|
|
209
218
|
...preliminary.shouldResolveName ? { requireFreshName: true } : {}
|
|
210
219
|
});
|
|
@@ -225,17 +234,53 @@ async function assertSlackReadTargetAllowed(params) {
|
|
|
225
234
|
}
|
|
226
235
|
if (!(info.type === "channel" ? resolved.channelAllowed : info.type === "group" ? resolved.groupDmAllowed : resolved.channelAllowed && resolved.groupDmAllowed)) deny();
|
|
227
236
|
}
|
|
228
|
-
function isSlackGroupDmTargetConfigured(account, channelId) {
|
|
237
|
+
function isSlackGroupDmTargetConfigured(account, channelId, teamId) {
|
|
229
238
|
const entries = account.config.dm?.groupChannels ?? [];
|
|
230
239
|
if (entries.length === 0) return true;
|
|
240
|
+
const candidates = new Set(buildSlackChannelIdCandidates(channelId, teamId, { allowUnscoped: getSlackInstallationKind(account.accountId) !== "enterprise" }).map((candidate) => candidate.toLowerCase()));
|
|
231
241
|
const target = channelId.trim().toLowerCase();
|
|
232
242
|
return entries.some((entry) => {
|
|
233
243
|
const candidate = String(entry).trim().toLowerCase();
|
|
234
|
-
return candidate === "*" || candidate === target || candidate === `slack:${target}` || candidate === `channel:${target}` || candidate === `group:${target}` || candidate === `mpim:${target}`;
|
|
244
|
+
return candidate === "*" || candidates.has(candidate) || candidate === target || candidate === `slack:${target}` || candidate === `channel:${target}` || candidate === `group:${target}` || candidate === `mpim:${target}`;
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
function resolveTrustedCurrentSlackTeamId(params) {
|
|
248
|
+
const requesterAccountId = params.context?.requesterAccountId?.trim();
|
|
249
|
+
if (normalizeOptionalLowercaseString(params.context?.currentChannelProvider) !== "slack" || !requesterAccountId || normalizeAccountId(requesterAccountId) !== normalizeAccountId(params.account.accountId)) return;
|
|
250
|
+
const matchingTeams = /* @__PURE__ */ new Map();
|
|
251
|
+
for (const raw of [params.context?.currentChannelId, params.context?.currentMessagingTarget]) {
|
|
252
|
+
if (!raw) continue;
|
|
253
|
+
const current = parseSlackTarget(raw);
|
|
254
|
+
if (current?.teamId && (!params.target || current.kind === params.target.kind && current.id.toLowerCase() === params.target.id.toLowerCase())) matchingTeams.set(current.teamId.toLowerCase(), current.teamId);
|
|
255
|
+
}
|
|
256
|
+
return matchingTeams.size === 1 ? matchingTeams.values().next().value : void 0;
|
|
257
|
+
}
|
|
258
|
+
function resolveSlackActionTarget(account, raw, context) {
|
|
259
|
+
const parsed = parseSlackTarget(raw, { defaultKind: "channel" });
|
|
260
|
+
if (!parsed) throw new Error("Slack target is required.");
|
|
261
|
+
const teamId = parsed.teamId ?? resolveTrustedCurrentSlackTeamId({
|
|
262
|
+
account,
|
|
263
|
+
target: parsed,
|
|
264
|
+
context
|
|
235
265
|
});
|
|
266
|
+
assertSlackDetachedTargetAllowed(account.accountId, teamId);
|
|
267
|
+
return {
|
|
268
|
+
routingTarget: teamId ? formatSlackTarget({
|
|
269
|
+
teamId,
|
|
270
|
+
kind: parsed.kind,
|
|
271
|
+
id: parsed.id
|
|
272
|
+
}) : raw,
|
|
273
|
+
teamId
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
function resolveSlackActionChannelTarget(account, raw, context) {
|
|
277
|
+
const resolved = resolveSlackActionTarget(account, raw, context);
|
|
278
|
+
return {
|
|
279
|
+
channelId: resolveSlackChannelId(raw),
|
|
280
|
+
teamId: resolved.teamId
|
|
281
|
+
};
|
|
236
282
|
}
|
|
237
283
|
async function handleSlackAction(params, cfg, context) {
|
|
238
|
-
const resolveChannelId = () => resolveSlackChannelId(readStringParam(params, "channelId", { required: true }));
|
|
239
284
|
const action = readStringParam(params, "action", { required: true });
|
|
240
285
|
const accountId = readStringParam(params, "accountId");
|
|
241
286
|
const { resolveSlackAccount, resolveSlackOperationToken } = await loadSlackAccountsRuntime();
|
|
@@ -243,38 +288,42 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
243
288
|
cfg,
|
|
244
289
|
accountId
|
|
245
290
|
});
|
|
246
|
-
|
|
291
|
+
const resolveChannelTarget = () => resolveSlackActionChannelTarget(account, readStringParam(params, "channelId", { required: true }), context);
|
|
247
292
|
const isActionEnabled = createActionGate(account.actions ?? cfg.channels?.slack?.actions);
|
|
248
293
|
const botToken = account.botToken?.trim();
|
|
249
|
-
const buildActionOpts = (operation) => {
|
|
294
|
+
const buildActionOpts = (operation, teamId) => {
|
|
250
295
|
const token = resolveSlackOperationToken(account, operation);
|
|
251
296
|
if (!token && account.identity === "user") throw new Error(`Slack operation token missing for account "${account.accountId}".`);
|
|
252
297
|
const tokenOverride = token && token !== botToken ? token : void 0;
|
|
253
298
|
return {
|
|
254
299
|
cfg,
|
|
255
300
|
...accountId ? { accountId } : {},
|
|
256
|
-
...tokenOverride ? { token: tokenOverride } : {}
|
|
301
|
+
...tokenOverride ? { token: tokenOverride } : {},
|
|
302
|
+
teamId
|
|
257
303
|
};
|
|
258
304
|
};
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
305
|
+
const assertReadTargetAllowed = async (target) => {
|
|
306
|
+
await assertSlackReadTargetAllowed({
|
|
307
|
+
account,
|
|
308
|
+
cfg,
|
|
309
|
+
channelId: target.channelId,
|
|
310
|
+
teamId: target.teamId,
|
|
311
|
+
conversationReadOrigin: context?.conversationReadOrigin,
|
|
312
|
+
context
|
|
313
|
+
});
|
|
314
|
+
};
|
|
268
315
|
if (reactionsActions.has(action)) {
|
|
269
316
|
if (!isActionEnabled("reactions")) throw new Error("Slack reactions are disabled.");
|
|
270
|
-
const
|
|
317
|
+
const target = resolveChannelTarget();
|
|
318
|
+
const { channelId } = target;
|
|
319
|
+
const readOpts = buildActionOpts("read", target.teamId);
|
|
320
|
+
const writeOpts = buildActionOpts("write", target.teamId);
|
|
271
321
|
const messageId = readStringParam(params, "messageId", { required: true });
|
|
272
322
|
if (action === "react") {
|
|
273
323
|
const { emoji, remove, isEmpty } = readReactionParams(params, { removeErrorMessage: "Emoji is required to remove a Slack reaction." });
|
|
274
|
-
await assertReadTargetAllowed(
|
|
324
|
+
await assertReadTargetAllowed(target);
|
|
275
325
|
if (remove) {
|
|
276
|
-
|
|
277
|
-
else await slackActionRuntime.removeSlackReaction(channelId, messageId, emoji);
|
|
326
|
+
await slackActionRuntime.removeSlackReaction(channelId, messageId, emoji, writeOpts);
|
|
278
327
|
return jsonResult({
|
|
279
328
|
ok: true,
|
|
280
329
|
removed: emoji
|
|
@@ -282,44 +331,47 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
282
331
|
}
|
|
283
332
|
if (isEmpty) return jsonResult({
|
|
284
333
|
ok: true,
|
|
285
|
-
removed:
|
|
334
|
+
removed: await slackActionRuntime.removeOwnSlackReactions(channelId, messageId, writeOpts)
|
|
286
335
|
});
|
|
287
|
-
|
|
288
|
-
else await slackActionRuntime.reactSlackMessage(channelId, messageId, emoji);
|
|
336
|
+
await slackActionRuntime.reactSlackMessage(channelId, messageId, emoji, writeOpts);
|
|
289
337
|
return jsonResult({
|
|
290
338
|
ok: true,
|
|
291
339
|
added: emoji
|
|
292
340
|
});
|
|
293
341
|
}
|
|
294
|
-
await assertReadTargetAllowed(
|
|
342
|
+
await assertReadTargetAllowed(target);
|
|
343
|
+
const limit = Math.min(readPositiveIntegerParam(params, "limit", { message: "limit must be a positive integer." }) ?? SLACK_REACTION_USER_LIMIT, SLACK_REACTION_USER_LIMIT);
|
|
295
344
|
return jsonResult({
|
|
296
345
|
ok: true,
|
|
297
|
-
reactions:
|
|
346
|
+
reactions: (await slackActionRuntime.listSlackReactions(channelId, messageId, readOpts))?.map((reaction) => reaction.users ? Object.assign({}, reaction, { users: reaction.users.slice(0, limit) }) : reaction)
|
|
298
347
|
});
|
|
299
348
|
}
|
|
300
349
|
if (messagingActions.has(action)) {
|
|
301
350
|
if (!isActionEnabled("messages")) throw new Error("Slack messages are disabled.");
|
|
302
351
|
switch (action) {
|
|
303
352
|
case "sendMessage": {
|
|
304
|
-
const
|
|
353
|
+
const destination = resolveSlackActionTarget(account, readStringParam(params, "to", { required: true }), context).routingTarget;
|
|
305
354
|
const content = readStringParam(params, "content", { allowEmpty: true });
|
|
306
355
|
const mediaUrl = readStringParam(params, "mediaUrl");
|
|
307
356
|
const blocks = readSlackBlocksParam(params);
|
|
308
357
|
const replyBroadcast = readBooleanParam(params, "replyBroadcast");
|
|
309
358
|
const textIsSlackMrkdwn = readBooleanParam(params, "textIsSlackMrkdwn");
|
|
310
359
|
const textIsSlackPlainText = readBooleanParam(params, "textIsSlackPlainText");
|
|
360
|
+
const forceDocument = readBooleanParam(params, "forceDocument") === true;
|
|
311
361
|
const preparedMessages = context?.preparedMessages;
|
|
312
362
|
const authoredTextPlacement = readStringParam(params, "authoredTextPlacement");
|
|
313
363
|
if (authoredTextPlacement && authoredTextPlacement !== "none" && authoredTextPlacement !== "blocks" && authoredTextPlacement !== "outside-blocks") throw new Error("Slack authoredTextPlacement is invalid.");
|
|
314
364
|
const nativeDataFallbackBaseText = readStringParam(params, "nativeDataFallbackBaseText", { allowEmpty: true });
|
|
315
365
|
if (!content && !mediaUrl && !blocks && !preparedMessages?.length) throw new Error("Slack sendMessage requires content, blocks, or mediaUrl.");
|
|
316
366
|
if (replyBroadcast && mediaUrl) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
|
|
317
|
-
const threadTs = resolveThreadTsFromContext(readStringParam(params, "threadTs"),
|
|
367
|
+
const threadTs = resolveThreadTsFromContext(readStringParam(params, "threadTs"), destination, context, { suppressImplicitThread: params.topLevel === true || params.threadTs === null });
|
|
318
368
|
const baseSendOpts = {
|
|
319
|
-
...
|
|
369
|
+
...buildActionOpts("write"),
|
|
370
|
+
mediaAccess: context?.mediaAccess,
|
|
320
371
|
mediaLocalRoots: context?.mediaLocalRoots,
|
|
321
372
|
mediaReadFile: context?.mediaReadFile,
|
|
322
|
-
threadTs: threadTs ?? void 0
|
|
373
|
+
threadTs: threadTs ?? void 0,
|
|
374
|
+
...forceDocument ? { forceDocument: true } : {}
|
|
323
375
|
};
|
|
324
376
|
const sendOpts = {
|
|
325
377
|
...baseSendOpts,
|
|
@@ -333,24 +385,24 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
333
385
|
const shouldSplitLongContent = content && content.length > 8e3 && !hasSlackNativeDataBlock(blocks);
|
|
334
386
|
if (content && shouldSplitLongContent) {
|
|
335
387
|
const { replyBroadcast: _replyBroadcast, ...blockSendOpts } = sendOpts;
|
|
336
|
-
await slackActionRuntime.sendSlackMessage(
|
|
388
|
+
await slackActionRuntime.sendSlackMessage(destination, "", {
|
|
337
389
|
...blockSendOpts,
|
|
338
390
|
blocks
|
|
339
391
|
});
|
|
340
|
-
return await slackActionRuntime.sendSlackMessage(
|
|
392
|
+
return await slackActionRuntime.sendSlackMessage(destination, content, sendOpts);
|
|
341
393
|
}
|
|
342
|
-
return await slackActionRuntime.sendSlackMessage(
|
|
394
|
+
return await slackActionRuntime.sendSlackMessage(destination, content ?? "", {
|
|
343
395
|
...sendOpts,
|
|
344
396
|
blocks
|
|
345
397
|
});
|
|
346
398
|
};
|
|
347
399
|
const result = preparedMessages?.length ? await (async () => {
|
|
348
400
|
let lastResult;
|
|
349
|
-
if (mediaUrl) lastResult = await slackActionRuntime.sendSlackMessage(
|
|
401
|
+
if (mediaUrl) lastResult = await slackActionRuntime.sendSlackMessage(destination, "", {
|
|
350
402
|
...baseSendOpts,
|
|
351
403
|
mediaUrl
|
|
352
404
|
});
|
|
353
|
-
for (const [index, message] of preparedMessages.entries()) lastResult = await slackActionRuntime.sendSlackMessage(
|
|
405
|
+
for (const [index, message] of preparedMessages.entries()) lastResult = await slackActionRuntime.sendSlackMessage(destination, message.text, {
|
|
354
406
|
...baseSendOpts,
|
|
355
407
|
...index === 0 && replyBroadcast ? { replyBroadcast: true } : {},
|
|
356
408
|
...message.blocks ? { blocks: message.blocks } : {},
|
|
@@ -361,24 +413,24 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
361
413
|
if (!lastResult) throw new Error("Slack prepared message plan produced no delivery.");
|
|
362
414
|
return lastResult;
|
|
363
415
|
})() : blocks ? await (async () => {
|
|
364
|
-
if (mediaUrl) await slackActionRuntime.sendSlackMessage(
|
|
416
|
+
if (mediaUrl) await slackActionRuntime.sendSlackMessage(destination, "", {
|
|
365
417
|
...sendOpts,
|
|
366
418
|
mediaUrl
|
|
367
419
|
});
|
|
368
420
|
return await sendContentAndBlocks();
|
|
369
|
-
})() : await slackActionRuntime.sendSlackMessage(
|
|
421
|
+
})() : await slackActionRuntime.sendSlackMessage(destination, content ?? "", {
|
|
370
422
|
...sendOpts,
|
|
371
423
|
mediaUrl: mediaUrl ?? void 0,
|
|
372
424
|
blocks
|
|
373
425
|
});
|
|
374
|
-
if (context?.hasRepliedRef && slackContextTargetsMatch(
|
|
426
|
+
if (context?.hasRepliedRef && slackContextTargetsMatch(destination, context)) context.hasRepliedRef.value = true;
|
|
375
427
|
return jsonResult({
|
|
376
428
|
ok: true,
|
|
377
429
|
result
|
|
378
430
|
});
|
|
379
431
|
}
|
|
380
432
|
case "uploadFile": {
|
|
381
|
-
const
|
|
433
|
+
const destination = resolveSlackActionTarget(account, readStringParam(params, "to", { required: true }), context).routingTarget;
|
|
382
434
|
const filePath = readStringParam(params, "filePath", {
|
|
383
435
|
required: true,
|
|
384
436
|
trim: false
|
|
@@ -386,48 +438,55 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
386
438
|
const initialComment = readStringParam(params, "initialComment", { allowEmpty: true });
|
|
387
439
|
const filename = readStringParam(params, "filename");
|
|
388
440
|
const title = readStringParam(params, "title");
|
|
441
|
+
const forceDocument = readBooleanParam(params, "forceDocument") === true;
|
|
389
442
|
if (readBooleanParam(params, "replyBroadcast")) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
|
|
390
|
-
const threadTs = resolveThreadTsFromContext(readStringParam(params, "threadTs"),
|
|
391
|
-
const result = await slackActionRuntime.sendSlackMessage(
|
|
392
|
-
...
|
|
443
|
+
const threadTs = resolveThreadTsFromContext(readStringParam(params, "threadTs"), destination, context, { suppressImplicitThread: params.topLevel === true || params.threadTs === null });
|
|
444
|
+
const result = await slackActionRuntime.sendSlackMessage(destination, initialComment ?? "", {
|
|
445
|
+
...buildActionOpts("write"),
|
|
393
446
|
mediaUrl: filePath,
|
|
447
|
+
mediaAccess: context?.mediaAccess,
|
|
394
448
|
mediaLocalRoots: context?.mediaLocalRoots,
|
|
395
449
|
mediaReadFile: context?.mediaReadFile,
|
|
396
450
|
threadTs: threadTs ?? void 0,
|
|
451
|
+
...forceDocument ? { forceDocument: true } : {},
|
|
397
452
|
...filename ? { uploadFileName: filename } : {},
|
|
398
453
|
...title ? { uploadTitle: title } : {}
|
|
399
454
|
});
|
|
400
|
-
if (context?.hasRepliedRef && slackContextTargetsMatch(
|
|
455
|
+
if (context?.hasRepliedRef && slackContextTargetsMatch(destination, context)) context.hasRepliedRef.value = true;
|
|
401
456
|
return jsonResult({
|
|
402
457
|
ok: true,
|
|
403
458
|
result
|
|
404
459
|
});
|
|
405
460
|
}
|
|
406
461
|
case "editMessage": {
|
|
407
|
-
const
|
|
462
|
+
const target = resolveChannelTarget();
|
|
463
|
+
const { channelId } = target;
|
|
408
464
|
const messageId = readStringParam(params, "messageId", { required: true });
|
|
409
465
|
const content = readStringParam(params, "content", { allowEmpty: true });
|
|
410
466
|
const blocks = readSlackBlocksParam(params);
|
|
411
467
|
if (!content && !blocks) throw new Error("Slack editMessage requires content or blocks.");
|
|
412
|
-
await assertReadTargetAllowed(
|
|
413
|
-
|
|
468
|
+
await assertReadTargetAllowed(target);
|
|
469
|
+
const writeOpts = buildActionOpts("write", target.teamId);
|
|
470
|
+
await slackActionRuntime.editSlackMessage(channelId, messageId, content ?? "", {
|
|
414
471
|
...writeOpts,
|
|
415
472
|
blocks
|
|
416
473
|
});
|
|
417
|
-
else await slackActionRuntime.editSlackMessage(channelId, messageId, content ?? "", { blocks });
|
|
418
474
|
return jsonResult({ ok: true });
|
|
419
475
|
}
|
|
420
476
|
case "deleteMessage": {
|
|
421
|
-
const
|
|
477
|
+
const target = resolveChannelTarget();
|
|
478
|
+
const { channelId } = target;
|
|
422
479
|
const messageId = readStringParam(params, "messageId", { required: true });
|
|
423
|
-
await assertReadTargetAllowed(
|
|
424
|
-
|
|
425
|
-
|
|
480
|
+
await assertReadTargetAllowed(target);
|
|
481
|
+
const writeOpts = buildActionOpts("write", target.teamId);
|
|
482
|
+
await slackActionRuntime.deleteSlackMessage(channelId, messageId, writeOpts);
|
|
426
483
|
return jsonResult({ ok: true });
|
|
427
484
|
}
|
|
428
485
|
case "readMessages": {
|
|
429
|
-
const
|
|
430
|
-
|
|
486
|
+
const target = resolveChannelTarget();
|
|
487
|
+
const { channelId } = target;
|
|
488
|
+
await assertReadTargetAllowed(target);
|
|
489
|
+
const readOpts = buildActionOpts("read", target.teamId);
|
|
431
490
|
const limit = readPositiveIntegerParam(params, "limit", { message: "limit must be a positive integer." });
|
|
432
491
|
const before = readStringParam(params, "before");
|
|
433
492
|
const after = readStringParam(params, "after");
|
|
@@ -454,14 +513,16 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
454
513
|
const fileId = readStringParam(params, "fileId", { required: true });
|
|
455
514
|
const channelTarget = readStringParam(params, "channelId") ?? readStringParam(params, "to") ?? context?.currentChannelId;
|
|
456
515
|
if (!channelTarget) throw new Error("Slack file download requires channelId or to so the read target can be authorized.");
|
|
457
|
-
const
|
|
458
|
-
|
|
516
|
+
const target = resolveSlackActionChannelTarget(account, channelTarget, context);
|
|
517
|
+
const { channelId } = target;
|
|
518
|
+
await assertReadTargetAllowed(target);
|
|
459
519
|
const threadId = readStringParam(params, "threadId") ?? readStringParam(params, "replyTo");
|
|
460
520
|
const maxBytes = account.config?.mediaMaxMb ? account.config.mediaMaxMb * 1024 * 1024 : 20 * 1024 * 1024;
|
|
461
521
|
const readToken = resolveSlackOperationToken(account, "read");
|
|
522
|
+
const readOpts = buildActionOpts("read", target.teamId);
|
|
462
523
|
const downloaded = await slackActionRuntime.downloadSlackFile(fileId, {
|
|
463
524
|
...readOpts,
|
|
464
|
-
...readToken && !readOpts
|
|
525
|
+
...readToken && !readOpts.token ? { token: readToken } : {},
|
|
465
526
|
maxBytes,
|
|
466
527
|
channelId,
|
|
467
528
|
threadId: threadId ?? void 0
|
|
@@ -499,25 +560,26 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
499
560
|
}
|
|
500
561
|
if (pinActions.has(action)) {
|
|
501
562
|
if (!isActionEnabled("pins")) throw new Error("Slack pins are disabled.");
|
|
502
|
-
const
|
|
563
|
+
const target = resolveChannelTarget();
|
|
564
|
+
const { channelId } = target;
|
|
565
|
+
const readOpts = buildActionOpts("read", target.teamId);
|
|
566
|
+
const writeOpts = buildActionOpts("write", target.teamId);
|
|
503
567
|
if (action === "pinMessage") {
|
|
504
568
|
const messageId = readStringParam(params, "messageId", { required: true });
|
|
505
|
-
await assertReadTargetAllowed(
|
|
506
|
-
|
|
507
|
-
else await slackActionRuntime.pinSlackMessage(channelId, messageId);
|
|
569
|
+
await assertReadTargetAllowed(target);
|
|
570
|
+
await slackActionRuntime.pinSlackMessage(channelId, messageId, writeOpts);
|
|
508
571
|
return jsonResult({ ok: true });
|
|
509
572
|
}
|
|
510
573
|
if (action === "unpinMessage") {
|
|
511
574
|
const messageId = readStringParam(params, "messageId", { required: true });
|
|
512
|
-
await assertReadTargetAllowed(
|
|
513
|
-
|
|
514
|
-
else await slackActionRuntime.unpinSlackMessage(channelId, messageId);
|
|
575
|
+
await assertReadTargetAllowed(target);
|
|
576
|
+
await slackActionRuntime.unpinSlackMessage(channelId, messageId, writeOpts);
|
|
515
577
|
return jsonResult({ ok: true });
|
|
516
578
|
}
|
|
517
|
-
await assertReadTargetAllowed(
|
|
579
|
+
await assertReadTargetAllowed(target);
|
|
518
580
|
return jsonResult({
|
|
519
581
|
ok: true,
|
|
520
|
-
pins: (
|
|
582
|
+
pins: (await slackActionRuntime.listSlackPins(channelId, readOpts)).map((pin) => {
|
|
521
583
|
const message = pin.message ? withNormalizedTimestamp(pin.message, pin.message.ts) : pin.message;
|
|
522
584
|
return message ? Object.assign({}, pin, { message }) : pin;
|
|
523
585
|
})
|
|
@@ -531,15 +593,25 @@ async function handleSlackAction(params, cfg, context) {
|
|
|
531
593
|
context,
|
|
532
594
|
userId
|
|
533
595
|
});
|
|
596
|
+
const teamId = resolveTrustedCurrentSlackTeamId({
|
|
597
|
+
account,
|
|
598
|
+
context
|
|
599
|
+
});
|
|
600
|
+
assertSlackDetachedTargetAllowed(account.accountId, teamId);
|
|
534
601
|
return jsonResult({
|
|
535
602
|
ok: true,
|
|
536
|
-
info:
|
|
603
|
+
info: await slackActionRuntime.getSlackMemberInfo(userId, buildActionOpts("read", teamId))
|
|
537
604
|
});
|
|
538
605
|
}
|
|
539
606
|
if (action === "emojiList") {
|
|
540
607
|
if (!isActionEnabled("emojiList")) throw new Error("Slack emoji list is disabled.");
|
|
541
608
|
const limit = readPositiveIntegerParam(params, "limit", { message: "limit must be a positive integer." });
|
|
542
|
-
const
|
|
609
|
+
const teamId = resolveTrustedCurrentSlackTeamId({
|
|
610
|
+
account,
|
|
611
|
+
context
|
|
612
|
+
});
|
|
613
|
+
assertSlackDetachedTargetAllowed(account.accountId, teamId);
|
|
614
|
+
const result = await slackActionRuntime.listSlackEmojis(buildActionOpts("read", teamId));
|
|
543
615
|
if (limit != null && limit > 0 && result.emoji != null) {
|
|
544
616
|
const entries = Object.entries(result.emoji).toSorted(([a], [b]) => a.localeCompare(b));
|
|
545
617
|
if (entries.length > limit) return jsonResult({
|