@openclaw/msteams 2026.7.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.
Files changed (35) hide show
  1. package/dist/api.cjs +8 -0
  2. package/dist/{channel-Cf5LJ4aO.js → channel-BKc8zroK.cjs} +648 -240
  3. package/dist/channel-config-api.cjs +3 -0
  4. package/dist/channel-plugin-api.cjs +3 -0
  5. package/dist/channel.runtime-hd1Zsoo2.cjs +1372 -0
  6. package/dist/{config-schema-BL4qQZiA.js → config-schema-BSNLJUta.cjs} +13 -3
  7. package/dist/{directory-contract-api.js → directory-contract-api.cjs} +8 -7
  8. package/dist/{doctor-contract-api.js → doctor-contract-api.cjs} +73 -57
  9. package/dist/index.cjs +21 -0
  10. package/dist/{probe-BnyZRZsD.js → messenger-BVcKl6dv.cjs} +436 -891
  11. package/dist/{oauth-BifWxWzq.js → oauth-yNoKtU_3.cjs} +21 -21
  12. package/dist/{polls-B_hs4aKm.js → polls-BhoI4VaN.cjs} +188 -38
  13. package/dist/{resolve-allowlist-Dnw4aNOu.js → resolve-allowlist-DXd097EP.cjs} +849 -140
  14. package/dist/rolldown-runtime-D6vf50IK.cjs +28 -0
  15. package/dist/runtime-api.cjs +207 -0
  16. package/dist/runtime-gZTAuFux.cjs +24 -0
  17. package/dist/secret-contract-api.cjs +31 -0
  18. package/dist/setup-entry.cjs +14 -0
  19. package/dist/setup-plugin-api.cjs +65 -0
  20. package/dist/{setup-surface-qW-ECHL-.js → setup-surface-D4f6x5cx.cjs} +127 -61
  21. package/dist/{src-DZFs5XtZ.js → src-20YasZEp.cjs} +686 -748
  22. package/dist/{sso-token-store-DrVbnCUF.js → sso-token-store-CktCz88k.cjs} +51 -10
  23. package/npm-shrinkwrap.json +3 -3
  24. package/openclaw.plugin.json +10 -31
  25. package/package.json +8 -7
  26. package/dist/api.js +0 -3
  27. package/dist/channel-config-api.js +0 -2
  28. package/dist/channel-plugin-api.js +0 -2
  29. package/dist/channel.runtime-Bwu6Tjhf.js +0 -664
  30. package/dist/index.js +0 -22
  31. package/dist/runtime-BS5AZrKK.js +0 -8
  32. package/dist/runtime-api.js +0 -20
  33. package/dist/secret-contract-api.js +0 -35
  34. package/dist/setup-entry.js +0 -15
  35. package/dist/setup-plugin-api.js +0 -64
@@ -1,24 +1,129 @@
1
- import { t as getMSTeamsRuntime } from "./runtime-BS5AZrKK.js";
2
- import { detectMime, extensionForMime, extractOriginalFilename, getFileExtension, loadOutboundMediaFromUrl, normalizeStringEntries as normalizeStringEntries$1, resolveChannelMediaMaxBytes } from "./runtime-api.js";
3
- import { B as normalizeBotFrameworkServiceUrl, C as resolveMSTeamsCredentials, F as loadMSTeamsSdkWithAuth, H as createMSTeamsHttpError, I as buildUserAgent, M as readAccessToken, P as createMSTeamsTokenProvider, R as describeBotFrameworkServiceUrlHost, S as loadDelegatedTokens, U as resolveMSTeamsSdkCloudOptions, W as validateMSTeamsProactiveServiceUrlBoundary, z as isAllowedBotFrameworkServiceUrl } from "./resolve-allowlist-Dnw4aNOu.js";
4
- import { m as resolveMSTeamsRouteConfig, p as resolveMSTeamsReplyPolicy } from "./channel-Cf5LJ4aO.js";
5
- import { a as formatUnknownError, i as formatMSTeamsSendErrorHint, o as isRevokedProxyError, r as classifyMSTeamsSendError } from "./setup-surface-qW-ECHL-.js";
6
- import { C as toPluginJsonValue, S as resolveMSTeamsSqliteStateEnv, o as buildMSTeamsPollCard, v as createMSTeamsConversationStoreState, w as withMSTeamsSqliteMutationLock } from "./polls-B_hs4aKm.js";
7
- import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-outbound";
8
- import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
9
- import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/string-coerce-runtime";
10
- import { resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
11
- import { convertMarkdownTables } from "openclaw/plugin-sdk/text-chunking";
12
- import { readProviderJsonResponse } from "openclaw/plugin-sdk/provider-http";
13
- import { lookup } from "node:dns/promises";
14
- import { isPrivateIpAddress } from "openclaw/plugin-sdk/ssrf-policy";
15
- import path from "node:path";
16
- import { isFutureDateTimestampMs } from "openclaw/plugin-sdk/number-runtime";
17
- import crypto, { createHash } from "node:crypto";
18
- import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
19
- import { SILENT_REPLY_TOKEN, isSilentReplyText } from "openclaw/plugin-sdk/reply-chunking";
20
- import { sleep } from "openclaw/plugin-sdk/text-utility-runtime";
21
- import { loadWebMedia } from "openclaw/plugin-sdk/web-media";
1
+ const require_rolldown_runtime = require("./rolldown-runtime-D6vf50IK.cjs");
2
+ const require_runtime = require("./runtime-gZTAuFux.cjs");
3
+ require("./runtime-api.cjs");
4
+ const require_resolve_allowlist = require("./resolve-allowlist-DXd097EP.cjs");
5
+ const require_setup_surface = require("./setup-surface-D4f6x5cx.cjs");
6
+ const require_polls = require("./polls-BhoI4VaN.cjs");
7
+ let openclaw_plugin_sdk_lazy_runtime = require("openclaw/plugin-sdk/lazy-runtime");
8
+ let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
9
+ let openclaw_plugin_sdk_reply_payload = require("openclaw/plugin-sdk/reply-payload");
10
+ let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
11
+ let node_dns_promises = require("node:dns/promises");
12
+ let openclaw_plugin_sdk_ssrf_policy = require("openclaw/plugin-sdk/ssrf-policy");
13
+ let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text-utility-runtime");
14
+ let node_path = require("node:path");
15
+ node_path = require_rolldown_runtime.__toESM(node_path, 1);
16
+ let openclaw_plugin_sdk_html_entity_runtime = require("openclaw/plugin-sdk/html-entity-runtime");
17
+ let node_crypto = require("node:crypto");
18
+ node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
19
+ let openclaw_plugin_sdk_reply_chunking = require("openclaw/plugin-sdk/reply-chunking");
20
+ let openclaw_plugin_sdk_web_media = require("openclaw/plugin-sdk/web-media");
21
+ let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runtime");
22
+ //#region extensions/msteams/src/graph-thread.ts
23
+ /**
24
+ * Strip HTML tags from Teams message content, preserving @mention display names.
25
+ * Teams wraps mentions in <at>Name</at> tags.
26
+ */
27
+ function stripHtmlFromTeamsMessage(html) {
28
+ let text = html.replace(/<at[^>]*>(.*?)<\/at>/gi, "@$1");
29
+ text = text.replace(/<[^>]*>/g, " ");
30
+ text = (0, openclaw_plugin_sdk_html_entity_runtime.decodeHtmlEntities)(text).replaceAll("\xA0", " ");
31
+ return text.replace(/\s+/g, " ").trim();
32
+ }
33
+ /**
34
+ * Fetch a single channel message (the parent/root of a thread).
35
+ * Returns undefined on error so callers can degrade gracefully.
36
+ */
37
+ async function fetchChannelMessage(token, groupId, channelId, messageId, deadline) {
38
+ const path = `/teams/${encodeURIComponent(groupId)}/channels/${encodeURIComponent(channelId)}/messages/${encodeURIComponent(messageId)}?$select=id,from,body,createdDateTime`;
39
+ try {
40
+ return await require_resolve_allowlist.fetchGraphJson({
41
+ token,
42
+ path,
43
+ ...deadline ? { deadline } : {}
44
+ });
45
+ } catch {
46
+ return;
47
+ }
48
+ }
49
+ /**
50
+ * Fetch a single chat message's full text via Graph and return plain text.
51
+ *
52
+ * Used to recover the complete quoted message for Teams quote replies: the
53
+ * inbound blockquote only carries a Teams-truncated `preview` snippet. The
54
+ * app-only `GET /chats/{chatId}/messages/{messageId}` endpoint IS permitted
55
+ * with the `Chat.Read.All` application permission.
56
+ *
57
+ * Returns undefined on any failure so callers degrade to the truncated preview.
58
+ */
59
+ async function fetchChatMessageText(token, chatId, messageId, deadline) {
60
+ const path = `/chats/${encodeURIComponent(chatId)}/messages/${encodeURIComponent(messageId)}`;
61
+ try {
62
+ const msg = await require_resolve_allowlist.fetchGraphJson({
63
+ token,
64
+ path,
65
+ ...deadline ? { deadline } : {}
66
+ });
67
+ const raw = msg.body?.content ?? "";
68
+ return (msg.body?.contentType === "html" ? stripHtmlFromTeamsMessage(raw) : raw.trim()) || void 0;
69
+ } catch {
70
+ return;
71
+ }
72
+ }
73
+ /**
74
+ * Fetch thread replies for a channel message, ordered chronologically.
75
+ *
76
+ * **Limitation:** The Graph API replies endpoint (`/messages/{id}/replies`) does not
77
+ * support `$orderby`, so results are always returned in ascending (oldest-first) order.
78
+ * Combined with the `$top` cap of 50, this means only the **oldest 50 replies** are
79
+ * returned for long threads — newer replies are silently omitted. There is currently no
80
+ * Graph API workaround for this; pagination via `@odata.nextLink` can retrieve more
81
+ * replies but still in ascending order only.
82
+ */
83
+ async function fetchThreadReplies(token, groupId, channelId, messageId, limit = 50, deadline) {
84
+ return (await require_resolve_allowlist.fetchGraphJson({
85
+ token,
86
+ path: `/teams/${encodeURIComponent(groupId)}/channels/${encodeURIComponent(channelId)}/messages/${encodeURIComponent(messageId)}/replies?$top=${Math.min(Math.max(limit, 1), 50)}&$select=id,from,body,createdDateTime`,
87
+ ...deadline ? { deadline } : {}
88
+ })).value ?? [];
89
+ }
90
+ /**
91
+ * Format thread messages into a context string for the agent.
92
+ * Skips the current message (by id) and blank messages.
93
+ */
94
+ function formatThreadContext(messages, currentMessageId) {
95
+ const lines = [];
96
+ for (const msg of messages) {
97
+ if (msg.id && msg.id === currentMessageId) continue;
98
+ const sender = msg.from?.user?.displayName ?? msg.from?.application?.displayName ?? "unknown";
99
+ const contentType = msg.body?.contentType ?? "text";
100
+ const rawContent = msg.body?.content ?? "";
101
+ const content = contentType === "html" ? stripHtmlFromTeamsMessage(rawContent) : rawContent.trim();
102
+ if (!content) continue;
103
+ lines.push(`${sender}: ${content}`);
104
+ }
105
+ return lines.join("\n");
106
+ }
107
+ //#endregion
108
+ //#region extensions/msteams/src/reaction-types.ts
109
+ const TEAMS_REACTION_EMOJI = {
110
+ like: "👍",
111
+ heart: "❤️",
112
+ laugh: "😆",
113
+ surprised: "😮",
114
+ sad: "😢",
115
+ angry: "😡"
116
+ };
117
+ const TEAMS_REACTION_TYPES = Object.keys(TEAMS_REACTION_EMOJI);
118
+ function getMSTeamsReactionEmoji(raw) {
119
+ return TEAMS_REACTION_EMOJI[raw.trim().toLowerCase()];
120
+ }
121
+ function resolveMSTeamsReactionEmoji(raw) {
122
+ const normalized = raw.trim();
123
+ if (!normalized) throw new Error(`Reaction type is required. Common types: ${TEAMS_REACTION_TYPES.join(", ")}`);
124
+ return getMSTeamsReactionEmoji(normalized) ?? normalized;
125
+ }
126
+ //#endregion
22
127
  //#region extensions/msteams/src/file-consent.ts
23
128
  /**
24
129
  * FileConsentCard utilities for MS Teams large file uploads (>4MB) in personal chats.
@@ -52,7 +157,7 @@ const CONSENT_UPLOAD_HOST_ALLOWLIST = [
52
157
  * Returns true if the given IPv4 or IPv6 address is private, internal, or
53
158
  * special-use and must never be reached via consent uploads.
54
159
  */
55
- const isPrivateOrReservedIP = isPrivateIpAddress;
160
+ const isPrivateOrReservedIP = openclaw_plugin_sdk_ssrf_policy.isPrivateIpAddress;
56
161
  /**
57
162
  * Validate that a consent upload URL is safe to PUT to.
58
163
  * Checks:
@@ -70,9 +175,9 @@ async function validateConsentUploadUrl(url, opts) {
70
175
  throw new Error("Consent upload URL is not a valid URL");
71
176
  }
72
177
  if (parsed.protocol !== "https:") throw new Error(`Consent upload URL must use HTTPS, got ${parsed.protocol}`);
73
- const hostname = normalizeLowercaseStringOrEmpty(parsed.hostname);
178
+ const hostname = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(parsed.hostname);
74
179
  if (!(opts?.allowlist ?? CONSENT_UPLOAD_HOST_ALLOWLIST).some((entry) => hostname === entry || hostname.endsWith(`.${entry}`))) throw new Error(`Consent upload URL hostname "${hostname}" is not in the allowed domains`);
75
- const resolveFn = opts?.resolveFn ?? ((name) => lookup(name, { all: true }));
180
+ const resolveFn = opts?.resolveFn ?? ((name) => (0, node_dns_promises.lookup)(name, { all: true }));
76
181
  let resolved;
77
182
  try {
78
183
  const result = await resolveFn(hostname);
@@ -141,15 +246,16 @@ function parseFileConsentInvoke(activity) {
141
246
  */
142
247
  async function uploadToConsentUrl(params) {
143
248
  await validateConsentUploadUrl(params.url, params.validationOpts);
144
- const res = await (params.fetchFn ?? fetch)(params.url, {
249
+ const fetchFn = params.fetchFn ?? fetch;
250
+ const res = await (0, openclaw_plugin_sdk_text_utility_runtime.fetchWithTimeout)(params.url, {
145
251
  method: "PUT",
146
252
  headers: {
147
- "User-Agent": buildUserAgent(),
253
+ "User-Agent": require_resolve_allowlist.buildUserAgent(),
148
254
  "Content-Type": params.contentType ?? "application/octet-stream",
149
255
  "Content-Range": `bytes 0-${params.buffer.length - 1}/${params.buffer.length}`
150
256
  },
151
257
  body: new Uint8Array(params.buffer)
152
- });
258
+ }, params.timeoutMs ?? require_resolve_allowlist.resolveMSTeamsSharePointUploadTimeoutMs(params.buffer.length), fetchFn);
153
259
  if (!res.ok) throw new Error(`File upload to consent URL failed: ${res.status} ${res.statusText}`);
154
260
  }
155
261
  //#endregion
@@ -166,21 +272,21 @@ const PENDING_UPLOAD_META_NAMESPACE = "pending-uploads";
166
272
  const PENDING_UPLOAD_CHUNKS_NAMESPACE = "pending-upload-chunks";
167
273
  const PENDING_UPLOAD_LOCK_FILENAME = "msteams-pending-uploads.sqlite.lock";
168
274
  function createMetaStore(options) {
169
- return getMSTeamsRuntime().state.openKeyedStore({
275
+ return require_runtime.getMSTeamsRuntime().state.openKeyedStore({
170
276
  namespace: PENDING_UPLOAD_META_NAMESPACE,
171
277
  maxEntries: PENDING_UPLOAD_META_MAX_ENTRIES,
172
- env: resolveMSTeamsSqliteStateEnv(options)
278
+ env: require_polls.resolveMSTeamsSqliteStateEnv(options)
173
279
  });
174
280
  }
175
281
  function createChunkStore(options) {
176
- return getMSTeamsRuntime().state.openKeyedStore({
282
+ return require_runtime.getMSTeamsRuntime().state.openKeyedStore({
177
283
  namespace: PENDING_UPLOAD_CHUNKS_NAMESPACE,
178
284
  maxEntries: MAX_PENDING_UPLOAD_CHUNK_ROWS,
179
- env: resolveMSTeamsSqliteStateEnv(options)
285
+ env: require_polls.resolveMSTeamsSqliteStateEnv(options)
180
286
  });
181
287
  }
182
288
  function buildUploadKey(id) {
183
- return `upload:${createHash("sha256").update(id).digest("hex")}`;
289
+ return `upload:${(0, node_crypto.createHash)("sha256").update(id).digest("hex")}`;
184
290
  }
185
291
  function buildMetaKey(id) {
186
292
  return `${buildUploadKey(id)}:meta`;
@@ -215,13 +321,13 @@ async function registerUploadRows(record, metaStore, chunkStore, ttlMs, overwrit
215
321
  await pruneUploadStore(metaStore, chunkStore, ttlMs, chunkCount);
216
322
  for (let index = 0; index < chunkCount; index += 1) {
217
323
  const chunk = buffer.subarray(index * RAW_CHUNK_BYTES, (index + 1) * RAW_CHUNK_BYTES);
218
- await chunkStore.register(buildChunkKey(record.id, index), toPluginJsonValue({
324
+ await chunkStore.register(buildChunkKey(record.id, index), require_polls.toPluginJsonValue({
219
325
  id: record.id,
220
326
  index,
221
327
  dataBase64: chunk.toString("base64")
222
328
  }));
223
329
  }
224
- await metaStore.register(buildMetaKey(record.id), toPluginJsonValue({
330
+ await metaStore.register(buildMetaKey(record.id), require_polls.toPluginJsonValue({
225
331
  id: record.id,
226
332
  filename: record.filename,
227
333
  contentType: record.contentType,
@@ -233,7 +339,7 @@ async function registerUploadRows(record, metaStore, chunkStore, ttlMs, overwrit
233
339
  }));
234
340
  }
235
341
  async function withPendingUploadLock(options, run) {
236
- return await withMSTeamsSqliteMutationLock(options, PENDING_UPLOAD_LOCK_FILENAME, run);
342
+ return await require_polls.withMSTeamsSqliteMutationLock(options, PENDING_UPLOAD_LOCK_FILENAME, run);
237
343
  }
238
344
  async function readUploadRows(id, metaStore, chunkStore) {
239
345
  const meta = await metaStore.lookup(buildMetaKey(id));
@@ -326,7 +432,7 @@ async function setPendingUploadActivityIdFs(id, activityId, options) {
326
432
  await withPendingUploadLock(options, async () => {
327
433
  const record = await metaStore.lookup(buildMetaKey(id));
328
434
  if (!record || Date.now() - record.createdAt > ttlMs) return;
329
- await metaStore.register(buildMetaKey(id), toPluginJsonValue({
435
+ await metaStore.register(buildMetaKey(id), require_polls.toPluginJsonValue({
330
436
  ...record,
331
437
  consentCardActivityId: activityId
332
438
  }));
@@ -351,7 +457,7 @@ const PENDING_UPLOAD_TTL_MS = 300 * 1e3;
351
457
  * Returns the upload ID to include in the FileConsentCard context.
352
458
  */
353
459
  function storePendingUpload(upload) {
354
- const id = crypto.randomUUID();
460
+ const id = node_crypto.default.randomUUID();
355
461
  const entry = {
356
462
  ...upload,
357
463
  id,
@@ -485,7 +591,7 @@ async function prepareFileConsentActivityFs(params) {
485
591
  * True for: personal chat AND (large file OR non-image)
486
592
  */
487
593
  function requiresFileConsent(params) {
488
- const isPersonal = normalizeOptionalLowercaseString(params.conversationType) === "personal";
594
+ const isPersonal = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(params.conversationType) === "personal";
489
595
  const isImage = params.contentType?.startsWith("image/") ?? false;
490
596
  const isLargeFile = params.bufferSize >= params.thresholdBytes;
491
597
  return isPersonal && (isLargeFile || !isImage);
@@ -496,7 +602,7 @@ function buildTeamsFileInfoCard(file) {
496
602
  const rawETag = file.eTag;
497
603
  const uniqueId = rawETag.replace(/^["']|["']$/g, "").replace(/[{}]/g, "").split(",")[0] ?? rawETag;
498
604
  const lastDot = file.name.lastIndexOf(".");
499
- const fileType = lastDot >= 0 ? normalizeLowercaseStringOrEmpty(file.name.slice(lastDot + 1)) : "";
605
+ const fileType = lastDot >= 0 ? (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(file.name.slice(lastDot + 1)) : "";
500
606
  return {
501
607
  contentType: "application/vnd.microsoft.teams.card.file.info",
502
608
  contentUrl: file.webDavUrl,
@@ -510,11 +616,10 @@ function buildTeamsFileInfoCard(file) {
510
616
  //#endregion
511
617
  //#region extensions/msteams/src/graph-upload.ts
512
618
  /**
513
- * OneDrive/SharePoint upload utilities for MS Teams file sending.
619
+ * SharePoint upload utilities for MS Teams file sending.
514
620
  *
515
621
  * For group chats and channels, files are uploaded to SharePoint and shared via a link.
516
622
  * This module provides utilities for:
517
- * - Uploading files to OneDrive (personal scope - now deprecated for bot use)
518
623
  * - Uploading files to SharePoint (group/channel scope)
519
624
  * - Creating sharing links (organization-wide or per-user)
520
625
  * - Getting chat members for per-user sharing
@@ -522,80 +627,19 @@ function buildTeamsFileInfoCard(file) {
522
627
  const GRAPH_ROOT = "https://graph.microsoft.com/v1.0";
523
628
  const GRAPH_BETA = "https://graph.microsoft.com/beta";
524
629
  const GRAPH_SCOPE = "https://graph.microsoft.com";
525
- /**
526
- * Upload a file to the user's OneDrive root folder.
527
- * For larger files, this uses the simple upload endpoint (up to 4MB).
528
- */
529
- async function uploadToOneDrive(params) {
530
- const fetchFn = params.fetchFn ?? fetch;
531
- const token = await params.tokenProvider.getAccessToken(GRAPH_SCOPE);
532
- const uploadPath = `/OpenClawShared/${encodeURIComponent(params.filename)}`;
533
- const res = await fetchFn(`${GRAPH_ROOT}/me/drive/root:${uploadPath}:/content`, {
534
- method: "PUT",
535
- headers: {
536
- "User-Agent": buildUserAgent(),
537
- Authorization: `Bearer ${token}`,
538
- "Content-Type": params.contentType ?? "application/octet-stream"
539
- },
540
- body: new Uint8Array(params.buffer)
541
- });
542
- if (!res.ok) throw await createMSTeamsHttpError(res, "OneDrive upload failed");
543
- const data = await readProviderJsonResponse(res, "msteams.graph-upload.uploadOneDriveFile");
544
- if (!data.id || !data.webUrl || !data.name) throw new Error("OneDrive upload response missing required fields");
545
- return {
546
- id: data.id,
547
- webUrl: data.webUrl,
548
- name: data.name
549
- };
550
- }
551
- /**
552
- * Create a sharing link for a OneDrive file.
553
- * The link allows organization members to view the file.
554
- */
555
- async function createSharingLink(params) {
556
- const fetchFn = params.fetchFn ?? fetch;
557
- const token = await params.tokenProvider.getAccessToken(GRAPH_SCOPE);
558
- const res = await fetchFn(`${GRAPH_ROOT}/me/drive/items/${params.itemId}/createLink`, {
559
- method: "POST",
560
- headers: {
561
- "User-Agent": buildUserAgent(),
562
- Authorization: `Bearer ${token}`,
563
- "Content-Type": "application/json"
564
- },
565
- body: JSON.stringify({
566
- type: "view",
567
- scope: params.scope ?? "organization"
568
- })
569
- });
570
- if (!res.ok) throw await createMSTeamsHttpError(res, "Create sharing link failed");
571
- const data = await readProviderJsonResponse(res, "msteams.graph-upload.createOneDriveSharingLink");
572
- if (!data.link?.webUrl) throw new Error("Create sharing link response missing webUrl");
573
- return { webUrl: data.link.webUrl };
574
- }
575
- /**
576
- * Upload a file to OneDrive and create a sharing link.
577
- * Convenience function for the common case.
578
- */
579
- async function uploadAndShareOneDrive(params) {
580
- const uploaded = await uploadToOneDrive({
581
- buffer: params.buffer,
582
- filename: params.filename,
583
- contentType: params.contentType,
584
- tokenProvider: params.tokenProvider,
585
- fetchFn: params.fetchFn
630
+ function requireMSTeamsSharePointSiteId(siteId) {
631
+ const normalized = siteId?.trim();
632
+ if (!normalized) throw new Error("channels.msteams.sharePointSiteId is required to send files to group chats or channels");
633
+ return normalized;
634
+ }
635
+ const SHAREPOINT_REQUEST_TIMEOUT_LABEL = "MS Teams SharePoint request";
636
+ const SHAREPOINT_UPLOAD_TIMEOUT_LABEL = "MS Teams SharePoint upload";
637
+ const GRAPH_TOKEN_TIMEOUT_LABEL = "MS Teams Graph token acquisition";
638
+ async function getGraphAccessToken(tokenProvider) {
639
+ return await require_resolve_allowlist.withMSTeamsRequestDeadline({
640
+ label: GRAPH_TOKEN_TIMEOUT_LABEL,
641
+ work: async () => await tokenProvider.getAccessToken(GRAPH_SCOPE)
586
642
  });
587
- const shareLink = await createSharingLink({
588
- itemId: uploaded.id,
589
- tokenProvider: params.tokenProvider,
590
- scope: params.scope,
591
- fetchFn: params.fetchFn
592
- });
593
- return {
594
- itemId: uploaded.id,
595
- webUrl: uploaded.webUrl,
596
- shareUrl: shareLink.webUrl,
597
- name: uploaded.name
598
- };
599
643
  }
600
644
  /**
601
645
  * Upload a file to a SharePoint site.
@@ -605,19 +649,26 @@ async function uploadAndShareOneDrive(params) {
605
649
  */
606
650
  async function uploadToSharePoint(params) {
607
651
  const fetchFn = params.fetchFn ?? fetch;
608
- const token = await params.tokenProvider.getAccessToken(GRAPH_SCOPE);
609
652
  const uploadPath = `/OpenClawShared/${encodeURIComponent(params.filename)}`;
610
- const res = await fetchFn(`${GRAPH_ROOT}/sites/${params.siteId}/drive/root:${uploadPath}:/content`, {
611
- method: "PUT",
612
- headers: {
613
- "User-Agent": buildUserAgent(),
614
- Authorization: `Bearer ${token}`,
615
- "Content-Type": params.contentType ?? "application/octet-stream"
616
- },
617
- body: new Uint8Array(params.buffer)
653
+ const data = await require_resolve_allowlist.withMSTeamsAbortableRequestTimeout({
654
+ label: SHAREPOINT_UPLOAD_TIMEOUT_LABEL,
655
+ timeoutMs: require_resolve_allowlist.resolveMSTeamsSharePointUploadTimeoutMs(params.buffer.length),
656
+ work: async (signal) => {
657
+ const token = await getGraphAccessToken(params.tokenProvider);
658
+ const res = await fetchFn(`${GRAPH_ROOT}/sites/${params.siteId}/drive/root:${uploadPath}:/content`, {
659
+ method: "PUT",
660
+ headers: {
661
+ "User-Agent": require_resolve_allowlist.buildUserAgent(),
662
+ Authorization: `Bearer ${token}`,
663
+ "Content-Type": params.contentType ?? "application/octet-stream"
664
+ },
665
+ body: new Uint8Array(params.buffer),
666
+ signal
667
+ });
668
+ if (!res.ok) throw await require_resolve_allowlist.createMSTeamsHttpError(res, "SharePoint upload failed");
669
+ return await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.uploadSharePointFile");
670
+ }
618
671
  });
619
- if (!res.ok) throw await createMSTeamsHttpError(res, "SharePoint upload failed");
620
- const data = await readProviderJsonResponse(res, "msteams.graph-upload.uploadSharePointFile");
621
672
  if (!data.id || !data.webUrl || !data.name) throw new Error("SharePoint upload response missing required fields");
622
673
  return {
623
674
  id: data.id,
@@ -634,13 +685,21 @@ async function uploadToSharePoint(params) {
634
685
  */
635
686
  async function getDriveItemProperties(params) {
636
687
  const fetchFn = params.fetchFn ?? fetch;
637
- const token = await params.tokenProvider.getAccessToken(GRAPH_SCOPE);
638
- const res = await fetchFn(`${GRAPH_ROOT}/sites/${params.siteId}/drive/items/${params.itemId}?$select=eTag,webDavUrl,name`, { headers: {
639
- "User-Agent": buildUserAgent(),
640
- Authorization: `Bearer ${token}`
641
- } });
642
- if (!res.ok) throw await createMSTeamsHttpError(res, "Get driveItem properties failed");
643
- const data = await readProviderJsonResponse(res, "msteams.graph-upload.getDriveItemProperties");
688
+ const data = await require_resolve_allowlist.withMSTeamsAbortableRequestTimeout({
689
+ label: SHAREPOINT_REQUEST_TIMEOUT_LABEL,
690
+ work: async (signal) => {
691
+ const token = await getGraphAccessToken(params.tokenProvider);
692
+ const res = await fetchFn(`${GRAPH_ROOT}/sites/${params.siteId}/drive/items/${params.itemId}?$select=eTag,webDavUrl,name`, {
693
+ headers: {
694
+ "User-Agent": require_resolve_allowlist.buildUserAgent(),
695
+ Authorization: `Bearer ${token}`
696
+ },
697
+ signal
698
+ });
699
+ if (!res.ok) throw await require_resolve_allowlist.createMSTeamsHttpError(res, "Get driveItem properties failed");
700
+ return await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.getDriveItemProperties");
701
+ }
702
+ });
644
703
  if (!data.eTag || !data.webDavUrl || !data.name) throw new Error("DriveItem response missing required properties (eTag, webDavUrl, or name)");
645
704
  return {
646
705
  eTag: data.eTag,
@@ -649,49 +708,26 @@ async function getDriveItemProperties(params) {
649
708
  };
650
709
  }
651
710
  /**
652
- * Resolve the Graph API-native chat ID from a Bot Framework conversation ID.
653
- *
654
- * Bot Framework personal DM conversation IDs use formats like `a:1xxx@unq.gbl.spaces`
655
- * or `8:orgid:xxx` that the Graph API does not accept. Graph API requires the
656
- * `19:xxx@thread.tacv2` or `19:xxx@unq.gbl.spaces` format.
657
- *
658
- * This function looks up the matching Graph chat by querying the bot's chats filtered
659
- * by the target user's AAD object ID.
660
- */
661
- async function resolveGraphChatId(params) {
662
- const { botFrameworkConversationId, userAadObjectId, tokenProvider } = params;
663
- const fetchFn = params.fetchFn ?? fetch;
664
- if (botFrameworkConversationId.startsWith("19:")) return botFrameworkConversationId;
665
- const token = await tokenProvider.getAccessToken(GRAPH_SCOPE);
666
- let path;
667
- if (userAadObjectId) path = `/me/chats?$filter=${encodeURIComponent(`chatType eq 'oneOnOne' and members/any(m:m/microsoft.graph.aadUserConversationMember/userId eq '${userAadObjectId}')`)}&$select=id`;
668
- else path = `/me/chats?$filter=${encodeURIComponent("chatType eq 'oneOnOne'")}&$select=id`;
669
- const res = await fetchFn(`${GRAPH_ROOT}${path}`, { headers: {
670
- "User-Agent": buildUserAgent(),
671
- Authorization: `Bearer ${token}`
672
- } });
673
- if (!res.ok) return null;
674
- const chats = (await readProviderJsonResponse(res, "msteams.graph-upload.getOneOnOneChatId")).value ?? [];
675
- if (userAadObjectId && chats.length > 0 && chats[0]?.id) return chats[0].id;
676
- if (!userAadObjectId && chats.length === 1 && chats[0]?.id) return chats[0].id;
677
- return null;
678
- }
679
- /**
680
711
  * Get members of a Teams chat for per-user sharing.
681
712
  * Used to create sharing links scoped to only the chat participants.
682
713
  */
683
714
  async function getChatMembers(params) {
684
715
  const fetchFn = params.fetchFn ?? fetch;
685
- const token = await params.tokenProvider.getAccessToken(GRAPH_SCOPE);
686
- const res = await fetchFn(`${GRAPH_ROOT}/chats/${params.chatId}/members`, { headers: {
687
- "User-Agent": buildUserAgent(),
688
- Authorization: `Bearer ${token}`
689
- } });
690
- if (!res.ok) throw await createMSTeamsHttpError(res, "Get chat members failed");
691
- return ((await readProviderJsonResponse(res, "msteams.graph-upload.getChatMembers")).value ?? []).map((m) => ({
692
- aadObjectId: m.userId ?? "",
693
- displayName: m.displayName
694
- })).filter((m) => m.aadObjectId);
716
+ return await require_resolve_allowlist.withMSTeamsAbortableRequestTimeout({
717
+ label: SHAREPOINT_REQUEST_TIMEOUT_LABEL,
718
+ work: async (signal) => {
719
+ const token = await getGraphAccessToken(params.tokenProvider);
720
+ const res = await fetchFn(`${GRAPH_ROOT}/chats/${params.chatId}/members`, {
721
+ headers: {
722
+ "User-Agent": require_resolve_allowlist.buildUserAgent(),
723
+ Authorization: `Bearer ${token}`
724
+ },
725
+ signal
726
+ });
727
+ if (!res.ok) throw await require_resolve_allowlist.createMSTeamsHttpError(res, res.status === 403 ? "Get chat members failed; verify Graph chat-member permissions and tenant access policies" : "Get chat members failed");
728
+ return ((await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.getChatMembers")).value ?? []).map((member) => ({ aadObjectId: member.userId ?? "" })).filter((member) => member.aadObjectId);
729
+ }
730
+ });
695
731
  }
696
732
  /**
697
733
  * Create a sharing link for a SharePoint drive item.
@@ -700,7 +736,6 @@ async function getChatMembers(params) {
700
736
  */
701
737
  async function createSharePointSharingLink(params) {
702
738
  const fetchFn = params.fetchFn ?? fetch;
703
- const token = await params.tokenProvider.getAccessToken(GRAPH_SCOPE);
704
739
  const scope = params.scope ?? "organization";
705
740
  const apiRoot = scope === "users" ? GRAPH_BETA : GRAPH_ROOT;
706
741
  const body = {
@@ -708,17 +743,24 @@ async function createSharePointSharingLink(params) {
708
743
  scope: scope === "users" ? "users" : "organization"
709
744
  };
710
745
  if (scope === "users" && params.recipientObjectIds?.length) body.recipients = params.recipientObjectIds.map((id) => ({ objectId: id }));
711
- const res = await fetchFn(`${apiRoot}/sites/${params.siteId}/drive/items/${params.itemId}/createLink`, {
712
- method: "POST",
713
- headers: {
714
- "User-Agent": buildUserAgent(),
715
- Authorization: `Bearer ${token}`,
716
- "Content-Type": "application/json"
717
- },
718
- body: JSON.stringify(body)
746
+ const data = await require_resolve_allowlist.withMSTeamsAbortableRequestTimeout({
747
+ label: SHAREPOINT_REQUEST_TIMEOUT_LABEL,
748
+ work: async (signal) => {
749
+ const token = await getGraphAccessToken(params.tokenProvider);
750
+ const res = await fetchFn(`${apiRoot}/sites/${params.siteId}/drive/items/${params.itemId}/createLink`, {
751
+ method: "POST",
752
+ headers: {
753
+ "User-Agent": require_resolve_allowlist.buildUserAgent(),
754
+ Authorization: `Bearer ${token}`,
755
+ "Content-Type": "application/json"
756
+ },
757
+ body: JSON.stringify(body),
758
+ signal
759
+ });
760
+ if (!res.ok) throw await require_resolve_allowlist.createMSTeamsHttpError(res, "Create SharePoint sharing link failed");
761
+ return await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.createSharePointSharingLink");
762
+ }
719
763
  });
720
- if (!res.ok) throw await createMSTeamsHttpError(res, "Create SharePoint sharing link failed");
721
- const data = await readProviderJsonResponse(res, "msteams.graph-upload.createSharePointSharingLink");
722
764
  if (!data.link?.webUrl) throw new Error("Create SharePoint sharing link response missing webUrl");
723
765
  return { webUrl: data.link.webUrl };
724
766
  }
@@ -730,7 +772,7 @@ async function createSharePointSharingLink(params) {
730
772
  *
731
773
  * @param params.siteId - SharePoint site ID
732
774
  * @param params.chatId - Optional chat ID for per-user sharing (group chats)
733
- * @param params.usePerUserSharing - Whether to use per-user sharing (requires beta API + Chat.Read.All)
775
+ * @param params.usePerUserSharing - Whether to use per-user sharing (requires beta API + chat-member read access)
734
776
  */
735
777
  async function uploadAndShareSharePoint(params) {
736
778
  const uploaded = await uploadToSharePoint({
@@ -743,17 +785,16 @@ async function uploadAndShareSharePoint(params) {
743
785
  });
744
786
  let scope = "organization";
745
787
  let recipientObjectIds;
746
- if (params.usePerUserSharing && params.chatId) try {
788
+ if (params.usePerUserSharing && params.chatId) {
747
789
  const members = await getChatMembers({
748
790
  chatId: params.chatId,
749
791
  tokenProvider: params.tokenProvider,
750
792
  fetchFn: params.fetchFn
751
793
  });
752
- if (members.length > 0) {
753
- scope = "users";
754
- recipientObjectIds = members.map((m) => m.aadObjectId);
755
- }
756
- } catch {}
794
+ if (members.length === 0) throw new Error("MS Teams chat member lookup returned no recipients");
795
+ scope = "users";
796
+ recipientObjectIds = members.map((member) => member.aadObjectId);
797
+ }
757
798
  const shareLink = await createSharePointSharingLink({
758
799
  siteId: params.siteId,
759
800
  itemId: uploaded.id,
@@ -783,7 +824,7 @@ async function getMimeType(url) {
783
824
  const match = url.match(/^data:([^;,]+)/);
784
825
  if (match?.[1]) return match[1];
785
826
  }
786
- return await detectMime({ filePath: url }) ?? "application/octet-stream";
827
+ return await (0, openclaw_plugin_sdk_media_runtime.detectMime)({ filePath: url }) ?? "application/octet-stream";
787
828
  }
788
829
  /**
789
830
  * Extract filename from URL or local path.
@@ -793,20 +834,20 @@ async function getMimeType(url) {
793
834
  async function extractFilename(url) {
794
835
  if (url.startsWith("data:")) {
795
836
  const mime = await getMimeType(url);
796
- const ext = extensionForMime(mime) ?? ".bin";
837
+ const ext = (0, openclaw_plugin_sdk_media_runtime.extensionForMime)(mime) ?? ".bin";
797
838
  return `${mime.startsWith("image/") ? "image" : "file"}${ext}`;
798
839
  }
799
840
  try {
800
841
  const pathname = new URL(url).pathname;
801
- const basename = path.basename(pathname);
802
- const existingExt = getFileExtension(pathname);
842
+ const basename = node_path.default.basename(pathname);
843
+ const existingExt = (0, openclaw_plugin_sdk_media_runtime.getFileExtension)(pathname);
803
844
  if (basename && existingExt) return basename;
804
845
  const mime = await getMimeType(url);
805
- const ext = extensionForMime(mime) ?? ".bin";
846
+ const ext = (0, openclaw_plugin_sdk_media_runtime.extensionForMime)(mime) ?? ".bin";
806
847
  const prefix = mime.startsWith("image/") ? "image" : "file";
807
848
  return basename ? `${basename}${ext}` : `${prefix}${ext}`;
808
849
  } catch {
809
- return extractOriginalFilename(url);
850
+ return (0, openclaw_plugin_sdk_media_runtime.extractOriginalFilename)(url);
810
851
  }
811
852
  }
812
853
  /**
@@ -883,21 +924,21 @@ async function withRevokedProxyFallback(params) {
883
924
  try {
884
925
  return await params.run();
885
926
  } catch (err) {
886
- if (!isRevokedProxyError(err)) throw err;
927
+ if (!require_setup_surface.isRevokedProxyError(err)) throw err;
887
928
  params.onRevokedLog?.();
888
929
  return await params.onRevoked();
889
930
  }
890
931
  }
891
932
  //#endregion
892
933
  //#region extensions/msteams/src/sdk-proactive.ts
893
- const loadMSTeamsApiModule = createLazyRuntimeModule(() => import("@microsoft/teams.api"));
934
+ const loadMSTeamsApiModule = (0, openclaw_plugin_sdk_lazy_runtime.createLazyRuntimeModule)(() => import("@microsoft/teams.api"));
894
935
  function resolveThreadedConversationId(conversationId, threadActivityId) {
895
936
  if (!threadActivityId) return conversationId.split(";")[0] ?? conversationId;
896
937
  return `${conversationId.split(";")[0] ?? conversationId};messageid=${threadActivityId}`;
897
938
  }
898
939
  function normalizeRequiredServiceUrl(ref) {
899
940
  if (!ref.serviceUrl) throw new Error("Invalid stored reference: missing serviceUrl");
900
- return normalizeBotFrameworkServiceUrl(ref.serviceUrl);
941
+ return require_resolve_allowlist.normalizeBotFrameworkServiceUrl(ref.serviceUrl);
901
942
  }
902
943
  function buildSdkConversationReference(source, options) {
903
944
  const bot = source.agent ?? source.bot ?? void 0;
@@ -905,7 +946,7 @@ function buildSdkConversationReference(source, options) {
905
946
  const conversationId = resolveThreadedConversationId(source.conversation.id, options?.threadActivityId);
906
947
  const tenantId = source.tenantId ?? source.conversation.tenantId;
907
948
  const serviceUrl = normalizeRequiredServiceUrl(source);
908
- if (options?.serviceUrlBoundary) validateMSTeamsProactiveServiceUrlBoundary({
949
+ if (options?.serviceUrlBoundary) require_resolve_allowlist.validateMSTeamsProactiveServiceUrlBoundary({
909
950
  cloud: options.serviceUrlBoundary.cloud,
910
951
  conversationId,
911
952
  storedServiceUrl: serviceUrl,
@@ -938,7 +979,7 @@ function getStructuralApiClient(app) {
938
979
  function sameServiceUrl(left, right) {
939
980
  if (!left) return false;
940
981
  try {
941
- return normalizeBotFrameworkServiceUrl(left) === right;
982
+ return require_resolve_allowlist.normalizeBotFrameworkServiceUrl(left) === right;
942
983
  } catch {
943
984
  return false;
944
985
  }
@@ -1026,14 +1067,14 @@ const AI_GENERATED_ENTITY = {
1026
1067
  //#region extensions/msteams/src/messenger.ts
1027
1068
  /**
1028
1069
  * MSTeams-specific media size limit (100MB).
1029
- * Higher than the default because OneDrive upload handles large files well.
1070
+ * Higher than the default to support Teams file-consent and SharePoint uploads.
1030
1071
  */
1031
- const MSTEAMS_MAX_MEDIA_BYTES$1 = 100 * 1024 * 1024;
1072
+ const MSTEAMS_MAX_MEDIA_BYTES = 100 * 1024 * 1024;
1032
1073
  /**
1033
1074
  * Threshold for large files that require FileConsentCard flow in personal chats.
1034
1075
  * Files >= 4MB use consent flow; smaller images can use inline base64.
1035
1076
  */
1036
- const FILE_CONSENT_THRESHOLD_BYTES$1 = 4 * 1024 * 1024;
1077
+ const FILE_CONSENT_THRESHOLD_BYTES = 4 * 1024 * 1024;
1037
1078
  function normalizeConversationId(rawId) {
1038
1079
  return rawId.split(";")[0] ?? rawId;
1039
1080
  }
@@ -1068,15 +1109,15 @@ function buildConversationReference(ref) {
1068
1109
  function pushTextMessages(out, text, opts) {
1069
1110
  if (!text) return;
1070
1111
  if (opts.chunkText) {
1071
- for (const chunk of getMSTeamsRuntime().channel.text.chunkMarkdownTextWithMode(text, opts.chunkLimit, opts.chunkMode)) {
1112
+ for (const chunk of require_runtime.getMSTeamsRuntime().channel.text.chunkMarkdownTextWithMode(text, opts.chunkLimit, opts.chunkMode)) {
1072
1113
  const trimmed = chunk.trim();
1073
- if (!trimmed || isSilentReplyText(trimmed, SILENT_REPLY_TOKEN)) continue;
1114
+ if (!trimmed || (0, openclaw_plugin_sdk_reply_chunking.isSilentReplyText)(trimmed, openclaw_plugin_sdk_reply_chunking.SILENT_REPLY_TOKEN)) continue;
1074
1115
  out.push({ text: trimmed });
1075
1116
  }
1076
1117
  return;
1077
1118
  }
1078
1119
  const trimmed = text.trim();
1079
- if (!trimmed || isSilentReplyText(trimmed, SILENT_REPLY_TOKEN)) return;
1120
+ if (!trimmed || (0, openclaw_plugin_sdk_reply_chunking.isSilentReplyText)(trimmed, openclaw_plugin_sdk_reply_chunking.SILENT_REPLY_TOKEN)) return;
1080
1121
  out.push({ text: trimmed });
1081
1122
  }
1082
1123
  function clampMs(value, maxMs) {
@@ -1110,12 +1151,12 @@ function renderReplyPayloadsToMessages(replies, options) {
1110
1151
  const chunkText = options.chunkText !== false;
1111
1152
  const chunkMode = options.chunkMode ?? "length";
1112
1153
  const mediaMode = options.mediaMode ?? "split";
1113
- const tableMode = options.tableMode ?? getMSTeamsRuntime().channel.text.resolveMarkdownTableMode({
1114
- cfg: getMSTeamsRuntime().config.current(),
1154
+ const tableMode = options.tableMode ?? require_runtime.getMSTeamsRuntime().channel.text.resolveMarkdownTableMode({
1155
+ cfg: require_runtime.getMSTeamsRuntime().config.current(),
1115
1156
  channel: "msteams"
1116
1157
  });
1117
1158
  for (const payload of replies) {
1118
- const reply = resolveSendableOutboundReplyParts(payload, { text: getMSTeamsRuntime().channel.text.convertMarkdownTables(payload.text ?? "", tableMode) });
1159
+ const reply = (0, openclaw_plugin_sdk_reply_payload.resolveSendableOutboundReplyParts)(payload, { text: require_runtime.getMSTeamsRuntime().channel.text.convertMarkdownTables(payload.text ?? "", tableMode) });
1119
1160
  if (!reply.hasContent) continue;
1120
1161
  if (!reply.hasMedia) {
1121
1162
  pushTextMessages(out, reply.text, {
@@ -1165,18 +1206,18 @@ async function buildActivity(msg, conversationRef, tokenProvider, sharePointSite
1165
1206
  let contentType = await getMimeType(msg.mediaUrl);
1166
1207
  let fileName = await extractFilename(msg.mediaUrl);
1167
1208
  if (isLocalPath(msg.mediaUrl)) {
1168
- const maxBytes = mediaMaxBytes ?? MSTEAMS_MAX_MEDIA_BYTES$1;
1169
- const media = await loadWebMedia(msg.mediaUrl, maxBytes);
1209
+ const maxBytes = mediaMaxBytes ?? MSTEAMS_MAX_MEDIA_BYTES;
1210
+ const media = await (0, openclaw_plugin_sdk_web_media.loadWebMedia)(msg.mediaUrl, maxBytes);
1170
1211
  contentType = media.contentType ?? contentType;
1171
1212
  fileName = media.fileName ?? fileName;
1172
- const conversationType = normalizeOptionalLowercaseString(conversationRef.conversation?.conversationType);
1213
+ const conversationType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(conversationRef.conversation?.conversationType);
1173
1214
  const isPersonal = conversationType === "personal";
1174
1215
  const isImage = media.kind === "image";
1175
1216
  if (requiresFileConsent({
1176
1217
  conversationType,
1177
1218
  contentType,
1178
1219
  bufferSize: media.buffer.length,
1179
- thresholdBytes: FILE_CONSENT_THRESHOLD_BYTES$1
1220
+ thresholdBytes: FILE_CONSENT_THRESHOLD_BYTES
1180
1221
  })) {
1181
1222
  const conversationId = conversationRef.conversation?.id ?? "unknown";
1182
1223
  const { activity: consentActivity, uploadId } = prepareFileConsentActivity({
@@ -1191,16 +1232,18 @@ async function buildActivity(msg, conversationRef, tokenProvider, sharePointSite
1191
1232
  consentActivity["_pendingUploadId"] = uploadId;
1192
1233
  return consentActivity;
1193
1234
  }
1194
- if (!isPersonal && !isImage && tokenProvider && sharePointSiteId) {
1195
- const chatId = conversationRef.graphChatId ?? conversationRef.conversation?.id;
1235
+ if (!isPersonal && !isImage) {
1236
+ const siteId = requireMSTeamsSharePointSiteId(sharePointSiteId);
1237
+ if (!tokenProvider) throw new Error("MS Teams Graph token provider unavailable for SharePoint file send");
1238
+ const chatId = conversationRef.conversation?.id;
1196
1239
  activity.attachments = [buildTeamsFileInfoCard(await getDriveItemProperties({
1197
- siteId: sharePointSiteId,
1240
+ siteId,
1198
1241
  itemId: (await uploadAndShareSharePoint({
1199
1242
  buffer: media.buffer,
1200
1243
  filename: fileName,
1201
1244
  contentType,
1202
1245
  tokenProvider,
1203
- siteId: sharePointSiteId,
1246
+ siteId,
1204
1247
  chatId: chatId ?? void 0,
1205
1248
  usePerUserSharing: conversationType === "groupchat"
1206
1249
  })).itemId,
@@ -1208,18 +1251,6 @@ async function buildActivity(msg, conversationRef, tokenProvider, sharePointSite
1208
1251
  }))];
1209
1252
  return activity;
1210
1253
  }
1211
- if (!isPersonal && media.kind !== "image" && tokenProvider) {
1212
- const uploaded = await uploadAndShareOneDrive({
1213
- buffer: media.buffer,
1214
- filename: fileName,
1215
- contentType,
1216
- tokenProvider
1217
- });
1218
- const fileLink = `📎 [${uploaded.name}](${uploaded.shareUrl})`;
1219
- const existingText = typeof activity.text === "string" ? activity.text : void 0;
1220
- activity.text = existingText ? `${existingText}\n\n${fileLink}` : fileLink;
1221
- return activity;
1222
- }
1223
1254
  const base64 = media.buffer.toString("base64");
1224
1255
  contentUrl = `data:${media.contentType};base64,${base64}`;
1225
1256
  }
@@ -1240,7 +1271,7 @@ async function sendMSTeamsMessages(params) {
1240
1271
  for (const attempt of Array.from({ length: retryOptions.maxAttempts }, (_, index) => index + 1)) try {
1241
1272
  return await sendOnce();
1242
1273
  } catch (err) {
1243
- const classification = classifyMSTeamsSendError(err);
1274
+ const classification = require_setup_surface.classifyMSTeamsSendError(err);
1244
1275
  if (!(attempt < retryOptions.maxAttempts && shouldRetry(classification))) throw err;
1245
1276
  const delayMs = computeRetryDelayMs(attempt, classification, retryOptions);
1246
1277
  const nextAttempt = attempt + 1;
@@ -1252,7 +1283,7 @@ async function sendMSTeamsMessages(params) {
1252
1283
  delayMs,
1253
1284
  classification
1254
1285
  });
1255
- await sleep(delayMs);
1286
+ await (0, openclaw_plugin_sdk_text_utility_runtime.sleep)(delayMs);
1256
1287
  }
1257
1288
  throw new Error("unreachable Teams send retry loop exit");
1258
1289
  };
@@ -1312,675 +1343,189 @@ async function sendMSTeamsMessages(params) {
1312
1343
  return await sendProactively(messages, 0);
1313
1344
  }
1314
1345
  //#endregion
1315
- //#region extensions/msteams/src/send-context.ts
1316
- function resolveMSTeamsProactiveReplyStyle(params) {
1317
- const threadRootId = params.ref.threadId ?? params.ref.activityId;
1318
- if (params.conversationType !== "channel" || !threadRootId) return "top-level";
1319
- const routeConfig = resolveMSTeamsRouteConfig({
1320
- cfg: params.cfg,
1321
- teamId: params.ref.teamId,
1322
- conversationId: params.conversationId,
1323
- allowNameMatching: false
1324
- });
1325
- const { replyStyle } = resolveMSTeamsReplyPolicy({
1326
- isDirectMessage: false,
1327
- globalConfig: params.cfg,
1328
- teamConfig: routeConfig.teamConfig,
1329
- channelConfig: routeConfig.channelConfig
1330
- });
1331
- return replyStyle;
1332
- }
1333
- /**
1334
- * Parse the target value into a conversation reference lookup key.
1335
- * Supported formats:
1336
- * - conversation:19:abc@thread.tacv2 → lookup by conversation ID
1337
- * - user:aad-object-id → lookup by user AAD object ID
1338
- * - 19:abc@thread.tacv2 → direct conversation ID
1339
- */
1340
- function parseRecipient(to) {
1341
- const trimmed = to.trim();
1342
- const finalize = (type, id) => {
1343
- const normalized = id.trim();
1344
- if (!normalized) throw new Error(`Invalid target value: missing ${type} id`);
1345
- return {
1346
- type,
1347
- id: normalized
1348
- };
1349
- };
1350
- if (trimmed.startsWith("conversation:")) return finalize("conversation", trimmed.slice(13));
1351
- if (trimmed.startsWith("user:")) return finalize("user", trimmed.slice(5));
1352
- if (trimmed.startsWith("19:") || trimmed.includes("@thread")) return finalize("conversation", trimmed);
1353
- return finalize("user", trimmed);
1354
- }
1355
- /**
1356
- * Find a stored conversation reference for the given recipient.
1357
- */
1358
- async function findConversationReference(recipient) {
1359
- if (recipient.type === "conversation") {
1360
- const ref = await recipient.store.get(recipient.id);
1361
- if (ref) return {
1362
- conversationId: recipient.id,
1363
- ref
1364
- };
1365
- return null;
1346
+ Object.defineProperty(exports, "buildConversationReference", {
1347
+ enumerable: true,
1348
+ get: function() {
1349
+ return buildConversationReference;
1366
1350
  }
1367
- const found = await recipient.store.findPreferredDmByUserId(recipient.id);
1368
- if (!found) return null;
1369
- return {
1370
- conversationId: found.conversationId,
1371
- ref: found.reference
1372
- };
1373
- }
1374
- async function resolveMSTeamsSendContext(params) {
1375
- const msteamsCfg = params.cfg.channels?.msteams;
1376
- if (!msteamsCfg?.enabled) throw new Error("msteams provider is not enabled");
1377
- const creds = resolveMSTeamsCredentials(msteamsCfg);
1378
- if (!creds) throw new Error("msteams credentials not configured");
1379
- const store = createMSTeamsConversationStoreState();
1380
- const recipient = parseRecipient(params.to);
1381
- const found = await findConversationReference({
1382
- ...recipient,
1383
- store
1384
- });
1385
- if (!found) throw new Error(`No conversation reference found for ${recipient.type}:${recipient.id}. The bot must receive a message from this conversation before it can send proactively.`);
1386
- const { conversationId, ref } = found;
1387
- const log = getMSTeamsRuntime().logging.getChildLogger({ name: "msteams:send" });
1388
- if (ref.serviceUrl && !isAllowedBotFrameworkServiceUrl(ref.serviceUrl)) {
1389
- try {
1390
- await store.remove(conversationId);
1391
- } catch (err) {
1392
- log.warn?.("failed to remove blocked msteams conversation reference", {
1393
- conversationId,
1394
- error: formatUnknownError(err)
1395
- });
1396
- }
1397
- throw new Error(`Stored Microsoft Teams conversation reference has blocked serviceUrl host: ${describeBotFrameworkServiceUrlHost(ref.serviceUrl)}. The bot must receive a new message from this conversation before it can send proactively.`);
1351
+ });
1352
+ Object.defineProperty(exports, "buildFileInfoCard", {
1353
+ enumerable: true,
1354
+ get: function() {
1355
+ return buildFileInfoCard;
1398
1356
  }
1399
- const safeRef = ref.serviceUrl ? {
1400
- ...ref,
1401
- serviceUrl: normalizeBotFrameworkServiceUrl(ref.serviceUrl)
1402
- } : ref;
1403
- if (recipient.type === "user") {
1404
- const resolvedType = normalizeLowercaseStringOrEmpty(safeRef.conversation?.conversationType ?? "");
1405
- if (resolvedType && resolvedType !== "personal") throw new Error(`Conversation reference for user:${recipient.id} resolved to a ${resolvedType} conversation (${conversationId}) instead of a personal DM. The bot must receive a DM from this user before it can send proactively.`);
1357
+ });
1358
+ Object.defineProperty(exports, "buildTeamsFileInfoCard", {
1359
+ enumerable: true,
1360
+ get: function() {
1361
+ return buildTeamsFileInfoCard;
1406
1362
  }
1407
- const sdkCloudOptions = resolveMSTeamsSdkCloudOptions(msteamsCfg);
1408
- const { app } = await loadMSTeamsSdkWithAuth(creds, sdkCloudOptions);
1409
- validateMSTeamsProactiveServiceUrlBoundary({
1410
- cloud: sdkCloudOptions.cloud,
1411
- conversationId,
1412
- storedServiceUrl: safeRef.serviceUrl,
1413
- configuredServiceUrl: sdkCloudOptions.serviceUrl
1414
- });
1415
- const tokenProvider = createMSTeamsTokenProvider(app);
1416
- const storedConversationType = normalizeLowercaseStringOrEmpty(safeRef.conversation?.conversationType ?? "");
1417
- let conversationType;
1418
- if (storedConversationType === "personal") conversationType = "personal";
1419
- else if (storedConversationType === "channel") conversationType = "channel";
1420
- else conversationType = "groupChat";
1421
- const replyStyle = resolveMSTeamsProactiveReplyStyle({
1422
- cfg: msteamsCfg,
1423
- conversationId,
1424
- ref: safeRef,
1425
- conversationType
1426
- });
1427
- const sharePointSiteId = msteamsCfg.sharePointSiteId;
1428
- const mediaMaxBytes = resolveChannelMediaMaxBytes({
1429
- cfg: params.cfg,
1430
- resolveChannelLimitMb: ({ cfg }) => cfg.channels?.msteams?.mediaMaxMb
1431
- });
1432
- let graphChatId = safeRef.graphChatId ?? void 0;
1433
- if (graphChatId === void 0 && sharePointSiteId) try {
1434
- const resolved = await resolveGraphChatId({
1435
- botFrameworkConversationId: conversationId,
1436
- userAadObjectId: safeRef.user?.aadObjectId,
1437
- tokenProvider
1438
- });
1439
- graphChatId = resolved;
1440
- if (resolved) await store.upsert(conversationId, {
1441
- ...safeRef,
1442
- graphChatId: resolved
1443
- });
1444
- else log.warn?.("could not resolve Graph chat ID; file uploads may fail for this conversation", { conversationId });
1445
- } catch (err) {
1446
- log.warn?.("failed to resolve Graph chat ID; file uploads may fall back to Bot Framework ID", {
1447
- conversationId,
1448
- error: formatUnknownError(err)
1449
- });
1450
- graphChatId = null;
1363
+ });
1364
+ Object.defineProperty(exports, "deleteMSTeamsActivityWithReference", {
1365
+ enumerable: true,
1366
+ get: function() {
1367
+ return deleteMSTeamsActivityWithReference;
1451
1368
  }
1452
- return {
1453
- appId: creds.appId,
1454
- conversationId,
1455
- ref: safeRef,
1456
- app,
1457
- log,
1458
- conversationType,
1459
- replyStyle,
1460
- sdkCloudOptions,
1461
- tokenProvider,
1462
- sharePointSiteId,
1463
- mediaMaxBytes,
1464
- graphChatId
1465
- };
1466
- }
1467
- //#endregion
1468
- //#region extensions/msteams/src/send.ts
1469
- /** Threshold for large files that require FileConsentCard flow in personal chats */
1470
- const FILE_CONSENT_THRESHOLD_BYTES = 4 * 1024 * 1024;
1471
- /**
1472
- * MSTeams-specific media size limit (100MB).
1473
- * Higher than the default because OneDrive upload handles large files well.
1474
- */
1475
- const MSTEAMS_MAX_MEDIA_BYTES = 100 * 1024 * 1024;
1476
- function createMSTeamsSendReceipt(params) {
1477
- return createMessageReceiptFromOutboundResults({
1478
- kind: params.kind,
1479
- results: params.platformMessageIds.map((messageId) => ({
1480
- channel: "msteams",
1481
- messageId,
1482
- conversationId: params.conversationId
1483
- }))
1484
- });
1485
- }
1486
- function createMSTeamsSendResult(params) {
1487
- const platformMessageIds = (params.platformMessageIds?.length ? [...params.platformMessageIds] : [params.messageId]).map((messageId) => messageId.trim()).filter((messageId) => messageId && messageId !== "unknown");
1488
- return {
1489
- messageId: params.messageId,
1490
- conversationId: params.conversationId,
1491
- receipt: createMSTeamsSendReceipt({
1492
- conversationId: params.conversationId,
1493
- platformMessageIds,
1494
- kind: params.kind
1495
- }),
1496
- ...params.pendingUploadId ? { pendingUploadId: params.pendingUploadId } : {}
1497
- };
1498
- }
1499
- /**
1500
- * Send a message to a Teams conversation or user.
1501
- *
1502
- * Uses the stored ConversationReference from previous interactions.
1503
- * The bot must have received at least one message from the conversation
1504
- * before proactive messaging works.
1505
- *
1506
- * File handling by conversation type:
1507
- * - Personal (1:1) chats: small images (<4MB) use base64, large files and non-images use FileConsentCard
1508
- * - Group chats / channels: files are uploaded to OneDrive and shared via link
1509
- */
1510
- async function sendMessageMSTeams(params) {
1511
- const { cfg, to, text, mediaUrl, filename, mediaLocalRoots, mediaReadFile } = params;
1512
- const tableMode = resolveMarkdownTableMode({
1513
- cfg,
1514
- channel: "msteams"
1515
- });
1516
- const messageText = convertMarkdownTables(text ?? "", tableMode);
1517
- const ctx = await resolveMSTeamsSendContext({
1518
- cfg,
1519
- to
1520
- });
1521
- const { app, conversationId, ref, log, conversationType, tokenProvider, sharePointSiteId, sdkCloudOptions } = ctx;
1522
- log.debug?.("sending proactive message", {
1523
- conversationId,
1524
- conversationType,
1525
- textLength: messageText.length,
1526
- hasMedia: Boolean(mediaUrl)
1527
- });
1528
- if (mediaUrl) {
1529
- const media = await loadOutboundMediaFromUrl(mediaUrl, {
1530
- maxBytes: ctx.mediaMaxBytes ?? MSTEAMS_MAX_MEDIA_BYTES,
1531
- mediaLocalRoots,
1532
- mediaReadFile
1533
- });
1534
- const isLargeFile = media.buffer.length >= FILE_CONSENT_THRESHOLD_BYTES;
1535
- const isImage = media.contentType?.startsWith("image/") ?? false;
1536
- const fallbackFileName = await extractFilename(mediaUrl);
1537
- const fileName = filename?.trim() || media.fileName || fallbackFileName;
1538
- log.debug?.("processing media", {
1539
- fileName,
1540
- contentType: media.contentType,
1541
- size: media.buffer.length,
1542
- isLargeFile,
1543
- isImage,
1544
- conversationType
1545
- });
1546
- if (requiresFileConsent({
1547
- conversationType,
1548
- contentType: media.contentType,
1549
- bufferSize: media.buffer.length,
1550
- thresholdBytes: FILE_CONSENT_THRESHOLD_BYTES
1551
- })) {
1552
- const { activity, uploadId } = await prepareFileConsentActivityFs({
1553
- media: {
1554
- buffer: media.buffer,
1555
- filename: fileName,
1556
- contentType: media.contentType
1557
- },
1558
- conversationId,
1559
- description: messageText || void 0
1560
- });
1561
- log.debug?.("sending file consent card", {
1562
- uploadId,
1563
- fileName,
1564
- size: media.buffer.length
1565
- });
1566
- const messageId = await sendProactiveActivity({
1567
- app,
1568
- ref,
1569
- activity,
1570
- errorPrefix: "msteams consent card send",
1571
- serviceUrlBoundary: sdkCloudOptions
1572
- });
1573
- setPendingUploadActivityId(uploadId, messageId);
1574
- await setPendingUploadActivityIdFs(uploadId, messageId);
1575
- log.info("sent file consent card", {
1576
- conversationId,
1577
- messageId,
1578
- uploadId
1579
- });
1580
- return createMSTeamsSendResult({
1581
- messageId,
1582
- conversationId,
1583
- kind: "card",
1584
- pendingUploadId: uploadId
1585
- });
1586
- }
1587
- if (conversationType === "personal") {
1588
- const base64 = media.buffer.toString("base64");
1589
- return sendTextWithMedia(ctx, messageText, `data:${media.contentType};base64,${base64}`);
1590
- }
1591
- if (isImage && !sharePointSiteId) {
1592
- const base64 = media.buffer.toString("base64");
1593
- return sendTextWithMedia(ctx, messageText, `data:${media.contentType};base64,${base64}`);
1594
- }
1595
- try {
1596
- if (sharePointSiteId) {
1597
- log.debug?.("uploading to SharePoint for native file card", {
1598
- fileName,
1599
- conversationType,
1600
- siteId: sharePointSiteId
1601
- });
1602
- const uploaded = await uploadAndShareSharePoint({
1603
- buffer: media.buffer,
1604
- filename: fileName,
1605
- contentType: media.contentType,
1606
- tokenProvider,
1607
- siteId: sharePointSiteId,
1608
- chatId: ctx.graphChatId ?? conversationId,
1609
- usePerUserSharing: conversationType === "groupChat"
1610
- });
1611
- log.debug?.("SharePoint upload complete", {
1612
- itemId: uploaded.itemId,
1613
- shareUrl: uploaded.shareUrl
1614
- });
1615
- const driveItem = await getDriveItemProperties({
1616
- siteId: sharePointSiteId,
1617
- itemId: uploaded.itemId,
1618
- tokenProvider
1619
- });
1620
- log.debug?.("driveItem properties retrieved", {
1621
- eTag: driveItem.eTag,
1622
- webDavUrl: driveItem.webDavUrl
1623
- });
1624
- const fileCardAttachment = buildTeamsFileInfoCard(driveItem);
1625
- const messageId = await sendProactiveActivityRaw({
1626
- app,
1627
- ref,
1628
- activity: {
1629
- type: "message",
1630
- text: messageText || void 0,
1631
- attachments: [fileCardAttachment]
1632
- },
1633
- serviceUrlBoundary: sdkCloudOptions
1634
- });
1635
- log.info("sent native file card", {
1636
- conversationId,
1637
- messageId,
1638
- fileName: driveItem.name
1639
- });
1640
- return createMSTeamsSendResult({
1641
- messageId,
1642
- conversationId,
1643
- kind: "media"
1644
- });
1645
- }
1646
- log.debug?.("uploading to OneDrive (no SharePoint site configured)", {
1647
- fileName,
1648
- conversationType
1649
- });
1650
- const uploaded = await uploadAndShareOneDrive({
1651
- buffer: media.buffer,
1652
- filename: fileName,
1653
- contentType: media.contentType,
1654
- tokenProvider
1655
- });
1656
- log.debug?.("OneDrive upload complete", {
1657
- itemId: uploaded.itemId,
1658
- shareUrl: uploaded.shareUrl
1659
- });
1660
- const fileLink = `📎 [${uploaded.name}](${uploaded.shareUrl})`;
1661
- const messageId = await sendProactiveActivityRaw({
1662
- app,
1663
- ref,
1664
- activity: {
1665
- type: "message",
1666
- text: messageText ? `${messageText}\n\n${fileLink}` : fileLink
1667
- },
1668
- serviceUrlBoundary: sdkCloudOptions
1669
- });
1670
- log.info("sent message with OneDrive file link", {
1671
- conversationId,
1672
- messageId,
1673
- shareUrl: uploaded.shareUrl
1674
- });
1675
- return createMSTeamsSendResult({
1676
- messageId,
1677
- conversationId,
1678
- kind: "media"
1679
- });
1680
- } catch (err) {
1681
- const classification = classifyMSTeamsSendError(err);
1682
- const hint = formatMSTeamsSendErrorHint(classification);
1683
- const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
1684
- throw new Error(`msteams file send failed${status}: ${formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
1685
- }
1369
+ });
1370
+ Object.defineProperty(exports, "extractFilename", {
1371
+ enumerable: true,
1372
+ get: function() {
1373
+ return extractFilename;
1686
1374
  }
1687
- return sendTextWithMedia(ctx, messageText, void 0);
1688
- }
1689
- /**
1690
- * Send a text message with optional base64 media URL.
1691
- */
1692
- async function sendTextWithMedia(ctx, text, mediaUrl) {
1693
- const { app, appId, conversationId, ref, log, tokenProvider, sharePointSiteId, mediaMaxBytes, replyStyle } = ctx;
1694
- let platformMessageIds;
1695
- try {
1696
- platformMessageIds = await sendMSTeamsMessages({
1697
- replyStyle,
1698
- app,
1699
- appId,
1700
- conversationRef: ref,
1701
- messages: [{
1702
- text: text || void 0,
1703
- mediaUrl
1704
- }],
1705
- retry: {},
1706
- onRetry: (event) => {
1707
- log.debug?.("retrying send", {
1708
- conversationId,
1709
- ...event
1710
- });
1711
- },
1712
- tokenProvider,
1713
- sharePointSiteId,
1714
- mediaMaxBytes,
1715
- serviceUrlBoundary: ctx.sdkCloudOptions
1716
- });
1717
- } catch (err) {
1718
- const classification = classifyMSTeamsSendError(err);
1719
- const hint = formatMSTeamsSendErrorHint(classification);
1720
- const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
1721
- throw new Error(`msteams send failed${status}: ${formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
1375
+ });
1376
+ Object.defineProperty(exports, "extractMessageId", {
1377
+ enumerable: true,
1378
+ get: function() {
1379
+ return extractMessageId;
1722
1380
  }
1723
- const messageId = platformMessageIds[0] ?? "unknown";
1724
- log.info("sent proactive message", {
1725
- conversationId,
1726
- messageId
1727
- });
1728
- return {
1729
- messageId,
1730
- conversationId,
1731
- receipt: createMSTeamsSendReceipt({
1732
- conversationId,
1733
- platformMessageIds,
1734
- kind: mediaUrl ? "media" : "text"
1735
- })
1736
- };
1737
- }
1738
- async function sendProactiveActivityRaw({ app, ref, activity, serviceUrlBoundary }) {
1739
- return extractMessageId(await sendMSTeamsActivityWithReference(app, buildConversationReference(ref), activity, { serviceUrlBoundary })) ?? "unknown";
1740
- }
1741
- async function sendProactiveActivity({ app, ref, activity, errorPrefix, serviceUrlBoundary }) {
1742
- try {
1743
- return await sendProactiveActivityRaw({
1744
- app,
1745
- ref,
1746
- activity,
1747
- serviceUrlBoundary
1748
- });
1749
- } catch (err) {
1750
- const classification = classifyMSTeamsSendError(err);
1751
- const hint = formatMSTeamsSendErrorHint(classification);
1752
- const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
1753
- throw new Error(`${errorPrefix} failed${status}: ${formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
1381
+ });
1382
+ Object.defineProperty(exports, "fetchChannelMessage", {
1383
+ enumerable: true,
1384
+ get: function() {
1385
+ return fetchChannelMessage;
1754
1386
  }
1755
- }
1756
- /**
1757
- * Send a poll (Adaptive Card) to a Teams conversation or user.
1758
- */
1759
- async function sendPollMSTeams(params) {
1760
- const { cfg, to, question, options, maxSelections } = params;
1761
- const { app, conversationId, ref, log, sdkCloudOptions } = await resolveMSTeamsSendContext({
1762
- cfg,
1763
- to
1764
- });
1765
- const pollCard = buildMSTeamsPollCard({
1766
- question,
1767
- options,
1768
- maxSelections
1769
- });
1770
- log.debug?.("sending poll", {
1771
- conversationId,
1772
- pollId: pollCard.pollId,
1773
- optionCount: pollCard.options.length
1774
- });
1775
- const messageId = await sendProactiveActivity({
1776
- app,
1777
- ref,
1778
- activity: {
1779
- type: "message",
1780
- attachments: [{
1781
- contentType: "application/vnd.microsoft.card.adaptive",
1782
- content: pollCard.card
1783
- }]
1784
- },
1785
- errorPrefix: "msteams poll send",
1786
- serviceUrlBoundary: sdkCloudOptions
1787
- });
1788
- log.info("sent poll", {
1789
- conversationId,
1790
- pollId: pollCard.pollId,
1791
- messageId
1792
- });
1793
- return {
1794
- pollId: pollCard.pollId,
1795
- messageId,
1796
- conversationId
1797
- };
1798
- }
1799
- /**
1800
- * Send an arbitrary Adaptive Card to a Teams conversation or user.
1801
- */
1802
- async function sendAdaptiveCardMSTeams(params) {
1803
- const { cfg, to, card } = params;
1804
- const { app, conversationId, ref, log, sdkCloudOptions } = await resolveMSTeamsSendContext({
1805
- cfg,
1806
- to
1807
- });
1808
- log.debug?.("sending adaptive card", {
1809
- conversationId,
1810
- cardType: card.type,
1811
- cardVersion: card.version
1812
- });
1813
- const messageId = await sendProactiveActivity({
1814
- app,
1815
- ref,
1816
- activity: {
1817
- type: "message",
1818
- attachments: [{
1819
- contentType: "application/vnd.microsoft.card.adaptive",
1820
- content: card
1821
- }]
1822
- },
1823
- errorPrefix: "msteams card send",
1824
- serviceUrlBoundary: sdkCloudOptions
1825
- });
1826
- log.info("sent adaptive card", {
1827
- conversationId,
1828
- messageId
1829
- });
1830
- return {
1831
- messageId,
1832
- conversationId
1833
- };
1834
- }
1835
- /**
1836
- * Edit (update) a previously sent message in a Teams conversation.
1837
- *
1838
- * Uses the Bot Framework REST API for proactive edits outside of the
1839
- * original turn context.
1840
- */
1841
- async function editMessageMSTeams(params) {
1842
- const { cfg, to, activityId, text } = params;
1843
- const { app, conversationId, ref, log, sdkCloudOptions } = await resolveMSTeamsSendContext({
1844
- cfg,
1845
- to
1846
- });
1847
- log.debug?.("editing proactive message", {
1848
- conversationId,
1849
- activityId,
1850
- textLength: text.length
1851
- });
1852
- try {
1853
- await updateMSTeamsActivityWithReference(app, buildConversationReference(ref), activityId, {
1854
- type: "message",
1855
- id: activityId,
1856
- text
1857
- }, { serviceUrlBoundary: sdkCloudOptions });
1858
- } catch (err) {
1859
- const classification = classifyMSTeamsSendError(err);
1860
- const hint = formatMSTeamsSendErrorHint(classification);
1861
- const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
1862
- throw new Error(`msteams edit failed${status}: ${formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
1387
+ });
1388
+ Object.defineProperty(exports, "fetchChatMessageText", {
1389
+ enumerable: true,
1390
+ get: function() {
1391
+ return fetchChatMessageText;
1863
1392
  }
1864
- log.info("edited proactive message", {
1865
- conversationId,
1866
- activityId
1867
- });
1868
- return { conversationId };
1869
- }
1870
- /**
1871
- * Delete a previously sent message in a Teams conversation.
1872
- *
1873
- * Uses the Bot Framework REST API for proactive deletes outside of the
1874
- * original turn context.
1875
- */
1876
- async function deleteMessageMSTeams(params) {
1877
- const { cfg, to, activityId } = params;
1878
- const { app, conversationId, ref, log, sdkCloudOptions } = await resolveMSTeamsSendContext({
1879
- cfg,
1880
- to
1881
- });
1882
- log.debug?.("deleting proactive message", {
1883
- conversationId,
1884
- activityId
1885
- });
1886
- try {
1887
- await deleteMSTeamsActivityWithReference(app, buildConversationReference(ref), activityId, { serviceUrlBoundary: sdkCloudOptions });
1888
- } catch (err) {
1889
- const classification = classifyMSTeamsSendError(err);
1890
- const hint = formatMSTeamsSendErrorHint(classification);
1891
- const status = classification.statusCode ? ` (HTTP ${classification.statusCode})` : "";
1892
- throw new Error(`msteams delete failed${status}: ${formatUnknownError(err)}${hint ? ` (${hint})` : ""}`, { cause: err });
1393
+ });
1394
+ Object.defineProperty(exports, "fetchThreadReplies", {
1395
+ enumerable: true,
1396
+ get: function() {
1397
+ return fetchThreadReplies;
1893
1398
  }
1894
- log.info("deleted proactive message", {
1895
- conversationId,
1896
- activityId
1897
- });
1898
- return { conversationId };
1899
- }
1900
- //#endregion
1901
- //#region extensions/msteams/src/probe.ts
1902
- function decodeJwtPayload(token) {
1903
- const parts = token.split(".");
1904
- if (parts.length < 2) return null;
1905
- const payload = parts[1] ?? "";
1906
- const normalized = payload.padEnd(payload.length + (4 - payload.length % 4) % 4, "=").replace(/-/g, "+").replace(/_/g, "/");
1907
- try {
1908
- const decoded = Buffer.from(normalized, "base64").toString("utf8");
1909
- const parsed = JSON.parse(decoded);
1910
- return parsed && typeof parsed === "object" ? parsed : null;
1911
- } catch {
1912
- return null;
1399
+ });
1400
+ Object.defineProperty(exports, "formatThreadContext", {
1401
+ enumerable: true,
1402
+ get: function() {
1403
+ return formatThreadContext;
1913
1404
  }
1914
- }
1915
- function readStringArray(value) {
1916
- if (!Array.isArray(value)) return;
1917
- const out = normalizeStringEntries$1(value);
1918
- return out.length > 0 ? out : void 0;
1919
- }
1920
- function readScopes(value) {
1921
- if (typeof value !== "string") return;
1922
- const out = normalizeStringEntries$1(value.split(/\s+/));
1923
- return out.length > 0 ? out : void 0;
1924
- }
1925
- async function probeMSTeams(cfg) {
1926
- const creds = resolveMSTeamsCredentials(cfg);
1927
- if (!creds) return {
1928
- ok: false,
1929
- error: "missing credentials (appId, appPassword, tenantId)"
1930
- };
1931
- try {
1932
- const { app } = await loadMSTeamsSdkWithAuth(creds, resolveMSTeamsSdkCloudOptions(cfg));
1933
- const tokenProvider = createMSTeamsTokenProvider(app);
1934
- if (!await tokenProvider.getAccessToken("https://api.botframework.com")) throw new Error("Failed to acquire bot token");
1935
- let graph;
1936
- try {
1937
- const accessToken = readAccessToken(await tokenProvider.getAccessToken("https://graph.microsoft.com"));
1938
- const payload = accessToken ? decodeJwtPayload(accessToken) : null;
1939
- graph = {
1940
- ok: true,
1941
- roles: readStringArray(payload?.roles),
1942
- scopes: readScopes(payload?.scp)
1943
- };
1944
- } catch (err) {
1945
- graph = {
1946
- ok: false,
1947
- error: formatUnknownError(err)
1948
- };
1949
- }
1950
- let delegatedAuth;
1951
- if (cfg?.delegatedAuth?.enabled) try {
1952
- const tokens = loadDelegatedTokens();
1953
- if (tokens) {
1954
- const isExpired = !isFutureDateTimestampMs(tokens.expiresAt);
1955
- delegatedAuth = {
1956
- ok: !isExpired,
1957
- scopes: tokens.scopes,
1958
- userPrincipalName: tokens.userPrincipalName,
1959
- ...isExpired ? { error: "token expired (will auto-refresh on next use)" } : {}
1960
- };
1961
- } else delegatedAuth = {
1962
- ok: false,
1963
- error: "no delegated tokens found (run setup wizard)"
1964
- };
1965
- } catch {
1966
- delegatedAuth = {
1967
- ok: false,
1968
- error: "failed to load delegated tokens"
1969
- };
1970
- }
1971
- return {
1972
- ok: true,
1973
- appId: creds.appId,
1974
- ...graph ? { graph } : {},
1975
- ...delegatedAuth ? { delegatedAuth } : {}
1976
- };
1977
- } catch (err) {
1978
- return {
1979
- ok: false,
1980
- appId: creds.appId,
1981
- error: formatUnknownError(err)
1982
- };
1405
+ });
1406
+ Object.defineProperty(exports, "getDriveItemProperties", {
1407
+ enumerable: true,
1408
+ get: function() {
1409
+ return getDriveItemProperties;
1983
1410
  }
1984
- }
1985
- //#endregion
1986
- export { buildFileInfoCard as _, sendMessageMSTeams as a, renderReplyPayloadsToMessages as c, withRevokedProxyFallback as d, resolveGraphChatId as f, removePendingUploadFs as g, getPendingUploadFs as h, sendAdaptiveCardMSTeams as i, sendMSTeamsMessages as l, removePendingUpload as m, deleteMessageMSTeams as n, sendPollMSTeams as o, getPendingUpload as p, editMessageMSTeams as r, buildConversationReference as s, probeMSTeams as t, sendMSTeamsActivityWithReference as u, parseFileConsentInvoke as v, uploadToConsentUrl as y };
1411
+ });
1412
+ Object.defineProperty(exports, "getMSTeamsReactionEmoji", {
1413
+ enumerable: true,
1414
+ get: function() {
1415
+ return getMSTeamsReactionEmoji;
1416
+ }
1417
+ });
1418
+ Object.defineProperty(exports, "getPendingUpload", {
1419
+ enumerable: true,
1420
+ get: function() {
1421
+ return getPendingUpload;
1422
+ }
1423
+ });
1424
+ Object.defineProperty(exports, "getPendingUploadFs", {
1425
+ enumerable: true,
1426
+ get: function() {
1427
+ return getPendingUploadFs;
1428
+ }
1429
+ });
1430
+ Object.defineProperty(exports, "parseFileConsentInvoke", {
1431
+ enumerable: true,
1432
+ get: function() {
1433
+ return parseFileConsentInvoke;
1434
+ }
1435
+ });
1436
+ Object.defineProperty(exports, "prepareFileConsentActivityFs", {
1437
+ enumerable: true,
1438
+ get: function() {
1439
+ return prepareFileConsentActivityFs;
1440
+ }
1441
+ });
1442
+ Object.defineProperty(exports, "removePendingUpload", {
1443
+ enumerable: true,
1444
+ get: function() {
1445
+ return removePendingUpload;
1446
+ }
1447
+ });
1448
+ Object.defineProperty(exports, "removePendingUploadFs", {
1449
+ enumerable: true,
1450
+ get: function() {
1451
+ return removePendingUploadFs;
1452
+ }
1453
+ });
1454
+ Object.defineProperty(exports, "renderReplyPayloadsToMessages", {
1455
+ enumerable: true,
1456
+ get: function() {
1457
+ return renderReplyPayloadsToMessages;
1458
+ }
1459
+ });
1460
+ Object.defineProperty(exports, "requireMSTeamsSharePointSiteId", {
1461
+ enumerable: true,
1462
+ get: function() {
1463
+ return requireMSTeamsSharePointSiteId;
1464
+ }
1465
+ });
1466
+ Object.defineProperty(exports, "requiresFileConsent", {
1467
+ enumerable: true,
1468
+ get: function() {
1469
+ return requiresFileConsent;
1470
+ }
1471
+ });
1472
+ Object.defineProperty(exports, "resolveMSTeamsReactionEmoji", {
1473
+ enumerable: true,
1474
+ get: function() {
1475
+ return resolveMSTeamsReactionEmoji;
1476
+ }
1477
+ });
1478
+ Object.defineProperty(exports, "sendMSTeamsActivityWithReference", {
1479
+ enumerable: true,
1480
+ get: function() {
1481
+ return sendMSTeamsActivityWithReference;
1482
+ }
1483
+ });
1484
+ Object.defineProperty(exports, "sendMSTeamsMessages", {
1485
+ enumerable: true,
1486
+ get: function() {
1487
+ return sendMSTeamsMessages;
1488
+ }
1489
+ });
1490
+ Object.defineProperty(exports, "setPendingUploadActivityId", {
1491
+ enumerable: true,
1492
+ get: function() {
1493
+ return setPendingUploadActivityId;
1494
+ }
1495
+ });
1496
+ Object.defineProperty(exports, "setPendingUploadActivityIdFs", {
1497
+ enumerable: true,
1498
+ get: function() {
1499
+ return setPendingUploadActivityIdFs;
1500
+ }
1501
+ });
1502
+ Object.defineProperty(exports, "stripHtmlFromTeamsMessage", {
1503
+ enumerable: true,
1504
+ get: function() {
1505
+ return stripHtmlFromTeamsMessage;
1506
+ }
1507
+ });
1508
+ Object.defineProperty(exports, "updateMSTeamsActivityWithReference", {
1509
+ enumerable: true,
1510
+ get: function() {
1511
+ return updateMSTeamsActivityWithReference;
1512
+ }
1513
+ });
1514
+ Object.defineProperty(exports, "uploadAndShareSharePoint", {
1515
+ enumerable: true,
1516
+ get: function() {
1517
+ return uploadAndShareSharePoint;
1518
+ }
1519
+ });
1520
+ Object.defineProperty(exports, "uploadToConsentUrl", {
1521
+ enumerable: true,
1522
+ get: function() {
1523
+ return uploadToConsentUrl;
1524
+ }
1525
+ });
1526
+ Object.defineProperty(exports, "withRevokedProxyFallback", {
1527
+ enumerable: true,
1528
+ get: function() {
1529
+ return withRevokedProxyFallback;
1530
+ }
1531
+ });