@openclaw/mattermost 2026.7.2-beta.1 → 2026.7.2-beta.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-C4Azn6rA.js +83 -0
- package/dist/api.js +3 -2
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel-plugin-runtime-BkzZgYxP.js → channel-plugin-runtime-BXmjNn6B.js} +75 -90
- package/dist/channel-plugin-runtime.js +1 -1
- package/dist/{channel.runtime-Cbs451W2.js → channel.runtime-CKb2-z0p.js} +85 -42
- package/dist/{accounts-B2NRPlqr.js → client-BzLj4dyf.js} +3 -83
- package/dist/interactions-DO7J-ND1.js +375 -0
- package/dist/policy-api.js +1 -1
- package/dist/slash-route-api.js +1 -1
- package/dist/{slash-state-Cr58Xd12.js → slash-state-C9bpBN40.js} +10 -375
- package/npm-shrinkwrap.json +3 -3
- package/openclaw.plugin.json +28 -0
- package/package.json +4 -4
- package/dist/{monitor-auth-BiDuyvOc.js → monitor-auth-dEHa1_On.js} +3 -3
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { f as normalizeMattermostBaseUrl } from "./client-BzLj4dyf.js";
|
|
2
|
+
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
|
+
import { resolveChannelPreviewStreamMode, resolveChannelStreamingBlockCoalesce, resolveChannelStreamingBlockEnabled, resolveChannelStreamingChunkMode } from "openclaw/plugin-sdk/channel-outbound";
|
|
4
|
+
import { createAccountListHelpers, hasConfiguredAccountValue } from "openclaw/plugin-sdk/account-helpers";
|
|
5
|
+
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
6
|
+
import { resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-resolution";
|
|
7
|
+
import { buildSecretInputSchema, hasConfiguredSecretInput, normalizeResolvedSecretInputString, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
8
|
+
//#region extensions/mattermost/src/mattermost/accounts.ts
|
|
9
|
+
const mattermostAccountHelpers = createAccountListHelpers("mattermost", { hasImplicitDefaultAccount: (cfg) => {
|
|
10
|
+
const mattermost = cfg.channels?.mattermost;
|
|
11
|
+
return Boolean(mattermost?.baseUrl?.trim() && (hasConfiguredAccountValue(mattermost.botToken) || process.env.MATTERMOST_BOT_TOKEN?.trim()));
|
|
12
|
+
} });
|
|
13
|
+
function listMattermostAccountIds(cfg) {
|
|
14
|
+
return mattermostAccountHelpers.listAccountIds(cfg);
|
|
15
|
+
}
|
|
16
|
+
function resolveDefaultMattermostAccountId(cfg) {
|
|
17
|
+
return mattermostAccountHelpers.resolveDefaultAccountId(cfg);
|
|
18
|
+
}
|
|
19
|
+
function mergeMattermostAccountConfig(cfg, accountId) {
|
|
20
|
+
return resolveMergedAccountConfig({
|
|
21
|
+
channelConfig: cfg.channels?.mattermost,
|
|
22
|
+
accounts: cfg.channels?.mattermost?.accounts,
|
|
23
|
+
accountId,
|
|
24
|
+
omitKeys: ["defaultAccount"],
|
|
25
|
+
nestedObjectKeys: ["commands"]
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function resolveMattermostRequireMention(config) {
|
|
29
|
+
if (config.chatmode === "oncall") return true;
|
|
30
|
+
if (config.chatmode === "onmessage") return false;
|
|
31
|
+
if (config.chatmode === "onchar") return true;
|
|
32
|
+
return config.requireMention;
|
|
33
|
+
}
|
|
34
|
+
function resolveMattermostAccount(params) {
|
|
35
|
+
const accountId = normalizeAccountId(params.accountId ?? resolveDefaultMattermostAccountId(params.cfg));
|
|
36
|
+
const baseEnabled = params.cfg.channels?.mattermost?.enabled !== false;
|
|
37
|
+
const merged = mergeMattermostAccountConfig(params.cfg, accountId);
|
|
38
|
+
const accountEnabled = merged.enabled !== false;
|
|
39
|
+
const enabled = baseEnabled && accountEnabled;
|
|
40
|
+
const allowEnv = accountId === DEFAULT_ACCOUNT_ID;
|
|
41
|
+
const envToken = allowEnv ? process.env.MATTERMOST_BOT_TOKEN?.trim() : void 0;
|
|
42
|
+
const envUrl = allowEnv ? process.env.MATTERMOST_URL?.trim() : void 0;
|
|
43
|
+
const configToken = params.allowUnresolvedSecretRef ? normalizeSecretInputString(merged.botToken) : normalizeResolvedSecretInputString({
|
|
44
|
+
value: merged.botToken,
|
|
45
|
+
path: `channels.mattermost.accounts.${accountId}.botToken`
|
|
46
|
+
});
|
|
47
|
+
const configUrl = merged.baseUrl?.trim();
|
|
48
|
+
const botToken = configToken || envToken;
|
|
49
|
+
const baseUrl = normalizeMattermostBaseUrl(configUrl || envUrl);
|
|
50
|
+
const requireMention = resolveMattermostRequireMention(merged);
|
|
51
|
+
const botTokenSource = configToken ? "config" : envToken ? "env" : "none";
|
|
52
|
+
const baseUrlSource = configUrl ? "config" : envUrl ? "env" : "none";
|
|
53
|
+
return {
|
|
54
|
+
accountId,
|
|
55
|
+
enabled,
|
|
56
|
+
name: normalizeOptionalString(merged.name),
|
|
57
|
+
botToken,
|
|
58
|
+
baseUrl,
|
|
59
|
+
botTokenSource,
|
|
60
|
+
baseUrlSource,
|
|
61
|
+
config: merged,
|
|
62
|
+
chatmode: merged.chatmode,
|
|
63
|
+
oncharPrefixes: merged.oncharPrefixes,
|
|
64
|
+
requireMention,
|
|
65
|
+
textChunkLimit: merged.textChunkLimit,
|
|
66
|
+
chunkMode: resolveChannelStreamingChunkMode(merged),
|
|
67
|
+
streamingMode: resolveChannelPreviewStreamMode(merged, "partial"),
|
|
68
|
+
blockStreaming: resolveChannelStreamingBlockEnabled(merged),
|
|
69
|
+
blockStreamingCoalesce: resolveChannelStreamingBlockCoalesce(merged)
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Resolve the effective replyToMode for a given chat type.
|
|
74
|
+
* Direct messages stay flat unless explicitly opted into a per-chat-type mode.
|
|
75
|
+
*/
|
|
76
|
+
function resolveMattermostReplyToMode(account, kind) {
|
|
77
|
+
const scopedMode = account.config.replyToModeByChatType?.[kind];
|
|
78
|
+
if (scopedMode !== void 0) return scopedMode;
|
|
79
|
+
if (kind === "direct") return "off";
|
|
80
|
+
return account.config.replyToMode ?? "off";
|
|
81
|
+
}
|
|
82
|
+
//#endregion
|
|
83
|
+
export { buildSecretInputSchema as a, resolveMattermostReplyToMode as i, resolveDefaultMattermostAccountId as n, hasConfiguredSecretInput as o, resolveMattermostAccount as r, listMattermostAccountIds as t };
|
package/dist/api.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import { r as isMattermostSenderAllowed } from "./monitor-auth-
|
|
2
|
-
|
|
1
|
+
import { r as isMattermostSenderAllowed } from "./monitor-auth-dEHa1_On.js";
|
|
2
|
+
import { t as buildButtonAttachments } from "./interactions-DO7J-ND1.js";
|
|
3
|
+
export { buildButtonAttachments, isMattermostSenderAllowed };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as MattermostChannelConfigSchema, c as mattermostConfigAdapter, l as mattermostMeta, n as mattermostSetupWizard, o as describeMattermostAccount, r as mattermostSetupAdapter, s as isMattermostConfigured, t as mattermostPlugin } from "./channel-plugin-runtime-BXmjNn6B.js";
|
|
2
2
|
import { t as resolveMattermostGatewayAuthBypassPaths } from "./gateway-auth-bypass-CL1PxV3z.js";
|
|
3
3
|
//#region extensions/mattermost/src/channel.setup.ts
|
|
4
4
|
const mattermostSetupPlugin = {
|
|
@@ -1,30 +1,31 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { f as normalizeMattermostBaseUrl } from "./client-BzLj4dyf.js";
|
|
2
|
+
import { a as buildSecretInputSchema, i as resolveMattermostReplyToMode, n as resolveDefaultMattermostAccountId, o as hasConfiguredSecretInput, r as resolveMattermostAccount, t as listMattermostAccountIds } from "./accounts-C4Azn6rA.js";
|
|
2
3
|
import { t as resolveMattermostGatewayAuthBypassPaths } from "./gateway-auth-bypass-CL1PxV3z.js";
|
|
3
4
|
import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-BaUvVh8e.js";
|
|
4
5
|
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-B4R5Bmhv.js";
|
|
5
6
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
7
|
+
import { buildPassiveProbedChannelStatusSummary } from "openclaw/plugin-sdk/extension-shared";
|
|
8
|
+
import { isPrivateNetworkOptInEnabled } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
9
|
+
import { z } from "zod";
|
|
6
10
|
import { formatNormalizedAllowFromEntries } from "openclaw/plugin-sdk/allow-from";
|
|
7
11
|
import { createLoggedPairingApprovalNotifier } from "openclaw/plugin-sdk/channel-pairing";
|
|
8
12
|
import { createAccountStatusSink, createChannelMessageAdapterFromOutbound } from "openclaw/plugin-sdk/channel-outbound";
|
|
9
13
|
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, buildChannelOutboundSessionRoute, buildThreadAwareOutboundSessionRoute, stripChannelTargetPrefix, stripTargetKindPrefix } from "openclaw/plugin-sdk/core";
|
|
10
14
|
import { createChannelConfigUiHints, createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
11
|
-
import { buildChannelGroupsScopeTree, createDangerousNameMatchingMutableAllowlistWarningCollector, createRestrictSendersChannelSecurity, resolveScopeRequireMention } from "openclaw/plugin-sdk/channel-policy";
|
|
15
|
+
import { buildChannelGroupsScopeTree, buildMutableAllowEntryDetector, collectStandardAllowlistLists, createDangerousNameMatchingMutableAllowlistWarningCollector, createRestrictSendersChannelSecurity, resolveScopeRequireMention } from "openclaw/plugin-sdk/channel-policy";
|
|
12
16
|
import { attachChannelToResult, createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
|
|
13
17
|
import { createChannelDirectoryAdapter } from "openclaw/plugin-sdk/directory-runtime";
|
|
14
|
-
import { buildPassiveProbedChannelStatusSummary } from "openclaw/plugin-sdk/extension-shared";
|
|
15
18
|
import { normalizeMessagePresentation, renderMessagePresentationFallbackText, resolveMessagePresentationButtonAction, resolveMessagePresentationControlValue } from "openclaw/plugin-sdk/interactive-runtime";
|
|
16
19
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
17
20
|
import { resolvePayloadMediaUrls, sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload";
|
|
18
|
-
import { isPrivateNetworkOptInEnabled } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
19
21
|
import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
|
|
20
22
|
import { chunkTextForOutbound, sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
|
|
21
23
|
import { createChannelApprovalAuth } from "openclaw/plugin-sdk/approval-auth-runtime";
|
|
22
24
|
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
23
25
|
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
24
|
-
import { z } from "zod";
|
|
25
26
|
import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
26
|
-
import { BlockStreamingCoalesceSchema, DmPolicySchema, GroupPolicySchema, MarkdownConfigSchema, buildChannelConfigSchema, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-schema";
|
|
27
|
-
import { applyAccountNameToChannelSection, applySetupAccountConfigPatch, createSetupTranslator, createStandardChannelSetupStatus, formatDocsLink, migrateBaseNameToDefaultAccount } from "openclaw/plugin-sdk/setup";
|
|
27
|
+
import { BlockStreamingCoalesceSchema, DmPolicySchema, GroupPolicySchema, MarkdownConfigSchema, buildChannelConfigSchema, buildGroupEntrySchema, buildMultiAccountChannelSchema, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-schema";
|
|
28
|
+
import { applyAccountNameToChannelSection, applySetupAccountConfigPatch, baseUrlTextInput, createSetupTranslator, createStandardChannelSetupStatus, defineTokenCredential, formatDocsLink, migrateBaseNameToDefaultAccount, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
|
|
28
29
|
import { createSetupInputPresenceValidator } from "openclaw/plugin-sdk/setup-runtime";
|
|
29
30
|
//#region extensions/mattermost/src/approval-auth.ts
|
|
30
31
|
const MATTERMOST_USER_ID_RE = /^[a-z0-9]{26}$/;
|
|
@@ -99,9 +100,14 @@ function describeMattermostAccount(account) {
|
|
|
99
100
|
}
|
|
100
101
|
//#endregion
|
|
101
102
|
//#region extensions/mattermost/src/config-schema-core.ts
|
|
102
|
-
const MattermostGroupSchema =
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
const MattermostGroupSchema = buildGroupEntrySchema().omit({
|
|
104
|
+
tools: true,
|
|
105
|
+
toolsBySender: true,
|
|
106
|
+
skills: true,
|
|
107
|
+
enabled: true,
|
|
108
|
+
allowFrom: true,
|
|
109
|
+
systemPrompt: true
|
|
110
|
+
});
|
|
105
111
|
function requireMattermostOpenAllowFrom(params) {
|
|
106
112
|
requireOpenAllowFrom({
|
|
107
113
|
policy: params.policy,
|
|
@@ -151,9 +157,13 @@ const MattermostStreamingProgressSchema = z.object({
|
|
|
151
157
|
labels: z.array(z.string()).optional(),
|
|
152
158
|
maxLines: z.number().int().positive().optional(),
|
|
153
159
|
maxLineChars: z.number().int().positive().optional(),
|
|
154
|
-
toolProgress: z.boolean().optional()
|
|
160
|
+
toolProgress: z.boolean().optional(),
|
|
161
|
+
commandText: z.enum(["raw", "status"]).optional()
|
|
162
|
+
}).strict();
|
|
163
|
+
const MattermostStreamingPreviewSchema = z.object({
|
|
164
|
+
toolProgress: z.boolean().optional(),
|
|
165
|
+
commandText: z.enum(["raw", "status"]).optional()
|
|
155
166
|
}).strict();
|
|
156
|
-
const MattermostStreamingPreviewSchema = z.object({ toolProgress: z.boolean().optional() }).strict();
|
|
157
167
|
const MattermostStreamingBlockSchema = z.object({
|
|
158
168
|
enabled: z.boolean().optional(),
|
|
159
169
|
coalesce: BlockStreamingCoalesceSchema.optional()
|
|
@@ -176,7 +186,9 @@ const MattermostReplyToModeByChatTypeSchema = z.object({
|
|
|
176
186
|
group: MattermostReplyToModeSchema.optional(),
|
|
177
187
|
channel: MattermostReplyToModeSchema.optional()
|
|
178
188
|
}).strict();
|
|
179
|
-
|
|
189
|
+
//#endregion
|
|
190
|
+
//#region extensions/mattermost/src/config-surface.ts
|
|
191
|
+
const MattermostChannelConfigSchema = buildChannelConfigSchema(buildMultiAccountChannelSchema(z.object({
|
|
180
192
|
name: z.string().optional(),
|
|
181
193
|
capabilities: z.array(z.string()).optional(),
|
|
182
194
|
dangerouslyAllowNameMatching: z.boolean().optional(),
|
|
@@ -213,25 +225,15 @@ const MattermostAccountSchemaBase = z.object({
|
|
|
213
225
|
network: MattermostNetworkSchema,
|
|
214
226
|
/** Retry configuration for DM channel creation */
|
|
215
227
|
dmChannelRetry: DmChannelRetrySchema
|
|
216
|
-
}).strict()
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
//#region extensions/mattermost/src/config-surface.ts
|
|
226
|
-
const MattermostChannelConfigSchema = buildChannelConfigSchema(MattermostAccountSchemaBase.extend({
|
|
227
|
-
accounts: z.record(z.string(), MattermostAccountSchema.optional()).optional(),
|
|
228
|
-
defaultAccount: z.string().optional()
|
|
229
|
-
}).superRefine((value, ctx) => {
|
|
230
|
-
requireMattermostOpenAllowFrom({
|
|
231
|
-
policy: value.dmPolicy,
|
|
232
|
-
allowFrom: value.allowFrom,
|
|
233
|
-
ctx
|
|
234
|
-
});
|
|
228
|
+
}).strict(), {
|
|
229
|
+
optionalAccount: true,
|
|
230
|
+
refine: (value, ctx) => {
|
|
231
|
+
requireMattermostOpenAllowFrom({
|
|
232
|
+
policy: value.dmPolicy,
|
|
233
|
+
allowFrom: value.allowFrom,
|
|
234
|
+
ctx
|
|
235
|
+
});
|
|
236
|
+
}
|
|
235
237
|
}), { uiHints: {
|
|
236
238
|
"": {
|
|
237
239
|
label: "Mattermost",
|
|
@@ -270,28 +272,13 @@ const MattermostChannelConfigSchema = buildChannelConfigSchema(MattermostAccount
|
|
|
270
272
|
help: "Merge streamed Mattermost block replies before final delivery."
|
|
271
273
|
}
|
|
272
274
|
} });
|
|
273
|
-
//#endregion
|
|
274
|
-
//#region extensions/mattermost/src/doctor.ts
|
|
275
|
-
function isMattermostMutableAllowEntry(raw) {
|
|
276
|
-
const text = raw.trim();
|
|
277
|
-
if (!text || text === "*") return false;
|
|
278
|
-
const lowered = normalizeLowercaseStringOrEmpty(text.replace(/^(mattermost|user):/i, "").replace(/^@/, "").trim());
|
|
279
|
-
if (/^[a-z0-9]{26}$/.test(lowered)) return false;
|
|
280
|
-
return true;
|
|
281
|
-
}
|
|
282
275
|
const mattermostDoctor = {
|
|
283
276
|
legacyConfigRules,
|
|
284
277
|
normalizeCompatibilityConfig,
|
|
285
278
|
collectMutableAllowlistWarnings: createDangerousNameMatchingMutableAllowlistWarningCollector({
|
|
286
279
|
channel: "mattermost",
|
|
287
|
-
detector:
|
|
288
|
-
collectLists: (scope) =>
|
|
289
|
-
pathLabel: `${scope.prefix}.allowFrom`,
|
|
290
|
-
list: scope.account.allowFrom
|
|
291
|
-
}, {
|
|
292
|
-
pathLabel: `${scope.prefix}.groupAllowFrom`,
|
|
293
|
-
list: scope.account.groupAllowFrom
|
|
294
|
-
}]
|
|
280
|
+
detector: buildMutableAllowEntryDetector({ stableIdPattern: /^(?:(?:mattermost|user):)?@?[a-z0-9]{26}$/i }),
|
|
281
|
+
collectLists: (scope) => collectStandardAllowlistLists(scope)
|
|
295
282
|
})
|
|
296
283
|
};
|
|
297
284
|
//#endregion
|
|
@@ -489,60 +476,50 @@ const mattermostSetupWizard = {
|
|
|
489
476
|
patch: {}
|
|
490
477
|
})
|
|
491
478
|
},
|
|
492
|
-
credentials: [{
|
|
479
|
+
credentials: [defineTokenCredential({
|
|
493
480
|
inputKey: "botToken",
|
|
481
|
+
configKey: "botToken",
|
|
494
482
|
providerHint: channel,
|
|
495
483
|
credentialLabel: t("wizard.mattermost.botToken"),
|
|
496
484
|
preferredEnvVar: "MATTERMOST_BOT_TOKEN",
|
|
497
485
|
envPrompt: t("wizard.mattermost.envPrompt"),
|
|
498
486
|
keepPrompt: t("wizard.mattermost.botTokenKeep"),
|
|
499
487
|
inputPrompt: t("wizard.mattermost.botTokenInput"),
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
accountConfigured: isMattermostConfigured(resolvedAccount),
|
|
504
|
-
hasConfiguredValue: hasConfiguredSecretInput(resolvedAccount.config.botToken)
|
|
505
|
-
};
|
|
506
|
-
},
|
|
507
|
-
applySet: async ({ cfg, accountId, value }) => applyMattermostSetupConfigPatch({
|
|
488
|
+
resolveAccount: ({ cfg, accountId }) => resolveMattermostAccountWithSecrets(cfg, accountId),
|
|
489
|
+
accountConfigured: isMattermostConfigured,
|
|
490
|
+
patchAccount: ({ cfg, accountId, patch }) => applyMattermostSetupConfigPatch({
|
|
508
491
|
cfg,
|
|
509
492
|
accountId,
|
|
510
|
-
patch
|
|
511
|
-
})
|
|
512
|
-
|
|
513
|
-
|
|
493
|
+
patch
|
|
494
|
+
}),
|
|
495
|
+
set: {}
|
|
496
|
+
})],
|
|
497
|
+
textInputs: [baseUrlTextInput({
|
|
514
498
|
inputKey: "httpUrl",
|
|
499
|
+
configKey: "baseUrl",
|
|
515
500
|
message: t("wizard.mattermost.baseUrlPrompt"),
|
|
516
501
|
confirmCurrentValue: false,
|
|
517
|
-
|
|
518
|
-
|
|
502
|
+
resolveAccount: ({ cfg, accountId }) => resolveMattermostAccountWithSecrets(cfg, accountId),
|
|
503
|
+
currentValue: (account) => account.baseUrl ?? process.env.MATTERMOST_URL?.trim(),
|
|
504
|
+
includeInitialValue: true,
|
|
519
505
|
shouldPrompt: ({ cfg, accountId, credentialValues, currentValue }) => {
|
|
520
506
|
const resolvedAccount = resolveMattermostAccountWithSecrets(cfg, accountId);
|
|
521
507
|
const tokenConfigured = Boolean(resolvedAccount.botToken?.trim()) || hasConfiguredSecretInput(resolvedAccount.config.botToken);
|
|
522
508
|
return Boolean(credentialValues.botToken) || !tokenConfigured || !currentValue;
|
|
523
509
|
},
|
|
524
|
-
validate: (
|
|
525
|
-
|
|
526
|
-
|
|
510
|
+
validate: (value) => normalizeMattermostBaseUrl(value) ? void 0 : "Mattermost base URL must include a valid base URL.",
|
|
511
|
+
normalize: (value) => normalizeMattermostBaseUrl(value) ?? value.trim(),
|
|
512
|
+
patchAccount: ({ cfg, accountId, patch }) => applyMattermostSetupConfigPatch({
|
|
527
513
|
cfg,
|
|
528
514
|
accountId,
|
|
529
|
-
patch
|
|
515
|
+
patch
|
|
530
516
|
})
|
|
531
|
-
}],
|
|
532
|
-
disable: (cfg) => (
|
|
533
|
-
...cfg,
|
|
534
|
-
channels: {
|
|
535
|
-
...cfg.channels,
|
|
536
|
-
mattermost: {
|
|
537
|
-
...cfg.channels?.mattermost,
|
|
538
|
-
enabled: false
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
})
|
|
517
|
+
})],
|
|
518
|
+
disable: (cfg) => setSetupChannelEnabled(cfg, channel, false)
|
|
542
519
|
};
|
|
543
520
|
//#endregion
|
|
544
521
|
//#region extensions/mattermost/src/channel.ts
|
|
545
|
-
const loadMattermostChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-
|
|
522
|
+
const loadMattermostChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-CKb2-z0p.js"));
|
|
546
523
|
function buildMattermostPresentationButtons(presentation) {
|
|
547
524
|
return presentation.blocks.filter((block) => block.type === "buttons").map((block) => block.buttons.flatMap((button) => {
|
|
548
525
|
if (button.action) return [];
|
|
@@ -567,7 +544,7 @@ const MATTERMOST_PRESENTATION_CAPABILITIES = {
|
|
|
567
544
|
function hasMattermostPresentationNavigation(presentation) {
|
|
568
545
|
return presentation.blocks.some((block) => block.type === "buttons" && block.buttons.some((button) => {
|
|
569
546
|
const action = resolveMessagePresentationButtonAction(button);
|
|
570
|
-
return action?.type === "url" || action?.type === "web-app";
|
|
547
|
+
return action?.type === "url" || action?.type === "web-app" && Boolean(action.url);
|
|
571
548
|
}));
|
|
572
549
|
}
|
|
573
550
|
function readMattermostPresentationButtons(payload) {
|
|
@@ -705,21 +682,26 @@ const mattermostMessageActions = {
|
|
|
705
682
|
supportsAction: ({ action }) => {
|
|
706
683
|
return action === "send" || action === "react";
|
|
707
684
|
},
|
|
708
|
-
handleAction: async ({ action, params, cfg, accountId, mediaAccess, mediaLocalRoots, mediaReadFile }) => {
|
|
685
|
+
handleAction: async ({ action, params, cfg, accountId, mediaAccess, mediaLocalRoots, mediaReadFile, conversationReadOrigin }) => {
|
|
709
686
|
if (action === "react") {
|
|
710
687
|
const resolvedAccountId = accountId ?? resolveDefaultMattermostAccountId(cfg);
|
|
711
688
|
const mattermostConfig = cfg.channels?.mattermost;
|
|
712
|
-
|
|
689
|
+
const account = resolveMattermostAccount({
|
|
713
690
|
cfg,
|
|
714
691
|
accountId: resolvedAccountId
|
|
715
|
-
})
|
|
692
|
+
});
|
|
693
|
+
if (!account.enabled) throw new Error(`Mattermost account "${resolvedAccountId}" is disabled`);
|
|
694
|
+
if (!(account.config.actions?.reactions ?? mattermostConfig?.actions?.reactions ?? true)) throw new Error("Mattermost reactions are disabled in config");
|
|
716
695
|
const { postId, emojiName, remove } = parseMattermostReactActionParams(params);
|
|
696
|
+
const authorizedTarget = normalizeOptionalString(params.to);
|
|
717
697
|
if (remove) {
|
|
718
698
|
const result = await (await loadMattermostChannelRuntime()).removeMattermostReaction({
|
|
719
699
|
cfg,
|
|
720
700
|
postId,
|
|
721
701
|
emojiName,
|
|
722
|
-
accountId: resolvedAccountId
|
|
702
|
+
accountId: resolvedAccountId,
|
|
703
|
+
authorizedTarget,
|
|
704
|
+
conversationReadOrigin
|
|
723
705
|
});
|
|
724
706
|
if (!result.ok) throw new Error(result.error);
|
|
725
707
|
return {
|
|
@@ -734,7 +716,9 @@ const mattermostMessageActions = {
|
|
|
734
716
|
cfg,
|
|
735
717
|
postId,
|
|
736
718
|
emojiName,
|
|
737
|
-
accountId: resolvedAccountId
|
|
719
|
+
accountId: resolvedAccountId,
|
|
720
|
+
authorizedTarget,
|
|
721
|
+
conversationReadOrigin
|
|
738
722
|
});
|
|
739
723
|
if (!result.ok) throw new Error(result.error);
|
|
740
724
|
return {
|
|
@@ -848,13 +832,12 @@ function collectMattermostAttachmentMedia(params) {
|
|
|
848
832
|
readMattermostStringParam(params, "fileUrl")
|
|
849
833
|
];
|
|
850
834
|
mediaUrlCandidates.push(...readMattermostStringArrayParam(params, "mediaUrls"));
|
|
851
|
-
let hasUnsupportedAttachmentPayload =
|
|
835
|
+
let hasUnsupportedAttachmentPayload = Boolean(readMattermostStringParam(params, "buffer") ?? readMattermostStringParam(params, "base64"));
|
|
852
836
|
if (Array.isArray(params.attachments)) for (const attachment of params.attachments) {
|
|
853
837
|
if (!attachment || typeof attachment !== "object" || Array.isArray(attachment)) continue;
|
|
854
838
|
const record = attachment;
|
|
855
839
|
mediaUrlCandidates.push(readMattermostStringParam(record, "media"), readMattermostStringParam(record, "mediaUrl"), readMattermostStringParam(record, "path"), readMattermostStringParam(record, "filePath"), readMattermostStringParam(record, "fileUrl"), readMattermostStringParam(record, "url"));
|
|
856
|
-
hasUnsupportedAttachmentPayload ||=
|
|
857
|
-
hasUnsupportedAttachmentPayload ||= typeof record.base64 === "string";
|
|
840
|
+
hasUnsupportedAttachmentPayload ||= Boolean(readMattermostStringParam(record, "buffer") ?? readMattermostStringParam(record, "base64"));
|
|
858
841
|
}
|
|
859
842
|
return {
|
|
860
843
|
mediaUrls: collectNonBlankStrings(mediaUrlCandidates),
|
|
@@ -1013,6 +996,8 @@ const mattermostPlugin = createChatChannelPlugin({
|
|
|
1013
996
|
}),
|
|
1014
997
|
messaging: {
|
|
1015
998
|
targetPrefixes: ["mattermost"],
|
|
999
|
+
directTargetStyle: "user-prefixed",
|
|
1000
|
+
targetIdComparison: "case-sensitive",
|
|
1016
1001
|
defaultMarkdownTableMode: "off",
|
|
1017
1002
|
normalizeTarget: normalizeMattermostMessagingTarget,
|
|
1018
1003
|
resolveDeliveryTarget: ({ conversationId, parentConversationId }) => {
|
|
@@ -1140,4 +1125,4 @@ const mattermostPlugin = createChatChannelPlugin({
|
|
|
1140
1125
|
outbound: mattermostOutbound
|
|
1141
1126
|
});
|
|
1142
1127
|
//#endregion
|
|
1143
|
-
export {
|
|
1128
|
+
export { MattermostChannelConfigSchema as a, mattermostConfigAdapter as c, normalizeMattermostMessagingTarget as i, mattermostMeta as l, mattermostSetupWizard as n, describeMattermostAccount as o, mattermostSetupAdapter as r, isMattermostConfigured$1 as s, mattermostPlugin as t };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as mattermostPlugin } from "./channel-plugin-runtime-
|
|
1
|
+
import { t as mattermostPlugin } from "./channel-plugin-runtime-BXmjNn6B.js";
|
|
2
2
|
export { mattermostPlugin };
|
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
import { C as resolveChannelMediaMaxBytes, E as warnMissingProviderGroupPolicyFallbackOnce, S as resolveAllowlistProviderRuntimeGroupPolicy, T as resolveDefaultGroupPolicy, _ as logInboundDrop, c as buildAgentMediaPayload, d as createChannelMessageReplyPipeline, f as createChannelPairingController, h as listSkillCommandsForAgents, i as normalizeMattermostAllowEntry, l as buildModelsProviderData, n as formatMattermostDirectMessageDropLog, o as resolveMattermostMonitorInboundAccess, s as DEFAULT_GROUP_HISTORY_LIMIT, t as authorizeMattermostCommandInvocation, u as createChannelHistoryWindow, v as logTypingFailure, x as registerPluginHttpRoute, y as parseTcpPort } from "./monitor-auth-BiDuyvOc.js";
|
|
2
|
-
import { _ as readMattermostError, a as MattermostPostSchema, b as updateMattermostPost, c as createMattermostPost, f as fetchMattermostMe, g as normalizeMattermostBaseUrl, h as fetchMattermostUserTeams, i as resolveMattermostReplyToMode, l as deleteMattermostPost, o as createMattermostClient, p as fetchMattermostUser, r as resolveMattermostAccount, t as listMattermostAccountIds, u as fetchMattermostChannel, y as sendMattermostTyping } from "./accounts-B2NRPlqr.js";
|
|
3
1
|
import { n as getOptionalMattermostRuntime, t as getMattermostRuntime } from "./runtime-CNB4YGqJ.js";
|
|
4
|
-
import {
|
|
2
|
+
import { a as deleteMattermostPost, c as fetchMattermostMe, d as fetchMattermostUserTeams, f as normalizeMattermostBaseUrl, g as updateMattermostPost, h as sendMattermostTyping, i as createMattermostPost, l as fetchMattermostUser, n as createMattermostClient, o as fetchMattermostChannel, p as readMattermostError, t as MattermostPostSchema } from "./client-BzLj4dyf.js";
|
|
3
|
+
import { C as resolveChannelMediaMaxBytes, E as warnMissingProviderGroupPolicyFallbackOnce, S as resolveAllowlistProviderRuntimeGroupPolicy, T as resolveDefaultGroupPolicy, _ as logInboundDrop, c as buildAgentMediaPayload, d as createChannelMessageReplyPipeline, f as createChannelPairingController, h as listSkillCommandsForAgents, i as normalizeMattermostAllowEntry, l as buildModelsProviderData, n as formatMattermostDirectMessageDropLog, o as resolveMattermostMonitorInboundAccess, s as DEFAULT_GROUP_HISTORY_LIMIT, t as authorizeMattermostCommandInvocation, u as createChannelHistoryWindow, v as logTypingFailure, x as registerPluginHttpRoute, y as parseTcpPort } from "./monitor-auth-dEHa1_On.js";
|
|
4
|
+
import { a as resolveInteractionCallbackPath, c as setInteractionSecret, i as createMattermostInteractionHandler, n as buildButtonProps, r as computeInteractionCallbackUrl, s as setInteractionCallbackUrl } from "./interactions-DO7J-ND1.js";
|
|
5
|
+
import { i as resolveMattermostReplyToMode, r as resolveMattermostAccount, t as listMattermostAccountIds } from "./accounts-C4Azn6rA.js";
|
|
6
|
+
import { i as normalizeMattermostMessagingTarget } from "./channel-plugin-runtime-BXmjNn6B.js";
|
|
7
|
+
import { _ as registerSlashCommands, a as sendMessageMattermost, c as deliverMattermostReplyPayload, d as renderMattermostModelsPickerView, f as renderMattermostProviderPickerView, g as isSlashCommandsEnabled, h as cleanupSlashCommands, l as buildMattermostAllowedModelRefs, m as DEFAULT_COMMAND_SPECS, n as deactivateSlashCommands, o as resolveMattermostOpaqueTarget, p as resolveMattermostModelPickerCurrentModel, r as getSlashCommandState, s as createMattermostReplyDeliveryBarrier, t as activateSlashCommands, u as parseMattermostModelPickerContext, v as resolveCallbackUrl, y as resolveSlashCommandConfig } from "./slash-state-C9bpBN40.js";
|
|
8
|
+
import { randomUUID } from "node:crypto";
|
|
9
|
+
import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
|
|
5
10
|
import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeStringEntries, normalizeTrimmedStringList, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
11
|
+
import { safeParseJsonWithSchema, safeParseWithSchema } from "openclaw/plugin-sdk/extension-shared";
|
|
12
|
+
import { asDateTimestampMs, resolveExpiresAtMsFromDurationMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
13
|
+
import { readProviderJsonResponse } from "openclaw/plugin-sdk/provider-http";
|
|
14
|
+
import { fetchWithSsrFGuard, isPrivateNetworkOptInEnabled, ssrfPolicyFromPrivateNetworkOptIn } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
15
|
+
import { z } from "zod";
|
|
6
16
|
import { formatInboundFromLabel, formatInboundMediaUnavailableText } from "openclaw/plugin-sdk/channel-inbound";
|
|
7
17
|
import { buildChannelProgressDraftLineForEntry, createChannelProgressDraftCompositor, createFinalizableDraftLifecycle, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, resolveChannelStreamingPreviewToolProgress } from "openclaw/plugin-sdk/channel-outbound";
|
|
8
18
|
import { rawDataToString } from "openclaw/plugin-sdk/webhook-ingress";
|
|
9
|
-
import { asDateTimestampMs, resolveExpiresAtMsFromDurationMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
10
|
-
import { safeParseJsonWithSchema, safeParseWithSchema } from "openclaw/plugin-sdk/extension-shared";
|
|
11
19
|
import { buildTtsSupplementMediaPayload, countOutboundMedia, getReplyPayloadTtsSupplement, isReasoningReplyPayload } from "openclaw/plugin-sdk/reply-payload";
|
|
12
|
-
import { fetchWithSsrFGuard, isPrivateNetworkOptInEnabled, ssrfPolicyFromPrivateNetworkOptIn } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
13
|
-
import { readProviderJsonResponse } from "openclaw/plugin-sdk/provider-http";
|
|
14
|
-
import { z } from "zod";
|
|
15
20
|
import { resolveInboundLastRouteSessionKey, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
|
|
16
|
-
import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
|
|
17
21
|
import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
18
|
-
import { randomUUID } from "node:crypto";
|
|
19
22
|
import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
|
|
20
23
|
import { isLoopbackHost } from "openclaw/plugin-sdk/gateway-runtime";
|
|
21
24
|
import { chunkMarkdownTextWithMode } from "openclaw/plugin-sdk/reply-chunking";
|
|
22
|
-
import {
|
|
25
|
+
import { createChannelReplayGuard } from "openclaw/plugin-sdk/persistent-dedupe";
|
|
23
26
|
import { captureWsEvent, createDebugProxyWebSocketAgent, resolveDebugProxySettings } from "openclaw/plugin-sdk/proxy-capture";
|
|
24
27
|
import WebSocket from "ws";
|
|
25
28
|
import { createPersistentDedupeCache } from "openclaw/plugin-sdk/dedupe-runtime";
|
|
@@ -620,34 +623,28 @@ function stripOncharPrefix(text, prefixes) {
|
|
|
620
623
|
}
|
|
621
624
|
//#endregion
|
|
622
625
|
//#region extensions/mattermost/src/mattermost/monitor-replay.ts
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
memoryMaxSize: 2e3
|
|
626
|
-
});
|
|
626
|
+
const RECENT_MATTERMOST_MESSAGE_TTL_MS = 5 * 6e4;
|
|
627
|
+
const RECENT_MATTERMOST_MESSAGE_MAX = 2e3;
|
|
627
628
|
function buildMattermostInboundReplayKeys(params) {
|
|
628
|
-
return
|
|
629
|
+
return params.messageIds.map((id) => id.trim() ? `${params.accountId}:${id.trim()}` : "");
|
|
630
|
+
}
|
|
631
|
+
function createMattermostInboundReplayGuard() {
|
|
632
|
+
return createChannelReplayGuard({
|
|
633
|
+
dedupe: {
|
|
634
|
+
ttlMs: RECENT_MATTERMOST_MESSAGE_TTL_MS,
|
|
635
|
+
memoryMaxSize: RECENT_MATTERMOST_MESSAGE_MAX
|
|
636
|
+
},
|
|
637
|
+
buildReplayKey: buildMattermostInboundReplayKeys
|
|
638
|
+
});
|
|
629
639
|
}
|
|
640
|
+
const recentInboundMessages = createMattermostInboundReplayGuard();
|
|
630
641
|
async function processMattermostReplayGuardedPost(params) {
|
|
631
642
|
const replayGuard = params.replayGuard ?? recentInboundMessages;
|
|
632
|
-
const
|
|
643
|
+
const event = {
|
|
633
644
|
accountId: params.accountId,
|
|
634
645
|
messageIds: params.messageIds
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
await params.handlePost();
|
|
638
|
-
return "processed";
|
|
639
|
-
}
|
|
640
|
-
const claimedKeys = [];
|
|
641
|
-
for (const replayKey of replayKeys) if ((await replayGuard.claim(replayKey)).kind === "claimed") claimedKeys.push(replayKey);
|
|
642
|
-
if (claimedKeys.length === 0) return "duplicate";
|
|
643
|
-
try {
|
|
644
|
-
await params.handlePost();
|
|
645
|
-
await Promise.all(claimedKeys.map((replayKey) => replayGuard.commit(replayKey)));
|
|
646
|
-
return "processed";
|
|
647
|
-
} catch (error) {
|
|
648
|
-
await Promise.all(claimedKeys.map((replayKey) => replayGuard.commit(replayKey)));
|
|
649
|
-
throw error;
|
|
650
|
-
}
|
|
646
|
+
};
|
|
647
|
+
return (await replayGuard.processGuarded(event, params.handlePost, { onError: "commit" })).kind === "processed" ? "processed" : "duplicate";
|
|
651
648
|
}
|
|
652
649
|
//#endregion
|
|
653
650
|
//#region extensions/mattermost/src/mattermost/monitor-resources.ts
|
|
@@ -887,6 +884,7 @@ async function registerMattermostMonitorSlashCommands(params) {
|
|
|
887
884
|
//#endregion
|
|
888
885
|
//#region extensions/mattermost/src/mattermost/monitor-websocket.ts
|
|
889
886
|
const MATTERMOST_WEBSOCKET_MAX_PAYLOAD_BYTES = 16 * 1024 * 1024;
|
|
887
|
+
const MATTERMOST_WEBSOCKET_HANDSHAKE_TIMEOUT_MS = 3e4;
|
|
890
888
|
const MattermostEventPayloadSchema = z.object({
|
|
891
889
|
event: z.string().optional(),
|
|
892
890
|
data: z.object({
|
|
@@ -920,11 +918,11 @@ var WebSocketClosedBeforeOpenError = class extends Error {
|
|
|
920
918
|
this.name = "WebSocketClosedBeforeOpenError";
|
|
921
919
|
}
|
|
922
920
|
};
|
|
923
|
-
const defaultMattermostWebSocketFactory = (url) => {
|
|
921
|
+
const defaultMattermostWebSocketFactory = (url, options) => {
|
|
924
922
|
const agent = createDebugProxyWebSocketAgent(resolveDebugProxySettings());
|
|
925
923
|
return new WebSocket(url, {
|
|
926
|
-
...
|
|
927
|
-
|
|
924
|
+
...options,
|
|
925
|
+
...agent ? { agent } : {}
|
|
928
926
|
});
|
|
929
927
|
};
|
|
930
928
|
function parsePostedPayload(payload) {
|
|
@@ -945,7 +943,10 @@ function createMattermostConnectOnce(opts) {
|
|
|
945
943
|
const pongTimeoutMs = opts.pongTimeoutMs ?? 1e4;
|
|
946
944
|
return async () => {
|
|
947
945
|
const flowId = randomUUID();
|
|
948
|
-
const ws = webSocketFactory(opts.wsUrl
|
|
946
|
+
const ws = webSocketFactory(opts.wsUrl, {
|
|
947
|
+
maxPayload: MATTERMOST_WEBSOCKET_MAX_PAYLOAD_BYTES,
|
|
948
|
+
handshakeTimeout: MATTERMOST_WEBSOCKET_HANDSHAKE_TIMEOUT_MS
|
|
949
|
+
});
|
|
949
950
|
const onAbort = () => ws.terminate();
|
|
950
951
|
opts.abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
951
952
|
const getBotUpdateAt = opts.getBotUpdateAt;
|
|
@@ -2818,6 +2819,42 @@ async function removeMattermostReaction(params) {
|
|
|
2818
2819
|
mutation: deleteReaction
|
|
2819
2820
|
});
|
|
2820
2821
|
}
|
|
2822
|
+
function parseAuthorizedReactionTarget(rawTarget) {
|
|
2823
|
+
const normalized = rawTarget ? normalizeMattermostMessagingTarget(rawTarget) : void 0;
|
|
2824
|
+
if (!normalized) return null;
|
|
2825
|
+
if (normalized.startsWith("channel:")) {
|
|
2826
|
+
const id = normalized.slice(8).trim();
|
|
2827
|
+
return id ? {
|
|
2828
|
+
kind: "channel",
|
|
2829
|
+
id
|
|
2830
|
+
} : null;
|
|
2831
|
+
}
|
|
2832
|
+
if (normalized.startsWith("user:")) {
|
|
2833
|
+
const id = normalized.slice(5).trim();
|
|
2834
|
+
return id ? {
|
|
2835
|
+
kind: "user",
|
|
2836
|
+
id
|
|
2837
|
+
} : null;
|
|
2838
|
+
}
|
|
2839
|
+
return null;
|
|
2840
|
+
}
|
|
2841
|
+
async function authorizeMattermostReactionResource(params) {
|
|
2842
|
+
const target = parseAuthorizedReactionTarget(params.authorizedTarget);
|
|
2843
|
+
if (!target) throw new Error("Mattermost delegated reactions require a canonical authorized conversation target.");
|
|
2844
|
+
const postChannelId = (await params.client.request(`/posts/${encodeURIComponent(params.postId)}`)).channel_id?.trim();
|
|
2845
|
+
if (!postChannelId) throw new Error("Mattermost reaction post is missing its conversation binding.");
|
|
2846
|
+
if (target.kind === "channel") {
|
|
2847
|
+
if (postChannelId !== target.id) throw new Error("Mattermost reaction post belongs to a different conversation.");
|
|
2848
|
+
return;
|
|
2849
|
+
}
|
|
2850
|
+
const botUserId = await resolveBotUserId(params.client, params.cacheKey);
|
|
2851
|
+
if (!botUserId) throw new Error("Mattermost reactions failed: could not resolve bot user id.");
|
|
2852
|
+
const channel = await fetchMattermostChannel(params.client, postChannelId);
|
|
2853
|
+
const participants = channel.name?.split("__").map((entry) => entry.trim()).filter(Boolean).toSorted() ?? [];
|
|
2854
|
+
const authorizedParticipants = [botUserId, target.id].toSorted();
|
|
2855
|
+
if (channel.type !== "D" || participants.length !== 2 || participants[0] !== authorizedParticipants[0] || participants[1] !== authorizedParticipants[1]) throw new Error("Mattermost reaction post belongs to a different direct conversation.");
|
|
2856
|
+
return botUserId;
|
|
2857
|
+
}
|
|
2821
2858
|
async function runMattermostReaction(params, options) {
|
|
2822
2859
|
const resolved = resolveMattermostAccount({
|
|
2823
2860
|
cfg: params.cfg,
|
|
@@ -2835,12 +2872,18 @@ async function runMattermostReaction(params, options) {
|
|
|
2835
2872
|
fetchImpl: params.fetchImpl,
|
|
2836
2873
|
allowPrivateNetwork: isPrivateNetworkOptInEnabled(resolved.config)
|
|
2837
2874
|
});
|
|
2838
|
-
const
|
|
2839
|
-
if (!userId) return {
|
|
2840
|
-
ok: false,
|
|
2841
|
-
error: "Mattermost reactions failed: could not resolve bot user id."
|
|
2842
|
-
};
|
|
2875
|
+
const cacheKey = `${baseUrl}:${botToken}`;
|
|
2843
2876
|
try {
|
|
2877
|
+
const userId = (params.conversationReadOrigin === "direct-operator" ? void 0 : await authorizeMattermostReactionResource({
|
|
2878
|
+
client,
|
|
2879
|
+
cacheKey,
|
|
2880
|
+
postId: params.postId,
|
|
2881
|
+
authorizedTarget: params.authorizedTarget
|
|
2882
|
+
})) ?? await resolveBotUserId(client, cacheKey);
|
|
2883
|
+
if (!userId) return {
|
|
2884
|
+
ok: false,
|
|
2885
|
+
error: "Mattermost reactions failed: could not resolve bot user id."
|
|
2886
|
+
};
|
|
2844
2887
|
await options.mutation(client, {
|
|
2845
2888
|
userId,
|
|
2846
2889
|
postId: params.postId,
|