@openclaw/msteams 2026.7.1-beta.6 → 2026.7.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/api.cjs +8 -0
  2. package/dist/{channel-Cf5LJ4aO.js → channel-BSyPdpGN.cjs} +641 -227
  3. package/dist/channel-config-api.cjs +3 -0
  4. package/dist/channel-plugin-api.cjs +3 -0
  5. package/dist/channel.runtime-DQTOzzet.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-DtS9gqkV.cjs} +369 -861
  11. package/dist/{oauth-BifWxWzq.js → oauth-C5E5powI.cjs} +21 -21
  12. package/dist/{polls-B_hs4aKm.js → polls-BhoI4VaN.cjs} +188 -38
  13. package/dist/{resolve-allowlist-Dnw4aNOu.js → resolve-allowlist-CyQ57MfH.cjs} +817 -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-BDTPN3dX.cjs} +123 -49
  21. package/dist/{src-DZFs5XtZ.js → src-CUMz2B6f.cjs} +672 -740
  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-CyQ57MfH.cjs");
5
+ const require_setup_surface = require("./setup-surface-BDTPN3dX.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,10 @@ 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
586
- });
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
- };
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;
599
634
  }
600
635
  /**
601
636
  * Upload a file to a SharePoint site.
@@ -610,14 +645,14 @@ async function uploadToSharePoint(params) {
610
645
  const res = await fetchFn(`${GRAPH_ROOT}/sites/${params.siteId}/drive/root:${uploadPath}:/content`, {
611
646
  method: "PUT",
612
647
  headers: {
613
- "User-Agent": buildUserAgent(),
648
+ "User-Agent": require_resolve_allowlist.buildUserAgent(),
614
649
  Authorization: `Bearer ${token}`,
615
650
  "Content-Type": params.contentType ?? "application/octet-stream"
616
651
  },
617
652
  body: new Uint8Array(params.buffer)
618
653
  });
619
- if (!res.ok) throw await createMSTeamsHttpError(res, "SharePoint upload failed");
620
- const data = await readProviderJsonResponse(res, "msteams.graph-upload.uploadSharePointFile");
654
+ if (!res.ok) throw await require_resolve_allowlist.createMSTeamsHttpError(res, "SharePoint upload failed");
655
+ const data = await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.uploadSharePointFile");
621
656
  if (!data.id || !data.webUrl || !data.name) throw new Error("SharePoint upload response missing required fields");
622
657
  return {
623
658
  id: data.id,
@@ -636,11 +671,11 @@ async function getDriveItemProperties(params) {
636
671
  const fetchFn = params.fetchFn ?? fetch;
637
672
  const token = await params.tokenProvider.getAccessToken(GRAPH_SCOPE);
638
673
  const res = await fetchFn(`${GRAPH_ROOT}/sites/${params.siteId}/drive/items/${params.itemId}?$select=eTag,webDavUrl,name`, { headers: {
639
- "User-Agent": buildUserAgent(),
674
+ "User-Agent": require_resolve_allowlist.buildUserAgent(),
640
675
  Authorization: `Bearer ${token}`
641
676
  } });
642
- if (!res.ok) throw await createMSTeamsHttpError(res, "Get driveItem properties failed");
643
- const data = await readProviderJsonResponse(res, "msteams.graph-upload.getDriveItemProperties");
677
+ if (!res.ok) throw await require_resolve_allowlist.createMSTeamsHttpError(res, "Get driveItem properties failed");
678
+ const data = await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.getDriveItemProperties");
644
679
  if (!data.eTag || !data.webDavUrl || !data.name) throw new Error("DriveItem response missing required properties (eTag, webDavUrl, or name)");
645
680
  return {
646
681
  eTag: data.eTag,
@@ -649,34 +684,6 @@ async function getDriveItemProperties(params) {
649
684
  };
650
685
  }
651
686
  /**
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
687
  * Get members of a Teams chat for per-user sharing.
681
688
  * Used to create sharing links scoped to only the chat participants.
682
689
  */
@@ -684,14 +691,11 @@ async function getChatMembers(params) {
684
691
  const fetchFn = params.fetchFn ?? fetch;
685
692
  const token = await params.tokenProvider.getAccessToken(GRAPH_SCOPE);
686
693
  const res = await fetchFn(`${GRAPH_ROOT}/chats/${params.chatId}/members`, { headers: {
687
- "User-Agent": buildUserAgent(),
694
+ "User-Agent": require_resolve_allowlist.buildUserAgent(),
688
695
  Authorization: `Bearer ${token}`
689
696
  } });
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);
697
+ if (!res.ok) throw await require_resolve_allowlist.createMSTeamsHttpError(res, "Get chat members failed");
698
+ return ((await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.getChatMembers")).value ?? []).map((m) => ({ aadObjectId: m.userId ?? "" })).filter((m) => m.aadObjectId);
695
699
  }
696
700
  /**
697
701
  * Create a sharing link for a SharePoint drive item.
@@ -711,14 +715,14 @@ async function createSharePointSharingLink(params) {
711
715
  const res = await fetchFn(`${apiRoot}/sites/${params.siteId}/drive/items/${params.itemId}/createLink`, {
712
716
  method: "POST",
713
717
  headers: {
714
- "User-Agent": buildUserAgent(),
718
+ "User-Agent": require_resolve_allowlist.buildUserAgent(),
715
719
  Authorization: `Bearer ${token}`,
716
720
  "Content-Type": "application/json"
717
721
  },
718
722
  body: JSON.stringify(body)
719
723
  });
720
- if (!res.ok) throw await createMSTeamsHttpError(res, "Create SharePoint sharing link failed");
721
- const data = await readProviderJsonResponse(res, "msteams.graph-upload.createSharePointSharingLink");
724
+ if (!res.ok) throw await require_resolve_allowlist.createMSTeamsHttpError(res, "Create SharePoint sharing link failed");
725
+ const data = await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.createSharePointSharingLink");
722
726
  if (!data.link?.webUrl) throw new Error("Create SharePoint sharing link response missing webUrl");
723
727
  return { webUrl: data.link.webUrl };
724
728
  }
@@ -783,7 +787,7 @@ async function getMimeType(url) {
783
787
  const match = url.match(/^data:([^;,]+)/);
784
788
  if (match?.[1]) return match[1];
785
789
  }
786
- return await detectMime({ filePath: url }) ?? "application/octet-stream";
790
+ return await (0, openclaw_plugin_sdk_media_runtime.detectMime)({ filePath: url }) ?? "application/octet-stream";
787
791
  }
788
792
  /**
789
793
  * Extract filename from URL or local path.
@@ -793,20 +797,20 @@ async function getMimeType(url) {
793
797
  async function extractFilename(url) {
794
798
  if (url.startsWith("data:")) {
795
799
  const mime = await getMimeType(url);
796
- const ext = extensionForMime(mime) ?? ".bin";
800
+ const ext = (0, openclaw_plugin_sdk_media_runtime.extensionForMime)(mime) ?? ".bin";
797
801
  return `${mime.startsWith("image/") ? "image" : "file"}${ext}`;
798
802
  }
799
803
  try {
800
804
  const pathname = new URL(url).pathname;
801
- const basename = path.basename(pathname);
802
- const existingExt = getFileExtension(pathname);
805
+ const basename = node_path.default.basename(pathname);
806
+ const existingExt = (0, openclaw_plugin_sdk_media_runtime.getFileExtension)(pathname);
803
807
  if (basename && existingExt) return basename;
804
808
  const mime = await getMimeType(url);
805
- const ext = extensionForMime(mime) ?? ".bin";
809
+ const ext = (0, openclaw_plugin_sdk_media_runtime.extensionForMime)(mime) ?? ".bin";
806
810
  const prefix = mime.startsWith("image/") ? "image" : "file";
807
811
  return basename ? `${basename}${ext}` : `${prefix}${ext}`;
808
812
  } catch {
809
- return extractOriginalFilename(url);
813
+ return (0, openclaw_plugin_sdk_media_runtime.extractOriginalFilename)(url);
810
814
  }
811
815
  }
812
816
  /**
@@ -883,21 +887,21 @@ async function withRevokedProxyFallback(params) {
883
887
  try {
884
888
  return await params.run();
885
889
  } catch (err) {
886
- if (!isRevokedProxyError(err)) throw err;
890
+ if (!require_setup_surface.isRevokedProxyError(err)) throw err;
887
891
  params.onRevokedLog?.();
888
892
  return await params.onRevoked();
889
893
  }
890
894
  }
891
895
  //#endregion
892
896
  //#region extensions/msteams/src/sdk-proactive.ts
893
- const loadMSTeamsApiModule = createLazyRuntimeModule(() => import("@microsoft/teams.api"));
897
+ const loadMSTeamsApiModule = (0, openclaw_plugin_sdk_lazy_runtime.createLazyRuntimeModule)(() => import("@microsoft/teams.api"));
894
898
  function resolveThreadedConversationId(conversationId, threadActivityId) {
895
899
  if (!threadActivityId) return conversationId.split(";")[0] ?? conversationId;
896
900
  return `${conversationId.split(";")[0] ?? conversationId};messageid=${threadActivityId}`;
897
901
  }
898
902
  function normalizeRequiredServiceUrl(ref) {
899
903
  if (!ref.serviceUrl) throw new Error("Invalid stored reference: missing serviceUrl");
900
- return normalizeBotFrameworkServiceUrl(ref.serviceUrl);
904
+ return require_resolve_allowlist.normalizeBotFrameworkServiceUrl(ref.serviceUrl);
901
905
  }
902
906
  function buildSdkConversationReference(source, options) {
903
907
  const bot = source.agent ?? source.bot ?? void 0;
@@ -905,7 +909,7 @@ function buildSdkConversationReference(source, options) {
905
909
  const conversationId = resolveThreadedConversationId(source.conversation.id, options?.threadActivityId);
906
910
  const tenantId = source.tenantId ?? source.conversation.tenantId;
907
911
  const serviceUrl = normalizeRequiredServiceUrl(source);
908
- if (options?.serviceUrlBoundary) validateMSTeamsProactiveServiceUrlBoundary({
912
+ if (options?.serviceUrlBoundary) require_resolve_allowlist.validateMSTeamsProactiveServiceUrlBoundary({
909
913
  cloud: options.serviceUrlBoundary.cloud,
910
914
  conversationId,
911
915
  storedServiceUrl: serviceUrl,
@@ -938,7 +942,7 @@ function getStructuralApiClient(app) {
938
942
  function sameServiceUrl(left, right) {
939
943
  if (!left) return false;
940
944
  try {
941
- return normalizeBotFrameworkServiceUrl(left) === right;
945
+ return require_resolve_allowlist.normalizeBotFrameworkServiceUrl(left) === right;
942
946
  } catch {
943
947
  return false;
944
948
  }
@@ -1026,14 +1030,14 @@ const AI_GENERATED_ENTITY = {
1026
1030
  //#region extensions/msteams/src/messenger.ts
1027
1031
  /**
1028
1032
  * MSTeams-specific media size limit (100MB).
1029
- * Higher than the default because OneDrive upload handles large files well.
1033
+ * Higher than the default to support Teams file-consent and SharePoint uploads.
1030
1034
  */
1031
- const MSTEAMS_MAX_MEDIA_BYTES$1 = 100 * 1024 * 1024;
1035
+ const MSTEAMS_MAX_MEDIA_BYTES = 100 * 1024 * 1024;
1032
1036
  /**
1033
1037
  * Threshold for large files that require FileConsentCard flow in personal chats.
1034
1038
  * Files >= 4MB use consent flow; smaller images can use inline base64.
1035
1039
  */
1036
- const FILE_CONSENT_THRESHOLD_BYTES$1 = 4 * 1024 * 1024;
1040
+ const FILE_CONSENT_THRESHOLD_BYTES = 4 * 1024 * 1024;
1037
1041
  function normalizeConversationId(rawId) {
1038
1042
  return rawId.split(";")[0] ?? rawId;
1039
1043
  }
@@ -1068,15 +1072,15 @@ function buildConversationReference(ref) {
1068
1072
  function pushTextMessages(out, text, opts) {
1069
1073
  if (!text) return;
1070
1074
  if (opts.chunkText) {
1071
- for (const chunk of getMSTeamsRuntime().channel.text.chunkMarkdownTextWithMode(text, opts.chunkLimit, opts.chunkMode)) {
1075
+ for (const chunk of require_runtime.getMSTeamsRuntime().channel.text.chunkMarkdownTextWithMode(text, opts.chunkLimit, opts.chunkMode)) {
1072
1076
  const trimmed = chunk.trim();
1073
- if (!trimmed || isSilentReplyText(trimmed, SILENT_REPLY_TOKEN)) continue;
1077
+ if (!trimmed || (0, openclaw_plugin_sdk_reply_chunking.isSilentReplyText)(trimmed, openclaw_plugin_sdk_reply_chunking.SILENT_REPLY_TOKEN)) continue;
1074
1078
  out.push({ text: trimmed });
1075
1079
  }
1076
1080
  return;
1077
1081
  }
1078
1082
  const trimmed = text.trim();
1079
- if (!trimmed || isSilentReplyText(trimmed, SILENT_REPLY_TOKEN)) return;
1083
+ if (!trimmed || (0, openclaw_plugin_sdk_reply_chunking.isSilentReplyText)(trimmed, openclaw_plugin_sdk_reply_chunking.SILENT_REPLY_TOKEN)) return;
1080
1084
  out.push({ text: trimmed });
1081
1085
  }
1082
1086
  function clampMs(value, maxMs) {
@@ -1110,12 +1114,12 @@ function renderReplyPayloadsToMessages(replies, options) {
1110
1114
  const chunkText = options.chunkText !== false;
1111
1115
  const chunkMode = options.chunkMode ?? "length";
1112
1116
  const mediaMode = options.mediaMode ?? "split";
1113
- const tableMode = options.tableMode ?? getMSTeamsRuntime().channel.text.resolveMarkdownTableMode({
1114
- cfg: getMSTeamsRuntime().config.current(),
1117
+ const tableMode = options.tableMode ?? require_runtime.getMSTeamsRuntime().channel.text.resolveMarkdownTableMode({
1118
+ cfg: require_runtime.getMSTeamsRuntime().config.current(),
1115
1119
  channel: "msteams"
1116
1120
  });
1117
1121
  for (const payload of replies) {
1118
- const reply = resolveSendableOutboundReplyParts(payload, { text: getMSTeamsRuntime().channel.text.convertMarkdownTables(payload.text ?? "", tableMode) });
1122
+ const reply = (0, openclaw_plugin_sdk_reply_payload.resolveSendableOutboundReplyParts)(payload, { text: require_runtime.getMSTeamsRuntime().channel.text.convertMarkdownTables(payload.text ?? "", tableMode) });
1119
1123
  if (!reply.hasContent) continue;
1120
1124
  if (!reply.hasMedia) {
1121
1125
  pushTextMessages(out, reply.text, {
@@ -1165,18 +1169,18 @@ async function buildActivity(msg, conversationRef, tokenProvider, sharePointSite
1165
1169
  let contentType = await getMimeType(msg.mediaUrl);
1166
1170
  let fileName = await extractFilename(msg.mediaUrl);
1167
1171
  if (isLocalPath(msg.mediaUrl)) {
1168
- const maxBytes = mediaMaxBytes ?? MSTEAMS_MAX_MEDIA_BYTES$1;
1169
- const media = await loadWebMedia(msg.mediaUrl, maxBytes);
1172
+ const maxBytes = mediaMaxBytes ?? MSTEAMS_MAX_MEDIA_BYTES;
1173
+ const media = await (0, openclaw_plugin_sdk_web_media.loadWebMedia)(msg.mediaUrl, maxBytes);
1170
1174
  contentType = media.contentType ?? contentType;
1171
1175
  fileName = media.fileName ?? fileName;
1172
- const conversationType = normalizeOptionalLowercaseString(conversationRef.conversation?.conversationType);
1176
+ const conversationType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(conversationRef.conversation?.conversationType);
1173
1177
  const isPersonal = conversationType === "personal";
1174
1178
  const isImage = media.kind === "image";
1175
1179
  if (requiresFileConsent({
1176
1180
  conversationType,
1177
1181
  contentType,
1178
1182
  bufferSize: media.buffer.length,
1179
- thresholdBytes: FILE_CONSENT_THRESHOLD_BYTES$1
1183
+ thresholdBytes: FILE_CONSENT_THRESHOLD_BYTES
1180
1184
  })) {
1181
1185
  const conversationId = conversationRef.conversation?.id ?? "unknown";
1182
1186
  const { activity: consentActivity, uploadId } = prepareFileConsentActivity({
@@ -1191,16 +1195,18 @@ async function buildActivity(msg, conversationRef, tokenProvider, sharePointSite
1191
1195
  consentActivity["_pendingUploadId"] = uploadId;
1192
1196
  return consentActivity;
1193
1197
  }
1194
- if (!isPersonal && !isImage && tokenProvider && sharePointSiteId) {
1195
- const chatId = conversationRef.graphChatId ?? conversationRef.conversation?.id;
1198
+ if (!isPersonal && !isImage) {
1199
+ const siteId = requireMSTeamsSharePointSiteId(sharePointSiteId);
1200
+ if (!tokenProvider) throw new Error("MS Teams Graph token provider unavailable for SharePoint file send");
1201
+ const chatId = conversationRef.conversation?.id;
1196
1202
  activity.attachments = [buildTeamsFileInfoCard(await getDriveItemProperties({
1197
- siteId: sharePointSiteId,
1203
+ siteId,
1198
1204
  itemId: (await uploadAndShareSharePoint({
1199
1205
  buffer: media.buffer,
1200
1206
  filename: fileName,
1201
1207
  contentType,
1202
1208
  tokenProvider,
1203
- siteId: sharePointSiteId,
1209
+ siteId,
1204
1210
  chatId: chatId ?? void 0,
1205
1211
  usePerUserSharing: conversationType === "groupchat"
1206
1212
  })).itemId,
@@ -1208,18 +1214,6 @@ async function buildActivity(msg, conversationRef, tokenProvider, sharePointSite
1208
1214
  }))];
1209
1215
  return activity;
1210
1216
  }
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
1217
  const base64 = media.buffer.toString("base64");
1224
1218
  contentUrl = `data:${media.contentType};base64,${base64}`;
1225
1219
  }
@@ -1240,7 +1234,7 @@ async function sendMSTeamsMessages(params) {
1240
1234
  for (const attempt of Array.from({ length: retryOptions.maxAttempts }, (_, index) => index + 1)) try {
1241
1235
  return await sendOnce();
1242
1236
  } catch (err) {
1243
- const classification = classifyMSTeamsSendError(err);
1237
+ const classification = require_setup_surface.classifyMSTeamsSendError(err);
1244
1238
  if (!(attempt < retryOptions.maxAttempts && shouldRetry(classification))) throw err;
1245
1239
  const delayMs = computeRetryDelayMs(attempt, classification, retryOptions);
1246
1240
  const nextAttempt = attempt + 1;
@@ -1252,7 +1246,7 @@ async function sendMSTeamsMessages(params) {
1252
1246
  delayMs,
1253
1247
  classification
1254
1248
  });
1255
- await sleep(delayMs);
1249
+ await (0, openclaw_plugin_sdk_text_utility_runtime.sleep)(delayMs);
1256
1250
  }
1257
1251
  throw new Error("unreachable Teams send retry loop exit");
1258
1252
  };
@@ -1312,675 +1306,189 @@ async function sendMSTeamsMessages(params) {
1312
1306
  return await sendProactively(messages, 0);
1313
1307
  }
1314
1308
  //#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;
1309
+ Object.defineProperty(exports, "buildConversationReference", {
1310
+ enumerable: true,
1311
+ get: function() {
1312
+ return buildConversationReference;
1366
1313
  }
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.`);
1314
+ });
1315
+ Object.defineProperty(exports, "buildFileInfoCard", {
1316
+ enumerable: true,
1317
+ get: function() {
1318
+ return buildFileInfoCard;
1398
1319
  }
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.`);
1320
+ });
1321
+ Object.defineProperty(exports, "buildTeamsFileInfoCard", {
1322
+ enumerable: true,
1323
+ get: function() {
1324
+ return buildTeamsFileInfoCard;
1406
1325
  }
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;
1326
+ });
1327
+ Object.defineProperty(exports, "deleteMSTeamsActivityWithReference", {
1328
+ enumerable: true,
1329
+ get: function() {
1330
+ return deleteMSTeamsActivityWithReference;
1451
1331
  }
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
- }
1332
+ });
1333
+ Object.defineProperty(exports, "extractFilename", {
1334
+ enumerable: true,
1335
+ get: function() {
1336
+ return extractFilename;
1686
1337
  }
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 });
1338
+ });
1339
+ Object.defineProperty(exports, "extractMessageId", {
1340
+ enumerable: true,
1341
+ get: function() {
1342
+ return extractMessageId;
1722
1343
  }
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 });
1344
+ });
1345
+ Object.defineProperty(exports, "fetchChannelMessage", {
1346
+ enumerable: true,
1347
+ get: function() {
1348
+ return fetchChannelMessage;
1754
1349
  }
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 });
1350
+ });
1351
+ Object.defineProperty(exports, "fetchChatMessageText", {
1352
+ enumerable: true,
1353
+ get: function() {
1354
+ return fetchChatMessageText;
1863
1355
  }
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 });
1356
+ });
1357
+ Object.defineProperty(exports, "fetchThreadReplies", {
1358
+ enumerable: true,
1359
+ get: function() {
1360
+ return fetchThreadReplies;
1893
1361
  }
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;
1362
+ });
1363
+ Object.defineProperty(exports, "formatThreadContext", {
1364
+ enumerable: true,
1365
+ get: function() {
1366
+ return formatThreadContext;
1913
1367
  }
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
- };
1368
+ });
1369
+ Object.defineProperty(exports, "getDriveItemProperties", {
1370
+ enumerable: true,
1371
+ get: function() {
1372
+ return getDriveItemProperties;
1983
1373
  }
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 };
1374
+ });
1375
+ Object.defineProperty(exports, "getMSTeamsReactionEmoji", {
1376
+ enumerable: true,
1377
+ get: function() {
1378
+ return getMSTeamsReactionEmoji;
1379
+ }
1380
+ });
1381
+ Object.defineProperty(exports, "getPendingUpload", {
1382
+ enumerable: true,
1383
+ get: function() {
1384
+ return getPendingUpload;
1385
+ }
1386
+ });
1387
+ Object.defineProperty(exports, "getPendingUploadFs", {
1388
+ enumerable: true,
1389
+ get: function() {
1390
+ return getPendingUploadFs;
1391
+ }
1392
+ });
1393
+ Object.defineProperty(exports, "parseFileConsentInvoke", {
1394
+ enumerable: true,
1395
+ get: function() {
1396
+ return parseFileConsentInvoke;
1397
+ }
1398
+ });
1399
+ Object.defineProperty(exports, "prepareFileConsentActivityFs", {
1400
+ enumerable: true,
1401
+ get: function() {
1402
+ return prepareFileConsentActivityFs;
1403
+ }
1404
+ });
1405
+ Object.defineProperty(exports, "removePendingUpload", {
1406
+ enumerable: true,
1407
+ get: function() {
1408
+ return removePendingUpload;
1409
+ }
1410
+ });
1411
+ Object.defineProperty(exports, "removePendingUploadFs", {
1412
+ enumerable: true,
1413
+ get: function() {
1414
+ return removePendingUploadFs;
1415
+ }
1416
+ });
1417
+ Object.defineProperty(exports, "renderReplyPayloadsToMessages", {
1418
+ enumerable: true,
1419
+ get: function() {
1420
+ return renderReplyPayloadsToMessages;
1421
+ }
1422
+ });
1423
+ Object.defineProperty(exports, "requireMSTeamsSharePointSiteId", {
1424
+ enumerable: true,
1425
+ get: function() {
1426
+ return requireMSTeamsSharePointSiteId;
1427
+ }
1428
+ });
1429
+ Object.defineProperty(exports, "requiresFileConsent", {
1430
+ enumerable: true,
1431
+ get: function() {
1432
+ return requiresFileConsent;
1433
+ }
1434
+ });
1435
+ Object.defineProperty(exports, "resolveMSTeamsReactionEmoji", {
1436
+ enumerable: true,
1437
+ get: function() {
1438
+ return resolveMSTeamsReactionEmoji;
1439
+ }
1440
+ });
1441
+ Object.defineProperty(exports, "sendMSTeamsActivityWithReference", {
1442
+ enumerable: true,
1443
+ get: function() {
1444
+ return sendMSTeamsActivityWithReference;
1445
+ }
1446
+ });
1447
+ Object.defineProperty(exports, "sendMSTeamsMessages", {
1448
+ enumerable: true,
1449
+ get: function() {
1450
+ return sendMSTeamsMessages;
1451
+ }
1452
+ });
1453
+ Object.defineProperty(exports, "setPendingUploadActivityId", {
1454
+ enumerable: true,
1455
+ get: function() {
1456
+ return setPendingUploadActivityId;
1457
+ }
1458
+ });
1459
+ Object.defineProperty(exports, "setPendingUploadActivityIdFs", {
1460
+ enumerable: true,
1461
+ get: function() {
1462
+ return setPendingUploadActivityIdFs;
1463
+ }
1464
+ });
1465
+ Object.defineProperty(exports, "stripHtmlFromTeamsMessage", {
1466
+ enumerable: true,
1467
+ get: function() {
1468
+ return stripHtmlFromTeamsMessage;
1469
+ }
1470
+ });
1471
+ Object.defineProperty(exports, "updateMSTeamsActivityWithReference", {
1472
+ enumerable: true,
1473
+ get: function() {
1474
+ return updateMSTeamsActivityWithReference;
1475
+ }
1476
+ });
1477
+ Object.defineProperty(exports, "uploadAndShareSharePoint", {
1478
+ enumerable: true,
1479
+ get: function() {
1480
+ return uploadAndShareSharePoint;
1481
+ }
1482
+ });
1483
+ Object.defineProperty(exports, "uploadToConsentUrl", {
1484
+ enumerable: true,
1485
+ get: function() {
1486
+ return uploadToConsentUrl;
1487
+ }
1488
+ });
1489
+ Object.defineProperty(exports, "withRevokedProxyFallback", {
1490
+ enumerable: true,
1491
+ get: function() {
1492
+ return withRevokedProxyFallback;
1493
+ }
1494
+ });