@openclaw/signal 2026.7.1-beta.1 → 2026.7.1-beta.4
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-hOCHbEhX.js → accounts-Bz4HtP0g.js} +22 -3
- package/dist/api.js +9 -9
- package/dist/approval-auth-CsHNcAiy.js +151 -0
- package/dist/{approval-handler.runtime-C4S7IAvt.js → approval-handler.runtime-DDQ4ZRyc.js} +28 -10
- package/dist/{approval-reactions-H-RPGBK7.js → approval-reactions-UFmUPD0A.js} +155 -37
- package/dist/{channel-aQhurb0Z.js → channel-Cnhy1RwG.js} +162 -59
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-C5skg4Q0.js → channel.runtime-CQN0RaFx.js} +3 -3
- package/dist/{reaction-runtime-api-BRJCLiqK.js → client-adapter-C9mB2Jz8.js} +42 -138
- package/dist/contract-api.js +2 -2
- package/dist/{identity-B6O4k8xg.js → identity-C8-yk4J9.js} +12 -8
- package/dist/{install-signal-cli-TwhJ0DGy.js → install-signal-cli-ik8VPaGg.js} +7 -7
- package/dist/{message-actions-BnugYXjB.js → message-actions-3OLDgjis.js} +7 -30
- package/dist/{monitor-C1gdgT7W.js → monitor-Bee8O5Ay.js} +259 -35
- package/dist/{probe-BvFJLOBi.js → probe-Cnht8Ihg.js} +1 -1
- package/dist/reaction-runtime-api-EQ7cc7-Y.js +115 -0
- package/dist/reaction-runtime-api.js +1 -1
- package/dist/rpc-context-DsHWh2hc.js +17 -0
- package/dist/runtime-api.js +9 -9
- package/dist/{send-De6LIOLq.js → send-CUJy6WPt.js} +84 -10
- package/dist/{send.runtime-BnjSh7QP.js → send.runtime-CEi5oyCG.js} +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/openclaw.plugin.json +150 -0
- package/package.json +4 -4
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { i as resolveSignalAccount, n as listSignalAccountIds, r as resolveDefaultSignalAccountId } from "./accounts-
|
|
2
|
-
import { c as resolveSignalSender, d as normalizeSignalMessagingTarget, l as looksLikeUuid, o as resolveSignalPeerId, s as resolveSignalRecipient, u as looksLikeSignalTargetId } from "./identity-
|
|
3
|
-
import { i as
|
|
1
|
+
import { a as resolveSignalReplyToMode, i as resolveSignalAccount, n as listSignalAccountIds, r as resolveDefaultSignalAccountId } from "./accounts-Bz4HtP0g.js";
|
|
2
|
+
import { c as resolveSignalSender, d as normalizeSignalMessagingTarget, l as looksLikeUuid, o as resolveSignalPeerId, s as resolveSignalRecipient, u as looksLikeSignalTargetId } from "./identity-C8-yk4J9.js";
|
|
3
|
+
import { i as resolveSignalTarget, r as listSignalAliasDirectoryEntries } from "./approval-auth-CsHNcAiy.js";
|
|
4
|
+
import { i as markdownToSignalTextChunks, n as resolveSignalReactionLevel, o as shouldSuppressLocalSignalExecApprovalPrompt, s as signalApprovalCapability, t as signalMessageActions } from "./message-actions-3OLDgjis.js";
|
|
4
5
|
import { t as SignalChannelConfigSchema } from "./config-schema-BiojLEsX.js";
|
|
5
6
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
|
|
6
7
|
import { buildDmGroupAccountAllowlistAdapter } from "openclaw/plugin-sdk/allowlist-config-edit";
|
|
7
8
|
import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
8
9
|
import { defineChannelMessageAdapter, resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-outbound";
|
|
9
10
|
import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
|
|
10
|
-
import { attachChannelToResult
|
|
11
|
+
import { attachChannelToResult } from "openclaw/plugin-sdk/channel-send-result";
|
|
11
12
|
import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
|
|
13
|
+
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
12
14
|
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
13
15
|
import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime";
|
|
14
16
|
import { chunkText, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-chunking";
|
|
@@ -72,7 +74,10 @@ const INVALID_SIGNAL_ACCOUNT_ERROR = "Invalid E.164 phone number (must start wit
|
|
|
72
74
|
function normalizeSignalAccountInput(value) {
|
|
73
75
|
const trimmed = normalizeOptionalString(value);
|
|
74
76
|
if (!trimmed) return null;
|
|
75
|
-
const
|
|
77
|
+
const phoneInput = trimmed.replace(/^signal:/i, "").trim();
|
|
78
|
+
const plusCount = phoneInput.match(/\+/g)?.length ?? 0;
|
|
79
|
+
if (plusCount > 1 || plusCount === 1 && !phoneInput.startsWith("+")) return null;
|
|
80
|
+
const digits = normalizeE164(phoneInput).slice(1);
|
|
76
81
|
if (!DIGITS_ONLY.test(digits)) return null;
|
|
77
82
|
if (digits.length < MIN_E164_DIGITS || digits.length > MAX_E164_DIGITS) return null;
|
|
78
83
|
return `+${digits}`;
|
|
@@ -235,27 +240,45 @@ function createSignalSetupWizardProxy(loadWizard) {
|
|
|
235
240
|
//#region extensions/signal/src/shared.ts
|
|
236
241
|
const SIGNAL_CHANNEL = "signal";
|
|
237
242
|
async function loadSignalChannelRuntime() {
|
|
238
|
-
return await import("./channel.runtime-
|
|
243
|
+
return await import("./channel.runtime-CQN0RaFx.js");
|
|
239
244
|
}
|
|
240
245
|
const signalSetupWizard = createSignalSetupWizardProxy(async () => (await loadSignalChannelRuntime()).signalSetupWizard);
|
|
241
|
-
const signalConfigAdapter =
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
246
|
+
const signalConfigAdapter = {
|
|
247
|
+
...createScopedChannelConfigAdapter({
|
|
248
|
+
sectionKey: SIGNAL_CHANNEL,
|
|
249
|
+
listAccountIds: (cfg) => listSignalAccountIds(cfg),
|
|
250
|
+
resolveAccount: adaptScopedAccountAccessor((params) => resolveSignalAccount(params)),
|
|
251
|
+
defaultAccountId: (cfg) => resolveDefaultSignalAccountId(cfg),
|
|
252
|
+
clearBaseFields: [
|
|
253
|
+
"account",
|
|
254
|
+
"configPath",
|
|
255
|
+
"httpUrl",
|
|
256
|
+
"httpHost",
|
|
257
|
+
"httpPort",
|
|
258
|
+
"cliPath",
|
|
259
|
+
"name"
|
|
260
|
+
],
|
|
261
|
+
resolveAllowFrom: (account) => account.config.allowFrom,
|
|
262
|
+
formatAllowFrom: (allowFrom) => normalizeStringifiedEntries(allowFrom).map((entry) => entry === "*" ? "*" : normalizeE164(entry.replace(/^signal:/i, ""))).filter(Boolean),
|
|
263
|
+
resolveDefaultTo: (account) => account.config.defaultTo
|
|
264
|
+
}),
|
|
265
|
+
resolveDefaultTo({ cfg, accountId }) {
|
|
266
|
+
const raw = resolveSignalAccount({
|
|
267
|
+
cfg,
|
|
268
|
+
accountId
|
|
269
|
+
}).config.defaultTo;
|
|
270
|
+
if (typeof raw !== "string" || !raw.trim()) return;
|
|
271
|
+
try {
|
|
272
|
+
return resolveSignalTarget({
|
|
273
|
+
cfg,
|
|
274
|
+
accountId,
|
|
275
|
+
input: raw
|
|
276
|
+
})?.to ?? raw.trim();
|
|
277
|
+
} catch {
|
|
278
|
+
return raw.trim();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
};
|
|
259
282
|
const signalSecurityAdapter = createRestrictSendersChannelSecurity({
|
|
260
283
|
channelKey: SIGNAL_CHANNEL,
|
|
261
284
|
resolveDmPolicy: (account) => account.config.dmPolicy,
|
|
@@ -303,26 +326,10 @@ function createSignalPluginBase(params) {
|
|
|
303
326
|
}
|
|
304
327
|
//#endregion
|
|
305
328
|
//#region extensions/signal/src/channel.ts
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
async function loadSignalMonitorModule() {
|
|
311
|
-
signalMonitorModulePromise ??= import("./monitor-C1gdgT7W.js").then((n) => n.n);
|
|
312
|
-
return await signalMonitorModulePromise;
|
|
313
|
-
}
|
|
314
|
-
async function loadSignalProbeModule() {
|
|
315
|
-
signalProbeModulePromise ??= import("./probe-BvFJLOBi.js").then((n) => n.n);
|
|
316
|
-
return await signalProbeModulePromise;
|
|
317
|
-
}
|
|
318
|
-
async function loadSignalSendRuntime() {
|
|
319
|
-
signalSendRuntimePromise ??= import("./send.runtime-BnjSh7QP.js");
|
|
320
|
-
return await signalSendRuntimePromise;
|
|
321
|
-
}
|
|
322
|
-
async function loadSignalApprovalReactionsModule() {
|
|
323
|
-
signalApprovalReactionsModulePromise ??= import("./approval-reactions-H-RPGBK7.js").then((n) => n.n);
|
|
324
|
-
return await signalApprovalReactionsModulePromise;
|
|
325
|
-
}
|
|
329
|
+
const loadSignalMonitorModule = createLazyRuntimeModule(() => import("./monitor-Bee8O5Ay.js").then((n) => n.n));
|
|
330
|
+
const loadSignalProbeModule = createLazyRuntimeModule(() => import("./probe-Cnht8Ihg.js").then((n) => n.n));
|
|
331
|
+
const loadSignalSendRuntime = createLazyRuntimeModule(() => import("./send.runtime-CEi5oyCG.js"));
|
|
332
|
+
const loadSignalApprovalReactionsModule = createLazyRuntimeModule(() => import("./approval-reactions-UFmUPD0A.js").then((n) => n.r));
|
|
326
333
|
async function resolveSignalSendContext(params) {
|
|
327
334
|
return {
|
|
328
335
|
send: resolveOutboundSendDep(params.deps, "signal") ?? (await loadSignalSendRuntime()).sendMessageSignal,
|
|
@@ -333,9 +340,16 @@ async function resolveSignalSendContext(params) {
|
|
|
333
340
|
})
|
|
334
341
|
};
|
|
335
342
|
}
|
|
343
|
+
function resolveSignalSendTarget(params) {
|
|
344
|
+
return resolveSignalTarget({
|
|
345
|
+
cfg: params.cfg,
|
|
346
|
+
accountId: params.accountId,
|
|
347
|
+
input: params.to
|
|
348
|
+
})?.to ?? params.to.trim();
|
|
349
|
+
}
|
|
336
350
|
async function sendSignalOutbound(params) {
|
|
337
351
|
const { send, maxBytes } = await resolveSignalSendContext(params);
|
|
338
|
-
return await send(params
|
|
352
|
+
return await send(resolveSignalSendTarget(params), params.text, {
|
|
339
353
|
cfg: params.cfg,
|
|
340
354
|
...params.mediaUrl ? { mediaUrl: params.mediaUrl } : {},
|
|
341
355
|
...params.mediaLocalRoots?.length ? { mediaLocalRoots: params.mediaLocalRoots } : {},
|
|
@@ -397,8 +411,11 @@ function buildSignalBaseSessionKey(params) {
|
|
|
397
411
|
});
|
|
398
412
|
}
|
|
399
413
|
function resolveSignalOutboundSessionRoute(params) {
|
|
400
|
-
const
|
|
414
|
+
const target = params.resolvedTarget?.to ?? params.target;
|
|
415
|
+
const resolved = resolveSignalOutboundTarget(target);
|
|
401
416
|
if (!resolved) return null;
|
|
417
|
+
const normalizedTarget = target.replace(/^signal:/i, "").trim();
|
|
418
|
+
const recipientSessionExact = resolved.chatType === "group" || /^\+?\d{3,15}$/.test(normalizedTarget) ? true : "direct-alias";
|
|
402
419
|
const baseSessionKey = buildSignalBaseSessionKey({
|
|
403
420
|
cfg: params.cfg,
|
|
404
421
|
agentId: params.agentId,
|
|
@@ -408,6 +425,7 @@ function resolveSignalOutboundSessionRoute(params) {
|
|
|
408
425
|
return {
|
|
409
426
|
sessionKey: baseSessionKey,
|
|
410
427
|
baseSessionKey,
|
|
428
|
+
recipientSessionExact,
|
|
411
429
|
...resolved
|
|
412
430
|
};
|
|
413
431
|
}
|
|
@@ -418,6 +436,11 @@ async function sendFormattedSignalText(ctx) {
|
|
|
418
436
|
deps: ctx.deps
|
|
419
437
|
});
|
|
420
438
|
const limit = resolveTextChunkLimit(ctx.cfg, "signal", ctx.accountId ?? void 0, { fallbackLimit: 4e3 });
|
|
439
|
+
const to = resolveSignalSendTarget({
|
|
440
|
+
cfg: ctx.cfg,
|
|
441
|
+
accountId: ctx.accountId ?? void 0,
|
|
442
|
+
to: ctx.to
|
|
443
|
+
});
|
|
421
444
|
const tableMode = resolveMarkdownTableMode({
|
|
422
445
|
cfg: ctx.cfg,
|
|
423
446
|
channel: "signal",
|
|
@@ -431,16 +454,17 @@ async function sendFormattedSignalText(ctx) {
|
|
|
431
454
|
const results = [];
|
|
432
455
|
for (const chunk of chunks) {
|
|
433
456
|
ctx.abortSignal?.throwIfAborted();
|
|
434
|
-
const
|
|
457
|
+
const deliveryResult = attachChannelToResult("signal", attachSignalVisibleText(await send(to, chunk.text, {
|
|
435
458
|
cfg: ctx.cfg,
|
|
436
459
|
maxBytes,
|
|
437
460
|
accountId: ctx.accountId ?? void 0,
|
|
438
461
|
textMode: "plain",
|
|
439
462
|
textStyles: chunk.styles
|
|
440
|
-
});
|
|
441
|
-
results.push(
|
|
463
|
+
}), chunk.text));
|
|
464
|
+
results.push(deliveryResult);
|
|
465
|
+
await ctx.onDeliveryResult?.(deliveryResult);
|
|
442
466
|
}
|
|
443
|
-
return
|
|
467
|
+
return results;
|
|
444
468
|
}
|
|
445
469
|
async function sendFormattedSignalMedia(ctx) {
|
|
446
470
|
ctx.abortSignal?.throwIfAborted();
|
|
@@ -449,6 +473,11 @@ async function sendFormattedSignalMedia(ctx) {
|
|
|
449
473
|
accountId: ctx.accountId ?? void 0,
|
|
450
474
|
deps: ctx.deps
|
|
451
475
|
});
|
|
476
|
+
const to = resolveSignalSendTarget({
|
|
477
|
+
cfg: ctx.cfg,
|
|
478
|
+
accountId: ctx.accountId ?? void 0,
|
|
479
|
+
to: ctx.to
|
|
480
|
+
});
|
|
452
481
|
const tableMode = resolveMarkdownTableMode({
|
|
453
482
|
cfg: ctx.cfg,
|
|
454
483
|
channel: "signal",
|
|
@@ -458,7 +487,7 @@ async function sendFormattedSignalMedia(ctx) {
|
|
|
458
487
|
text: ctx.text,
|
|
459
488
|
styles: []
|
|
460
489
|
};
|
|
461
|
-
return attachChannelToResult("signal", attachSignalVisibleText(await send(
|
|
490
|
+
return attachChannelToResult("signal", attachSignalVisibleText(await send(to, formatted.text, {
|
|
462
491
|
cfg: ctx.cfg,
|
|
463
492
|
mediaUrl: ctx.mediaUrl,
|
|
464
493
|
mediaLocalRoots: ctx.mediaLocalRoots,
|
|
@@ -474,14 +503,20 @@ async function registerDeliveredSignalApprovalPayloadForReactions(params) {
|
|
|
474
503
|
cfg: params.cfg,
|
|
475
504
|
accountId: params.target.accountId ?? void 0
|
|
476
505
|
});
|
|
477
|
-
|
|
506
|
+
const targetAuthor = normalizeOptionalString(account.config.account);
|
|
507
|
+
const targetAuthorUuid = normalizeOptionalString(account.config.accountUuid);
|
|
508
|
+
if (!targetAuthor && !targetAuthorUuid) return;
|
|
478
509
|
const { registerSignalApprovalReactionTargetForDeliveredPayload } = await loadSignalApprovalReactionsModule();
|
|
479
510
|
registerSignalApprovalReactionTargetForDeliveredPayload({
|
|
480
511
|
cfg: params.cfg,
|
|
481
|
-
target:
|
|
512
|
+
target: {
|
|
513
|
+
...params.target,
|
|
514
|
+
accountId: account.accountId
|
|
515
|
+
},
|
|
482
516
|
payload: params.payload,
|
|
483
517
|
results: params.results,
|
|
484
|
-
targetAuthor
|
|
518
|
+
targetAuthor,
|
|
519
|
+
targetAuthorUuid
|
|
485
520
|
});
|
|
486
521
|
}
|
|
487
522
|
async function renderSignalApprovalPayloadForReactions(params) {
|
|
@@ -489,14 +524,17 @@ async function renderSignalApprovalPayloadForReactions(params) {
|
|
|
489
524
|
cfg: params.ctx.cfg,
|
|
490
525
|
accountId: params.ctx.accountId ?? void 0
|
|
491
526
|
});
|
|
492
|
-
|
|
527
|
+
const targetAuthor = normalizeOptionalString(account.config.account);
|
|
528
|
+
const targetAuthorUuid = normalizeOptionalString(account.config.accountUuid);
|
|
529
|
+
if (!targetAuthor && !targetAuthorUuid) return null;
|
|
493
530
|
const { addSignalApprovalReactionHintToStructuredPayload } = await loadSignalApprovalReactionsModule();
|
|
494
531
|
return addSignalApprovalReactionHintToStructuredPayload({
|
|
495
532
|
cfg: params.ctx.cfg,
|
|
496
533
|
accountId: params.ctx.accountId ?? void 0,
|
|
497
534
|
to: params.ctx.to,
|
|
498
535
|
payload: params.payload,
|
|
499
|
-
targetAuthor
|
|
536
|
+
targetAuthor,
|
|
537
|
+
targetAuthorUuid
|
|
500
538
|
});
|
|
501
539
|
}
|
|
502
540
|
const signalPlugin = createChatChannelPlugin({
|
|
@@ -537,9 +575,44 @@ const signalPlugin = createChatChannelPlugin({
|
|
|
537
575
|
resolveOutboundSessionRoute: (params) => resolveSignalOutboundSessionRoute(params),
|
|
538
576
|
targetResolver: {
|
|
539
577
|
looksLikeId: looksLikeSignalTargetId,
|
|
540
|
-
hint: "<E.164|uuid:ID|group:ID|signal:group:ID|signal:+E.164>"
|
|
578
|
+
hint: "<E.164|uuid:ID|group:ID|signal:group:ID|signal:+E.164>",
|
|
579
|
+
resolveTarget: async ({ cfg, accountId, input }) => {
|
|
580
|
+
let target;
|
|
581
|
+
try {
|
|
582
|
+
target = resolveSignalTarget({
|
|
583
|
+
cfg,
|
|
584
|
+
accountId,
|
|
585
|
+
input
|
|
586
|
+
});
|
|
587
|
+
} catch {
|
|
588
|
+
return null;
|
|
589
|
+
}
|
|
590
|
+
if (!target) return null;
|
|
591
|
+
return {
|
|
592
|
+
to: target.to,
|
|
593
|
+
kind: target.kind,
|
|
594
|
+
display: target.source === "alias" ? target.alias : void 0,
|
|
595
|
+
source: target.source === "alias" ? "directory" : "normalized"
|
|
596
|
+
};
|
|
597
|
+
}
|
|
541
598
|
}
|
|
542
599
|
},
|
|
600
|
+
directory: {
|
|
601
|
+
listPeers: async ({ cfg, accountId, query, limit }) => listSignalAliasDirectoryEntries({
|
|
602
|
+
cfg,
|
|
603
|
+
accountId,
|
|
604
|
+
query,
|
|
605
|
+
limit,
|
|
606
|
+
kind: "user"
|
|
607
|
+
}),
|
|
608
|
+
listGroups: async ({ cfg, accountId, query, limit }) => listSignalAliasDirectoryEntries({
|
|
609
|
+
cfg,
|
|
610
|
+
accountId,
|
|
611
|
+
query,
|
|
612
|
+
limit,
|
|
613
|
+
kind: "group"
|
|
614
|
+
})
|
|
615
|
+
},
|
|
543
616
|
heartbeat: {
|
|
544
617
|
sendTyping: async ({ cfg, to, accountId }) => {
|
|
545
618
|
await (await loadSignalSendRuntime()).sendTypingSignal(to, {
|
|
@@ -605,9 +678,38 @@ const signalPlugin = createChatChannelPlugin({
|
|
|
605
678
|
}
|
|
606
679
|
} },
|
|
607
680
|
security: signalSecurityAdapter,
|
|
681
|
+
threading: { resolveReplyToMode: (params) => resolveSignalReplyToMode(params) },
|
|
608
682
|
outbound: {
|
|
609
683
|
base: {
|
|
610
684
|
deliveryMode: "direct",
|
|
685
|
+
resolveTarget: ({ cfg, to, accountId }) => {
|
|
686
|
+
const raw = to?.trim();
|
|
687
|
+
if (!raw) return {
|
|
688
|
+
ok: false,
|
|
689
|
+
error: /* @__PURE__ */ new Error("Signal target is required")
|
|
690
|
+
};
|
|
691
|
+
let target;
|
|
692
|
+
try {
|
|
693
|
+
target = resolveSignalTarget({
|
|
694
|
+
cfg: cfg ?? {},
|
|
695
|
+
accountId,
|
|
696
|
+
input: raw
|
|
697
|
+
});
|
|
698
|
+
} catch (error) {
|
|
699
|
+
return {
|
|
700
|
+
ok: false,
|
|
701
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
if (!target) return {
|
|
705
|
+
ok: false,
|
|
706
|
+
error: /* @__PURE__ */ new Error(`Unknown Signal alias or target "${raw}". Configure channels.signal.aliases.${raw.replace(/^signal:/i, "")} or use E.164, uuid:<id>, username:<name>, or group:<id>.`)
|
|
707
|
+
};
|
|
708
|
+
return {
|
|
709
|
+
ok: true,
|
|
710
|
+
to: target.to
|
|
711
|
+
};
|
|
712
|
+
},
|
|
611
713
|
chunker: chunkText,
|
|
612
714
|
chunkerMode: "text",
|
|
613
715
|
textChunkLimit: 4e3,
|
|
@@ -620,13 +722,14 @@ const signalPlugin = createChatChannelPlugin({
|
|
|
620
722
|
}),
|
|
621
723
|
afterDeliverPayload: async (params) => await registerDeliveredSignalApprovalPayloadForReactions(params),
|
|
622
724
|
renderPresentation: async (params) => await renderSignalApprovalPayloadForReactions(params),
|
|
623
|
-
sendFormattedText: async ({ cfg, to, text, accountId, deps, abortSignal }) => await sendFormattedSignalText({
|
|
725
|
+
sendFormattedText: async ({ cfg, to, text, accountId, deps, abortSignal, onDeliveryResult }) => await sendFormattedSignalText({
|
|
624
726
|
cfg,
|
|
625
727
|
to,
|
|
626
728
|
text,
|
|
627
729
|
accountId,
|
|
628
730
|
deps,
|
|
629
|
-
abortSignal
|
|
731
|
+
abortSignal,
|
|
732
|
+
onDeliveryResult
|
|
630
733
|
}),
|
|
631
734
|
sendFormattedMedia: async ({ cfg, to, text, mediaUrl, mediaLocalRoots, mediaReadFile, accountId, deps, abortSignal }) => await sendFormattedSignalMedia({
|
|
632
735
|
cfg,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as signalPlugin } from "./channel-
|
|
1
|
+
import { t as signalPlugin } from "./channel-Cnhy1RwG.js";
|
|
2
2
|
export { signalPlugin };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { i as resolveSignalAccount, n as listSignalAccountIds } from "./accounts-
|
|
2
|
-
import { c as signalNumberTextInput, i as createSignalCliPathTextInput, o as signalCompletionNote, s as signalDmPolicy } from "./channel-
|
|
3
|
-
import { r as installSignalCli } from "./install-signal-cli-
|
|
1
|
+
import { i as resolveSignalAccount, n as listSignalAccountIds } from "./accounts-Bz4HtP0g.js";
|
|
2
|
+
import { c as signalNumberTextInput, i as createSignalCliPathTextInput, o as signalCompletionNote, s as signalDmPolicy } from "./channel-Cnhy1RwG.js";
|
|
3
|
+
import { r as installSignalCli } from "./install-signal-cli-ik8VPaGg.js";
|
|
4
4
|
import { detectBinary } from "openclaw/plugin-sdk/setup-tools";
|
|
5
5
|
import { createDetectedBinaryStatus, createSetupTranslator, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
|
|
6
6
|
//#region extensions/signal/src/setup-surface.ts
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import { i as resolveSignalAccount } from "./accounts-hOCHbEhX.js";
|
|
2
1
|
import { detectMime, parseMediaContentLength } from "openclaw/plugin-sdk/media-runtime";
|
|
3
|
-
import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
4
2
|
import { asDateTimestampMs, parseStrictNonNegativeInteger, resolveExpiresAtMsFromDurationMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
5
|
-
import
|
|
6
|
-
import fs from "node:fs/promises";
|
|
7
|
-
import path from "node:path";
|
|
3
|
+
import nodePath from "node:path";
|
|
8
4
|
import { resolveFetch } from "openclaw/plugin-sdk/fetch-runtime";
|
|
9
5
|
import { readProviderTextResponse, readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
|
|
10
6
|
import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
|
|
7
|
+
import { readRegularFile } from "openclaw/plugin-sdk/security-runtime";
|
|
11
8
|
import WebSocket from "ws";
|
|
12
9
|
import { Buffer as Buffer$1 } from "node:buffer";
|
|
13
10
|
import http from "node:http";
|
|
@@ -24,6 +21,8 @@ import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
|
24
21
|
*/
|
|
25
22
|
const DEFAULT_TIMEOUT_MS$2 = 1e4;
|
|
26
23
|
const DEFAULT_ATTACHMENT_RESPONSE_MAX_BYTES = 1048576;
|
|
24
|
+
const SIGNAL_CONTAINER_WS_MAX_PAYLOAD_BYTES = 1024 * 1024;
|
|
25
|
+
const DEFAULT_SIGNAL_CONTAINER_MAX_ATTACHMENT_BYTES = 8 * 1024 * 1024;
|
|
27
26
|
const CONTAINER_TEXT_STYLE_MARKERS = {
|
|
28
27
|
BOLD: "**",
|
|
29
28
|
ITALIC: "*",
|
|
@@ -123,7 +122,7 @@ function containerReceiveCheck(normalizedBaseUrl, account, timeoutMs) {
|
|
|
123
122
|
resolve(result);
|
|
124
123
|
};
|
|
125
124
|
try {
|
|
126
|
-
ws = new WebSocket(wsUrl);
|
|
125
|
+
ws = new WebSocket(wsUrl, { maxPayload: SIGNAL_CONTAINER_WS_MAX_PAYLOAD_BYTES });
|
|
127
126
|
} catch (err) {
|
|
128
127
|
settle({
|
|
129
128
|
ok: false,
|
|
@@ -156,10 +155,11 @@ function containerReceiveCheck(normalizedBaseUrl, account, timeoutMs) {
|
|
|
156
155
|
});
|
|
157
156
|
});
|
|
158
157
|
ws.once("close", (code, reason) => {
|
|
158
|
+
const reasonText = reason.length > 0 ? `: ${reason.toString("utf8")}` : "";
|
|
159
159
|
settle({
|
|
160
160
|
ok: false,
|
|
161
161
|
status: null,
|
|
162
|
-
error: `Signal container receive WebSocket closed before open (${code}${
|
|
162
|
+
error: `Signal container receive WebSocket closed before open (${code}${reasonText})`
|
|
163
163
|
});
|
|
164
164
|
});
|
|
165
165
|
});
|
|
@@ -227,7 +227,7 @@ async function streamContainerEvents(params) {
|
|
|
227
227
|
}
|
|
228
228
|
};
|
|
229
229
|
try {
|
|
230
|
-
ws = new WebSocket(wsUrl);
|
|
230
|
+
ws = new WebSocket(wsUrl, { maxPayload: SIGNAL_CONTAINER_WS_MAX_PAYLOAD_BYTES });
|
|
231
231
|
} catch (err) {
|
|
232
232
|
logError(`[signal-ws] failed to create WebSocket: ${err instanceof Error ? err.message : String(err)}`);
|
|
233
233
|
reject(toLintErrorObject$1(err, "Non-Error rejection"));
|
|
@@ -249,7 +249,8 @@ async function streamContainerEvents(params) {
|
|
|
249
249
|
logError(`[signal-ws] error: ${err instanceof Error ? err.message : String(err)}`);
|
|
250
250
|
});
|
|
251
251
|
ws.on("close", (code, reason) => {
|
|
252
|
-
|
|
252
|
+
const reasonStr = reason?.toString() || "no reason";
|
|
253
|
+
log(`[signal-ws] closed (code=${code}, reason=${reasonStr})`);
|
|
253
254
|
cleanup();
|
|
254
255
|
resolve();
|
|
255
256
|
});
|
|
@@ -274,15 +275,20 @@ async function streamContainerEvents(params) {
|
|
|
274
275
|
* Convert local file paths to base64 data URIs for the container REST API.
|
|
275
276
|
* The bbernhard container /v2/send only accepts `base64_attachments` (not file paths).
|
|
276
277
|
*/
|
|
277
|
-
async function filesToBase64DataUris(filePaths) {
|
|
278
|
+
async function filesToBase64DataUris(filePaths, maxAttachmentBytes) {
|
|
278
279
|
const results = [];
|
|
280
|
+
let remainingBytes = maxAttachmentBytes;
|
|
279
281
|
for (const filePath of filePaths) {
|
|
280
|
-
const buffer = await
|
|
282
|
+
const { buffer } = await readRegularFile({
|
|
283
|
+
filePath,
|
|
284
|
+
maxBytes: remainingBytes
|
|
285
|
+
});
|
|
286
|
+
remainingBytes -= buffer.byteLength;
|
|
281
287
|
const mime = await detectMime({
|
|
282
288
|
buffer,
|
|
283
289
|
filePath
|
|
284
290
|
}) ?? "application/octet-stream";
|
|
285
|
-
const filename =
|
|
291
|
+
const filename = nodePath.basename(filePath);
|
|
286
292
|
const b64 = buffer.toString("base64");
|
|
287
293
|
results.push(`data:${mime};filename=${filename};base64,${b64}`);
|
|
288
294
|
}
|
|
@@ -305,7 +311,7 @@ function renderContainerStyledText(text, styles) {
|
|
|
305
311
|
};
|
|
306
312
|
}).filter((span) => span !== null);
|
|
307
313
|
if (spans.length === 0) return text;
|
|
308
|
-
const positions = [
|
|
314
|
+
const positions = [.../* @__PURE__ */ new Set([
|
|
309
315
|
0,
|
|
310
316
|
text.length,
|
|
311
317
|
...spans.flatMap((span) => [span.start, span.end])
|
|
@@ -326,6 +332,12 @@ function parseContainerSendTimestamp(raw) {
|
|
|
326
332
|
if (timestamp === void 0) throw new Error("Signal REST send returned invalid timestamp");
|
|
327
333
|
return timestamp;
|
|
328
334
|
}
|
|
335
|
+
function normalizeContainerQuoteTimestamp(raw) {
|
|
336
|
+
return parseStrictNonNegativeInteger(raw) ?? void 0;
|
|
337
|
+
}
|
|
338
|
+
function normalizeContainerQuoteText(raw) {
|
|
339
|
+
return typeof raw === "string" ? raw : void 0;
|
|
340
|
+
}
|
|
329
341
|
/**
|
|
330
342
|
* Send message via bbernhard container REST API.
|
|
331
343
|
*/
|
|
@@ -339,7 +351,16 @@ async function containerSendMessage(params) {
|
|
|
339
351
|
payload.message = renderContainerStyledText(params.message, params.textStyles);
|
|
340
352
|
payload["text_mode"] = "styled";
|
|
341
353
|
}
|
|
342
|
-
if (params.attachments && params.attachments.length > 0)
|
|
354
|
+
if (params.attachments && params.attachments.length > 0) {
|
|
355
|
+
const configuredMaxBytes = params.maxAttachmentBytes;
|
|
356
|
+
const maxAttachmentBytes = typeof configuredMaxBytes === "number" && Number.isFinite(configuredMaxBytes) && configuredMaxBytes >= 0 ? Math.floor(configuredMaxBytes) : DEFAULT_SIGNAL_CONTAINER_MAX_ATTACHMENT_BYTES;
|
|
357
|
+
payload.base64_attachments = await filesToBase64DataUris(params.attachments, maxAttachmentBytes);
|
|
358
|
+
}
|
|
359
|
+
if (params.quoteTimestamp !== void 0 && params.quoteAuthor) {
|
|
360
|
+
payload.quote_timestamp = params.quoteTimestamp;
|
|
361
|
+
payload.quote_author = params.quoteAuthor;
|
|
362
|
+
payload.quote_message = params.quoteMessage ?? "";
|
|
363
|
+
}
|
|
343
364
|
const timestamp = parseContainerSendTimestamp((await containerRestRequest("/v2/send", {
|
|
344
365
|
baseUrl: params.baseUrl,
|
|
345
366
|
timeoutMs: params.timeoutMs
|
|
@@ -440,6 +461,8 @@ async function containerRpcRequest(method, params, opts) {
|
|
|
440
461
|
style
|
|
441
462
|
};
|
|
442
463
|
});
|
|
464
|
+
const quoteTimestamp = normalizeContainerQuoteTimestamp(p.quoteTimestamp ?? p["quote-timestamp"]);
|
|
465
|
+
const quoteAuthor = normalizeContainerQuoteText(p.quoteAuthor ?? p["quote-author"]);
|
|
443
466
|
return await containerSendMessage({
|
|
444
467
|
baseUrl: opts.baseUrl,
|
|
445
468
|
account: p.account ?? "",
|
|
@@ -447,6 +470,10 @@ async function containerRpcRequest(method, params, opts) {
|
|
|
447
470
|
message: p.message ?? "",
|
|
448
471
|
textStyles,
|
|
449
472
|
attachments: p.attachments,
|
|
473
|
+
maxAttachmentBytes: opts.maxAttachmentBytes,
|
|
474
|
+
quoteTimestamp,
|
|
475
|
+
quoteAuthor: quoteAuthor ? stripUuidPrefix(quoteAuthor) : void 0,
|
|
476
|
+
quoteMessage: normalizeContainerQuoteText(p.quoteMessage ?? p["quote-message"]),
|
|
450
477
|
timeoutMs: opts.timeoutMs
|
|
451
478
|
});
|
|
452
479
|
}
|
|
@@ -953,127 +980,4 @@ async function streamSignalEvents(params) {
|
|
|
953
980
|
});
|
|
954
981
|
}
|
|
955
982
|
//#endregion
|
|
956
|
-
|
|
957
|
-
function resolveSignalRpcContext(opts, accountInfo) {
|
|
958
|
-
const hasBaseUrl = Boolean(normalizeOptionalString(opts.baseUrl));
|
|
959
|
-
const hasAccount = Boolean(normalizeOptionalString(opts.account));
|
|
960
|
-
if ((!hasBaseUrl || !hasAccount) && !accountInfo) throw new Error("Signal account config is required when baseUrl or account is missing");
|
|
961
|
-
const resolvedAccount = accountInfo;
|
|
962
|
-
const baseUrl = normalizeOptionalString(opts.baseUrl) ?? resolvedAccount?.baseUrl;
|
|
963
|
-
if (!baseUrl) throw new Error("Signal base URL is required");
|
|
964
|
-
return {
|
|
965
|
-
baseUrl,
|
|
966
|
-
account: normalizeOptionalString(opts.account) ?? normalizeOptionalString(resolvedAccount?.config.account)
|
|
967
|
-
};
|
|
968
|
-
}
|
|
969
|
-
//#endregion
|
|
970
|
-
//#region extensions/signal/src/send-reactions.ts
|
|
971
|
-
function normalizeSignalId(raw) {
|
|
972
|
-
const trimmed = raw.trim();
|
|
973
|
-
if (!trimmed) return "";
|
|
974
|
-
return trimmed.replace(/^signal:/i, "").trim();
|
|
975
|
-
}
|
|
976
|
-
function normalizeSignalUuid(raw) {
|
|
977
|
-
const trimmed = normalizeSignalId(raw);
|
|
978
|
-
if (!trimmed) return "";
|
|
979
|
-
if (normalizeLowercaseStringOrEmpty(trimmed).startsWith("uuid:")) return trimmed.slice(5).trim();
|
|
980
|
-
return trimmed;
|
|
981
|
-
}
|
|
982
|
-
function resolveTargetAuthorParams(params) {
|
|
983
|
-
const candidates = [
|
|
984
|
-
params.targetAuthor,
|
|
985
|
-
params.targetAuthorUuid,
|
|
986
|
-
params.fallback
|
|
987
|
-
];
|
|
988
|
-
for (const candidate of candidates) {
|
|
989
|
-
const raw = candidate?.trim();
|
|
990
|
-
if (!raw) continue;
|
|
991
|
-
const normalized = normalizeSignalUuid(raw);
|
|
992
|
-
if (normalized) return { targetAuthor: normalized };
|
|
993
|
-
}
|
|
994
|
-
return {};
|
|
995
|
-
}
|
|
996
|
-
async function sendReactionSignalCore(params) {
|
|
997
|
-
const cfg = requireRuntimeConfig(params.opts.cfg, "Signal reactions");
|
|
998
|
-
const apiMode = cfg.channels?.signal?.apiMode;
|
|
999
|
-
const accountInfo = resolveSignalAccount({
|
|
1000
|
-
cfg,
|
|
1001
|
-
accountId: params.opts.accountId
|
|
1002
|
-
});
|
|
1003
|
-
const { baseUrl, account } = resolveSignalRpcContext(params.opts, accountInfo);
|
|
1004
|
-
const normalizedRecipient = normalizeSignalUuid(params.recipient);
|
|
1005
|
-
const groupId = params.opts.groupId?.trim();
|
|
1006
|
-
if (!normalizedRecipient && !groupId) throw new Error(params.errors.missingRecipient);
|
|
1007
|
-
if (!Number.isFinite(params.targetTimestamp) || params.targetTimestamp <= 0) throw new Error(params.errors.invalidTargetTimestamp);
|
|
1008
|
-
const normalizedEmoji = params.emoji?.trim();
|
|
1009
|
-
if (!normalizedEmoji) throw new Error(params.errors.missingEmoji);
|
|
1010
|
-
const targetAuthorParams = resolveTargetAuthorParams({
|
|
1011
|
-
targetAuthor: params.opts.targetAuthor,
|
|
1012
|
-
targetAuthorUuid: params.opts.targetAuthorUuid,
|
|
1013
|
-
fallback: normalizedRecipient
|
|
1014
|
-
});
|
|
1015
|
-
if (groupId && !targetAuthorParams.targetAuthor) throw new Error(params.errors.missingTargetAuthor);
|
|
1016
|
-
const requestParams = {
|
|
1017
|
-
emoji: normalizedEmoji,
|
|
1018
|
-
targetTimestamp: params.targetTimestamp,
|
|
1019
|
-
...params.remove ? { remove: true } : {},
|
|
1020
|
-
...targetAuthorParams
|
|
1021
|
-
};
|
|
1022
|
-
if (normalizedRecipient) requestParams.recipients = [normalizedRecipient];
|
|
1023
|
-
if (groupId) requestParams.groupIds = [groupId];
|
|
1024
|
-
if (account) requestParams.account = account;
|
|
1025
|
-
return {
|
|
1026
|
-
ok: true,
|
|
1027
|
-
timestamp: (await signalRpcRequest("sendReaction", requestParams, {
|
|
1028
|
-
baseUrl,
|
|
1029
|
-
timeoutMs: params.opts.timeoutMs,
|
|
1030
|
-
apiMode
|
|
1031
|
-
}))?.timestamp
|
|
1032
|
-
};
|
|
1033
|
-
}
|
|
1034
|
-
/**
|
|
1035
|
-
* Send a Signal reaction to a message
|
|
1036
|
-
* @param recipient - UUID or E.164 phone number of the message author
|
|
1037
|
-
* @param targetTimestamp - Message ID (timestamp) to react to
|
|
1038
|
-
* @param emoji - Emoji to react with
|
|
1039
|
-
* @param opts - Optional account/connection overrides
|
|
1040
|
-
*/
|
|
1041
|
-
async function sendReactionSignal(recipient, targetTimestamp, emoji, opts) {
|
|
1042
|
-
return await sendReactionSignalCore({
|
|
1043
|
-
recipient,
|
|
1044
|
-
targetTimestamp,
|
|
1045
|
-
emoji,
|
|
1046
|
-
remove: false,
|
|
1047
|
-
opts,
|
|
1048
|
-
errors: {
|
|
1049
|
-
missingRecipient: "Recipient or groupId is required for Signal reaction",
|
|
1050
|
-
invalidTargetTimestamp: "Valid targetTimestamp is required for Signal reaction",
|
|
1051
|
-
missingEmoji: "Emoji is required for Signal reaction",
|
|
1052
|
-
missingTargetAuthor: "targetAuthor is required for group reactions"
|
|
1053
|
-
}
|
|
1054
|
-
});
|
|
1055
|
-
}
|
|
1056
|
-
/**
|
|
1057
|
-
* Remove a Signal reaction from a message
|
|
1058
|
-
* @param recipient - UUID or E.164 phone number of the message author
|
|
1059
|
-
* @param targetTimestamp - Message ID (timestamp) to remove reaction from
|
|
1060
|
-
* @param emoji - Emoji to remove
|
|
1061
|
-
* @param opts - Optional account/connection overrides
|
|
1062
|
-
*/
|
|
1063
|
-
async function removeReactionSignal(recipient, targetTimestamp, emoji, opts) {
|
|
1064
|
-
return await sendReactionSignalCore({
|
|
1065
|
-
recipient,
|
|
1066
|
-
targetTimestamp,
|
|
1067
|
-
emoji,
|
|
1068
|
-
remove: true,
|
|
1069
|
-
opts,
|
|
1070
|
-
errors: {
|
|
1071
|
-
missingRecipient: "Recipient or groupId is required for Signal reaction removal",
|
|
1072
|
-
invalidTargetTimestamp: "Valid targetTimestamp is required for Signal reaction removal",
|
|
1073
|
-
missingEmoji: "Emoji is required for Signal reaction removal",
|
|
1074
|
-
missingTargetAuthor: "targetAuthor is required for group reaction removal"
|
|
1075
|
-
}
|
|
1076
|
-
});
|
|
1077
|
-
}
|
|
1078
|
-
//#endregion
|
|
1079
|
-
export { signalRpcRequest as a, signalCheck as i, sendReactionSignal as n, streamSignalEvents as o, resolveSignalRpcContext as r, removeReactionSignal as t };
|
|
983
|
+
export { signalRpcRequest as n, streamSignalEvents as r, signalCheck as t };
|
package/dist/contract-api.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { d as normalizeSignalMessagingTarget, i as isSignalSenderAllowed, u as looksLikeSignalTargetId } from "./identity-
|
|
2
|
-
import { a as looksLikeArchive, i as installSignalCliFromRelease, n as extractSignalCliArchive, o as pickAsset, r as installSignalCli, t as downloadToFile } from "./install-signal-cli-
|
|
1
|
+
import { d as normalizeSignalMessagingTarget, i as isSignalSenderAllowed, u as looksLikeSignalTargetId } from "./identity-C8-yk4J9.js";
|
|
2
|
+
import { a as looksLikeArchive, i as installSignalCliFromRelease, n as extractSignalCliArchive, o as pickAsset, r as installSignalCli, t as downloadToFile } from "./install-signal-cli-ik8VPaGg.js";
|
|
3
3
|
export { downloadToFile, extractSignalCliArchive, installSignalCli, installSignalCliFromRelease, isSignalSenderAllowed, looksLikeArchive, looksLikeSignalTargetId, normalizeSignalMessagingTarget, pickAsset };
|