@openclaw/msteams 2026.10.10 → 2026.11.5-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.
Files changed (32) hide show
  1. package/dist/.setup/{adapter.runtime-BMvpm7sS.cjs → adapter.runtime-UOD_H_ph.cjs} +20 -23
  2. package/dist/.setup/{approval-card-Bo8kHYbj.cjs → approval-card-CD5q0Nla.cjs} +5 -9
  3. package/dist/.setup/{approval-handler.runtime-BS3avHFu.cjs → approval-handler.runtime-DbPxvynk.cjs} +4 -4
  4. package/dist/.setup/{channel-CdCSk3Rg.cjs → channel-DQrXOfhf.cjs} +24 -224
  5. package/dist/.setup/{channel.runtime--ZjTYgkY.cjs → channel.runtime-Du4GPMES.cjs} +65 -106
  6. package/dist/.setup/{channel.setup-nSTtK77J.cjs → channel.setup--7ko_Kxv.cjs} +161 -262
  7. package/dist/.setup/{config-schema-Bm15lF-j.cjs → config-schema-BEXDIOC-.cjs} +120 -123
  8. package/dist/.setup/{conversation-store-state-NJU9osd-.cjs → conversation-store-state-AVgRyNE9.cjs} +411 -598
  9. package/dist/.setup/{delegated-state-CbMd3rIh.cjs → delegated-state-DhIHahf1.cjs} +68 -6
  10. package/dist/.setup/{monitor-BxLDs5fk.cjs → monitor-CXjIKz7o.cjs} +1883 -2284
  11. package/dist/.setup/{oauth-B-Y5pNM4.cjs → oauth-BWG6qWCd.cjs} +10 -20
  12. package/dist/.setup/presentation-CaLawc5j.cjs +211 -0
  13. package/dist/.setup/{reaction-types-BaL1EVBS.cjs → reaction-types-DOzN5oTl.cjs} +1 -1
  14. package/dist/.setup/{resolve-allowlist-CqNzS9bZ.cjs → resolve-allowlist-Drj1jaq0.cjs} +213 -90
  15. package/dist/.setup/{secret-contract-api-BOzdWSn9.cjs → secret-contract-api-DFqDvc_a.cjs} +4 -6
  16. package/dist/.setup/{secret-contract-api-5aH1Fl_c.cjs → secret-contract-api-YGHrfAT0.cjs} +1 -1
  17. package/dist/.setup/{send-BXjI3ufq.cjs → send-BRUztzVJ.cjs} +86 -182
  18. package/dist/.setup/{setup-plugin-api-lPpin6Gg.cjs → setup-plugin-api-BHEfter5.cjs} +1 -1
  19. package/dist/.setup/{thread-session-DZMoCsSR.cjs → thread-session-BUUV1zk_.cjs} +4 -6
  20. package/dist/.setup/{token-config-DTZ00Ibq.cjs → token-config-7K6UbNCo.cjs} +0 -2
  21. package/dist/.source-module-urls/7e43ee3ae4faab430a47269c8217f8d99ec60ecd85233f40e81d03efeb543068.json +1 -1
  22. package/dist/api.cjs +2 -2
  23. package/dist/channel-config-api.cjs +1 -1
  24. package/dist/channel-plugin-api.cjs +1 -1
  25. package/dist/directory-contract-api.cjs +1 -1
  26. package/dist/doctor-contract-api.cjs +6 -13
  27. package/dist/qa-runner-api.cjs +1 -1
  28. package/dist/secret-contract-api.cjs +1 -1
  29. package/dist/setup-entry.cjs +2 -2
  30. package/dist/setup-plugin-api.cjs +1 -1
  31. package/openclaw.plugin.json +0 -30
  32. package/package.json +11 -11
@@ -1,8 +1,8 @@
1
1
  const require_bot_framework_service_url = require("./bot-framework-service-url-CgVuKiIR.cjs");
2
- const require_token_config = require("./token-config-DTZ00Ibq.cjs");
2
+ const require_token_config = require("./token-config-7K6UbNCo.cjs");
3
3
  const require_runtime = require("./runtime-CbKazLGv.cjs");
4
4
  require("../runtime-api.cjs");
5
- const require_delegated_state = require("./delegated-state-CbMd3rIh.cjs");
5
+ const require_delegated_state = require("./delegated-state-DhIHahf1.cjs");
6
6
  let openclaw_plugin_sdk_lazy_runtime = require("openclaw/plugin-sdk/lazy-runtime");
7
7
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
8
8
  let openclaw_plugin_sdk_account_helpers = require("openclaw/plugin-sdk/account-helpers");
@@ -14,13 +14,14 @@ let openclaw_plugin_sdk_fetch_runtime = require("openclaw/plugin-sdk/fetch-runti
14
14
  let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
15
15
  let openclaw_plugin_sdk_ssrf_runtime = require("openclaw/plugin-sdk/ssrf-runtime");
16
16
  let node_buffer = require("node:buffer");
17
- let node_dns_promises = require("node:dns/promises");
18
17
  let openclaw_plugin_sdk_ssrf_policy = require("openclaw/plugin-sdk/ssrf-policy");
19
18
  let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
20
19
  let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text-utility-runtime");
21
20
  let openclaw_plugin_sdk_secret_file = require("openclaw/plugin-sdk/secret-file");
22
21
  let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
23
22
  let node_module = require("node:module");
23
+ let node_crypto = require("node:crypto");
24
+ let openclaw_plugin_sdk_provider_oauth_runtime = require("openclaw/plugin-sdk/provider-oauth-runtime");
24
25
  let openclaw_plugin_sdk_html_entity_runtime = require("openclaw/plugin-sdk/html-entity-runtime");
25
26
  // extensions/msteams/src/accounts.ts
26
27
  const { listAccountIds, resolveDefaultAccountId } = (0, openclaw_plugin_sdk_account_helpers.createAccountListHelpers)("msteams", {
@@ -169,6 +170,20 @@ function inspectMSTeamsAccount(params) {
169
170
  path: account.config.webhook?.path ?? "/api/messages"
170
171
  };
171
172
  }
173
+ // extensions/msteams/src/microsoft-hosts.ts
174
+ const GRAPH_HOSTS = [
175
+ "graph.microsoft.com",
176
+ "graph.microsoft.us",
177
+ "graph.microsoft.de",
178
+ "graph.microsoft.cn"
179
+ ];
180
+ const SHAREPOINT_HOSTS = [
181
+ "sharepoint.com",
182
+ "sharepoint.us",
183
+ "sharepoint.de",
184
+ "sharepoint.cn",
185
+ "sharepoint-df.com"
186
+ ];
172
187
  // extensions/msteams/src/request-timeout.ts
173
188
  const MSTEAMS_REQUEST_TIMEOUT_MS = 3e4;
174
189
  const MSTEAMS_SHAREPOINT_UPLOAD_BASE_TIMEOUT_MS = 3e5;
@@ -227,7 +242,7 @@ const IMAGE_EXT_RE = /\.(avif|bmp|gif|heic|heif|jpe?g|png|tiff?|webp)$/i;
227
242
  * tag wins, and a quoted value may contain `>`. Each `<tag` start is resolved from
228
243
  * precomputed next-`>` and next-quote positions in one forward pass.
229
244
  */
230
- function htmlTagAttributeValues(html, tag, attr) {
245
+ function htmlTagAttributeValues(html, tag, attr, visit) {
231
246
  const length = html.length;
232
247
  const nextGt = new Int32Array(length + 1).fill(length);
233
248
  const nextQuote = new Int32Array(length + 1).fill(length);
@@ -257,13 +272,37 @@ function htmlTagAttributeValues(html, tag, attr) {
257
272
  while (pastWindow < candidates.length && candidates[pastWindow].start <= lastStart) pastWindow += 1;
258
273
  const candidate = candidates[pastWindow - 1];
259
274
  if (candidate && candidate.start > nameEnd) {
260
- values.push(html.slice(candidate.valueStart, candidate.valueEnd));
275
+ const value = html.slice(candidate.valueStart, candidate.valueEnd);
276
+ if (visit) visit(value, open.index, candidate.end);
277
+ else values.push(value);
261
278
  resumeAt = candidate.end;
262
279
  }
263
280
  }
264
281
  return values;
265
282
  }
266
283
  const GRAPH_HOSTED_CONTENT_SRC_RE = /\/hostedContents\/([^/?#]+)/i;
284
+ const TEAMS_EMOJI_CDN_HOST = "statics.teams.cdn.office.net";
285
+ const TEAMS_EMOJI_ASSET_PATH_RE = /\/emoji([/?#]|$)/i;
286
+ const IMG_ALT_ATTR_RE = /\balt=["']([^"']*)["']/i;
287
+ const EMOJI_PICTOGRAPHIC_RE = /\p{Extended_Pictographic}/u;
288
+ function isTeamsEmojiSpriteImage(src, imgTag) {
289
+ const url = URL.parse(src);
290
+ const host = url?.hostname.toLowerCase() ?? "";
291
+ if (host !== TEAMS_EMOJI_CDN_HOST && !host.endsWith(`.${TEAMS_EMOJI_CDN_HOST}`)) return false;
292
+ return TEAMS_EMOJI_ASSET_PATH_RE.test(url?.pathname ?? "") || EMOJI_PICTOGRAPHIC_RE.test(IMG_ALT_ATTR_RE.exec(imgTag)?.[1] ?? "");
293
+ }
294
+ function replaceTeamsEmojiSpriteImagesWithAltText(html) {
295
+ const parts = [];
296
+ let cursor = 0;
297
+ htmlTagAttributeValues(html, "img", "src", (src, start, end) => {
298
+ const imgTag = html.slice(start, end);
299
+ if (isTeamsEmojiSpriteImage(src.trim(), imgTag)) {
300
+ parts.push(html.slice(cursor, start), IMG_ALT_ATTR_RE.exec(imgTag)?.[1] ?? "");
301
+ cursor = end;
302
+ }
303
+ });
304
+ return parts.join("") + html.slice(cursor);
305
+ }
267
306
  function resolveInlineImageSourceId(src) {
268
307
  const hostedContentId = GRAPH_HOSTED_CONTENT_SRC_RE.exec(src)?.[1];
269
308
  if (!hostedContentId) return src;
@@ -274,15 +313,8 @@ function resolveInlineImageSourceId(src) {
274
313
  }
275
314
  }
276
315
  const DEFAULT_MEDIA_HOST_ALLOWLIST = [
277
- "graph.microsoft.com",
278
- "graph.microsoft.us",
279
- "graph.microsoft.de",
280
- "graph.microsoft.cn",
281
- "sharepoint.com",
282
- "sharepoint.us",
283
- "sharepoint.de",
284
- "sharepoint.cn",
285
- "sharepoint-df.com",
316
+ ...GRAPH_HOSTS,
317
+ ...SHAREPOINT_HOSTS,
286
318
  "1drv.ms",
287
319
  "onedrive.com",
288
320
  "teams.microsoft.com",
@@ -304,10 +336,7 @@ const DEFAULT_MEDIA_AUTH_HOST_ALLOWLIST = [
304
336
  "botframework.com",
305
337
  "smba.trafficmanager.net",
306
338
  "botframework.azure.cn",
307
- "graph.microsoft.com",
308
- "graph.microsoft.us",
309
- "graph.microsoft.de",
310
- "graph.microsoft.cn"
339
+ ...GRAPH_HOSTS
311
340
  ];
312
341
  const GRAPH_ROOT = "https://graph.microsoft.com/v1.0";
313
342
  /**
@@ -319,11 +348,7 @@ const GRAPH_ROOT = "https://graph.microsoft.com/v1.0";
319
348
  * https://learn.microsoft.com/en-us/graph/api/shares-get for the encoding.
320
349
  */
321
350
  const GRAPH_SHARED_LINK_HOST_SUFFIXES = [
322
- ".sharepoint.com",
323
- ".sharepoint.us",
324
- ".sharepoint.de",
325
- ".sharepoint.cn",
326
- ".sharepoint-df.com",
351
+ ...SHAREPOINT_HOSTS.map((host) => `.${host}`),
327
352
  "1drv.ms",
328
353
  "onedrive.live.com",
329
354
  "onedrive.com"
@@ -401,7 +426,7 @@ function extractInlineImageReferences(attachments) {
401
426
  for (const att of attachments) {
402
427
  const html = extractHtmlFromAttachment(att);
403
428
  if (!html) continue;
404
- for (const value of htmlTagAttributeValues(html, "img", "src")) {
429
+ for (const value of htmlTagAttributeValues(replaceTeamsEmojiSpriteImagesWithAltText(html), "img", "src")) {
405
430
  const src = value.trim();
406
431
  if (src) {
407
432
  if (src.startsWith("data:")) out.push({
@@ -434,15 +459,6 @@ function safeHostForUrl(url) {
434
459
  const parsed = URL.parse(url);
435
460
  return parsed ? (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(parsed.hostname) : "invalid-url";
436
461
  }
437
- function isMockFetchFn(fetchFn) {
438
- const candidate = fetchFn;
439
- return Boolean(candidate.mock || Object.hasOwn(candidate, "_isMockFunction"));
440
- }
441
- function resolveGuardedFetchImpl(fetchFn) {
442
- if (!fetchFn) return;
443
- if (fetchFn === fetch || fetchFn === globalThis.fetch || isMockFetchFn(fetchFn)) return fetchFn;
444
- throw new Error("MSTeams attachment fetchFn must set fetchFnSupportsDispatcher to use guarded DNS pinning");
445
- }
446
462
  function resolveRetainedAuthorizationRedirectHostnameAllowlist(input) {
447
463
  if (!input) return;
448
464
  if (input.includes("*")) return ["*"];
@@ -464,21 +480,20 @@ function isRedirectStatus(status) {
464
480
  }
465
481
  /**
466
482
  * Fetch a URL with redirect: "manual", validating each redirect target
467
- * against the hostname allowlist and optional DNS-resolved IP (anti-SSRF).
483
+ * against the hostname allowlist and DNS-resolved IP (anti-SSRF).
468
484
  *
469
485
  * This prevents:
470
486
  * - Auto-following redirects to non-allowlisted hosts
471
- * - DNS rebinding attacks when a lookup function is provided
487
+ * - DNS rebinding attacks through the pinned DNS lookup
472
488
  */
473
489
  async function safeFetchWithPolicy(params) {
474
490
  const { allowHosts, authAllowHosts } = params.policy;
475
- const resolveFn = params.resolveFn ?? node_dns_promises.lookup;
476
491
  const currentHeaders = new Headers(params.requestInit?.headers);
477
492
  const currentUrl = params.url;
478
493
  if (!(0, openclaw_plugin_sdk_ssrf_policy.isHttpsUrlAllowedByHostnameSuffixAllowlist)(currentUrl, allowHosts)) throw new Error(`Initial download URL blocked: ${currentUrl}`);
479
494
  if (currentHeaders.has("authorization") && !(0, openclaw_plugin_sdk_ssrf_policy.isHttpsUrlAllowedByHostnameSuffixAllowlist)(currentUrl, authAllowHosts)) currentHeaders.delete("authorization");
480
495
  const lookupFn = async (hostname) => {
481
- const resolved = await resolveFn(hostname);
496
+ const resolved = await params.resolveFn(hostname);
482
497
  return [{
483
498
  ...resolved,
484
499
  family: resolved.address.includes(":") ? 6 : 4
@@ -486,7 +501,6 @@ async function safeFetchWithPolicy(params) {
486
501
  };
487
502
  const guarded = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
488
503
  url: currentUrl,
489
- fetchImpl: resolveGuardedFetchImpl(params.fetchFn),
490
504
  init: {
491
505
  ...params.requestInit,
492
506
  headers: currentHeaders
@@ -792,7 +806,7 @@ const EXPIRY_BUFFER_MS = 3e5;
792
806
  function parseMSTeamsTokenResponse(data, failureLabel) {
793
807
  if (!(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(data)) throw new Error(`MSTeams ${failureLabel} failed: invalid token response fields`);
794
808
  const expiresAt = (0, openclaw_plugin_sdk_number_runtime.resolveExpiresAtMsFromDurationSeconds)(data.expires_in, { bufferMs: EXPIRY_BUFFER_MS });
795
- if (typeof data.access_token !== "string" || !data.access_token || expiresAt === void 0 || data.refresh_token !== void 0 && typeof data.refresh_token !== "string" || data.scope !== void 0 && typeof data.scope !== "string") throw new Error(`MSTeams ${failureLabel} failed: invalid token response fields`);
809
+ if (typeof data.access_token !== "string" || !data.access_token || expiresAt === void 0 || data.refresh_token !== void 0 && (typeof data.refresh_token !== "string" || !data.refresh_token) || data.scope !== void 0 && typeof data.scope !== "string") throw new Error(`MSTeams ${failureLabel} failed: invalid token response fields`);
796
810
  return {
797
811
  access_token: data.access_token,
798
812
  refresh_token: data.refresh_token,
@@ -801,7 +815,11 @@ function parseMSTeamsTokenResponse(data, failureLabel) {
801
815
  };
802
816
  }
803
817
  async function fetchMSTeamsTokens(params) {
818
+ let dispatched = false;
804
819
  const { response, release } = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
820
+ beforeRequest: () => {
821
+ dispatched = true;
822
+ },
805
823
  url: params.tokenUrl,
806
824
  init: {
807
825
  method: "POST",
@@ -813,10 +831,56 @@ async function fetchMSTeamsTokens(params) {
813
831
  signal: AbortSignal.timeout(MSTEAMS_DEFAULT_TOKEN_FETCH_TIMEOUT_MS)
814
832
  },
815
833
  auditContext: params.auditContext
834
+ }).catch((cause) => {
835
+ if (!params.refresh) throw cause;
836
+ throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("MSTeams refresh transport failed", dispatched ? {
837
+ version: 1,
838
+ phase: "token-response",
839
+ outcome: "unchanged",
840
+ recovery: {
841
+ kind: "later",
842
+ evidence: "documented-reusable-grant"
843
+ }
844
+ } : {
845
+ version: 1,
846
+ phase: "before-dispatch",
847
+ outcome: "not-attempted",
848
+ recovery: {
849
+ kind: "later",
850
+ evidence: "dispatch-not-started"
851
+ }
852
+ }, { cause });
816
853
  });
817
854
  try {
818
- if (!response.ok) throw await (0, openclaw_plugin_sdk_provider_http.createProviderHttpError)(response, `MSTeams ${params.failureLabel} failed`);
819
- return parseMSTeamsTokenResponse(await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(response, `MSTeams ${params.failureLabel} failed`), params.failureLabel);
855
+ if (!response.ok && !params.refresh) throw await (0, openclaw_plugin_sdk_provider_http.createProviderHttpError)(response, `MSTeams ${params.failureLabel} failed`);
856
+ let data;
857
+ try {
858
+ data = await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(response, `MSTeams ${params.failureLabel} failed`);
859
+ } catch (cause) {
860
+ if (!params.refresh) throw cause;
861
+ if (!response.ok) throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshResponseError)("MSTeams token refresh", response.status, void 0, "documented-reusable-grant");
862
+ throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("MSTeams refresh response could not be read", {
863
+ version: 1,
864
+ phase: "token-response",
865
+ outcome: "unchanged",
866
+ recovery: {
867
+ kind: "later",
868
+ evidence: "documented-reusable-grant"
869
+ }
870
+ }, { cause });
871
+ }
872
+ if (params.refresh && (!response.ok || (0, openclaw_plugin_sdk_provider_oauth_runtime.readOAuthRefreshErrorReason)(data))) throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshResponseError)("MSTeams token refresh", response.status, data, "documented-reusable-grant");
873
+ try {
874
+ return parseMSTeamsTokenResponse(data, params.failureLabel);
875
+ } catch (cause) {
876
+ if (!params.refresh) throw cause;
877
+ throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("MSTeams refresh response fields are invalid", {
878
+ version: 1,
879
+ phase: "after-token-response",
880
+ outcome: "unknown",
881
+ status: response.status
882
+ }, { cause });
883
+ }
820
884
  } finally {
821
885
  await release();
822
886
  }
@@ -834,7 +898,8 @@ async function requestMSTeamsDelegatedTokens(params) {
834
898
  tokenUrl: buildMSTeamsTokenEndpoint(params.tenantId),
835
899
  body,
836
900
  auditContext: params.auditContext,
837
- failureLabel: params.failureLabel
901
+ failureLabel: params.failureLabel,
902
+ refresh: params.grantType === "refresh_token"
838
903
  });
839
904
  return {
840
905
  accessToken: data.access_token,
@@ -849,7 +914,6 @@ async function exchangeMSTeamsCodeForTokens(params) {
849
914
  clientId: params.clientId,
850
915
  clientSecret: params.clientSecret,
851
916
  grantType: "authorization_code",
852
- scopes: params.scopes,
853
917
  values: {
854
918
  code: params.code,
855
919
  redirect_uri: MSTEAMS_OAUTH_REDIRECT_URI,
@@ -877,22 +941,67 @@ async function refreshMSTeamsDelegatedTokens(params) {
877
941
  });
878
942
  }
879
943
  // extensions/msteams/src/token.ts
944
+ const refreshes = /* @__PURE__ */ new WeakMap();
880
945
  async function resolveDelegatedAccessToken(params) {
881
- const tokens = await require_delegated_state.loadMSTeamsDelegatedTokens(params.accountId);
882
- if (!tokens) return;
946
+ const runtime = require_runtime.getMSTeamsRuntime();
947
+ const callerKey = (0, node_crypto.createHash)("sha256").update(JSON.stringify([
948
+ runtime.state.resolveStateDir(),
949
+ require_delegated_state.resolveMSTeamsAccountStateNamespace("delegated-token", params.accountId),
950
+ params.tenantId,
951
+ params.clientId,
952
+ params.clientSecret
953
+ ])).digest("hex");
954
+ const state = await require_delegated_state.loadMSTeamsDelegatedTokenState(params.accountId);
955
+ const tokens = require_delegated_state.normalizeMSTeamsDelegatedTokens(state);
956
+ const active = refreshes.get(runtime) ?? /* @__PURE__ */ new Map();
957
+ refreshes.set(runtime, active);
958
+ if (state && "refreshClaim" in state && state.callerKey === callerKey) {
959
+ const pending = active.get(state.requestKey);
960
+ if (pending) return await pending;
961
+ }
962
+ if (!tokens) return state && "refreshClaim" in state && state.callerKey === callerKey ? await active.get(state.requestKey) : void 0;
883
963
  if ((0, openclaw_plugin_sdk_number_runtime.isFutureDateTimestampMs)(tokens.expiresAt)) return tokens.accessToken;
964
+ const key = (0, node_crypto.createHash)("sha256").update(JSON.stringify([callerKey, tokens])).digest("hex");
965
+ const pending = active.get(key);
966
+ if (pending) return await pending;
967
+ const task = (async () => {
968
+ try {
969
+ const claim = await require_delegated_state.claimMSTeamsDelegatedTokenRefresh(tokens, key, callerKey, params.accountId);
970
+ if (!claim) return;
971
+ let refreshed;
972
+ try {
973
+ if (require_runtime.getMSTeamsRuntime() !== runtime) throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("Microsoft Teams token owner changed before refresh dispatch", {
974
+ version: 1,
975
+ phase: "before-dispatch",
976
+ outcome: "not-attempted",
977
+ recovery: {
978
+ kind: "later",
979
+ evidence: "dispatch-not-started"
980
+ }
981
+ });
982
+ refreshed = await refreshMSTeamsDelegatedTokens({
983
+ ...params,
984
+ refreshToken: tokens.refreshToken,
985
+ scopes: tokens.scopes
986
+ });
987
+ } catch (error) {
988
+ if ((0, openclaw_plugin_sdk_provider_oauth_runtime.isRecoverableOAuthRefreshFailure)(error)) await claim.settle(tokens);
989
+ else await claim.reject();
990
+ return;
991
+ }
992
+ return await claim.settle({
993
+ ...tokens,
994
+ ...refreshed
995
+ }) ? refreshed.accessToken : void 0;
996
+ } catch {
997
+ return;
998
+ }
999
+ })();
1000
+ active.set(key, task);
884
1001
  try {
885
- const refreshed = await refreshMSTeamsDelegatedTokens({
886
- tenantId: params.tenantId,
887
- clientId: params.clientId,
888
- clientSecret: params.clientSecret,
889
- refreshToken: tokens.refreshToken,
890
- scopes: tokens.scopes
891
- });
892
- await require_delegated_state.saveMSTeamsDelegatedTokens(refreshed, params.accountId);
893
- return refreshed.accessToken;
894
- } catch {
895
- return;
1002
+ return await task;
1003
+ } finally {
1004
+ if (active.get(key) === task) active.delete(key);
896
1005
  }
897
1006
  }
898
1007
  // extensions/msteams/src/graph.ts
@@ -910,9 +1019,6 @@ function captureGraphRequestCurrentness(assertReadAuthority) {
910
1019
  assertCurrent();
911
1020
  };
912
1021
  }
913
- function normalizeQuery(value) {
914
- return value?.trim() ?? "";
915
- }
916
1022
  function escapeOData(value) {
917
1023
  return value.replace(/'/g, "''");
918
1024
  }
@@ -1053,9 +1159,6 @@ async function resolveGraphToken(cfg, options) {
1053
1159
  if (!accessToken) throw new Error("MS Teams graph token unavailable");
1054
1160
  return accessToken;
1055
1161
  }
1056
- async function listTeamsByName(token, query) {
1057
- return (await listTeamsByNameWithPageInfo(token, query)).items;
1058
- }
1059
1162
  async function listTeamsByNameWithPageInfo(token, query) {
1060
1163
  const filter = `resourceProvisioningOptions/Any(x:x eq 'Team') and startsWith(displayName,'${escapeOData(query)}')`;
1061
1164
  return await fetchAllGraphPages({
@@ -1071,9 +1174,6 @@ async function deleteGraphRequest(params) {
1071
1174
  errorPrefix: "Graph DELETE"
1072
1175
  })).body?.cancel().catch(() => void 0);
1073
1176
  }
1074
- async function listChannelsForTeam(token, teamId) {
1075
- return (await listChannelsForTeamWithPageInfo(token, teamId)).items;
1076
- }
1077
1177
  async function listChannelsForTeamWithPageInfo(token, teamId) {
1078
1178
  return await fetchAllGraphPages({
1079
1179
  token,
@@ -1093,7 +1193,7 @@ async function searchGraphUsers(params) {
1093
1193
  path
1094
1194
  })).value ?? [];
1095
1195
  }
1096
- const top = typeof params.top === "number" && params.top > 0 ? params.top : 10;
1196
+ const top = params.top !== void 0 && params.top > 0 ? params.top : 10;
1097
1197
  const path = `/users?$search=${encodeURIComponent(`"displayName:${query}"`)}&$select=id,displayName,mail,userPrincipalName&$top=${top}`;
1098
1198
  return (await fetchGraphJson({
1099
1199
  token: params.token,
@@ -1190,6 +1290,22 @@ function parseMSTeamsActivityTimestamp(value) {
1190
1290
  function stripMSTeamsMentionTags(text) {
1191
1291
  return text.replace(/<at[^>]*>.*?<\/at>/gi, "").trim();
1192
1292
  }
1293
+ function normalizeMSTeamsMentionTags(text, activity, options = {}) {
1294
+ const normalizeTag = (tag) => tag.trim().replace(/<\/?at\b/gi, (delimiter) => delimiter.toLowerCase());
1295
+ const botId = activity.recipient?.id;
1296
+ const botMentions = /* @__PURE__ */ new Map();
1297
+ for (const entity of activity.entities ?? []) {
1298
+ if (entity.type !== "mention" || typeof entity.text !== "string") continue;
1299
+ const tag = normalizeTag(entity.text);
1300
+ const isBot = Boolean(botId && entity.mentioned?.id === botId);
1301
+ botMentions.set(tag, isBot && botMentions.get(tag) !== false);
1302
+ }
1303
+ return text.replace(/<at\b[^>]*>([\s\S]*?)<\/at\s*>/gi, (tag, label) => {
1304
+ if (botMentions.get(normalizeTag(tag))) return options.preserveHtml ? " " : "";
1305
+ const displayName = htmlToPlainText(label);
1306
+ return displayName ? `@${options.preserveHtml ? label : displayName}` : "";
1307
+ }).trim();
1308
+ }
1193
1309
  function wasMSTeamsBotMentioned(activity) {
1194
1310
  const botId = activity.recipient?.id;
1195
1311
  if (!botId) return false;
@@ -1203,27 +1319,22 @@ function keepConfiguredMSTeamsAllowlistActive(configured, projected) {
1203
1319
  if (!Array.isArray(configured) || configured.every((entry) => !entry?.trim())) return projected;
1204
1320
  return projected && projected.length > 0 ? projected : [MSTEAMS_UNMATCHABLE_THREAD_ID];
1205
1321
  }
1206
- function uniqueItemsById(items) {
1322
+ function findExactMatches(items, query, fields = ["displayName"]) {
1323
+ const normalized = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(query);
1207
1324
  const byId = /* @__PURE__ */ new Map();
1208
1325
  for (const item of items) {
1326
+ if (!fields.some((field) => (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(item[field]) === normalized)) continue;
1209
1327
  const id = item.id?.trim();
1210
1328
  if (id && !byId.has(id)) byId.set(id, item);
1211
1329
  }
1212
1330
  return [...byId.values()];
1213
1331
  }
1214
- function findExactMatches(items, query, fields = ["displayName"]) {
1215
- const normalized = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(query);
1216
- return uniqueItemsById(items.filter((item) => fields.some((field) => (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(item[field]) === normalized)));
1217
- }
1218
- function isStableMSTeamsUserId(raw) {
1219
- return /^[0-9a-fA-F-]{16,}$/.test(normalizeMSTeamsUserInput(raw));
1220
- }
1221
1332
  function normalizeStaticMSTeamsAllowEntry(raw) {
1222
1333
  const trimmed = raw.trim();
1223
1334
  if (!trimmed) return;
1224
1335
  if (trimmed === "*" || /^accessGroup:/i.test(trimmed)) return trimmed;
1225
1336
  const id = normalizeMSTeamsUserInput(trimmed);
1226
- return isStableMSTeamsUserId(id) ? id : void 0;
1337
+ return /^[0-9a-fA-F-]{16,}$/.test(normalizeMSTeamsUserInput(id)) ? id : void 0;
1227
1338
  }
1228
1339
  function projectStableMSTeamsAllowlist(entries, allowConversations) {
1229
1340
  if (!entries) return;
@@ -1645,11 +1756,17 @@ async function resolveMSTeamsUserAllowlist(params) {
1645
1756
  input,
1646
1757
  resolved: true,
1647
1758
  id: match.id,
1648
- name: match.displayName ?? void 0
1759
+ name: match.displayName
1649
1760
  };
1650
1761
  }
1651
1762
  });
1652
1763
  }
1764
+ Object.defineProperty(exports, "GRAPH_HOSTS", {
1765
+ enumerable: true,
1766
+ get: function() {
1767
+ return GRAPH_HOSTS;
1768
+ }
1769
+ });
1653
1770
  Object.defineProperty(exports, "GRAPH_ROOT", {
1654
1771
  enumerable: true,
1655
1772
  get: function() {
@@ -1674,6 +1791,12 @@ Object.defineProperty(exports, "MSTEAMS_REQUEST_TIMEOUT_MS", {
1674
1791
  return MSTEAMS_REQUEST_TIMEOUT_MS;
1675
1792
  }
1676
1793
  });
1794
+ Object.defineProperty(exports, "SHAREPOINT_HOSTS", {
1795
+ enumerable: true,
1796
+ get: function() {
1797
+ return SHAREPOINT_HOSTS;
1798
+ }
1799
+ });
1677
1800
  Object.defineProperty(exports, "applyAuthorizationHeaderForUrl", {
1678
1801
  enumerable: true,
1679
1802
  get: function() {
@@ -1842,12 +1965,6 @@ Object.defineProperty(exports, "keepConfiguredMSTeamsAllowlistActive", {
1842
1965
  return keepConfiguredMSTeamsAllowlistActive;
1843
1966
  }
1844
1967
  });
1845
- Object.defineProperty(exports, "listChannelsForTeam", {
1846
- enumerable: true,
1847
- get: function() {
1848
- return listChannelsForTeam;
1849
- }
1850
- });
1851
1968
  Object.defineProperty(exports, "listChannelsForTeamWithPageInfo", {
1852
1969
  enumerable: true,
1853
1970
  get: function() {
@@ -1860,10 +1977,10 @@ Object.defineProperty(exports, "listMSTeamsAccountIds", {
1860
1977
  return listMSTeamsAccountIds;
1861
1978
  }
1862
1979
  });
1863
- Object.defineProperty(exports, "listTeamsByName", {
1980
+ Object.defineProperty(exports, "listTeamsByNameWithPageInfo", {
1864
1981
  enumerable: true,
1865
1982
  get: function() {
1866
- return listTeamsByName;
1983
+ return listTeamsByNameWithPageInfo;
1867
1984
  }
1868
1985
  });
1869
1986
  Object.defineProperty(exports, "loadMSTeamsSdkWithAuth", {
@@ -1902,22 +2019,22 @@ Object.defineProperty(exports, "normalizeMSTeamsConversationId", {
1902
2019
  return normalizeMSTeamsConversationId;
1903
2020
  }
1904
2021
  });
1905
- Object.defineProperty(exports, "normalizeMSTeamsMessagingTarget", {
2022
+ Object.defineProperty(exports, "normalizeMSTeamsMentionTags", {
1906
2023
  enumerable: true,
1907
2024
  get: function() {
1908
- return normalizeMSTeamsMessagingTarget;
2025
+ return normalizeMSTeamsMentionTags;
1909
2026
  }
1910
2027
  });
1911
- Object.defineProperty(exports, "normalizeMSTeamsUserInput", {
2028
+ Object.defineProperty(exports, "normalizeMSTeamsMessagingTarget", {
1912
2029
  enumerable: true,
1913
2030
  get: function() {
1914
- return normalizeMSTeamsUserInput;
2031
+ return normalizeMSTeamsMessagingTarget;
1915
2032
  }
1916
2033
  });
1917
- Object.defineProperty(exports, "normalizeQuery", {
2034
+ Object.defineProperty(exports, "normalizeMSTeamsUserInput", {
1918
2035
  enumerable: true,
1919
2036
  get: function() {
1920
- return normalizeQuery;
2037
+ return normalizeMSTeamsUserInput;
1921
2038
  }
1922
2039
  });
1923
2040
  Object.defineProperty(exports, "parseMSTeamsActivityTimestamp", {
@@ -1962,6 +2079,12 @@ Object.defineProperty(exports, "projectStableMSTeamsUserAllowlist", {
1962
2079
  return projectStableMSTeamsUserAllowlist;
1963
2080
  }
1964
2081
  });
2082
+ Object.defineProperty(exports, "replaceTeamsEmojiSpriteImagesWithAltText", {
2083
+ enumerable: true,
2084
+ get: function() {
2085
+ return replaceTeamsEmojiSpriteImagesWithAltText;
2086
+ }
2087
+ });
1965
2088
  Object.defineProperty(exports, "resolveAttachmentFetchPolicy", {
1966
2089
  enumerable: true,
1967
2090
  get: function() {
@@ -1,4 +1,4 @@
1
- let openclaw_plugin_sdk_setup = require("openclaw/plugin-sdk/setup");
1
+ let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
2
2
  let openclaw_plugin_sdk_channel_secret_basic_runtime = require("openclaw/plugin-sdk/channel-secret-basic-runtime");
3
3
  // extensions/msteams/src/secret-contract.ts
4
4
  const secretTargetRegistryEntries = (0, openclaw_plugin_sdk_channel_secret_basic_runtime.createChannelSecretTargetRegistryEntries)({
@@ -10,13 +10,14 @@ function collectRuntimeConfigAssignments(params) {
10
10
  const resolved = (0, openclaw_plugin_sdk_channel_secret_basic_runtime.getChannelSurface)(params.config, "msteams");
11
11
  if (!resolved) return;
12
12
  const { channel: msteams, surface } = resolved;
13
+ const defaultEnabled = (surface.hasExplicitAccounts ? surface.accounts.find(({ accountId }) => (0, openclaw_plugin_sdk_account_id.normalizeAccountId)(accountId) === openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID) : void 0)?.enabled ?? surface.channelEnabled;
13
14
  (0, openclaw_plugin_sdk_channel_secret_basic_runtime.collectSecretInputAssignment)({
14
15
  value: msteams.appPassword,
15
16
  path: "channels.msteams.appPassword",
16
17
  expected: "string",
17
18
  defaults: params.defaults,
18
19
  context: params.context,
19
- active: isRootDefaultIdentityActive(msteams, surface),
20
+ active: defaultEnabled && (isConfiguredIdentityField(msteams.appId) || isConfiguredIdentityField(msteams.appPassword)),
20
21
  inactiveReason: "no enabled account inherits this top-level Microsoft Teams appPassword.",
21
22
  owner: {
22
23
  ownerKind: "account",
@@ -42,7 +43,7 @@ function collectRuntimeConfigAssignments(params) {
42
43
  inactiveReason: "Microsoft Teams account is disabled.",
43
44
  owner: {
44
45
  ownerKind: "account",
45
- ownerId: `msteams:${(0, openclaw_plugin_sdk_setup.normalizeAccountId)(accountId)}`,
46
+ ownerId: `msteams:${(0, openclaw_plugin_sdk_account_id.normalizeAccountId)(accountId)}`,
46
47
  requiredForGateway: false,
47
48
  disposition: "isolate",
48
49
  contract: account
@@ -57,9 +58,6 @@ function isConfiguredIdentityField(value) {
57
58
  if (typeof value === "string") return value.trim().length > 0;
58
59
  return value !== void 0 && value !== null;
59
60
  }
60
- function isRootDefaultIdentityActive(channel, surface) {
61
- return ((surface.hasExplicitAccounts ? surface.accounts.find(({ accountId }) => (0, openclaw_plugin_sdk_setup.normalizeAccountId)(accountId) === openclaw_plugin_sdk_setup.DEFAULT_ACCOUNT_ID) : void 0)?.enabled ?? surface.channelEnabled) && (isConfiguredIdentityField(channel.appId) || isConfiguredIdentityField(channel.appPassword));
62
- }
63
61
  const channelSecrets = {
64
62
  secretTargetRegistryEntries,
65
63
  collectRuntimeConfigAssignments
@@ -1,4 +1,4 @@
1
- const require_secret_contract_api = require("./secret-contract-api-BOzdWSn9.cjs");
1
+ const require_secret_contract_api = require("./secret-contract-api-DFqDvc_a.cjs");
2
2
  exports.channelSecrets = require_secret_contract_api.channelSecrets;
3
3
  exports.collectRuntimeConfigAssignments = require_secret_contract_api.collectRuntimeConfigAssignments;
4
4
  exports.secretTargetRegistryEntries = require_secret_contract_api.secretTargetRegistryEntries;