@openclaw/imessage 2026.8.1-beta.3 → 2026.8.2
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-D00Njxg2.js → accounts-CCirBEIm.js} +4 -5
- package/dist/{actions.runtime-B_xJiBXF.js → actions.runtime-UDLBuS_8.js} +5 -5
- package/dist/api.js +6 -5
- package/dist/{approval-handler.runtime-BKku8aUf.js → approval-handler.runtime-ZaQQ2c4l.js} +9 -8
- package/dist/{approval-reactions-BME5eA6T.js → approval-reactions-B2-_97DN.js} +7 -11
- package/dist/{channel-BFQTpvrG.js → channel-B0wzN0uJ.js} +18 -16
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-BjkXwX9_.js → channel.runtime-lJfW7FBd.js} +60 -13
- package/dist/{config-schema-DV0KP5nC.js → config-schema-DuGbA8Kp.js} +8 -7
- package/dist/contract-api.js +1 -1
- package/dist/doctor-contract-api.js +8 -281
- package/dist/{group-policy-Ca3c5KES.js → group-policy-fYokgrgz.js} +25 -23
- package/dist/media-contract-api.js +1 -1
- package/dist/{media-contract-BEgdvYhW.js → media-contract-pns3TSS5.js} +3 -2
- package/dist/{message-tool-api-TZiNYA17.js → message-tool-api-CLWaomvw.js} +9 -7
- package/dist/message-tool-api.js +1 -1
- package/dist/{monitor-Uv5RaRTk.js → monitor-CSTZ-GFU.js} +304 -40
- package/dist/{question-reactions-to0i8vxE.js → question-reactions-viP7ZcyG.js} +1 -1
- package/dist/{reaction-context-DaNrZqYo.js → reaction-context-BAYI7pz0.js} +2 -2
- package/dist/{remote-file-CDuk0joc.js → remote-file-CmdycSRk.js} +9 -8
- package/dist/runtime-Cza4CY5T.js +8 -0
- package/dist/runtime-api.js +10 -9
- package/dist/{sanitize-outbound-DaLmdkbf.js → sanitize-outbound-DKRlFQoD.js} +371 -80
- package/dist/{send-Dake4Awx.js → send-DxhFcMfW.js} +146 -24
- package/dist/state-contract-DvahEY4X.js +56 -0
- package/dist/state-migrations-BhY4RwjU.js +277 -0
- package/node_modules/typebox/build/format/date.d.mts +1 -1
- package/node_modules/typebox/build/format/date.mjs +1 -1
- package/node_modules/typebox/build/format/date_time.d.mts +2 -2
- package/node_modules/typebox/build/format/date_time.mjs +3 -3
- package/node_modules/typebox/build/format/email.d.mts +1 -1
- package/node_modules/typebox/build/format/email.mjs +2 -2
- package/node_modules/typebox/build/format/hostname.mjs +2 -10
- package/node_modules/typebox/build/format/idn_email.d.mts +1 -1
- package/node_modules/typebox/build/format/idn_email.mjs +3 -3
- package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idn_hostname.mjs +3 -11
- package/node_modules/typebox/build/format/idna/format/bidi.d.mts +3 -0
- package/node_modules/typebox/build/format/idna/format/bidi.mjs +98 -0
- package/node_modules/typebox/build/format/idna/format/puny.d.mts +3 -0
- package/node_modules/typebox/build/format/idna/format/puny.mjs +144 -0
- package/node_modules/typebox/build/format/idna/hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/hostname.mjs +16 -0
- package/node_modules/typebox/build/format/idna/idn-hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/idn-hostname.mjs +41 -0
- package/node_modules/typebox/build/format/idna/index.d.mts +2 -0
- package/node_modules/typebox/build/format/idna/index.mjs +2 -0
- package/node_modules/typebox/build/format/idna/label/ascii.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/ascii.mjs +9 -0
- package/node_modules/typebox/build/format/idna/label/puny.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/puny.mjs +28 -0
- package/node_modules/typebox/build/format/idna/label/unicode.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/unicode.mjs +106 -0
- package/node_modules/typebox/build/format/idna/pattern/pattern.d.mts +30 -0
- package/node_modules/typebox/build/format/idna/pattern/pattern.mjs +70 -0
- package/node_modules/typebox/build/format/ipv4.d.mts +0 -1
- package/node_modules/typebox/build/format/ipv4.mjs +2 -32
- package/node_modules/typebox/build/format/ipv6.mjs +2 -61
- package/node_modules/typebox/build/format/iri.d.mts +2 -2
- package/node_modules/typebox/build/format/iri.mjs +26 -8
- package/node_modules/typebox/build/format/iri_reference.d.mts +2 -2
- package/node_modules/typebox/build/format/iri_reference.mjs +9 -55
- package/node_modules/typebox/build/format/regex.d.mts +1 -2
- package/node_modules/typebox/build/format/regex.mjs +2 -6
- package/node_modules/typebox/build/format/time.d.mts +2 -2
- package/node_modules/typebox/build/format/time.mjs +19 -14
- package/node_modules/typebox/build/format/uri.d.mts +1 -1
- package/node_modules/typebox/build/format/uri.mjs +3 -130
- package/node_modules/typebox/build/format/uri_reference.d.mts +1 -1
- package/node_modules/typebox/build/format/uri_reference.mjs +2 -3
- package/node_modules/typebox/build/format/uri_template.d.mts +2 -3
- package/node_modules/typebox/build/format/uri_template.mjs +4 -5
- package/node_modules/typebox/build/format/url.d.mts +3 -3
- package/node_modules/typebox/build/format/url.mjs +4 -5
- package/node_modules/typebox/build/guard/emit.d.mts +3 -1
- package/node_modules/typebox/build/guard/emit.mjs +12 -5
- package/node_modules/typebox/build/guard/guard.d.mts +8 -2
- package/node_modules/typebox/build/guard/guard.mjs +25 -4
- package/node_modules/typebox/build/guard/string.d.mts +2 -2
- package/node_modules/typebox/build/guard/string.mjs +7 -7
- package/node_modules/typebox/build/schema/engine/_context.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/_functions.mjs +1 -2
- package/node_modules/typebox/build/schema/engine/_regexp.d.mts +2 -0
- package/node_modules/typebox/build/schema/engine/_regexp.mjs +4 -0
- package/node_modules/typebox/build/schema/engine/_stack.mjs +12 -13
- package/node_modules/typebox/build/schema/engine/additionalItems.mjs +17 -7
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +4 -3
- package/node_modules/typebox/build/schema/engine/contains.mjs +18 -6
- package/node_modules/typebox/build/schema/engine/enum.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/items.mjs +26 -6
- package/node_modules/typebox/build/schema/engine/maxContains.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/minContains.mjs +14 -4
- package/node_modules/typebox/build/schema/engine/not.mjs +4 -2
- package/node_modules/typebox/build/schema/engine/oneOf.mjs +7 -6
- package/node_modules/typebox/build/schema/engine/pattern.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +4 -3
- package/node_modules/typebox/build/schema/engine/ref.mjs +1 -7
- package/node_modules/typebox/build/schema/engine/schema.mjs +13 -4
- package/node_modules/typebox/build/schema/engine/type.mjs +1 -1
- package/node_modules/typebox/build/schema/resolve/resolve.d.mts +4 -1
- package/node_modules/typebox/build/schema/resolve/resolve.mjs +202 -1
- package/node_modules/typebox/build/schema/static/propertyNames.d.mts +5 -0
- package/node_modules/typebox/build/schema/static/propertyNames.mjs +3 -0
- package/node_modules/typebox/build/schema/static/schema.d.mts +3 -0
- package/node_modules/typebox/build/schema/types/index.d.mts +0 -2
- package/node_modules/typebox/build/schema/types/index.mjs +0 -2
- package/node_modules/typebox/build/system/memory/clone.mjs +14 -11
- package/node_modules/typebox/build/system/memory/discard.mjs +6 -5
- package/node_modules/typebox/build/system/settings/settings.d.mts +9 -0
- package/node_modules/typebox/build/system/settings/settings.mjs +2 -0
- package/node_modules/typebox/build/type/engine/call/distribute_arguments.d.mts +6 -1
- package/node_modules/typebox/build/type/engine/call/distribute_arguments.mjs +16 -3
- package/node_modules/typebox/build/type/engine/call/instantiate.mjs +34 -4
- package/node_modules/typebox/build/type/engine/evaluate/broaden.d.mts +5 -5
- package/node_modules/typebox/build/type/engine/evaluate/broaden.mjs +20 -26
- package/node_modules/typebox/build/type/engine/evaluate/compare.d.mts +6 -10
- package/node_modules/typebox/build/type/engine/evaluate/compare.mjs +9 -13
- package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +7 -4
- package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +12 -19
- package/node_modules/typebox/build/type/engine/evaluate/distribute.d.mts +4 -20
- package/node_modules/typebox/build/type/engine/evaluate/distribute.mjs +8 -20
- package/node_modules/typebox/build/type/engine/evaluate/evaluate.d.mts +4 -4
- package/node_modules/typebox/build/type/engine/evaluate/evaluate.mjs +11 -8
- package/node_modules/typebox/build/type/engine/evaluate/flatten.d.mts +1 -1
- package/node_modules/typebox/build/type/engine/evaluate/flatten.mjs +3 -4
- package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +17 -2
- package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +26 -6
- package/node_modules/typebox/build/type/engine/exclude/operation.mjs +3 -4
- package/node_modules/typebox/build/type/engine/extract/operation.d.mts +1 -1
- package/node_modules/typebox/build/type/engine/extract/operation.mjs +3 -4
- package/node_modules/typebox/build/type/engine/priority/priority.d.mts +2 -2
- package/node_modules/typebox/build/type/engine/priority/priority.mjs +3 -4
- package/node_modules/typebox/build/type/script/mapping.d.mts +32 -29
- package/node_modules/typebox/build/type/script/mapping.mjs +18 -25
- package/node_modules/typebox/build/type/script/parser.d.mts +19 -25
- package/node_modules/typebox/build/type/script/parser.mjs +27 -23
- package/node_modules/typebox/build/value/errors/errors.d.mts +2 -2
- package/node_modules/typebox/build/value/errors/errors.mjs +1 -1
- package/node_modules/typebox/package.json +27 -27
- package/node_modules/typebox/readme.md +79 -82
- package/openclaw.plugin.json +0 -6
- package/package.json +5 -5
- package/dist/catchup-Dh-Rv4Ur.js +0 -294
- package/dist/monitor-reply-cache-BdeUQaHO.js +0 -353
- package/dist/persisted-echo-cache-DGxy-J4t.js +0 -143
- package/node_modules/typebox/build/format/_idna.d.mts +0 -2
- package/node_modules/typebox/build/format/_idna.mjs +0 -246
- package/node_modules/typebox/build/format/_puny.d.mts +0 -1
- package/node_modules/typebox/build/format/_puny.mjs +0 -77
- package/node_modules/typebox/build/schema/resolve/ref.d.mts +0 -3
- package/node_modules/typebox/build/schema/resolve/ref.mjs +0 -146
- package/node_modules/typebox/build/schema/types/contentEncoding.d.mts +0 -9
- package/node_modules/typebox/build/schema/types/contentEncoding.mjs +0 -13
- package/node_modules/typebox/build/schema/types/contentMediaType.d.mts +0 -9
- package/node_modules/typebox/build/schema/types/contentMediaType.mjs +0 -13
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import { d as resolveIMessageChatDbLookupPath, f as resolveIMessageHomeDir, l as resolveIMessageRemoteHost, o as resolveIMessageAccount } from "./accounts-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { t as
|
|
12
|
-
import { n as maybeResolveIMessageQuestionReaction, t as hasIMessageQuestionReactionTarget } from "./question-reactions-to0i8vxE.js";
|
|
1
|
+
import { d as resolveIMessageChatDbLookupPath, f as resolveIMessageHomeDir, l as resolveIMessageRemoteHost, o as resolveIMessageAccount } from "./accounts-CCirBEIm.js";
|
|
2
|
+
import { c as parseIMessageAllowTarget, f as getCachedIMessagePrivateApiStatus, i as isAllowedIMessageReplyContextSender, l as parseIMessageTarget, n as formatIMessageChatTarget, p as imessageRpcSupportsMethod, s as normalizeIMessageHandle } from "./message-tool-api-CLWaomvw.js";
|
|
3
|
+
import { l as isKnownFromMeIMessageMessageId, o as createIMessageRpcClient, r as sanitizeOutboundText, u as rememberIMessageReplyCache, v as resolveIMessageDirectChatService } from "./sanitize-outbound-DKRlFQoD.js";
|
|
4
|
+
import { f as probeIMessage, r as resolveIMessageInboundConversationId } from "./group-policy-fYokgrgz.js";
|
|
5
|
+
import { t as getIMessageRuntime } from "./runtime-Cza4CY5T.js";
|
|
6
|
+
import { d as resolveIMessageEchoMediaKey, l as capFailureRetriesMap, t as IMESSAGE_CATCHUP_CURSOR_NAMESPACE, u as resolveIMessageCatchupCursorKey } from "./state-contract-DvahEY4X.js";
|
|
7
|
+
import { n as resolveIMessageAttachmentRoots, r as resolveIMessageRemoteAttachmentRoots } from "./media-contract-pns3TSS5.js";
|
|
8
|
+
import { i as registerIMessageApprovalReactionTarget, n as handleIMessageApprovalReaction, o as listPendingIMessageApprovalReactionPollTargets, r as maybeResolveIMessageApprovalReaction, s as buildIMessageApprovalConversationKeyForInbound } from "./approval-reactions-B2-_97DN.js";
|
|
9
|
+
import { c as iMessageApprovalControlBindings, n as hasPersistedIMessageEcho, r as stripLeadingEchoTextCorruptionMarkers, s as maybeResolveIMessageApprovalPollVote, t as sendMessageIMessage } from "./send-DxhFcMfW.js";
|
|
10
|
+
import { t as resolveIMessageReactionContext } from "./reaction-context-BAYI7pz0.js";
|
|
11
|
+
import { n as maybeResolveIMessageQuestionReaction, t as hasIMessageQuestionReactionTarget } from "./question-reactions-viP7ZcyG.js";
|
|
13
12
|
import { bindIngressLifecycleToReplyOptions, createChannelIngressError, createChannelIngressMonitor, createChannelMessageReplyPipeline, createMessageReceiptFromOutboundResults, listMessageReceiptPlatformIds, resolveChannelStreamingBlockEnabled } from "openclaw/plugin-sdk/channel-outbound";
|
|
14
13
|
import { chunkMarkdownTextWithMode as chunkTextWithMode, resolveChunkMode, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime";
|
|
15
14
|
import { resolveAgentRoute, resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
|
|
@@ -18,17 +17,15 @@ import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
|
18
17
|
import { asSafeIntegerInRange, hasNonEmptyString, isRecord, normalizeOptionalString, normalizeStringEntries, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
19
18
|
import fs from "node:fs/promises";
|
|
20
19
|
import { createNonExitingRuntime, danger, logVerbose, shouldLogVerbose, warn } from "openclaw/plugin-sdk/runtime-env";
|
|
21
|
-
import {
|
|
20
|
+
import { isInboundPathAllowed, kindFromMime } from "openclaw/plugin-sdk/media-runtime";
|
|
21
|
+
import { asDateTimestampMs, asPositiveFiniteNumber, parseDateStringTimestampMs, resolveIntegerOption, timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
|
22
22
|
import { createHash } from "node:crypto";
|
|
23
23
|
import { getRuntimeConfig } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
24
24
|
import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
25
25
|
import { collectErrorGraphCandidates, formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
26
|
-
import { isInboundPathAllowed, kindFromMime } from "openclaw/plugin-sdk/media-runtime";
|
|
27
|
-
import { convertMarkdownTables as convertMarkdownTables$1, findCodeRegions, isInsideCode, sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
|
|
28
26
|
import { buildChannelGroupsScopeTree, resolveChannelGroupPolicy, resolveScopeRequireMention } from "openclaw/plugin-sdk/channel-policy";
|
|
27
|
+
import { convertMarkdownTables as convertMarkdownTables$1, findCodeRegions, isInsideCode, sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
|
|
29
28
|
import { buildChannelInboundEventContext, buildMentionRegexes, createChannelInboundDebouncer, createChannelPartialDeliveryError, filterChannelInboundQuoteContext, formatInboundEnvelope, formatInboundFromLabel, formatInboundMediaUnavailableText, formatMediaPlaceholderText, isChannelPartialDeliveryError, logInboundDrop, matchesMentionPatterns, resolveEnvelopeFormatOptions, resolveInboundMentionDecision, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent, shouldDebounceTextInbound, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
|
|
30
|
-
import { openLocalFileSafely, resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
|
|
31
|
-
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
|
|
32
29
|
import { resolveAgentConfig, resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
|
|
33
30
|
import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-runtime";
|
|
34
31
|
import { logTypingFailure } from "openclaw/plugin-sdk/channel-feedback";
|
|
@@ -40,12 +37,14 @@ import { channelReadyPatch } from "openclaw/plugin-sdk/gateway-runtime";
|
|
|
40
37
|
import { redactIdentifier } from "openclaw/plugin-sdk/logging-core";
|
|
41
38
|
import { DEFAULT_GROUP_HISTORY_LIMIT, createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
|
|
42
39
|
import { resolveDefaultGroupPolicy, resolveOpenProviderRuntimeGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
|
|
40
|
+
import { openLocalFileSafely, resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
|
|
43
41
|
import { getSessionEntry, readSessionUpdatedAt, resolveSendPolicy, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
44
42
|
import { openNodeSqliteDatabase } from "openclaw/plugin-sdk/sqlite-runtime";
|
|
45
43
|
import { waitForTransportReady } from "openclaw/plugin-sdk/transport-ready-runtime";
|
|
46
44
|
import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
47
45
|
import { resolveMarkdownTableMode as resolveMarkdownTableMode$1 } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
48
46
|
import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
|
|
47
|
+
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
|
|
49
48
|
import { deliverTextOrMediaReply, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
|
|
50
49
|
import { createDedupeCache } from "openclaw/plugin-sdk/dedupe-runtime";
|
|
51
50
|
import { hasControlCommand } from "openclaw/plugin-sdk/command-auth-native";
|
|
@@ -264,6 +263,269 @@ function attachIMessageMonitorAbortHandler(params) {
|
|
|
264
263
|
return () => abort.removeEventListener("abort", onAbort);
|
|
265
264
|
}
|
|
266
265
|
//#endregion
|
|
266
|
+
//#region extensions/imessage/src/monitor/catchup.ts
|
|
267
|
+
const DEFAULT_MAX_AGE_MINUTES = 120;
|
|
268
|
+
const MAX_MAX_AGE_MINUTES = 720;
|
|
269
|
+
const DEFAULT_PER_RUN_LIMIT = 50;
|
|
270
|
+
const MAX_PER_RUN_LIMIT = 500;
|
|
271
|
+
const DEFAULT_FIRST_RUN_LOOKBACK_MINUTES = 30;
|
|
272
|
+
const DEFAULT_MAX_FAILURE_RETRIES = 10;
|
|
273
|
+
const MAX_MAX_FAILURE_RETRIES = 1e3;
|
|
274
|
+
const cursorWriteQueue = new KeyedAsyncQueue();
|
|
275
|
+
function openCatchupCursorStore() {
|
|
276
|
+
return getIMessageRuntime().state.openSyncKeyedStore({
|
|
277
|
+
namespace: IMESSAGE_CATCHUP_CURSOR_NAMESPACE,
|
|
278
|
+
maxEntries: 256
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
function updateCatchupCursorStore(key, updateValue) {
|
|
282
|
+
const store = openCatchupCursorStore();
|
|
283
|
+
if (!store.update) throw new Error("iMessage catchup cursor persistence requires atomic plugin-state update.");
|
|
284
|
+
return store.update(key, updateValue);
|
|
285
|
+
}
|
|
286
|
+
function enqueueCursorWrite(accountId, fn) {
|
|
287
|
+
const key = resolveIMessageCatchupCursorKey(accountId);
|
|
288
|
+
return cursorWriteQueue.enqueue(key, fn);
|
|
289
|
+
}
|
|
290
|
+
function sanitizeFailureRetriesInput(raw) {
|
|
291
|
+
if (!raw || typeof raw !== "object") return {};
|
|
292
|
+
const out = {};
|
|
293
|
+
for (const [guid, count] of Object.entries(raw)) {
|
|
294
|
+
if (!guid || typeof guid !== "string") continue;
|
|
295
|
+
if (typeof count !== "number" || !Number.isFinite(count) || count <= 0) continue;
|
|
296
|
+
out[guid] = Math.floor(count);
|
|
297
|
+
}
|
|
298
|
+
return out;
|
|
299
|
+
}
|
|
300
|
+
function normalizeIMessageCatchupCursor(value) {
|
|
301
|
+
if (!value || typeof value !== "object") return null;
|
|
302
|
+
const raw = value;
|
|
303
|
+
if (typeof raw.lastSeenMs !== "number" || !Number.isFinite(raw.lastSeenMs)) return null;
|
|
304
|
+
if (typeof raw.lastSeenRowid !== "number" || !Number.isFinite(raw.lastSeenRowid)) return null;
|
|
305
|
+
const failureRetries = sanitizeFailureRetriesInput(raw.failureRetries);
|
|
306
|
+
const hasRetries = Object.keys(failureRetries).length > 0;
|
|
307
|
+
return {
|
|
308
|
+
lastSeenMs: raw.lastSeenMs,
|
|
309
|
+
lastSeenRowid: raw.lastSeenRowid,
|
|
310
|
+
updatedAt: typeof raw.updatedAt === "number" ? raw.updatedAt : 0,
|
|
311
|
+
...hasRetries ? { failureRetries } : {}
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
function readIMessageCatchupCursor(accountId) {
|
|
315
|
+
return normalizeIMessageCatchupCursor(openCatchupCursorStore().lookup(resolveIMessageCatchupCursorKey(accountId)));
|
|
316
|
+
}
|
|
317
|
+
async function loadIMessageCatchupCursor(accountId) {
|
|
318
|
+
return readIMessageCatchupCursor(accountId);
|
|
319
|
+
}
|
|
320
|
+
function buildIMessageCatchupCursor(next) {
|
|
321
|
+
const sanitized = sanitizeFailureRetriesInput(next.failureRetries);
|
|
322
|
+
const hasRetries = Object.keys(sanitized).length > 0;
|
|
323
|
+
return {
|
|
324
|
+
lastSeenMs: next.lastSeenMs,
|
|
325
|
+
lastSeenRowid: next.lastSeenRowid,
|
|
326
|
+
updatedAt: Date.now(),
|
|
327
|
+
...hasRetries ? { failureRetries: sanitized } : {}
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
async function saveIMessageCatchupCursor(accountId, next, options = {}) {
|
|
331
|
+
const cursor = buildIMessageCatchupCursor(next);
|
|
332
|
+
updateCatchupCursorStore(resolveIMessageCatchupCursorKey(accountId), (existingValue) => {
|
|
333
|
+
const existing = normalizeIMessageCatchupCursor(existingValue);
|
|
334
|
+
if (existing && cursor.lastSeenRowid < existing.lastSeenRowid) {
|
|
335
|
+
if (!options.allowCursorRewindForRetries) return;
|
|
336
|
+
return buildIMessageCatchupCursor({
|
|
337
|
+
lastSeenMs: cursor.lastSeenMs,
|
|
338
|
+
lastSeenRowid: cursor.lastSeenRowid,
|
|
339
|
+
failureRetries: {
|
|
340
|
+
...existing.failureRetries,
|
|
341
|
+
...cursor.failureRetries
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
return cursor;
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
function clampInt(value, min, max, fallback) {
|
|
349
|
+
return resolveIntegerOption(value, fallback, {
|
|
350
|
+
min,
|
|
351
|
+
max
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
function resolveCatchupConfig(raw) {
|
|
355
|
+
return {
|
|
356
|
+
enabled: Boolean(raw?.enabled),
|
|
357
|
+
maxAgeMinutes: clampInt(raw?.maxAgeMinutes, 1, MAX_MAX_AGE_MINUTES, DEFAULT_MAX_AGE_MINUTES),
|
|
358
|
+
perRunLimit: clampInt(raw?.perRunLimit, 1, MAX_PER_RUN_LIMIT, DEFAULT_PER_RUN_LIMIT),
|
|
359
|
+
firstRunLookbackMinutes: clampInt(raw?.firstRunLookbackMinutes, 1, MAX_MAX_AGE_MINUTES, DEFAULT_FIRST_RUN_LOOKBACK_MINUTES),
|
|
360
|
+
maxFailureRetries: clampInt(raw?.maxFailureRetries, 1, MAX_MAX_FAILURE_RETRIES, DEFAULT_MAX_FAILURE_RETRIES)
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
async function advanceIMessageCatchupCursor(accountId, next, config) {
|
|
364
|
+
if (!Number.isFinite(next.lastSeenMs) || !Number.isFinite(next.lastSeenRowid)) return false;
|
|
365
|
+
return await enqueueCursorWrite(accountId, async () => {
|
|
366
|
+
let advanced = false;
|
|
367
|
+
updateCatchupCursorStore(resolveIMessageCatchupCursorKey(accountId), (existingValue) => {
|
|
368
|
+
const cursor = normalizeIMessageCatchupCursor(existingValue);
|
|
369
|
+
if (cursor && next.lastSeenRowid <= cursor.lastSeenRowid) return;
|
|
370
|
+
if (Object.values(cursor?.failureRetries ?? {}).some((count) => count < config.maxFailureRetries)) return;
|
|
371
|
+
advanced = true;
|
|
372
|
+
return buildIMessageCatchupCursor({
|
|
373
|
+
lastSeenMs: Math.max(cursor?.lastSeenMs ?? next.lastSeenMs, next.lastSeenMs),
|
|
374
|
+
lastSeenRowid: next.lastSeenRowid,
|
|
375
|
+
failureRetries: cursor?.failureRetries
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
return advanced;
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* One catchup pass. Loads the cursor, fetches `messages.history`, replays
|
|
383
|
+
* each row through `dispatch`, advances the cursor on success / give-up,
|
|
384
|
+
* persists the cursor, returns a summary.
|
|
385
|
+
*
|
|
386
|
+
* The fetch and dispatch functions are injected so this loop is unit-testable
|
|
387
|
+
* without standing up an `imsg` daemon. The wiring in `monitor-provider.ts`
|
|
388
|
+
* passes the live `client.request("messages.history", ...)` adapter as
|
|
389
|
+
* `fetch` and the `evaluateIMessageInbound` + `runChannelInboundEvent`
|
|
390
|
+
* pipeline as `dispatch`.
|
|
391
|
+
*/
|
|
392
|
+
async function performIMessageCatchup(params) {
|
|
393
|
+
const now = params.now ?? Date.now();
|
|
394
|
+
const cfg = params.config;
|
|
395
|
+
const cursor = await loadIMessageCatchupCursor(params.accountId);
|
|
396
|
+
const lookbackMs = cursor === null ? cfg.firstRunLookbackMinutes * 6e4 : cfg.maxAgeMinutes * 6e4;
|
|
397
|
+
const ageBoundMs = now - cfg.maxAgeMinutes * 6e4;
|
|
398
|
+
const windowStartMs = Math.max(cursor?.lastSeenMs ?? now - lookbackMs, ageBoundMs);
|
|
399
|
+
const windowEndMs = now;
|
|
400
|
+
const sinceRowid = cursor?.lastSeenRowid ?? 0;
|
|
401
|
+
const summary = {
|
|
402
|
+
querySucceeded: false,
|
|
403
|
+
fullyCaughtUp: false,
|
|
404
|
+
fetchedCount: 0,
|
|
405
|
+
replayed: 0,
|
|
406
|
+
skippedFromMe: 0,
|
|
407
|
+
skippedPreCursor: 0,
|
|
408
|
+
skippedGivenUp: 0,
|
|
409
|
+
failed: 0,
|
|
410
|
+
givenUp: 0,
|
|
411
|
+
cursorBefore: cursor ? {
|
|
412
|
+
lastSeenMs: cursor.lastSeenMs,
|
|
413
|
+
lastSeenRowid: cursor.lastSeenRowid
|
|
414
|
+
} : null,
|
|
415
|
+
cursorAfter: {
|
|
416
|
+
lastSeenMs: cursor?.lastSeenMs ?? windowStartMs,
|
|
417
|
+
lastSeenRowid: cursor?.lastSeenRowid ?? 0
|
|
418
|
+
},
|
|
419
|
+
windowStartMs,
|
|
420
|
+
windowEndMs
|
|
421
|
+
};
|
|
422
|
+
let fetchResult;
|
|
423
|
+
try {
|
|
424
|
+
fetchResult = await params.fetch({
|
|
425
|
+
sinceMs: windowStartMs,
|
|
426
|
+
sinceRowid,
|
|
427
|
+
limit: cfg.perRunLimit
|
|
428
|
+
});
|
|
429
|
+
} catch (err) {
|
|
430
|
+
params.warn?.(`imessage catchup: fetch failed: ${String(err)}`);
|
|
431
|
+
return summary;
|
|
432
|
+
}
|
|
433
|
+
if (!fetchResult.resolved) {
|
|
434
|
+
params.warn?.(`imessage catchup: fetch returned unresolved result`);
|
|
435
|
+
return summary;
|
|
436
|
+
}
|
|
437
|
+
summary.querySucceeded = true;
|
|
438
|
+
summary.fullyCaughtUp = fetchResult.fullyCaughtUp !== false;
|
|
439
|
+
summary.fetchedCount = fetchResult.rows.length;
|
|
440
|
+
const rows = fetchResult.rows.toSorted((a, b) => a.rowid - b.rowid);
|
|
441
|
+
const failureRetries = { ...cursor?.failureRetries };
|
|
442
|
+
const cursorBeforeMs = cursor?.lastSeenMs ?? windowStartMs;
|
|
443
|
+
const cursorBeforeRowid = cursor?.lastSeenRowid ?? 0;
|
|
444
|
+
let highWatermarkMs = cursorBeforeMs;
|
|
445
|
+
let highWatermarkRowid = cursorBeforeRowid;
|
|
446
|
+
let earliestHeldFailureRow = null;
|
|
447
|
+
for (const row of rows) {
|
|
448
|
+
if (row.rowid <= sinceRowid) {
|
|
449
|
+
summary.skippedPreCursor += 1;
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
if (row.date < ageBoundMs) {
|
|
453
|
+
summary.skippedPreCursor += 1;
|
|
454
|
+
highWatermarkMs = Math.max(highWatermarkMs, row.date);
|
|
455
|
+
highWatermarkRowid = Math.max(highWatermarkRowid, row.rowid);
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
if (row.isFromMe) {
|
|
459
|
+
try {
|
|
460
|
+
await params.observeSkippedFromMe?.(row);
|
|
461
|
+
} catch (err) {
|
|
462
|
+
params.warn?.(`imessage catchup: from-me observer failed for guid=${row.guid}: ${String(err)}`);
|
|
463
|
+
}
|
|
464
|
+
summary.skippedFromMe += 1;
|
|
465
|
+
highWatermarkMs = Math.max(highWatermarkMs, row.date);
|
|
466
|
+
highWatermarkRowid = Math.max(highWatermarkRowid, row.rowid);
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
const priorCount = failureRetries[row.guid] ?? 0;
|
|
470
|
+
if (priorCount >= cfg.maxFailureRetries) {
|
|
471
|
+
summary.skippedGivenUp += 1;
|
|
472
|
+
highWatermarkMs = Math.max(highWatermarkMs, row.date);
|
|
473
|
+
highWatermarkRowid = Math.max(highWatermarkRowid, row.rowid);
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
let dispatched;
|
|
477
|
+
try {
|
|
478
|
+
dispatched = await params.dispatch(row);
|
|
479
|
+
} catch (err) {
|
|
480
|
+
params.warn?.(`imessage catchup: dispatch threw for guid=${row.guid}: ${String(err)}`);
|
|
481
|
+
dispatched = { ok: false };
|
|
482
|
+
}
|
|
483
|
+
if (dispatched.ok) {
|
|
484
|
+
summary.replayed += 1;
|
|
485
|
+
delete failureRetries[row.guid];
|
|
486
|
+
highWatermarkMs = Math.max(highWatermarkMs, row.date);
|
|
487
|
+
highWatermarkRowid = Math.max(highWatermarkRowid, row.rowid);
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
const nextCount = priorCount + 1;
|
|
491
|
+
failureRetries[row.guid] = nextCount;
|
|
492
|
+
summary.failed += 1;
|
|
493
|
+
if (nextCount >= cfg.maxFailureRetries) {
|
|
494
|
+
summary.givenUp += 1;
|
|
495
|
+
params.warn?.(`imessage catchup: giving up on guid=${row.guid} after ${nextCount} failures; advancing cursor past it`);
|
|
496
|
+
highWatermarkMs = Math.max(highWatermarkMs, row.date);
|
|
497
|
+
highWatermarkRowid = Math.max(highWatermarkRowid, row.rowid);
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
if (earliestHeldFailureRow === null || row.rowid < earliestHeldFailureRow.rowid) earliestHeldFailureRow = row;
|
|
501
|
+
}
|
|
502
|
+
if (earliestHeldFailureRow === null) {
|
|
503
|
+
if (typeof fetchResult.highWatermarkMs === "number") highWatermarkMs = Math.max(highWatermarkMs, fetchResult.highWatermarkMs);
|
|
504
|
+
if (typeof fetchResult.highWatermarkRowid === "number") highWatermarkRowid = Math.max(highWatermarkRowid, fetchResult.highWatermarkRowid);
|
|
505
|
+
}
|
|
506
|
+
let lastSeenMs;
|
|
507
|
+
let lastSeenRowid;
|
|
508
|
+
if (earliestHeldFailureRow !== null) {
|
|
509
|
+
lastSeenMs = Math.max(cursorBeforeMs, earliestHeldFailureRow.date - 1);
|
|
510
|
+
lastSeenRowid = Math.max(cursorBeforeRowid, earliestHeldFailureRow.rowid - 1);
|
|
511
|
+
} else {
|
|
512
|
+
lastSeenMs = highWatermarkMs;
|
|
513
|
+
lastSeenRowid = highWatermarkRowid;
|
|
514
|
+
}
|
|
515
|
+
const capped = capFailureRetriesMap(failureRetries);
|
|
516
|
+
summary.cursorAfter = {
|
|
517
|
+
lastSeenMs,
|
|
518
|
+
lastSeenRowid
|
|
519
|
+
};
|
|
520
|
+
await saveIMessageCatchupCursor(params.accountId, {
|
|
521
|
+
lastSeenMs,
|
|
522
|
+
lastSeenRowid,
|
|
523
|
+
failureRetries: capped
|
|
524
|
+
}, { allowCursorRewindForRetries: earliestHeldFailureRow !== null });
|
|
525
|
+
if (summary.replayed > 0 || summary.failed > 0 || summary.givenUp > 0) params.log?.(`imessage catchup: replayed=${summary.replayed} skippedFromMe=${summary.skippedFromMe} skippedGivenUp=${summary.skippedGivenUp} failed=${summary.failed} givenUp=${summary.givenUp} fetchedCount=${summary.fetchedCount}`);
|
|
526
|
+
return summary;
|
|
527
|
+
}
|
|
528
|
+
//#endregion
|
|
267
529
|
//#region extensions/imessage/src/monitor/strip-imsg-length-prefixed-text.ts
|
|
268
530
|
const utf8Decoder = new TextDecoder();
|
|
269
531
|
function readVarint(buf, start) {
|
|
@@ -304,9 +566,6 @@ function stripImessageLengthPrefixedUtf8Text(text) {
|
|
|
304
566
|
function isOptionalString(value) {
|
|
305
567
|
return value === void 0 || value === null || typeof value === "string";
|
|
306
568
|
}
|
|
307
|
-
function isOptionalStringOrNumber(value) {
|
|
308
|
-
return value === void 0 || value === null || typeof value === "string" || typeof value === "number";
|
|
309
|
-
}
|
|
310
569
|
function isOptionalNumber(value) {
|
|
311
570
|
return value === void 0 || value === null || typeof value === "number";
|
|
312
571
|
}
|
|
@@ -329,7 +588,7 @@ function parseIMessageNotification(raw) {
|
|
|
329
588
|
const maybeMessage = raw.message;
|
|
330
589
|
if (!isRecord(maybeMessage)) return null;
|
|
331
590
|
const message = maybeMessage;
|
|
332
|
-
if (!isOptionalNumber(message.id) || !isOptionalString(message.guid) || !isOptionalNumber(message.chat_id) || !isOptionalString(message.sender) || !isOptionalString(message.destination_caller_id) || !isOptionalBoolean(message.is_from_me) || !isOptionalString(message.text) || !
|
|
591
|
+
if (!isOptionalNumber(message.id) || !isOptionalString(message.guid) || !isOptionalNumber(message.chat_id) || !isOptionalString(message.sender) || !isOptionalString(message.destination_caller_id) || !isOptionalBoolean(message.is_from_me) || !isOptionalString(message.text) || !isOptionalString(message.thread_originator_guid) || !isOptionalString(message.reply_to_guid) || !isOptionalString(message.reply_to_text) || !isOptionalString(message.reply_to_sender) || !isOptionalString(message.created_at) || !isOptionalBoolean(message.is_reaction) || !isOptionalBoolean(message.is_tapback) || !isOptionalString(message.associated_message_guid) || !isOptionalNumber(message.associated_message_type) || !isOptionalString(message.reaction_type) || !isOptionalString(message.reaction_emoji) || !isOptionalBoolean(message.is_reaction_add) || !isOptionalString(message.reacted_to_guid) || !isOptionalAttachments(message.attachments) || !isOptionalString(message.chat_identifier) || !isOptionalString(message.chat_guid) || !isOptionalString(message.chat_name) || !isOptionalStringArray(message.participants) || !isOptionalBoolean(message.is_group)) return null;
|
|
333
592
|
return {
|
|
334
593
|
...message,
|
|
335
594
|
text: typeof message.text === "string" ? stripImessageLengthPrefixedUtf8Text(message.text) : message.text,
|
|
@@ -518,7 +777,7 @@ function combineIMessagePayloads(payloads) {
|
|
|
518
777
|
const first = expectDefined(payloads[0], "first iMessage payload to coalesce");
|
|
519
778
|
if (payloads.length === 1) return first;
|
|
520
779
|
const last = expectDefined(payloads.at(-1), "last iMessage payload to coalesce");
|
|
521
|
-
const boundedPayloads = payloads.length > MAX_COALESCED_ENTRIES ? [...payloads.slice(0,
|
|
780
|
+
const boundedPayloads = payloads.length > MAX_COALESCED_ENTRIES ? [...payloads.slice(0, 9), last] : payloads;
|
|
522
781
|
const seenTexts = /* @__PURE__ */ new Set();
|
|
523
782
|
const textParts = [];
|
|
524
783
|
for (const payload of boundedPayloads) {
|
|
@@ -549,15 +808,16 @@ function combineIMessagePayloads(payloads) {
|
|
|
549
808
|
seenGuids.add(guid);
|
|
550
809
|
coalescedMessageGuids.push(guid);
|
|
551
810
|
}
|
|
552
|
-
const
|
|
811
|
+
const reply = payloads.find((payload) => payload.thread_originator_guid != null || payload.reply_to_guid != null) ?? first;
|
|
553
812
|
return {
|
|
554
813
|
...first,
|
|
555
814
|
text: combinedText,
|
|
556
815
|
attachments: allAttachments.length > 0 ? allAttachments : null,
|
|
557
816
|
created_at: latestCreatedAt,
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
817
|
+
thread_originator_guid: reply.thread_originator_guid ?? null,
|
|
818
|
+
reply_to_guid: reply.reply_to_guid ?? null,
|
|
819
|
+
reply_to_text: reply.reply_to_text ?? null,
|
|
820
|
+
reply_to_sender: reply.reply_to_sender ?? null,
|
|
561
821
|
coalescedMessageGuids: coalescedMessageGuids.length > 0 ? coalescedMessageGuids : void 0,
|
|
562
822
|
coalescedCatchupCursor: Number.isFinite(maxRowid) && Number.isFinite(maxDateMs) ? {
|
|
563
823
|
lastSeenMs: maxDateMs,
|
|
@@ -700,7 +960,8 @@ async function deliverIMessageReply(params) {
|
|
|
700
960
|
accountId
|
|
701
961
|
});
|
|
702
962
|
const chunkMode = resolveChunkMode(cfg, "imessage", accountId);
|
|
703
|
-
const
|
|
963
|
+
const rawText = sanitizeOutboundText(payload.text ?? "");
|
|
964
|
+
const reply = resolveSendableOutboundReplyParts(payload, { text: convertMarkdownTables$1(rawText, tableMode) });
|
|
704
965
|
const accepted = [];
|
|
705
966
|
const sendAccepted = async (text, mediaUrl) => {
|
|
706
967
|
const sent = await sendMessageIMessage(target, text, {
|
|
@@ -762,7 +1023,8 @@ async function deliverIMessageReply(params) {
|
|
|
762
1023
|
}
|
|
763
1024
|
function createIMessageEchoCachingSend(params) {
|
|
764
1025
|
return async (target, text, opts) => {
|
|
765
|
-
const
|
|
1026
|
+
const sanitizedText = sanitizeOutboundText(text);
|
|
1027
|
+
const sent = await sendMessageIMessage(target, sanitizedText, opts);
|
|
766
1028
|
const scope = `${params.accountId ?? opts.accountId ?? ""}:${target}`;
|
|
767
1029
|
const echoText = sent.echoText ?? (sent.sentText || void 0);
|
|
768
1030
|
params.sentMessageCache?.remember(scope, {
|
|
@@ -977,8 +1239,8 @@ function warnGroupAllowlistDropPerChatOnce(params) {
|
|
|
977
1239
|
}
|
|
978
1240
|
//#endregion
|
|
979
1241
|
//#region extensions/imessage/src/monitor/inbound-dedupe.ts
|
|
980
|
-
const IMESSAGE_STALE_INBOUND_THRESHOLD_MS =
|
|
981
|
-
const IMESSAGE_RECOVERY_MAX_AGE_MS =
|
|
1242
|
+
const IMESSAGE_STALE_INBOUND_THRESHOLD_MS = 9e5;
|
|
1243
|
+
const IMESSAGE_RECOVERY_MAX_AGE_MS = 72e5;
|
|
982
1244
|
/**
|
|
983
1245
|
* Age fence: true when the message's own send date is materially older than
|
|
984
1246
|
* now, i.e. stale backlog rather than a live message. Fails open (returns
|
|
@@ -1177,7 +1439,7 @@ function describeReplyContext(message) {
|
|
|
1177
1439
|
if (!body) return null;
|
|
1178
1440
|
return {
|
|
1179
1441
|
body,
|
|
1180
|
-
id: normalizeReplyField(message.
|
|
1442
|
+
id: normalizeReplyField(message.thread_originator_guid) ?? normalizeReplyField(message.reply_to_guid),
|
|
1181
1443
|
sender: normalizeReplyField(message.reply_to_sender)
|
|
1182
1444
|
};
|
|
1183
1445
|
}
|
|
@@ -1722,6 +1984,7 @@ async function buildIMessageInboundContext(params) {
|
|
|
1722
1984
|
const directService = resolveIMessageDirectChatService(params.accountService, decision.chatGuid) ?? "auto";
|
|
1723
1985
|
const imessageTo = decision.isGroup ? chatTarget || `imessage:${decision.sender}` : `${directService}:${decision.sender}`;
|
|
1724
1986
|
const imessageFrom = decision.isGroup ? `imessage:group:${chatId ?? "unknown"}` : imessageTo;
|
|
1987
|
+
const replyTarget = decision.isGroup ? imessageTo : chatId != null ? `chat_id:${chatId}` : decision.chatGuid ? `chat_guid:${decision.chatGuid}` : imessageTo;
|
|
1725
1988
|
const inboundHistory = !decision.isGroup && params.dmHistory?.inboundHistory ? params.dmHistory.inboundHistory : decision.isGroup && decision.historyKey && params.historyLimit > 0 ? createChannelHistoryWindow({ historyMap: params.groupHistories }).buildInboundHistory({
|
|
1726
1989
|
historyKey: decision.historyKey,
|
|
1727
1990
|
limit: params.historyLimit
|
|
@@ -1749,7 +2012,8 @@ async function buildIMessageInboundContext(params) {
|
|
|
1749
2012
|
from: imessageFrom,
|
|
1750
2013
|
sender: {
|
|
1751
2014
|
id: decision.sender,
|
|
1752
|
-
name: decision.senderNormalized
|
|
2015
|
+
name: decision.senderNormalized,
|
|
2016
|
+
isSelf: params.message.is_from_me === true
|
|
1753
2017
|
},
|
|
1754
2018
|
conversation: {
|
|
1755
2019
|
kind: decision.isGroup ? "group" : "direct",
|
|
@@ -1766,7 +2030,7 @@ async function buildIMessageInboundContext(params) {
|
|
|
1766
2030
|
accountId: decision.route.accountId,
|
|
1767
2031
|
routeSessionKey: decision.route.sessionKey
|
|
1768
2032
|
},
|
|
1769
|
-
reply: { to:
|
|
2033
|
+
reply: { to: replyTarget },
|
|
1770
2034
|
message: {
|
|
1771
2035
|
body: combinedBody,
|
|
1772
2036
|
bodyForAgent: decision.agentBodyText ?? decision.bodyText,
|
|
@@ -1924,7 +2188,7 @@ function createIMessageDurableIngress(options) {
|
|
|
1924
2188
|
},
|
|
1925
2189
|
pollIntervalMs: IMESSAGE_INGRESS_DRAIN_INTERVAL_MS,
|
|
1926
2190
|
retention: {
|
|
1927
|
-
completedTtlMs:
|
|
2191
|
+
completedTtlMs: 144e5,
|
|
1928
2192
|
completedMaxEntries: 1e4,
|
|
1929
2193
|
failedMaxEntries: 1e3
|
|
1930
2194
|
},
|
|
@@ -2051,18 +2315,18 @@ async function readPinnedAttachmentBytes(handle, maxBytes) {
|
|
|
2051
2315
|
let totalBytes = 0;
|
|
2052
2316
|
while (totalBytes <= maxBytes) {
|
|
2053
2317
|
const remaining = maxBytes + 1 - totalBytes;
|
|
2054
|
-
const chunk = Buffer.allocUnsafe(Math.min(
|
|
2318
|
+
const chunk = Buffer.allocUnsafe(Math.min(65536, remaining));
|
|
2055
2319
|
const { bytesRead } = await handle.read(chunk, 0, chunk.length, null);
|
|
2056
2320
|
if (bytesRead === 0) return Buffer.concat(chunks, totalBytes);
|
|
2057
2321
|
chunks.push(chunk.subarray(0, bytesRead));
|
|
2058
2322
|
totalBytes += bytesRead;
|
|
2059
2323
|
}
|
|
2060
|
-
throw new Error(`attachment exceeds ${Math.round(maxBytes /
|
|
2324
|
+
throw new Error(`attachment exceeds ${Math.round(maxBytes / 1048576)}MB limit`);
|
|
2061
2325
|
}
|
|
2062
2326
|
async function readAttachmentBuffer(params) {
|
|
2063
2327
|
const opened = await (params.deps.openLocalFileSafely ?? openLocalFileSafely)({ filePath: params.attachmentPath });
|
|
2064
2328
|
try {
|
|
2065
|
-
if (opened.stat.size > params.maxBytes) throw new Error(`attachment exceeds ${Math.round(params.maxBytes /
|
|
2329
|
+
if (opened.stat.size > params.maxBytes) throw new Error(`attachment exceeds ${Math.round(params.maxBytes / 1048576)}MB limit`);
|
|
2066
2330
|
await assertAllowedCanonicalAttachmentPath({
|
|
2067
2331
|
canonicalPath: opened.realPath,
|
|
2068
2332
|
allowedRoots: params.allowedRoots
|
|
@@ -2442,7 +2706,7 @@ function sanitizeIMessageWatchErrorPayload(payload) {
|
|
|
2442
2706
|
if (typeof payload.code === "number" && Number.isFinite(payload.code)) safe.code = payload.code;
|
|
2443
2707
|
if (typeof payload.message === "string") {
|
|
2444
2708
|
const sanitizedMessage = sanitizeTerminalText(payload.message);
|
|
2445
|
-
if (sanitizedMessage) safe.message = sanitizedMessage.length > MAX_WATCH_ERROR_MESSAGE_CHARS ? `${truncateUtf16Safe(sanitizedMessage,
|
|
2709
|
+
if (sanitizedMessage) safe.message = sanitizedMessage.length > MAX_WATCH_ERROR_MESSAGE_CHARS ? `${truncateUtf16Safe(sanitizedMessage, 199)}…` : sanitizedMessage;
|
|
2446
2710
|
}
|
|
2447
2711
|
return safe;
|
|
2448
2712
|
}
|
|
@@ -2454,7 +2718,7 @@ const CHANNEL_APPROVAL_GATEWAY_RUNTIME_CONTEXT_CAPABILITY = "approval.gateway";
|
|
|
2454
2718
|
const APPROVAL_REACTION_POLL_INTERVAL_MS = 2e3;
|
|
2455
2719
|
const APPROVAL_REACTION_DISCOVERY_INTERVAL_MS = 6e4;
|
|
2456
2720
|
const IMESSAGE_TYPING_KEEPALIVE_INTERVAL_MS = 8e3;
|
|
2457
|
-
const IMESSAGE_TYPING_KEEPALIVE_MAX_DURATION_MS =
|
|
2721
|
+
const IMESSAGE_TYPING_KEEPALIVE_MAX_DURATION_MS = 6e5;
|
|
2458
2722
|
function resolveConfiguredIMessageTypingMode(cfg, agentId) {
|
|
2459
2723
|
return resolveAgentConfig(cfg, agentId)?.typingMode ?? cfg.agents?.defaults?.typingMode;
|
|
2460
2724
|
}
|
|
@@ -2838,7 +3102,7 @@ async function monitorIMessageProvider(opts = {}) {
|
|
|
2838
3102
|
const conversationKey = chatId != null ? `group:${chatId}` : `dm:${senderForKey}`;
|
|
2839
3103
|
const rateLimitKey = `${accountInfo.accountId}:${conversationKey}`;
|
|
2840
3104
|
if (decision.kind === "drop") {
|
|
2841
|
-
if (decision.reason === "echo" || decision.reason === "
|
|
3105
|
+
if (decision.reason === "echo" || decision.reason === "reflected assistant content") loopRateLimiter.record(rateLimitKey);
|
|
2842
3106
|
const diagnostic = describeIMessageInboundDropDiagnostic({
|
|
2843
3107
|
accountId: accountInfo.accountId,
|
|
2844
3108
|
reason: decision.reason,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { t as resolveIMessageReactionContext } from "./reaction-context-
|
|
2
|
+
import { t as resolveIMessageReactionContext } from "./reaction-context-BAYI7pz0.js";
|
|
3
3
|
import { createQuestionReactionTargetStore, questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
|
|
4
4
|
//#region extensions/imessage/src/question-reactions.ts
|
|
5
5
|
var question_reactions_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -80,11 +80,11 @@ function resolveTapbackTextContext(bodyText) {
|
|
|
80
80
|
for (const pattern of TAPBACK_TEXT_PATTERNS) {
|
|
81
81
|
if (!lower.startsWith(pattern.prefix)) continue;
|
|
82
82
|
const afterPrefix = bodyText.slice(pattern.prefix.length).trim();
|
|
83
|
-
if (!/^["
|
|
83
|
+
if (!/^(?:"[\s\S]*"|“[\s\S]*”)$/u.test(afterPrefix)) continue;
|
|
84
84
|
return {
|
|
85
85
|
action: pattern.action,
|
|
86
86
|
emoji: pattern.emoji,
|
|
87
|
-
targetText: afterPrefix.
|
|
87
|
+
targetText: afterPrefix.slice(1, -1).trim()
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
return null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { p as resolveLocalIMessageChatDbPath, u as expandIMessageUserPath } from "./accounts-
|
|
2
|
-
import {
|
|
1
|
+
import { p as resolveLocalIMessageChatDbPath, u as expandIMessageUserPath } from "./accounts-CCirBEIm.js";
|
|
2
|
+
import { d as resolveIMessageCachedResourceBinding, f as resolveIMessageMessageId, g as isIMessageEmailChatIdentifier, h as chatContextFromIMessageTarget } from "./sanitize-outbound-DKRlFQoD.js";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { normalizeScpRemoteHost } from "openclaw/plugin-sdk/host-runtime";
|
|
5
5
|
import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
|
|
@@ -9,8 +9,8 @@ import { runCommandWithTimeout } from "openclaw/plugin-sdk/process-runtime";
|
|
|
9
9
|
import { openNodeSqliteDatabase } from "openclaw/plugin-sdk/sqlite-runtime";
|
|
10
10
|
import { sanitizeTempFileName } from "openclaw/plugin-sdk/temp-path";
|
|
11
11
|
//#region extensions/imessage/src/cli-output.ts
|
|
12
|
-
const IMESSAGE_CLI_STDOUT_MAX_BYTES =
|
|
13
|
-
const IMESSAGE_CLI_STDERR_TAIL_BYTES =
|
|
12
|
+
const IMESSAGE_CLI_STDOUT_MAX_BYTES = 8388608;
|
|
13
|
+
const IMESSAGE_CLI_STDERR_TAIL_BYTES = 65536;
|
|
14
14
|
function parseLastJsonObject(stdout) {
|
|
15
15
|
const last = stdout.split(/\r?\n/u).findLast((line) => line.trim().length > 0)?.trim();
|
|
16
16
|
if (!last) return null;
|
|
@@ -23,12 +23,13 @@ function parseLastJsonObject(stdout) {
|
|
|
23
23
|
}
|
|
24
24
|
async function runIMessageCliJsonCommand(params) {
|
|
25
25
|
const dbPath = params.dbPath?.trim();
|
|
26
|
-
const
|
|
26
|
+
const argv = [
|
|
27
27
|
expandIMessageUserPath(params.cliPath),
|
|
28
28
|
...params.args,
|
|
29
29
|
...dbPath ? ["--db", dbPath] : [],
|
|
30
30
|
"--json"
|
|
31
|
-
]
|
|
31
|
+
];
|
|
32
|
+
const result = await runCommandWithTimeout(argv, {
|
|
32
33
|
killProcessTree: true,
|
|
33
34
|
maxOutputBytes: {
|
|
34
35
|
stdout: IMESSAGE_CLI_STDOUT_MAX_BYTES,
|
|
@@ -213,8 +214,8 @@ async function runChecked(run, label, argv, options) {
|
|
|
213
214
|
const result = await run(argv, {
|
|
214
215
|
killProcessTree: true,
|
|
215
216
|
maxOutputBytes: {
|
|
216
|
-
stdout:
|
|
217
|
-
stderr:
|
|
217
|
+
stdout: 4096,
|
|
218
|
+
stderr: 65536
|
|
218
219
|
},
|
|
219
220
|
outputCapture: {
|
|
220
221
|
stdout: "head",
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
2
|
+
//#region extensions/imessage/src/runtime.ts
|
|
3
|
+
const { getRuntime: getIMessageRuntime, setRuntime: setIMessageRuntime, tryGetRuntime: getOptionalIMessageRuntime } = createPluginRuntimeStore({
|
|
4
|
+
pluginId: "imessage",
|
|
5
|
+
errorMessage: "iMessage runtime not initialized"
|
|
6
|
+
});
|
|
7
|
+
//#endregion
|
|
8
|
+
export { getOptionalIMessageRuntime as n, setIMessageRuntime as r, getIMessageRuntime as t };
|
package/dist/runtime-api.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { o as resolveIMessageAccount } from "./accounts-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { n as IMessageConfigSchema } from "./config-schema-
|
|
5
|
-
import { t as sendMessageIMessage } from "./send-
|
|
6
|
-
import { t as monitorIMessageProvider } from "./monitor-
|
|
7
|
-
import { buildComputedAccountStatusSnapshot, collectStatusIssuesFromLastError } from "openclaw/plugin-sdk/status-helpers";
|
|
1
|
+
import { o as resolveIMessageAccount } from "./accounts-CCirBEIm.js";
|
|
2
|
+
import { c as normalizeIMessageMessagingTarget, d as imessageMessageActions, f as probeIMessage, n as resolveIMessageGroupToolPolicy, s as looksLikeIMessageTargetId, t as resolveIMessageGroupRequireMention } from "./group-policy-fYokgrgz.js";
|
|
3
|
+
import { r as setIMessageRuntime } from "./runtime-Cza4CY5T.js";
|
|
4
|
+
import { n as IMessageConfigSchema } from "./config-schema-DuGbA8Kp.js";
|
|
5
|
+
import { t as sendMessageIMessage } from "./send-DxhFcMfW.js";
|
|
6
|
+
import { t as monitorIMessageProvider } from "./monitor-CSTZ-GFU.js";
|
|
8
7
|
import { formatTrimmedAllowFromEntries } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
9
|
-
import {
|
|
8
|
+
import { buildComputedAccountStatusSnapshot, collectStatusIssuesFromLastError } from "openclaw/plugin-sdk/status-helpers";
|
|
9
|
+
import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/account-helpers";
|
|
10
|
+
import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
|
|
10
11
|
import { DEFAULT_ACCOUNT_ID, getChatChannelMeta } from "openclaw/plugin-sdk/core";
|
|
11
|
-
import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime";
|
|
12
12
|
import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
|
|
13
|
+
import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
|
|
13
14
|
//#region extensions/imessage/src/config-accessors.ts
|
|
14
15
|
function resolveIMessageConfigAllowFrom(params) {
|
|
15
16
|
return (resolveIMessageAccount(params).config.allowFrom ?? []).map((entry) => String(entry));
|