mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-05 17:10:20 +00:00
Refactor channel approval capability seams (#58634)
Merged via squash.
Prepared head SHA: c9ad4e4706
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
committed by
GitHub
parent
d9a7ffe003
commit
c87c8e66bf
@@ -258,7 +258,7 @@ describe("slack native approval adapter", () => {
|
||||
});
|
||||
|
||||
it("suppresses generic slack fallback only for slack-originated approvals", () => {
|
||||
const shouldSuppress = slackNativeApprovalAdapter.delivery.shouldSuppressForwardingFallback;
|
||||
const shouldSuppress = slackNativeApprovalAdapter.delivery?.shouldSuppressForwardingFallback;
|
||||
if (!shouldSuppress) {
|
||||
throw new Error("slack native delivery suppression unavailable");
|
||||
}
|
||||
@@ -266,12 +266,16 @@ describe("slack native approval adapter", () => {
|
||||
expect(
|
||||
shouldSuppress({
|
||||
cfg: buildConfig(),
|
||||
target: { channel: "slack", accountId: "default" },
|
||||
target: { channel: "slack", to: "channel:C123ROOM", accountId: "default" },
|
||||
request: {
|
||||
id: "approval-1",
|
||||
request: {
|
||||
command: "echo hi",
|
||||
turnSourceChannel: "slack",
|
||||
turnSourceAccountId: "default",
|
||||
},
|
||||
createdAtMs: 0,
|
||||
expiresAtMs: 1_000,
|
||||
},
|
||||
}),
|
||||
).toBe(true);
|
||||
@@ -279,12 +283,16 @@ describe("slack native approval adapter", () => {
|
||||
expect(
|
||||
shouldSuppress({
|
||||
cfg: buildConfig(),
|
||||
target: { channel: "slack", accountId: "default" },
|
||||
target: { channel: "slack", to: "channel:C123ROOM", accountId: "default" },
|
||||
request: {
|
||||
id: "approval-1",
|
||||
request: {
|
||||
command: "echo hi",
|
||||
turnSourceChannel: "discord",
|
||||
turnSourceAccountId: "default",
|
||||
},
|
||||
createdAtMs: 0,
|
||||
expiresAtMs: 1_000,
|
||||
},
|
||||
}),
|
||||
).toBe(false);
|
||||
@@ -301,7 +309,7 @@ describe("slack native approval adapter", () => {
|
||||
});
|
||||
|
||||
expect(
|
||||
slackNativeApprovalAdapter.auth.authorizeActorAction({
|
||||
slackNativeApprovalAdapter.auth.authorizeActorAction?.({
|
||||
cfg,
|
||||
accountId: "default",
|
||||
senderId: "U123OWNER",
|
||||
@@ -311,7 +319,7 @@ describe("slack native approval adapter", () => {
|
||||
).toEqual({ authorized: true });
|
||||
|
||||
expect(
|
||||
slackNativeApprovalAdapter.auth.authorizeActorAction({
|
||||
slackNativeApprovalAdapter.auth.authorizeActorAction?.({
|
||||
cfg,
|
||||
accountId: "default",
|
||||
senderId: "U999EXEC",
|
||||
@@ -324,7 +332,7 @@ describe("slack native approval adapter", () => {
|
||||
});
|
||||
|
||||
expect(
|
||||
slackNativeApprovalAdapter.auth.authorizeActorAction({
|
||||
slackNativeApprovalAdapter.auth.authorizeActorAction?.({
|
||||
cfg,
|
||||
accountId: "default",
|
||||
senderId: "U999EXEC",
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import {
|
||||
createApproverRestrictedNativeApprovalAdapter,
|
||||
resolveApprovalRequestOriginTarget,
|
||||
createChannelApproverDmTargetResolver,
|
||||
createChannelNativeOriginTargetResolver,
|
||||
createApproverRestrictedNativeApprovalCapability,
|
||||
splitChannelApprovalCapability,
|
||||
} from "openclaw/plugin-sdk/approval-runtime";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import type { ExecApprovalRequest, PluginApprovalRequest } from "openclaw/plugin-sdk/infra-runtime";
|
||||
@@ -88,40 +90,31 @@ function slackTargetsMatch(a: SlackOriginTarget, b: SlackOriginTarget): boolean
|
||||
);
|
||||
}
|
||||
|
||||
function resolveSlackOriginTarget(params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId: string;
|
||||
request: ApprovalRequest;
|
||||
}) {
|
||||
if (!shouldHandleSlackExecApprovalRequest(params)) {
|
||||
return null;
|
||||
}
|
||||
return resolveApprovalRequestOriginTarget({
|
||||
cfg: params.cfg,
|
||||
request: params.request,
|
||||
channel: "slack",
|
||||
accountId: params.accountId,
|
||||
resolveTurnSourceTarget: resolveTurnSourceSlackOriginTarget,
|
||||
resolveSessionTarget: resolveSessionSlackOriginTarget,
|
||||
targetsMatch: slackTargetsMatch,
|
||||
});
|
||||
}
|
||||
const resolveSlackOriginTarget = createChannelNativeOriginTargetResolver({
|
||||
channel: "slack",
|
||||
shouldHandleRequest: ({ cfg, accountId, request }) =>
|
||||
shouldHandleSlackExecApprovalRequest({
|
||||
cfg,
|
||||
accountId,
|
||||
request,
|
||||
}),
|
||||
resolveTurnSourceTarget: resolveTurnSourceSlackOriginTarget,
|
||||
resolveSessionTarget: resolveSessionSlackOriginTarget,
|
||||
targetsMatch: slackTargetsMatch,
|
||||
});
|
||||
|
||||
function resolveSlackApproverDmTargets(params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId?: string | null;
|
||||
request: ApprovalRequest;
|
||||
}) {
|
||||
if (!shouldHandleSlackExecApprovalRequest(params)) {
|
||||
return [];
|
||||
}
|
||||
return getSlackExecApprovalApprovers({
|
||||
cfg: params.cfg,
|
||||
accountId: params.accountId,
|
||||
}).map((approver) => ({ to: `user:${approver}` }));
|
||||
}
|
||||
const resolveSlackApproverDmTargets = createChannelApproverDmTargetResolver({
|
||||
shouldHandleRequest: ({ cfg, accountId, request }) =>
|
||||
shouldHandleSlackExecApprovalRequest({
|
||||
cfg,
|
||||
accountId,
|
||||
request,
|
||||
}),
|
||||
resolveApprovers: getSlackExecApprovalApprovers,
|
||||
mapApprover: (approver) => ({ to: `user:${approver}` }),
|
||||
});
|
||||
|
||||
export const slackNativeApprovalAdapter = createApproverRestrictedNativeApprovalAdapter({
|
||||
export const slackApprovalCapability = createApproverRestrictedNativeApprovalCapability({
|
||||
channel: "slack",
|
||||
channelLabel: "Slack",
|
||||
listAccountIds: listSlackAccountIds,
|
||||
@@ -138,9 +131,9 @@ export const slackNativeApprovalAdapter = createApproverRestrictedNativeApproval
|
||||
requireMatchingTurnSourceChannel: true,
|
||||
resolveSuppressionAccountId: ({ target, request }) =>
|
||||
target.accountId?.trim() || request.request.turnSourceAccountId?.trim() || undefined,
|
||||
resolveOriginTarget: ({ cfg, accountId, request }) =>
|
||||
accountId ? resolveSlackOriginTarget({ cfg, accountId, request }) : null,
|
||||
resolveApproverDmTargets: ({ cfg, accountId, request }) =>
|
||||
resolveSlackApproverDmTargets({ cfg, accountId, request }),
|
||||
resolveOriginTarget: resolveSlackOriginTarget,
|
||||
resolveApproverDmTargets: resolveSlackApproverDmTargets,
|
||||
notifyOriginWhenDmOnly: true,
|
||||
});
|
||||
|
||||
export const slackNativeApprovalAdapter = splitChannelApprovalCapability(slackApprovalCapability);
|
||||
|
||||
@@ -38,7 +38,7 @@ import {
|
||||
} from "./accounts.js";
|
||||
import type { SlackActionContext } from "./action-runtime.js";
|
||||
import { resolveSlackAutoThreadId } from "./action-threading.js";
|
||||
import { slackNativeApprovalAdapter } from "./approval-native.js";
|
||||
import { slackApprovalCapability } from "./approval-native.js";
|
||||
import { createSlackActions } from "./channel-actions.js";
|
||||
import { resolveSlackChannelType } from "./channel-type.js";
|
||||
import {
|
||||
@@ -283,11 +283,7 @@ export const slackPlugin: ChannelPlugin<ResolvedSlackAccount, SlackProbe> = crea
|
||||
}),
|
||||
resolveNames: resolveSlackAllowlistNames,
|
||||
},
|
||||
auth: slackNativeApprovalAdapter.auth,
|
||||
approvals: {
|
||||
delivery: slackNativeApprovalAdapter.delivery,
|
||||
native: slackNativeApprovalAdapter.native,
|
||||
},
|
||||
approvalCapability: slackApprovalCapability,
|
||||
groups: {
|
||||
resolveRequireMention: resolveSlackGroupRequireMention,
|
||||
resolveToolPolicy: resolveSlackGroupToolPolicy,
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
import {
|
||||
createChannelExecApprovalProfile,
|
||||
doesApprovalRequestMatchChannelAccount,
|
||||
getExecApprovalReplyMetadata,
|
||||
matchesApprovalRequestFilters,
|
||||
isChannelExecApprovalTargetRecipient,
|
||||
resolveApprovalApprovers,
|
||||
} from "openclaw/plugin-sdk/approval-runtime";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import type { ExecApprovalRequest, PluginApprovalRequest } from "openclaw/plugin-sdk/infra-runtime";
|
||||
import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime";
|
||||
import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
|
||||
import { resolveSlackAccount } from "./accounts.js";
|
||||
|
||||
type ApprovalRequest = ExecApprovalRequest | PluginApprovalRequest;
|
||||
|
||||
export function normalizeSlackApproverId(value: string | number): string | undefined {
|
||||
const trimmed = String(value).trim();
|
||||
if (!trimmed) {
|
||||
@@ -38,123 +33,49 @@ function resolveSlackOwnerApprovers(cfg: OpenClawConfig): string[] {
|
||||
normalizeApprover: normalizeSlackApproverId,
|
||||
});
|
||||
}
|
||||
|
||||
export function shouldHandleSlackExecApprovalRequest(params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId?: string | null;
|
||||
request: ApprovalRequest;
|
||||
}): boolean {
|
||||
if (
|
||||
!doesApprovalRequestMatchChannelAccount({
|
||||
cfg: params.cfg,
|
||||
request: params.request,
|
||||
channel: "slack",
|
||||
accountId: params.accountId,
|
||||
})
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const config = resolveSlackAccount(params).config.execApprovals;
|
||||
if (!config?.enabled) {
|
||||
return false;
|
||||
}
|
||||
if (getSlackExecApprovalApprovers(params).length === 0) {
|
||||
return false;
|
||||
}
|
||||
return matchesApprovalRequestFilters({
|
||||
request: params.request.request,
|
||||
agentFilter: config.agentFilter,
|
||||
sessionFilter: config.sessionFilter,
|
||||
});
|
||||
}
|
||||
|
||||
export function getSlackExecApprovalApprovers(params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId?: string | null;
|
||||
}): string[] {
|
||||
const account = resolveSlackAccount(params).config;
|
||||
return resolveApprovalApprovers({
|
||||
explicit:
|
||||
resolveSlackAccount(params).config.execApprovals?.approvers ??
|
||||
resolveSlackOwnerApprovers(params.cfg),
|
||||
explicit: account.execApprovals?.approvers ?? resolveSlackOwnerApprovers(params.cfg),
|
||||
normalizeApprover: normalizeSlackApproverId,
|
||||
});
|
||||
}
|
||||
|
||||
export function isSlackExecApprovalClientEnabled(params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId?: string | null;
|
||||
}): boolean {
|
||||
const config = resolveSlackAccount(params).config.execApprovals;
|
||||
return Boolean(config?.enabled && getSlackExecApprovalApprovers(params).length > 0);
|
||||
}
|
||||
|
||||
export function isSlackExecApprovalApprover(params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId?: string | null;
|
||||
senderId?: string | null;
|
||||
}): boolean {
|
||||
const senderId = params.senderId ? normalizeSlackApproverId(params.senderId) : undefined;
|
||||
if (!senderId) {
|
||||
return false;
|
||||
}
|
||||
return getSlackExecApprovalApprovers(params).includes(senderId);
|
||||
}
|
||||
|
||||
function isSlackExecApprovalTargetsMode(cfg: OpenClawConfig): boolean {
|
||||
const execApprovals = cfg.approvals?.exec;
|
||||
if (!execApprovals?.enabled) {
|
||||
return false;
|
||||
}
|
||||
return execApprovals.mode === "targets" || execApprovals.mode === "both";
|
||||
}
|
||||
|
||||
export function isSlackExecApprovalTargetRecipient(params: {
|
||||
cfg: OpenClawConfig;
|
||||
senderId?: string | null;
|
||||
accountId?: string | null;
|
||||
}): boolean {
|
||||
const senderId = params.senderId ? normalizeSlackApproverId(params.senderId) : undefined;
|
||||
if (!senderId || !isSlackExecApprovalTargetsMode(params.cfg)) {
|
||||
return false;
|
||||
}
|
||||
const targets = params.cfg.approvals?.exec?.targets;
|
||||
if (!targets) {
|
||||
return false;
|
||||
}
|
||||
const accountId = params.accountId ? normalizeAccountId(params.accountId) : undefined;
|
||||
return targets.some((target) => {
|
||||
if (target.channel?.trim().toLowerCase() !== "slack") {
|
||||
return false;
|
||||
}
|
||||
if (accountId && target.accountId && normalizeAccountId(target.accountId) !== accountId) {
|
||||
return false;
|
||||
}
|
||||
return normalizeSlackApproverId(target.to) === senderId;
|
||||
return isChannelExecApprovalTargetRecipient({
|
||||
...params,
|
||||
channel: "slack",
|
||||
normalizeSenderId: normalizeSlackApproverId,
|
||||
matchTarget: ({ target, normalizedSenderId }) =>
|
||||
normalizeSlackApproverId(target.to) === normalizedSenderId,
|
||||
});
|
||||
}
|
||||
|
||||
export function isSlackExecApprovalAuthorizedSender(params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId?: string | null;
|
||||
senderId?: string | null;
|
||||
}): boolean {
|
||||
return isSlackExecApprovalApprover(params) || isSlackExecApprovalTargetRecipient(params);
|
||||
}
|
||||
const slackExecApprovalProfile = createChannelExecApprovalProfile({
|
||||
resolveConfig: (params) => resolveSlackAccount(params).config.execApprovals,
|
||||
resolveApprovers: getSlackExecApprovalApprovers,
|
||||
normalizeSenderId: normalizeSlackApproverId,
|
||||
isTargetRecipient: isSlackExecApprovalTargetRecipient,
|
||||
matchesRequestAccount: (params) =>
|
||||
doesApprovalRequestMatchChannelAccount({
|
||||
cfg: params.cfg,
|
||||
request: params.request,
|
||||
channel: "slack",
|
||||
accountId: params.accountId,
|
||||
}),
|
||||
});
|
||||
|
||||
export function resolveSlackExecApprovalTarget(params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId?: string | null;
|
||||
}): "dm" | "channel" | "both" {
|
||||
return resolveSlackAccount(params).config.execApprovals?.target ?? "dm";
|
||||
}
|
||||
|
||||
export function shouldSuppressLocalSlackExecApprovalPrompt(params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId?: string | null;
|
||||
payload: ReplyPayload;
|
||||
}): boolean {
|
||||
return (
|
||||
isSlackExecApprovalClientEnabled(params) &&
|
||||
getExecApprovalReplyMetadata(params.payload) !== null
|
||||
);
|
||||
}
|
||||
export const isSlackExecApprovalClientEnabled = slackExecApprovalProfile.isClientEnabled;
|
||||
export const isSlackExecApprovalApprover = slackExecApprovalProfile.isApprover;
|
||||
export const isSlackExecApprovalAuthorizedSender = slackExecApprovalProfile.isAuthorizedSender;
|
||||
export const resolveSlackExecApprovalTarget = slackExecApprovalProfile.resolveTarget;
|
||||
export const shouldHandleSlackExecApprovalRequest = slackExecApprovalProfile.shouldHandleRequest;
|
||||
export const shouldSuppressLocalSlackExecApprovalPrompt =
|
||||
slackExecApprovalProfile.shouldSuppressLocalPrompt;
|
||||
|
||||
@@ -3,8 +3,7 @@ import type { Block, KnownBlock } from "@slack/web-api";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import {
|
||||
buildApprovalInteractiveReply,
|
||||
createExecApprovalChannelRuntime,
|
||||
deliverApprovalRequestViaChannelNativePlan,
|
||||
createChannelNativeApprovalRuntime,
|
||||
getExecApprovalApproverDmNoticeText,
|
||||
resolveExecApprovalCommandDisplay,
|
||||
type ExecApprovalChannelRuntime,
|
||||
@@ -27,6 +26,10 @@ type SlackPendingApproval = {
|
||||
channelId: string;
|
||||
messageTs: string;
|
||||
};
|
||||
type SlackPendingDelivery = {
|
||||
text: string;
|
||||
blocks: SlackBlock[];
|
||||
};
|
||||
|
||||
type SlackExecApprovalConfig = NonNullable<
|
||||
NonNullable<NonNullable<OpenClawConfig["channels"]>["slack"]>["execApprovals"]
|
||||
@@ -219,11 +222,19 @@ export class SlackExecApprovalHandler {
|
||||
|
||||
constructor(opts: SlackExecApprovalHandlerOpts) {
|
||||
this.opts = opts;
|
||||
this.runtime = createExecApprovalChannelRuntime<SlackPendingApproval>({
|
||||
this.runtime = createChannelNativeApprovalRuntime<
|
||||
SlackPendingApproval,
|
||||
{ to: string; threadTs?: string },
|
||||
SlackPendingDelivery,
|
||||
ExecApprovalRequest,
|
||||
ExecApprovalResolved
|
||||
>({
|
||||
label: "slack/exec-approvals",
|
||||
clientDisplayName: "Slack Exec Approvals",
|
||||
cfg: opts.cfg,
|
||||
accountId: opts.accountId,
|
||||
gatewayUrl: opts.gatewayUrl,
|
||||
nativeAdapter: slackNativeApprovalAdapter.native,
|
||||
isConfigured: () =>
|
||||
Boolean(
|
||||
opts.config.enabled &&
|
||||
@@ -233,7 +244,49 @@ export class SlackExecApprovalHandler {
|
||||
}).length > 0,
|
||||
),
|
||||
shouldHandle: (request) => this.shouldHandle(request),
|
||||
deliverRequested: async (request) => await this.deliverRequested(request),
|
||||
buildPendingContent: ({ request }) => ({
|
||||
text: buildSlackPendingApprovalText(request),
|
||||
blocks: buildSlackPendingApprovalBlocks(request),
|
||||
}),
|
||||
sendOriginNotice: async ({ originTarget }) => {
|
||||
await sendMessageSlack(originTarget.to, getExecApprovalApproverDmNoticeText(), {
|
||||
cfg: this.opts.cfg,
|
||||
accountId: this.opts.accountId,
|
||||
threadTs: originTarget.threadId != null ? String(originTarget.threadId) : undefined,
|
||||
client: this.opts.app.client,
|
||||
});
|
||||
},
|
||||
prepareTarget: ({ plannedTarget }) => ({
|
||||
dedupeKey: `${plannedTarget.target.to}:${plannedTarget.target.threadId == null ? "" : String(plannedTarget.target.threadId)}`,
|
||||
target: {
|
||||
to: plannedTarget.target.to,
|
||||
threadTs:
|
||||
plannedTarget.target.threadId != null
|
||||
? String(plannedTarget.target.threadId)
|
||||
: undefined,
|
||||
},
|
||||
}),
|
||||
deliverTarget: async ({ preparedTarget, pendingContent, request }) => {
|
||||
const message = await sendMessageSlack(preparedTarget.to, pendingContent.text, {
|
||||
cfg: this.opts.cfg,
|
||||
accountId: this.opts.accountId,
|
||||
threadTs: preparedTarget.threadTs,
|
||||
blocks: pendingContent.blocks,
|
||||
client: this.opts.app.client,
|
||||
});
|
||||
return {
|
||||
channelId: message.channelId,
|
||||
messageTs: message.messageId,
|
||||
};
|
||||
},
|
||||
onOriginNoticeError: ({ error }) => {
|
||||
logError(`slack exec approvals: failed to send DM redirect notice: ${String(error)}`);
|
||||
},
|
||||
onDeliveryError: ({ error, request }) => {
|
||||
logError(
|
||||
`slack exec approvals: failed to deliver approval ${request.id}: ${String(error)}`,
|
||||
);
|
||||
},
|
||||
finalizeResolved: async ({ request, resolved, entries }) => {
|
||||
await this.finalizeResolved(request, resolved, entries);
|
||||
},
|
||||
@@ -248,7 +301,14 @@ export class SlackExecApprovalHandler {
|
||||
cfg: this.opts.cfg,
|
||||
accountId: this.opts.accountId,
|
||||
request,
|
||||
});
|
||||
})
|
||||
? slackNativeApprovalAdapter.native?.describeDeliveryCapabilities({
|
||||
cfg: this.opts.cfg,
|
||||
accountId: this.opts.accountId,
|
||||
approvalKind: "exec",
|
||||
request,
|
||||
}).enabled === true
|
||||
: false;
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
@@ -271,57 +331,6 @@ export class SlackExecApprovalHandler {
|
||||
await this.runtime.handleExpired(approvalId);
|
||||
}
|
||||
|
||||
private async deliverRequested(request: ExecApprovalRequest): Promise<SlackPendingApproval[]> {
|
||||
const text = buildSlackPendingApprovalText(request);
|
||||
const blocks = buildSlackPendingApprovalBlocks(request);
|
||||
return await deliverApprovalRequestViaChannelNativePlan({
|
||||
cfg: this.opts.cfg,
|
||||
accountId: this.opts.accountId,
|
||||
approvalKind: "exec",
|
||||
request,
|
||||
adapter: slackNativeApprovalAdapter.native,
|
||||
sendOriginNotice: async ({ originTarget }) => {
|
||||
await sendMessageSlack(originTarget.to, getExecApprovalApproverDmNoticeText(), {
|
||||
cfg: this.opts.cfg,
|
||||
accountId: this.opts.accountId,
|
||||
threadTs: originTarget.threadId != null ? String(originTarget.threadId) : undefined,
|
||||
client: this.opts.app.client,
|
||||
});
|
||||
},
|
||||
prepareTarget: ({ plannedTarget }) => ({
|
||||
dedupeKey: `${plannedTarget.target.to}:${plannedTarget.target.threadId == null ? "" : String(plannedTarget.target.threadId)}`,
|
||||
target: {
|
||||
to: plannedTarget.target.to,
|
||||
threadTs:
|
||||
plannedTarget.target.threadId != null
|
||||
? String(plannedTarget.target.threadId)
|
||||
: undefined,
|
||||
},
|
||||
}),
|
||||
deliverTarget: async ({ preparedTarget }) => {
|
||||
const message = await sendMessageSlack(preparedTarget.to, text, {
|
||||
cfg: this.opts.cfg,
|
||||
accountId: this.opts.accountId,
|
||||
threadTs: preparedTarget.threadTs,
|
||||
blocks,
|
||||
client: this.opts.app.client,
|
||||
});
|
||||
return {
|
||||
channelId: message.channelId,
|
||||
messageTs: message.messageId,
|
||||
};
|
||||
},
|
||||
onOriginNoticeError: ({ error }) => {
|
||||
logError(`slack exec approvals: failed to send DM redirect notice: ${String(error)}`);
|
||||
},
|
||||
onDeliveryError: ({ error }) => {
|
||||
logError(
|
||||
`slack exec approvals: failed to deliver approval ${request.id}: ${String(error)}`,
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private async finalizeResolved(
|
||||
request: ExecApprovalRequest,
|
||||
resolved: ExecApprovalResolved,
|
||||
|
||||
Reference in New Issue
Block a user