UNPKG

@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
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; }