@openclaw/msteams 2026.9.5 → 2026.9.7
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.
- package/assets/icon.png +0 -0
- package/dist/.setup/{adapter.runtime-ChuVK6k_.cjs → adapter.runtime-BiWeMKXE.cjs} +24 -30
- package/dist/.setup/{approval-card-CPNH_q3P.cjs → approval-card-DWPDItvq.cjs} +6 -3
- package/dist/.setup/{approval-handler.runtime-DDxGPJDz.cjs → approval-handler.runtime-D1s7UR3U.cjs} +4 -4
- package/dist/.setup/bot-framework-service-url-BUhTe8F3.cjs +55 -0
- package/dist/.setup/{channel-Dzpbbht8.cjs → channel-ByzS7QJ0.cjs} +338 -220
- package/dist/.setup/{channel.runtime-TE49QvFv.cjs → channel.runtime-Baz8XDFs.cjs} +47 -144
- package/dist/.setup/{channel.setup-BVDfgdCc.cjs → channel.setup-DL8lcWT_.cjs} +6 -6
- package/dist/.setup/{config-schema-D22Lr1Qk.cjs → config-schema-0KoBzb0t.cjs} +24 -38
- package/dist/.setup/{messenger-BR1l4zw-.cjs → conversation-store-state-B7JuyZTm.cjs} +697 -297
- package/dist/.setup/{src-CpKfpP1m.cjs → monitor-BJ7IyH4y.cjs} +440 -663
- package/dist/.setup/{oauth-C6m7dvHj.cjs → oauth-DQjOnJ4l.cjs} +1 -1
- package/dist/.setup/{reaction-types-C7RA7Wxt.cjs → reaction-types-CQ4oSUe7.cjs} +2 -6
- package/dist/.setup/{resolve-allowlist-CHzaaWiC.cjs → resolve-allowlist-Pl_NQFYH.cjs} +55 -312
- package/dist/.setup/{rolldown-runtime-VH7oDXx4.cjs → rolldown-runtime-BloeesfJ.cjs} +22 -0
- package/dist/.setup/{send-D8ATH4QI.cjs → send-VUM7Sryb.cjs} +47 -97
- package/dist/.setup/{setup-plugin-api-DpiaA8z1.cjs → setup-plugin-api-Dyf8kF-l.cjs} +1 -1
- package/dist/.setup/{thread-session-CXgHK-yi.cjs → thread-session--rw3BTal.cjs} +2 -5
- package/dist/api.cjs +2 -2
- package/dist/channel-config-api.cjs +1 -1
- package/dist/channel-plugin-api.cjs +1 -1
- package/dist/configured-state.cjs +0 -1
- package/dist/directory-contract-api.cjs +1 -1
- package/dist/doctor-contract-api.cjs +201 -371
- package/dist/qa-runner-api.cjs +1 -1
- package/dist/runtime-api.cjs +0 -6
- package/dist/setup-entry.cjs +1 -1
- package/dist/setup-plugin-api.cjs +1 -1
- package/openclaw.plugin.json +46 -5
- package/package.json +10 -10
- package/dist/.setup/polls-BJ4-4uZm.cjs +0 -668
- package/dist/.setup/secret-input-C65t6kjM.cjs +0 -1
- package/dist/.setup/sso-token-store-YYLHXgFH.cjs +0 -111
|
@@ -1,44 +1,40 @@
|
|
|
1
|
-
const require_rolldown_runtime = require("./rolldown-runtime-
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-BloeesfJ.cjs");
|
|
2
2
|
const require_runtime = require("./runtime-gZTAuFux.cjs");
|
|
3
3
|
require("../runtime-api.cjs");
|
|
4
|
-
const require_resolve_allowlist = require("./resolve-allowlist-
|
|
5
|
-
const
|
|
6
|
-
const
|
|
4
|
+
const require_resolve_allowlist = require("./resolve-allowlist-Pl_NQFYH.cjs");
|
|
5
|
+
const require_bot_framework_service_url = require("./bot-framework-service-url-BUhTe8F3.cjs");
|
|
6
|
+
const require_channel_setup = require("./channel.setup-DL8lcWT_.cjs");
|
|
7
7
|
let openclaw_plugin_sdk_lazy_runtime = require("openclaw/plugin-sdk/lazy-runtime");
|
|
8
8
|
let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
|
|
9
9
|
let openclaw_plugin_sdk_fetch_runtime = require("openclaw/plugin-sdk/fetch-runtime");
|
|
10
10
|
let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
|
|
11
|
+
let openclaw_plugin_sdk_file_lock = require("openclaw/plugin-sdk/file-lock");
|
|
11
12
|
let openclaw_plugin_sdk_reply_payload = require("openclaw/plugin-sdk/reply-payload");
|
|
12
13
|
let openclaw_plugin_sdk_ssrf_runtime = require("openclaw/plugin-sdk/ssrf-runtime");
|
|
13
14
|
let openclaw_plugin_sdk_text_chunking = require("openclaw/plugin-sdk/text-chunking");
|
|
14
15
|
let node_dns_promises = require("node:dns/promises");
|
|
15
16
|
let openclaw_plugin_sdk_ssrf_policy = require("openclaw/plugin-sdk/ssrf-policy");
|
|
17
|
+
let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
|
|
16
18
|
let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text-utility-runtime");
|
|
17
19
|
let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
|
|
18
20
|
let openclaw_plugin_sdk_retry_runtime = require("openclaw/plugin-sdk/retry-runtime");
|
|
19
|
-
let node_crypto = require("node:crypto");
|
|
20
|
-
node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
|
|
21
21
|
let node_path = require("node:path");
|
|
22
22
|
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
23
23
|
let openclaw_plugin_sdk_runtime_env = require("openclaw/plugin-sdk/runtime-env");
|
|
24
24
|
let openclaw_plugin_sdk_markdown_table_runtime = require("openclaw/plugin-sdk/markdown-table-runtime");
|
|
25
25
|
let openclaw_plugin_sdk_blob_runtime = require("openclaw/plugin-sdk/blob-runtime");
|
|
26
|
+
let node_crypto = require("node:crypto");
|
|
27
|
+
node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
|
|
28
|
+
let openclaw_plugin_sdk_keyed_async_queue = require("openclaw/plugin-sdk/keyed-async-queue");
|
|
26
29
|
let openclaw_plugin_sdk_global_singleton = require("openclaw/plugin-sdk/global-singleton");
|
|
27
30
|
let openclaw_plugin_sdk_expect_runtime = require("openclaw/plugin-sdk/expect-runtime");
|
|
28
31
|
let openclaw_plugin_sdk_reply_chunking = require("openclaw/plugin-sdk/reply-chunking");
|
|
29
32
|
let openclaw_plugin_sdk_web_media = require("openclaw/plugin-sdk/web-media");
|
|
33
|
+
let openclaw_plugin_sdk_dedupe_runtime = require("openclaw/plugin-sdk/dedupe-runtime");
|
|
34
|
+
let openclaw_plugin_sdk_plugin_state_runtime = require("openclaw/plugin-sdk/plugin-state-runtime");
|
|
30
35
|
let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runtime");
|
|
31
36
|
//#region extensions/msteams/src/file-consent.ts
|
|
32
37
|
/**
|
|
33
|
-
* FileConsentCard utilities for MS Teams large file uploads (>4MB) in personal chats.
|
|
34
|
-
*
|
|
35
|
-
* Teams requires user consent before the bot can upload large files. This module provides
|
|
36
|
-
* utilities for:
|
|
37
|
-
* - Building FileConsentCard attachments (to request upload permission)
|
|
38
|
-
* - Building FileInfoCard attachments (to confirm upload completion)
|
|
39
|
-
* - Parsing fileConsent/invoke activities
|
|
40
|
-
*/
|
|
41
|
-
/**
|
|
42
38
|
* Allowlist of domains that are valid targets for file consent uploads.
|
|
43
39
|
* These are the Microsoft/SharePoint domains that Teams legitimately provides
|
|
44
40
|
* as upload destinations in the FileConsentCard flow.
|
|
@@ -58,11 +54,6 @@ const CONSENT_UPLOAD_HOST_ALLOWLIST = [
|
|
|
58
54
|
"graph.microsoft.cn"
|
|
59
55
|
];
|
|
60
56
|
/**
|
|
61
|
-
* Returns true if the given IPv4 or IPv6 address is private, internal, or
|
|
62
|
-
* special-use and must never be reached via consent uploads.
|
|
63
|
-
*/
|
|
64
|
-
const isPrivateOrReservedIP = openclaw_plugin_sdk_ssrf_policy.isPrivateIpAddress;
|
|
65
|
-
/**
|
|
66
57
|
* Validate that a consent upload URL is safe to PUT to.
|
|
67
58
|
* Checks:
|
|
68
59
|
* 1. Protocol is HTTPS
|
|
@@ -89,7 +80,7 @@ async function validateConsentUploadUrl(url, opts) {
|
|
|
89
80
|
} catch {
|
|
90
81
|
throw new Error(`Failed to resolve consent upload URL hostname "${hostname}"`);
|
|
91
82
|
}
|
|
92
|
-
for (const entry of resolved) if (
|
|
83
|
+
for (const entry of resolved) if ((0, openclaw_plugin_sdk_ssrf_policy.isPrivateIpAddress)(entry.address)) throw new Error(`Consent upload URL resolves to a private/reserved IP (${entry.address})`);
|
|
93
84
|
}
|
|
94
85
|
/**
|
|
95
86
|
* Build a FileConsentCard attachment for requesting upload permission.
|
|
@@ -164,6 +155,47 @@ async function uploadToConsentUrl(params) {
|
|
|
164
155
|
if (!res.ok) throw new Error(`File upload to consent URL failed: ${res.status} ${res.statusText}`);
|
|
165
156
|
}
|
|
166
157
|
//#endregion
|
|
158
|
+
//#region extensions/msteams/src/sqlite-state.ts
|
|
159
|
+
function resolveStateDirOverride(options) {
|
|
160
|
+
if (!options) return;
|
|
161
|
+
if (options.stateDir) return options.stateDir;
|
|
162
|
+
if (options.storePath) return node_path.default.dirname(options.storePath);
|
|
163
|
+
if (options.homedir) return require_runtime.getMSTeamsRuntime().state.resolveStateDir(options.env ?? process.env, options.homedir);
|
|
164
|
+
return options.env?.OPENCLAW_STATE_DIR?.trim() || void 0;
|
|
165
|
+
}
|
|
166
|
+
function resolveMSTeamsSqliteStateEnv(options) {
|
|
167
|
+
const stateDir = resolveStateDirOverride(options);
|
|
168
|
+
if (!stateDir) return options?.env;
|
|
169
|
+
return {
|
|
170
|
+
...options?.env ?? process.env,
|
|
171
|
+
OPENCLAW_STATE_DIR: stateDir
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function toPluginJsonValue(value) {
|
|
175
|
+
const serialized = JSON.stringify(value);
|
|
176
|
+
return JSON.parse(serialized);
|
|
177
|
+
}
|
|
178
|
+
function resolveMSTeamsSqliteStateDir(options) {
|
|
179
|
+
return resolveStateDirOverride(options) ?? require_runtime.getMSTeamsRuntime().state.resolveStateDir(options?.env ?? process.env, options?.homedir);
|
|
180
|
+
}
|
|
181
|
+
const sqliteMutationLocks = new openclaw_plugin_sdk_keyed_async_queue.KeyedAsyncQueue();
|
|
182
|
+
const MSTEAMS_MUTATION_LOCK_OPTIONS = {
|
|
183
|
+
retries: {
|
|
184
|
+
retries: 10,
|
|
185
|
+
factor: 2,
|
|
186
|
+
minTimeout: 100,
|
|
187
|
+
maxTimeout: 1e4,
|
|
188
|
+
randomize: true
|
|
189
|
+
},
|
|
190
|
+
stale: 3e4
|
|
191
|
+
};
|
|
192
|
+
async function withMSTeamsSqliteMutationLock(options, mutationKey, fn) {
|
|
193
|
+
const scopedMutationKey = node_path.default.join(resolveMSTeamsSqliteStateDir(options), mutationKey);
|
|
194
|
+
return await sqliteMutationLocks.enqueue(scopedMutationKey, async () => {
|
|
195
|
+
return await (0, openclaw_plugin_sdk_file_lock.withFileLock)(scopedMutationKey, MSTEAMS_MUTATION_LOCK_OPTIONS, fn);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
//#endregion
|
|
167
199
|
//#region extensions/msteams/src/pending-uploads-fs.ts
|
|
168
200
|
/** TTL for persisted pending uploads (matches in-memory store). */
|
|
169
201
|
const PENDING_UPLOAD_TTL_MS$1 = 3e5;
|
|
@@ -180,14 +212,14 @@ function createMetaStore(options) {
|
|
|
180
212
|
return require_runtime.getMSTeamsRuntime().state.openKeyedStore({
|
|
181
213
|
namespace: PENDING_UPLOAD_META_NAMESPACE,
|
|
182
214
|
maxEntries: PENDING_UPLOAD_META_MAX_ENTRIES,
|
|
183
|
-
env:
|
|
215
|
+
env: resolveMSTeamsSqliteStateEnv(options)
|
|
184
216
|
});
|
|
185
217
|
}
|
|
186
218
|
function createChunkStore(options) {
|
|
187
219
|
return require_runtime.getMSTeamsRuntime().state.openKeyedStore({
|
|
188
220
|
namespace: PENDING_UPLOAD_CHUNKS_NAMESPACE,
|
|
189
221
|
maxEntries: MAX_PENDING_UPLOAD_CHUNK_ROWS,
|
|
190
|
-
env:
|
|
222
|
+
env: resolveMSTeamsSqliteStateEnv(options)
|
|
191
223
|
});
|
|
192
224
|
}
|
|
193
225
|
function buildUploadKey(id) {
|
|
@@ -217,22 +249,21 @@ async function deleteUploadRows(id, metaStore, chunkStore) {
|
|
|
217
249
|
const chunkCount = existing.chunkCount;
|
|
218
250
|
for (let index = 0; index < chunkCount; index += 1) await chunkStore.delete(buildChunkKey(id, index));
|
|
219
251
|
}
|
|
220
|
-
async function registerUploadRows(record, metaStore, chunkStore, ttlMs
|
|
221
|
-
const buffer = Buffer.from(record.
|
|
252
|
+
async function registerUploadRows(record, metaStore, chunkStore, ttlMs) {
|
|
253
|
+
const buffer = Buffer.from(record.buffer);
|
|
222
254
|
const chunkCount = Math.max(1, Math.ceil(buffer.byteLength / RAW_CHUNK_BYTES));
|
|
223
255
|
if (chunkCount > MAX_CHUNKS_PER_UPLOAD) throw new Error(`Microsoft Teams pending upload ${record.id} exceeds SQLite chunk limit (${chunkCount}/${MAX_CHUNKS_PER_UPLOAD})`);
|
|
224
|
-
|
|
225
|
-
else if (await metaStore.lookup(buildMetaKey(record.id))) return;
|
|
256
|
+
await deleteUploadRows(record.id, metaStore, chunkStore);
|
|
226
257
|
await pruneUploadStore(metaStore, chunkStore, ttlMs, chunkCount);
|
|
227
258
|
for (let index = 0; index < chunkCount; index += 1) {
|
|
228
259
|
const chunk = buffer.subarray(index * RAW_CHUNK_BYTES, (index + 1) * RAW_CHUNK_BYTES);
|
|
229
|
-
await chunkStore.register(buildChunkKey(record.id, index),
|
|
260
|
+
await chunkStore.register(buildChunkKey(record.id, index), toPluginJsonValue({
|
|
230
261
|
id: record.id,
|
|
231
262
|
index,
|
|
232
263
|
dataBase64: chunk.toString("base64")
|
|
233
264
|
}));
|
|
234
265
|
}
|
|
235
|
-
await metaStore.register(buildMetaKey(record.id),
|
|
266
|
+
await metaStore.register(buildMetaKey(record.id), toPluginJsonValue({
|
|
236
267
|
id: record.id,
|
|
237
268
|
filename: record.filename,
|
|
238
269
|
contentType: record.contentType,
|
|
@@ -244,7 +275,7 @@ async function registerUploadRows(record, metaStore, chunkStore, ttlMs, overwrit
|
|
|
244
275
|
}));
|
|
245
276
|
}
|
|
246
277
|
async function withPendingUploadLock(options, run) {
|
|
247
|
-
return await
|
|
278
|
+
return await withMSTeamsSqliteMutationLock(options, PENDING_UPLOAD_MUTATION_KEY, run);
|
|
248
279
|
}
|
|
249
280
|
async function readUploadRows(id, metaStore, chunkStore) {
|
|
250
281
|
const meta = await metaStore.lookup(buildMetaKey(id));
|
|
@@ -295,19 +326,16 @@ async function storePendingUploadFs(upload, options) {
|
|
|
295
326
|
await withPendingUploadLock(options, async () => {
|
|
296
327
|
await registerUploadRows({
|
|
297
328
|
id: upload.id,
|
|
298
|
-
|
|
329
|
+
buffer: upload.buffer,
|
|
299
330
|
filename: upload.filename,
|
|
300
331
|
contentType: upload.contentType,
|
|
301
332
|
conversationId: upload.conversationId,
|
|
302
333
|
consentCardActivityId: upload.consentCardActivityId,
|
|
303
334
|
createdAt: Date.now()
|
|
304
|
-
}, metaStore, chunkStore, ttlMs
|
|
335
|
+
}, metaStore, chunkStore, ttlMs);
|
|
305
336
|
await pruneUploadStore(metaStore, chunkStore, ttlMs);
|
|
306
337
|
});
|
|
307
338
|
}
|
|
308
|
-
/**
|
|
309
|
-
* Retrieve a persisted pending upload. Expired entries are treated as absent.
|
|
310
|
-
*/
|
|
311
339
|
async function getPendingUploadFs(id, options) {
|
|
312
340
|
if (!id) return;
|
|
313
341
|
const ttlMs = options?.ttlMs ?? PENDING_UPLOAD_TTL_MS$1;
|
|
@@ -319,10 +347,6 @@ async function getPendingUploadFs(id, options) {
|
|
|
319
347
|
}
|
|
320
348
|
return upload;
|
|
321
349
|
}
|
|
322
|
-
/**
|
|
323
|
-
* Remove a persisted pending upload (after successful upload or decline).
|
|
324
|
-
* No-op if the entry is already gone.
|
|
325
|
-
*/
|
|
326
350
|
async function removePendingUploadFs(id, options) {
|
|
327
351
|
if (!id) return;
|
|
328
352
|
const metaStore = createMetaStore(options);
|
|
@@ -331,17 +355,13 @@ async function removePendingUploadFs(id, options) {
|
|
|
331
355
|
await deleteUploadRows(id, metaStore, chunkStore);
|
|
332
356
|
});
|
|
333
357
|
}
|
|
334
|
-
/**
|
|
335
|
-
* Set the consent card activity ID on a persisted entry. Called after the
|
|
336
|
-
* FileConsentCard activity is sent and we know its message id.
|
|
337
|
-
*/
|
|
338
358
|
async function setPendingUploadActivityIdFs(id, activityId, options) {
|
|
339
359
|
const ttlMs = options?.ttlMs ?? PENDING_UPLOAD_TTL_MS$1;
|
|
340
360
|
const metaStore = createMetaStore(options);
|
|
341
361
|
await withPendingUploadLock(options, async () => {
|
|
342
362
|
const record = await metaStore.lookup(buildMetaKey(id));
|
|
343
363
|
if (!record || Date.now() - record.createdAt > ttlMs) return;
|
|
344
|
-
await metaStore.register(buildMetaKey(id),
|
|
364
|
+
await metaStore.register(buildMetaKey(id), toPluginJsonValue({
|
|
345
365
|
...record,
|
|
346
366
|
consentCardActivityId: activityId
|
|
347
367
|
}));
|
|
@@ -365,7 +385,6 @@ const { pendingUploads, pendingUploadTimers } = (0, openclaw_plugin_sdk_global_s
|
|
|
365
385
|
state.pendingUploadTimers.clear();
|
|
366
386
|
state.pendingUploads.clear();
|
|
367
387
|
});
|
|
368
|
-
/** TTL for pending uploads: 5 minutes */
|
|
369
388
|
const PENDING_UPLOAD_TTL_MS = 3e5;
|
|
370
389
|
/**
|
|
371
390
|
* Store a file pending user consent.
|
|
@@ -386,21 +405,12 @@ function storePendingUpload(upload) {
|
|
|
386
405
|
pendingUploadTimers.set(id, timer);
|
|
387
406
|
return id;
|
|
388
407
|
}
|
|
389
|
-
/**
|
|
390
|
-
* Retrieve a pending upload by ID.
|
|
391
|
-
* Returns undefined if not found or expired.
|
|
392
|
-
*/
|
|
393
408
|
function getPendingUpload(id) {
|
|
394
409
|
if (!id) return;
|
|
395
410
|
const entry = pendingUploads.get(id);
|
|
396
411
|
if (!entry) return;
|
|
397
412
|
if (Date.now() - entry.createdAt > PENDING_UPLOAD_TTL_MS) {
|
|
398
|
-
|
|
399
|
-
const timer = pendingUploadTimers.get(id);
|
|
400
|
-
if (timer !== void 0) {
|
|
401
|
-
clearTimeout(timer);
|
|
402
|
-
pendingUploadTimers.delete(id);
|
|
403
|
-
}
|
|
413
|
+
removePendingUpload(id);
|
|
404
414
|
return;
|
|
405
415
|
}
|
|
406
416
|
return entry;
|
|
@@ -419,10 +429,6 @@ function removePendingUpload(id) {
|
|
|
419
429
|
}
|
|
420
430
|
}
|
|
421
431
|
}
|
|
422
|
-
/**
|
|
423
|
-
* Set the consent card activity ID on an existing pending upload.
|
|
424
|
-
* Called after the FileConsentCard is sent and we know its activity ID.
|
|
425
|
-
*/
|
|
426
432
|
function setPendingUploadActivityId(uploadId, activityId) {
|
|
427
433
|
const entry = pendingUploads.get(uploadId);
|
|
428
434
|
if (entry) entry.consentCardActivityId = activityId;
|
|
@@ -479,18 +485,16 @@ function prepareFileConsentActivity(params) {
|
|
|
479
485
|
*/
|
|
480
486
|
async function prepareFileConsentActivityFs(params) {
|
|
481
487
|
const { media, conversationId, description } = params;
|
|
482
|
-
const
|
|
488
|
+
const upload = {
|
|
483
489
|
buffer: media.buffer,
|
|
484
490
|
filename: media.filename,
|
|
485
491
|
contentType: media.contentType,
|
|
486
492
|
conversationId
|
|
487
|
-
}
|
|
493
|
+
};
|
|
494
|
+
const uploadId = storePendingUpload(upload);
|
|
488
495
|
await storePendingUploadFs({
|
|
489
496
|
id: uploadId,
|
|
490
|
-
|
|
491
|
-
filename: media.filename,
|
|
492
|
-
contentType: media.contentType,
|
|
493
|
-
conversationId
|
|
497
|
+
...upload
|
|
494
498
|
});
|
|
495
499
|
return {
|
|
496
500
|
activity: buildConsentActivity({
|
|
@@ -501,10 +505,6 @@ async function prepareFileConsentActivityFs(params) {
|
|
|
501
505
|
uploadId
|
|
502
506
|
};
|
|
503
507
|
}
|
|
504
|
-
/**
|
|
505
|
-
* Check if a file requires FileConsentCard flow.
|
|
506
|
-
* True for: personal chat AND (large file OR non-image)
|
|
507
|
-
*/
|
|
508
508
|
function requiresFileConsent(params) {
|
|
509
509
|
const isPersonal = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(params.conversationType) === "personal";
|
|
510
510
|
const isImage = params.contentType?.startsWith("image/") ?? false;
|
|
@@ -775,14 +775,15 @@ function formatMSTeamsMarkdown(markdown, tableMode) {
|
|
|
775
775
|
const index = escapedMarkdown.push(escaped) - 1;
|
|
776
776
|
return `${tokenPrefix}e${index}${TOKEN_END}`;
|
|
777
777
|
});
|
|
778
|
-
const
|
|
778
|
+
const parsed = (0, openclaw_plugin_sdk_text_chunking.markdownToIR)(protectedMarkdown, {
|
|
779
779
|
autolink: false,
|
|
780
780
|
enableSpoilers: true,
|
|
781
781
|
enableTaskLists: true,
|
|
782
782
|
headingStyle: "rich",
|
|
783
783
|
linkify: false,
|
|
784
784
|
blockquotePrefix: ""
|
|
785
|
-
})
|
|
785
|
+
});
|
|
786
|
+
const protectedValues = [
|
|
786
787
|
{
|
|
787
788
|
prefix: `${tokenPrefix}e`,
|
|
788
789
|
values: escapedMarkdown
|
|
@@ -803,8 +804,9 @@ function formatMSTeamsMarkdown(markdown, tableMode) {
|
|
|
803
804
|
prefix: `${tokenPrefix}h`,
|
|
804
805
|
values: entities
|
|
805
806
|
}
|
|
806
|
-
]
|
|
807
|
-
|
|
807
|
+
];
|
|
808
|
+
const ir = prefixMSTeamsBlockquotes(protectMSTeamsCode(parsed, tokenPrefix, codeRegions, protectedValues));
|
|
809
|
+
const rendered = (0, openclaw_plugin_sdk_text_chunking.renderMarkdownWithMarkers)(ir, {
|
|
808
810
|
styleMarkers: MSTEAMS_MARKERS,
|
|
809
811
|
escapeText: (text) => text,
|
|
810
812
|
buildLink: (link) => ({
|
|
@@ -813,12 +815,8 @@ function formatMSTeamsMarkdown(markdown, tableMode) {
|
|
|
813
815
|
open: "[",
|
|
814
816
|
close: `](${serializeMarkdownDestination(link.href)})`
|
|
815
817
|
})
|
|
816
|
-
}, MSTEAMS_FORMAT_CAPABILITIES)
|
|
817
|
-
|
|
818
|
-
restored = restoreTokens(restored, `${tokenPrefix}t`, rawTables);
|
|
819
|
-
restored = restoreTokens(restored, `${tokenPrefix}m`, mentions);
|
|
820
|
-
restored = restoreTokens(restored, `${tokenPrefix}i`, images);
|
|
821
|
-
return restoreTokens(restored, `${tokenPrefix}h`, entities);
|
|
818
|
+
}, MSTEAMS_FORMAT_CAPABILITIES);
|
|
819
|
+
return protectedValues.reduce((text, { prefix, values }) => restoreTokens(text, prefix, values), restoreTokens(rendered, `${tokenPrefix}c`, codeRegions));
|
|
822
820
|
}
|
|
823
821
|
//#endregion
|
|
824
822
|
//#region extensions/msteams/src/graph-chat.ts
|
|
@@ -827,43 +825,18 @@ function buildTeamsFileInfoCard(file) {
|
|
|
827
825
|
const uniqueId = rawETag.replace(/^["']|["']$/g, "").replace(/[{}]/g, "").split(",")[0] ?? rawETag;
|
|
828
826
|
const lastDot = file.name.lastIndexOf(".");
|
|
829
827
|
const fileType = lastDot >= 0 ? (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(file.name.slice(lastDot + 1)) : "";
|
|
830
|
-
return {
|
|
831
|
-
|
|
828
|
+
return buildFileInfoCard({
|
|
829
|
+
filename: file.name,
|
|
832
830
|
contentUrl: file.webDavUrl,
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
fileType
|
|
837
|
-
}
|
|
838
|
-
};
|
|
831
|
+
uniqueId,
|
|
832
|
+
fileType
|
|
833
|
+
});
|
|
839
834
|
}
|
|
840
835
|
//#endregion
|
|
841
836
|
//#region extensions/msteams/src/graph-upload.ts
|
|
842
|
-
/**
|
|
843
|
-
* SharePoint upload utilities for MS Teams file sending.
|
|
844
|
-
*
|
|
845
|
-
* For group chats and channels, files are uploaded to SharePoint and shared via a link.
|
|
846
|
-
* This module provides utilities for:
|
|
847
|
-
* - Uploading files to SharePoint (group/channel scope)
|
|
848
|
-
* - Creating sharing links (organization-wide or per-user)
|
|
849
|
-
* - Getting chat members for per-user sharing
|
|
850
|
-
*/
|
|
851
837
|
const GRAPH_ROOT = "https://graph.microsoft.com/v1.0";
|
|
852
838
|
const GRAPH_BETA = "https://graph.microsoft.com/beta";
|
|
853
839
|
const GRAPH_SCOPE = "https://graph.microsoft.com";
|
|
854
|
-
async function requestSharePoint(url, init, params) {
|
|
855
|
-
const { response, release } = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
|
|
856
|
-
url,
|
|
857
|
-
init,
|
|
858
|
-
fetchImpl: params.fetchFn,
|
|
859
|
-
mode: "trusted_env_proxy",
|
|
860
|
-
beforeRequest: () => require_resolve_allowlist.assertMSTeamsSendHandoff(params),
|
|
861
|
-
maxRedirects: 20,
|
|
862
|
-
allowCrossOriginUnsafeRedirectReplay: true,
|
|
863
|
-
auditContext: "msteams.graph-upload"
|
|
864
|
-
});
|
|
865
|
-
return (0, openclaw_plugin_sdk_fetch_runtime.responseWithRelease)(response, release);
|
|
866
|
-
}
|
|
867
840
|
function requireMSTeamsSharePointSiteId(siteId) {
|
|
868
841
|
const normalized = siteId?.trim();
|
|
869
842
|
if (!normalized) throw new Error("channels.msteams.sharePointSiteId is required to send files to group chats or channels");
|
|
@@ -872,43 +845,55 @@ function requireMSTeamsSharePointSiteId(siteId) {
|
|
|
872
845
|
const SHAREPOINT_REQUEST_TIMEOUT_LABEL = "MS Teams SharePoint request";
|
|
873
846
|
const SHAREPOINT_UPLOAD_TIMEOUT_LABEL = "MS Teams SharePoint upload";
|
|
874
847
|
const GRAPH_TOKEN_TIMEOUT_LABEL = "MS Teams Graph token acquisition";
|
|
875
|
-
async function
|
|
876
|
-
return await require_resolve_allowlist.
|
|
877
|
-
label:
|
|
878
|
-
|
|
879
|
-
});
|
|
880
|
-
}
|
|
881
|
-
/**
|
|
882
|
-
* Upload a file to a SharePoint site.
|
|
883
|
-
* This is used for group chats and channels where /me/drive doesn't work for bots.
|
|
884
|
-
*
|
|
885
|
-
* @param params.siteId - SharePoint site ID (e.g., "contoso.sharepoint.com,guid1,guid2")
|
|
886
|
-
*/
|
|
887
|
-
async function uploadToSharePoint(params) {
|
|
888
|
-
const uploadPath = `/OpenClawShared/${encodeURIComponent(params.filename)}`;
|
|
889
|
-
const uploadUrl = `${GRAPH_ROOT}/sites/${params.siteId}/drive/root:${uploadPath}:/content?@microsoft.graph.conflictBehavior=rename`;
|
|
890
|
-
const timeoutMs = require_resolve_allowlist.resolveMSTeamsSharePointUploadTimeoutMs(params.buffer.length);
|
|
891
|
-
const data = await require_resolve_allowlist.withMSTeamsAbortableRequestTimeout({
|
|
892
|
-
label: SHAREPOINT_UPLOAD_TIMEOUT_LABEL,
|
|
893
|
-
timeoutMs,
|
|
848
|
+
async function requestSharePointJson(params, request) {
|
|
849
|
+
return await require_resolve_allowlist.withMSTeamsAbortableRequestTimeout({
|
|
850
|
+
label: request.timeoutMs !== void 0 ? SHAREPOINT_UPLOAD_TIMEOUT_LABEL : SHAREPOINT_REQUEST_TIMEOUT_LABEL,
|
|
851
|
+
timeoutMs: request.timeoutMs,
|
|
894
852
|
work: async (signal) => {
|
|
895
853
|
require_resolve_allowlist.assertMSTeamsSendHandoff(params);
|
|
896
|
-
const token = await
|
|
854
|
+
const token = await require_resolve_allowlist.withMSTeamsRequestDeadline({
|
|
855
|
+
label: GRAPH_TOKEN_TIMEOUT_LABEL,
|
|
856
|
+
work: () => params.tokenProvider.getAccessToken(GRAPH_SCOPE)
|
|
857
|
+
});
|
|
897
858
|
require_resolve_allowlist.assertMSTeamsSendHandoff(params);
|
|
898
|
-
const
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
859
|
+
const init = request.init?.();
|
|
860
|
+
const { response, release } = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
|
|
861
|
+
url: request.url,
|
|
862
|
+
init: {
|
|
863
|
+
...init,
|
|
864
|
+
headers: {
|
|
865
|
+
"User-Agent": require_resolve_allowlist.buildUserAgent(),
|
|
866
|
+
Authorization: `Bearer ${token}`,
|
|
867
|
+
...init?.headers
|
|
868
|
+
},
|
|
869
|
+
signal
|
|
904
870
|
},
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
871
|
+
fetchImpl: params.fetchFn,
|
|
872
|
+
mode: "trusted_env_proxy",
|
|
873
|
+
beforeRequest: () => require_resolve_allowlist.assertMSTeamsSendHandoff(params),
|
|
874
|
+
maxRedirects: 20,
|
|
875
|
+
allowCrossOriginUnsafeRedirectReplay: true,
|
|
876
|
+
auditContext: "msteams.graph-upload"
|
|
877
|
+
});
|
|
878
|
+
const res = (0, openclaw_plugin_sdk_fetch_runtime.responseWithRelease)(response, release);
|
|
879
|
+
if (!res.ok) throw await (0, openclaw_plugin_sdk_provider_http.createProviderHttpError)(res, typeof request.error === "string" ? request.error : request.error(res));
|
|
880
|
+
return await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, request.label, { chunkTimeoutMs: request.timeoutMs });
|
|
910
881
|
}
|
|
911
882
|
});
|
|
883
|
+
}
|
|
884
|
+
async function uploadToSharePoint(params) {
|
|
885
|
+
const uploadPath = `/OpenClawShared/${encodeURIComponent(params.filename)}`;
|
|
886
|
+
const data = await requestSharePointJson(params, {
|
|
887
|
+
url: `${GRAPH_ROOT}/sites/${params.siteId}/drive/root:${uploadPath}:/content?@microsoft.graph.conflictBehavior=rename`,
|
|
888
|
+
timeoutMs: require_resolve_allowlist.resolveMSTeamsSharePointUploadTimeoutMs(params.buffer.length),
|
|
889
|
+
init: () => ({
|
|
890
|
+
method: "PUT",
|
|
891
|
+
headers: { "Content-Type": params.contentType ?? "application/octet-stream" },
|
|
892
|
+
body: new Blob([(0, openclaw_plugin_sdk_blob_runtime.bufferToBlobPart)(params.buffer)])
|
|
893
|
+
}),
|
|
894
|
+
error: "SharePoint upload failed",
|
|
895
|
+
label: "msteams.graph-upload.uploadSharePointFile"
|
|
896
|
+
});
|
|
912
897
|
if (!data.id || !data.webUrl || !data.name) throw new Error("SharePoint upload response missing required fields");
|
|
913
898
|
return {
|
|
914
899
|
id: data.id,
|
|
@@ -916,30 +901,11 @@ async function uploadToSharePoint(params) {
|
|
|
916
901
|
name: data.name
|
|
917
902
|
};
|
|
918
903
|
}
|
|
919
|
-
/**
|
|
920
|
-
* Get driveItem properties needed for native Teams file card attachments.
|
|
921
|
-
* This fetches the eTag and webDavUrl which are required for "reference" type attachments.
|
|
922
|
-
*
|
|
923
|
-
* @param params.siteId - SharePoint site ID
|
|
924
|
-
* @param params.itemId - The driveItem ID (returned from upload)
|
|
925
|
-
*/
|
|
926
904
|
async function getDriveItemProperties(params) {
|
|
927
|
-
const data = await
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
const token = await getGraphAccessToken(params.tokenProvider);
|
|
932
|
-
require_resolve_allowlist.assertMSTeamsSendHandoff(params);
|
|
933
|
-
const res = await requestSharePoint(`${GRAPH_ROOT}/sites/${params.siteId}/drive/items/${params.itemId}?$select=eTag,webDavUrl,name`, {
|
|
934
|
-
headers: {
|
|
935
|
-
"User-Agent": require_resolve_allowlist.buildUserAgent(),
|
|
936
|
-
Authorization: `Bearer ${token}`
|
|
937
|
-
},
|
|
938
|
-
signal
|
|
939
|
-
}, params);
|
|
940
|
-
if (!res.ok) throw await require_resolve_allowlist.createMSTeamsHttpError(res, "Get driveItem properties failed");
|
|
941
|
-
return await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.getDriveItemProperties");
|
|
942
|
-
}
|
|
905
|
+
const data = await requestSharePointJson(params, {
|
|
906
|
+
url: `${GRAPH_ROOT}/sites/${params.siteId}/drive/items/${params.itemId}?$select=eTag,webDavUrl,name`,
|
|
907
|
+
error: "Get driveItem properties failed",
|
|
908
|
+
label: "msteams.graph-upload.getDriveItemProperties"
|
|
943
909
|
});
|
|
944
910
|
if (!data.eTag || !data.webDavUrl || !data.name) throw new Error("DriveItem response missing required properties (eTag, webDavUrl, or name)");
|
|
945
911
|
return {
|
|
@@ -948,31 +914,12 @@ async function getDriveItemProperties(params) {
|
|
|
948
914
|
name: data.name
|
|
949
915
|
};
|
|
950
916
|
}
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
label: SHAREPOINT_REQUEST_TIMEOUT_LABEL,
|
|
958
|
-
work: async (signal) => {
|
|
959
|
-
require_resolve_allowlist.assertMSTeamsSendHandoff(params);
|
|
960
|
-
const token = await getGraphAccessToken(params.tokenProvider);
|
|
961
|
-
require_resolve_allowlist.assertMSTeamsSendHandoff(params);
|
|
962
|
-
const res = await requestSharePoint(`${GRAPH_ROOT}/chats/${params.chatId}/members`, {
|
|
963
|
-
headers: {
|
|
964
|
-
"User-Agent": require_resolve_allowlist.buildUserAgent(),
|
|
965
|
-
Authorization: `Bearer ${token}`
|
|
966
|
-
},
|
|
967
|
-
signal
|
|
968
|
-
}, params);
|
|
969
|
-
if (!res.ok) {
|
|
970
|
-
const message = res.status === 403 ? "Get chat members failed; verify Graph chat-member permissions and tenant access policies" : "Get chat members failed";
|
|
971
|
-
throw await require_resolve_allowlist.createMSTeamsHttpError(res, message);
|
|
972
|
-
}
|
|
973
|
-
return ((await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.getChatMembers")).value ?? []).map((member) => ({ aadObjectId: member.userId ?? "" })).filter((member) => member.aadObjectId);
|
|
974
|
-
}
|
|
975
|
-
});
|
|
917
|
+
async function getChatMemberIds(params) {
|
|
918
|
+
return ((await requestSharePointJson(params, {
|
|
919
|
+
url: `${GRAPH_ROOT}/chats/${params.chatId}/members`,
|
|
920
|
+
error: (res) => res.status === 403 ? "Get chat members failed; verify Graph chat-member permissions and tenant access policies" : "Get chat members failed",
|
|
921
|
+
label: "msteams.graph-upload.getChatMembers"
|
|
922
|
+
})).value ?? []).flatMap((member) => member.userId ? [member.userId] : []);
|
|
976
923
|
}
|
|
977
924
|
/**
|
|
978
925
|
* Create a sharing link for a SharePoint drive item.
|
|
@@ -987,63 +934,40 @@ async function createSharePointSharingLink(params) {
|
|
|
987
934
|
scope: scope === "users" ? "users" : "organization"
|
|
988
935
|
};
|
|
989
936
|
if (scope === "users" && params.recipientObjectIds?.length) body.recipients = params.recipientObjectIds.map((id) => ({ objectId: id }));
|
|
990
|
-
const data = await
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
"User-Agent": require_resolve_allowlist.buildUserAgent(),
|
|
1000
|
-
Authorization: `Bearer ${token}`,
|
|
1001
|
-
"Content-Type": "application/json"
|
|
1002
|
-
},
|
|
1003
|
-
body: JSON.stringify(body),
|
|
1004
|
-
signal
|
|
1005
|
-
}, params);
|
|
1006
|
-
if (!res.ok) throw await require_resolve_allowlist.createMSTeamsHttpError(res, "Create SharePoint sharing link failed");
|
|
1007
|
-
return await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(res, "msteams.graph-upload.createSharePointSharingLink");
|
|
1008
|
-
}
|
|
937
|
+
const data = await requestSharePointJson(params, {
|
|
938
|
+
url: `${apiRoot}/sites/${params.siteId}/drive/items/${params.itemId}/createLink`,
|
|
939
|
+
init: () => ({
|
|
940
|
+
method: "POST",
|
|
941
|
+
headers: { "Content-Type": "application/json" },
|
|
942
|
+
body: JSON.stringify(body)
|
|
943
|
+
}),
|
|
944
|
+
error: "Create SharePoint sharing link failed",
|
|
945
|
+
label: "msteams.graph-upload.createSharePointSharingLink"
|
|
1009
946
|
});
|
|
1010
947
|
if (!data.link?.webUrl) throw new Error("Create SharePoint sharing link response missing webUrl");
|
|
1011
|
-
return
|
|
948
|
+
return data.link.webUrl;
|
|
1012
949
|
}
|
|
1013
950
|
/**
|
|
1014
951
|
* Upload a file to SharePoint and create a sharing link.
|
|
1015
952
|
*
|
|
1016
953
|
* For group chats, this creates a per-user sharing link scoped to chat members.
|
|
1017
954
|
* For channels, this creates an organization-wide sharing link.
|
|
1018
|
-
*
|
|
1019
|
-
* @param params.siteId - SharePoint site ID
|
|
1020
|
-
* @param params.chatId - Optional chat ID for per-user sharing (group chats)
|
|
1021
|
-
* @param params.usePerUserSharing - Whether to use per-user sharing (requires beta API + chat-member read access)
|
|
1022
955
|
*/
|
|
1023
956
|
async function uploadAndShareSharePoint(params) {
|
|
1024
|
-
const uploaded = await uploadToSharePoint(
|
|
1025
|
-
buffer: params.buffer,
|
|
1026
|
-
filename: params.filename,
|
|
1027
|
-
contentType: params.contentType,
|
|
1028
|
-
tokenProvider: params.tokenProvider,
|
|
1029
|
-
siteId: params.siteId,
|
|
1030
|
-
fetchFn: params.fetchFn,
|
|
1031
|
-
assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
|
|
1032
|
-
});
|
|
957
|
+
const uploaded = await uploadToSharePoint(params);
|
|
1033
958
|
let scope = "organization";
|
|
1034
959
|
let recipientObjectIds;
|
|
1035
960
|
if (params.usePerUserSharing && params.chatId) {
|
|
1036
|
-
|
|
961
|
+
recipientObjectIds = await getChatMemberIds({
|
|
1037
962
|
chatId: params.chatId,
|
|
1038
963
|
tokenProvider: params.tokenProvider,
|
|
1039
964
|
fetchFn: params.fetchFn,
|
|
1040
965
|
assertDirectAdapterHandoff: params.assertDirectAdapterHandoff
|
|
1041
966
|
});
|
|
1042
|
-
if (
|
|
967
|
+
if (recipientObjectIds.length === 0) throw new Error("MS Teams chat member lookup returned no recipients");
|
|
1043
968
|
scope = "users";
|
|
1044
|
-
recipientObjectIds = members.map((member) => member.aadObjectId);
|
|
1045
969
|
}
|
|
1046
|
-
const
|
|
970
|
+
const shareUrl = await createSharePointSharingLink({
|
|
1047
971
|
siteId: params.siteId,
|
|
1048
972
|
itemId: uploaded.id,
|
|
1049
973
|
tokenProvider: params.tokenProvider,
|
|
@@ -1055,16 +979,13 @@ async function uploadAndShareSharePoint(params) {
|
|
|
1055
979
|
return {
|
|
1056
980
|
itemId: uploaded.id,
|
|
1057
981
|
webUrl: uploaded.webUrl,
|
|
1058
|
-
shareUrl
|
|
982
|
+
shareUrl,
|
|
1059
983
|
name: uploaded.name
|
|
1060
984
|
};
|
|
1061
985
|
}
|
|
1062
986
|
//#endregion
|
|
1063
987
|
//#region extensions/msteams/src/media-helpers.ts
|
|
1064
988
|
/**
|
|
1065
|
-
* MIME type detection and filename extraction for MSTeams media attachments.
|
|
1066
|
-
*/
|
|
1067
|
-
/**
|
|
1068
989
|
* Detect MIME type from URL extension or data URL.
|
|
1069
990
|
* Uses shared MIME detection for consistency with core handling.
|
|
1070
991
|
*/
|
|
@@ -1103,25 +1024,16 @@ async function extractFilename(url) {
|
|
|
1103
1024
|
return (0, openclaw_plugin_sdk_media_runtime.extractOriginalFilename)(url);
|
|
1104
1025
|
}
|
|
1105
1026
|
}
|
|
1106
|
-
/**
|
|
1107
|
-
* Check if a URL refers to a local file path.
|
|
1108
|
-
*/
|
|
1109
1027
|
function isLocalPath(url) {
|
|
1110
|
-
|
|
1111
|
-
if (url.startsWith("\\") && !url.startsWith("\\\\")) return true;
|
|
1112
|
-
if (/^[a-zA-Z]:[\\/]/.test(url)) return true;
|
|
1113
|
-
if (url.startsWith("\\\\")) return true;
|
|
1114
|
-
return false;
|
|
1028
|
+
return /^file:\/\//iu.test(url) || url.startsWith("/") || url.startsWith("~") || url.startsWith("\\") || /^[a-zA-Z]:[\\/]/.test(url);
|
|
1115
1029
|
}
|
|
1116
1030
|
/**
|
|
1117
1031
|
* Extract the message ID from a Bot Framework response.
|
|
1118
1032
|
*/
|
|
1119
1033
|
function extractMessageId(response) {
|
|
1120
|
-
if (!response || typeof response !== "object") return null;
|
|
1121
|
-
if (!("id" in response)) return null;
|
|
1034
|
+
if (!response || typeof response !== "object" || !("id" in response)) return null;
|
|
1122
1035
|
const { id } = response;
|
|
1123
|
-
|
|
1124
|
-
return id;
|
|
1036
|
+
return typeof id === "string" && id ? id : null;
|
|
1125
1037
|
}
|
|
1126
1038
|
//#endregion
|
|
1127
1039
|
//#region extensions/msteams/src/mentions.ts
|
|
@@ -1189,6 +1101,15 @@ function buildMSTeamsMessageActivity(text) {
|
|
|
1189
1101
|
entities: [...parsed.entities, AI_GENERATED_ENTITY]
|
|
1190
1102
|
};
|
|
1191
1103
|
}
|
|
1104
|
+
function buildMSTeamsAdaptiveCardActivity(card) {
|
|
1105
|
+
return {
|
|
1106
|
+
type: "message",
|
|
1107
|
+
attachments: [{
|
|
1108
|
+
contentType: "application/vnd.microsoft.card.adaptive",
|
|
1109
|
+
content: card
|
|
1110
|
+
}]
|
|
1111
|
+
};
|
|
1112
|
+
}
|
|
1192
1113
|
//#endregion
|
|
1193
1114
|
//#region extensions/msteams/src/revoked-context.ts
|
|
1194
1115
|
async function withRevokedProxyFallback(params) {
|
|
@@ -1201,6 +1122,36 @@ async function withRevokedProxyFallback(params) {
|
|
|
1201
1122
|
}
|
|
1202
1123
|
}
|
|
1203
1124
|
//#endregion
|
|
1125
|
+
//#region extensions/msteams/src/sent-message-cache.ts
|
|
1126
|
+
const sentMessages = (0, openclaw_plugin_sdk_dedupe_runtime.createPersistentDedupeCache)({
|
|
1127
|
+
globalKey: Symbol.for("openclaw.msteamsSentMessages"),
|
|
1128
|
+
ttlMs: 864e5,
|
|
1129
|
+
maxSize: 2e4,
|
|
1130
|
+
persistent: {
|
|
1131
|
+
namespace: "msteams.sent-messages",
|
|
1132
|
+
maxEntries: 1e3,
|
|
1133
|
+
openStore: (options) => require_runtime.getOptionalMSTeamsRuntime()?.state.openKeyedStore(options),
|
|
1134
|
+
logError: (0, openclaw_plugin_sdk_plugin_state_runtime.createPluginStateErrorReporter)(require_runtime.getOptionalMSTeamsRuntime, "msteams", "sent-message-state", "Microsoft Teams persistent sent-message state failed"),
|
|
1135
|
+
readTimestamp: (record) => record.sentAt
|
|
1136
|
+
}
|
|
1137
|
+
});
|
|
1138
|
+
function makeKey(conversationId, messageId, botId) {
|
|
1139
|
+
return botId ? JSON.stringify([
|
|
1140
|
+
botId,
|
|
1141
|
+
conversationId,
|
|
1142
|
+
messageId
|
|
1143
|
+
]) : `${conversationId}:${messageId}`;
|
|
1144
|
+
}
|
|
1145
|
+
function recordMSTeamsSentMessage(conversationId, messageId, botId) {
|
|
1146
|
+
if (!conversationId || !messageId || messageId === "unknown") return;
|
|
1147
|
+
const sentAt = Date.now();
|
|
1148
|
+
sentMessages.register(makeKey(conversationId, messageId, botId), { sentAt }, { at: sentAt });
|
|
1149
|
+
}
|
|
1150
|
+
async function wasMSTeamsMessageSentWithPersistence(params) {
|
|
1151
|
+
if (!params.conversationId || !params.messageId) return false;
|
|
1152
|
+
return await sentMessages.lookup(makeKey(params.conversationId, params.messageId, params.botId));
|
|
1153
|
+
}
|
|
1154
|
+
//#endregion
|
|
1204
1155
|
//#region extensions/msteams/src/sdk-proactive.ts
|
|
1205
1156
|
const loadMSTeamsApiModule = (0, openclaw_plugin_sdk_lazy_runtime.createLazyRuntimeModule)(() => import("@microsoft/teams.api"));
|
|
1206
1157
|
async function quoteMSTeamsActivity(activity, messageId) {
|
|
@@ -1210,12 +1161,12 @@ async function quoteMSTeamsActivity(activity, messageId) {
|
|
|
1210
1161
|
return MessageActivityInput.from(activity).prependQuote(messageId);
|
|
1211
1162
|
}
|
|
1212
1163
|
function resolveThreadedConversationId(conversationId, threadActivityId) {
|
|
1213
|
-
|
|
1214
|
-
return `${
|
|
1164
|
+
const baseId = conversationId.split(";")[0] ?? conversationId;
|
|
1165
|
+
return threadActivityId ? `${baseId};messageid=${threadActivityId}` : baseId;
|
|
1215
1166
|
}
|
|
1216
1167
|
function normalizeRequiredServiceUrl(ref) {
|
|
1217
1168
|
if (!ref.serviceUrl) throw new Error("Invalid stored reference: missing serviceUrl");
|
|
1218
|
-
return
|
|
1169
|
+
return require_bot_framework_service_url.normalizeBotFrameworkServiceUrl(ref.serviceUrl);
|
|
1219
1170
|
}
|
|
1220
1171
|
function buildSdkConversationReference(source, options) {
|
|
1221
1172
|
const bot = source.agent ?? source.bot ?? void 0;
|
|
@@ -1250,13 +1201,10 @@ function buildSdkConversationReference(source, options) {
|
|
|
1250
1201
|
...source.aadObjectId ? { aadObjectId: source.aadObjectId } : {}
|
|
1251
1202
|
};
|
|
1252
1203
|
}
|
|
1253
|
-
function getStructuralApiClient(app) {
|
|
1254
|
-
return app.api;
|
|
1255
|
-
}
|
|
1256
1204
|
function sameServiceUrl(left, right) {
|
|
1257
1205
|
if (!left) return false;
|
|
1258
1206
|
try {
|
|
1259
|
-
return
|
|
1207
|
+
return require_bot_framework_service_url.normalizeBotFrameworkServiceUrl(left) === right;
|
|
1260
1208
|
} catch {
|
|
1261
1209
|
return false;
|
|
1262
1210
|
}
|
|
@@ -1268,7 +1216,7 @@ function stringifyReferenceFallbackActivity(activity) {
|
|
|
1268
1216
|
return "";
|
|
1269
1217
|
}
|
|
1270
1218
|
async function getApiClientForReference(app, ref) {
|
|
1271
|
-
const api =
|
|
1219
|
+
const api = app.api;
|
|
1272
1220
|
if (sameServiceUrl(api.serviceUrl, ref.serviceUrl)) return api;
|
|
1273
1221
|
const appInternals = app;
|
|
1274
1222
|
const httpClient = appInternals.api?.http ?? appInternals.client;
|
|
@@ -1277,12 +1225,12 @@ async function getApiClientForReference(app, ref) {
|
|
|
1277
1225
|
return new Client(ref.serviceUrl, httpClient);
|
|
1278
1226
|
}
|
|
1279
1227
|
function mergeReferenceIntoActivity(activity, ref) {
|
|
1280
|
-
const source =
|
|
1228
|
+
const source = (0, openclaw_plugin_sdk_string_coerce_runtime.asOptionalRecord)(activity) ?? {
|
|
1281
1229
|
type: "message",
|
|
1282
1230
|
text: stringifyReferenceFallbackActivity(activity)
|
|
1283
1231
|
};
|
|
1284
|
-
const existingChannelData =
|
|
1285
|
-
const existingTenant =
|
|
1232
|
+
const existingChannelData = (0, openclaw_plugin_sdk_string_coerce_runtime.asOptionalRecord)(source.channelData);
|
|
1233
|
+
const existingTenant = (0, openclaw_plugin_sdk_string_coerce_runtime.asOptionalRecord)(existingChannelData?.tenant);
|
|
1286
1234
|
let channelData = existingChannelData ? { ...existingChannelData } : void 0;
|
|
1287
1235
|
if (ref.tenantId) {
|
|
1288
1236
|
channelData ??= {};
|
|
@@ -1321,6 +1269,8 @@ async function sendMSTeamsActivityWithReference(app, source, activity, options)
|
|
|
1321
1269
|
};
|
|
1322
1270
|
}
|
|
1323
1271
|
const res = isTargeted && activities.createTargeted ? await activities.createTargeted(activityWithRef) : await activities.create(activityWithRef);
|
|
1272
|
+
const conversationId = ref.conversation.id.split(";")[0] ?? ref.conversation.id;
|
|
1273
|
+
if (res.id && activityWithRef.type === "message" && ref.conversation.conversationType === "channel" && ref.conversation.id === conversationId) recordMSTeamsSentMessage(conversationId, res.id, ref.bot.id);
|
|
1324
1274
|
return {
|
|
1325
1275
|
...activityWithRef,
|
|
1326
1276
|
...res
|
|
@@ -1347,9 +1297,6 @@ const MSTEAMS_MAX_MEDIA_BYTES = 104857600;
|
|
|
1347
1297
|
* Files >= 4MB use consent flow; smaller images can use inline base64.
|
|
1348
1298
|
*/
|
|
1349
1299
|
const FILE_CONSENT_THRESHOLD_BYTES = 4194304;
|
|
1350
|
-
function normalizeConversationId(rawId) {
|
|
1351
|
-
return rawId.split(";")[0] ?? rawId;
|
|
1352
|
-
}
|
|
1353
1300
|
function buildConversationReference(ref) {
|
|
1354
1301
|
const conversationId = ref.conversation?.id?.trim();
|
|
1355
1302
|
if (!conversationId) throw new Error("Invalid stored reference: missing conversation.id");
|
|
@@ -1367,7 +1314,7 @@ function buildConversationReference(ref) {
|
|
|
1367
1314
|
} : user,
|
|
1368
1315
|
agent,
|
|
1369
1316
|
conversation: {
|
|
1370
|
-
id:
|
|
1317
|
+
id: require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId),
|
|
1371
1318
|
conversationType: ref.conversation?.conversationType,
|
|
1372
1319
|
tenantId
|
|
1373
1320
|
},
|
|
@@ -1380,17 +1327,11 @@ function buildConversationReference(ref) {
|
|
|
1380
1327
|
}
|
|
1381
1328
|
function pushTextMessages(out, text, opts) {
|
|
1382
1329
|
if (!text) return;
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
out.push({ text: trimmed });
|
|
1388
|
-
}
|
|
1389
|
-
return;
|
|
1330
|
+
const chunks = opts.chunkText ? require_runtime.getMSTeamsRuntime().channel.text.chunkMarkdownTextWithMode(text, opts.chunkLimit, opts.chunkMode) : [text];
|
|
1331
|
+
for (const chunk of chunks) {
|
|
1332
|
+
const trimmed = chunk.trim();
|
|
1333
|
+
if (trimmed && !(0, openclaw_plugin_sdk_reply_chunking.isSilentReplyText)(trimmed, openclaw_plugin_sdk_reply_chunking.SILENT_REPLY_TOKEN)) out.push({ text: trimmed });
|
|
1390
1334
|
}
|
|
1391
|
-
const trimmed = text.trim();
|
|
1392
|
-
if (!trimmed || (0, openclaw_plugin_sdk_reply_chunking.isSilentReplyText)(trimmed, openclaw_plugin_sdk_reply_chunking.SILENT_REPLY_TOKEN)) return;
|
|
1393
|
-
out.push({ text: trimmed });
|
|
1394
1335
|
}
|
|
1395
1336
|
function clampMs(value, maxMs) {
|
|
1396
1337
|
if (!Number.isFinite(value) || value < 0) return 0;
|
|
@@ -1405,9 +1346,9 @@ function resolveRetryOptions(retry) {
|
|
|
1405
1346
|
};
|
|
1406
1347
|
return {
|
|
1407
1348
|
enabled: true,
|
|
1408
|
-
maxAttempts: Math.max(1, retry
|
|
1409
|
-
baseDelayMs: Math.max(0, retry
|
|
1410
|
-
maxDelayMs: Math.max(0, retry
|
|
1349
|
+
maxAttempts: Math.max(1, retry.maxAttempts ?? 3),
|
|
1350
|
+
baseDelayMs: Math.max(0, retry.baseDelayMs ?? 250),
|
|
1351
|
+
maxDelayMs: Math.max(0, retry.maxDelayMs ?? 1e4)
|
|
1411
1352
|
};
|
|
1412
1353
|
}
|
|
1413
1354
|
function computeRetryDelayMs(attempt, classification, opts) {
|
|
@@ -1427,37 +1368,20 @@ function renderReplyPayloadsToMessages(replies, options) {
|
|
|
1427
1368
|
for (const payload of replies) {
|
|
1428
1369
|
const reply = (0, openclaw_plugin_sdk_reply_payload.resolveSendableOutboundReplyParts)(payload, { text: formatMSTeamsMarkdown(payload.text ?? "", tableMode) });
|
|
1429
1370
|
if (!reply.hasContent) continue;
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1371
|
+
const [firstMedia, ...remainingMedia] = reply.mediaUrls;
|
|
1372
|
+
if (mediaMode === "inline" && firstMedia) {
|
|
1373
|
+
out.push({
|
|
1374
|
+
text: reply.text || void 0,
|
|
1375
|
+
mediaUrl: firstMedia
|
|
1435
1376
|
});
|
|
1436
|
-
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1439
|
-
const firstMedia = reply.mediaUrls[0];
|
|
1440
|
-
if (firstMedia) {
|
|
1441
|
-
out.push({
|
|
1442
|
-
text: reply.text || void 0,
|
|
1443
|
-
mediaUrl: firstMedia
|
|
1444
|
-
});
|
|
1445
|
-
for (let i = 1; i < reply.mediaUrls.length; i++) if (reply.mediaUrls[i]) out.push({ mediaUrl: reply.mediaUrls[i] });
|
|
1446
|
-
} else pushTextMessages(out, reply.text, {
|
|
1377
|
+
out.push(...remainingMedia.map((mediaUrl) => ({ mediaUrl })));
|
|
1378
|
+
} else {
|
|
1379
|
+
pushTextMessages(out, reply.text, {
|
|
1447
1380
|
chunkText,
|
|
1448
1381
|
chunkLimit,
|
|
1449
1382
|
chunkMode
|
|
1450
1383
|
});
|
|
1451
|
-
|
|
1452
|
-
}
|
|
1453
|
-
pushTextMessages(out, reply.text, {
|
|
1454
|
-
chunkText,
|
|
1455
|
-
chunkLimit,
|
|
1456
|
-
chunkMode
|
|
1457
|
-
});
|
|
1458
|
-
for (const mediaUrl of reply.mediaUrls) {
|
|
1459
|
-
if (!mediaUrl) continue;
|
|
1460
|
-
out.push({ mediaUrl });
|
|
1384
|
+
out.push(...reply.mediaUrls.map((mediaUrl) => ({ mediaUrl })));
|
|
1461
1385
|
}
|
|
1462
1386
|
}
|
|
1463
1387
|
return out;
|
|
@@ -1620,9 +1544,8 @@ async function sendMSTeamsMessages(params) {
|
|
|
1620
1544
|
fellBack: false
|
|
1621
1545
|
}),
|
|
1622
1546
|
onRevoked: async () => {
|
|
1623
|
-
const remaining = messages.slice(idx);
|
|
1624
1547
|
return {
|
|
1625
|
-
ids:
|
|
1548
|
+
ids: await sendProactively(messages.slice(idx), idx, resolvedThreadId),
|
|
1626
1549
|
fellBack: true
|
|
1627
1550
|
};
|
|
1628
1551
|
}
|
|
@@ -1635,6 +1558,423 @@ async function sendMSTeamsMessages(params) {
|
|
|
1635
1558
|
return await sendProactively(messages, 0);
|
|
1636
1559
|
}
|
|
1637
1560
|
//#endregion
|
|
1561
|
+
//#region extensions/msteams/src/polls.ts
|
|
1562
|
+
const MSTEAMS_POLLS_NAMESPACE = "polls";
|
|
1563
|
+
const MSTEAMS_POLL_VOTE_BUCKETS_NAMESPACE = "poll-vote-buckets";
|
|
1564
|
+
const MSTEAMS_MAX_POLLS = 1e3;
|
|
1565
|
+
const MSTEAMS_SQLITE_MAX_POLL_ROWS = 2e3;
|
|
1566
|
+
const MSTEAMS_POLL_VOTE_BUCKET_COUNT = 32;
|
|
1567
|
+
const MSTEAMS_MAX_POLL_VOTE_BUCKET_ROWS = 1001 * MSTEAMS_POLL_VOTE_BUCKET_COUNT;
|
|
1568
|
+
const MSTEAMS_POLL_TTL_MS = 2592e6;
|
|
1569
|
+
function normalizeChoiceValue(value) {
|
|
1570
|
+
if (typeof value === "string") {
|
|
1571
|
+
const trimmed = value.trim();
|
|
1572
|
+
return trimmed ? trimmed : null;
|
|
1573
|
+
}
|
|
1574
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
1575
|
+
return null;
|
|
1576
|
+
}
|
|
1577
|
+
function extractSelections(value) {
|
|
1578
|
+
if (Array.isArray(value)) return value.map(normalizeChoiceValue).filter((entry) => Boolean(entry));
|
|
1579
|
+
const normalized = normalizeChoiceValue(value);
|
|
1580
|
+
if (!normalized) return [];
|
|
1581
|
+
if (normalized.includes(",")) return (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeStringEntries)(normalized.split(","));
|
|
1582
|
+
return [normalized];
|
|
1583
|
+
}
|
|
1584
|
+
function readNestedValue(value, keys) {
|
|
1585
|
+
let current = value;
|
|
1586
|
+
for (const key of keys) {
|
|
1587
|
+
if (!(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(current)) return;
|
|
1588
|
+
current = current[key];
|
|
1589
|
+
}
|
|
1590
|
+
return current;
|
|
1591
|
+
}
|
|
1592
|
+
function readNestedString(value, keys) {
|
|
1593
|
+
return (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalString)(readNestedValue(value, keys));
|
|
1594
|
+
}
|
|
1595
|
+
function extractMSTeamsPollVote(activity) {
|
|
1596
|
+
const value = activity?.value;
|
|
1597
|
+
if (!value || !(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(value)) return null;
|
|
1598
|
+
const pollId = readNestedString(value, ["openclawPollId"]) ?? readNestedString(value, ["pollId"]) ?? readNestedString(value, ["openclaw", "pollId"]) ?? readNestedString(value, [
|
|
1599
|
+
"openclaw",
|
|
1600
|
+
"poll",
|
|
1601
|
+
"id"
|
|
1602
|
+
]) ?? readNestedString(value, ["data", "openclawPollId"]) ?? readNestedString(value, ["data", "pollId"]) ?? readNestedString(value, [
|
|
1603
|
+
"data",
|
|
1604
|
+
"openclaw",
|
|
1605
|
+
"pollId"
|
|
1606
|
+
]) ?? readNestedString(value, [
|
|
1607
|
+
"action",
|
|
1608
|
+
"data",
|
|
1609
|
+
"openclawPollId"
|
|
1610
|
+
]) ?? readNestedString(value, [
|
|
1611
|
+
"action",
|
|
1612
|
+
"data",
|
|
1613
|
+
"pollId"
|
|
1614
|
+
]);
|
|
1615
|
+
if (!pollId) return null;
|
|
1616
|
+
const selections = [
|
|
1617
|
+
value.choices,
|
|
1618
|
+
readNestedValue(value, ["data", "choices"]),
|
|
1619
|
+
readNestedValue(value, [
|
|
1620
|
+
"action",
|
|
1621
|
+
"data",
|
|
1622
|
+
"choices"
|
|
1623
|
+
])
|
|
1624
|
+
].map(extractSelections).find((choices) => choices.length > 0) ?? [];
|
|
1625
|
+
if (selections.length === 0) return null;
|
|
1626
|
+
return {
|
|
1627
|
+
pollId,
|
|
1628
|
+
selections
|
|
1629
|
+
};
|
|
1630
|
+
}
|
|
1631
|
+
function buildMSTeamsPollCard(params) {
|
|
1632
|
+
const pollId = params.pollId ?? node_crypto.default.randomUUID();
|
|
1633
|
+
const maxSelections = typeof params.maxSelections === "number" && params.maxSelections > 1 ? Math.floor(params.maxSelections) : 1;
|
|
1634
|
+
const cappedMaxSelections = Math.min(Math.max(1, maxSelections), params.options.length);
|
|
1635
|
+
const choices = params.options.map((option, index) => ({
|
|
1636
|
+
title: option,
|
|
1637
|
+
value: String(index)
|
|
1638
|
+
}));
|
|
1639
|
+
const hint = cappedMaxSelections > 1 ? `Select up to ${cappedMaxSelections} option${cappedMaxSelections === 1 ? "" : "s"}.` : "Select one option.";
|
|
1640
|
+
const card = {
|
|
1641
|
+
type: "AdaptiveCard",
|
|
1642
|
+
version: "1.5",
|
|
1643
|
+
body: [
|
|
1644
|
+
{
|
|
1645
|
+
type: "TextBlock",
|
|
1646
|
+
text: params.question,
|
|
1647
|
+
wrap: true,
|
|
1648
|
+
weight: "Bolder",
|
|
1649
|
+
size: "Medium"
|
|
1650
|
+
},
|
|
1651
|
+
{
|
|
1652
|
+
type: "Input.ChoiceSet",
|
|
1653
|
+
id: "choices",
|
|
1654
|
+
isMultiSelect: cappedMaxSelections > 1,
|
|
1655
|
+
style: "expanded",
|
|
1656
|
+
choices
|
|
1657
|
+
},
|
|
1658
|
+
{
|
|
1659
|
+
type: "TextBlock",
|
|
1660
|
+
text: hint,
|
|
1661
|
+
wrap: true,
|
|
1662
|
+
isSubtle: true,
|
|
1663
|
+
spacing: "Small"
|
|
1664
|
+
}
|
|
1665
|
+
],
|
|
1666
|
+
actions: [{
|
|
1667
|
+
type: "Action.Execute",
|
|
1668
|
+
title: "Vote",
|
|
1669
|
+
verb: "openclaw.poll.vote",
|
|
1670
|
+
data: {
|
|
1671
|
+
openclawPollId: pollId,
|
|
1672
|
+
pollId
|
|
1673
|
+
}
|
|
1674
|
+
}]
|
|
1675
|
+
};
|
|
1676
|
+
const fallbackLines = [`Poll: ${params.question}`, ...params.options.map((option, index) => `${index + 1}. ${option}`)];
|
|
1677
|
+
return {
|
|
1678
|
+
pollId,
|
|
1679
|
+
question: params.question,
|
|
1680
|
+
options: params.options,
|
|
1681
|
+
maxSelections: cappedMaxSelections,
|
|
1682
|
+
card,
|
|
1683
|
+
fallbackText: fallbackLines.join("\n")
|
|
1684
|
+
};
|
|
1685
|
+
}
|
|
1686
|
+
function createPollStateStore(params) {
|
|
1687
|
+
return require_runtime.getMSTeamsRuntime().state.openKeyedStore({
|
|
1688
|
+
namespace: MSTEAMS_POLLS_NAMESPACE,
|
|
1689
|
+
maxEntries: MSTEAMS_SQLITE_MAX_POLL_ROWS,
|
|
1690
|
+
env: resolveMSTeamsSqliteStateEnv(params)
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
function createPollVoteBucketStateStore(params) {
|
|
1694
|
+
return require_runtime.getMSTeamsRuntime().state.openKeyedStore({
|
|
1695
|
+
namespace: MSTEAMS_POLL_VOTE_BUCKETS_NAMESPACE,
|
|
1696
|
+
maxEntries: MSTEAMS_MAX_POLL_VOTE_BUCKET_ROWS,
|
|
1697
|
+
env: resolveMSTeamsSqliteStateEnv(params)
|
|
1698
|
+
});
|
|
1699
|
+
}
|
|
1700
|
+
function isPollExpired(poll) {
|
|
1701
|
+
const cutoff = Date.now() - MSTEAMS_POLL_TTL_MS;
|
|
1702
|
+
return !(((0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(poll.updatedAt ?? poll.createdAt) ?? 0) >= cutoff);
|
|
1703
|
+
}
|
|
1704
|
+
function normalizeMSTeamsPollSelections(poll, selections) {
|
|
1705
|
+
const maxSelections = Math.max(1, poll.maxSelections);
|
|
1706
|
+
const mapped = selections.map((entry) => (0, openclaw_plugin_sdk_number_runtime.parseStrictNonNegativeInteger)(entry)).filter((value) => value !== void 0).filter((value) => value >= 0 && value < poll.options.length).map((value) => String(value));
|
|
1707
|
+
return (0, openclaw_plugin_sdk_string_coerce_runtime.uniqueStrings)(mapped).slice(0, maxSelections);
|
|
1708
|
+
}
|
|
1709
|
+
function hashMSTeamsPollVote(pollId, voterId) {
|
|
1710
|
+
return node_crypto.default.createHash("sha256").update(pollId).update("\0").update(voterId).digest("hex");
|
|
1711
|
+
}
|
|
1712
|
+
function buildMSTeamsPollStateKey(pollId) {
|
|
1713
|
+
return node_crypto.default.createHash("sha256").update(pollId).digest("hex");
|
|
1714
|
+
}
|
|
1715
|
+
function selectMSTeamsPollVoteBucket(pollId, voterId) {
|
|
1716
|
+
const bucket = Number.parseInt(hashMSTeamsPollVote(pollId, voterId).slice(0, 8), 16);
|
|
1717
|
+
return String(bucket % MSTEAMS_POLL_VOTE_BUCKET_COUNT).padStart(4, "0");
|
|
1718
|
+
}
|
|
1719
|
+
function buildMSTeamsPollVoteBucketKey(pollId, bucket) {
|
|
1720
|
+
return `${buildMSTeamsPollStateKey(pollId)}:${bucket}`;
|
|
1721
|
+
}
|
|
1722
|
+
function createMSTeamsPollStoreState(params) {
|
|
1723
|
+
const pollStore = createPollStateStore(params);
|
|
1724
|
+
const voteBucketStore = createPollVoteBucketStateStore(params);
|
|
1725
|
+
const readPollVotes = async (pollId) => {
|
|
1726
|
+
const votes = {};
|
|
1727
|
+
for (const row of await voteBucketStore.entries()) if (row.value.pollId === pollId) Object.assign(votes, row.value.votes);
|
|
1728
|
+
return votes;
|
|
1729
|
+
};
|
|
1730
|
+
const deletePollVotes = async (pollId, cachedRows) => {
|
|
1731
|
+
for (const row of cachedRows?.values() ?? await voteBucketStore.entries()) if (row.value.pollId === pollId) {
|
|
1732
|
+
await voteBucketStore.delete(row.key);
|
|
1733
|
+
cachedRows?.delete(row.key);
|
|
1734
|
+
}
|
|
1735
|
+
};
|
|
1736
|
+
const registerPollVotes = async (pollId, votes, updatedAt) => {
|
|
1737
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
1738
|
+
for (const [voterId, selections] of Object.entries(votes)) {
|
|
1739
|
+
const bucket = selectMSTeamsPollVoteBucket(pollId, voterId);
|
|
1740
|
+
const bucketVotes = buckets.get(bucket) ?? {};
|
|
1741
|
+
bucketVotes[voterId] = selections;
|
|
1742
|
+
buckets.set(bucket, bucketVotes);
|
|
1743
|
+
}
|
|
1744
|
+
for (const [bucket, bucketVotes] of buckets) {
|
|
1745
|
+
const key = buildMSTeamsPollVoteBucketKey(pollId, bucket);
|
|
1746
|
+
const existing = await voteBucketStore.lookup(key);
|
|
1747
|
+
await voteBucketStore.register(key, toPluginJsonValue({
|
|
1748
|
+
pollId,
|
|
1749
|
+
bucket,
|
|
1750
|
+
votes: {
|
|
1751
|
+
...bucketVotes,
|
|
1752
|
+
...existing?.votes
|
|
1753
|
+
},
|
|
1754
|
+
updatedAt
|
|
1755
|
+
}));
|
|
1756
|
+
}
|
|
1757
|
+
};
|
|
1758
|
+
const registerPollVote = async (pollId, voterId, selections, updatedAt) => {
|
|
1759
|
+
const bucket = selectMSTeamsPollVoteBucket(pollId, voterId);
|
|
1760
|
+
const key = buildMSTeamsPollVoteBucketKey(pollId, bucket);
|
|
1761
|
+
const existing = await voteBucketStore.lookup(key);
|
|
1762
|
+
await voteBucketStore.register(key, toPluginJsonValue({
|
|
1763
|
+
pollId,
|
|
1764
|
+
bucket,
|
|
1765
|
+
votes: {
|
|
1766
|
+
...existing?.votes,
|
|
1767
|
+
[voterId]: selections
|
|
1768
|
+
},
|
|
1769
|
+
updatedAt
|
|
1770
|
+
}));
|
|
1771
|
+
};
|
|
1772
|
+
const reconstructPoll = async (metadata) => {
|
|
1773
|
+
return {
|
|
1774
|
+
...metadata,
|
|
1775
|
+
votes: await readPollVotes(metadata.id)
|
|
1776
|
+
};
|
|
1777
|
+
};
|
|
1778
|
+
const prunePollStoreToLimit = async () => {
|
|
1779
|
+
let voteRows;
|
|
1780
|
+
const deletePrunedPollVotes = async (pollId) => {
|
|
1781
|
+
voteRows ??= new Map((await voteBucketStore.entries()).map((row) => [row.key, row]));
|
|
1782
|
+
await deletePollVotes(pollId, voteRows);
|
|
1783
|
+
};
|
|
1784
|
+
const rows = [];
|
|
1785
|
+
for (const row of await pollStore.entries()) {
|
|
1786
|
+
if (isPollExpired(row.value)) {
|
|
1787
|
+
await pollStore.delete(row.key);
|
|
1788
|
+
await deletePrunedPollVotes(row.value.id);
|
|
1789
|
+
continue;
|
|
1790
|
+
}
|
|
1791
|
+
rows.push(row);
|
|
1792
|
+
}
|
|
1793
|
+
if (rows.length <= MSTEAMS_MAX_POLLS) return;
|
|
1794
|
+
const sorted = rows.toSorted((a, b) => {
|
|
1795
|
+
return ((0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(a.value.updatedAt ?? a.value.createdAt) ?? 0) - ((0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(b.value.updatedAt ?? b.value.createdAt) ?? 0) || a.key.localeCompare(b.key);
|
|
1796
|
+
});
|
|
1797
|
+
for (const row of sorted.slice(0, rows.length - MSTEAMS_MAX_POLLS)) {
|
|
1798
|
+
await pollStore.delete(row.key);
|
|
1799
|
+
await deletePrunedPollVotes(row.value.id);
|
|
1800
|
+
}
|
|
1801
|
+
};
|
|
1802
|
+
const createPoll = async (poll) => {
|
|
1803
|
+
await withMSTeamsSqliteMutationLock(params, MSTEAMS_POLLS_NAMESPACE, async () => {
|
|
1804
|
+
const { votes, ...metadata } = poll;
|
|
1805
|
+
await pollStore.register(buildMSTeamsPollStateKey(poll.id), toPluginJsonValue(metadata));
|
|
1806
|
+
await deletePollVotes(poll.id);
|
|
1807
|
+
await registerPollVotes(poll.id, votes, poll.updatedAt ?? poll.createdAt);
|
|
1808
|
+
await prunePollStoreToLimit();
|
|
1809
|
+
});
|
|
1810
|
+
};
|
|
1811
|
+
const getPoll = async (pollId) => {
|
|
1812
|
+
const poll = await pollStore.lookup(buildMSTeamsPollStateKey(pollId));
|
|
1813
|
+
if (!poll) return null;
|
|
1814
|
+
if (isPollExpired(poll)) return null;
|
|
1815
|
+
return await reconstructPoll(poll);
|
|
1816
|
+
};
|
|
1817
|
+
const recordVote = async (vote) => {
|
|
1818
|
+
return await withMSTeamsSqliteMutationLock(params, MSTEAMS_POLLS_NAMESPACE, async () => {
|
|
1819
|
+
const pollKey = buildMSTeamsPollStateKey(vote.pollId);
|
|
1820
|
+
const poll = await pollStore.lookup(pollKey);
|
|
1821
|
+
if (!poll) return null;
|
|
1822
|
+
if (isPollExpired(poll)) {
|
|
1823
|
+
await pollStore.delete(pollKey);
|
|
1824
|
+
await deletePollVotes(vote.pollId);
|
|
1825
|
+
return null;
|
|
1826
|
+
}
|
|
1827
|
+
const normalized = normalizeMSTeamsPollSelections(await reconstructPoll(poll), vote.selections);
|
|
1828
|
+
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1829
|
+
poll.updatedAt = updatedAt;
|
|
1830
|
+
await pollStore.register(pollKey, toPluginJsonValue(poll));
|
|
1831
|
+
await registerPollVote(vote.pollId, vote.voterId, normalized, updatedAt);
|
|
1832
|
+
await prunePollStoreToLimit();
|
|
1833
|
+
return await reconstructPoll(poll);
|
|
1834
|
+
});
|
|
1835
|
+
};
|
|
1836
|
+
return {
|
|
1837
|
+
createPoll,
|
|
1838
|
+
getPoll,
|
|
1839
|
+
recordVote
|
|
1840
|
+
};
|
|
1841
|
+
}
|
|
1842
|
+
//#endregion
|
|
1843
|
+
//#region extensions/msteams/src/conversation-store-helpers.ts
|
|
1844
|
+
function toConversationStoreEntries(entries) {
|
|
1845
|
+
return Array.from(entries, ([conversationId, reference]) => ({
|
|
1846
|
+
conversationId,
|
|
1847
|
+
reference
|
|
1848
|
+
}));
|
|
1849
|
+
}
|
|
1850
|
+
function mergeStoredConversationReference(existing, incoming, nowIso) {
|
|
1851
|
+
return {
|
|
1852
|
+
...existing?.timezone && !incoming.timezone ? { timezone: existing.timezone } : {},
|
|
1853
|
+
...existing?.tenantId && !incoming.tenantId ? { tenantId: existing.tenantId } : {},
|
|
1854
|
+
...existing?.aadObjectId && !incoming.aadObjectId ? { aadObjectId: existing.aadObjectId } : {},
|
|
1855
|
+
...incoming,
|
|
1856
|
+
lastSeenAt: nowIso
|
|
1857
|
+
};
|
|
1858
|
+
}
|
|
1859
|
+
function findPreferredDmConversationByUserId(entries, id) {
|
|
1860
|
+
const target = id.trim();
|
|
1861
|
+
if (!target) return null;
|
|
1862
|
+
const personalMatches = [];
|
|
1863
|
+
const unknownTypeMatches = [];
|
|
1864
|
+
for (const entry of entries) {
|
|
1865
|
+
if (entry.reference.user?.aadObjectId !== target && entry.reference.user?.id !== target) continue;
|
|
1866
|
+
const convType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(entry.reference.conversation?.conversationType ?? "");
|
|
1867
|
+
if (convType === "personal") personalMatches.push(entry);
|
|
1868
|
+
else if (convType === "channel" || convType === "groupchat") {} else unknownTypeMatches.push(entry);
|
|
1869
|
+
}
|
|
1870
|
+
const candidates = personalMatches.length > 0 ? personalMatches : unknownTypeMatches;
|
|
1871
|
+
if (candidates.length === 0) return null;
|
|
1872
|
+
if (candidates.length > 1) candidates.sort((a, b) => ((0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(b.reference.lastSeenAt) ?? 0) - ((0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(a.reference.lastSeenAt) ?? 0));
|
|
1873
|
+
return candidates[0] ?? null;
|
|
1874
|
+
}
|
|
1875
|
+
//#endregion
|
|
1876
|
+
//#region extensions/msteams/src/conversation-store-state.ts
|
|
1877
|
+
const MSTEAMS_CONVERSATIONS_NAMESPACE = "conversations";
|
|
1878
|
+
const MSTEAMS_MAX_CONVERSATIONS = 1e3;
|
|
1879
|
+
const MSTEAMS_SQLITE_MAX_CONVERSATION_ROWS = 2e3;
|
|
1880
|
+
const MSTEAMS_CONVERSATION_TTL_MS = 31536e6;
|
|
1881
|
+
const CONVERSATION_MUTATION_KEY = "conversations";
|
|
1882
|
+
function createConversationStateStore(params) {
|
|
1883
|
+
return require_runtime.getMSTeamsRuntime().state.openKeyedStore({
|
|
1884
|
+
namespace: MSTEAMS_CONVERSATIONS_NAMESPACE,
|
|
1885
|
+
maxEntries: MSTEAMS_SQLITE_MAX_CONVERSATION_ROWS,
|
|
1886
|
+
env: resolveMSTeamsSqliteStateEnv(params)
|
|
1887
|
+
});
|
|
1888
|
+
}
|
|
1889
|
+
function buildMSTeamsConversationStateKey(conversationId) {
|
|
1890
|
+
return node_crypto.default.createHash("sha256").update(conversationId).digest("hex");
|
|
1891
|
+
}
|
|
1892
|
+
function prepareMSTeamsConversationReferenceForStorage(conversationId, reference) {
|
|
1893
|
+
return {
|
|
1894
|
+
...reference,
|
|
1895
|
+
conversation: {
|
|
1896
|
+
...reference.conversation,
|
|
1897
|
+
id: conversationId
|
|
1898
|
+
}
|
|
1899
|
+
};
|
|
1900
|
+
}
|
|
1901
|
+
function getStoredConversationId(reference) {
|
|
1902
|
+
const rawId = reference.conversation?.id;
|
|
1903
|
+
return rawId ? require_resolve_allowlist.normalizeMSTeamsConversationId(rawId) : null;
|
|
1904
|
+
}
|
|
1905
|
+
function createMSTeamsConversationStoreState(params) {
|
|
1906
|
+
const ttlMs = params?.ttlMs ?? MSTEAMS_CONVERSATION_TTL_MS;
|
|
1907
|
+
const conversationStore = createConversationStateStore(params);
|
|
1908
|
+
const isExpired = (reference) => {
|
|
1909
|
+
const lastSeenAt = (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(reference.lastSeenAt);
|
|
1910
|
+
return lastSeenAt != null && Date.now() - lastSeenAt > ttlMs;
|
|
1911
|
+
};
|
|
1912
|
+
const lookupStored = async (conversationId) => {
|
|
1913
|
+
const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
|
|
1914
|
+
const value = await conversationStore.lookup(buildMSTeamsConversationStateKey(normalizedId));
|
|
1915
|
+
if (!value) return null;
|
|
1916
|
+
if (isExpired(value)) return null;
|
|
1917
|
+
return value;
|
|
1918
|
+
};
|
|
1919
|
+
const entries = async () => {
|
|
1920
|
+
const rows = await conversationStore.entries();
|
|
1921
|
+
const kept = [];
|
|
1922
|
+
for (const row of rows) {
|
|
1923
|
+
if (isExpired(row.value)) continue;
|
|
1924
|
+
const conversationId = getStoredConversationId(row.value);
|
|
1925
|
+
if (conversationId) kept.push([conversationId, row.value]);
|
|
1926
|
+
}
|
|
1927
|
+
return kept;
|
|
1928
|
+
};
|
|
1929
|
+
const register = async (conversationId, reference) => {
|
|
1930
|
+
const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
|
|
1931
|
+
await conversationStore.register(buildMSTeamsConversationStateKey(normalizedId), toPluginJsonValue(prepareMSTeamsConversationReferenceForStorage(normalizedId, reference)));
|
|
1932
|
+
const rows = [];
|
|
1933
|
+
for (const row of await conversationStore.entries()) {
|
|
1934
|
+
if (isExpired(row.value)) {
|
|
1935
|
+
await conversationStore.delete(row.key);
|
|
1936
|
+
continue;
|
|
1937
|
+
}
|
|
1938
|
+
rows.push(row);
|
|
1939
|
+
}
|
|
1940
|
+
if (rows.length <= MSTEAMS_MAX_CONVERSATIONS) return;
|
|
1941
|
+
const sorted = rows.toSorted((a, b) => {
|
|
1942
|
+
const aTs = (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(a.value.lastSeenAt) ?? 0;
|
|
1943
|
+
const bTs = (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(b.value.lastSeenAt) ?? 0;
|
|
1944
|
+
const aId = getStoredConversationId(a.value) ?? a.key;
|
|
1945
|
+
const bId = getStoredConversationId(b.value) ?? b.key;
|
|
1946
|
+
return aTs - bTs || aId.localeCompare(bId);
|
|
1947
|
+
});
|
|
1948
|
+
for (const row of sorted.slice(0, rows.length - MSTEAMS_MAX_CONVERSATIONS)) await conversationStore.delete(row.key);
|
|
1949
|
+
};
|
|
1950
|
+
const list = async () => {
|
|
1951
|
+
return toConversationStoreEntries(await entries());
|
|
1952
|
+
};
|
|
1953
|
+
const findPreferredDmByUserId = async (id) => {
|
|
1954
|
+
return findPreferredDmConversationByUserId(await list(), id);
|
|
1955
|
+
};
|
|
1956
|
+
const upsert = async (conversationId, reference) => {
|
|
1957
|
+
const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
|
|
1958
|
+
await withMSTeamsSqliteMutationLock(params, CONVERSATION_MUTATION_KEY, async () => {
|
|
1959
|
+
const existing = await lookupStored(normalizedId);
|
|
1960
|
+
await register(normalizedId, mergeStoredConversationReference(existing ?? void 0, reference, (/* @__PURE__ */ new Date()).toISOString()));
|
|
1961
|
+
});
|
|
1962
|
+
};
|
|
1963
|
+
const remove = async (conversationId) => {
|
|
1964
|
+
const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
|
|
1965
|
+
return await withMSTeamsSqliteMutationLock(params, CONVERSATION_MUTATION_KEY, async () => {
|
|
1966
|
+
return await conversationStore.delete(buildMSTeamsConversationStateKey(normalizedId));
|
|
1967
|
+
});
|
|
1968
|
+
};
|
|
1969
|
+
return {
|
|
1970
|
+
upsert,
|
|
1971
|
+
get: lookupStored,
|
|
1972
|
+
list,
|
|
1973
|
+
remove,
|
|
1974
|
+
findPreferredDmByUserId
|
|
1975
|
+
};
|
|
1976
|
+
}
|
|
1977
|
+
//#endregion
|
|
1638
1978
|
Object.defineProperty(exports, "buildConversationReference", {
|
|
1639
1979
|
enumerable: true,
|
|
1640
1980
|
get: function() {
|
|
@@ -1647,18 +1987,42 @@ Object.defineProperty(exports, "buildFileInfoCard", {
|
|
|
1647
1987
|
return buildFileInfoCard;
|
|
1648
1988
|
}
|
|
1649
1989
|
});
|
|
1990
|
+
Object.defineProperty(exports, "buildMSTeamsAdaptiveCardActivity", {
|
|
1991
|
+
enumerable: true,
|
|
1992
|
+
get: function() {
|
|
1993
|
+
return buildMSTeamsAdaptiveCardActivity;
|
|
1994
|
+
}
|
|
1995
|
+
});
|
|
1650
1996
|
Object.defineProperty(exports, "buildMSTeamsMessageActivity", {
|
|
1651
1997
|
enumerable: true,
|
|
1652
1998
|
get: function() {
|
|
1653
1999
|
return buildMSTeamsMessageActivity;
|
|
1654
2000
|
}
|
|
1655
2001
|
});
|
|
2002
|
+
Object.defineProperty(exports, "buildMSTeamsPollCard", {
|
|
2003
|
+
enumerable: true,
|
|
2004
|
+
get: function() {
|
|
2005
|
+
return buildMSTeamsPollCard;
|
|
2006
|
+
}
|
|
2007
|
+
});
|
|
1656
2008
|
Object.defineProperty(exports, "buildTeamsFileInfoCard", {
|
|
1657
2009
|
enumerable: true,
|
|
1658
2010
|
get: function() {
|
|
1659
2011
|
return buildTeamsFileInfoCard;
|
|
1660
2012
|
}
|
|
1661
2013
|
});
|
|
2014
|
+
Object.defineProperty(exports, "createMSTeamsConversationStoreState", {
|
|
2015
|
+
enumerable: true,
|
|
2016
|
+
get: function() {
|
|
2017
|
+
return createMSTeamsConversationStoreState;
|
|
2018
|
+
}
|
|
2019
|
+
});
|
|
2020
|
+
Object.defineProperty(exports, "createMSTeamsPollStoreState", {
|
|
2021
|
+
enumerable: true,
|
|
2022
|
+
get: function() {
|
|
2023
|
+
return createMSTeamsPollStoreState;
|
|
2024
|
+
}
|
|
2025
|
+
});
|
|
1662
2026
|
Object.defineProperty(exports, "deleteMSTeamsActivityWithReference", {
|
|
1663
2027
|
enumerable: true,
|
|
1664
2028
|
get: function() {
|
|
@@ -1671,6 +2035,12 @@ Object.defineProperty(exports, "extractFilename", {
|
|
|
1671
2035
|
return extractFilename;
|
|
1672
2036
|
}
|
|
1673
2037
|
});
|
|
2038
|
+
Object.defineProperty(exports, "extractMSTeamsPollVote", {
|
|
2039
|
+
enumerable: true,
|
|
2040
|
+
get: function() {
|
|
2041
|
+
return extractMSTeamsPollVote;
|
|
2042
|
+
}
|
|
2043
|
+
});
|
|
1674
2044
|
Object.defineProperty(exports, "extractMessageId", {
|
|
1675
2045
|
enumerable: true,
|
|
1676
2046
|
get: function() {
|
|
@@ -1713,6 +2083,12 @@ Object.defineProperty(exports, "prepareFileConsentActivityFs", {
|
|
|
1713
2083
|
return prepareFileConsentActivityFs;
|
|
1714
2084
|
}
|
|
1715
2085
|
});
|
|
2086
|
+
Object.defineProperty(exports, "recordMSTeamsSentMessage", {
|
|
2087
|
+
enumerable: true,
|
|
2088
|
+
get: function() {
|
|
2089
|
+
return recordMSTeamsSentMessage;
|
|
2090
|
+
}
|
|
2091
|
+
});
|
|
1716
2092
|
Object.defineProperty(exports, "removePendingUpload", {
|
|
1717
2093
|
enumerable: true,
|
|
1718
2094
|
get: function() {
|
|
@@ -1743,6 +2119,12 @@ Object.defineProperty(exports, "requiresFileConsent", {
|
|
|
1743
2119
|
return requiresFileConsent;
|
|
1744
2120
|
}
|
|
1745
2121
|
});
|
|
2122
|
+
Object.defineProperty(exports, "resolveMSTeamsSqliteStateEnv", {
|
|
2123
|
+
enumerable: true,
|
|
2124
|
+
get: function() {
|
|
2125
|
+
return resolveMSTeamsSqliteStateEnv;
|
|
2126
|
+
}
|
|
2127
|
+
});
|
|
1746
2128
|
Object.defineProperty(exports, "sendMSTeamsActivityWithReference", {
|
|
1747
2129
|
enumerable: true,
|
|
1748
2130
|
get: function() {
|
|
@@ -1767,6 +2149,12 @@ Object.defineProperty(exports, "setPendingUploadActivityIdFs", {
|
|
|
1767
2149
|
return setPendingUploadActivityIdFs;
|
|
1768
2150
|
}
|
|
1769
2151
|
});
|
|
2152
|
+
Object.defineProperty(exports, "toPluginJsonValue", {
|
|
2153
|
+
enumerable: true,
|
|
2154
|
+
get: function() {
|
|
2155
|
+
return toPluginJsonValue;
|
|
2156
|
+
}
|
|
2157
|
+
});
|
|
1770
2158
|
Object.defineProperty(exports, "updateMSTeamsActivityWithReference", {
|
|
1771
2159
|
enumerable: true,
|
|
1772
2160
|
get: function() {
|
|
@@ -1785,6 +2173,18 @@ Object.defineProperty(exports, "uploadToConsentUrl", {
|
|
|
1785
2173
|
return uploadToConsentUrl;
|
|
1786
2174
|
}
|
|
1787
2175
|
});
|
|
2176
|
+
Object.defineProperty(exports, "wasMSTeamsMessageSentWithPersistence", {
|
|
2177
|
+
enumerable: true,
|
|
2178
|
+
get: function() {
|
|
2179
|
+
return wasMSTeamsMessageSentWithPersistence;
|
|
2180
|
+
}
|
|
2181
|
+
});
|
|
2182
|
+
Object.defineProperty(exports, "withMSTeamsSqliteMutationLock", {
|
|
2183
|
+
enumerable: true,
|
|
2184
|
+
get: function() {
|
|
2185
|
+
return withMSTeamsSqliteMutationLock;
|
|
2186
|
+
}
|
|
2187
|
+
});
|
|
1788
2188
|
Object.defineProperty(exports, "withRevokedProxyFallback", {
|
|
1789
2189
|
enumerable: true,
|
|
1790
2190
|
get: function() {
|