@openclaw/msteams 2026.6.1 → 2026.6.5-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +2 -2
- package/dist/{channel-Dhw8AvTl.js → channel--oT3fyD5.js} +5 -5
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-t52N99bX.js → channel.runtime-KNuY2Oaw.js} +5 -4
- package/dist/directory-contract-api.js +35 -0
- package/dist/doctor-contract-api.js +254 -44
- package/dist/{oauth-ei63gdyS.js → oauth-CDUB5xPY.js} +1 -1
- package/dist/polls-C1VgSvKE.js +548 -0
- package/dist/{probe-DYb-0Hmx.js → probe-C-rWMb-m.js} +10 -742
- package/dist/{errors-Dpn8B05h.js → resolve-allowlist-BzIUWmMm.js} +334 -165
- package/dist/runtime-BS5AZrKK.js +8 -0
- package/dist/runtime-api.js +19 -1
- package/dist/setup-plugin-api.js +2 -2
- package/dist/{setup-surface-DGTz8Mlf.js → setup-surface-Dik4VU7f.js} +180 -220
- package/dist/{src-DZ76sgTp.js → src-CLsoqMj1.js} +9 -124
- package/dist/sso-token-store-BYZaKr82.js +70 -0
- package/npm-shrinkwrap.json +3 -3
- package/openclaw.plugin.json +3 -0
- package/package.json +4 -4
- package/dist/oauth.token-BKzEFepQ.js +0 -132
- package/dist/runtime-api-BlvMnDKz.js +0 -26
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { t as getMSTeamsRuntime } from "./runtime-BS5AZrKK.js";
|
|
2
|
+
import { fetchWithSsrFGuard as fetchWithSsrFGuard$1 } from "./runtime-api.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
|
-
import {
|
|
4
|
+
import { mapAllowlistResolutionInputs } from "openclaw/plugin-sdk/allow-from";
|
|
5
|
+
import { isRecord as isRecord$1, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
6
|
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
6
|
-
import { readProviderJsonResponse } from "openclaw/plugin-sdk/provider-http";
|
|
7
|
+
import { createProviderHttpError, readProviderJsonResponse } from "openclaw/plugin-sdk/provider-http";
|
|
7
8
|
import { Buffer } from "node:buffer";
|
|
8
9
|
import { lookup } from "node:dns/promises";
|
|
9
10
|
import { buildHostnameAllowlistPolicyFromSuffixAllowlist, isHttpsUrlAllowedByHostnameSuffixAllowlist, isPrivateIpAddress, normalizeHostnameSuffixAllowlist } from "openclaw/plugin-sdk/ssrf-policy";
|
|
10
11
|
import * as fs from "node:fs";
|
|
11
12
|
import { readFileSync } from "node:fs";
|
|
12
13
|
import path, { basename, dirname } from "node:path";
|
|
13
|
-
import {
|
|
14
|
+
import { isFutureDateTimestampMs, resolveExpiresAtMsFromDurationSeconds } from "openclaw/plugin-sdk/number-runtime";
|
|
14
15
|
import { privateFileStoreSync } from "openclaw/plugin-sdk/security-runtime";
|
|
15
16
|
import { hasConfiguredSecretInput, normalizeResolvedSecretInputString, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
16
17
|
//#region extensions/msteams/src/attachments/shared.ts
|
|
@@ -539,6 +540,11 @@ function validateMSTeamsProactiveServiceUrlBoundary(params) {
|
|
|
539
540
|
if (isChinaBotFrameworkServiceUrl(stored.value)) throw new Error(`msteams proactive send blocked for ${params.conversationId}: stored conversation serviceUrl (${stored.value}) requires channels.msteams.cloud=China.`);
|
|
540
541
|
if (stored.host !== PUBLIC_MSTEAMS_SERVICE_HOST) throw new Error(`msteams proactive send blocked for ${params.conversationId}: stored conversation serviceUrl (${stored.value}) is not a Microsoft Teams public-cloud Bot Connector endpoint. Set channels.msteams.cloud and channels.msteams.serviceUrl for the supported Teams cloud that owns this conversation.`);
|
|
541
542
|
}
|
|
543
|
+
//#endregion
|
|
544
|
+
//#region extensions/msteams/src/http-error.ts
|
|
545
|
+
async function createMSTeamsHttpError(response, label, options) {
|
|
546
|
+
return await createProviderHttpError(response, label, options);
|
|
547
|
+
}
|
|
542
548
|
const BOT_FRAMEWORK_SERVICE_URL_HOST_ALLOWLIST = normalizeHostnameSuffixAllowlist([
|
|
543
549
|
"smba.trafficmanager.net",
|
|
544
550
|
"smba.infra.gcc.teams.microsoft.com",
|
|
@@ -728,6 +734,129 @@ function readAccessToken(value) {
|
|
|
728
734
|
return null;
|
|
729
735
|
}
|
|
730
736
|
//#endregion
|
|
737
|
+
//#region extensions/msteams/src/oauth.shared.ts
|
|
738
|
+
const MSTEAMS_OAUTH_REDIRECT_URI = "http://localhost:8086/oauth2callback";
|
|
739
|
+
const MSTEAMS_OAUTH_CALLBACK_PORT = 8086;
|
|
740
|
+
const MSTEAMS_OAUTH_CALLBACK_PATH = "/oauth2callback";
|
|
741
|
+
const MSTEAMS_DEFAULT_TOKEN_FETCH_TIMEOUT_MS = 1e4;
|
|
742
|
+
const MSTEAMS_DEFAULT_DELEGATED_SCOPES = [
|
|
743
|
+
"ChatMessage.Send",
|
|
744
|
+
"ChannelMessage.Send",
|
|
745
|
+
"Chat.ReadWrite",
|
|
746
|
+
"offline_access"
|
|
747
|
+
];
|
|
748
|
+
function buildMSTeamsAuthEndpoint(tenantId) {
|
|
749
|
+
return `https://login.microsoftonline.com/${encodeURIComponent(tenantId)}/oauth2/v2.0/authorize`;
|
|
750
|
+
}
|
|
751
|
+
function buildMSTeamsTokenEndpoint(tenantId) {
|
|
752
|
+
return `https://login.microsoftonline.com/${encodeURIComponent(tenantId)}/oauth2/v2.0/token`;
|
|
753
|
+
}
|
|
754
|
+
//#endregion
|
|
755
|
+
//#region extensions/msteams/src/oauth.token.ts
|
|
756
|
+
/** Five-minute buffer subtracted from token expiry to avoid edge-case clock drift. */
|
|
757
|
+
const EXPIRY_BUFFER_MS = 300 * 1e3;
|
|
758
|
+
function createMSTeamsTokenBody(params) {
|
|
759
|
+
const body = new URLSearchParams({
|
|
760
|
+
client_id: params.clientId,
|
|
761
|
+
client_secret: params.clientSecret,
|
|
762
|
+
grant_type: params.grantType,
|
|
763
|
+
scope: [...params.scopes].join(" ")
|
|
764
|
+
});
|
|
765
|
+
for (const [key, value] of Object.entries(params.values ?? {})) body.set(key, value);
|
|
766
|
+
return body;
|
|
767
|
+
}
|
|
768
|
+
function resolveMSTeamsTokenExpiresAt(value) {
|
|
769
|
+
return resolveExpiresAtMsFromDurationSeconds(value, { bufferMs: EXPIRY_BUFFER_MS });
|
|
770
|
+
}
|
|
771
|
+
function parseMSTeamsTokenResponse(data, failureLabel) {
|
|
772
|
+
const expiresAt = resolveMSTeamsTokenExpiresAt(data.expires_in);
|
|
773
|
+
if (typeof data.access_token !== "string" || !data.access_token || expiresAt === void 0 || data.refresh_token !== void 0 && typeof data.refresh_token !== "string" || data.scope !== void 0 && typeof data.scope !== "string") throw new Error(`MSTeams ${failureLabel} failed: invalid token response fields`);
|
|
774
|
+
return {
|
|
775
|
+
access_token: data.access_token,
|
|
776
|
+
refresh_token: data.refresh_token,
|
|
777
|
+
expiresAt,
|
|
778
|
+
scope: data.scope
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
async function fetchMSTeamsTokens(params) {
|
|
782
|
+
const currentFetch = globalThis.fetch;
|
|
783
|
+
const { response, release } = await fetchWithSsrFGuard({
|
|
784
|
+
url: params.tokenUrl,
|
|
785
|
+
fetchImpl: async (input, guardedInit) => await currentFetch(input, guardedInit),
|
|
786
|
+
init: {
|
|
787
|
+
method: "POST",
|
|
788
|
+
headers: {
|
|
789
|
+
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
|
790
|
+
Accept: "application/json"
|
|
791
|
+
},
|
|
792
|
+
body: params.body,
|
|
793
|
+
signal: AbortSignal.timeout(MSTEAMS_DEFAULT_TOKEN_FETCH_TIMEOUT_MS)
|
|
794
|
+
},
|
|
795
|
+
auditContext: params.auditContext
|
|
796
|
+
});
|
|
797
|
+
try {
|
|
798
|
+
if (!response.ok) throw await createMSTeamsHttpError(response, `MSTeams ${params.failureLabel} failed`);
|
|
799
|
+
return parseMSTeamsTokenResponse(await readProviderJsonResponse(response, `MSTeams ${params.failureLabel} failed`), params.failureLabel);
|
|
800
|
+
} finally {
|
|
801
|
+
await release();
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
async function requestMSTeamsDelegatedTokens(params) {
|
|
805
|
+
const scopes = params.scopes ?? MSTEAMS_DEFAULT_DELEGATED_SCOPES;
|
|
806
|
+
const body = createMSTeamsTokenBody({
|
|
807
|
+
clientId: params.clientId,
|
|
808
|
+
clientSecret: params.clientSecret,
|
|
809
|
+
grantType: params.grantType,
|
|
810
|
+
scopes,
|
|
811
|
+
values: params.values
|
|
812
|
+
});
|
|
813
|
+
const data = await fetchMSTeamsTokens({
|
|
814
|
+
tokenUrl: buildMSTeamsTokenEndpoint(params.tenantId),
|
|
815
|
+
body,
|
|
816
|
+
auditContext: params.auditContext,
|
|
817
|
+
failureLabel: params.failureLabel
|
|
818
|
+
});
|
|
819
|
+
return {
|
|
820
|
+
accessToken: data.access_token,
|
|
821
|
+
refreshToken: params.resolveRefreshToken(data),
|
|
822
|
+
expiresAt: data.expiresAt,
|
|
823
|
+
scopes: data.scope ? data.scope.split(" ") : [...scopes]
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
async function exchangeMSTeamsCodeForTokens(params) {
|
|
827
|
+
return await requestMSTeamsDelegatedTokens({
|
|
828
|
+
tenantId: params.tenantId,
|
|
829
|
+
clientId: params.clientId,
|
|
830
|
+
clientSecret: params.clientSecret,
|
|
831
|
+
grantType: "authorization_code",
|
|
832
|
+
scopes: params.scopes,
|
|
833
|
+
values: {
|
|
834
|
+
code: params.code,
|
|
835
|
+
redirect_uri: MSTEAMS_OAUTH_REDIRECT_URI,
|
|
836
|
+
code_verifier: params.verifier
|
|
837
|
+
},
|
|
838
|
+
auditContext: "msteams-oauth-token-exchange",
|
|
839
|
+
failureLabel: "token exchange",
|
|
840
|
+
resolveRefreshToken: (data) => {
|
|
841
|
+
if (!data.refresh_token) throw new Error("No refresh token received from Azure AD. Please try again.");
|
|
842
|
+
return data.refresh_token;
|
|
843
|
+
}
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
async function refreshMSTeamsDelegatedTokens(params) {
|
|
847
|
+
return await requestMSTeamsDelegatedTokens({
|
|
848
|
+
tenantId: params.tenantId,
|
|
849
|
+
clientId: params.clientId,
|
|
850
|
+
clientSecret: params.clientSecret,
|
|
851
|
+
grantType: "refresh_token",
|
|
852
|
+
scopes: params.scopes,
|
|
853
|
+
values: { refresh_token: params.refreshToken },
|
|
854
|
+
auditContext: "msteams-oauth-token-refresh",
|
|
855
|
+
failureLabel: "token refresh",
|
|
856
|
+
resolveRefreshToken: (data) => data.refresh_token ?? params.refreshToken
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
//#endregion
|
|
731
860
|
//#region extensions/msteams/src/storage.ts
|
|
732
861
|
function resolveMSTeamsStorePath(params) {
|
|
733
862
|
if (params.storePath) return params.storePath;
|
|
@@ -1032,179 +1161,219 @@ async function searchGraphUsers(params) {
|
|
|
1032
1161
|
})).value ?? [];
|
|
1033
1162
|
}
|
|
1034
1163
|
//#endregion
|
|
1035
|
-
//#region extensions/msteams/src/
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
if (
|
|
1042
|
-
|
|
1043
|
-
if (
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
return JSON.stringify(err) ?? "unknown error";
|
|
1047
|
-
} catch {
|
|
1048
|
-
return "unknown error";
|
|
1164
|
+
//#region extensions/msteams/src/resolve-allowlist.ts
|
|
1165
|
+
function stripProviderPrefix(raw) {
|
|
1166
|
+
return raw.replace(/^(msteams|teams):/i, "");
|
|
1167
|
+
}
|
|
1168
|
+
function normalizeMSTeamsMessagingTarget(raw) {
|
|
1169
|
+
let trimmed = raw.trim();
|
|
1170
|
+
if (!trimmed) return;
|
|
1171
|
+
trimmed = stripProviderPrefix(trimmed).trim();
|
|
1172
|
+
if (/^conversation:/i.test(trimmed)) {
|
|
1173
|
+
const id = trimmed.slice(13).trim();
|
|
1174
|
+
return id ? `conversation:${id}` : void 0;
|
|
1049
1175
|
}
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
const parseStatusCode = (value) => {
|
|
1054
|
-
if (typeof value === "number") return Number.isInteger(value) && value >= 100 && value <= 599 ? value : null;
|
|
1055
|
-
if (typeof value === "string") {
|
|
1056
|
-
const trimmed = value.trim();
|
|
1057
|
-
if (!/^\d{3}$/.test(trimmed)) return null;
|
|
1058
|
-
const parsed = Number(trimmed);
|
|
1059
|
-
return parsed >= 100 && parsed <= 599 ? parsed : null;
|
|
1060
|
-
}
|
|
1061
|
-
return null;
|
|
1062
|
-
};
|
|
1063
|
-
const directStatus = parseStatusCode(err.statusCode ?? err.status);
|
|
1064
|
-
if (directStatus !== null) return directStatus;
|
|
1065
|
-
const response = err.response;
|
|
1066
|
-
if (isRecord(response)) {
|
|
1067
|
-
const responseStatus = parseStatusCode(response.status);
|
|
1068
|
-
if (responseStatus !== null) return responseStatus;
|
|
1176
|
+
if (/^user:/i.test(trimmed)) {
|
|
1177
|
+
const id = trimmed.slice(5).trim();
|
|
1178
|
+
return id ? `user:${id}` : void 0;
|
|
1069
1179
|
}
|
|
1070
|
-
return
|
|
1180
|
+
return trimmed || void 0;
|
|
1071
1181
|
}
|
|
1072
|
-
function
|
|
1073
|
-
|
|
1074
|
-
const direct = err.code;
|
|
1075
|
-
if (typeof direct === "string" && direct.trim()) return direct;
|
|
1076
|
-
const response = err.response;
|
|
1077
|
-
if (!isRecord(response)) return null;
|
|
1078
|
-
const body = response.body;
|
|
1079
|
-
if (isRecord(body)) {
|
|
1080
|
-
const error = body.error;
|
|
1081
|
-
if (isRecord(error) && typeof error.code === "string" && error.code.trim()) return error.code;
|
|
1082
|
-
}
|
|
1083
|
-
return null;
|
|
1182
|
+
function normalizeMSTeamsUserInput(raw) {
|
|
1183
|
+
return stripProviderPrefix(raw).replace(/^(user|conversation):/i, "").trim();
|
|
1084
1184
|
}
|
|
1085
|
-
function
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
max: Number.MAX_SAFE_INTEGER
|
|
1090
|
-
});
|
|
1091
|
-
if (directMs !== void 0) return directMs;
|
|
1092
|
-
const retryAfter = err.retryAfter ?? err.retry_after;
|
|
1093
|
-
const retryAfterSeconds = asFiniteNumberInRange(retryAfter, {
|
|
1094
|
-
min: 0,
|
|
1095
|
-
max: MAX_SAFE_RETRY_AFTER_SECONDS
|
|
1096
|
-
});
|
|
1097
|
-
if (retryAfterSeconds !== void 0) return retryAfterSeconds * 1e3;
|
|
1098
|
-
if (typeof retryAfter === "string") {
|
|
1099
|
-
const parsed = parseNonNegativeRetryAfterSeconds(retryAfter);
|
|
1100
|
-
if (parsed !== void 0) return parsed * 1e3;
|
|
1101
|
-
}
|
|
1102
|
-
const response = err.response;
|
|
1103
|
-
if (!isRecord(response)) return null;
|
|
1104
|
-
const headers = response.headers;
|
|
1105
|
-
if (!headers) return null;
|
|
1106
|
-
if (isRecord(headers)) {
|
|
1107
|
-
const raw = headers["retry-after"] ?? headers["Retry-After"];
|
|
1108
|
-
if (typeof raw === "string") {
|
|
1109
|
-
const parsed = parseNonNegativeRetryAfterSeconds(raw);
|
|
1110
|
-
if (parsed !== void 0) return parsed * 1e3;
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
if (typeof headers === "object" && headers !== null && "get" in headers && typeof headers.get === "function") {
|
|
1114
|
-
const raw = headers.get("retry-after");
|
|
1115
|
-
if (raw) {
|
|
1116
|
-
const parsed = parseNonNegativeRetryAfterSeconds(raw);
|
|
1117
|
-
if (parsed !== void 0) return parsed * 1e3;
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
return null;
|
|
1121
|
-
}
|
|
1122
|
-
function parseNonNegativeRetryAfterSeconds(raw) {
|
|
1123
|
-
const trimmed = raw.trim();
|
|
1124
|
-
if (!/^\d+(?:\.\d+)?$/.test(trimmed)) return;
|
|
1125
|
-
return asFiniteNumberInRange(parseStrictFiniteNumber(trimmed), {
|
|
1126
|
-
min: 0,
|
|
1127
|
-
max: MAX_SAFE_RETRY_AFTER_SECONDS
|
|
1128
|
-
});
|
|
1185
|
+
function parseMSTeamsConversationId(raw) {
|
|
1186
|
+
const trimmed = stripProviderPrefix(raw).trim();
|
|
1187
|
+
if (!/^conversation:/i.test(trimmed)) return null;
|
|
1188
|
+
return trimmed.slice(13).trim();
|
|
1129
1189
|
}
|
|
1130
1190
|
/**
|
|
1131
|
-
*
|
|
1191
|
+
* Detect whether a raw target string looks like a Microsoft Teams conversation
|
|
1192
|
+
* or user id that cron announce delivery and other explicit-target paths can
|
|
1193
|
+
* forward verbatim to the channel adapter.
|
|
1132
1194
|
*
|
|
1133
|
-
*
|
|
1134
|
-
*
|
|
1135
|
-
*
|
|
1136
|
-
*
|
|
1195
|
+
* Accepts both prefixed and bare formats:
|
|
1196
|
+
* - `conversation:<id>` — explicit conversation prefix
|
|
1197
|
+
* - `user:<aad-guid>` — user id (16+ hex chars, UUID-like)
|
|
1198
|
+
* - `19:abc@thread.tacv2` / `19:abc@thread.skype` — channel / legacy group
|
|
1199
|
+
* - `19:{userId}_{appId}@unq.gbl.spaces` — Graph 1:1 chat thread format
|
|
1200
|
+
* - `a:1xxx` — Bot Framework personal (1:1) chat id
|
|
1201
|
+
* - `8:orgid:xxx` — Bot Framework org-scoped personal chat id
|
|
1202
|
+
* - `29:xxx` — Bot Framework user id
|
|
1203
|
+
*
|
|
1204
|
+
* Display-name user targets such as `user:John Smith` intentionally return
|
|
1205
|
+
* false so that the Graph API directory lookup still runs for them.
|
|
1137
1206
|
*/
|
|
1138
|
-
function
|
|
1139
|
-
const
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
if (
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
errorCode
|
|
1146
|
-
};
|
|
1147
|
-
if (statusCode === 403) {
|
|
1148
|
-
if (errorCode === "ContentStreamNotAllowed") return {
|
|
1149
|
-
kind: "permanent",
|
|
1150
|
-
statusCode,
|
|
1151
|
-
errorCode
|
|
1152
|
-
};
|
|
1153
|
-
return {
|
|
1154
|
-
kind: "auth",
|
|
1155
|
-
statusCode,
|
|
1156
|
-
errorCode
|
|
1157
|
-
};
|
|
1207
|
+
function looksLikeMSTeamsTargetId(raw) {
|
|
1208
|
+
const trimmed = raw.trim();
|
|
1209
|
+
if (!trimmed) return false;
|
|
1210
|
+
if (/^conversation:/i.test(trimmed)) return true;
|
|
1211
|
+
if (/^user:/i.test(trimmed)) {
|
|
1212
|
+
const id = trimmed.slice(5).trim();
|
|
1213
|
+
return /^[0-9a-fA-F-]{16,}$/.test(id);
|
|
1158
1214
|
}
|
|
1159
|
-
if (
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1215
|
+
if (/^19:.+@thread\.(tacv2|skype)$/i.test(trimmed)) return true;
|
|
1216
|
+
if (/^19:.+@unq\.gbl\.spaces$/i.test(trimmed)) return true;
|
|
1217
|
+
if (/^a:1[A-Za-z0-9_-]+$/i.test(trimmed)) return true;
|
|
1218
|
+
if (/^8:orgid:[A-Za-z0-9-]+$/i.test(trimmed)) return true;
|
|
1219
|
+
if (/^29:[A-Za-z0-9_-]+$/i.test(trimmed)) return true;
|
|
1220
|
+
return /@thread\b/i.test(trimmed);
|
|
1221
|
+
}
|
|
1222
|
+
function normalizeMSTeamsTeamKey(raw) {
|
|
1223
|
+
return stripProviderPrefix(raw).replace(/^team:/i, "").trim() || void 0;
|
|
1224
|
+
}
|
|
1225
|
+
function normalizeMSTeamsChannelKey(raw) {
|
|
1226
|
+
return (raw?.trim().replace(/^#/, "").trim() ?? "") || void 0;
|
|
1227
|
+
}
|
|
1228
|
+
function normalizeMSTeamsConversationTargetId(raw) {
|
|
1229
|
+
const trimmed = stripProviderPrefix(raw).trim();
|
|
1230
|
+
return parseMSTeamsConversationId(trimmed) ?? trimmed;
|
|
1231
|
+
}
|
|
1232
|
+
function looksLikeMSTeamsThreadConversationId(raw) {
|
|
1233
|
+
const normalized = normalizeMSTeamsConversationTargetId(raw);
|
|
1234
|
+
return /^19:.+@thread\./i.test(normalized);
|
|
1235
|
+
}
|
|
1236
|
+
function parseMSTeamsTeamChannelInput(raw) {
|
|
1237
|
+
const trimmed = stripProviderPrefix(raw).trim();
|
|
1238
|
+
if (!trimmed) return {};
|
|
1239
|
+
const parts = trimmed.split("/");
|
|
1240
|
+
const team = normalizeMSTeamsTeamKey(parts[0] ?? "");
|
|
1241
|
+
const channel = parts.length > 1 ? normalizeMSTeamsChannelKey(parts.slice(1).join("/")) : void 0;
|
|
1242
|
+
return {
|
|
1243
|
+
...team ? { team } : {},
|
|
1244
|
+
...channel ? { channel } : {}
|
|
1175
1245
|
};
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
errorCode: networkCode
|
|
1181
|
-
};
|
|
1182
|
-
}
|
|
1246
|
+
}
|
|
1247
|
+
function parseMSTeamsTeamEntry(raw) {
|
|
1248
|
+
const { team, channel } = parseMSTeamsTeamChannelInput(raw);
|
|
1249
|
+
if (!team) return null;
|
|
1183
1250
|
return {
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
retryAfterMs: retryAfterMs ?? void 0,
|
|
1187
|
-
errorCode
|
|
1251
|
+
teamKey: team,
|
|
1252
|
+
...channel ? { channelKey: channel } : {}
|
|
1188
1253
|
};
|
|
1189
1254
|
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1255
|
+
async function resolveMSTeamsChannelAllowlist(params) {
|
|
1256
|
+
let tokenPromise;
|
|
1257
|
+
const getToken = () => {
|
|
1258
|
+
tokenPromise ??= resolveGraphToken(params.cfg);
|
|
1259
|
+
return tokenPromise;
|
|
1260
|
+
};
|
|
1261
|
+
return await mapAllowlistResolutionInputs({
|
|
1262
|
+
inputs: params.entries,
|
|
1263
|
+
mapInput: async (input) => {
|
|
1264
|
+
const { team, channel } = parseMSTeamsTeamChannelInput(input);
|
|
1265
|
+
if (!team) return {
|
|
1266
|
+
input,
|
|
1267
|
+
resolved: false
|
|
1268
|
+
};
|
|
1269
|
+
if (looksLikeMSTeamsThreadConversationId(team)) {
|
|
1270
|
+
const teamId = normalizeMSTeamsConversationTargetId(team);
|
|
1271
|
+
if (!channel) return {
|
|
1272
|
+
input,
|
|
1273
|
+
resolved: true,
|
|
1274
|
+
teamId,
|
|
1275
|
+
teamName: teamId
|
|
1276
|
+
};
|
|
1277
|
+
if (!looksLikeMSTeamsThreadConversationId(channel)) return {
|
|
1278
|
+
input,
|
|
1279
|
+
resolved: false,
|
|
1280
|
+
teamId,
|
|
1281
|
+
teamName: teamId,
|
|
1282
|
+
note: "channel id required for conversation-id team"
|
|
1283
|
+
};
|
|
1284
|
+
const channelId = normalizeMSTeamsConversationTargetId(channel);
|
|
1285
|
+
return {
|
|
1286
|
+
input,
|
|
1287
|
+
resolved: true,
|
|
1288
|
+
teamId,
|
|
1289
|
+
teamName: teamId,
|
|
1290
|
+
channelId,
|
|
1291
|
+
channelName: channelId
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
1294
|
+
const token = await getToken();
|
|
1295
|
+
const teams = /^[0-9a-fA-F-]{16,}$/.test(team) ? [{
|
|
1296
|
+
id: team,
|
|
1297
|
+
displayName: team
|
|
1298
|
+
}] : await listTeamsByName(token, team);
|
|
1299
|
+
if (teams.length === 0) return {
|
|
1300
|
+
input,
|
|
1301
|
+
resolved: false,
|
|
1302
|
+
note: "team not found"
|
|
1303
|
+
};
|
|
1304
|
+
const teamMatch = teams[0];
|
|
1305
|
+
const graphTeamId = teamMatch.id?.trim();
|
|
1306
|
+
const teamName = teamMatch.displayName?.trim() || team;
|
|
1307
|
+
if (!graphTeamId) return {
|
|
1308
|
+
input,
|
|
1309
|
+
resolved: false,
|
|
1310
|
+
note: "team id missing"
|
|
1311
|
+
};
|
|
1312
|
+
let teamChannels = [];
|
|
1313
|
+
try {
|
|
1314
|
+
teamChannels = await listChannelsForTeam(token, graphTeamId);
|
|
1315
|
+
} catch {}
|
|
1316
|
+
const teamId = teamChannels.find((ch) => normalizeOptionalLowercaseString(ch.displayName) === "general")?.id?.trim() || graphTeamId;
|
|
1317
|
+
if (!channel) return {
|
|
1318
|
+
input,
|
|
1319
|
+
resolved: true,
|
|
1320
|
+
teamId,
|
|
1321
|
+
teamName,
|
|
1322
|
+
note: teams.length > 1 ? "multiple teams; chose first" : void 0
|
|
1323
|
+
};
|
|
1324
|
+
const normalizedChannel = normalizeOptionalLowercaseString(channel);
|
|
1325
|
+
const channelMatch = teamChannels.find((item) => item.id === channel) ?? teamChannels.find((item) => normalizeOptionalLowercaseString(item.displayName) === normalizedChannel) ?? teamChannels.find((item) => normalizeLowercaseStringOrEmpty(item.displayName ?? "").includes(normalizedChannel ?? ""));
|
|
1326
|
+
if (!channelMatch?.id) return {
|
|
1327
|
+
input,
|
|
1328
|
+
resolved: false,
|
|
1329
|
+
note: "channel not found"
|
|
1330
|
+
};
|
|
1331
|
+
return {
|
|
1332
|
+
input,
|
|
1333
|
+
resolved: true,
|
|
1334
|
+
teamId,
|
|
1335
|
+
teamName,
|
|
1336
|
+
channelId: channelMatch.id,
|
|
1337
|
+
channelName: channelMatch.displayName ?? channel,
|
|
1338
|
+
note: teamChannels.length > 1 ? "multiple channels; chose first" : void 0
|
|
1339
|
+
};
|
|
1340
|
+
}
|
|
1341
|
+
});
|
|
1201
1342
|
}
|
|
1202
|
-
function
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1343
|
+
async function resolveMSTeamsUserAllowlist(params) {
|
|
1344
|
+
const token = await resolveGraphToken(params.cfg);
|
|
1345
|
+
return await mapAllowlistResolutionInputs({
|
|
1346
|
+
inputs: params.entries,
|
|
1347
|
+
mapInput: async (input) => {
|
|
1348
|
+
const query = normalizeQuery(normalizeMSTeamsUserInput(input));
|
|
1349
|
+
if (!query) return {
|
|
1350
|
+
input,
|
|
1351
|
+
resolved: false
|
|
1352
|
+
};
|
|
1353
|
+
if (/^[0-9a-fA-F-]{16,}$/.test(query)) return {
|
|
1354
|
+
input,
|
|
1355
|
+
resolved: true,
|
|
1356
|
+
id: query
|
|
1357
|
+
};
|
|
1358
|
+
const users = await searchGraphUsers({
|
|
1359
|
+
token,
|
|
1360
|
+
query,
|
|
1361
|
+
top: 10
|
|
1362
|
+
});
|
|
1363
|
+
const match = users[0];
|
|
1364
|
+
if (!match?.id) return {
|
|
1365
|
+
input,
|
|
1366
|
+
resolved: false
|
|
1367
|
+
};
|
|
1368
|
+
return {
|
|
1369
|
+
input,
|
|
1370
|
+
resolved: true,
|
|
1371
|
+
id: match.id,
|
|
1372
|
+
name: match.displayName ?? void 0,
|
|
1373
|
+
note: users.length > 1 ? "multiple matches; chose first" : void 0
|
|
1374
|
+
};
|
|
1375
|
+
}
|
|
1376
|
+
});
|
|
1208
1377
|
}
|
|
1209
1378
|
//#endregion
|
|
1210
|
-
export {
|
|
1379
|
+
export { inferPlaceholder as $, MSTEAMS_OAUTH_REDIRECT_URI as A, normalizeBotFrameworkServiceUrl as B, resolveMSTeamsCredentials as C, MSTEAMS_DEFAULT_DELEGATED_SCOPES as D, exchangeMSTeamsCodeForTokens as E, loadMSTeamsSdkWithAuth as F, ATTACHMENT_TAG_RE as G, createMSTeamsHttpError as H, buildUserAgent as I, applyAuthorizationHeaderForUrl as J, GRAPH_ROOT as K, ensureUserAgentHeader as L, readAccessToken as M, createMSTeamsExpressAdapter as N, MSTEAMS_OAUTH_CALLBACK_PATH as O, createMSTeamsTokenProvider as P, extractInlineImageCandidates as Q, describeBotFrameworkServiceUrlHost as R, loadDelegatedTokens as S, normalizeSecretInputString as T, resolveMSTeamsSdkCloudOptions as U, tryNormalizeBotFrameworkServiceUrl as V, validateMSTeamsProactiveServiceUrlBoundary as W, estimateBase64DecodedBytes as X, encodeGraphShareId as Y, extractHtmlFromAttachment as Z, patchGraphJson as _, parseMSTeamsTeamChannelInput as a, readNestedString as at, resolveGraphToken as b, resolveMSTeamsUserAllowlist as c, resolveRequestUrl as ct, escapeOData as d, tryBuildGraphSharesUrlForSharedLink as dt, isDownloadableAttachment as et, fetchGraphAbsoluteUrl as f, normalizeQuery as g, listTeamsByName as h, parseMSTeamsConversationId as i, normalizeContentType as it, buildMSTeamsAuthEndpoint as j, MSTEAMS_OAUTH_CALLBACK_PORT as k, searchGraphUsers as l, safeFetchWithPolicy as lt, listChannelsForTeam as m, normalizeMSTeamsMessagingTarget as n, isRecord$1 as nt, parseMSTeamsTeamEntry as o, resolveAttachmentFetchPolicy as ot, fetchGraphJson as p, IMG_SRC_RE as q, normalizeMSTeamsUserInput as r, isUrlAllowed as rt, resolveMSTeamsChannelAllowlist as s, resolveMediaSsrfPolicy as st, looksLikeMSTeamsTargetId as t, isLikelyImageAttachment as tt, deleteGraphRequest as u, safeHostForUrl as ut, postGraphBetaJson as v, saveDelegatedTokens as w, hasConfiguredMSTeamsCredentials as x, postGraphJson as y, isAllowedBotFrameworkServiceUrl as z };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
2
|
+
//#region extensions/msteams/src/runtime.ts
|
|
3
|
+
const { setRuntime: setMSTeamsRuntime, getRuntime: getMSTeamsRuntime, tryGetRuntime: getOptionalMSTeamsRuntime } = createPluginRuntimeStore({
|
|
4
|
+
pluginId: "msteams",
|
|
5
|
+
errorMessage: "MSTeams runtime not initialized"
|
|
6
|
+
});
|
|
7
|
+
//#endregion
|
|
8
|
+
export { getOptionalMSTeamsRuntime as n, setMSTeamsRuntime as r, getMSTeamsRuntime as t };
|
package/dist/runtime-api.js
CHANGED
|
@@ -1,2 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { r as setMSTeamsRuntime } from "./runtime-BS5AZrKK.js";
|
|
2
|
+
import { mergeAllowlist, resolveAllowlistMatchSimple, summarizeMapping } from "openclaw/plugin-sdk/allow-from";
|
|
3
|
+
import { createChannelMessageReplyPipeline, keepHttpServerTaskAlive, logTypingFailure } from "openclaw/plugin-sdk/channel-outbound";
|
|
4
|
+
import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
|
|
5
|
+
import { resolveToolsBySender } from "openclaw/plugin-sdk/channel-policy";
|
|
6
|
+
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
|
|
7
|
+
import { PAIRING_APPROVED_MESSAGE, buildProbeChannelStatusSummary, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/channel-status";
|
|
8
|
+
import { buildChannelKeyCandidates, normalizeChannelSlug, resolveChannelEntryMatchWithFallback, resolveNestedAllowlistDecision } from "openclaw/plugin-sdk/channel-targets";
|
|
9
|
+
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
|
|
10
|
+
import { resolveDefaultGroupPolicy } from "openclaw/plugin-sdk/runtime-group-policy";
|
|
11
|
+
import { withFileLock } from "openclaw/plugin-sdk/file-lock";
|
|
12
|
+
import { detectMime, extensionForMime, extractOriginalFilename, getFileExtension, resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime";
|
|
13
|
+
import { dispatchReplyFromConfigWithSettledDispatcher } from "openclaw/plugin-sdk/channel-inbound";
|
|
14
|
+
import { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media";
|
|
15
|
+
import { buildMediaPayload } from "openclaw/plugin-sdk/reply-payload";
|
|
16
|
+
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
17
|
+
import { normalizeStringEntries } from "openclaw/plugin-sdk/string-normalization-runtime";
|
|
18
|
+
import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
|
|
19
|
+
import { DEFAULT_WEBHOOK_MAX_BODY_BYTES } from "openclaw/plugin-sdk/webhook-ingress";
|
|
2
20
|
export { DEFAULT_ACCOUNT_ID, DEFAULT_WEBHOOK_MAX_BODY_BYTES, PAIRING_APPROVED_MESSAGE, buildChannelKeyCandidates, buildMediaPayload, buildProbeChannelStatusSummary, chunkTextForOutbound, createChannelMessageReplyPipeline, createChannelPairingController, createDefaultChannelRuntimeState, detectMime, dispatchReplyFromConfigWithSettledDispatcher, extensionForMime, extractOriginalFilename, fetchWithSsrFGuard, getFileExtension, isDangerousNameMatchingEnabled, keepHttpServerTaskAlive, loadOutboundMediaFromUrl, logTypingFailure, mergeAllowlist, normalizeChannelSlug, normalizeStringEntries, resolveAllowlistMatchSimple, resolveChannelEntryMatchWithFallback, resolveChannelMediaMaxBytes, resolveDefaultGroupPolicy, resolveNestedAllowlistDecision, resolveToolsBySender, setMSTeamsRuntime, summarizeMapping, withFileLock };
|
package/dist/setup-plugin-api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { i as msteamsSetupAdapter, t as msteamsSetupWizard } from "./setup-surface-DGTz8Mlf.js";
|
|
1
|
+
import { C as resolveMSTeamsCredentials } from "./resolve-allowlist-BzIUWmMm.js";
|
|
3
2
|
import { t as MSTeamsChannelConfigSchema } from "./config-schema-BL4qQZiA.js";
|
|
3
|
+
import { c as msteamsSetupAdapter, t as msteamsSetupWizard } from "./setup-surface-Dik4VU7f.js";
|
|
4
4
|
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
5
5
|
import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from";
|
|
6
6
|
import { createTopLevelChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
|