@kodelyth/msteams 2026.5.39 → 2026.5.42
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/api.ts +3 -0
- package/channel-config-api.ts +1 -0
- package/channel-plugin-api.ts +2 -0
- package/config-api.ts +4 -0
- package/contract-api.ts +4 -0
- package/dist/api.js +3 -0
- package/dist/channel-BvTXHuGs.js +1161 -0
- package/dist/channel-config-api.js +2 -0
- package/dist/channel-plugin-api.js +2 -0
- package/dist/channel.runtime-NssGKZm5.js +650 -0
- package/dist/config-schema-Btk-XCOd.js +43 -0
- package/dist/contract-api.js +2 -0
- package/dist/graph-users-D-gKCguI.js +1411 -0
- package/dist/index.js +22 -0
- package/dist/oauth-BUxlphX3.js +114 -0
- package/dist/oauth.token-ebId9946.js +116 -0
- package/dist/probe-Cj2KsAGF.js +2190 -0
- package/dist/runtime-api-BL4DOWXD.js +28 -0
- package/dist/runtime-api.js +2 -0
- package/dist/secret-contract-Bo7kdUrT.js +35 -0
- package/dist/secret-contract-api.js +2 -0
- package/dist/setup-entry.js +15 -0
- package/dist/setup-plugin-api.js +64 -0
- package/dist/setup-surface-COTQDcTQ.js +531 -0
- package/dist/src-tvpsGYPV.js +4226 -0
- package/dist/test-api.js +2 -0
- package/index.ts +20 -0
- package/klaw.plugin.json +2 -726
- package/package.json +4 -4
- package/runtime-api.ts +66 -0
- package/secret-contract-api.ts +5 -0
- package/setup-entry.ts +13 -0
- package/setup-plugin-api.ts +3 -0
- package/src/ai-entity.ts +7 -0
- package/src/approval-auth.ts +44 -0
- package/src/attachments/bot-framework.test.ts +506 -0
- package/src/attachments/bot-framework.ts +348 -0
- package/src/attachments/download.ts +328 -0
- package/src/attachments/graph.test.ts +441 -0
- package/src/attachments/graph.ts +489 -0
- package/src/attachments/html.ts +122 -0
- package/src/attachments/payload.ts +14 -0
- package/src/attachments/remote-media.test.ts +187 -0
- package/src/attachments/remote-media.ts +86 -0
- package/src/attachments/shared.test.ts +547 -0
- package/src/attachments/shared.ts +655 -0
- package/src/attachments/types.ts +47 -0
- package/src/attachments.graph.test.ts +414 -0
- package/src/attachments.helpers.test.ts +245 -0
- package/src/attachments.test-helpers.ts +17 -0
- package/src/attachments.test.ts +754 -0
- package/src/attachments.ts +18 -0
- package/src/block-streaming-config.test.ts +61 -0
- package/src/channel-api.ts +1 -0
- package/src/channel.actions.test.ts +797 -0
- package/src/channel.directory.test.ts +176 -0
- package/src/channel.message-adapter.test.ts +227 -0
- package/src/channel.runtime.ts +56 -0
- package/src/channel.setup.ts +77 -0
- package/src/channel.test.ts +136 -0
- package/src/channel.ts +1176 -0
- package/src/config-schema.ts +6 -0
- package/src/config-ui-hints.ts +40 -0
- package/src/conversation-store-fs.test.ts +81 -0
- package/src/conversation-store-fs.ts +149 -0
- package/src/conversation-store-helpers.test.ts +202 -0
- package/src/conversation-store-helpers.ts +105 -0
- package/src/conversation-store-memory.ts +51 -0
- package/src/conversation-store.shared.test.ts +260 -0
- package/src/conversation-store.ts +71 -0
- package/src/directory-live.test.ts +156 -0
- package/src/directory-live.ts +111 -0
- package/src/doctor.ts +27 -0
- package/src/errors.test.ts +154 -0
- package/src/errors.ts +270 -0
- package/src/feedback-reflection-prompt.ts +117 -0
- package/src/feedback-reflection-store.ts +113 -0
- package/src/feedback-reflection.test.ts +237 -0
- package/src/feedback-reflection.ts +268 -0
- package/src/file-consent-helpers.test.ts +328 -0
- package/src/file-consent-helpers.ts +115 -0
- package/src/file-consent-invoke.ts +150 -0
- package/src/file-consent.test.ts +378 -0
- package/src/file-consent.ts +223 -0
- package/src/graph-chat.ts +36 -0
- package/src/graph-group-management.test.ts +332 -0
- package/src/graph-group-management.ts +168 -0
- package/src/graph-members.test.ts +89 -0
- package/src/graph-members.ts +48 -0
- package/src/graph-messages.actions.test.ts +253 -0
- package/src/graph-messages.read.test.ts +391 -0
- package/src/graph-messages.search.test.ts +227 -0
- package/src/graph-messages.test-helpers.ts +50 -0
- package/src/graph-messages.ts +534 -0
- package/src/graph-teams.test.ts +222 -0
- package/src/graph-teams.ts +114 -0
- package/src/graph-thread.test.ts +252 -0
- package/src/graph-thread.ts +146 -0
- package/src/graph-upload.test.ts +253 -0
- package/src/graph-upload.ts +531 -0
- package/src/graph-users.ts +29 -0
- package/src/graph.test.ts +540 -0
- package/src/graph.ts +308 -0
- package/src/inbound.test.ts +221 -0
- package/src/inbound.ts +148 -0
- package/src/index.ts +4 -0
- package/src/media-helpers.test.ts +220 -0
- package/src/media-helpers.ts +105 -0
- package/src/mentions.test.ts +254 -0
- package/src/mentions.ts +114 -0
- package/src/messenger.test.ts +961 -0
- package/src/messenger.ts +608 -0
- package/src/monitor-handler/access.ts +136 -0
- package/src/monitor-handler/inbound-media.test.ts +314 -0
- package/src/monitor-handler/inbound-media.ts +180 -0
- package/src/monitor-handler/message-handler-mock-support.test-support.ts +28 -0
- package/src/monitor-handler/message-handler.authz.test.ts +739 -0
- package/src/monitor-handler/message-handler.dm-media.test.ts +54 -0
- package/src/monitor-handler/message-handler.test-support.ts +99 -0
- package/src/monitor-handler/message-handler.thread-parent.test.ts +225 -0
- package/src/monitor-handler/message-handler.thread-session.test.ts +132 -0
- package/src/monitor-handler/message-handler.ts +1003 -0
- package/src/monitor-handler/reaction-handler.test.ts +325 -0
- package/src/monitor-handler/reaction-handler.ts +122 -0
- package/src/monitor-handler/thread-session.ts +30 -0
- package/src/monitor-handler.adaptive-card.test.ts +158 -0
- package/src/monitor-handler.feedback-authz.test.ts +357 -0
- package/src/monitor-handler.file-consent.test.ts +443 -0
- package/src/monitor-handler.sso.test.ts +576 -0
- package/src/monitor-handler.test-helpers.ts +181 -0
- package/src/monitor-handler.ts +538 -0
- package/src/monitor-handler.types.ts +27 -0
- package/src/monitor-types.ts +6 -0
- package/src/monitor.lifecycle.test.ts +457 -0
- package/src/monitor.test.ts +119 -0
- package/src/monitor.ts +476 -0
- package/src/oauth.flow.ts +77 -0
- package/src/oauth.shared.ts +37 -0
- package/src/oauth.test.ts +350 -0
- package/src/oauth.token.ts +162 -0
- package/src/oauth.ts +130 -0
- package/src/outbound.test.ts +400 -0
- package/src/outbound.ts +198 -0
- package/src/pending-uploads-fs.test.ts +261 -0
- package/src/pending-uploads-fs.ts +235 -0
- package/src/pending-uploads.test.ts +186 -0
- package/src/pending-uploads.ts +121 -0
- package/src/policy.test.ts +156 -0
- package/src/policy.ts +245 -0
- package/src/polls-store-memory.ts +32 -0
- package/src/polls.test.ts +169 -0
- package/src/polls.ts +312 -0
- package/src/presentation.ts +93 -0
- package/src/probe.test.ts +79 -0
- package/src/probe.ts +132 -0
- package/src/reply-dispatcher.test.ts +543 -0
- package/src/reply-dispatcher.ts +523 -0
- package/src/reply-stream-controller.test.ts +424 -0
- package/src/reply-stream-controller.ts +334 -0
- package/src/resolve-allowlist.test.ts +253 -0
- package/src/resolve-allowlist.ts +309 -0
- package/src/revoked-context.ts +17 -0
- package/src/runtime.ts +12 -0
- package/src/sdk-types.ts +59 -0
- package/src/sdk.test.ts +727 -0
- package/src/sdk.ts +916 -0
- package/src/secret-contract.ts +49 -0
- package/src/secret-input.ts +7 -0
- package/src/send-context.test.ts +93 -0
- package/src/send-context.ts +269 -0
- package/src/send.test.ts +588 -0
- package/src/send.ts +697 -0
- package/src/sent-message-cache.test.ts +106 -0
- package/src/sent-message-cache.ts +174 -0
- package/src/session-route.ts +40 -0
- package/src/setup-core.ts +162 -0
- package/src/setup-surface.test.ts +175 -0
- package/src/setup-surface.ts +319 -0
- package/src/sso-token-store.test.ts +74 -0
- package/src/sso-token-store.ts +166 -0
- package/src/sso.ts +300 -0
- package/src/storage.ts +25 -0
- package/src/store-fs.ts +42 -0
- package/src/streaming-message.test.ts +323 -0
- package/src/streaming-message.ts +327 -0
- package/src/test-runtime.ts +16 -0
- package/src/thread-parent-context.test.ts +224 -0
- package/src/thread-parent-context.ts +159 -0
- package/src/token-response.ts +11 -0
- package/src/token.test.ts +268 -0
- package/src/token.ts +194 -0
- package/src/user-agent.test.ts +121 -0
- package/src/user-agent.ts +53 -0
- package/src/webhook-timeouts.ts +27 -0
- package/src/welcome-card.test.ts +104 -0
- package/src/welcome-card.ts +57 -0
- package/test-api.ts +1 -0
- package/tsconfig.json +16 -0
- package/api.js +0 -7
- package/channel-config-api.js +0 -7
- package/channel-plugin-api.js +0 -7
- package/contract-api.js +0 -7
- package/index.js +0 -7
- package/runtime-api.js +0 -7
- package/secret-contract-api.js +0 -7
- package/setup-entry.js +0 -7
- package/setup-plugin-api.js +0 -7
- package/test-api.js +0 -7
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { mergeAllowlist, resolveAllowlistMatchSimple, summarizeMapping } from "klaw/plugin-sdk/allow-from";
|
|
2
|
+
import { createChannelMessageReplyPipeline } from "klaw/plugin-sdk/channel-message";
|
|
3
|
+
import { createChannelPairingController } from "klaw/plugin-sdk/channel-pairing";
|
|
4
|
+
import { resolveToolsBySender } from "klaw/plugin-sdk/channel-policy";
|
|
5
|
+
import { DEFAULT_ACCOUNT_ID } from "klaw/plugin-sdk/account-id";
|
|
6
|
+
import { logTypingFailure } from "klaw/plugin-sdk/channel-logging";
|
|
7
|
+
import { PAIRING_APPROVED_MESSAGE, buildProbeChannelStatusSummary, createDefaultChannelRuntimeState } from "klaw/plugin-sdk/channel-status";
|
|
8
|
+
import { buildChannelKeyCandidates, normalizeChannelSlug, resolveChannelEntryMatchWithFallback, resolveNestedAllowlistDecision } from "klaw/plugin-sdk/channel-targets";
|
|
9
|
+
import { isDangerousNameMatchingEnabled } from "klaw/plugin-sdk/dangerous-name-runtime";
|
|
10
|
+
import { resolveDefaultGroupPolicy } from "klaw/plugin-sdk/runtime-group-policy";
|
|
11
|
+
import { withFileLock as withFileLock$1 } from "klaw/plugin-sdk/file-lock";
|
|
12
|
+
import { keepHttpServerTaskAlive } from "klaw/plugin-sdk/channel-lifecycle";
|
|
13
|
+
import { detectMime, extensionForMime, extractOriginalFilename, getFileExtension, resolveChannelMediaMaxBytes } from "klaw/plugin-sdk/media-runtime";
|
|
14
|
+
import { dispatchReplyFromConfigWithSettledDispatcher as dispatchReplyFromConfigWithSettledDispatcher$1 } from "klaw/plugin-sdk/inbound-reply-dispatch";
|
|
15
|
+
import { loadOutboundMediaFromUrl } from "klaw/plugin-sdk/outbound-media";
|
|
16
|
+
import { buildMediaPayload } from "klaw/plugin-sdk/reply-payload";
|
|
17
|
+
import { fetchWithSsrFGuard as fetchWithSsrFGuard$1 } from "klaw/plugin-sdk/ssrf-runtime";
|
|
18
|
+
import { normalizeStringEntries } from "klaw/plugin-sdk/string-normalization-runtime";
|
|
19
|
+
import { chunkTextForOutbound } from "klaw/plugin-sdk/text-chunking";
|
|
20
|
+
import { DEFAULT_WEBHOOK_MAX_BODY_BYTES } from "klaw/plugin-sdk/webhook-ingress";
|
|
21
|
+
import { createPluginRuntimeStore } from "klaw/plugin-sdk/runtime-store";
|
|
22
|
+
//#region extensions/msteams/src/runtime.ts
|
|
23
|
+
const { setRuntime: setMSTeamsRuntime, getRuntime: getMSTeamsRuntime, tryGetRuntime: getOptionalMSTeamsRuntime } = createPluginRuntimeStore({
|
|
24
|
+
pluginId: "msteams",
|
|
25
|
+
errorMessage: "MSTeams runtime not initialized"
|
|
26
|
+
});
|
|
27
|
+
//#endregion
|
|
28
|
+
export { summarizeMapping as A, normalizeStringEntries as C, resolveDefaultGroupPolicy as D, resolveChannelMediaMaxBytes as E, getMSTeamsRuntime as M, getOptionalMSTeamsRuntime as N, resolveNestedAllowlistDecision as O, setMSTeamsRuntime as P, normalizeChannelSlug as S, resolveChannelEntryMatchWithFallback as T, isDangerousNameMatchingEnabled as _, buildMediaPayload as a, logTypingFailure as b, createChannelMessageReplyPipeline as c, detectMime as d, dispatchReplyFromConfigWithSettledDispatcher$1 as f, getFileExtension as g, fetchWithSsrFGuard$1 as h, buildChannelKeyCandidates as i, withFileLock$1 as j, resolveToolsBySender as k, createChannelPairingController as l, extractOriginalFilename as m, DEFAULT_WEBHOOK_MAX_BODY_BYTES as n, buildProbeChannelStatusSummary as o, extensionForMime as p, PAIRING_APPROVED_MESSAGE as r, chunkTextForOutbound as s, DEFAULT_ACCOUNT_ID as t, createDefaultChannelRuntimeState as u, keepHttpServerTaskAlive as v, resolveAllowlistMatchSimple as w, mergeAllowlist as x, loadOutboundMediaFromUrl as y };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { A as summarizeMapping, C as normalizeStringEntries, D as resolveDefaultGroupPolicy, E as resolveChannelMediaMaxBytes, O as resolveNestedAllowlistDecision, P as setMSTeamsRuntime, S as normalizeChannelSlug, T as resolveChannelEntryMatchWithFallback, _ as isDangerousNameMatchingEnabled, a as buildMediaPayload, b as logTypingFailure, c as createChannelMessageReplyPipeline, d as detectMime, f as dispatchReplyFromConfigWithSettledDispatcher, g as getFileExtension, h as fetchWithSsrFGuard, i as buildChannelKeyCandidates, j as withFileLock, k as resolveToolsBySender, l as createChannelPairingController, m as extractOriginalFilename, n as DEFAULT_WEBHOOK_MAX_BODY_BYTES, o as buildProbeChannelStatusSummary, p as extensionForMime, r as PAIRING_APPROVED_MESSAGE, s as chunkTextForOutbound, t as DEFAULT_ACCOUNT_ID, u as createDefaultChannelRuntimeState, v as keepHttpServerTaskAlive, w as resolveAllowlistMatchSimple, x as mergeAllowlist, y as loadOutboundMediaFromUrl } from "./runtime-api-BL4DOWXD.js";
|
|
2
|
+
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 };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { collectSecretInputAssignment, getChannelRecord } from "klaw/plugin-sdk/channel-secret-basic-runtime";
|
|
2
|
+
//#region extensions/msteams/src/secret-contract.ts
|
|
3
|
+
const secretTargetRegistryEntries = [{
|
|
4
|
+
id: "channels.msteams.appPassword",
|
|
5
|
+
targetType: "channels.msteams.appPassword",
|
|
6
|
+
configFile: "klaw.json",
|
|
7
|
+
pathPattern: "channels.msteams.appPassword",
|
|
8
|
+
secretShape: "secret_input",
|
|
9
|
+
expectedResolvedValue: "string",
|
|
10
|
+
includeInPlan: true,
|
|
11
|
+
includeInConfigure: true,
|
|
12
|
+
includeInAudit: true
|
|
13
|
+
}];
|
|
14
|
+
function collectRuntimeConfigAssignments(params) {
|
|
15
|
+
const msteams = getChannelRecord(params.config, "msteams");
|
|
16
|
+
if (!msteams) return;
|
|
17
|
+
collectSecretInputAssignment({
|
|
18
|
+
value: msteams.appPassword,
|
|
19
|
+
path: "channels.msteams.appPassword",
|
|
20
|
+
expected: "string",
|
|
21
|
+
defaults: params.defaults,
|
|
22
|
+
context: params.context,
|
|
23
|
+
active: msteams.enabled !== false,
|
|
24
|
+
inactiveReason: "Microsoft Teams channel is disabled.",
|
|
25
|
+
apply: (value) => {
|
|
26
|
+
msteams.appPassword = value;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const channelSecrets = {
|
|
31
|
+
secretTargetRegistryEntries,
|
|
32
|
+
collectRuntimeConfigAssignments
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
35
|
+
export { collectRuntimeConfigAssignments as n, secretTargetRegistryEntries as r, channelSecrets as t };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineBundledChannelSetupEntry } from "klaw/plugin-sdk/channel-entry-contract";
|
|
2
|
+
//#region extensions/msteams/setup-entry.ts
|
|
3
|
+
var setup_entry_default = defineBundledChannelSetupEntry({
|
|
4
|
+
importMetaUrl: import.meta.url,
|
|
5
|
+
plugin: {
|
|
6
|
+
specifier: "./setup-plugin-api.js",
|
|
7
|
+
exportName: "msteamsSetupPlugin"
|
|
8
|
+
},
|
|
9
|
+
secrets: {
|
|
10
|
+
specifier: "./secret-contract-api.js",
|
|
11
|
+
exportName: "channelSecrets"
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
//#endregion
|
|
15
|
+
export { setup_entry_default as default };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { h as resolveMSTeamsCredentials } from "./graph-users-D-gKCguI.js";
|
|
2
|
+
import { i as msteamsSetupAdapter, t as msteamsSetupWizard } from "./setup-surface-COTQDcTQ.js";
|
|
3
|
+
import { t as MSTeamsChannelConfigSchema } from "./config-schema-Btk-XCOd.js";
|
|
4
|
+
import { describeAccountSnapshot } from "klaw/plugin-sdk/account-helpers";
|
|
5
|
+
import { formatAllowFromLowercase } from "klaw/plugin-sdk/allow-from";
|
|
6
|
+
import { createTopLevelChannelConfigAdapter } from "klaw/plugin-sdk/channel-config-helpers";
|
|
7
|
+
//#region extensions/msteams/src/channel.setup.ts
|
|
8
|
+
const meta = {
|
|
9
|
+
id: "msteams",
|
|
10
|
+
label: "Microsoft Teams",
|
|
11
|
+
selectionLabel: "Microsoft Teams (Bot Framework)",
|
|
12
|
+
docsPath: "/channels/msteams",
|
|
13
|
+
docsLabel: "msteams",
|
|
14
|
+
blurb: "Teams SDK; enterprise support.",
|
|
15
|
+
aliases: ["teams"],
|
|
16
|
+
order: 60
|
|
17
|
+
};
|
|
18
|
+
const resolveMSTeamsChannelConfig = (cfg) => ({
|
|
19
|
+
allowFrom: cfg.channels?.msteams?.allowFrom,
|
|
20
|
+
defaultTo: cfg.channels?.msteams?.defaultTo
|
|
21
|
+
});
|
|
22
|
+
const msteamsConfigAdapter = createTopLevelChannelConfigAdapter({
|
|
23
|
+
sectionKey: "msteams",
|
|
24
|
+
resolveAccount: (cfg) => ({
|
|
25
|
+
accountId: "default",
|
|
26
|
+
enabled: cfg.channels?.msteams?.enabled !== false,
|
|
27
|
+
configured: Boolean(resolveMSTeamsCredentials(cfg.channels?.msteams))
|
|
28
|
+
}),
|
|
29
|
+
resolveAccessorAccount: ({ cfg }) => resolveMSTeamsChannelConfig(cfg),
|
|
30
|
+
resolveAllowFrom: (account) => account.allowFrom,
|
|
31
|
+
formatAllowFrom: (allowFrom) => formatAllowFromLowercase({ allowFrom }),
|
|
32
|
+
resolveDefaultTo: (account) => account.defaultTo
|
|
33
|
+
});
|
|
34
|
+
const msteamsSetupPlugin = {
|
|
35
|
+
id: "msteams",
|
|
36
|
+
meta: {
|
|
37
|
+
...meta,
|
|
38
|
+
aliases: [...meta.aliases]
|
|
39
|
+
},
|
|
40
|
+
capabilities: {
|
|
41
|
+
chatTypes: [
|
|
42
|
+
"direct",
|
|
43
|
+
"channel",
|
|
44
|
+
"thread"
|
|
45
|
+
],
|
|
46
|
+
polls: true,
|
|
47
|
+
threads: true,
|
|
48
|
+
media: true
|
|
49
|
+
},
|
|
50
|
+
reload: { configPrefixes: ["channels.msteams"] },
|
|
51
|
+
configSchema: MSTeamsChannelConfigSchema,
|
|
52
|
+
config: {
|
|
53
|
+
...msteamsConfigAdapter,
|
|
54
|
+
isConfigured: (_account, cfg) => Boolean(resolveMSTeamsCredentials(cfg.channels?.msteams)),
|
|
55
|
+
describeAccount: (account) => describeAccountSnapshot({
|
|
56
|
+
account,
|
|
57
|
+
configured: account.configured
|
|
58
|
+
})
|
|
59
|
+
},
|
|
60
|
+
setupWizard: msteamsSetupWizard,
|
|
61
|
+
setup: msteamsSetupAdapter
|
|
62
|
+
};
|
|
63
|
+
//#endregion
|
|
64
|
+
export { msteamsSetupPlugin };
|
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
import { O as formatUnknownError, c as normalizeQuery, f as resolveGraphToken, g as saveDelegatedTokens, h as resolveMSTeamsCredentials, o as listChannelsForTeam, p as hasConfiguredMSTeamsCredentials, s as listTeamsByName, t as searchGraphUsers, v as normalizeSecretInputString } from "./graph-users-D-gKCguI.js";
|
|
2
|
+
import { mapAllowlistResolutionInputs } from "klaw/plugin-sdk/allow-from";
|
|
3
|
+
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString } from "klaw/plugin-sdk/string-coerce-runtime";
|
|
4
|
+
import { DEFAULT_ACCOUNT_ID, createSetupTranslator, createStandardChannelSetupStatus, createTopLevelChannelAllowFromSetter, createTopLevelChannelDmPolicy, createTopLevelChannelGroupPolicySetter, mergeAllowFromEntries, splitSetupEntries } from "klaw/plugin-sdk/setup";
|
|
5
|
+
import { formatDocsLink } from "klaw/plugin-sdk/setup-tools";
|
|
6
|
+
//#region extensions/msteams/src/resolve-allowlist.ts
|
|
7
|
+
function stripProviderPrefix(raw) {
|
|
8
|
+
return raw.replace(/^(msteams|teams):/i, "");
|
|
9
|
+
}
|
|
10
|
+
function normalizeMSTeamsMessagingTarget(raw) {
|
|
11
|
+
let trimmed = raw.trim();
|
|
12
|
+
if (!trimmed) return;
|
|
13
|
+
trimmed = stripProviderPrefix(trimmed).trim();
|
|
14
|
+
if (/^conversation:/i.test(trimmed)) {
|
|
15
|
+
const id = trimmed.slice(13).trim();
|
|
16
|
+
return id ? `conversation:${id}` : void 0;
|
|
17
|
+
}
|
|
18
|
+
if (/^user:/i.test(trimmed)) {
|
|
19
|
+
const id = trimmed.slice(5).trim();
|
|
20
|
+
return id ? `user:${id}` : void 0;
|
|
21
|
+
}
|
|
22
|
+
return trimmed || void 0;
|
|
23
|
+
}
|
|
24
|
+
function normalizeMSTeamsUserInput(raw) {
|
|
25
|
+
return stripProviderPrefix(raw).replace(/^(user|conversation):/i, "").trim();
|
|
26
|
+
}
|
|
27
|
+
function parseMSTeamsConversationId(raw) {
|
|
28
|
+
const trimmed = stripProviderPrefix(raw).trim();
|
|
29
|
+
if (!/^conversation:/i.test(trimmed)) return null;
|
|
30
|
+
return trimmed.slice(13).trim();
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Detect whether a raw target string looks like a Microsoft Teams conversation
|
|
34
|
+
* or user id that cron announce delivery and other explicit-target paths can
|
|
35
|
+
* forward verbatim to the channel adapter.
|
|
36
|
+
*
|
|
37
|
+
* Accepts both prefixed and bare formats:
|
|
38
|
+
* - `conversation:<id>` — explicit conversation prefix
|
|
39
|
+
* - `user:<aad-guid>` — user id (16+ hex chars, UUID-like)
|
|
40
|
+
* - `19:abc@thread.tacv2` / `19:abc@thread.skype` — channel / legacy group
|
|
41
|
+
* - `19:{userId}_{appId}@unq.gbl.spaces` — Graph 1:1 chat thread format
|
|
42
|
+
* - `a:1xxx` — Bot Framework personal (1:1) chat id
|
|
43
|
+
* - `8:orgid:xxx` — Bot Framework org-scoped personal chat id
|
|
44
|
+
* - `29:xxx` — Bot Framework user id
|
|
45
|
+
*
|
|
46
|
+
* Display-name user targets such as `user:John Smith` intentionally return
|
|
47
|
+
* false so that the Graph API directory lookup still runs for them.
|
|
48
|
+
*/
|
|
49
|
+
function looksLikeMSTeamsTargetId(raw) {
|
|
50
|
+
const trimmed = raw.trim();
|
|
51
|
+
if (!trimmed) return false;
|
|
52
|
+
if (/^conversation:/i.test(trimmed)) return true;
|
|
53
|
+
if (/^user:/i.test(trimmed)) {
|
|
54
|
+
const id = trimmed.slice(5).trim();
|
|
55
|
+
return /^[0-9a-fA-F-]{16,}$/.test(id);
|
|
56
|
+
}
|
|
57
|
+
if (/^19:.+@thread\.(tacv2|skype)$/i.test(trimmed)) return true;
|
|
58
|
+
if (/^19:.+@unq\.gbl\.spaces$/i.test(trimmed)) return true;
|
|
59
|
+
if (/^a:1[A-Za-z0-9_-]+$/i.test(trimmed)) return true;
|
|
60
|
+
if (/^8:orgid:[A-Za-z0-9-]+$/i.test(trimmed)) return true;
|
|
61
|
+
if (/^29:[A-Za-z0-9_-]+$/i.test(trimmed)) return true;
|
|
62
|
+
return /@thread\b/i.test(trimmed);
|
|
63
|
+
}
|
|
64
|
+
function normalizeMSTeamsTeamKey(raw) {
|
|
65
|
+
return stripProviderPrefix(raw).replace(/^team:/i, "").trim() || void 0;
|
|
66
|
+
}
|
|
67
|
+
function normalizeMSTeamsChannelKey(raw) {
|
|
68
|
+
return (raw?.trim().replace(/^#/, "").trim() ?? "") || void 0;
|
|
69
|
+
}
|
|
70
|
+
function normalizeMSTeamsConversationTargetId(raw) {
|
|
71
|
+
const trimmed = stripProviderPrefix(raw).trim();
|
|
72
|
+
return parseMSTeamsConversationId(trimmed) ?? trimmed;
|
|
73
|
+
}
|
|
74
|
+
function looksLikeMSTeamsThreadConversationId(raw) {
|
|
75
|
+
const normalized = normalizeMSTeamsConversationTargetId(raw);
|
|
76
|
+
return /^19:.+@thread\./i.test(normalized);
|
|
77
|
+
}
|
|
78
|
+
function parseMSTeamsTeamChannelInput(raw) {
|
|
79
|
+
const trimmed = stripProviderPrefix(raw).trim();
|
|
80
|
+
if (!trimmed) return {};
|
|
81
|
+
const parts = trimmed.split("/");
|
|
82
|
+
const team = normalizeMSTeamsTeamKey(parts[0] ?? "");
|
|
83
|
+
const channel = parts.length > 1 ? normalizeMSTeamsChannelKey(parts.slice(1).join("/")) : void 0;
|
|
84
|
+
return {
|
|
85
|
+
...team ? { team } : {},
|
|
86
|
+
...channel ? { channel } : {}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function parseMSTeamsTeamEntry(raw) {
|
|
90
|
+
const { team, channel } = parseMSTeamsTeamChannelInput(raw);
|
|
91
|
+
if (!team) return null;
|
|
92
|
+
return {
|
|
93
|
+
teamKey: team,
|
|
94
|
+
...channel ? { channelKey: channel } : {}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
async function resolveMSTeamsChannelAllowlist(params) {
|
|
98
|
+
let tokenPromise;
|
|
99
|
+
const getToken = () => {
|
|
100
|
+
tokenPromise ??= resolveGraphToken(params.cfg);
|
|
101
|
+
return tokenPromise;
|
|
102
|
+
};
|
|
103
|
+
return await mapAllowlistResolutionInputs({
|
|
104
|
+
inputs: params.entries,
|
|
105
|
+
mapInput: async (input) => {
|
|
106
|
+
const { team, channel } = parseMSTeamsTeamChannelInput(input);
|
|
107
|
+
if (!team) return {
|
|
108
|
+
input,
|
|
109
|
+
resolved: false
|
|
110
|
+
};
|
|
111
|
+
if (looksLikeMSTeamsThreadConversationId(team)) {
|
|
112
|
+
const teamId = normalizeMSTeamsConversationTargetId(team);
|
|
113
|
+
if (!channel) return {
|
|
114
|
+
input,
|
|
115
|
+
resolved: true,
|
|
116
|
+
teamId,
|
|
117
|
+
teamName: teamId
|
|
118
|
+
};
|
|
119
|
+
if (!looksLikeMSTeamsThreadConversationId(channel)) return {
|
|
120
|
+
input,
|
|
121
|
+
resolved: false,
|
|
122
|
+
teamId,
|
|
123
|
+
teamName: teamId,
|
|
124
|
+
note: "channel id required for conversation-id team"
|
|
125
|
+
};
|
|
126
|
+
const channelId = normalizeMSTeamsConversationTargetId(channel);
|
|
127
|
+
return {
|
|
128
|
+
input,
|
|
129
|
+
resolved: true,
|
|
130
|
+
teamId,
|
|
131
|
+
teamName: teamId,
|
|
132
|
+
channelId,
|
|
133
|
+
channelName: channelId
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
const token = await getToken();
|
|
137
|
+
const teams = /^[0-9a-fA-F-]{16,}$/.test(team) ? [{
|
|
138
|
+
id: team,
|
|
139
|
+
displayName: team
|
|
140
|
+
}] : await listTeamsByName(token, team);
|
|
141
|
+
if (teams.length === 0) return {
|
|
142
|
+
input,
|
|
143
|
+
resolved: false,
|
|
144
|
+
note: "team not found"
|
|
145
|
+
};
|
|
146
|
+
const teamMatch = teams[0];
|
|
147
|
+
const graphTeamId = teamMatch.id?.trim();
|
|
148
|
+
const teamName = teamMatch.displayName?.trim() || team;
|
|
149
|
+
if (!graphTeamId) return {
|
|
150
|
+
input,
|
|
151
|
+
resolved: false,
|
|
152
|
+
note: "team id missing"
|
|
153
|
+
};
|
|
154
|
+
let teamChannels = [];
|
|
155
|
+
try {
|
|
156
|
+
teamChannels = await listChannelsForTeam(token, graphTeamId);
|
|
157
|
+
} catch {}
|
|
158
|
+
const teamId = teamChannels.find((ch) => normalizeOptionalLowercaseString(ch.displayName) === "general")?.id?.trim() || graphTeamId;
|
|
159
|
+
if (!channel) return {
|
|
160
|
+
input,
|
|
161
|
+
resolved: true,
|
|
162
|
+
teamId,
|
|
163
|
+
teamName,
|
|
164
|
+
note: teams.length > 1 ? "multiple teams; chose first" : void 0
|
|
165
|
+
};
|
|
166
|
+
const normalizedChannel = normalizeOptionalLowercaseString(channel);
|
|
167
|
+
const channelMatch = teamChannels.find((item) => item.id === channel) ?? teamChannels.find((item) => normalizeOptionalLowercaseString(item.displayName) === normalizedChannel) ?? teamChannels.find((item) => normalizeLowercaseStringOrEmpty(item.displayName ?? "").includes(normalizedChannel ?? ""));
|
|
168
|
+
if (!channelMatch?.id) return {
|
|
169
|
+
input,
|
|
170
|
+
resolved: false,
|
|
171
|
+
note: "channel not found"
|
|
172
|
+
};
|
|
173
|
+
return {
|
|
174
|
+
input,
|
|
175
|
+
resolved: true,
|
|
176
|
+
teamId,
|
|
177
|
+
teamName,
|
|
178
|
+
channelId: channelMatch.id,
|
|
179
|
+
channelName: channelMatch.displayName ?? channel,
|
|
180
|
+
note: teamChannels.length > 1 ? "multiple channels; chose first" : void 0
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
async function resolveMSTeamsUserAllowlist(params) {
|
|
186
|
+
const token = await resolveGraphToken(params.cfg);
|
|
187
|
+
return await mapAllowlistResolutionInputs({
|
|
188
|
+
inputs: params.entries,
|
|
189
|
+
mapInput: async (input) => {
|
|
190
|
+
const query = normalizeQuery(normalizeMSTeamsUserInput(input));
|
|
191
|
+
if (!query) return {
|
|
192
|
+
input,
|
|
193
|
+
resolved: false
|
|
194
|
+
};
|
|
195
|
+
if (/^[0-9a-fA-F-]{16,}$/.test(query)) return {
|
|
196
|
+
input,
|
|
197
|
+
resolved: true,
|
|
198
|
+
id: query
|
|
199
|
+
};
|
|
200
|
+
const users = await searchGraphUsers({
|
|
201
|
+
token,
|
|
202
|
+
query,
|
|
203
|
+
top: 10
|
|
204
|
+
});
|
|
205
|
+
const match = users[0];
|
|
206
|
+
if (!match?.id) return {
|
|
207
|
+
input,
|
|
208
|
+
resolved: false
|
|
209
|
+
};
|
|
210
|
+
return {
|
|
211
|
+
input,
|
|
212
|
+
resolved: true,
|
|
213
|
+
id: match.id,
|
|
214
|
+
name: match.displayName ?? void 0,
|
|
215
|
+
note: users.length > 1 ? "multiple matches; chose first" : void 0
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
//#endregion
|
|
221
|
+
//#region extensions/msteams/src/setup-core.ts
|
|
222
|
+
const t$1 = createSetupTranslator();
|
|
223
|
+
const msteamsSetupAdapter = {
|
|
224
|
+
resolveAccountId: () => DEFAULT_ACCOUNT_ID,
|
|
225
|
+
applyAccountConfig: ({ cfg }) => ({
|
|
226
|
+
...cfg,
|
|
227
|
+
channels: {
|
|
228
|
+
...cfg.channels,
|
|
229
|
+
msteams: {
|
|
230
|
+
...cfg.channels?.msteams,
|
|
231
|
+
enabled: true
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
})
|
|
235
|
+
};
|
|
236
|
+
const channel$1 = "msteams";
|
|
237
|
+
async function promptMSTeamsCredentials(prompter) {
|
|
238
|
+
return {
|
|
239
|
+
appId: (await prompter.text({
|
|
240
|
+
message: t$1("wizard.msteams.appIdPrompt"),
|
|
241
|
+
validate: (value) => value?.trim() ? void 0 : t$1("common.required")
|
|
242
|
+
})).trim(),
|
|
243
|
+
appPassword: (await prompter.text({
|
|
244
|
+
message: t$1("wizard.msteams.appPasswordPrompt"),
|
|
245
|
+
validate: (value) => value?.trim() ? void 0 : t$1("common.required")
|
|
246
|
+
})).trim(),
|
|
247
|
+
tenantId: (await prompter.text({
|
|
248
|
+
message: t$1("wizard.msteams.tenantIdPrompt"),
|
|
249
|
+
validate: (value) => value?.trim() ? void 0 : t$1("common.required")
|
|
250
|
+
})).trim()
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
async function noteMSTeamsCredentialHelp(prompter) {
|
|
254
|
+
await prompter.note([
|
|
255
|
+
t$1("wizard.msteams.helpAzureBot"),
|
|
256
|
+
t$1("wizard.msteams.helpClientSecret"),
|
|
257
|
+
t$1("wizard.msteams.helpWebhook"),
|
|
258
|
+
t$1("wizard.msteams.helpEnvTip"),
|
|
259
|
+
t$1("wizard.channels.docs", { link: formatDocsLink("/channels/msteams", "msteams") })
|
|
260
|
+
].join("\n"), t$1("wizard.msteams.credentialsTitle"));
|
|
261
|
+
}
|
|
262
|
+
function createMSTeamsSetupWizardBase() {
|
|
263
|
+
return {
|
|
264
|
+
channel: channel$1,
|
|
265
|
+
resolveAccountIdForConfigure: () => DEFAULT_ACCOUNT_ID,
|
|
266
|
+
resolveShouldPromptAccountIds: () => false,
|
|
267
|
+
status: createStandardChannelSetupStatus({
|
|
268
|
+
channelLabel: "MS Teams",
|
|
269
|
+
configuredLabel: t$1("wizard.channels.statusConfigured"),
|
|
270
|
+
unconfiguredLabel: t$1("wizard.channels.statusNeedsAppCredentials"),
|
|
271
|
+
configuredHint: t$1("wizard.channels.statusConfigured"),
|
|
272
|
+
unconfiguredHint: t$1("wizard.channels.statusNeedsAppCreds"),
|
|
273
|
+
configuredScore: 2,
|
|
274
|
+
unconfiguredScore: 0,
|
|
275
|
+
includeStatusLine: true,
|
|
276
|
+
resolveConfigured: ({ cfg }) => Boolean(resolveMSTeamsCredentials(cfg.channels?.msteams)) || hasConfiguredMSTeamsCredentials(cfg.channels?.msteams)
|
|
277
|
+
}),
|
|
278
|
+
credentials: [],
|
|
279
|
+
finalize: async ({ cfg, prompter }) => {
|
|
280
|
+
const resolved = resolveMSTeamsCredentials(cfg.channels?.msteams);
|
|
281
|
+
const hasConfigCreds = hasConfiguredMSTeamsCredentials(cfg.channels?.msteams);
|
|
282
|
+
const canUseEnv = Boolean(!hasConfigCreds && normalizeSecretInputString(process.env.MSTEAMS_APP_ID) && normalizeSecretInputString(process.env.MSTEAMS_APP_PASSWORD) && normalizeSecretInputString(process.env.MSTEAMS_TENANT_ID));
|
|
283
|
+
let next = cfg;
|
|
284
|
+
let appId = null;
|
|
285
|
+
let appPassword = null;
|
|
286
|
+
let tenantId = null;
|
|
287
|
+
if (!resolved && !hasConfigCreds) await noteMSTeamsCredentialHelp(prompter);
|
|
288
|
+
if (canUseEnv) if (await prompter.confirm({
|
|
289
|
+
message: t$1("wizard.msteams.envPrompt"),
|
|
290
|
+
initialValue: true
|
|
291
|
+
})) next = msteamsSetupAdapter.applyAccountConfig({
|
|
292
|
+
cfg: next,
|
|
293
|
+
accountId: DEFAULT_ACCOUNT_ID,
|
|
294
|
+
input: {}
|
|
295
|
+
});
|
|
296
|
+
else ({appId, appPassword, tenantId} = await promptMSTeamsCredentials(prompter));
|
|
297
|
+
else if (hasConfigCreds) {
|
|
298
|
+
if (!await prompter.confirm({
|
|
299
|
+
message: t$1("wizard.msteams.credentialsKeep"),
|
|
300
|
+
initialValue: true
|
|
301
|
+
})) ({appId, appPassword, tenantId} = await promptMSTeamsCredentials(prompter));
|
|
302
|
+
} else ({appId, appPassword, tenantId} = await promptMSTeamsCredentials(prompter));
|
|
303
|
+
if (appId && appPassword && tenantId) next = {
|
|
304
|
+
...next,
|
|
305
|
+
channels: {
|
|
306
|
+
...next.channels,
|
|
307
|
+
msteams: {
|
|
308
|
+
...next.channels?.msteams,
|
|
309
|
+
enabled: true,
|
|
310
|
+
appId,
|
|
311
|
+
appPassword,
|
|
312
|
+
tenantId
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
return {
|
|
317
|
+
cfg: next,
|
|
318
|
+
accountId: DEFAULT_ACCOUNT_ID
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
//#endregion
|
|
324
|
+
//#region extensions/msteams/src/setup-surface.ts
|
|
325
|
+
const t = createSetupTranslator();
|
|
326
|
+
const channel = "msteams";
|
|
327
|
+
const setMSTeamsAllowFrom = createTopLevelChannelAllowFromSetter({ channel });
|
|
328
|
+
const setMSTeamsGroupPolicy = createTopLevelChannelGroupPolicySetter({
|
|
329
|
+
channel,
|
|
330
|
+
enabled: true
|
|
331
|
+
});
|
|
332
|
+
function openDelegatedOAuthUrl(url) {
|
|
333
|
+
return Promise.reject(/* @__PURE__ */ new Error(`Automatic browser launch is not available. Open this URL manually: ${url}`));
|
|
334
|
+
}
|
|
335
|
+
function looksLikeGuid(value) {
|
|
336
|
+
return /^[0-9a-fA-F-]{16,}$/.test(value);
|
|
337
|
+
}
|
|
338
|
+
async function promptMSTeamsAllowFrom(params) {
|
|
339
|
+
const existing = params.cfg.channels?.msteams?.allowFrom ?? [];
|
|
340
|
+
await params.prompter.note([
|
|
341
|
+
t("wizard.msteams.allowlistIntro"),
|
|
342
|
+
t("wizard.msteams.allowlistResolve"),
|
|
343
|
+
t("wizard.msteams.examples"),
|
|
344
|
+
"- alex@example.com",
|
|
345
|
+
"- Alex Johnson",
|
|
346
|
+
"- 00000000-0000-0000-0000-000000000000"
|
|
347
|
+
].join("\n"), t("wizard.msteams.allowlistTitle"));
|
|
348
|
+
while (true) {
|
|
349
|
+
const parts = splitSetupEntries(await params.prompter.text({
|
|
350
|
+
message: t("wizard.msteams.allowFromPrompt"),
|
|
351
|
+
placeholder: "alex@example.com, Alex Johnson",
|
|
352
|
+
initialValue: existing[0] ? existing[0] : void 0,
|
|
353
|
+
validate: (value) => value.trim() ? void 0 : t("common.required")
|
|
354
|
+
}));
|
|
355
|
+
if (parts.length === 0) {
|
|
356
|
+
await params.prompter.note(t("wizard.msteams.enterAtLeastOneUser"), t("wizard.msteams.allowlistTitle"));
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
const resolved = await resolveMSTeamsUserAllowlist({
|
|
360
|
+
cfg: params.cfg,
|
|
361
|
+
entries: parts
|
|
362
|
+
}).catch(() => null);
|
|
363
|
+
if (!resolved) {
|
|
364
|
+
const ids = parts.filter((part) => looksLikeGuid(part));
|
|
365
|
+
if (ids.length !== parts.length) {
|
|
366
|
+
await params.prompter.note(t("wizard.msteams.graphLookupUnavailable"), t("wizard.msteams.allowlistTitle"));
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
const unique = mergeAllowFromEntries(existing, ids);
|
|
370
|
+
return setMSTeamsAllowFrom(params.cfg, unique);
|
|
371
|
+
}
|
|
372
|
+
const unresolved = resolved.filter((item) => !item.resolved || !item.id);
|
|
373
|
+
if (unresolved.length > 0) {
|
|
374
|
+
await params.prompter.note(t("wizard.msteams.couldNotResolve", { entries: unresolved.map((item) => item.input).join(", ") }), t("wizard.msteams.allowlistTitle"));
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
const unique = mergeAllowFromEntries(existing, resolved.map((item) => item.id));
|
|
378
|
+
return setMSTeamsAllowFrom(params.cfg, unique);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
function setMSTeamsTeamsAllowlist(cfg, entries) {
|
|
382
|
+
const teams = { ...cfg.channels?.msteams?.teams ?? {} };
|
|
383
|
+
for (const entry of entries) {
|
|
384
|
+
const teamKey = entry.teamKey;
|
|
385
|
+
if (!teamKey) continue;
|
|
386
|
+
const existing = teams[teamKey] ?? {};
|
|
387
|
+
if (entry.channelKey) {
|
|
388
|
+
const channels = { ...existing.channels };
|
|
389
|
+
channels[entry.channelKey] = channels[entry.channelKey] ?? {};
|
|
390
|
+
teams[teamKey] = {
|
|
391
|
+
...existing,
|
|
392
|
+
channels
|
|
393
|
+
};
|
|
394
|
+
} else teams[teamKey] = existing;
|
|
395
|
+
}
|
|
396
|
+
return {
|
|
397
|
+
...cfg,
|
|
398
|
+
channels: {
|
|
399
|
+
...cfg.channels,
|
|
400
|
+
msteams: {
|
|
401
|
+
...cfg.channels?.msteams,
|
|
402
|
+
enabled: true,
|
|
403
|
+
teams
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
function listMSTeamsGroupEntries(cfg) {
|
|
409
|
+
return Object.entries(cfg.channels?.msteams?.teams ?? {}).flatMap(([teamKey, value]) => {
|
|
410
|
+
const channels = value?.channels ?? {};
|
|
411
|
+
const channelKeys = Object.keys(channels);
|
|
412
|
+
if (channelKeys.length === 0) return [teamKey];
|
|
413
|
+
return channelKeys.map((channelKey) => `${teamKey}/${channelKey}`);
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
async function resolveMSTeamsGroupAllowlist(params) {
|
|
417
|
+
let resolvedEntries = params.entries.map((entry) => parseMSTeamsTeamEntry(entry)).filter(Boolean);
|
|
418
|
+
if (params.entries.length === 0 || !resolveMSTeamsCredentials(params.cfg.channels?.msteams)) return resolvedEntries;
|
|
419
|
+
try {
|
|
420
|
+
const lookups = await resolveMSTeamsChannelAllowlist({
|
|
421
|
+
cfg: params.cfg,
|
|
422
|
+
entries: params.entries
|
|
423
|
+
});
|
|
424
|
+
const resolvedChannels = lookups.filter((entry) => entry.resolved && entry.teamId && entry.channelId);
|
|
425
|
+
const resolvedTeams = lookups.filter((entry) => entry.resolved && entry.teamId && !entry.channelId);
|
|
426
|
+
const unresolved = lookups.filter((entry) => !entry.resolved).map((entry) => entry.input);
|
|
427
|
+
resolvedEntries = [
|
|
428
|
+
...resolvedChannels.map((entry) => ({
|
|
429
|
+
teamKey: entry.teamId,
|
|
430
|
+
channelKey: entry.channelId
|
|
431
|
+
})),
|
|
432
|
+
...resolvedTeams.map((entry) => ({ teamKey: entry.teamId })),
|
|
433
|
+
...unresolved.map((entry) => parseMSTeamsTeamEntry(entry)).filter(Boolean)
|
|
434
|
+
];
|
|
435
|
+
const summary = [];
|
|
436
|
+
if (resolvedChannels.length > 0) summary.push(t("wizard.msteams.resolvedChannels", { entries: resolvedChannels.map((entry) => entry.channelId).filter(Boolean).join(", ") }));
|
|
437
|
+
if (resolvedTeams.length > 0) summary.push(t("wizard.msteams.resolvedTeams", { entries: resolvedTeams.map((entry) => entry.teamId).filter(Boolean).join(", ") }));
|
|
438
|
+
if (unresolved.length > 0) summary.push(t("wizard.msteams.unresolvedKept", { entries: unresolved.join(", ") }));
|
|
439
|
+
if (summary.length > 0) await params.prompter.note(summary.join("\n"), t("wizard.msteams.channelsLabel"));
|
|
440
|
+
return resolvedEntries;
|
|
441
|
+
} catch (err) {
|
|
442
|
+
await params.prompter.note(t("wizard.msteams.channelLookupFailed", { error: formatUnknownError(err) }), t("wizard.msteams.channelsLabel"));
|
|
443
|
+
return resolvedEntries;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
const msteamsGroupAccess = {
|
|
447
|
+
label: t("wizard.msteams.channelsLabel"),
|
|
448
|
+
placeholder: "Team Name/Channel Name, teamId/conversationId",
|
|
449
|
+
currentPolicy: ({ cfg }) => cfg.channels?.msteams?.groupPolicy ?? "allowlist",
|
|
450
|
+
currentEntries: ({ cfg }) => listMSTeamsGroupEntries(cfg),
|
|
451
|
+
updatePrompt: ({ cfg }) => Boolean(cfg.channels?.msteams?.teams),
|
|
452
|
+
setPolicy: ({ cfg, policy }) => setMSTeamsGroupPolicy(cfg, policy),
|
|
453
|
+
resolveAllowlist: async ({ cfg, entries, prompter }) => await resolveMSTeamsGroupAllowlist({
|
|
454
|
+
cfg,
|
|
455
|
+
entries,
|
|
456
|
+
prompter
|
|
457
|
+
}),
|
|
458
|
+
applyAllowlist: ({ cfg, resolved }) => setMSTeamsTeamsAllowlist(cfg, resolved)
|
|
459
|
+
};
|
|
460
|
+
const msteamsDmPolicy = createTopLevelChannelDmPolicy({
|
|
461
|
+
label: "MS Teams",
|
|
462
|
+
channel,
|
|
463
|
+
policyKey: "channels.msteams.dmPolicy",
|
|
464
|
+
allowFromKey: "channels.msteams.allowFrom",
|
|
465
|
+
getCurrent: (cfg) => cfg.channels?.msteams?.dmPolicy ?? "pairing",
|
|
466
|
+
promptAllowFrom: promptMSTeamsAllowFrom
|
|
467
|
+
});
|
|
468
|
+
const msteamsSetupWizardBase = createMSTeamsSetupWizardBase();
|
|
469
|
+
const msteamsSetupWizard = {
|
|
470
|
+
...msteamsSetupWizardBase,
|
|
471
|
+
finalize: async (params) => {
|
|
472
|
+
const baseFinalize = msteamsSetupWizardBase.finalize;
|
|
473
|
+
const baseResult = baseFinalize ? await baseFinalize(params) : void 0;
|
|
474
|
+
let next = baseResult?.cfg ?? params.cfg;
|
|
475
|
+
const finalCreds = resolveMSTeamsCredentials(next.channels?.msteams);
|
|
476
|
+
if (finalCreds?.type === "secret") {
|
|
477
|
+
if (await params.prompter.confirm({
|
|
478
|
+
message: t("wizard.msteams.delegatedAuthPrompt"),
|
|
479
|
+
initialValue: false
|
|
480
|
+
})) {
|
|
481
|
+
next = {
|
|
482
|
+
...next,
|
|
483
|
+
channels: {
|
|
484
|
+
...next.channels,
|
|
485
|
+
msteams: {
|
|
486
|
+
...next.channels?.msteams,
|
|
487
|
+
delegatedAuth: { enabled: true }
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
try {
|
|
492
|
+
const { loginMSTeamsDelegated } = await import("./oauth-BUxlphX3.js");
|
|
493
|
+
const progress = params.prompter.progress(t("wizard.msteams.delegatedOAuthProgress"));
|
|
494
|
+
saveDelegatedTokens(await loginMSTeamsDelegated({
|
|
495
|
+
isRemote: true,
|
|
496
|
+
openUrl: openDelegatedOAuthUrl,
|
|
497
|
+
log: (msg) => params.prompter.note(msg),
|
|
498
|
+
note: (msg, title) => params.prompter.note(msg, title),
|
|
499
|
+
prompt: (msg) => params.prompter.text({ message: msg }),
|
|
500
|
+
progress
|
|
501
|
+
}, {
|
|
502
|
+
tenantId: finalCreds.tenantId,
|
|
503
|
+
clientId: finalCreds.appId,
|
|
504
|
+
clientSecret: finalCreds.appPassword
|
|
505
|
+
}));
|
|
506
|
+
progress.stop(t("wizard.msteams.delegatedAuthConfigured"));
|
|
507
|
+
} catch (err) {
|
|
508
|
+
await params.prompter.note(`Delegated auth setup failed: ${formatUnknownError(err)}\n` + t("wizard.msteams.delegatedAuthRetry"), t("wizard.msteams.delegatedAuthTitle"));
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return {
|
|
513
|
+
...baseResult,
|
|
514
|
+
cfg: next
|
|
515
|
+
};
|
|
516
|
+
},
|
|
517
|
+
dmPolicy: msteamsDmPolicy,
|
|
518
|
+
groupAccess: msteamsGroupAccess,
|
|
519
|
+
disable: (cfg) => ({
|
|
520
|
+
...cfg,
|
|
521
|
+
channels: {
|
|
522
|
+
...cfg.channels,
|
|
523
|
+
msteams: {
|
|
524
|
+
...cfg.channels?.msteams,
|
|
525
|
+
enabled: false
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
})
|
|
529
|
+
};
|
|
530
|
+
//#endregion
|
|
531
|
+
export { looksLikeMSTeamsTargetId as a, parseMSTeamsConversationId as c, resolveMSTeamsUserAllowlist as d, msteamsSetupAdapter as i, parseMSTeamsTeamChannelInput as l, openDelegatedOAuthUrl as n, normalizeMSTeamsMessagingTarget as o, createMSTeamsSetupWizardBase as r, normalizeMSTeamsUserInput as s, msteamsSetupWizard as t, resolveMSTeamsChannelAllowlist as u };
|