diff --git a/extensions/discord/src/approval-native.ts b/extensions/discord/src/approval-native.ts index a1b522283c5..9e3e0da48c1 100644 --- a/extensions/discord/src/approval-native.ts +++ b/extensions/discord/src/approval-native.ts @@ -1,4 +1,5 @@ import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime"; +import type { ChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime"; import { resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime"; import type { DiscordExecApprovalConfig, OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import type { ExecApprovalRequest, PluginApprovalRequest } from "openclaw/plugin-sdk/infra-runtime"; @@ -239,7 +240,8 @@ export function createDiscordApprovalCapability(configOverride?: DiscordExecAppr configOverride, }), load: async () => - (await import("./approval-handler.runtime.js")).discordApprovalNativeRuntime, + (await import("./approval-handler.runtime.js")) + .discordApprovalNativeRuntime as unknown as ChannelApprovalNativeRuntimeAdapter, }), }); } diff --git a/extensions/matrix/src/approval-handler.runtime.ts b/extensions/matrix/src/approval-handler.runtime.ts index 3fd6aa74f26..051793eecf1 100644 --- a/extensions/matrix/src/approval-handler.runtime.ts +++ b/extensions/matrix/src/approval-handler.runtime.ts @@ -223,7 +223,8 @@ export const matrixApprovalNativeRuntime = createChannelApprovalNativeRuntimeAda PendingApprovalContent, PreparedMatrixTarget, PendingMessage, - ReactionTargetRef + ReactionTargetRef, + string >({ eventKinds: ["exec", "plugin"], availability: { @@ -330,7 +331,7 @@ export const matrixApprovalNativeRuntime = createChannelApprovalNativeRuntimeAda if (!primaryMessageId) { return; } - const text = payload as string; + const text = payload; await Promise.allSettled([ editMessage(entry.roomId, primaryMessageId, text, { cfg: cfg as CoreConfig, diff --git a/extensions/matrix/src/approval-native.ts b/extensions/matrix/src/approval-native.ts index dc1c2439e1e..93d5b8c28ed 100644 --- a/extensions/matrix/src/approval-native.ts +++ b/extensions/matrix/src/approval-native.ts @@ -4,6 +4,7 @@ import { splitChannelApprovalCapability, } from "openclaw/plugin-sdk/approval-delivery-runtime"; import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime"; +import type { ChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime"; import { createChannelNativeOriginTargetResolver, resolveApprovalRequestSessionConversation, @@ -237,7 +238,9 @@ const matrixNativeApprovalCapability = createApproverRestrictedNativeApprovalCap accountId, request, }), - load: async () => (await import("./approval-handler.runtime.js")).matrixApprovalNativeRuntime, + load: async () => + (await import("./approval-handler.runtime.js")) + .matrixApprovalNativeRuntime as unknown as ChannelApprovalNativeRuntimeAdapter, }), }); diff --git a/extensions/slack/src/approval-handler.runtime.test.ts b/extensions/slack/src/approval-handler.runtime.test.ts index 22675d9f1db..2270dd0411a 100644 --- a/extensions/slack/src/approval-handler.runtime.test.ts +++ b/extensions/slack/src/approval-handler.runtime.test.ts @@ -103,8 +103,6 @@ describe("slackApprovalNativeRuntime", () => { } expect(result.payload.text).toContain("*Exec approval: Allowed once*"); expect(result.payload.text).toContain("Resolved by <@U123APPROVER>."); - expect( - (result.payload.blocks as Array<{ type?: string }>).some((block) => block.type === "actions"), - ).toBe(false); + expect(result.payload.blocks.some((block) => block.type === "actions")).toBe(false); }); }); diff --git a/extensions/slack/src/approval-handler.runtime.ts b/extensions/slack/src/approval-handler.runtime.ts index 5c345237b26..8eb43046267 100644 --- a/extensions/slack/src/approval-handler.runtime.ts +++ b/extensions/slack/src/approval-handler.runtime.ts @@ -229,7 +229,8 @@ export const slackApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdap SlackPendingDelivery, { to: string; threadTs?: string }, SlackPendingApproval, - never + never, + SlackPendingDelivery >({ eventKinds: ["exec"], availability: { @@ -313,7 +314,7 @@ export const slackApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdap if (!resolved) { return; } - const nextPayload = payload as SlackPendingDelivery; + const nextPayload = payload; await updateMessage({ app: resolved.context.app, channelId: entry.channelId, diff --git a/extensions/slack/src/approval-native.ts b/extensions/slack/src/approval-native.ts index dca5d896ef6..22363eaf263 100644 --- a/extensions/slack/src/approval-native.ts +++ b/extensions/slack/src/approval-native.ts @@ -3,6 +3,7 @@ import { splitChannelApprovalCapability, } from "openclaw/plugin-sdk/approval-delivery-runtime"; import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime"; +import type { ChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime"; import { createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, @@ -183,7 +184,9 @@ export const slackApprovalCapability = createApproverRestrictedNativeApprovalCap accountId, request, }), - load: async () => (await import("./approval-handler.runtime.js")).slackApprovalNativeRuntime, + load: async () => + (await import("./approval-handler.runtime.js")) + .slackApprovalNativeRuntime as unknown as ChannelApprovalNativeRuntimeAdapter, }), }); diff --git a/extensions/telegram/src/approval-native.ts b/extensions/telegram/src/approval-native.ts index e6ddc42d231..454590dd1b6 100644 --- a/extensions/telegram/src/approval-native.ts +++ b/extensions/telegram/src/approval-native.ts @@ -3,6 +3,7 @@ import { splitChannelApprovalCapability, } from "openclaw/plugin-sdk/approval-delivery-runtime"; import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime"; +import type { ChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime"; import { createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, @@ -128,7 +129,9 @@ const telegramNativeApprovalCapability = createApproverRestrictedNativeApprovalC accountId, request, }), - load: async () => (await import("./approval-handler.runtime.js")).telegramApprovalNativeRuntime, + load: async () => + (await import("./approval-handler.runtime.js")) + .telegramApprovalNativeRuntime as unknown as ChannelApprovalNativeRuntimeAdapter, }), }); diff --git a/src/infra/approval-handler-adapter-runtime.ts b/src/infra/approval-handler-adapter-runtime.ts index 90a513de07b..505536f35f5 100644 --- a/src/infra/approval-handler-adapter-runtime.ts +++ b/src/infra/approval-handler-adapter-runtime.ts @@ -7,29 +7,75 @@ import type { ExecApprovalChannelRuntimeEventKind } from "./exec-approval-channe export const CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY = "approval.native"; -type LazyChannelApprovalNativeRuntimeParams = { - load: () => Promise; +export function createLazyChannelApprovalNativeRuntimeAdapter< + TPendingPayload = unknown, + TPreparedTarget = unknown, + TPendingEntry = unknown, + TBinding = unknown, + TFinalPayload = unknown, +>(params: { + load: () => Promise< + ChannelApprovalNativeRuntimeAdapter< + TPendingPayload, + TPreparedTarget, + TPendingEntry, + TBinding, + TFinalPayload + > + >; isConfigured: ChannelApprovalNativeAvailabilityAdapter["isConfigured"]; shouldHandle: ChannelApprovalNativeAvailabilityAdapter["shouldHandle"]; eventKinds?: readonly ExecApprovalChannelRuntimeEventKind[]; resolveApprovalKind?: ChannelApprovalNativeRuntimeAdapter["resolveApprovalKind"]; -}; - -export function createLazyChannelApprovalNativeRuntimeAdapter( - params: LazyChannelApprovalNativeRuntimeParams, -): ChannelApprovalNativeRuntimeAdapter { +}): ChannelApprovalNativeRuntimeAdapter< + TPendingPayload, + TPreparedTarget, + TPendingEntry, + TBinding, + TFinalPayload +> { const loadRuntime = createLazyRuntimeModule(params.load); - let loadedRuntime: ChannelApprovalNativeRuntimeAdapter | null = null; - const loadResolvedRuntime = async (): Promise => { + let loadedRuntime: ChannelApprovalNativeRuntimeAdapter< + TPendingPayload, + TPreparedTarget, + TPendingEntry, + TBinding, + TFinalPayload + > | null = null; + const loadResolvedRuntime = async (): Promise< + ChannelApprovalNativeRuntimeAdapter< + TPendingPayload, + TPreparedTarget, + TPendingEntry, + TBinding, + TFinalPayload + > + > => { const runtime = await loadRuntime(); loadedRuntime = runtime; return runtime; }; const loadRequired = async ( - select: (runtime: ChannelApprovalNativeRuntimeAdapter) => TResult, + select: ( + runtime: ChannelApprovalNativeRuntimeAdapter< + TPendingPayload, + TPreparedTarget, + TPendingEntry, + TBinding, + TFinalPayload + >, + ) => TResult, ): Promise => select(await loadResolvedRuntime()); const loadOptional = async ( - select: (runtime: ChannelApprovalNativeRuntimeAdapter) => TResult | undefined, + select: ( + runtime: ChannelApprovalNativeRuntimeAdapter< + TPendingPayload, + TPreparedTarget, + TPendingEntry, + TBinding, + TFinalPayload + >, + ) => TResult | undefined, ): Promise => select(await loadResolvedRuntime()); return { @@ -63,7 +109,8 @@ export function createLazyChannelApprovalNativeRuntimeAdapter( }, interactions: { bindPending: async (runtimeParams) => - (await loadOptional((runtime) => runtime.interactions?.bindPending))?.(runtimeParams), + (await loadOptional((runtime) => runtime.interactions?.bindPending))?.(runtimeParams) ?? + null, unbindPending: async (runtimeParams) => await ( await loadOptional((runtime) => runtime.interactions?.unbindPending) diff --git a/src/infra/approval-handler-runtime.ts b/src/infra/approval-handler-runtime.ts index 39282d67205..3feca4ae41e 100644 --- a/src/infra/approval-handler-runtime.ts +++ b/src/infra/approval-handler-runtime.ts @@ -222,13 +222,24 @@ export type ChannelApprovalNativeObserveAdapter< ) => void; }; -export type ChannelApprovalNativeRuntimeAdapter = { +export type ChannelApprovalNativeRuntimeAdapter< + TPendingPayload = unknown, + TPreparedTarget = unknown, + TPendingEntry = unknown, + TBinding = unknown, + TFinalPayload = unknown, +> = { eventKinds?: readonly ExecApprovalChannelRuntimeEventKind[]; resolveApprovalKind?: (request: ApprovalRequest) => ChannelApprovalKind; availability: ChannelApprovalNativeAvailabilityAdapter; - presentation: ChannelApprovalNativePresentationAdapter; - transport: ChannelApprovalNativeTransportAdapter; - interactions?: ChannelApprovalNativeInteractionAdapter; + presentation: ChannelApprovalNativePresentationAdapter; + transport: ChannelApprovalNativeTransportAdapter< + TPreparedTarget, + TPendingEntry, + TPendingPayload, + TFinalPayload + >; + interactions?: ChannelApprovalNativeInteractionAdapter; observe?: ChannelApprovalNativeObserveAdapter; }; @@ -237,6 +248,7 @@ export type ChannelApprovalNativeRuntimeSpec< TPreparedTarget, TPendingEntry, TBinding = unknown, + TFinalPayload = unknown, TPendingView extends PendingApprovalView = PendingApprovalView, TResolvedView extends ResolvedApprovalView = ResolvedApprovalView, TExpiredView extends ExpiredApprovalView = ExpiredApprovalView, @@ -261,8 +273,8 @@ export type ChannelApprovalNativeRuntimeSpec< entry: TPendingEntry; }, ) => - | ChannelApprovalNativeFinalAction - | Promise>; + | ChannelApprovalNativeFinalAction + | Promise>; buildExpiredResult: ( params: ChannelApprovalCapabilityHandlerContext & { request: ApprovalRequest; @@ -270,8 +282,8 @@ export type ChannelApprovalNativeRuntimeSpec< entry: TPendingEntry; }, ) => - | ChannelApprovalNativeFinalAction - | Promise>; + | ChannelApprovalNativeFinalAction + | Promise>; }; transport: { prepareTarget: ( @@ -299,7 +311,7 @@ export type ChannelApprovalNativeRuntimeSpec< updateEntry?: ( params: ChannelApprovalCapabilityHandlerContext & { entry: TPendingEntry; - payload: unknown; + payload: TFinalPayload; phase: "resolved" | "expired"; }, ) => Promise; @@ -487,6 +499,7 @@ export function createChannelApprovalNativeRuntimeAdapter< TPreparedTarget, TPendingEntry, TBinding = unknown, + TFinalPayload = unknown, TPendingView extends PendingApprovalView = PendingApprovalView, TResolvedView extends ResolvedApprovalView = ResolvedApprovalView, TExpiredView extends ExpiredApprovalView = ExpiredApprovalView, @@ -496,11 +509,18 @@ export function createChannelApprovalNativeRuntimeAdapter< TPreparedTarget, TPendingEntry, TBinding, + TFinalPayload, TPendingView, TResolvedView, TExpiredView >, -): ChannelApprovalNativeRuntimeAdapter { +): ChannelApprovalNativeRuntimeAdapter< + TPendingPayload, + TPreparedTarget, + TPendingEntry, + TBinding, + TFinalPayload +> { return { ...(spec.eventKinds ? { eventKinds: spec.eventKinds } : {}), ...(spec.resolveApprovalKind ? { resolveApprovalKind: spec.resolveApprovalKind } : {}), @@ -547,7 +567,7 @@ export function createChannelApprovalNativeRuntimeAdapter< ...(spec.interactions.bindPending ? { bindPending: async (params) => - await spec.interactions?.bindPending?.(params as never), + (await spec.interactions!.bindPending!(params as never)) ?? null, } : {}), ...(spec.interactions.unbindPending diff --git a/src/infra/net/fetch-guard.ssrf.test.ts b/src/infra/net/fetch-guard.ssrf.test.ts index c5beb964650..4ad9d2c4774 100644 --- a/src/infra/net/fetch-guard.ssrf.test.ts +++ b/src/infra/net/fetch-guard.ssrf.test.ts @@ -978,7 +978,9 @@ describe("fetchWithSsrFGuard hardening", () => { fetch: vi.fn(async () => okResponse()), }; const lookupFn: LookupFn = vi.fn(async (hostname: string) => { - if (hostname === "localhost") return [{ address: "127.0.0.1", family: 4 }]; + if (hostname === "localhost") { + return [{ address: "127.0.0.1", family: 4 }]; + } return [{ address: "149.154.167.220", family: 4 }]; }) as unknown as LookupFn; const fetchImpl = vi.fn(async () => okResponse()); @@ -1008,7 +1010,9 @@ describe("fetchWithSsrFGuard hardening", () => { fetch: vi.fn(async () => okResponse()), }; const lookupFn: LookupFn = vi.fn(async (hostname: string) => { - if (hostname === "localhost") return [{ address: "127.0.0.1", family: 4 }]; + if (hostname === "localhost") { + return [{ address: "127.0.0.1", family: 4 }]; + } return [{ address: "149.154.167.220", family: 4 }]; }) as unknown as LookupFn; const fetchImpl = vi.fn();