eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
4 lines (3 loc) • 5.68 kB
JavaScript
import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";const TEAMS_MESSAGE_TEXT_MAX_LENGTH=81920,BOT_FRAMEWORK_TENANT=`botframework.com`,accessTokenCache=new Map;function teamsContinuationToken(e){let t=normalizeTeamsContinuationAddress(e);return[e.tenantId??`_`,t.conversationId,t.replyToActivityId??``].map(e=>encodeURIComponent(e)).join(`:`)}function normalizeTeamsContinuationAddress(e){let t=e.conversationId.lastIndexOf(`;messageid=`);return t<0?{conversationId:e.conversationId,replyToActivityId:e.replyToActivityId??null}:{conversationId:e.conversationId.slice(0,t),replyToActivityId:e.conversationId.slice(t+11)||e.replyToActivityId||null}}async function resolveTeamsAppId(e){let t=e??process.env.MICROSOFT_APP_ID??process.env.TEAMS_APP_ID;if(!t)throw Error(`MICROSOFT_APP_ID or TEAMS_APP_ID is required.`);return typeof t==`function`?await t():t}async function resolveTeamsAppPassword(e){let t=e??process.env.MICROSOFT_APP_PASSWORD??process.env.TEAMS_APP_PASSWORD;if(!t)throw Error(`MICROSOFT_APP_PASSWORD or TEAMS_APP_PASSWORD is required.`);return typeof t==`function`?await t():t}async function resolveTeamsTenantId(e){let t=e??process.env.MICROSOFT_TENANT_ID??process.env.TEAMS_TENANT_ID;if(t)return typeof t==`function`?await t():t}async function resolveTeamsAccessToken(e={}){let t=e.credentials;if(t?.tokenProvider!==void 0)return normalizeAccessTokenResult(await t.tokenProvider()).accessToken;let n=await resolveTeamsAppId(t?.appId),r=await resolveTeamsAppPassword(t?.appPassword),i=await resolveTeamsTenantId(t?.tenantId),a=trimTrailingSlash(e.loginBaseUrl??`https://login.microsoftonline.com`),o=`${a}:${i??BOT_FRAMEWORK_TENANT}:${n}`,s=accessTokenCache.get(o),c=Date.now();if(s!==void 0&&s.expiresAt-6e4>c)return s.accessToken;let l=`${a}/${encodeURIComponent(i??BOT_FRAMEWORK_TENANT)}/oauth2/v2.0/token`,u=new URLSearchParams({client_id:n,client_secret:r,grant_type:`client_credentials`,scope:`https://api.botframework.com/.default`}),d=await(e.fetch??fetch)(l,{body:u,headers:{"content-type":`application/x-www-form-urlencoded`},method:`POST`}),f=await parseResponseBody(d);if(!d.ok)throw Error(`Teams access-token request failed with HTTP ${d.status}.`);let p=isObject(f)?f:{},m=typeof p.access_token==`string`?p.access_token:``;if(!m)throw Error(`Teams access-token response did not include access_token.`);let h=typeof p.expires_in==`number`?p.expires_in:3600;return accessTokenCache.set(o,{accessToken:m,expiresAt:c+h*1e3}),m}async function callTeamsConnectorApi(e){let t=e.fetch??fetch,n=new Headers;n.set(`authorization`,`Bearer ${await resolveTeamsAccessToken(e)}`),n.set(`content-type`,`application/json; charset=utf-8`);let r={headers:n,method:e.method??`POST`};e.body!==void 0&&(r.body=JSON.stringify(parseJsonObject(e.body)));let i=await t(`${trimTrailingSlash(e.serviceUrl)}${e.path}`,r);return{body:await parseResponseBody(i),ok:i.ok,status:i.status}}async function sendTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities`});if(!t.ok)throw Error(`Teams send activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function replyToTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities/${encodeURIComponent(e.activityId)}`});if(!t.ok)throw Error(`Teams reply activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function updateTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,method:`PUT`,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities/${encodeURIComponent(e.activityId)}`});if(!t.ok)throw Error(`Teams update activity failed with HTTP ${t.status} for conversation "${e.conversationId}" activity "${e.activityId}": ${formatConnectorErrorBody(t.body)}`);return toPostedActivity(t.body)}async function triggerTeamsTypingIndicator(e){let t=await callTeamsConnectorApi({...e,body:{type:`typing`},path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities`});if(!t.ok)throw Error(`Teams typing indicator failed with HTTP ${t.status}.`)}function splitTeamsMessageText(e){if(e.length<=81920)return[e];let t=[],n=e;for(;n.length>TEAMS_MESSAGE_TEXT_MAX_LENGTH;){let e=n.lastIndexOf(`
`,TEAMS_MESSAGE_TEXT_MAX_LENGTH);e<=0&&(e=n.lastIndexOf(`
`,TEAMS_MESSAGE_TEXT_MAX_LENGTH)),e<=0&&(e=n.lastIndexOf(` `,TEAMS_MESSAGE_TEXT_MAX_LENGTH)),e<=0&&(e=TEAMS_MESSAGE_TEXT_MAX_LENGTH),t.push(n.slice(0,e).trimEnd()),n=n.slice(e).trimStart()}return t.push(n),t}function normalizeTeamsPostInput(e){return typeof e==`string`?{text:e,textFormat:`markdown`}:e}function normalizeAccessTokenResult(e){if(typeof e==`string`)return{accessToken:e};let t=e.expiresAt instanceof Date?e.expiresAt.getTime():e.expiresAt;return{accessToken:e.accessToken,expiresAt:t}}function toPostedActivity(e){let t=isObject(e)?e:{};return{id:typeof t.id==`string`?t.id:``,raw:e}}function formatConnectorErrorBody(e){let t=typeof e==`string`?e:JSON.stringify(e);return t===void 0||t.length===0?`empty response body`:t.length<=1e3?t:`${t.slice(0,997)}...`}function trimTrailingSlash(e){return e.replace(/\/+$/,``)}async function parseResponseBody(e){let t=await e.text();if(!t)return null;try{return JSON.parse(t)}catch{return t}}export{TEAMS_MESSAGE_TEXT_MAX_LENGTH,callTeamsConnectorApi,normalizeTeamsContinuationAddress,normalizeTeamsPostInput,replyToTeamsActivity,resolveTeamsAccessToken,resolveTeamsAppId,resolveTeamsAppPassword,resolveTeamsTenantId,sendTeamsActivity,splitTeamsMessageText,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity};