@openclaw/msteams 2026.8.1-beta.3 → 2026.9.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.
@@ -1,16 +1,20 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-D6vf50IK.cjs");
2
2
  const require_runtime = require("./runtime-gZTAuFux.cjs");
3
3
  require("./runtime-api.cjs");
4
- const require_resolve_allowlist = require("./resolve-allowlist-CIfWUwuc.cjs");
5
- const require_channel = require("./channel-KpWENcgK.cjs");
6
- const require_channel_setup = require("./channel.setup-mOFtsfYz.cjs");
4
+ const require_resolve_allowlist = require("./resolve-allowlist-B6FQAa3r.cjs");
5
+ const require_channel = require("./channel-BsqcQ0E9.cjs");
6
+ const require_thread_session = require("./thread-session-DdWfgc8U.cjs");
7
+ const require_channel_setup = require("./channel.setup-BvYxZIFG.cjs");
7
8
  const require_polls = require("./polls-DvuJvaDG.cjs");
8
9
  const require_sso_token_store = require("./sso-token-store-ChhO1f4i.cjs");
9
- const require_messenger = require("./messenger-IISPSOvj.cjs");
10
+ const require_approval_card = require("./approval-card-B6ZIMO83.cjs");
11
+ const require_messenger = require("./messenger-BJB30CC2.cjs");
12
+ const require_reaction_types = require("./reaction-types-dGkp4bkW.cjs");
10
13
  let openclaw_plugin_sdk_channel_outbound = require("openclaw/plugin-sdk/channel-outbound");
11
14
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
12
15
  let openclaw_plugin_sdk_allow_from = require("openclaw/plugin-sdk/allow-from");
13
16
  let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
17
+ let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
14
18
  let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runtime");
15
19
  let openclaw_plugin_sdk_ssrf_runtime = require("openclaw/plugin-sdk/ssrf-runtime");
16
20
  let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
@@ -18,8 +22,10 @@ let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text
18
22
  let openclaw_plugin_sdk_routing = require("openclaw/plugin-sdk/routing");
19
23
  let node_crypto = require("node:crypto");
20
24
  node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
25
+ let openclaw_plugin_sdk_collection_runtime = require("openclaw/plugin-sdk/collection-runtime");
21
26
  let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
22
27
  let openclaw_plugin_sdk_channel_inbound = require("openclaw/plugin-sdk/channel-inbound");
28
+ let openclaw_plugin_sdk_approval_gateway_runtime = require("openclaw/plugin-sdk/approval-gateway-runtime");
23
29
  let openclaw_plugin_sdk_channel_ingress_runtime = require("openclaw/plugin-sdk/channel-ingress-runtime");
24
30
  let openclaw_plugin_sdk_context_visibility_runtime = require("openclaw/plugin-sdk/context-visibility-runtime");
25
31
  let openclaw_plugin_sdk_reply_history = require("openclaw/plugin-sdk/reply-history");
@@ -28,10 +34,8 @@ let openclaw_plugin_sdk_extension_shared = require("openclaw/plugin-sdk/extensio
28
34
  let openclaw_plugin_sdk_plugin_runtime = require("openclaw/plugin-sdk/plugin-runtime");
29
35
  let openclaw_plugin_sdk_dedupe_runtime = require("openclaw/plugin-sdk/dedupe-runtime");
30
36
  let openclaw_plugin_sdk_plugin_state_runtime = require("openclaw/plugin-sdk/plugin-state-runtime");
31
- let openclaw_plugin_sdk_collection_runtime = require("openclaw/plugin-sdk/collection-runtime");
32
37
  let openclaw_plugin_sdk_gateway_runtime = require("openclaw/plugin-sdk/gateway-runtime");
33
38
  let openclaw_plugin_sdk_channel_pairing = require("openclaw/plugin-sdk/channel-pairing");
34
- let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
35
39
  let openclaw_plugin_sdk_runtime_group_policy = require("openclaw/plugin-sdk/runtime-group-policy");
36
40
  let openclaw_plugin_sdk_dangerous_name_runtime = require("openclaw/plugin-sdk/dangerous-name-runtime");
37
41
  let openclaw_plugin_sdk_webhook_ingress = require("openclaw/plugin-sdk/webhook-ingress");
@@ -166,6 +170,99 @@ function serializeMSTeamsAdaptiveCardActionValue(value) {
166
170
  }
167
171
  }
168
172
  //#endregion
173
+ //#region extensions/msteams/src/approval-card-submit.ts
174
+ function isMSTeamsApprovalSubmit(value) {
175
+ if (!(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(value)) return false;
176
+ if (value.openclawAction === "approval") return true;
177
+ const data = ((0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(value.action) ? value.action : void 0)?.data;
178
+ return (0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(data) && data.openclawAction === "approval";
179
+ }
180
+ async function maybeHandleMSTeamsApprovalCardSubmit(params) {
181
+ const { context, deps } = params;
182
+ if (!isMSTeamsApprovalSubmit(context.activity.value)) return false;
183
+ const ignored = (reason) => deps.log.info("msteams approval ignored", { reason });
184
+ const token = require_approval_card.readMSTeamsApprovalActionToken(context.activity.value);
185
+ if (!token) {
186
+ ignored("missing card token");
187
+ return true;
188
+ }
189
+ const binding = require_approval_card.getMSTeamsApprovalCardBinding(token);
190
+ if (!binding) {
191
+ ignored("unknown or expired card token");
192
+ return true;
193
+ }
194
+ if (binding.accountId !== openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID) {
195
+ ignored("card token account mismatch");
196
+ return true;
197
+ }
198
+ if (require_resolve_allowlist.normalizeMSTeamsConversationId(context.activity.conversation?.id ?? "") !== require_resolve_allowlist.normalizeMSTeamsConversationId(binding.conversationId)) {
199
+ ignored("card token conversation mismatch");
200
+ return true;
201
+ }
202
+ if (context.activity.replyToId && context.activity.replyToId !== binding.activityId) {
203
+ ignored("card token activity mismatch");
204
+ return true;
205
+ }
206
+ if (!binding.allowedDecisions.includes(binding.decision)) {
207
+ ignored("card token decision is no longer allowed");
208
+ return true;
209
+ }
210
+ const senderId = context.activity.from?.aadObjectId;
211
+ if (!(require_thread_session.msTeamsApprovalAuth.authorizeActorAction?.({
212
+ cfg: deps.cfg,
213
+ accountId: openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID,
214
+ senderId,
215
+ action: "approve",
216
+ approvalKind: binding.approvalKind
217
+ }))?.authorized) {
218
+ ignored(`unauthorized actor ${senderId || "unknown"}`);
219
+ return true;
220
+ }
221
+ const claim = require_approval_card.claimMSTeamsApprovalCardBinding(token);
222
+ if (claim.kind !== "claimed") {
223
+ ignored(claim.kind === "in-flight" ? "card token resolve already in flight" : "card token already consumed");
224
+ return true;
225
+ }
226
+ const consumed = claim.binding;
227
+ let result;
228
+ try {
229
+ result = await (0, openclaw_plugin_sdk_approval_gateway_runtime.resolveApprovalOverGateway)({
230
+ cfg: deps.cfg,
231
+ approvalId: consumed.approvalId,
232
+ approvalKind: consumed.approvalKind,
233
+ decision: consumed.decision,
234
+ channel: "msteams",
235
+ accountId: openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID,
236
+ senderId
237
+ });
238
+ await context.updateActivity({
239
+ type: "message",
240
+ id: consumed.activityId,
241
+ attachments: [{
242
+ contentType: "application/vnd.microsoft.card.adaptive",
243
+ content: require_approval_card.buildMSTeamsCanonicalApprovalTerminalCard(result)
244
+ }]
245
+ });
246
+ } catch (error) {
247
+ if ((0, openclaw_plugin_sdk_error_runtime.isApprovalNotFoundError)(error)) {
248
+ require_approval_card.completeMSTeamsApprovalCardBinding(token);
249
+ ignored(`approval expired or no longer exists id=${consumed.approvalId}`);
250
+ return true;
251
+ }
252
+ require_approval_card.releaseMSTeamsApprovalCardBinding(token);
253
+ throw error;
254
+ }
255
+ require_approval_card.completeMSTeamsApprovalCardBinding(token);
256
+ deps.log.info("msteams approval resolved", {
257
+ approvalId: consumed.approvalId,
258
+ approvalKind: consumed.approvalKind,
259
+ applied: result.applied,
260
+ status: result.approval.status,
261
+ senderId
262
+ });
263
+ return true;
264
+ }
265
+ //#endregion
169
266
  //#region extensions/msteams/src/monitor-handler/access.ts
170
267
  const msteamsIngressIdentity = {
171
268
  key: "sender-id",
@@ -2842,7 +2939,7 @@ function resolveParentCacheExpiresAt(nowRaw) {
2842
2939
  * Uses the injected `fetchParent` (defaults to `fetchChannelMessage`) so
2843
2940
  * tests can swap in a stub without mocking the Graph transport.
2844
2941
  */
2845
- async function fetchParentMessageCached(token, groupId, channelId, parentId, fetchParent = require_messenger.fetchChannelMessage) {
2942
+ async function fetchParentMessageCached(token, groupId, channelId, parentId, fetchParent = require_reaction_types.fetchChannelMessage) {
2846
2943
  const key = buildParentCacheKey(groupId, channelId, parentId);
2847
2944
  const now = (0, openclaw_plugin_sdk_number_runtime.asDateTimestampMs)(Date.now());
2848
2945
  const cached = parentCache.get(key);
@@ -2872,7 +2969,7 @@ function summarizeParentMessage(message) {
2872
2969
  const sender = message.from?.user?.displayName ?? message.from?.application?.displayName ?? "unknown";
2873
2970
  const contentType = message.body?.contentType ?? "text";
2874
2971
  const raw = message.body?.content ?? "";
2875
- const text = contentType === "html" ? require_messenger.stripHtmlFromTeamsMessage(raw) : raw.replace(/\s+/g, " ").trim();
2972
+ const text = contentType === "html" ? require_reaction_types.stripHtmlFromTeamsMessage(raw) : raw.replace(/\s+/g, " ").trim();
2876
2973
  if (!text) return;
2877
2974
  return {
2878
2975
  sender,
@@ -2916,7 +3013,7 @@ function prepareMSTeamsThreadRouting(params) {
2916
3013
  id: params.isDirectMessage ? params.senderId : params.conversationId
2917
3014
  }
2918
3015
  });
2919
- route.sessionKey = require_channel.resolveMSTeamsRouteSessionKey({
3016
+ route.sessionKey = require_thread_session.resolveMSTeamsRouteSessionKey({
2920
3017
  baseSessionKey: route.sessionKey,
2921
3018
  isChannel: params.isChannel,
2922
3019
  conversationMessageId: params.conversationMessageId,
@@ -2967,7 +3064,7 @@ async function resolveMSTeamsThreadContext(params) {
2967
3064
  quoteBodyFull = await require_resolve_allowlist.withMSTeamsRequestDeadline({
2968
3065
  deadline,
2969
3066
  label: "MS Teams quote lookup",
2970
- work: () => require_messenger.fetchChatMessageText(graphToken, params.conversationId, quoteMessageId, deadline)
3067
+ work: () => require_reaction_types.fetchChatMessageText(graphToken, params.conversationId, quoteMessageId, deadline)
2971
3068
  });
2972
3069
  } catch (err) {
2973
3070
  params.log.debug?.("failed to fetch full quoted message text", { error: require_channel_setup.formatUnknownError(err) });
@@ -2983,7 +3080,7 @@ async function resolveMSTeamsThreadContext(params) {
2983
3080
  const [parentResult, repliesResult] = await require_resolve_allowlist.withMSTeamsRequestDeadline({
2984
3081
  deadline,
2985
3082
  label: "MS Teams thread history",
2986
- work: () => Promise.allSettled([fetchParentMessageCached(graphToken, teamAadGroupId, params.conversationId, threadParentId, (token, groupId, requestedChannelId, messageId) => require_messenger.fetchChannelMessage(token, groupId, requestedChannelId, messageId, deadline)), require_messenger.fetchThreadReplies(graphToken, teamAadGroupId, params.conversationId, threadParentId, 50, deadline)])
3083
+ work: () => Promise.allSettled([fetchParentMessageCached(graphToken, teamAadGroupId, params.conversationId, threadParentId, (token, groupId, requestedChannelId, messageId) => require_reaction_types.fetchChannelMessage(token, groupId, requestedChannelId, messageId, deadline)), require_reaction_types.fetchThreadReplies(graphToken, teamAadGroupId, params.conversationId, threadParentId, 50, deadline)])
2987
3084
  });
2988
3085
  const parentMsg = parentResult.status === "fulfilled" ? parentResult.value : void 0;
2989
3086
  const replies = repliesResult.status === "fulfilled" ? repliesResult.value : [];
@@ -3023,7 +3120,7 @@ async function resolveMSTeamsThreadContext(params) {
3023
3120
  kind: "thread",
3024
3121
  isSenderAllowed: isThreadSenderAllowed
3025
3122
  });
3026
- threadContext = require_messenger.formatThreadContext(threadMessages, activity.id) || void 0;
3123
+ threadContext = require_reaction_types.formatThreadContext(threadMessages, activity.id) || void 0;
3027
3124
  } catch (err) {
3028
3125
  params.log.debug?.("failed to fetch thread history", { error: require_channel_setup.formatUnknownError(err) });
3029
3126
  }
@@ -3349,7 +3446,7 @@ function createMSTeamsReactionHandler(deps) {
3349
3446
  const targetMessageId = activity.replyToId ?? "unknown";
3350
3447
  for (const reaction of reactions) {
3351
3448
  const reactionType = reaction.type ?? "unknown";
3352
- const emoji = require_messenger.resolveMSTeamsReactionEmoji(reactionType);
3449
+ const emoji = require_reaction_types.resolveMSTeamsReactionEmoji(reactionType);
3353
3450
  const label = direction === "added" ? `Teams reaction ${emoji} added by ${senderName} on message ${targetMessageId}` : `Teams reaction ${emoji} removed by ${senderName} from message ${targetMessageId}`;
3354
3451
  log.info(`reaction ${direction}`, {
3355
3452
  sender: senderId,
@@ -3491,6 +3588,10 @@ function registerMSTeamsHandlers(handler, deps) {
3491
3588
  if (originalRun) handler.run = async (context, turnAdoptionLifecycle) => {
3492
3589
  const ctx = context;
3493
3590
  if (ctx.activity?.type === "invoke" && ctx.activity?.name === "adaptiveCard/action") {
3591
+ if (await maybeHandleMSTeamsApprovalCardSubmit({
3592
+ context: ctx,
3593
+ deps
3594
+ })) return;
3494
3595
  const text = serializeMSTeamsAdaptiveCardActionValue(ctx.activity?.value);
3495
3596
  if (text) return await handleTeamsMessage({
3496
3597
  ...ctx,
@@ -3511,7 +3612,15 @@ function registerMSTeamsHandlers(handler, deps) {
3511
3612
  await next();
3512
3613
  };
3513
3614
  try {
3514
- const result = await handleTeamsMessage(context, turnAdoptionLifecycle);
3615
+ const ctx = context;
3616
+ if (await maybeHandleMSTeamsApprovalCardSubmit({
3617
+ context: ctx,
3618
+ deps
3619
+ })) {
3620
+ await runNext();
3621
+ return;
3622
+ }
3623
+ const result = await handleTeamsMessage(ctx, turnAdoptionLifecycle);
3515
3624
  await runNext();
3516
3625
  return result;
3517
3626
  } catch (err) {
@@ -0,0 +1,63 @@
1
+ const require_resolve_allowlist = require("./resolve-allowlist-B6FQAa3r.cjs");
2
+ let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
3
+ let openclaw_plugin_sdk_approval_auth_runtime = require("openclaw/plugin-sdk/approval-auth-runtime");
4
+ let openclaw_plugin_sdk_routing = require("openclaw/plugin-sdk/routing");
5
+ //#region extensions/msteams/src/approval-auth.ts
6
+ const MSTEAMS_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
7
+ function normalizeMSTeamsApproverId(value) {
8
+ const normalized = require_resolve_allowlist.normalizeMSTeamsMessagingTarget(String(value));
9
+ const id = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(normalized?.startsWith("user:") ? normalized.slice(5) : normalized);
10
+ return id && MSTEAMS_ID_RE.test(id) ? id : void 0;
11
+ }
12
+ function resolveMSTeamsChannelConfig(cfg) {
13
+ return cfg.channels?.msteams;
14
+ }
15
+ const msTeamsApproval = (0, openclaw_plugin_sdk_approval_auth_runtime.createChannelApprovalAuth)({
16
+ channelLabel: "Microsoft Teams",
17
+ resolveInputs: ({ cfg }) => {
18
+ const channel = resolveMSTeamsChannelConfig(cfg);
19
+ return {
20
+ allowFrom: channel?.allowFrom,
21
+ defaultTo: channel?.defaultTo
22
+ };
23
+ },
24
+ normalizeApprover: normalizeMSTeamsApproverId,
25
+ normalizeSenderId: (value) => {
26
+ const trimmed = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(value);
27
+ if (!trimmed) return;
28
+ return MSTEAMS_ID_RE.test(trimmed) ? trimmed : void 0;
29
+ }
30
+ });
31
+ const getMSTeamsApprovalApprovers = msTeamsApproval.resolveApprovers;
32
+ const msTeamsApprovalAuth = msTeamsApproval.approvalAuth;
33
+ //#endregion
34
+ //#region extensions/msteams/src/monitor-handler/thread-session.ts
35
+ const TRAILING_THREAD_SUFFIX = /(?::thread:[^:]+)+$/;
36
+ function resolveMSTeamsRouteSessionKey(params) {
37
+ const channelThreadId = params.isChannel ? params.conversationMessageId ?? params.replyToId ?? void 0 : void 0;
38
+ const cleanBase = params.baseSessionKey.replace(TRAILING_THREAD_SUFFIX, "");
39
+ return (0, openclaw_plugin_sdk_routing.resolveThreadSessionKeys)({
40
+ baseSessionKey: cleanBase,
41
+ threadId: channelThreadId,
42
+ parentSessionKey: channelThreadId ? cleanBase : void 0
43
+ }).sessionKey;
44
+ }
45
+ //#endregion
46
+ Object.defineProperty(exports, "getMSTeamsApprovalApprovers", {
47
+ enumerable: true,
48
+ get: function() {
49
+ return getMSTeamsApprovalApprovers;
50
+ }
51
+ });
52
+ Object.defineProperty(exports, "msTeamsApprovalAuth", {
53
+ enumerable: true,
54
+ get: function() {
55
+ return msTeamsApprovalAuth;
56
+ }
57
+ });
58
+ Object.defineProperty(exports, "resolveMSTeamsRouteSessionKey", {
59
+ enumerable: true,
60
+ get: function() {
61
+ return resolveMSTeamsRouteSessionKey;
62
+ }
63
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/msteams",
3
- "version": "2026.8.1-beta.3",
3
+ "version": "2026.9.1-beta.1",
4
4
  "description": "OpenClaw Microsoft Teams channel plugin for bot conversations.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,21 +8,21 @@
8
8
  },
9
9
  "type": "module",
10
10
  "dependencies": {
11
- "@azure/identity": "4.13.1",
12
- "@microsoft/teams.api": "2.0.14",
13
- "@microsoft/teams.apps": "2.0.14",
11
+ "@azure/identity": "4.13.2",
12
+ "@microsoft/teams.api": "2.0.15",
13
+ "@microsoft/teams.apps": "2.0.15",
14
14
  "express": "5.2.1",
15
- "typebox": "1.3.6",
15
+ "typebox": "1.3.16",
16
16
  "zod": "4.4.3"
17
17
  },
18
18
  "devDependencies": {
19
- "@microsoft/teams.common": "2.0.14",
19
+ "@microsoft/teams.common": "2.0.15",
20
20
  "@openclaw/plugin-sdk": "workspace:*",
21
- "jose": "6.2.4",
21
+ "jose": "6.2.9",
22
22
  "openclaw": "workspace:*"
23
23
  },
24
24
  "peerDependencies": {
25
- "openclaw": ">=2026.8.1-beta.3"
25
+ "openclaw": ">=2026.9.1-beta.1"
26
26
  },
27
27
  "peerDependenciesMeta": {
28
28
  "openclaw": {
@@ -43,7 +43,9 @@
43
43
  "MSTEAMS_APP_PASSWORD",
44
44
  "MSTEAMS_TENANT_ID"
45
45
  ]
46
- }
46
+ },
47
+ "specifier": "./dist/configured-state.cjs",
48
+ "exportName": "hasConfiguredMSTeamsChannelState"
47
49
  },
48
50
  "label": "Microsoft Teams",
49
51
  "selectionLabel": "Microsoft Teams (Teams SDK)",
@@ -70,10 +72,10 @@
70
72
  "minHostVersion": ">=2026.4.10"
71
73
  },
72
74
  "compat": {
73
- "pluginApi": ">=2026.8.1-beta.3"
75
+ "pluginApi": ">=2026.9.1-beta.1"
74
76
  },
75
77
  "build": {
76
- "openclawVersion": "2026.8.1-beta.3",
78
+ "openclawVersion": "2026.9.1-beta.1",
77
79
  "runtimeFormat": "cjs"
78
80
  },
79
81
  "release": {