@microsoft/teams.apps
Version:
<p> <a href="https://www.npmjs.com/package/@microsoft/teams.apps" target="_blank"> <img src="https://img.shields.io/npm/v/@microsoft/teams.apps/latest" /> </a> <a href="https://www.npmjs.com/package/@microsoft/teams.apps?activeTab=code
387 lines • 32.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ActivityProcessor = void 0;
const teams_api_1 = require("@microsoft/teams.api");
const activity_sender_1 = require("./activity-sender");
const api_1 = require("./api");
const contexts_1 = require("./contexts");
const agent365_baggage_1 = require("./diagnostics/agent365-baggage");
const constants_1 = require("./diagnostics/constants");
const helpers_1 = require("./diagnostics/helpers");
const files_credential_1 = require("./files-credential");
const utils_1 = require("./utils");
function getAgenticIdentity(account) {
if (!account?.agenticAppBlueprintId) {
return undefined;
}
return {
agenticAppId: account.agenticAppId,
agenticUserId: account.agenticUserId,
tenantId: account.tenantId,
agenticAppBlueprintId: account.agenticAppBlueprintId,
};
}
/**
* Encapsulates inbound activity processing: building the activity context,
* running the middleware/route chain, wiring streaming + send events, and
* producing the {@link InvokeResponse}.
*
* This replaces the `this: App`-bound `$process` free function. All of its
* collaborators are supplied via the constructor so the processor can be
* reasoned about (and tested) without reaching into `App` internals.
*/
class ActivityProcessor {
options;
constructor(options) {
this.options = options;
}
/**
* activity handler called when an inbound activity is received
* @param event the received activity event
*/
async process(event) {
const { token, body } = event;
if (!body) {
throw new Error('Activity body is required');
}
// TODO: We currently simply cast the models to Activity,
// but we should probably be validating this conversion
const activity = body;
this.options.log.debug(`activity/${activity.type}${activity.type === 'invoke' ? `/${activity.name}` : ''}`);
let serviceUrl = activity.serviceUrl || token.serviceUrl;
if (serviceUrl.endsWith('/')) {
serviceUrl = serviceUrl.slice(0, serviceUrl.length - 1);
}
// Establish Agent365 baggage before any span starts, so every span in the
// turn observes the same identity. A route-level middleware runs too late:
// the root span already exists by then.
return this.withActivityBaggage(activity, () => traceActivityProcess(activity, serviceUrl, async (activityProcessSpan) => {
const agenticIdentity = getAgenticIdentity(activity.recipient);
const apiClient = this.options.api.clone({
serviceUrl,
agenticIdentity,
});
let userToken;
// Legacy context OAuth fields opt into this eager lookup.
if (this.options.shouldFetchUserToken()) {
try {
userToken = await this.getUserToken(apiClient, activity.channelId, activity.from.id);
}
catch (err) {
// noop
}
}
const client = this.options.client.clone();
const apiClientFactory = (senderServiceUrl, senderAgenticIdentity) => apiClient.clone({
serviceUrl: senderServiceUrl,
agenticIdentity: senderAgenticIdentity ?? agenticIdentity,
});
const userGraph = new api_1.GraphClient(client.clone({ token: () => userToken }), { baseUrlRoot: this.options.graphBaseUrl });
const appGraph = new api_1.GraphClient(client.clone({
// The token provider returns null when the app has no credentials, but the HTTP token contract treats only undefined as "no token"; coerce so null is never forwarded as an auth header.
token: async () => (await this.options.getAppGraphToken((0, utils_1.extractTenantId)(activity))) ?? undefined,
}), { baseUrlRoot: this.options.graphBaseUrl });
const ref = {
serviceUrl,
activityId: activity.id,
bot: activity.recipient,
channelId: activity.channelId,
conversation: activity.conversation,
locale: activity.locale,
user: activity.from,
};
const routes = this.options.router.selectRoutes(activity);
if (routes.length === 0) {
(0, helpers_1.recordTeamsBotHandlerUnmatched)(activity.type, getInvokeName(activity));
}
// Collect plugin contexts BEFORE creating the activity context
let pluginContexts = {};
for (let i = this.options.plugins.length - 1; i > -1; i--) {
const plugin = this.options.plugins[i];
if (plugin.onActivity) {
const additionalPluginContext = await plugin.onActivity({
...ref,
activity,
token,
});
if (additionalPluginContext) {
for (const key in additionalPluginContext) {
if (key in pluginContexts) {
this.options.log.warn(`Plugin context key "${key}" already exists. Overriding.`);
}
}
pluginContexts = {
...pluginContexts,
...additionalPluginContext,
};
}
}
}
let i = -1;
let data = undefined;
const next = async (ctx) => {
if (i === routes.length - 1)
return data;
i++;
const mergedContext = ctx || {
...context.toInterface(),
...pluginContexts,
};
const route = routes[i];
const handler = route.callback;
const res = await traceHandler(activity, route, async () => handler(mergedContext));
if (res) {
data = res;
}
return data;
};
const activitySender = new activity_sender_1.ActivitySender(this.options.log, apiClientFactory);
// Resolved at fetch time rather than eagerly, so a turn that never touches files pays nothing for it.
//
// An Agentic User reads as itself. An app-only token sees what the app may read tenant-wide, a different set from what was shared with the agent, so it would 403 on exactly the files the agent was given.
const filesCredential = (0, files_credential_1.selectFilesCredential)({
agenticIdentity,
tenantId: (0, utils_1.extractTenantId)(activity),
graphBaseUrlRoot: this.options.graphBaseUrl,
getAppGraphToken: (t) => this.options.getAppGraphToken(t),
getAgenticGraphToken: (i, t) => this.options.getAgenticGraphToken(i, t),
});
// Inline images are read with the turn's Bot API token, not Graph.
const filesBotApiCredential = (0, files_credential_1.selectInlineImageCredential)({
agenticIdentity,
serviceUrl: activity.serviceUrl,
getToken: () => apiClient.http.token,
});
const context = new contexts_1.ActivityContext({
activity,
next,
api: apiClient,
client: this.options.client,
userGraph,
appGraph,
appId: this.options.getId() || '',
log: this.options.log,
userToken: userToken,
ref,
storage: this.options.storage,
isSignedIn: !!userToken,
connectionName: this.options.getConnectionName(),
validateOAuthConnection: this.options.validateOAuthConnection,
onOAuthSignInInitiated: this.options.onOAuthSignInInitiated,
getOAuthConnectionStatus: this.options.getOAuthConnectionStatus,
filesCredential,
filesBotApiCredential,
activitySender,
...pluginContexts
});
const conversationId = activity.conversation?.id;
const userId = activity.from?.id;
const stateLoader = this.options.getStateLoader();
const send = context.send.bind(context);
context.send = async (activity, conversationRef) => {
const res = conversationRef
? await send(activity, conversationRef)
: await send(activity);
this.options.eventManager.onActivitySent({
...(conversationRef ?? ref),
activity: res,
});
return res;
};
let planAttached = false;
const getPlan = context.plan.bind(context);
context.plan = () => {
const plan = getPlan();
if (!planAttached) {
const planRef = structuredClone(context.ref);
plan.events.on('sent', (activity) => {
this.options.eventManager.onActivitySent({ ...structuredClone(planRef), activity });
});
planAttached = true;
}
return plan;
};
context.stream.events.on('chunk', (activity) => {
this.options.eventManager.onActivitySent({
...ref,
activity,
});
});
context.stream.events.on('close', (activity) => {
this.options.eventManager.onActivitySent({
...ref,
activity,
});
});
const response = await this.executeTurnLifecycle(context, activity, activityProcessSpan, conversationId, userId, stateLoader, async () => {
const res = await next();
await context.stream.close();
return (0, teams_api_1.isInvokeResponse)(res)
? res
: { status: 200, body: res };
});
this.options.eventManager.onActivityResponse({
...ref,
activity,
response,
});
return response;
}));
}
async executeTurnLifecycle(context, activity, activityProcessSpan, conversationId, userId, stateLoader, dispatch) {
let response = { status: 500 };
let dispatchError;
let saveError;
try {
if (stateLoader && conversationId) {
context.state = await stateLoader.load(conversationId, userId);
}
response = await dispatch();
}
catch (error) {
dispatchError = error;
}
finally {
if (context.state && stateLoader && conversationId) {
try {
await stateLoader.save(context.state);
}
catch (error) {
saveError = error;
}
finally {
context.state.seal();
}
}
}
if (dispatchError) {
await this.reportTurnError(dispatchError, activity, activityProcessSpan);
}
if (saveError) {
await this.reportTurnError(saveError, activity, activityProcessSpan);
}
if (dispatchError || saveError) {
return { status: 500 };
}
return response;
}
async reportTurnError(error, activity, activityProcessSpan) {
(0, helpers_1.recordTeamsBotApplicationException)(activityProcessSpan, error);
await this.options.eventManager.onError({
error: error instanceof Error ? error : new Error(String(error)),
activity,
});
}
/**
* Runs the inbound turn inside an Agent365 baggage scope derived from the
* activity, unless the bridge is disabled.
*/
withActivityBaggage(activity, execute) {
const options = this.options.agent365Baggage;
if (options === false) {
return execute();
}
return (0, agent365_baggage_1.withAgent365Baggage)((0, agent365_baggage_1.agent365BaggageFromActivity)(activity, options ?? {}), execute);
}
/**
* fetch the user's token for the given channel/user, if signed in
*/
async getUserToken(apiClient, channelId, userId) {
const res = await apiClient.users.getToken({
channelId,
userId,
connectionName: this.options.getConnectionName(),
});
return res.token;
}
}
exports.ActivityProcessor = ActivityProcessor;
function getInvokeName(activity) {
return activity.type === 'invoke' ? activity.name : undefined;
}
function getHandlerType(activity) {
return getInvokeName(activity) ?? activity.type;
}
function getHandlerDispatch(activity, route) {
if (!route.name) {
return constants_1.APP_HANDLER_DISPATCH.catchall;
}
if (route.name === 'activity') {
return constants_1.APP_HANDLER_DISPATCH.catchall;
}
if (route.name === activity.type) {
return constants_1.APP_HANDLER_DISPATCH.type;
}
if (activity.type === 'invoke') {
return constants_1.APP_HANDLER_DISPATCH.invoke;
}
return constants_1.APP_HANDLER_DISPATCH.catchall;
}
function getActivityProcessAttributes(activity, serviceUrl) {
const attributes = {
[constants_1.APP_ATTRIBUTE_NAMES.activityType]: activity.type,
};
if (activity.id) {
attributes[constants_1.APP_ATTRIBUTE_NAMES.activityId] = activity.id;
}
if (activity.conversation?.id) {
attributes[constants_1.APP_ATTRIBUTE_NAMES.conversationId] = activity.conversation.id;
}
if (activity.channelId) {
attributes[constants_1.APP_ATTRIBUTE_NAMES.channelId] = activity.channelId;
}
if (activity.recipient?.id) {
attributes[constants_1.APP_ATTRIBUTE_NAMES.botId] = activity.recipient.id;
}
if (serviceUrl) {
attributes[constants_1.APP_ATTRIBUTE_NAMES.serviceUrl] = serviceUrl;
}
return attributes;
}
async function traceActivityProcess(activity, serviceUrl, execute) {
const activityType = activity.type;
const startedAt = Date.now();
(0, helpers_1.recordTeamsBotActivityReceived)(activityType);
return (0, helpers_1.getTeamsBotApplicationTracer)().startActiveSpan(constants_1.APP_SPAN_NAMES.activityProcess, { attributes: getActivityProcessAttributes(activity, serviceUrl) }, async (span) => {
try {
return await execute(span);
}
catch (error) {
(0, helpers_1.recordTeamsBotApplicationException)(span, error);
throw error;
}
finally {
(0, helpers_1.recordTeamsBotActivityProcessDuration)(activityType, Date.now() - startedAt);
span.end();
}
});
}
async function traceHandler(activity, route, execute) {
if (route.type === 'system') {
return execute();
}
const handlerType = getHandlerType(activity);
const handlerDispatch = getHandlerDispatch(activity, route);
const startedAt = Date.now();
(0, helpers_1.recordTeamsBotHandlerDispatched)(handlerType, handlerDispatch);
return (0, helpers_1.getTeamsBotApplicationTracer)().startActiveSpan(constants_1.APP_SPAN_NAMES.handler, {
attributes: {
[constants_1.APP_ATTRIBUTE_NAMES.handlerType]: handlerType,
[constants_1.APP_ATTRIBUTE_NAMES.handlerDispatch]: handlerDispatch,
},
}, async (span) => {
try {
return await execute();
}
catch (error) {
(0, helpers_1.recordTeamsBotHandlerFailure)(handlerType, handlerDispatch);
(0, helpers_1.recordTeamsBotApplicationException)(span, error);
throw error;
}
finally {
(0, helpers_1.recordTeamsBotHandlerDuration)(handlerType, handlerDispatch, Date.now() - startedAt);
span.end();
}
});
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwLnByb2Nlc3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYXBwLnByb2Nlc3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBRUEsb0RBYThCO0FBRzlCLHVEQUFtRDtBQUNuRCwrQkFBb0Q7QUFFcEQseUNBQStEO0FBQy9ELHFFQUl3QztBQUN4Qyx1REFBb0c7QUFDcEcsbURBUytCO0FBRS9CLHlEQUF3RjtBQU94RixtQ0FBMEM7QUFFMUMsU0FBUyxrQkFBa0IsQ0FBQyxPQUFpQjtJQUMzQyxJQUFJLENBQUMsT0FBTyxFQUFFLHFCQUFxQixFQUFFLENBQUM7UUFDcEMsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUVELE9BQU87UUFDTCxZQUFZLEVBQUUsT0FBTyxDQUFDLFlBQVk7UUFDbEMsYUFBYSxFQUFFLE9BQU8sQ0FBQyxhQUFhO1FBQ3BDLFFBQVEsRUFBRSxPQUFPLENBQUMsUUFBUTtRQUMxQixxQkFBcUIsRUFBRSxPQUFPLENBQUMscUJBQXFCO0tBQ3JELENBQUM7QUFDSixDQUFDO0FBMkVEOzs7Ozs7OztHQVFHO0FBQ0gsTUFBYSxpQkFBaUI7SUFDQztJQUE3QixZQUE2QixPQUEyQztRQUEzQyxZQUFPLEdBQVAsT0FBTyxDQUFvQztJQUFJLENBQUM7SUFFN0U7OztPQUdHO0lBQ0gsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFxQjtRQUNqQyxNQUFNLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxHQUFHLEtBQUssQ0FBQztRQUU5QixJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDVixNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixDQUFDLENBQUM7UUFDL0MsQ0FBQztRQUVELHlEQUF5RDtRQUN6RCx1REFBdUQ7UUFDdkQsTUFBTSxRQUFRLEdBQUcsSUFBZ0IsQ0FBQztRQUVsQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQ3BCLFlBQVksUUFBUSxDQUFDLElBQUksR0FBRyxRQUFR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