@openclaw/imessage 2026.9.7 → 2026.10.1-beta.1
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/.setup/{accounts-nzcU0cq2.mjs → accounts-evTpvJMv.mjs} +6 -12
- package/dist/.setup/{group-policy-90pw4tyG.mjs → actions-DJqbUmbN.mjs} +103 -269
- package/dist/.setup/{actions.runtime-DdBN29zj.mjs → actions.runtime-DL5i-Y4J.mjs} +49 -84
- package/dist/.setup/{api-B9Qx21G-.mjs → api-SAVMfMoY.mjs} +5 -5
- package/dist/.setup/{api-D2S6FhGw.mjs → api-oq_MryN7.mjs} +6 -6
- package/dist/.setup/{approval-handler.runtime-DKSq0DWq.mjs → approval-handler.runtime-Bj2NGNXF.mjs} +26 -62
- package/dist/.setup/{approval-reactions-Bp33xc83.mjs → approval-reactions-L9Ul7PAu.mjs} +3 -2
- package/dist/.setup/{channel-9fyvuN_p.mjs → channel-CL73qdMG.mjs} +134 -60
- package/dist/.setup/{monitor-fv9nRuTH.mjs → channel.runtime-DY7JJ0_9.mjs} +202 -206
- package/dist/.setup/{sanitize-outbound-3MLljgtY.mjs → client-12apu4Ip.mjs} +26 -635
- package/dist/.setup/{config-schema-4Q3_EqYt.mjs → config-schema-DXwa_3V5.mjs} +1 -1
- package/dist/.setup/{media-contract-CagwSMvo.mjs → media-contract-DjQGZlfl.mjs} +1 -1
- package/dist/.setup/{message-tool-api-D032l82H.mjs → message-tool-api-CqfRxLlT.mjs} +2 -2
- package/dist/.setup/{question-reactions-Cy-dmU_j.mjs → question-reactions-DJV-TnA8.mjs} +2 -1
- package/dist/.setup/{reaction-context-Br-vAJFp.mjs → reaction-context-By7kUMBC.mjs} +2 -7
- package/dist/.setup/{remote-file-DRPCaVmg.mjs → remote-file-BU7pA-Zi.mjs} +7 -11
- package/dist/.setup/sanitize-outbound-C0x4BPky.mjs +564 -0
- package/dist/.setup/{send-Cu9nl757.mjs → send-pkYwL6Rt.mjs} +56 -103
- package/dist/.setup/{setup-core-8MDdYHj5.mjs → setup-core-DqOBe-n0.mjs} +1 -1
- package/dist/.setup/{setup-surface-tGXFDdWh.mjs → setup-surface-zKhIinwY.mjs} +2 -2
- package/dist/api.js +6 -6
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/contract-api.js +1 -1
- package/dist/doctor-contract-api.js +29 -21
- package/dist/media-contract-api.js +1 -1
- package/dist/message-tool-api.js +1 -1
- package/dist/runtime-api.js +2 -24
- package/dist/setup-entry.js +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +4 -4
- package/dist/.setup/channel.runtime-n-MPKL8k.mjs +0 -92
- package/dist/.setup/state-migrations-B-Q7bO0Y.mjs +0 -47
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
import { c as parseIMessageTarget, o as normalizeIMessageHandle, r as isAllowedIMessageReplyContextSender, s as parseIMessageAllowTarget, t as formatIMessageChatTarget } from "./targets-BicBiYsM.mjs";
|
|
2
|
-
import { d as resolveIMessageChatDbLookupPath, f as resolveIMessageHomeDir, l as resolveIMessageRemoteHost, o as resolveIMessageAccount } from "./accounts-
|
|
3
|
-
import { r as imessageRpcSupportsMethod } from "./message-tool-api-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { d as resolveIMessageChatDbLookupPath, f as resolveIMessageHomeDir, l as resolveIMessageRemoteHost, o as resolveIMessageAccount, r as listEnabledIMessageAccounts, s as resolveIMessageDuplicateSourceOwner } from "./accounts-evTpvJMv.mjs";
|
|
3
|
+
import { r as imessageRpcSupportsMethod } from "./message-tool-api-CqfRxLlT.mjs";
|
|
4
|
+
import { C as resolveIMessageDirectChatService, c as rememberIMessageReplyCache, d as IMESSAGE_CATCHUP_CURSOR_NAMESPACE, g as resolveIMessageEchoMediaKey, h as resolveIMessageCatchupCursorKey, m as capFailureRetriesMap, n as createIMessageRpcClient, s as isKnownFromMeIMessageTarget } from "./client-12apu4Ip.mjs";
|
|
5
|
+
import { a as normalizeIMessageMessageId, i as normalizeIMessageGuid, n as probeIMessage, r as probeIMessagePrivateApi } from "./actions-DJqbUmbN.mjs";
|
|
6
6
|
import { t as getIMessageRuntime } from "./runtime-Cza4CY5T.mjs";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { i as resolveIMessageStartupRowidWatermark } from "./remote-file-
|
|
12
|
-
import { n as
|
|
7
|
+
import { a as resolveIMessageGroupSystemPrompt, s as resolveIMessageInboundConversationId } from "./channel-CL73qdMG.mjs";
|
|
8
|
+
import { r as sanitizeOutboundText } from "./sanitize-outbound-C0x4BPky.mjs";
|
|
9
|
+
import { n as resolveIMessageAttachmentRoots, r as resolveIMessageRemoteAttachmentRoots } from "./media-contract-DjQGZlfl.mjs";
|
|
10
|
+
import { t as IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS } from "./outbound-send-deps-B-QEsLSM.mjs";
|
|
11
|
+
import { i as resolveIMessageStartupRowidWatermark } from "./remote-file-BU7pA-Zi.mjs";
|
|
12
|
+
import { i as registerIMessageApprovalReactionTarget, n as handleIMessageApprovalReaction, o as listPendingIMessageApprovalReactionPollTargets, r as maybeResolveIMessageApprovalReaction, s as buildIMessageApprovalConversationKeyForInbound } from "./approval-reactions-L9Ul7PAu.mjs";
|
|
13
|
+
import { c as iMessageApprovalControlBindings, n as hasPersistedIMessageEcho, r as normalizeIMessageEchoText, s as maybeResolveIMessageApprovalPollVote, t as sendMessageIMessage } from "./send-pkYwL6Rt.mjs";
|
|
14
|
+
import { t as resolveIMessageReactionContext } from "./reaction-context-By7kUMBC.mjs";
|
|
15
|
+
import { n as maybeResolveIMessageQuestionReaction, t as hasIMessageQuestionReactionTarget } from "./question-reactions-DJV-TnA8.mjs";
|
|
16
|
+
import { imessageSetupWizard } from "./setup-surface-zKhIinwY.mjs";
|
|
13
17
|
import { asSafeIntegerInRange, hasNonEmptyString, isRecord, normalizeOptionalString, normalizeStringEntries, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
14
|
-
import {
|
|
18
|
+
import { normalizeChannelDmPolicy } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
19
|
+
import { bindIngressLifecycleToReplyOptions, createAccountStatusSink, createChannelIngressError, createChannelIngressMonitor, createChannelMessageReplyPipeline, resolveChannelStreamingBlockEnabled, resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-outbound";
|
|
15
20
|
import { resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime";
|
|
16
21
|
import { resolveAgentRoute, resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
|
|
17
22
|
import path from "node:path";
|
|
23
|
+
import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/account-helpers";
|
|
18
24
|
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
19
25
|
import fs from "node:fs/promises";
|
|
20
26
|
import { isInboundPathAllowed, kindFromMime } from "openclaw/plugin-sdk/media-runtime";
|
|
21
|
-
import { createNonExitingRuntime, danger, logVerbose, shouldLogVerbose, warn } from "openclaw/plugin-sdk/runtime-env";
|
|
27
|
+
import { createNonExitingRuntime, danger, logVerbose, shouldLogVerbose, sleepWithAbort, waitForAbortSignal, warn } from "openclaw/plugin-sdk/runtime-env";
|
|
22
28
|
import { asDateTimestampMs, asPositiveFiniteNumber, parseDateStringTimestampMs, resolveIntegerOption, resolvePromptHistoryLimit, timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
|
23
29
|
import { createHash } from "node:crypto";
|
|
24
30
|
import { createRuntimeConfigReader, getRuntimeConfig } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
@@ -27,8 +33,12 @@ import { collectErrorGraphCandidates, formatErrorMessage } from "openclaw/plugin
|
|
|
27
33
|
import { resolveChannelGroupPolicy, resolveChannelGroups, resolveChannelGroupsConfigPath, resolveScopeRequireMention } from "openclaw/plugin-sdk/channel-policy";
|
|
28
34
|
import { convertMarkdownTables, findCodeRegions, isInsideCode, sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
|
|
29
35
|
import { buildChannelInboundEventContext, buildMentionRegexes, createAcceptedChannelDeliveryResult, createChannelInboundDebouncer, createChannelPartialDeliveryError, filterChannelInboundQuoteContext, formatInboundEnvelope, formatInboundFromLabel, formatInboundMediaUnavailableText, formatMediaPlaceholderText, isChannelPartialDeliveryError, logInboundDrop, matchesMentionPatterns, resolveEnvelopeFormatOptions, resolveInboundDebounceMs, resolveInboundMentionDecision, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent, shouldDebounceTextInbound, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
|
|
30
|
-
import {
|
|
36
|
+
import { FsSafeError, openLocalFileSafely, resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
|
|
37
|
+
import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
|
|
31
38
|
import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-runtime";
|
|
39
|
+
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
40
|
+
import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
41
|
+
import { resolveAgentConfig, resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
|
|
32
42
|
import { logTypingFailure } from "openclaw/plugin-sdk/channel-feedback";
|
|
33
43
|
import { defineStableChannelIngressIdentity, fanInChannelIngressLifecycles } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
34
44
|
import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
|
|
@@ -37,12 +47,8 @@ import { ensureConfiguredBindingRouteReady, readChannelAllowFromStore, upsertCha
|
|
|
37
47
|
import { channelReadyPatch } from "openclaw/plugin-sdk/gateway-runtime";
|
|
38
48
|
import { redactIdentifier } from "openclaw/plugin-sdk/logging-core";
|
|
39
49
|
import { resolveDefaultGroupPolicy, resolveOpenProviderRuntimeGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
|
|
40
|
-
import { FsSafeError, openLocalFileSafely, resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
|
|
41
50
|
import { getSessionEntry, readSessionUpdatedAt, resolveSendPolicy, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
42
51
|
import { waitForTransportReady } from "openclaw/plugin-sdk/transport-ready-runtime";
|
|
43
|
-
import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
44
|
-
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
45
|
-
import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
|
|
46
52
|
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
|
|
47
53
|
import { chunkMarkdownTextWithMode, resolveChunkMode } from "openclaw/plugin-sdk/reply-chunking";
|
|
48
54
|
import { deliverTextOrMediaReply, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
|
|
@@ -148,12 +154,12 @@ async function bindObservedConversation(params) {
|
|
|
148
154
|
}
|
|
149
155
|
async function pollPendingIMessageApprovalReactions(params) {
|
|
150
156
|
const targets = await listPendingIMessageApprovalReactionPollTargets({ accountId: params.accountId });
|
|
151
|
-
if (targets.length === 0) return;
|
|
157
|
+
if (params.signal?.aborted || targets.length === 0) return;
|
|
152
158
|
const pendingByMessageId = buildPendingTargetsByMessageId(targets);
|
|
153
159
|
const explicitChatIds = listTargetChatIds(targets);
|
|
154
160
|
const chatIds = params.allowRecentChatDiscovery === true && hasUnscopedTarget(targets) ? [.../* @__PURE__ */ new Set([...explicitChatIds, ...await listRecentChatIds(params.client)])] : explicitChatIds;
|
|
155
|
-
if (chatIds.length === 0) return;
|
|
156
161
|
for (const chatId of chatIds) {
|
|
162
|
+
if (params.signal?.aborted) return;
|
|
157
163
|
let messages;
|
|
158
164
|
try {
|
|
159
165
|
messages = await fetchRecentHistory({
|
|
@@ -165,6 +171,7 @@ async function pollPendingIMessageApprovalReactions(params) {
|
|
|
165
171
|
continue;
|
|
166
172
|
}
|
|
167
173
|
for (const message of messages) {
|
|
174
|
+
if (params.signal?.aborted) return;
|
|
168
175
|
const targetGuid = message.guid?.trim();
|
|
169
176
|
if (!targetGuid) continue;
|
|
170
177
|
const target = pendingByMessageId.get(targetGuid) ?? pendingByMessageId.get(normalizeIMessageGuid(targetGuid));
|
|
@@ -174,6 +181,7 @@ async function pollPendingIMessageApprovalReactions(params) {
|
|
|
174
181
|
message
|
|
175
182
|
});
|
|
176
183
|
for (const reaction of message.reactions ?? []) {
|
|
184
|
+
if (params.signal?.aborted) return;
|
|
177
185
|
const reactionPayload = buildReactionPayload({
|
|
178
186
|
targetMessage: message,
|
|
179
187
|
reaction
|
|
@@ -607,21 +615,7 @@ function parseIMessageNotification(raw) {
|
|
|
607
615
|
const PER_CHAT_HISTORY_LIMIT = 500;
|
|
608
616
|
const CATCHUP_CHATS_LIST_LIMIT = 200;
|
|
609
617
|
const CATCHUP_RPC_TIMEOUT_MS = 3e4;
|
|
610
|
-
/**
|
|
611
|
-
* Wire `performIMessageCatchup` against the live `imsg` JSON-RPC client.
|
|
612
|
-
*
|
|
613
|
-
* Catchup recovers messages that landed in `chat.db` while the gateway was
|
|
614
|
-
* offline (crash, restart, mac sleep) by:
|
|
615
|
-
* 1. listing recently-active chats via `chats.list`,
|
|
616
|
-
* 2. fetching per-chat history since the cursor via `messages.history`,
|
|
617
|
-
* 3. sorting cross-chat by `rowid`, capping at `perRunLimit`,
|
|
618
|
-
* 4. admitting each row through the same durable GUID queue used by live
|
|
619
|
-
* notifications, so replay, coalescing, echo, and receipt behavior match.
|
|
620
|
-
*
|
|
621
|
-
* Runs at most once per `monitorIMessageProvider` invocation, between
|
|
622
|
-
* `watch.subscribe` and the live dispatch loop. Anything that arrives during
|
|
623
|
-
* catchup itself flows through live admission; queue tombstones reject overlap.
|
|
624
|
-
*/
|
|
618
|
+
/** Replay oldest-first through durable admission; tombstones reject live/watch overlap. */
|
|
625
619
|
async function runIMessageCatchup(params) {
|
|
626
620
|
const { client, accountId, config, includeAttachments, dispatchPayload, runtime } = params;
|
|
627
621
|
const log = (msg) => runtime?.log?.(msg);
|
|
@@ -699,22 +693,13 @@ async function runIMessageCatchup(params) {
|
|
|
699
693
|
const sorted = collected.toSorted((a, b) => a.rowid - b.rowid);
|
|
700
694
|
const capped = sorted.slice(0, limit);
|
|
701
695
|
const isCapTruncated = capped.length < sorted.length;
|
|
702
|
-
if (isCapTruncated) {
|
|
703
|
-
warnLog(`imessage catchup: fetched ${sorted.length} rows across chats, capped to perRunLimit=${limit} (oldest first); next startup picks up the rest`);
|
|
704
|
-
const keep = new Set(capped.map((row) => row.guid));
|
|
705
|
-
for (const guid of payloadByGuid.keys()) if (!keep.has(guid)) payloadByGuid.delete(guid);
|
|
706
|
-
}
|
|
696
|
+
if (isCapTruncated) warnLog(`imessage catchup: fetched ${sorted.length} rows across chats, capped to perRunLimit=${limit} (oldest first); next startup picks up the rest`);
|
|
707
697
|
let effectiveWatermarkRowid = rawWatermarkRowid;
|
|
708
698
|
let effectiveWatermarkMs = rawWatermarkMs;
|
|
709
|
-
if (isCapTruncated
|
|
699
|
+
if (isCapTruncated) {
|
|
710
700
|
const last = capped.at(-1);
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
effectiveWatermarkMs = Math.min(effectiveWatermarkMs, last.date);
|
|
714
|
-
}
|
|
715
|
-
} else if (isCapTruncated && capped.length === 0) {
|
|
716
|
-
effectiveWatermarkRowid = NaN;
|
|
717
|
-
effectiveWatermarkMs = NaN;
|
|
701
|
+
effectiveWatermarkRowid = last ? Math.min(rawWatermarkRowid, last.rowid) : NaN;
|
|
702
|
+
effectiveWatermarkMs = last ? Math.min(rawWatermarkMs, last.date) : NaN;
|
|
718
703
|
}
|
|
719
704
|
return {
|
|
720
705
|
resolved: true,
|
|
@@ -828,7 +813,7 @@ function hasUsableConversationAnchor(projection) {
|
|
|
828
813
|
return hasPositiveChatId(projection.chat_id) || hasNonEmptyString(projection.chat_guid) || hasNonEmptyString(projection.chat_identifier);
|
|
829
814
|
}
|
|
830
815
|
function isIMessageAnchorless(message) {
|
|
831
|
-
if (
|
|
816
|
+
if (hasUsableConversationAnchor(message)) return false;
|
|
832
817
|
return message.chat_id === null || typeof message.chat_id === "number" && (!Number.isFinite(message.chat_id) || message.chat_id <= 0) || isExplicitEmptyString(message.chat_guid) || isExplicitEmptyString(message.chat_identifier);
|
|
833
818
|
}
|
|
834
819
|
function extractAuthoritativeRecoveryProjection(entry) {
|
|
@@ -1085,12 +1070,6 @@ function createIMessageThrottledDropDiagnosticCache() {
|
|
|
1085
1070
|
//#region extensions/imessage/src/monitor/echo-cache.ts
|
|
1086
1071
|
const SENT_MESSAGE_TEXT_TTL_MS = 4e3;
|
|
1087
1072
|
const SENT_MESSAGE_ID_TTL_MS = 6e4;
|
|
1088
|
-
function normalizeEchoMessageIdKey(messageId) {
|
|
1089
|
-
if (!messageId) return null;
|
|
1090
|
-
const normalized = messageId.trim();
|
|
1091
|
-
if (!normalized || normalized === "ok" || normalized === "unknown") return null;
|
|
1092
|
-
return normalized;
|
|
1093
|
-
}
|
|
1094
1073
|
var DefaultSentMessageCache = class {
|
|
1095
1074
|
constructor() {
|
|
1096
1075
|
this.textCache = /* @__PURE__ */ new Map();
|
|
@@ -1104,7 +1083,7 @@ var DefaultSentMessageCache = class {
|
|
|
1104
1083
|
if (textKey) this.textCache.set(`${scope}:${textKey}`, Date.now());
|
|
1105
1084
|
const mediaKey = resolveIMessageEchoMediaKey(lookup.media);
|
|
1106
1085
|
if (mediaKey) this.mediaCache.set(`${scope}:${mediaKey}`, Date.now());
|
|
1107
|
-
const messageIdKey =
|
|
1086
|
+
const messageIdKey = normalizeIMessageMessageId(lookup.messageId);
|
|
1108
1087
|
if (messageIdKey) {
|
|
1109
1088
|
this.messageIdCache.set(`${scope}:${messageIdKey}`, Date.now());
|
|
1110
1089
|
if (textKey) this.textBackedByIdCache.set(`${scope}:${textKey}`, Date.now());
|
|
@@ -1125,7 +1104,7 @@ var DefaultSentMessageCache = class {
|
|
|
1125
1104
|
})) return true;
|
|
1126
1105
|
const textKey = normalizeIMessageEchoText(lookup.text);
|
|
1127
1106
|
const mediaKey = resolveIMessageEchoMediaKey(lookup.media);
|
|
1128
|
-
const messageIdKey =
|
|
1107
|
+
const messageIdKey = normalizeIMessageMessageId(lookup.messageId);
|
|
1129
1108
|
let canUseMediaFallback = !messageIdKey;
|
|
1130
1109
|
if (messageIdKey) {
|
|
1131
1110
|
const idTimestamp = this.messageIdCache.get(`${scope}:${messageIdKey}`);
|
|
@@ -1450,18 +1429,11 @@ function normalizeIMessageChatIdentifierEntry(entry) {
|
|
|
1450
1429
|
const parsed = parseIMessageAllowTarget(entry.trim());
|
|
1451
1430
|
return parsed.kind === "chat_identifier" ? parsed.chatIdentifier.trim() || null : null;
|
|
1452
1431
|
}
|
|
1453
|
-
function normalizeDmPolicy(policy) {
|
|
1454
|
-
return policy === "open" || policy === "allowlist" || policy === "disabled" ? policy : "pairing";
|
|
1455
|
-
}
|
|
1456
1432
|
function normalizeGroupPolicy(policy) {
|
|
1457
1433
|
return policy === "open" || policy === "disabled" ? policy : "allowlist";
|
|
1458
1434
|
}
|
|
1459
1435
|
function normalizeReplyField(value) {
|
|
1460
|
-
|
|
1461
|
-
const trimmed = value.trim();
|
|
1462
|
-
return trimmed ? trimmed : void 0;
|
|
1463
|
-
}
|
|
1464
|
-
if (typeof value === "number") return String(value);
|
|
1436
|
+
return typeof value === "number" ? String(value) : normalizeOptionalString(value);
|
|
1465
1437
|
}
|
|
1466
1438
|
function describeReplyContext(message) {
|
|
1467
1439
|
const body = normalizeReplyField(message.reply_to_text);
|
|
@@ -1573,6 +1545,14 @@ async function resolveIMessageInboundDecision(params) {
|
|
|
1573
1545
|
const inboundMessageIds = resolveInboundEchoMessageIds(params.message);
|
|
1574
1546
|
const inboundMessageId = inboundMessageIds[0];
|
|
1575
1547
|
const hasInboundGuid = Boolean(normalizeReplyField(params.message.guid));
|
|
1548
|
+
const echoScope = buildIMessageEchoScope({
|
|
1549
|
+
accountId: params.accountId,
|
|
1550
|
+
isGroup,
|
|
1551
|
+
chatId,
|
|
1552
|
+
chatGuid,
|
|
1553
|
+
chatIdentifier,
|
|
1554
|
+
sender
|
|
1555
|
+
});
|
|
1576
1556
|
if (params.message.is_from_me) {
|
|
1577
1557
|
if (isAmbiguousSelfThread) params.selfChatCache?.remember(selfChatLookup);
|
|
1578
1558
|
if (isSelfChat) {
|
|
@@ -1580,14 +1560,6 @@ async function resolveIMessageInboundDecision(params) {
|
|
|
1580
1560
|
...selfChatLookup,
|
|
1581
1561
|
allowCreatedAtSkew: true
|
|
1582
1562
|
});
|
|
1583
|
-
const echoScope = buildIMessageEchoScope({
|
|
1584
|
-
accountId: params.accountId,
|
|
1585
|
-
isGroup,
|
|
1586
|
-
chatId,
|
|
1587
|
-
chatGuid,
|
|
1588
|
-
chatIdentifier,
|
|
1589
|
-
sender
|
|
1590
|
-
});
|
|
1591
1563
|
if (params.echoCache && (bodyText || inboundMessageId || mediaFacts.length > 0) && await hasIMessageEchoMatch({
|
|
1592
1564
|
echoCache: params.echoCache,
|
|
1593
1565
|
scope: echoScope,
|
|
@@ -1642,7 +1614,7 @@ async function resolveIMessageInboundDecision(params) {
|
|
|
1642
1614
|
id: chatId != null ? String(chatId) : sender
|
|
1643
1615
|
},
|
|
1644
1616
|
contextBinding,
|
|
1645
|
-
dmPolicy:
|
|
1617
|
+
dmPolicy: normalizeChannelDmPolicy(params.dmPolicy) ?? "pairing",
|
|
1646
1618
|
groupPolicy: normalizeGroupPolicy(params.groupPolicy),
|
|
1647
1619
|
policy: { groupAllowFromFallbackToAllowFrom: false },
|
|
1648
1620
|
allowFrom: params.allowFrom,
|
|
@@ -1715,14 +1687,7 @@ async function resolveIMessageInboundDecision(params) {
|
|
|
1715
1687
|
const targetGuids = reactionContext.targetGuids ?? (targetGuid ? [targetGuid] : []);
|
|
1716
1688
|
const targetIsOwn = Boolean(targetGuid && (params.echoCache && await hasIMessageEchoMatch({
|
|
1717
1689
|
echoCache: params.echoCache,
|
|
1718
|
-
scope:
|
|
1719
|
-
accountId: params.accountId,
|
|
1720
|
-
isGroup,
|
|
1721
|
-
chatId,
|
|
1722
|
-
chatGuid,
|
|
1723
|
-
chatIdentifier,
|
|
1724
|
-
sender
|
|
1725
|
-
}),
|
|
1690
|
+
scope: echoScope,
|
|
1726
1691
|
messageIds: targetGuids
|
|
1727
1692
|
}) || await isKnownFromMeIMessageTarget({
|
|
1728
1693
|
messageIds: targetGuids,
|
|
@@ -1776,14 +1741,6 @@ async function resolveIMessageInboundDecision(params) {
|
|
|
1776
1741
|
};
|
|
1777
1742
|
}
|
|
1778
1743
|
if (params.echoCache && (messageText || inboundMessageId || mediaFacts.length > 0)) {
|
|
1779
|
-
const echoScope = buildIMessageEchoScope({
|
|
1780
|
-
accountId: params.accountId,
|
|
1781
|
-
isGroup,
|
|
1782
|
-
chatId,
|
|
1783
|
-
chatGuid,
|
|
1784
|
-
chatIdentifier,
|
|
1785
|
-
sender
|
|
1786
|
-
});
|
|
1787
1744
|
if (await hasIMessageEchoMatch({
|
|
1788
1745
|
echoCache: params.echoCache,
|
|
1789
1746
|
scope: echoScope,
|
|
@@ -1816,7 +1773,7 @@ async function resolveIMessageInboundDecision(params) {
|
|
|
1816
1773
|
channel: "imessage",
|
|
1817
1774
|
accountId: params.accountId
|
|
1818
1775
|
});
|
|
1819
|
-
const replyContextAllowFrom =
|
|
1776
|
+
const replyContextAllowFrom = uniqueStrings([...groupAllowFromForAccess, ...effectiveGroupAllowFrom]);
|
|
1820
1777
|
const replySenderAllowed = resolveInboundSupplementalSenderAllowed({
|
|
1821
1778
|
isGroup,
|
|
1822
1779
|
groupPolicy: replyContextAllowFrom.length === 0 ? "open" : "allowlist",
|
|
@@ -2247,29 +2204,29 @@ function createLoopRateLimiter(opts) {
|
|
|
2247
2204
|
const now = Date.now();
|
|
2248
2205
|
if (now - lastCleanup < CLEANUP_INTERVAL_MS) return;
|
|
2249
2206
|
lastCleanup = now;
|
|
2250
|
-
for (const [key,
|
|
2251
|
-
const recent =
|
|
2207
|
+
for (const [key, timestamps] of conversations.entries()) {
|
|
2208
|
+
const recent = timestamps.filter((ts) => now - ts <= windowMs);
|
|
2252
2209
|
if (recent.length === 0) conversations.delete(key);
|
|
2253
|
-
else
|
|
2210
|
+
else conversations.set(key, recent);
|
|
2254
2211
|
}
|
|
2255
2212
|
}
|
|
2256
2213
|
return {
|
|
2257
2214
|
record(conversationKey) {
|
|
2258
2215
|
cleanup();
|
|
2259
|
-
let
|
|
2260
|
-
if (!
|
|
2261
|
-
|
|
2262
|
-
conversations.set(conversationKey,
|
|
2216
|
+
let timestamps = conversations.get(conversationKey);
|
|
2217
|
+
if (!timestamps) {
|
|
2218
|
+
timestamps = [];
|
|
2219
|
+
conversations.set(conversationKey, timestamps);
|
|
2263
2220
|
}
|
|
2264
|
-
|
|
2221
|
+
timestamps.push(Date.now());
|
|
2265
2222
|
},
|
|
2266
2223
|
isRateLimited(conversationKey) {
|
|
2267
2224
|
cleanup();
|
|
2268
|
-
const
|
|
2269
|
-
if (!
|
|
2225
|
+
const timestamps = conversations.get(conversationKey);
|
|
2226
|
+
if (!timestamps) return false;
|
|
2270
2227
|
const now = Date.now();
|
|
2271
|
-
const recent =
|
|
2272
|
-
|
|
2228
|
+
const recent = timestamps.filter((ts) => now - ts <= windowMs);
|
|
2229
|
+
conversations.set(conversationKey, recent);
|
|
2273
2230
|
return recent.length >= maxHits;
|
|
2274
2231
|
}
|
|
2275
2232
|
};
|
|
@@ -2640,9 +2597,7 @@ function buildScope(parts) {
|
|
|
2640
2597
|
var DefaultSelfChatCache = class {
|
|
2641
2598
|
constructor() {
|
|
2642
2599
|
this.cache = /* @__PURE__ */ new Map();
|
|
2643
|
-
this.insertionOrder =
|
|
2644
|
-
this.insertionOrderOffset = 0;
|
|
2645
|
-
this.entryCount = 0;
|
|
2600
|
+
this.insertionOrder = /* @__PURE__ */ new Map();
|
|
2646
2601
|
this.lastCleanupAt = 0;
|
|
2647
2602
|
this.nextEntryId = 1;
|
|
2648
2603
|
}
|
|
@@ -2656,19 +2611,14 @@ var DefaultSelfChatCache = class {
|
|
|
2656
2611
|
if (!key || !isUsableTimestamp(lookup.createdAt)) return;
|
|
2657
2612
|
const entries = this.cache.get(key) ?? /* @__PURE__ */ new Map();
|
|
2658
2613
|
const entry = {
|
|
2659
|
-
id: this.nextEntryId,
|
|
2660
2614
|
createdAt: lookup.createdAt,
|
|
2661
2615
|
createdAtSkewToleranceMs: lookup.allowCreatedAtSkew ? SELF_CHAT_CREATED_AT_TOLERANCE_MS : 0,
|
|
2662
2616
|
rememberedAt: Date.now()
|
|
2663
2617
|
};
|
|
2664
|
-
this.nextEntryId
|
|
2665
|
-
entries.set(
|
|
2618
|
+
const id = this.nextEntryId++;
|
|
2619
|
+
entries.set(id, entry);
|
|
2666
2620
|
this.cache.set(key, entries);
|
|
2667
|
-
this.insertionOrder.
|
|
2668
|
-
key,
|
|
2669
|
-
id: entry.id
|
|
2670
|
-
});
|
|
2671
|
-
this.entryCount += 1;
|
|
2621
|
+
this.insertionOrder.set(id, key);
|
|
2672
2622
|
this.maybeCleanup();
|
|
2673
2623
|
}
|
|
2674
2624
|
has(lookup) {
|
|
@@ -2691,25 +2641,18 @@ var DefaultSelfChatCache = class {
|
|
|
2691
2641
|
for (const [key, entries] of this.cache.entries()) {
|
|
2692
2642
|
for (const [id, entry] of entries.entries()) if (now - entry.rememberedAt > SELF_CHAT_TTL_MS) {
|
|
2693
2643
|
entries.delete(id);
|
|
2694
|
-
this.
|
|
2644
|
+
this.insertionOrder.delete(id);
|
|
2695
2645
|
}
|
|
2696
2646
|
if (entries.size === 0) this.cache.delete(key);
|
|
2697
2647
|
}
|
|
2698
|
-
while (this.
|
|
2699
|
-
const
|
|
2700
|
-
this.
|
|
2701
|
-
const entries = this.cache.get(
|
|
2648
|
+
while (this.insertionOrder.size > MAX_SELF_CHAT_CACHE_ENTRIES) {
|
|
2649
|
+
const [id, key] = expectDefined(this.insertionOrder.entries().next().value, "oldest iMessage self-chat cache entry");
|
|
2650
|
+
this.insertionOrder.delete(id);
|
|
2651
|
+
const entries = this.cache.get(key);
|
|
2702
2652
|
if (!entries) continue;
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
if (entries.size === 0) this.cache.delete(oldest.key);
|
|
2653
|
+
entries.delete(id);
|
|
2654
|
+
if (entries.size === 0) this.cache.delete(key);
|
|
2706
2655
|
}
|
|
2707
|
-
this.compactInsertionOrder();
|
|
2708
|
-
}
|
|
2709
|
-
compactInsertionOrder() {
|
|
2710
|
-
if (this.insertionOrderOffset <= 1024 && this.insertionOrder.length <= this.entryCount + 1024) return;
|
|
2711
|
-
this.insertionOrder = this.insertionOrder.slice(this.insertionOrderOffset).filter((entry) => this.cache.get(entry.key)?.has(entry.id));
|
|
2712
|
-
this.insertionOrderOffset = 0;
|
|
2713
2656
|
}
|
|
2714
2657
|
};
|
|
2715
2658
|
function createSelfChatCache() {
|
|
@@ -2815,22 +2758,8 @@ function describeIMessageWatchSubscribeStartupFailure(params) {
|
|
|
2815
2758
|
const retry = params.retryDelayMs !== void 0 ? ` retry_in_ms=${params.retryDelayMs}` : "";
|
|
2816
2759
|
return `imessage: watch.subscribe startup failed attempt=${params.attempt}/${params.maxAttempts} account=${params.accountId} cliPath=${params.cliPath} dbPath=${params.dbPath ? "configured" : "default"} remoteHost=${params.remoteHost ? "configured" : "none"} timeoutMs=${params.probeTimeoutMs} since_rowid=${params.watchSinceRowid ?? "none"} attachments=${params.includeAttachments} include_reactions=true${retry}: ${String(params.error)}`;
|
|
2817
2760
|
}
|
|
2818
|
-
async function
|
|
2819
|
-
|
|
2820
|
-
await new Promise((resolve) => {
|
|
2821
|
-
const timer = setTimeout(() => {
|
|
2822
|
-
params.abortSignal?.removeEventListener("abort", onAbort);
|
|
2823
|
-
resolve();
|
|
2824
|
-
}, params.ms);
|
|
2825
|
-
const onAbort = () => {
|
|
2826
|
-
clearTimeout(timer);
|
|
2827
|
-
params.abortSignal?.removeEventListener("abort", onAbort);
|
|
2828
|
-
resolve();
|
|
2829
|
-
};
|
|
2830
|
-
params.abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
2831
|
-
});
|
|
2832
|
-
}
|
|
2833
|
-
async function monitorIMessageProvider(opts = {}) {
|
|
2761
|
+
async function monitorIMessageProvider(opts) {
|
|
2762
|
+
const { scheduler } = opts;
|
|
2834
2763
|
const runtime = opts.runtime ?? createNonExitingRuntime();
|
|
2835
2764
|
const cfg = opts.config ?? getRuntimeConfig();
|
|
2836
2765
|
const readConfig = createRuntimeConfigReader(cfg);
|
|
@@ -2995,13 +2924,8 @@ async function monitorIMessageProvider(opts = {}) {
|
|
|
2995
2924
|
await abandon();
|
|
2996
2925
|
return;
|
|
2997
2926
|
}
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
await settle();
|
|
3001
|
-
return;
|
|
3002
|
-
}
|
|
3003
|
-
const combined = combineIMessagePayloads(entries.map((entry) => entry.message));
|
|
3004
|
-
if (shouldLogVerbose()) {
|
|
2927
|
+
const combined = entries.length === 1 ? expectDefined(entries[0], "single iMessage dispatch entry").message : combineIMessagePayloads(entries.map((entry) => entry.message));
|
|
2928
|
+
if (entries.length > 1 && shouldLogVerbose()) {
|
|
3005
2929
|
const text = combined.text ?? "";
|
|
3006
2930
|
const preview = sliceUtf16Safe(text, 0, 50);
|
|
3007
2931
|
const ellipsis = text.length > 50 ? "..." : "";
|
|
@@ -3378,6 +3302,10 @@ async function monitorIMessageProvider(opts = {}) {
|
|
|
3378
3302
|
}
|
|
3379
3303
|
};
|
|
3380
3304
|
let directTypingController;
|
|
3305
|
+
const startDirectToolTyping = async () => {
|
|
3306
|
+
await directTypingController?.startTypingLoop();
|
|
3307
|
+
return false;
|
|
3308
|
+
};
|
|
3381
3309
|
const directToolTypingOptions = shouldUseDirectToolTypingOptions ? {
|
|
3382
3310
|
suppressDefaultToolProgressMessages: true,
|
|
3383
3311
|
allowToolLifecycleWhenProgressHidden: true,
|
|
@@ -3385,14 +3313,8 @@ async function monitorIMessageProvider(opts = {}) {
|
|
|
3385
3313
|
onTypingController: (typing) => {
|
|
3386
3314
|
directTypingController = typing;
|
|
3387
3315
|
},
|
|
3388
|
-
onToolResult:
|
|
3389
|
-
|
|
3390
|
-
return false;
|
|
3391
|
-
},
|
|
3392
|
-
...supportsTyping ? { onToolStart: async () => {
|
|
3393
|
-
await directTypingController?.startTypingLoop();
|
|
3394
|
-
return false;
|
|
3395
|
-
} } : {}
|
|
3316
|
+
onToolResult: startDirectToolTyping,
|
|
3317
|
+
...supportsTyping ? { onToolStart: startDirectToolTyping } : {}
|
|
3396
3318
|
} : {};
|
|
3397
3319
|
const configuredBlockStreaming = resolveChannelStreamingBlockEnabled(accountInfo.config);
|
|
3398
3320
|
const inboundLastRouteSessionKey = resolveInboundLastRouteSessionKey({
|
|
@@ -3608,25 +3530,27 @@ async function monitorIMessageProvider(opts = {}) {
|
|
|
3608
3530
|
} catch (err) {
|
|
3609
3531
|
if (abort?.aborted) return;
|
|
3610
3532
|
const retriable = isRetriableWatchSubscribeStartupError(err);
|
|
3611
|
-
|
|
3533
|
+
const shouldRetry = attempt < WATCH_SUBSCRIBE_MAX_ATTEMPTS && retriable;
|
|
3534
|
+
const failureParams = {
|
|
3535
|
+
accountId: accountInfo.accountId,
|
|
3536
|
+
attempt,
|
|
3537
|
+
maxAttempts: WATCH_SUBSCRIBE_MAX_ATTEMPTS,
|
|
3538
|
+
cliPath,
|
|
3539
|
+
dbPath,
|
|
3540
|
+
remoteHost,
|
|
3541
|
+
includeAttachments,
|
|
3542
|
+
probeTimeoutMs,
|
|
3543
|
+
watchSinceRowid,
|
|
3544
|
+
error: err
|
|
3545
|
+
};
|
|
3546
|
+
if (!shouldRetry) {
|
|
3612
3547
|
opts.statusSink?.({
|
|
3613
3548
|
connected: false,
|
|
3614
3549
|
lifecycle: retriable ? "recovering" : "blocked",
|
|
3615
3550
|
terminalDisconnect: retriable ? void 0 : true,
|
|
3616
3551
|
lastError: String(err)
|
|
3617
3552
|
});
|
|
3618
|
-
runtime.error?.(danger(`imessage: monitor failed: ${describeIMessageWatchSubscribeStartupFailure(
|
|
3619
|
-
accountId: accountInfo.accountId,
|
|
3620
|
-
attempt,
|
|
3621
|
-
maxAttempts: WATCH_SUBSCRIBE_MAX_ATTEMPTS,
|
|
3622
|
-
cliPath,
|
|
3623
|
-
dbPath,
|
|
3624
|
-
remoteHost,
|
|
3625
|
-
includeAttachments,
|
|
3626
|
-
probeTimeoutMs,
|
|
3627
|
-
watchSinceRowid,
|
|
3628
|
-
error: err
|
|
3629
|
-
})}`));
|
|
3553
|
+
runtime.error?.(danger(`imessage: monitor failed: ${describeIMessageWatchSubscribeStartupFailure(failureParams)}`));
|
|
3630
3554
|
throw err;
|
|
3631
3555
|
}
|
|
3632
3556
|
opts.statusSink?.({
|
|
@@ -3635,25 +3559,15 @@ async function monitorIMessageProvider(opts = {}) {
|
|
|
3635
3559
|
lastError: String(err)
|
|
3636
3560
|
});
|
|
3637
3561
|
runtime.log?.(warn(describeIMessageWatchSubscribeStartupFailure({
|
|
3638
|
-
|
|
3639
|
-
attempt,
|
|
3640
|
-
maxAttempts: WATCH_SUBSCRIBE_MAX_ATTEMPTS,
|
|
3641
|
-
cliPath,
|
|
3642
|
-
dbPath,
|
|
3643
|
-
remoteHost,
|
|
3644
|
-
includeAttachments,
|
|
3645
|
-
probeTimeoutMs,
|
|
3646
|
-
watchSinceRowid,
|
|
3647
|
-
error: err,
|
|
3562
|
+
...failureParams,
|
|
3648
3563
|
retryDelayMs: WATCH_SUBSCRIBE_RETRY_DELAY_MS
|
|
3649
3564
|
})));
|
|
3650
3565
|
attemptDetachAbortHandler();
|
|
3651
3566
|
attemptDetachAbortHandler = () => {};
|
|
3652
3567
|
await attemptClient?.stop();
|
|
3653
3568
|
attemptClient = void 0;
|
|
3654
|
-
await
|
|
3655
|
-
|
|
3656
|
-
abortSignal: abort
|
|
3569
|
+
await sleepWithAbort(WATCH_SUBSCRIBE_RETRY_DELAY_MS, abort).catch((error) => {
|
|
3570
|
+
if (!abort?.aborted) throw error;
|
|
3657
3571
|
});
|
|
3658
3572
|
if (abort?.aborted) return;
|
|
3659
3573
|
} finally {
|
|
@@ -3664,7 +3578,11 @@ async function monitorIMessageProvider(opts = {}) {
|
|
|
3664
3578
|
}
|
|
3665
3579
|
}
|
|
3666
3580
|
const activeClient = client;
|
|
3667
|
-
if (!activeClient)
|
|
3581
|
+
if (!activeClient || scheduler.signal.aborted) {
|
|
3582
|
+
detachAbortHandler();
|
|
3583
|
+
await activeClient?.stop();
|
|
3584
|
+
return;
|
|
3585
|
+
}
|
|
3668
3586
|
ingress.start();
|
|
3669
3587
|
const approvalContextLease = opts.channelRuntime ? registerChannelRuntimeContext({
|
|
3670
3588
|
channelRuntime: opts.channelRuntime,
|
|
@@ -3674,32 +3592,29 @@ async function monitorIMessageProvider(opts = {}) {
|
|
|
3674
3592
|
context: { accountId: accountInfo.accountId },
|
|
3675
3593
|
abortSignal: abort
|
|
3676
3594
|
}) : void 0;
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3595
|
+
const approvalScheduler = scheduler.scope();
|
|
3596
|
+
let nextDiscoveryAt = 0;
|
|
3597
|
+
approvalScheduler.schedule({
|
|
3598
|
+
id: "approval-reactions",
|
|
3599
|
+
delayMs: 0,
|
|
3600
|
+
everyMs: APPROVAL_REACTION_POLL_INTERVAL_MS,
|
|
3601
|
+
run: () => {
|
|
3602
|
+
const now = approvalScheduler.now();
|
|
3603
|
+
const allowRecentChatDiscovery = now >= nextDiscoveryAt;
|
|
3604
|
+
if (allowRecentChatDiscovery) nextDiscoveryAt = now + APPROVAL_REACTION_DISCOVERY_INTERVAL_MS;
|
|
3605
|
+
return pollPendingIMessageApprovalReactions({
|
|
3606
|
+
signal: approvalScheduler.signal,
|
|
3683
3607
|
client: activeClient,
|
|
3684
3608
|
cfg,
|
|
3685
3609
|
accountId: accountInfo.accountId,
|
|
3686
3610
|
allowRecentChatDiscovery,
|
|
3687
3611
|
gatewayRuntime: approvalGatewayRuntime,
|
|
3688
3612
|
logVerboseMessage: logVerbose
|
|
3613
|
+
}).catch((err) => {
|
|
3614
|
+
logVerbose(`imessage: approval reaction poll failed: ${String(err)}`);
|
|
3689
3615
|
});
|
|
3690
|
-
} catch (err) {
|
|
3691
|
-
logVerbose(`imessage: approval reaction poll failed: ${String(err)}`);
|
|
3692
|
-
} finally {
|
|
3693
|
-
approvalReactionPollInFlight = false;
|
|
3694
3616
|
}
|
|
3695
|
-
};
|
|
3696
|
-
const approvalReactionPollTimer = setInterval(() => {
|
|
3697
|
-
pollApprovalReactions();
|
|
3698
|
-
}, APPROVAL_REACTION_POLL_INTERVAL_MS);
|
|
3699
|
-
const approvalReactionDiscoveryTimer = setInterval(() => {
|
|
3700
|
-
pollApprovalReactions(true);
|
|
3701
|
-
}, APPROVAL_REACTION_DISCOVERY_INTERVAL_MS);
|
|
3702
|
-
pollApprovalReactions(true);
|
|
3617
|
+
});
|
|
3703
3618
|
if (catchupCfg.enabled && !abort?.aborted) {
|
|
3704
3619
|
startupCatchupInProgress = true;
|
|
3705
3620
|
try {
|
|
@@ -3739,13 +3654,94 @@ async function monitorIMessageProvider(opts = {}) {
|
|
|
3739
3654
|
runtime.error?.(danger(`imessage: monitor failed: ${String(err)}`));
|
|
3740
3655
|
throw err;
|
|
3741
3656
|
} finally {
|
|
3742
|
-
|
|
3743
|
-
clearInterval(approvalReactionDiscoveryTimer);
|
|
3657
|
+
approvalScheduler.beginClose();
|
|
3744
3658
|
approvalContextLease?.dispose();
|
|
3745
3659
|
detachAbortHandler();
|
|
3746
3660
|
await activeClient.stop();
|
|
3661
|
+
await approvalScheduler.stop();
|
|
3747
3662
|
await ingress.stop();
|
|
3748
3663
|
}
|
|
3749
3664
|
}
|
|
3750
3665
|
//#endregion
|
|
3751
|
-
|
|
3666
|
+
//#region extensions/imessage/src/channel.runtime.ts
|
|
3667
|
+
async function sendIMessageOutbound(params) {
|
|
3668
|
+
const send = resolveOutboundSendDep(params.deps, "imessage", { legacyKeys: IMESSAGE_LEGACY_OUTBOUND_SEND_DEP_KEYS }) ?? sendMessageIMessage;
|
|
3669
|
+
const maxBytes = resolveChannelMediaMaxBytes({
|
|
3670
|
+
cfg: params.cfg,
|
|
3671
|
+
resolveChannelLimitMb: () => resolveIMessageAccount(params).config.mediaMaxMb
|
|
3672
|
+
});
|
|
3673
|
+
const result = await send(params.to, params.text, {
|
|
3674
|
+
config: params.cfg,
|
|
3675
|
+
...params.mediaUrl ? { mediaUrl: params.mediaUrl } : {},
|
|
3676
|
+
...params.mediaAccess ? { mediaAccess: params.mediaAccess } : {},
|
|
3677
|
+
...params.mediaLocalRoots?.length ? { mediaLocalRoots: params.mediaLocalRoots } : {},
|
|
3678
|
+
...params.mediaReadFile ? { mediaReadFile: params.mediaReadFile } : {},
|
|
3679
|
+
...params.audioAsVoice ? { audioAsVoice: true } : {},
|
|
3680
|
+
maxBytes,
|
|
3681
|
+
accountId: params.accountId ?? void 0,
|
|
3682
|
+
replyToId: params.replyToId ?? void 0,
|
|
3683
|
+
conversationReadOrigin: params.conversationReadOrigin,
|
|
3684
|
+
assertDirectAdapterHandoff: params.assertDirectAdapterHandoff,
|
|
3685
|
+
onPlatformSendDispatch: params.onPlatformSendDispatch,
|
|
3686
|
+
...params.onDeliveryResult ? { onDeliveryResult: params.onDeliveryResult } : {}
|
|
3687
|
+
});
|
|
3688
|
+
const meta = {
|
|
3689
|
+
...result.meta,
|
|
3690
|
+
...result.guid ? { imessageMessageGuid: result.guid } : {},
|
|
3691
|
+
...result.sentText ? { imessageVisibleText: result.sentText } : {}
|
|
3692
|
+
};
|
|
3693
|
+
return Object.keys(meta).length > 0 ? {
|
|
3694
|
+
...result,
|
|
3695
|
+
meta
|
|
3696
|
+
} : result;
|
|
3697
|
+
}
|
|
3698
|
+
async function probeIMessageAccount(params) {
|
|
3699
|
+
return await probeIMessage(params?.timeoutMs, {
|
|
3700
|
+
cliPath: params?.cliPath,
|
|
3701
|
+
dbPath: params?.dbPath,
|
|
3702
|
+
remoteHost: params?.remoteHost,
|
|
3703
|
+
forceRefresh: true
|
|
3704
|
+
});
|
|
3705
|
+
}
|
|
3706
|
+
async function startIMessageGatewayAccount(ctx) {
|
|
3707
|
+
const account = ctx.account;
|
|
3708
|
+
const cliPath = account.config.cliPath?.trim() || "imsg";
|
|
3709
|
+
const dbPath = account.config.dbPath?.trim();
|
|
3710
|
+
ctx.setStatus({
|
|
3711
|
+
accountId: account.accountId,
|
|
3712
|
+
cliPath,
|
|
3713
|
+
dbPath: dbPath ?? null
|
|
3714
|
+
});
|
|
3715
|
+
await Promise.all(listEnabledIMessageAccounts(ctx.cfg).map(async (candidate) => {
|
|
3716
|
+
await resolveIMessageRemoteHost({
|
|
3717
|
+
cliPath: candidate.config.cliPath?.trim() || "imsg",
|
|
3718
|
+
remoteHost: candidate.config.remoteHost
|
|
3719
|
+
});
|
|
3720
|
+
}));
|
|
3721
|
+
const ownerAccountId = resolveIMessageDuplicateSourceOwner({
|
|
3722
|
+
cfg: ctx.cfg,
|
|
3723
|
+
account
|
|
3724
|
+
});
|
|
3725
|
+
if (ownerAccountId) {
|
|
3726
|
+
ctx.log?.info?.(`[${account.accountId}] skipping watcher: duplicate iMessage source; using account "${ownerAccountId}"`);
|
|
3727
|
+
await waitForAbortSignal(ctx.abortSignal);
|
|
3728
|
+
return;
|
|
3729
|
+
}
|
|
3730
|
+
const statusSink = createAccountStatusSink({
|
|
3731
|
+
accountId: account.accountId,
|
|
3732
|
+
setStatus: ctx.setStatus
|
|
3733
|
+
});
|
|
3734
|
+
statusSink({ lifecycle: "starting" });
|
|
3735
|
+
ctx.log?.info?.(`[${account.accountId}] starting provider (${cliPath}${dbPath ? ` db=${dbPath}` : ""})`);
|
|
3736
|
+
return await monitorIMessageProvider({
|
|
3737
|
+
scheduler: ctx.scheduler,
|
|
3738
|
+
accountId: account.accountId,
|
|
3739
|
+
config: ctx.cfg,
|
|
3740
|
+
runtime: ctx.runtime,
|
|
3741
|
+
abortSignal: ctx.abortSignal,
|
|
3742
|
+
channelRuntime: ctx.channelRuntime,
|
|
3743
|
+
statusSink
|
|
3744
|
+
});
|
|
3745
|
+
}
|
|
3746
|
+
//#endregion
|
|
3747
|
+
export { imessageSetupWizard, probeIMessageAccount, sendIMessageOutbound, startIMessageGatewayAccount };
|