@openclaw/msteams 2026.11.3 → 2026.11.5-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.
Files changed (32) hide show
  1. package/dist/.setup/{adapter.runtime-B-6Q3nMI.cjs → adapter.runtime-BB38Rdj_.cjs} +20 -23
  2. package/dist/.setup/{approval-card-DWPDItvq.cjs → approval-card-BHAKsdAM.cjs} +5 -9
  3. package/dist/.setup/{approval-handler.runtime-D0jbDypb.cjs → approval-handler.runtime-C16UvawQ.cjs} +4 -4
  4. package/dist/.setup/{channel-Ci6K9Njb.cjs → channel-BaTw0JW3.cjs} +35 -254
  5. package/dist/.setup/{channel.runtime-DeHVAVxL.cjs → channel.runtime-Ch2M_-jN.cjs} +65 -107
  6. package/dist/.setup/{channel.setup-BN3uhq3r.cjs → channel.setup-B9yKGEse.cjs} +161 -262
  7. package/dist/.setup/{config-schema-CkKdphSp.cjs → config-schema-3lVZ45cB.cjs} +120 -125
  8. package/dist/.setup/{conversation-store-state-B-4g4uq5.cjs → conversation-store-state-CVhMM0QY.cjs} +411 -601
  9. package/dist/.setup/{delegated-state-Bv5cWuec.cjs → delegated-state-ilYzKwD8.cjs} +68 -6
  10. package/dist/.setup/{monitor-cuifGELM.cjs → monitor-b0zPpnmW.cjs} +1883 -2310
  11. package/dist/.setup/{oauth-BBUQCwmq.cjs → oauth-CUtfkgKE.cjs} +10 -21
  12. package/dist/.setup/presentation-Duoi9Ijn.cjs +213 -0
  13. package/dist/.setup/{reaction-types-CwP5RVQB.cjs → reaction-types-C6F6g2nk.cjs} +1 -1
  14. package/dist/.setup/{resolve-allowlist-gI34MnpE.cjs → resolve-allowlist-7mIEepXB.cjs} +214 -90
  15. package/dist/.setup/{secret-contract-api-wAyY5UHv.cjs → secret-contract-api-D554HIrH.cjs} +4 -6
  16. package/dist/.setup/{secret-contract-api-YY3v6MP8.cjs → secret-contract-api-r3hRtbBW.cjs} +1 -1
  17. package/dist/.setup/{send-C9JY42T6.cjs → send-D1w7a_ip.cjs} +86 -182
  18. package/dist/.setup/{setup-plugin-api-B-NYBLkF.cjs → setup-plugin-api-ChovZJU6.cjs} +1 -1
  19. package/dist/.setup/{thread-session-BWVCoYza.cjs → thread-session-CeWYiol_.cjs} +4 -6
  20. package/dist/.setup/{token-config-bEpua_Q7.cjs → token-config-DICiuJWr.cjs} +0 -2
  21. package/dist/.source-module-urls/7e43ee3ae4faab430a47269c8217f8d99ec60ecd85233f40e81d03efeb543068.json +1 -0
  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 +3 -11
  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-B3FWn2SV.cjs");
2
- const require_token_config = require("./token-config-bEpua_Q7.cjs");
2
+ const require_token_config = require("./token-config-DICiuJWr.cjs");
3
3
  const require_runtime = require("./runtime-gZTAuFux.cjs");
4
4
  require("../runtime-api.cjs");
5
- const require_delegated_state = require("./delegated-state-Bv5cWuec.cjs");
5
+ const require_delegated_state = require("./delegated-state-ilYzKwD8.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
  //#region extensions/msteams/src/accounts.ts
26
27
  const { listAccountIds, resolveDefaultAccountId } = (0, openclaw_plugin_sdk_account_helpers.createAccountListHelpers)("msteams", {
@@ -170,6 +171,21 @@ function inspectMSTeamsAccount(params) {
170
171
  };
171
172
  }
172
173
  //#endregion
174
+ //#region extensions/msteams/src/microsoft-hosts.ts
175
+ const GRAPH_HOSTS = [
176
+ "graph.microsoft.com",
177
+ "graph.microsoft.us",
178
+ "graph.microsoft.de",
179
+ "graph.microsoft.cn"
180
+ ];
181
+ const SHAREPOINT_HOSTS = [
182
+ "sharepoint.com",
183
+ "sharepoint.us",
184
+ "sharepoint.de",
185
+ "sharepoint.cn",
186
+ "sharepoint-df.com"
187
+ ];
188
+ //#endregion
173
189
  //#region extensions/msteams/src/request-timeout.ts
174
190
  const MSTEAMS_REQUEST_TIMEOUT_MS = 3e4;
175
191
  const MSTEAMS_SHAREPOINT_UPLOAD_BASE_TIMEOUT_MS = 3e5;
@@ -229,7 +245,7 @@ const IMAGE_EXT_RE = /\.(avif|bmp|gif|heic|heif|jpe?g|png|tiff?|webp)$/i;
229
245
  * tag wins, and a quoted value may contain `>`. Each `<tag` start is resolved from
230
246
  * precomputed next-`>` and next-quote positions in one forward pass.
231
247
  */
232
- function htmlTagAttributeValues(html, tag, attr) {
248
+ function htmlTagAttributeValues(html, tag, attr, visit) {
233
249
  const length = html.length;
234
250
  const nextGt = new Int32Array(length + 1).fill(length);
235
251
  const nextQuote = new Int32Array(length + 1).fill(length);
@@ -259,13 +275,37 @@ function htmlTagAttributeValues(html, tag, attr) {
259
275
  while (pastWindow < candidates.length && candidates[pastWindow].start <= lastStart) pastWindow += 1;
260
276
  const candidate = candidates[pastWindow - 1];
261
277
  if (candidate && candidate.start > nameEnd) {
262
- values.push(html.slice(candidate.valueStart, candidate.valueEnd));
278
+ const value = html.slice(candidate.valueStart, candidate.valueEnd);
279
+ if (visit) visit(value, open.index, candidate.end);
280
+ else values.push(value);
263
281
  resumeAt = candidate.end;
264
282
  }
265
283
  }
266
284
  return values;
267
285
  }
268
286
  const GRAPH_HOSTED_CONTENT_SRC_RE = /\/hostedContents\/([^/?#]+)/i;
287
+ const TEAMS_EMOJI_CDN_HOST = "statics.teams.cdn.office.net";
288
+ const TEAMS_EMOJI_ASSET_PATH_RE = /\/emoji([/?#]|$)/i;
289
+ const IMG_ALT_ATTR_RE = /\balt=["']([^"']*)["']/i;
290
+ const EMOJI_PICTOGRAPHIC_RE = /\p{Extended_Pictographic}/u;
291
+ function isTeamsEmojiSpriteImage(src, imgTag) {
292
+ const url = URL.parse(src);
293
+ const host = url?.hostname.toLowerCase() ?? "";
294
+ if (host !== TEAMS_EMOJI_CDN_HOST && !host.endsWith(`.${TEAMS_EMOJI_CDN_HOST}`)) return false;
295
+ return TEAMS_EMOJI_ASSET_PATH_RE.test(url?.pathname ?? "") || EMOJI_PICTOGRAPHIC_RE.test(IMG_ALT_ATTR_RE.exec(imgTag)?.[1] ?? "");
296
+ }
297
+ function replaceTeamsEmojiSpriteImagesWithAltText(html) {
298
+ const parts = [];
299
+ let cursor = 0;
300
+ htmlTagAttributeValues(html, "img", "src", (src, start, end) => {
301
+ const imgTag = html.slice(start, end);
302
+ if (isTeamsEmojiSpriteImage(src.trim(), imgTag)) {
303
+ parts.push(html.slice(cursor, start), IMG_ALT_ATTR_RE.exec(imgTag)?.[1] ?? "");
304
+ cursor = end;
305
+ }
306
+ });
307
+ return parts.join("") + html.slice(cursor);
308
+ }
269
309
  function resolveInlineImageSourceId(src) {
270
310
  const hostedContentId = GRAPH_HOSTED_CONTENT_SRC_RE.exec(src)?.[1];
271
311
  if (!hostedContentId) return src;
@@ -276,15 +316,8 @@ function resolveInlineImageSourceId(src) {
276
316
  }
277
317
  }
278
318
  const DEFAULT_MEDIA_HOST_ALLOWLIST = [
279
- "graph.microsoft.com",
280
- "graph.microsoft.us",
281
- "graph.microsoft.de",
282
- "graph.microsoft.cn",
283
- "sharepoint.com",
284
- "sharepoint.us",
285
- "sharepoint.de",
286
- "sharepoint.cn",
287
- "sharepoint-df.com",
319
+ ...GRAPH_HOSTS,
320
+ ...SHAREPOINT_HOSTS,
288
321
  "1drv.ms",
289
322
  "onedrive.com",
290
323
  "teams.microsoft.com",
@@ -306,10 +339,7 @@ const DEFAULT_MEDIA_AUTH_HOST_ALLOWLIST = [
306
339
  "botframework.com",
307
340
  "smba.trafficmanager.net",
308
341
  "botframework.azure.cn",
309
- "graph.microsoft.com",
310
- "graph.microsoft.us",
311
- "graph.microsoft.de",
312
- "graph.microsoft.cn"
342
+ ...GRAPH_HOSTS
313
343
  ];
314
344
  const GRAPH_ROOT = "https://graph.microsoft.com/v1.0";
315
345
  /**
@@ -321,11 +351,7 @@ const GRAPH_ROOT = "https://graph.microsoft.com/v1.0";
321
351
  * https://learn.microsoft.com/en-us/graph/api/shares-get for the encoding.
322
352
  */
323
353
  const GRAPH_SHARED_LINK_HOST_SUFFIXES = [
324
- ".sharepoint.com",
325
- ".sharepoint.us",
326
- ".sharepoint.de",
327
- ".sharepoint.cn",
328
- ".sharepoint-df.com",
354
+ ...SHAREPOINT_HOSTS.map((host) => `.${host}`),
329
355
  "1drv.ms",
330
356
  "onedrive.live.com",
331
357
  "onedrive.com"
@@ -403,7 +429,7 @@ function extractInlineImageReferences(attachments) {
403
429
  for (const att of attachments) {
404
430
  const html = extractHtmlFromAttachment(att);
405
431
  if (!html) continue;
406
- for (const value of htmlTagAttributeValues(html, "img", "src")) {
432
+ for (const value of htmlTagAttributeValues(replaceTeamsEmojiSpriteImagesWithAltText(html), "img", "src")) {
407
433
  const src = value.trim();
408
434
  if (src) {
409
435
  if (src.startsWith("data:")) out.push({
@@ -436,15 +462,6 @@ function safeHostForUrl(url) {
436
462
  const parsed = URL.parse(url);
437
463
  return parsed ? (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(parsed.hostname) : "invalid-url";
438
464
  }
439
- function isMockFetchFn(fetchFn) {
440
- const candidate = fetchFn;
441
- return Boolean(candidate.mock || Object.hasOwn(candidate, "_isMockFunction"));
442
- }
443
- function resolveGuardedFetchImpl(fetchFn) {
444
- if (!fetchFn) return;
445
- if (fetchFn === fetch || fetchFn === globalThis.fetch || isMockFetchFn(fetchFn)) return fetchFn;
446
- throw new Error("MSTeams attachment fetchFn must set fetchFnSupportsDispatcher to use guarded DNS pinning");
447
- }
448
465
  function resolveRetainedAuthorizationRedirectHostnameAllowlist(input) {
449
466
  if (!input) return;
450
467
  if (input.includes("*")) return ["*"];
@@ -466,21 +483,20 @@ function isRedirectStatus(status) {
466
483
  }
467
484
  /**
468
485
  * Fetch a URL with redirect: "manual", validating each redirect target
469
- * against the hostname allowlist and optional DNS-resolved IP (anti-SSRF).
486
+ * against the hostname allowlist and DNS-resolved IP (anti-SSRF).
470
487
  *
471
488
  * This prevents:
472
489
  * - Auto-following redirects to non-allowlisted hosts
473
- * - DNS rebinding attacks when a lookup function is provided
490
+ * - DNS rebinding attacks through the pinned DNS lookup
474
491
  */
475
492
  async function safeFetchWithPolicy(params) {
476
493
  const { allowHosts, authAllowHosts } = params.policy;
477
- const resolveFn = params.resolveFn ?? node_dns_promises.lookup;
478
494
  const currentHeaders = new Headers(params.requestInit?.headers);
479
495
  const currentUrl = params.url;
480
496
  if (!(0, openclaw_plugin_sdk_ssrf_policy.isHttpsUrlAllowedByHostnameSuffixAllowlist)(currentUrl, allowHosts)) throw new Error(`Initial download URL blocked: ${currentUrl}`);
481
497
  if (currentHeaders.has("authorization") && !(0, openclaw_plugin_sdk_ssrf_policy.isHttpsUrlAllowedByHostnameSuffixAllowlist)(currentUrl, authAllowHosts)) currentHeaders.delete("authorization");
482
498
  const lookupFn = async (hostname) => {
483
- const resolved = await resolveFn(hostname);
499
+ const resolved = await params.resolveFn(hostname);
484
500
  return [{
485
501
  ...resolved,
486
502
  family: resolved.address.includes(":") ? 6 : 4
@@ -488,7 +504,6 @@ async function safeFetchWithPolicy(params) {
488
504
  };
489
505
  const guarded = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
490
506
  url: currentUrl,
491
- fetchImpl: resolveGuardedFetchImpl(params.fetchFn),
492
507
  init: {
493
508
  ...params.requestInit,
494
509
  headers: currentHeaders
@@ -801,7 +816,7 @@ const EXPIRY_BUFFER_MS = 3e5;
801
816
  function parseMSTeamsTokenResponse(data, failureLabel) {
802
817
  if (!(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(data)) throw new Error(`MSTeams ${failureLabel} failed: invalid token response fields`);
803
818
  const expiresAt = (0, openclaw_plugin_sdk_number_runtime.resolveExpiresAtMsFromDurationSeconds)(data.expires_in, { bufferMs: EXPIRY_BUFFER_MS });
804
- 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`);
819
+ 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`);
805
820
  return {
806
821
  access_token: data.access_token,
807
822
  refresh_token: data.refresh_token,
@@ -810,7 +825,11 @@ function parseMSTeamsTokenResponse(data, failureLabel) {
810
825
  };
811
826
  }
812
827
  async function fetchMSTeamsTokens(params) {
828
+ let dispatched = false;
813
829
  const { response, release } = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
830
+ beforeRequest: () => {
831
+ dispatched = true;
832
+ },
814
833
  url: params.tokenUrl,
815
834
  init: {
816
835
  method: "POST",
@@ -822,10 +841,56 @@ async function fetchMSTeamsTokens(params) {
822
841
  signal: AbortSignal.timeout(MSTEAMS_DEFAULT_TOKEN_FETCH_TIMEOUT_MS)
823
842
  },
824
843
  auditContext: params.auditContext
844
+ }).catch((cause) => {
845
+ if (!params.refresh) throw cause;
846
+ throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("MSTeams refresh transport failed", dispatched ? {
847
+ version: 1,
848
+ phase: "token-response",
849
+ outcome: "unchanged",
850
+ recovery: {
851
+ kind: "later",
852
+ evidence: "documented-reusable-grant"
853
+ }
854
+ } : {
855
+ version: 1,
856
+ phase: "before-dispatch",
857
+ outcome: "not-attempted",
858
+ recovery: {
859
+ kind: "later",
860
+ evidence: "dispatch-not-started"
861
+ }
862
+ }, { cause });
825
863
  });
826
864
  try {
827
- if (!response.ok) throw await (0, openclaw_plugin_sdk_provider_http.createProviderHttpError)(response, `MSTeams ${params.failureLabel} failed`);
828
- return parseMSTeamsTokenResponse(await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(response, `MSTeams ${params.failureLabel} failed`), params.failureLabel);
865
+ if (!response.ok && !params.refresh) throw await (0, openclaw_plugin_sdk_provider_http.createProviderHttpError)(response, `MSTeams ${params.failureLabel} failed`);
866
+ let data;
867
+ try {
868
+ data = await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(response, `MSTeams ${params.failureLabel} failed`);
869
+ } catch (cause) {
870
+ if (!params.refresh) throw cause;
871
+ if (!response.ok) throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshResponseError)("MSTeams token refresh", response.status, void 0, "documented-reusable-grant");
872
+ throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("MSTeams refresh response could not be read", {
873
+ version: 1,
874
+ phase: "token-response",
875
+ outcome: "unchanged",
876
+ recovery: {
877
+ kind: "later",
878
+ evidence: "documented-reusable-grant"
879
+ }
880
+ }, { cause });
881
+ }
882
+ 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");
883
+ try {
884
+ return parseMSTeamsTokenResponse(data, params.failureLabel);
885
+ } catch (cause) {
886
+ if (!params.refresh) throw cause;
887
+ throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("MSTeams refresh response fields are invalid", {
888
+ version: 1,
889
+ phase: "after-token-response",
890
+ outcome: "unknown",
891
+ status: response.status
892
+ }, { cause });
893
+ }
829
894
  } finally {
830
895
  await release();
831
896
  }
@@ -843,7 +908,8 @@ async function requestMSTeamsDelegatedTokens(params) {
843
908
  tokenUrl: buildMSTeamsTokenEndpoint(params.tenantId),
844
909
  body,
845
910
  auditContext: params.auditContext,
846
- failureLabel: params.failureLabel
911
+ failureLabel: params.failureLabel,
912
+ refresh: params.grantType === "refresh_token"
847
913
  });
848
914
  return {
849
915
  accessToken: data.access_token,
@@ -858,7 +924,6 @@ async function exchangeMSTeamsCodeForTokens(params) {
858
924
  clientId: params.clientId,
859
925
  clientSecret: params.clientSecret,
860
926
  grantType: "authorization_code",
861
- scopes: params.scopes,
862
927
  values: {
863
928
  code: params.code,
864
929
  redirect_uri: MSTEAMS_OAUTH_REDIRECT_URI,
@@ -887,22 +952,67 @@ async function refreshMSTeamsDelegatedTokens(params) {
887
952
  }
888
953
  //#endregion
889
954
  //#region extensions/msteams/src/token.ts
955
+ const refreshes = /* @__PURE__ */ new WeakMap();
890
956
  async function resolveDelegatedAccessToken(params) {
891
- const tokens = await require_delegated_state.loadMSTeamsDelegatedTokens(params.accountId);
892
- if (!tokens) return;
957
+ const runtime = require_runtime.getMSTeamsRuntime();
958
+ const callerKey = (0, node_crypto.createHash)("sha256").update(JSON.stringify([
959
+ runtime.state.resolveStateDir(),
960
+ require_delegated_state.resolveMSTeamsAccountStateNamespace("delegated-token", params.accountId),
961
+ params.tenantId,
962
+ params.clientId,
963
+ params.clientSecret
964
+ ])).digest("hex");
965
+ const state = await require_delegated_state.loadMSTeamsDelegatedTokenState(params.accountId);
966
+ const tokens = require_delegated_state.normalizeMSTeamsDelegatedTokens(state);
967
+ const active = refreshes.get(runtime) ?? /* @__PURE__ */ new Map();
968
+ refreshes.set(runtime, active);
969
+ if (state && "refreshClaim" in state && state.callerKey === callerKey) {
970
+ const pending = active.get(state.requestKey);
971
+ if (pending) return await pending;
972
+ }
973
+ if (!tokens) return state && "refreshClaim" in state && state.callerKey === callerKey ? await active.get(state.requestKey) : void 0;
893
974
  if ((0, openclaw_plugin_sdk_number_runtime.isFutureDateTimestampMs)(tokens.expiresAt)) return tokens.accessToken;
975
+ const key = (0, node_crypto.createHash)("sha256").update(JSON.stringify([callerKey, tokens])).digest("hex");
976
+ const pending = active.get(key);
977
+ if (pending) return await pending;
978
+ const task = (async () => {
979
+ try {
980
+ const claim = await require_delegated_state.claimMSTeamsDelegatedTokenRefresh(tokens, key, callerKey, params.accountId);
981
+ if (!claim) return;
982
+ let refreshed;
983
+ try {
984
+ if (require_runtime.getMSTeamsRuntime() !== runtime) throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("Microsoft Teams token owner changed before refresh dispatch", {
985
+ version: 1,
986
+ phase: "before-dispatch",
987
+ outcome: "not-attempted",
988
+ recovery: {
989
+ kind: "later",
990
+ evidence: "dispatch-not-started"
991
+ }
992
+ });
993
+ refreshed = await refreshMSTeamsDelegatedTokens({
994
+ ...params,
995
+ refreshToken: tokens.refreshToken,
996
+ scopes: tokens.scopes
997
+ });
998
+ } catch (error) {
999
+ if ((0, openclaw_plugin_sdk_provider_oauth_runtime.isRecoverableOAuthRefreshFailure)(error)) await claim.settle(tokens);
1000
+ else await claim.reject();
1001
+ return;
1002
+ }
1003
+ return await claim.settle({
1004
+ ...tokens,
1005
+ ...refreshed
1006
+ }) ? refreshed.accessToken : void 0;
1007
+ } catch {
1008
+ return;
1009
+ }
1010
+ })();
1011
+ active.set(key, task);
894
1012
  try {
895
- const refreshed = await refreshMSTeamsDelegatedTokens({
896
- tenantId: params.tenantId,
897
- clientId: params.clientId,
898
- clientSecret: params.clientSecret,
899
- refreshToken: tokens.refreshToken,
900
- scopes: tokens.scopes
901
- });
902
- await require_delegated_state.saveMSTeamsDelegatedTokens(refreshed, params.accountId);
903
- return refreshed.accessToken;
904
- } catch {
905
- return;
1013
+ return await task;
1014
+ } finally {
1015
+ if (active.get(key) === task) active.delete(key);
906
1016
  }
907
1017
  }
908
1018
  //#endregion
@@ -921,9 +1031,6 @@ function captureGraphRequestCurrentness(assertReadAuthority) {
921
1031
  assertCurrent();
922
1032
  };
923
1033
  }
924
- function normalizeQuery(value) {
925
- return value?.trim() ?? "";
926
- }
927
1034
  function escapeOData(value) {
928
1035
  return value.replace(/'/g, "''");
929
1036
  }
@@ -1064,9 +1171,6 @@ async function resolveGraphToken(cfg, options) {
1064
1171
  if (!accessToken) throw new Error("MS Teams graph token unavailable");
1065
1172
  return accessToken;
1066
1173
  }
1067
- async function listTeamsByName(token, query) {
1068
- return (await listTeamsByNameWithPageInfo(token, query)).items;
1069
- }
1070
1174
  async function listTeamsByNameWithPageInfo(token, query) {
1071
1175
  const filter = `resourceProvisioningOptions/Any(x:x eq 'Team') and startsWith(displayName,'${escapeOData(query)}')`;
1072
1176
  return await fetchAllGraphPages({
@@ -1082,9 +1186,6 @@ async function deleteGraphRequest(params) {
1082
1186
  errorPrefix: "Graph DELETE"
1083
1187
  })).body?.cancel().catch(() => void 0);
1084
1188
  }
1085
- async function listChannelsForTeam(token, teamId) {
1086
- return (await listChannelsForTeamWithPageInfo(token, teamId)).items;
1087
- }
1088
1189
  async function listChannelsForTeamWithPageInfo(token, teamId) {
1089
1190
  return await fetchAllGraphPages({
1090
1191
  token,
@@ -1105,7 +1206,7 @@ async function searchGraphUsers(params) {
1105
1206
  path
1106
1207
  })).value ?? [];
1107
1208
  }
1108
- const top = typeof params.top === "number" && params.top > 0 ? params.top : 10;
1209
+ const top = params.top !== void 0 && params.top > 0 ? params.top : 10;
1109
1210
  const path = `/users?$search=${encodeURIComponent(`"displayName:${query}"`)}&$select=id,displayName,mail,userPrincipalName&$top=${top}`;
1110
1211
  return (await fetchGraphJson({
1111
1212
  token: params.token,
@@ -1203,6 +1304,22 @@ function parseMSTeamsActivityTimestamp(value) {
1203
1304
  function stripMSTeamsMentionTags(text) {
1204
1305
  return text.replace(/<at[^>]*>.*?<\/at>/gi, "").trim();
1205
1306
  }
1307
+ function normalizeMSTeamsMentionTags(text, activity, options = {}) {
1308
+ const normalizeTag = (tag) => tag.trim().replace(/<\/?at\b/gi, (delimiter) => delimiter.toLowerCase());
1309
+ const botId = activity.recipient?.id;
1310
+ const botMentions = /* @__PURE__ */ new Map();
1311
+ for (const entity of activity.entities ?? []) {
1312
+ if (entity.type !== "mention" || typeof entity.text !== "string") continue;
1313
+ const tag = normalizeTag(entity.text);
1314
+ const isBot = Boolean(botId && entity.mentioned?.id === botId);
1315
+ botMentions.set(tag, isBot && botMentions.get(tag) !== false);
1316
+ }
1317
+ return text.replace(/<at\b[^>]*>([\s\S]*?)<\/at\s*>/gi, (tag, label) => {
1318
+ if (botMentions.get(normalizeTag(tag))) return options.preserveHtml ? " " : "";
1319
+ const displayName = htmlToPlainText(label);
1320
+ return displayName ? `@${options.preserveHtml ? label : displayName}` : "";
1321
+ }).trim();
1322
+ }
1206
1323
  function wasMSTeamsBotMentioned(activity) {
1207
1324
  const botId = activity.recipient?.id;
1208
1325
  if (!botId) return false;
@@ -1217,27 +1334,22 @@ function keepConfiguredMSTeamsAllowlistActive(configured, projected) {
1217
1334
  if (!Array.isArray(configured) || configured.every((entry) => !entry?.trim())) return projected;
1218
1335
  return projected && projected.length > 0 ? projected : [MSTEAMS_UNMATCHABLE_THREAD_ID];
1219
1336
  }
1220
- function uniqueItemsById(items) {
1337
+ function findExactMatches(items, query, fields = ["displayName"]) {
1338
+ const normalized = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(query);
1221
1339
  const byId = /* @__PURE__ */ new Map();
1222
1340
  for (const item of items) {
1341
+ if (!fields.some((field) => (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(item[field]) === normalized)) continue;
1223
1342
  const id = item.id?.trim();
1224
1343
  if (id && !byId.has(id)) byId.set(id, item);
1225
1344
  }
1226
1345
  return [...byId.values()];
1227
1346
  }
1228
- function findExactMatches(items, query, fields = ["displayName"]) {
1229
- const normalized = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(query);
1230
- return uniqueItemsById(items.filter((item) => fields.some((field) => (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(item[field]) === normalized)));
1231
- }
1232
- function isStableMSTeamsUserId(raw) {
1233
- return /^[0-9a-fA-F-]{16,}$/.test(normalizeMSTeamsUserInput(raw));
1234
- }
1235
1347
  function normalizeStaticMSTeamsAllowEntry(raw) {
1236
1348
  const trimmed = raw.trim();
1237
1349
  if (!trimmed) return;
1238
1350
  if (trimmed === "*" || /^accessGroup:/i.test(trimmed)) return trimmed;
1239
1351
  const id = normalizeMSTeamsUserInput(trimmed);
1240
- return isStableMSTeamsUserId(id) ? id : void 0;
1352
+ return /^[0-9a-fA-F-]{16,}$/.test(normalizeMSTeamsUserInput(id)) ? id : void 0;
1241
1353
  }
1242
1354
  function projectStableMSTeamsAllowlist(entries, allowConversations) {
1243
1355
  if (!entries) return;
@@ -1659,12 +1771,18 @@ async function resolveMSTeamsUserAllowlist(params) {
1659
1771
  input,
1660
1772
  resolved: true,
1661
1773
  id: match.id,
1662
- name: match.displayName ?? void 0
1774
+ name: match.displayName
1663
1775
  };
1664
1776
  }
1665
1777
  });
1666
1778
  }
1667
1779
  //#endregion
1780
+ Object.defineProperty(exports, "GRAPH_HOSTS", {
1781
+ enumerable: true,
1782
+ get: function() {
1783
+ return GRAPH_HOSTS;
1784
+ }
1785
+ });
1668
1786
  Object.defineProperty(exports, "GRAPH_ROOT", {
1669
1787
  enumerable: true,
1670
1788
  get: function() {
@@ -1689,6 +1807,12 @@ Object.defineProperty(exports, "MSTEAMS_REQUEST_TIMEOUT_MS", {
1689
1807
  return MSTEAMS_REQUEST_TIMEOUT_MS;
1690
1808
  }
1691
1809
  });
1810
+ Object.defineProperty(exports, "SHAREPOINT_HOSTS", {
1811
+ enumerable: true,
1812
+ get: function() {
1813
+ return SHAREPOINT_HOSTS;
1814
+ }
1815
+ });
1692
1816
  Object.defineProperty(exports, "applyAuthorizationHeaderForUrl", {
1693
1817
  enumerable: true,
1694
1818
  get: function() {
@@ -1857,12 +1981,6 @@ Object.defineProperty(exports, "keepConfiguredMSTeamsAllowlistActive", {
1857
1981
  return keepConfiguredMSTeamsAllowlistActive;
1858
1982
  }
1859
1983
  });
1860
- Object.defineProperty(exports, "listChannelsForTeam", {
1861
- enumerable: true,
1862
- get: function() {
1863
- return listChannelsForTeam;
1864
- }
1865
- });
1866
1984
  Object.defineProperty(exports, "listChannelsForTeamWithPageInfo", {
1867
1985
  enumerable: true,
1868
1986
  get: function() {
@@ -1875,10 +1993,10 @@ Object.defineProperty(exports, "listMSTeamsAccountIds", {
1875
1993
  return listMSTeamsAccountIds;
1876
1994
  }
1877
1995
  });
1878
- Object.defineProperty(exports, "listTeamsByName", {
1996
+ Object.defineProperty(exports, "listTeamsByNameWithPageInfo", {
1879
1997
  enumerable: true,
1880
1998
  get: function() {
1881
- return listTeamsByName;
1999
+ return listTeamsByNameWithPageInfo;
1882
2000
  }
1883
2001
  });
1884
2002
  Object.defineProperty(exports, "loadMSTeamsSdkWithAuth", {
@@ -1917,22 +2035,22 @@ Object.defineProperty(exports, "normalizeMSTeamsConversationId", {
1917
2035
  return normalizeMSTeamsConversationId;
1918
2036
  }
1919
2037
  });
1920
- Object.defineProperty(exports, "normalizeMSTeamsMessagingTarget", {
2038
+ Object.defineProperty(exports, "normalizeMSTeamsMentionTags", {
1921
2039
  enumerable: true,
1922
2040
  get: function() {
1923
- return normalizeMSTeamsMessagingTarget;
2041
+ return normalizeMSTeamsMentionTags;
1924
2042
  }
1925
2043
  });
1926
- Object.defineProperty(exports, "normalizeMSTeamsUserInput", {
2044
+ Object.defineProperty(exports, "normalizeMSTeamsMessagingTarget", {
1927
2045
  enumerable: true,
1928
2046
  get: function() {
1929
- return normalizeMSTeamsUserInput;
2047
+ return normalizeMSTeamsMessagingTarget;
1930
2048
  }
1931
2049
  });
1932
- Object.defineProperty(exports, "normalizeQuery", {
2050
+ Object.defineProperty(exports, "normalizeMSTeamsUserInput", {
1933
2051
  enumerable: true,
1934
2052
  get: function() {
1935
- return normalizeQuery;
2053
+ return normalizeMSTeamsUserInput;
1936
2054
  }
1937
2055
  });
1938
2056
  Object.defineProperty(exports, "parseMSTeamsActivityTimestamp", {
@@ -1977,6 +2095,12 @@ Object.defineProperty(exports, "projectStableMSTeamsUserAllowlist", {
1977
2095
  return projectStableMSTeamsUserAllowlist;
1978
2096
  }
1979
2097
  });
2098
+ Object.defineProperty(exports, "replaceTeamsEmojiSpriteImagesWithAltText", {
2099
+ enumerable: true,
2100
+ get: function() {
2101
+ return replaceTeamsEmojiSpriteImagesWithAltText;
2102
+ }
2103
+ });
1980
2104
  Object.defineProperty(exports, "resolveAttachmentFetchPolicy", {
1981
2105
  enumerable: true,
1982
2106
  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
  //#region 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-wAyY5UHv.cjs");
1
+ const require_secret_contract_api = require("./secret-contract-api-D554HIrH.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;