@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
313 lines (312 loc) • 15.3 kB
TypeScript
import { Activity, ActivityLike, AgenticIdentity, CloudEnvironment, DeprecatedInputActivity, InvokeResponse, SentActivity } from '@microsoft/teams.api';
import { Client as HttpClient, EventEmitter, EventHandler, ILogger, IStorage, LocalStorage } from '@microsoft/teams.common';
import { ActivitySender } from './activity-sender';
import { ApiClient, GraphClient } from './api';
import type { AppGetAgenticIdentityOptions, AppOptions, AppSendOptions } from './app.options';
export type { AppActivityOptions, AppGetAgenticIdentityOptions, AppOptions, AppSendOptions, AppTelemetryOptions, } from './app.options';
import { PluginManager } from './app.plugins';
import { Container } from './container';
import { IActivityContext, IFunctionContext } from './contexts';
import { IActivityEvent } from './events';
import { HttpServer } from './http/http-server';
import * as middleware from './middleware';
import { OAuthFlow } from './oauth';
import type { OAuthSignInOptions } from './oauth';
import { HttpPlugin } from './plugins';
import { Router } from './router';
import { IRoutes } from './routes';
import { SocketModeAdapter } from './socket-mode';
import { IAppTokenProvider } from './token-provider';
import { AppEvents, IPlugin, PluginName, RouteHandler } from './types';
import { PluginAdditionalContext } from './types/app-routing';
/**
* The orchestrator for receiving/sending activities
*/
export declare class App<TPlugin extends IPlugin = IPlugin> {
readonly options: AppOptions<TPlugin>;
readonly api: ApiClient;
readonly cloud: CloudEnvironment;
readonly graph: GraphClient;
readonly log: ILogger;
readonly server: HttpServer;
/**
* **Experimental.** The Socket Mode inbound transport, present only when the
* app was constructed with `socketMode` enabled. It is the same
* {@link IHttpServerAdapter} instance {@link App.server} runs on. Use it to
* observe the socket lifecycle
* (`app.socketMode.status`, `app.socketMode.geoStatuses`, `app.socketMode.events`).
* WebSocket is only recommended for use when developing agents.
*
* @experimental This API is in preview and may change in the future.
*/
readonly socketMode?: SocketModeAdapter;
readonly http?: HttpPlugin;
readonly client: HttpClient;
/**
* The app's legacy shared storage instance.
*
* @deprecated Use `ctx.state` for turn state. Applications that need general
* persistence should own and use their storage provider directly.
*/
readonly storage: IStorage;
readonly entraTokenValidator?: middleware.JwtValidator;
/**
* Graph API base URL derived from the configured cloud's `graphScope`.
* Undefined when the scope isn't a URL — `GraphClient` then uses its public-cloud default.
* Shared across every `GraphClient` the app constructs (`app.graph`, `ctx.appGraph`, `ctx.userGraph`)
* so sovereign customers get consistent routing.
*/
readonly graphBaseUrl?: string;
/**
* the apps credentials
*/
get credentials(): import("@microsoft/teams.api").Credentials | undefined;
/**
* The app's token source, for acquiring a token for something the SDK does not
* call for you, such as an OpenTelemetry exporter.
*/
get tokenProvider(): IAppTokenProvider;
/**
* the apps id
*/
get id(): string | undefined;
get oauth(): {
defaultConnectionName: string;
fetchUserToken?: boolean;
};
protected container: Container;
protected pluginManager: PluginManager<TPlugin>;
protected router: Router<PluginAdditionalContext<TPlugin>>;
protected tenantTokens: LocalStorage<string>;
protected events: EventEmitter<AppEvents<TPlugin>>;
protected isInitialized: boolean;
protected port?: number | string;
protected activitySender: ActivitySender;
/**
* The concrete token machinery: MSAL clients, credential resolution, and the
* per-grant acquisition logic. Private because {@link App.tokenProvider} is
* the supported way in.
*/
private readonly tokenManager;
private readonly _tokenProvider;
private stateLoader?;
private eventManager;
private activityProcessor;
private readonly oauthFlowRegistry;
private readonly _userAgent;
constructor(options?: AppOptions<TPlugin>);
/**
* initialize the app.
*/
initialize(): Promise<void>;
/**
* start the server after initialization
* @param port port to listen on
*/
start(port?: number | string): Promise<void>;
/**
* stop the app
*/
stop(): Promise<void>;
/**
* @deprecated Use MessageActivityInput or TypingActivityInput instead.
*/
send(conversationId: string, activity: DeprecatedInputActivity, options?: AppSendOptions): Promise<SentActivity>;
/**
* send an activity proactively to a conversation.
*
* Sends to the exact conversation ID provided.
* To reply in a reply chain (thread), use {@link reply}.
*
* @param conversationId the conversation to send to
* @param activity the activity to send
*/
send(conversationId: string, activity: ActivityLike, options?: AppSendOptions): Promise<SentActivity>;
/**
* send an activity proactively to a conversation.
*
* Sends to the exact conversation ID provided.
* To reply in a reply chain (thread), use {@link reply}.
*
* @param conversationId the conversation to send to
* @param activity the activity to send
*/
send(conversationId: string, activity: ActivityLike | DeprecatedInputActivity, options?: AppSendOptions): Promise<SentActivity>;
/**
* @deprecated Use MessageActivityInput or TypingActivityInput instead.
*/
reply(conversationId: string, messageId: string, activity: DeprecatedInputActivity, options?: AppSendOptions): Promise<any>;
/**
* send an activity proactively as a reply in a reply chain (thread).
*
* Posts to the reply chain of the message `messageId`, in the chat or channel `conversationId`.
* Any error from the service is thrown, and the activity is not sent anywhere else.
* The SDK does not state where a client shows the message in a group chat.
*
* @param conversationId the id of the chat or channel: `channelData.chat.id` or `channelData.channel.id`, **not** `conversation.id`.
* @param messageId the id of the message at the root of the reply chain: `channelData.replyChain.id`
* @param activity the activity to send
* @throws Error when `conversationId` or `messageId` is empty or blank
* @throws Error when `conversationId` or `messageId` is a dot segment (`.` or `..`)
*/
reply(conversationId: string, messageId: string, activity: ActivityLike, options?: AppSendOptions): Promise<any>;
/**
* send an activity proactively as a reply in a reply chain (thread).
*
* Posts to the reply chain of the message `messageId`, in the chat or channel `conversationId`.
* Any error from the service is thrown, and the activity is not sent anywhere else.
* The SDK does not state where a client shows the message in a group chat.
*
* @param conversationId the id of the chat or channel: `channelData.chat.id` or `channelData.channel.id`, **not** `conversation.id`.
* @param messageId the id of the message at the root of the reply chain: `channelData.replyChain.id`
* @param activity the activity to send
* @throws Error when `conversationId` or `messageId` is empty or blank
* @throws Error when `conversationId` or `messageId` is a dot segment (`.` or `..`)
*/
reply(conversationId: string, messageId: string, activity: ActivityLike | DeprecatedInputActivity, options?: AppSendOptions): Promise<any>;
/**
* send an activity proactively to a conversation, using the legacy two-argument form.
*
* @deprecated The two-argument form `reply(conversationId, activity)` is deprecated and will be removed in a future release. Use `send(conversationId, activity, options)` for a root message, or `reply(conversationId, messageId, activity, options)` to reply in a reply chain (thread).
* Passing a `DeprecatedInputActivity` is also deprecated. Use MessageActivityInput or TypingActivityInput instead.
*/
reply(conversationId: string, activity: DeprecatedInputActivity, options?: AppSendOptions): Promise<any>;
/**
* send an activity proactively to a conversation, using the legacy two-argument form.
*
* @deprecated The two-argument form `reply(conversationId, activity)` is deprecated and will be removed in a future release. Use `send(conversationId, activity, options)` for a root message, or `reply(conversationId, messageId, activity, options)` to reply in a reply chain (thread).
*/
reply(conversationId: string, activity: ActivityLike, options?: AppSendOptions): Promise<any>;
/**
* send an activity proactively to a conversation, using the legacy two-argument form.
*
* @deprecated The two-argument form `reply(conversationId, activity)` is deprecated and will be removed in a future release. Use `send(conversationId, activity, options)` for a root message, or `reply(conversationId, messageId, activity, options)` to reply in a reply chain (thread).
*/
reply(conversationId: string, activity: ActivityLike | DeprecatedInputActivity, options?: AppSendOptions): Promise<any>;
/**
* Create an AgenticIdentity for scoped proactive sends and API clients.
*
* AgenticIdentity is the SDK operation/request scope for Agent 365. This
* helper fills the required blueprint and tenant identifiers from app
* configuration while allowing app/user IDs to be omitted or set to `null`
* when the operation is not scoped to a concrete agentic app or user.
*
* @param options identity fields and optional overrides
*/
getAgenticIdentity(options?: AppGetAgenticIdentityOptions): AgenticIdentity;
/**
* Registers an OAuth flow for one Bot Framework OAuth connection.
*
* Connection names are matched case-insensitively. Registering the same
* connection more than once throws. The first registration removes
* the implicit legacy default. This method cannot be used when
* `oauth.defaultConnectionName` was configured.
*
* @param connectionName OAuth connection name.
* @param options Optional card defaults for the flow.
* @returns The registered flow so callbacks can be chained.
*/
addOAuthFlow(connectionName: string, options?: OAuthSignInOptions): OAuthFlow<TPlugin>;
/**
* Gets the OAuth flow for a connection.
*
* The implicit legacy default is available only until the first flow
* is registered.
*
* @param connectionName Connection to resolve.
* @throws When the connection name is blank or no matching flow is registered.
*/
getOAuthFlow(connectionName: string): OAuthFlow<TPlugin>;
/**
* subscribe to an event
* @param name event to subscribe to
* @param cb callback to invoke
*/
on<Name extends keyof IRoutes>(name: Name, cb: Exclude<IRoutes<PluginAdditionalContext<TPlugin>>[Name], undefined>): this;
/**
* subscribe to a message event for a specific pattern
* @param pattern pattern to match against message text
* @param cb callback to invoke
*/
message(pattern: string | RegExp, cb: Exclude<IRoutes<PluginAdditionalContext<TPlugin>>['message'], undefined>): this;
/**
* register a middleware
* @param cb callback to invoke
*/
use(cb: RouteHandler<IActivityContext<Activity, PluginAdditionalContext<TPlugin>>, void | InvokeResponse>): this;
/**
* subscribe to an event
* @param name the event to subscribe to
* @param cb the callback to invoke
*/
event<Name extends keyof AppEvents<TPlugin>>(name: Name, cb: EventHandler<AppEvents<TPlugin>[Name]>): this;
/**
* add a plugin
* @param plugin plugin to add
*/
plugin(plugin: TPlugin): this;
/**
* get a plugin
*/
getPlugin(name: PluginName): IPlugin | undefined;
/**
* add/update a function that can be called remotely
* @param name The unique function name
* @param cb The callback to handle the function
*/
function<TData>(name: string, cb: (context: IFunctionContext<TData>) => any | Promise<any>): this;
function<TPluginOverride, TData>(name: string, cb: (context: IFunctionContext<TData>) => any | Promise<any>): this;
/**
* add/update a static tab.
* the tab will be hosted at
* `http://localhost:{{PORT}}/tabs/{{name}}` or `https://{{BOT_DOMAIN}}/tabs/{{name}}`
* @remark scopes default to `personal`
* @param name A unique identifier for the entity which the tab displays.
* @param path The path to the web `dist` folder.
*/
tab(name: string, path: string): this;
/**
* whether any registered route matches the inbound activity
*
* Useful for hosts that embed the app behind their own pipeline (e.g. the
* Microsoft 365 Extension and need to decide whether to hand a turn
* to this app or let it fall through, without running the activity.
* @param activity the inbound activity to test against registered routes
*/
hasMatchingRoute(activity: Activity): boolean;
/**
* activity handler called when an inbound activity is received
* @param event the received activity event
*/
process(event: IActivityEvent): Promise<InvokeResponse>;
onActivity(event: IActivityEvent): Promise<InvokeResponse>;
protected getBotToken(): Promise<import("@microsoft/teams.api").IToken | null>;
/**
* Acquires a Graph token for an Agentic User, via the federated identity exchange the token manager already performs.
*
* Separate from {@link getAppGraphToken} because the identity differs, not merely the scope: this reads as the agent, so it sees what was shared with the agent rather than everything the app may read.
*/
protected getAgenticGraphToken(identity: AgenticIdentity, tenantId?: string): Promise<import("@microsoft/teams.api").IToken | null>;
protected getAppGraphToken(tenantId?: string): Promise<import("@microsoft/teams.api").IToken | null>;
/**
* Whether deprecated context OAuth fields require an eager token lookup.
*
* Registered flows never enable this behavior. An explicit legacy
* `oauth.fetchUserToken` wins; otherwise lookup is enabled only when the
* legacy default connection was explicitly configured.
*
* @deprecated Registered flows fetch tokens only through `OAuthFlow` methods.
*/
protected shouldFetchUserToken(): boolean;
private sendActivity;
/**
* Build the Socket Mode inbound transport and the {@link HttpServer} that runs
* it. The {@link SocketModeAdapter} is constructed internally so it can reuse
* the app's credentials, and token provider.
*
* Socket Mode is the server's only adapter. A supplied `httpServerAdapter` is
* intentionally unused, and no HTTP listener or route is created.
*/
private buildSocketMode;
private enableOAuthState;
}