This commit is contained in:
DeuceBucket 2026-01-30 11:55:31 +00:00 committed by GitHub
commit 40baca12a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 75 additions and 1 deletions

View File

@ -1,5 +1,5 @@
import { chunkText } from "../../../auto-reply/chunk.js";
import { sendMessageSignal } from "../../../signal/send.js";
import { sendMessageSignal, sendPollSignal } from "../../../signal/send.js";
import { resolveChannelMediaMaxBytes } from "../media-limits.js";
import type { ChannelOutboundAdapter } from "../types.js";
@ -8,6 +8,7 @@ export const signalOutbound: ChannelOutboundAdapter = {
chunker: chunkText,
chunkerMode: "text",
textChunkLimit: 4000,
pollMaxOptions: 12,
sendText: async ({ cfg, to, text, accountId, deps }) => {
const send = deps?.sendSignal ?? sendMessageSignal;
const maxBytes = resolveChannelMediaMaxBytes({
@ -37,4 +38,11 @@ export const signalOutbound: ChannelOutboundAdapter = {
});
return { channel: "signal", ...result };
},
sendPoll: async ({ to, poll, accountId }) => {
const result = await sendPollSignal(to, poll.question, poll.options, {
multiSelect: (poll.maxSelections ?? 1) > 1,
accountId: accountId ?? undefined,
});
return { messageId: result.messageId };
},
};

View File

@ -255,3 +255,69 @@ export async function sendReadReceiptSignal(
});
return true;
}
export type SignalPollOpts = SignalRpcOpts & {
/** Allow multiple selections (default: true) */
multiSelect?: boolean;
};
export type SignalPollResult = {
messageId: string;
timestamp?: number;
};
/**
* Create and send a poll to a Signal recipient or group.
*/
export async function sendPollSignal(
to: string,
question: string,
options: string[],
opts: SignalPollOpts = {},
): Promise<SignalPollResult> {
if (!question?.trim()) {
throw new Error("Poll question is required");
}
if (!options || options.length < 2) {
throw new Error("Poll requires at least 2 options");
}
if (options.length > 12) {
throw new Error("Poll cannot have more than 12 options");
}
const { baseUrl, account } = resolveSignalRpcContext(opts);
const target = parseTarget(to);
const targetParams = buildTargetParams(target, {
recipient: true,
group: true,
username: true,
});
if (!targetParams) {
throw new Error("Signal poll recipient is required");
}
const params: Record<string, unknown> = {
question: question.trim(),
option: options.map((o) => o.trim()).filter(Boolean),
...targetParams,
};
if (account) params.account = account;
// signal-cli uses --no-multi to disable multi-select, so we invert the logic
// Default is multi-select allowed (true), pass multiSelect: false to restrict to single choice
if (opts.multiSelect === false) {
params.multiSelect = false;
}
const result = await signalRpcRequest<{ timestamp?: number }>("sendPollCreate", params, {
baseUrl,
timeoutMs: opts.timeoutMs ?? 15_000, // polls may take longer
});
const timestamp = result?.timestamp;
return {
messageId: timestamp ? String(timestamp) : "unknown",
timestamp,
};
}